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 - 2017 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 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:

<code>WEBKIT_WEB_VIEW (view)</code>

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

<code>"<html><body></body></html>"</code>

El archivo HTML más simple que pueda escribir.

<code>"text/html"</code>

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

<code>"UTF-8"</code>

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.

<code>NULL</code>

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.