# Cuadro de mensajes (C)

Un programa sencillo usando WebKitGTK+ y el DOM.
Shaun McCance
shaunm@gnome.org 2010
Marta Maria Casetti
mmcasetti@gmail.com 2013
Daniel Mustieles
daniel.mustieles@gmail.com 2011 - 2020
Nicolás Satragno
nsatragno@gmail.com 2012 - 2013
Jorge González
jorgegonz@svn.gnome.org 2011

# Cuadro de mensajes

      En este tutorial aprenderá:

        Cómo mostrar una página web con WebKit
        Como manipular el contenido de una página web usando las funciones del DOM del WebKit.

      En este tutorial se asume que está familiarizado con el lenguaje de programación C y que tiene un conocimiento básico de GTK+, incluyendo cómo crear y colocar widgets y cómo conectar funciones de retorno de retorno de la llamadas a señales. Consulte la sección  para aprender las nociones básicas de GTK+.

# Crear un proyecto en Anjuta

La plataforma GNOME incluye WebKitGTK+, construido sobre el potente marco de trabajo WebKit. WebKitGTK se usa en todo GNOME, no sólo para ver páginas web en Internet, sino también para crear interfaces de usuario enriquecidas a las que se pueden añadir estilos fácilmente con CSS.

En este tutorial, se creará un cuadro de mensajes sencillo usando WebKit. El cuadro de mensajes le permitirá introducir algún texto y añadirlo a una lista de mensajes en HTML. Antes de empezar, deberá configurar un proyecto en Anjuta.

En Anjuta, pulse ArchivoNuevo Proyecto para abrir el asistente para proyecto nuevo.

Seleccione GTK+ (simple) en la pestaña C y pulse Continuar.

Rellene sus detalles en la página Información básica. Use cuadro-mensajes para el nombre del proyecto. Pulse Continuar.

Desactive la opción Usar GtkBuilder para la interfaz del usuario, ya que, en este tutorial, la interfaz de usuario se construye manualmente.

Deberá indicar a Anjuta que va a usar WebKitGTK+ en este proyecto. En la página Opciones del proyecto, seleccione Configurar paquetes externos. Pulse Continuar. En la página Configurar paquetes externos seleccione webkitgtk-3.0.

Cuando termine el asistente de creación de un nuevo proyecto, abra el archivo src/main.c desde la pestaña Proyecto o desde Archivo. Anjuta lo habrá rellenado con algo de código GTK+ básico de sus plantillas. Ya que está creando un proyecto WebKit, primero debe incluir las cabeceras de WebKit. Después de la línea que incluye `gtk/gtk.h`, añada la siguiente línea:

#include <webkit/webkit.h>

Verifique que todo funciona construyendo lo que tiene hasta ahora. Pulse ConstruirConstruir proyecto o simplemente pulse MayúsF7. La primera vez que construya, se le pedirán algunas opciones de configuración. Simplemente acepte los valores predeterminados y pulse Ejecutar.

Ahora debería poder ejecutar el programa. Pulse EjecutarEjecutar o simplemente pulse F3. Debería ver aparecer una ventana vacía.

# La disposición de la ventana y la vista web

Ahora que puede mostrar una ventana, es el momento de empezar a trabajar con WebKit. Para este tutorial, se creará una entrada de texto y una vista web y ambas se empaquetarán en una ventana. Busque la función `create_window` y reemplácela con lo siguiente

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), "<html><body></body></html>", "text/html", "UTF-8", NULL);

gtk_widget_show_all (GTK_WIDGET (box)); return window; }

Primero cree un objeto `GtkWindow` y establezca su título y su tamaño predeterminado. También puede conectar la función `gtk_main_quit` a la señal `delete-event`. La señal `delete-event` se emite cuando se cierra la ventana. La función `gtk_main_quit` es parte de GTK+, y sale de la aplicación.

Ahora cree una caja vertical y añádala a la ventana. Una ventana sólo puede contener un widget hijo, por lo que necesitará una caja para añadir varios widgets. El segundo argumento de `gtk_box_new` configura la cantidad de espacio (en píxeles) entre cada hijo, y la siguiente línea añade un borde de seis píxeles alrededor de la cosa completa.

Después, cree un objeto `GtkEntry` y empaquételo en una caja. Los argumentos tercero y cuarto de `gtk_box_pack_start` especifican que la entrada no debería coger ningún espacio adicional que tenga la caja. El cuarto es la cantidad de relleno que quiere alrededor de la entrada. En este caso, se establece el relleno a cero, ya que se está permitiendo que la caja maneje todo el relleno.

Antes de añadir la vista web debe crear una ventana desplazada para ponerla dentro. La ventana desplazada contendrá barras de desplazamiento a la derecha y abajo cuando sea necesario, y evitará que la vista web abarque la pantalla entera. En este momento, se pasa `TRUE` y `TRUE` a `gtk_box_pack_start` para permitir que la ventana desplazada (y por lo tanto, la vista web) usen el espacio adicional disponible en la caja.

Finalmente, cree una `WebKitWebView` y añádala a la ventana desplazada. Entonces cargue una página HTML muy simple en la vista web llamando a `webkit_web_view_load_string` con los siguientes argumentos:

## `WEBKIT_WEB_VIEW (view)`

La vista en sí. Ya que `view` es de tipo `GtkWidget*`, debe usar `WEBKIT_WEB_VIEW` para convertir el tipo del objeto con seguridad.

## `"<html><body></body></html>"`

El archivo HTML más simple que pueda escribir.

## `"text/html"`

El tipo MIME del contenido que ha proporcionado. En este caso, está usando HTML plano.

## `"UTF-8"`

La codificación de caracteres del contenido que ha proporcionado. Aunque sólo use caracteres ASCII, es una buena idea especificar UTF-8, ya que es la codificación que se usa de manera predeterminada en toda la plataforma GNOME.

## `NULL`

El URI base. En este ejemplo no se necesita, pero puede querer proporcionar un URI file: si añade imágenes u otras características cuando quiera usar referencias a URI relativos.

Cada vez que añade un widget, debe llamar a la función `gtk_widget_show` sobre él para hacerlo visible. Si llama a `gtk_widget_show` en un contenedor de widgets como `GtkBox`, GTK+ mostrará automáticamente todos los widgets del contenedor, en cualquier nivel. Algunas veces no se quiere llamar a la función `gtk_widget_show_all`, como cuando se quieren ocultar o mostrar dinámicamente algunos objetos en respuesta a determinados eventos.

Finalmente, debe llamar a la función `gtk_widget_show_all` sobre la caja. De otro modo, ninguno de los widgets que haya creado será visible. (La ventana se muestra en la función `main` con `gtk_widget_show`.)

Construya y ejecute el cuadro de mensajes de nuevo. Debería ver una ventana con una entrada de texto y una vista web. Todavía no hace nada porque la entrada de texto y la vista web no saben nada la una acerca de la otra.

# Conectar señales

Ahora se quiere hacer que el cuadro haga algo cuando se introduce texto en la entrada de texto. Para hacer esto, conecte una función de retorno de la llamada a la señal `activate` de `entry`. GTK+ emite la señal `activate` cuando el usuario pulsa Intro en la entrada. Añada lo siguiente en `create_window`, en cualquier lugar después de que `entry` y `view` se hayan definido:

g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), view);

Entonces se debe definir `entry_activate_cb`. Defínalo como quiera, en cualquier lugar por encima de `create_window`:

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, ""); }

Lo primero que hacer es obtener un objeto `WebKitDOMDocument` que representa el documento HTML mostrado en la `view`. Las clases DOM y los métodos de WebKit le permiten inspeccionar y manipular el documento HTML, y trabajar de manera similar a las API DOM que ya debería conocer de JavaScript.

Una vez que tenga el documento, querrá obtener el elemento `body` para poder añadirle elementos `div`. La función `webkit_dom_document_query_selector` le permite encontrar un elemento en el documento usando selectores CSS. Esto le evita tener que escribir bucles tediosos para recorrer el documento.

Ahora, cree un elemento `div` que contenga el mensaje. Cada elemento que cree se debe adjuntar se debe adjuntar a un documento, por lo que la función para crear un elemento toma el `WebKitDOMDocument` como primer argumento. Debe entonces establecer el contenido del elemento con el contenido de la entrada de texto. Dado que `gtk_entry_get_text` devuelve un `const gchar*`, no tiene que liberar el resultado.

Finalmente, añada el nuevo elemento `div` al cuerpo y limpie la salida de texto para poder escribir algo nuevo. Construya y ejecute el programa otra vez y pruébelo por su cuenta.

# Mejorar el aspecto con CSS

En este punto, su programa es completamente funcional, pero no es muy atractivo. Puede añadir estilos a la visualización de los mensajes con CSS, igual que puede hacer con una página web. Hay muchas maneras de incluir un CSS en la página: puede añadirlo al documento HTML inicial, añadirlo en línea usando el atributo `style` de los elementos `div` o puede incluso construirlo con programación usando las API DOM.

En este tutorial se adjuntará el CSS usando la propiedad `user-stylesheet-uri` del objeto `WebKitWebSetting` empotrado en la vista web. En una aplicación más completa, se podría querer guardar y cargar el archivo HTML. Mantener la información de estilo fuera del HTML actual significa que se puede cambiar el estilo completo de la aplicación sin tener que cambiar los archivos del usuario. Normalmente se instala un archivo junto con la aplicación, pero simplemente para mantener todo en un archivo en esta demostración, se usará un truco llamado URI de datos. En primer lugar, se define el CSS como una cadena estática cerca del principio del archivo.

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;" "}";

Todo lo que tiene en este ejemplo son elementos `div` dentro de un elemento `body`. Si ha creado HTML más complejo, puede usar cualquier CSS que sea necesario. Si se siente cómodo usando CSS debería intentar cambiar esto por algo que le guste más.

Para aplicar el CSS, configure la `user-stylesheet-uri` en la función `create_window`, en cualquier lugar después de que `view` se haya definido.

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);

Asegúrese de añadir declaraciones de variables para `tmp` y `css` a la parte superior de `create_window`.

gchar *tmp, *css;

Un URI de datos empieza por data: y cierta información sobre el tipo de contenido y cómo se codifican los datos. Los datos reales siguen después de una coma, en este caso, codificados en Base64. A diferencia de otros esquemas de URI como http:, ftp:, y file:, the data:, el esquema del URI no especifica dónde encontrar un archivo que cargar. En vez de eso, ofrece el contenido completo del archivo.

El código anterior primero codifica las definiciones CSS en Base64, y luego las combina con una cadena fija para crear una URI de datos. La función `g_strconcat` puede tomar cualquier número de argumentos de cadena y concatenarlos todos juntos, por lo que tiene que pasar `NULL` como argumento final para que sepa dónde parar. No olvide liberar esas cadenas temporales después de establecer la propiedad de la hoja de estilos.

Construya y ejecute el programa de nuevo. Debería funcionar exactamente igual que al final de la última sección, excepto que los mensajes tendrán estilos con un borde y un degradado de fondo sutil.

# Aprender más

Este tutorial le ha mostrado cómo crear una aplicación sencilla usando GTK+ y WebKit, incluyendo cómo mostrar un documento y manipular su contenido. Para crear una aplicación real, probablemente quiera hacer algo más. Pruebe a añadir características usted mismo. Aquí hay algunas ideas:

Si se siente cómo usando CSS, pruebe a cambiar el estilo de la visualización del mensaje. Es fácil iniciarse en CSS, pero cada vez es más potente. Hay una gran cantidad de tutoriales de CSS en Internet, y casi todo lo que se puede hacer en una página web, se puede hacer en esta aplicación.

Ahora mismo, todos los mensajes se pierden al cerras el cuadro de mensajes. Pruebe a guardar el contenido HTML después de cada envío, y a cargar el archivo guardado (si existe) al inicio.

Si guarda sus mensajes durante mucho tiempo, empezará a preguntarse dónde los escribió. Añada una marca de tiempo a cada mensaje cuando se envía. Probablemente quiera crear algún elemento `div` hijo adicional con diferentes clases que puede modelar en el CSS.

Este programa guarda los mensajes para siempre. Piense alguna manera para que el usuario pueda eliminar mensajes. Tal vez quiera que los mensajes desaparezca automáticamente cuando son muy antiguos o después de que haya cierto número de mensajes por delante. O podría añadir un enlace en cada mensaje para eliminarlo. También puede omitir el menú contextual cuando pulsa con el botón derecho sobe un mensaje. Esta características implican explorar más la API del DOM de WebKit.