<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" type="topic" id="message-board.c" lang="ko">

  <info>
    <title type="text">게시판 (C)</title>
    <link type="guide" xref="c#examples"/>

    <desc>WebKitGTK+와 DOM을 사용한 간단한 프로그램.</desc>

    <revision pkgversion="0.1" version="0.1" date="2010-12-06" status="draft"/>
    <credit type="author copyright">
      <name>Shaun McCance</name>
      <email its:translate="no">shaunm@gnome.org</email>
      <years>2010</years>
    </credit>
    <credit type="editor">
      <name>Marta Maria Casetti</name>
      <email its:translate="no">mmcasetti@gmail.com</email>
      <years>2013</years>
    </credit>
  <credit type="translator copyright"><name>조성호</name><email>shcho@gnome.org</email><years>2017-2019.</years></credit></info>

<title>게시판</title>

<synopsis>
  <p>이 지침서를 통해 다음을 배웁니다:</p>
  <list style="compact">
    <item><p>WebKit으로 웹 페이지를 표시합니다.</p></item>
    <item><p>WebKit의 DOM 함수로 웹 페이지 내용을 다룹니다.</p></item>
  </list>
  <p>이 따라하기 예제에서는 독자 여러분이 C 프로그래밍 언어에 익숙하며, 위젯을 어떻게 만들어 두고, 콜백 함수를 시그널에 어떻게 연결하는지에 대해  GTK+를 기본적으로 이해하고 있다고 간주합니다. GTK+ 기본을 배우려면 <link xref="image-viewer.c"/>를 참고하십시오.</p>
</synopsis>

<media type="video" mime="video/ogg" src="media/message-board.ogv"/>

<links type="section"/>

<section id="create">
  <title>안주타에서 프로젝트 만들기</title>

  <p>그놈 플랫폼에는 강력한 웹킷 HTML 프레임워크를 바탕으로 만든 WebKitGTK+가 있습니다. WebKit은 그놈 전반적으로 활용하며, 인터넷의 웹 페이지를 보기만 하는 목적으로 쓰는게 아니라, CSS로 쉽게 스타일을 지정할 수 있는 리치 사용자 인터페이스를 만들 때도 사용합니다.</p>

  <p>이 따라하기 지침에서는 WebKit으로 간단한 게시판을 만들어보겠습니다. 게시판에서는 일부 텍스트를 입력할 수 있으며  HTML 메시지 목록을 추가할 수 있습니다. 시작하기 전에 Anjuta에서 프로젝트를 설정해야합니다.</p>

  <steps>
    <item><p>안주타에서  <guiseq><gui>파일</gui><gui>새로 만들기</gui> <gui>프로젝트</gui></guiseq>를 눌러 새 프로젝트 도우미를 여십시오.</p></item>
    <item><p><gui>C</gui> 탭에서 <gui>GTK+ (단순)</gui>을 선택하고, <gui>계속</gui>을 누르십시오.</p></item>
    <item><p><gui>기본 정보</gui> 페이지에 자세한 내용을 적어나가심시오. 프로젝트 이름은 <input>message-board</input>라고 하십시오. <gui>계속</gui>을 누르십시오.</p></item>
    <item><p>따라하기 지침을 통해 사용자 인터페이스를 직접 만들 예정이므로 <gui>사용자 인터페이스에 GtkBuilder 사용</gui> 설정을 끄십시오.</p>
    </item>
    <item><p>안주타 프로그램에서 프로젝트에 WebkitGTK+를 사용한다고 알려야합니다. <gui>프로젝트 옵션</gui> 페이지에서, <gui>외부 패키지 설정</gui>을 선택하십시오. <gui>계속</gui>을 누르십시오. <gui>외부 패키지 설정</gui> 페이지에서 <gui>webkitgtk-3.0</gui>을 선택하십시오.</p></item>
  </steps>

  <p>새 프로젝트 도우미를 끝내고 나면 <gui>프로젝트</gui>탭 또는 the <gui>파일</gui>탭에서 <file>src/main.c</file> 파일을 여십시오 안주타에서는 서식에 일부 기본 GTK+ 코드를 채워넣습니다. WebKit 프로젝트를 만들고 있으니 WebKit 레더를 추가해야합니다. <code>gtk/gtk.h</code>줄 다음에 다음 줄을 추가하십시오:</p>

  <code>#include &lt;webkit/webkit.h&gt;</code>

  <p>여태껏 작성해오던 코드로 모든 부분이 동작하는지 확인하십시오. <guiseq><gui>빌드</gui><gui>프로젝트 빌드</gui></guiseq> 를 누르거나 그냥 <keyseq><key>Shift</key><key>F7</key></keyseq>키를 누르십시오. 처음 빌드할 때는 몇가지 설정 옵션을 물어봅니다. 그냥 기본 값으로 설정하고 <gui>실행</gui>을 누르십시오.</p>

  <p>이제 프로그램을 실행할 수 있어야합니다. <guiseq> <gui>실행</gui><gui>실행</gui></guiseq>을 누르든지 그냥 <key>F3</key> 키를 누르십시오. 빈 창이 나타납니다.</p>
</section>

<section id="webview">
  <title>창과 웹 뷰 배치</title>

  <p>이제 창을 보여줄 수 있으니 WebKit을 다룰 시간입니다. 이 따라하기 안내에 따라 텍스트 항목과 웹 뷰를 만들고 이 요소를 창에 추가합니다. <code>create_window</code>  함수를 찾아 다음 코드로 바꾸십시오:</p>

<code style="numbered" mime="text/C">
static GtkWidget*
create_window (void)
{
    GtkWidget *window, *box, *scroll, *view, *entry;

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
    gtk_window_set_title (GTK_WINDOW (window), "Message Board");
    g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);

    box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
    gtk_container_set_border_width (GTK_CONTAINER (box), 6);
    gtk_container_add (GTK_CONTAINER (window), box);

    entry = gtk_entry_new ();
    gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);

    scroll = gtk_scrolled_window_new (NULL, NULL);
    g_object_set (scroll, "shadow-type", GTK_SHADOW_IN, NULL);
    gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0);

    view = webkit_web_view_new ();
    gtk_container_add (GTK_CONTAINER (scroll), view);
    webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
                                 "&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;",
                                 "text/html",
                                 "UTF-8",
                                 NULL);

    gtk_widget_show_all (GTK_WIDGET (box));
    return window;
}
</code>

  <p>우선 <code>GtkWindow</code> 객체를 만들고 제목과 기본 크기를 설정합니다. <code>gtk_main_quit</code> 함수를 <code>delete-event</code> 시그널에 연결하기도 합니다. <code>delete-event</code>시그널은 창을 닫을때 방출합니다. <code>gtk_main_quit</code> 함수는 GTK의 알부이며, 프로그램을 끝냅니다.</p>

  <p>이제 수직 박스를 만들어 창에 추가했습니다. 창은 오직 단일 하위 위젯을 가질 수 있기 때문에 여러 위젯을 추가하려면 박스를 사용해야합니다. <code>gtk_box_new</code>의 두번째 인자는 각 하위 위젯의 (픽셀 단위)간격을 설정하고 다음 줄에는 전체에 6 픽셀 두께의 테두리를 넣습니다.</p>

  <p>다음 <code>GtkEntry</code> 객체를 만들어 박스에 넣으십시오. <code>gtk_box_pack_start</code>의 세번째, 네번째 인자는 박스에 추가 여유 공간이 있을때, 항목이 차지하지 않도록 설정합니다. 네번째 인저에서는 항목 주변의 여백 공간입니다. 지금의 경우 여백 공간을 0으로 설정했는데 박스에서 내부 여백을 처리할 수 있기 때문입니다.</p>

  <p>웹 뷰를 추가하기 전에 웹 뷰를 넣을 스크롤 뷰를 우선 넣어야합니다. 스크롤 뷰는 필요한 경우 스크롤 표시줄을 오른편과 하단에 두고  웹 뷰가 화면 전체를 차지하지 않게 막아줍니다.  여기서는 <code>gtk_box_pack_start</code>에 <code>TRUE</code>와 <code>TRUE</code>를 넣어 스크롤 창(웹 뷰!)에서 박스의 추가 여분 공간을 사용합니다.</p>

  <p>마지막으로 <code>WebKitWebView</code>를 만들고 스크롤 창에 추가했습니다. 그리고 <code>webkit_web_view_load_string</code> 함수와 다음 인자를 통해 매우 기본적인 HTML페이지를 웹 뷰에 불러다놓았습니다:</p>

  <terms>
    <item>
      <title><code>WEBKIT_WEB_VIEW (view)</code></title>
      <p>뷰 자체입니다.  <code>view</code> 는 <code>GtkWidget*</code> 형식이므로 객체를 안전하게 캐스팅하려면 <code>WEBKIT_WEB_VIEW</code> 를 사용해야합니다.</p>
    </item>
    <item>
      <title><code>"&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;"</code></title>
      <p>여러분이 작성할 수 있는 간단한 HTML 파일입니다.</p>
    </item>
    <item>
      <title><code>"text/html"</code></title>
      <p>여러분이 제공한 컨텐트의 MIME 형식입니다. 지금 같은 경우는 플레인 HTML을 사용중입니다.</p>
    </item>
    <item>
      <title><code>"UTF-8"</code></title>
      <p>여러분이 제공한 내용의 문자 인코딩 방식입니다. ASCII 문자만 활용했다 히더라도 UTF-8로 지정하시는게 좋습니다. UTF-8은 그놈 플랫폼 이곳저곳에서 기본 인코딩으로 활용합니다.</p>
    </item>
    <item>
      <title><code>NULL</code></title>
      <p>기본 URI. 이 간단한 예제에서는 필요하지 않습니다만, 그림을 추가하거나 상대 URI 참고 경로를 추가한다면 <sys>file:</sys> URI를 제공하는게 좋습니다.</p>
    </item>
  </terms>

  <note style="sidebar">
    <p>위젯을 추가할 때마다 위젯이 나타나게 <code>gtk_widget_show</code>  함수를 호출해야합니다. <code>GtkBox</code>와 같은 컨테이너 위젯에서 <code>gtk_widget_show_all</code>  함수를 호출하면, GTK+에서 알아서 컨테이너의 어떤 깊은 곳에 있든 다 끄집어내어 자동으로 보여줍니다. 때로는 이벤트에 대한 응답으로 위젯을 동적으로 숨기거나 보이려고 하는 그런 경우에 <code>gtk_widget_show_all</code>을 호출하고 싶지 않을 때도 있습니다.</p>
  </note>

  <p>마지막으로 박스의 <code>gtk_widget_show_all</code>를 호출해야 합니다. 그렇지 않으면 만들어 둔 어떤 위젯도 볼 수 없습니다(창은 <code>main</code> 함수의 <code>gtk_widget_show</code> 호출로 나타납니다.)</p>

  <p>게시판을 다시 빌드하고 실행하십시오. 텍스트 항목과 웹 뷰가 나타납니다. 텍스트 항목과 웹 뷰는 서로를 알지 못하기 대문에 어떤 일도 일어나지 않습니다.</p>
</section>

<section id="signals">
  <title>시그널 걸어두기</title>

  <p>이제 텍스트 항목에 텍스트를 입력했을때 실제로 게시판에서 어떤 <em>일</em>을 일어나게 하려고 합니다. 콜백 함수를 <code>entry</code>의 <code>activate</code> 시그널로 연결합니다. GTK+는 사용자가 항목 위치에서 <key>Enter</key> 키를 누를 때마다 <code>activate</code> 시그널을 내보냅니다. <code>entry</code>와 <code>view</code>를 정의한 어디에든 다음 코드를 <code>create_window</code>에 넣으십시오:</p>

<code>
g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), view);
</code>

  <p>실제로 <code>entry_activate_cb</code>를 정의해야합니다. <code>create_window</code> 위 어디에든 다음 처럼 정의하십시오:</p>

<code style="numbered">
static void
entry_activate_cb (GtkEntry *entry, WebKitWebView *view)
{
    WebKitDOMDocument *document;
    WebKitDOMElement *body, *div;

    document = webkit_web_view_get_dom_document (view);
    body = webkit_dom_document_query_selector (document, "body", NULL);
    div = webkit_dom_document_create_element (document, "div", NULL);
    webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (div),
                                      gtk_entry_get_text (entry),
                                      NULL);
    webkit_dom_node_append_child (WEBKIT_DOM_NODE (body),
                                  WEBKIT_DOM_NODE (div),
                                  NULL);
    gtk_entry_set_text (entry, "");
}
</code>

  <p>여러분은 우선 <code>view</code>에 HTML 문서를 나타내는 <code>WebKitDOMDocument</code>를 가져와야 합니다. 웹킷 DOM 클래스와 메서드는 HTML을 살펴보고 다룰 수 있게 하며, JavaScript를 통해 이미 알고 있는 DOM API와 매우 유사하게 다룰 수 있습니다.</p>

  <p>문서를 가져온 후에는 <code>body</code> 구성요소를 가져와서 <code>div</code> 구성요소를 넣을 수 있게 해야합니다. <code>webkit_dom_document_query_selector</code> 함수는 CSS 선택자로 문서의 구성 요소를 찾게 해줍니다. 이 방식을 통해 문서를 돌아볼 때 짜증나는 반복문을 작성하지 않게 해줍니다.</p>

  <p>다음, 메시지를 넣어둘 새 <code>div</code> 구성요소를 만듭니다. 여러분이 만든 모든 구성 요소는 문서에 붙으므로, 구성 요소를 만드는 함수의 첫번째 인자로 <code>WebKitDOMDocument</code>를 갖습니다. 그 다음 텍스트 항목의 컨텐트로 구성 요소의 텍스트를 설정합니다. <code>gtk_entry_get_text</code> 에서 <code>const gchar*</code>를 반환하기에, 결과를 굳이 해제하지 않아도 됩니다.</p>

  <p>마지막으로 <code>div</code> 구성요소를 body에 추가하고 텍스트 항목을 지워서 새 내용을 입력할 수 있게 하십시오.프로그램을 다시 빌드하고 실행한 후 여러분 자신이 직접 테스트해보십시오.</p>
</section>


<section id="css">
  <title>CSS로 더 멋지게 만들기</title>

  <p>여기서 프로그램의 기능은 완벽하게 동작하지만 썩 매력있는 편은 아닙니다. 화면에 나타나는 메시지를 다른 HTML페이지를 다루어왔던 것처럼 CSS로 장식할 수 있습니다. 일부 CSS를 페이지에 붙여넣는 방법에는 여러가지가 있는데, 처음 HTML 문서에 추가하는 방법, <code>div</code> 구성 요소의 <code>style</code> 속성에 넣는 방법, DOM API로 프로그래밍 방식으로 넣는 방법이 있습니다.</p>

  <p>이 따라하기 지침에서는 웹 뷰에 붙은 <code>WebKitWebSetting</code> 객체의 <code>user-stylesheet-uri</code> 속성으로 CSS를 붙입니다. 좀 더 완벽한 프로그램에서는 HTML 파일을 저장하고 불러오고 싶을 수도 있습니다. HTML의 실제 스타일 정보를 외부에서 유지한다는건, 굳이 사용자 파일을 건드리지 않아도 프로그램에서 완벽하게 스타일을 바꿀 수 있다는 의미가 되겠습니다.  보통 프로그램과 해당 파일을 같이 설치해야 하겠지만 이 시연 프로그램에서는 하나의 파일에 모두 담아두고 데이터 URI로 꼼수를 쓰겠습니다. 우선 파일 상단 부분에 정적 CSS를 정의하십시오.</p>

<code>
static const guchar CSS[] =
"body { margin: 0; padding: 0; }\n"
"div { "
" -webkit-border-radius: 2px;"
" background: -webkit-gradient(linear, 0% 100%, 0% 0%,"
" from(#f1f1f1), to(white));"
" border: solid 1px #c6c6c6;"
" -webkit-box-shadow: 0px 0px 2px #c6c6c6;"
" margin: 12px; padding: 6px;"
"}";
</code>

  <p>이 예제에 들어간 모든 내용은 <code>body</code> 구성 요소의 <code>div</code> 구성요소입니다. 더 복잡한 HTML을 만든다면 어떤 CSS든 필요합니다. 사실, CSS가 편하다면 여러분이 더 좋아하는 방식대로, 이 코드를 바꿔보시는게 좋습니다.</p>

  <p>CSS를 적용하려면, <code>view</code> 를 설정한 이후 어디든 <code>create_window</code> 함수에서 <code>user-stylesheet-uri</code>를 설정하십시오.</p>

<code>
tmp = g_base64_encode (CSS, strlen((gchar *) CSS));
css = g_strconcat ("data:text/css;charset=utf-8;base64,",
                   tmp, NULL);
g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)),
              "user-stylesheet-uri", css, NULL);
g_free (css);
g_free (tmp);
</code>

  <p>또한 <code>create_window</code> 상단에 <code>tmp</code> 와 <code>css</code> 변수 선언을 추가했는지 확인하십시오.</p>

<code>
gchar *tmp, *css;
</code>

 <p><sys>data:</sys>로 시작하는 데이터 URI와 컨텐트 형식 일부 정보, 데이터 인코딩 방식입니다. 실제 데이터는 콤마 뒤에 따라오는데 이 경우에는 Base64 방식으로 인코딩합니다. <sys>http:</sys>, <sys>ftp:</sys>, <sys>file:</sys> 같은 다른 URI 형식과는 다르게 URI 스킴에는 불러올 파일이 어디있는지 지정하지 않습니다. 대신 파일의 전체 내용을 제시해줍니다.</p>

 <p>위 코드는 우선 CSS 정의를 Base64 방식으로 인코딩한 다음 데이터 URI를 만드는 정적 문자열과 합칩니다. <code>g_strconcat</code> 함수에서는 여러 문자열 인자를 취하여 합칠 수 있으므로, 마지막 인자 값은 <code>NULL</code>로 주어 언제 문자열을 합치는 동작을 멈출 지 알려야합니다. 그리고 스타일 시트를 올바르게 설정하고 나면 잊지 마시고 임시 문자열에 대해 메모리 해제를 반드시 수행하십시오.</p>

 <p>프로그램을 다시 빌드하고 실행하십시오. 테두리와 미묘한 백그라운드 그레디언트로 멋지게 장식할 메시지 부분을 제외하고는 섹션의 마지막 부분과 정확히 동일하게 동작합니다.</p>
</section>

<section id="more">
  <title>더 알아보기</title>

  <p>이 따라하기 지침에서는 GTK+와 웹킷으로 문서를 보여주고 내용을 다루는 기본적인 프로그램을 만드는 방법을 보여줍니다. 실제 프로그램을 만들려면, 프로그램에 좀 더 이것저것 붙여보고 싶을지도 모릅니다. 기능 추가는 여러분이 직접 해보시죠. 몇가지 아이디어를 드리겠습니다:</p>

  <list>
    <item><p>CSS가 불편하다면 메시지 표시 방식을 바꿔보십시오. CSS는 시작하기 쉬우면서도 다루어 볼수록 점점 강력해집니다. 인터넷에는 다양한 CSS 따라하기 문서가 있으며, 웹에 할 수 있는 모든걸 이 프로그램에서 해볼 수 있습니다.</p></item>

    <item><p>바로 지금 게시판을 닫는다면 모든 메시지가 증발합니다. 각 게시물을 올린 다음 HTML 문서를 저장해보고 시작할 때 저장한 파일(있을 경우)을 불려와보십시오.</p></item>

    <item><p>메시지를 오랫동안 유지했다면 언제 게시했는지 궁금해하실겁니다. 각 메시지를 게시할 때 타임 스탬프를 추가하십시오. 아마도 CSS로 모양새를 갖출 수 있도록 다른 클래스 이름을 부여한 추가 하위 <code>div</code> 구성요소를 만들고 싶을 수도 있습니다.</p>
    </item>

    <item><p>이 프로그램은 메시지를 계속 유지합니다. 사용자가 메시지를 지울 수 있게 하는 방법을 생각해보시죠. 아마도 너무 오래됐거나, 일정 갯수가 넘어가면 자동으로 메시지를 사라지게 하고 싶을지도 모릅니다. 아니면 각 메시지에 삭제할 수 있는 링크를 달아둘 수 있습니다. 심지어 메시지에 마우스 단추를 올려두고 오른쪽 단추를 눌렀을 때 단축 메뉴를 띄울 수 있습니다. 이 기능을 구현하려면 웹킷 DOM API를 좀 더 찾아봐야 합니다.</p></item>
  </list>
</section>
</page>
