Vývěska (C) Jednoduchý program používající WebKitGTK+ a DOM. Shaun McCance shaunm@gnome.org 2010 Marta Maria Casetti mmcasetti@gmail.com 2013 Vývěska

V této lekci se seznámíme s následujícími věcmi:

Jak zobrazit webovou stránku pomocí jádra WebKit.

Jak pracovat s obsahem webové stránky pomocí funkcí DOM jádra WebKit.

Tato lekce předpokládá, že máte znalosti programování v jazyce C a základní povědomí o GTK+, včetně toho, jak vytvořit a umístit widgety a jak připojit funkce zpětného volání k signálům. Viz ohledně výuky základů GTK+.

Vytvoření projektu ve studiu Anjuta

Součástí platformy GNOME je WebKitGTK+ vycházející z mocné základní konstrukce WebKit pro HTML. WebKit je používán napříč celým GNOME, ne jen pro zobrazení webových stránek z Internetu, ale také k vytváření vizuálně bohatého uživatelského rozhraní, které lze jednoduše stylovat pomocí CSS.

V této lekci vytvoříme jednoduchou vývěsku pomocí knihovny WebKit. Vývěska bude umožňovat vkládat text a přidávat jej do seznamu zpráv v HTML. Než začneme, potřebujeme vytvořit projekt v IDE Anjuta.

Ve studiu Anjuta klikněte na Soubor Nový Projekt, aby se otevřel průvodce novým projektem.

Vyberte GTK+ (jednoduchý) na kartě C a klikněte na Pokračovat.

Na stránce Základní informace vyplňte své údaje. Jako název projektu použijte message-board. Klikněte na Pokračovat.

Vypněte volbu Použít GtkBuilder k tvorbě uživatelského rozhraní, protože jej chceme v této lekci vytvořit ručně.

Potřebujete vývojářskému studiu Anjuta říct, že ve svém projektu používáte WebKitGTK+. Na stránce Volby projektu vyberte Konfigurovat externí balíčky. Klikněte na Pokračovat a na stránce Konfigurace externích balíčků zaškrtněte webkitgtk-3.0.

Po té, co projdete průvodcem nového projektu, otevřete src/main.c na kartě Projekt nebo Soubor. Anjuta jej vyplní nějakým základním kódem GTK+ ze šablony. Protože vytváříte projekt s knihovnou WebKit, potřebujete nejdříve vložit příslušné hlavičkové soubory. Za řádek, který vkládá gtk/gtk.h přidejte následující řádek:

#include <webkit/webkit.h>

Ověřte, že vše, co máte doposud hotovo, funguje. Klikněte na Sestavit Sestavit projekt nebo jen zmáčkněte Shift F7. Při prvním sestavení budete dotázáni na některé volby konfigurace. Stačí přijmout výchozí hodnoty a kliknout na Spustit.

Nyní byste měli být schopni program spustit. Klikněte na Spustit Spustit nebo jen zmáčkněte F3. Měli byste spatřit prázdné okno.

Rozvržení vašeho okna a webového zobrazení

Nyní, když můžete zobrazit okno, je načase začít pracovat s knihovnou WebKit. V této lekci vytvoříte textové vstupní pole a webové zobrazení a obojí zabalíte do okna. Najděte funkci create_window a nahraďte ji následujícím:

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

Nejprve vytvoříte objekt GtkWindow a nastavíte jeho název do záhlaví a výchozí velikost. Rovněž napojíte funkci gtk_main_quit na signál "delete-event". Tento signál je vyslán, když je okno zavřeno. Funkce gtk_main_quit je součástí GTK a ukončí aplikaci.

Pak vytvoříte svislý box a přidáte jej do okna. Okno může obsahovat jen jediný synovský widget, takže potřebujete box, abyste mohli přidat víc widgetů. Druhým argumentem u funkce gtk_box_new se nastaví velikost odsazení (v pixelech) mezi jednotlivými potomky a následující řádek vloží 6pixelový okraj okolo toho všeho.

Následně vytvoříte objekt GtkEntry a zabalíte jej do boxu. Třetí argument u gtk_box_pack_start určují, že vstupní pole by nemělo zabírat žádné místo navíc, které je v boxu dostupné. Čtvrtý argument je velikost odsazení okolo vstupního pole. V tomto případě jej nastavte na nulu, protože o odsazení se postará box.

Než přidáte webové zobrazení, musíte vytvořit okno s posuvníky, do kterého jej pak vložíte. Okno s posuvníky umístí v případě potřeby doprava a dolů posuvníky a zabrání vašemu webovému zobrazení, aby zaplnilo celou obrazovku. Tentokrát funkci gtk_box_pack_start předejte TRUE a TRUE, aby umožnila oknu s posuvníky (a tím webovému zobrazení) použít dodatečné místo dostupné v boxu.

Nakonec vytvoříte WebKitWebView a přidáte jej do okna s posuvníky. Potom načtěte úplně základní stránku v HTML do webového zobrazení zavoláním webkit_web_view_load_string s následujícími parametry:

<code>WEBKIT_WEB_VIEW (view)</code>

Vlastní zobrazení. Protože view je typováno jako GtkWidget*, musíte požít WEBKIT_WEB_VIEW, aby se objekt bezpečně přetypoval.

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

Nejjednodušší soubor HTML, který byste mohli napsat.

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

Typ MIME obsahu, který poskytujete. V tomto případě používáte prosté HTML.

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

Kódování znaků v obsahu, který poskytujete. I když použijete jen znaky ASCII, je dobrým pravidlem zadat UTF-8. UTF-8 je totiž používáno jako výchozí kódování napříč celou platformou GNOME.

<code>NULL</code>

Základní adresa URI. V tomto příkladu ji nepotřebujeme, ale možná budete chtít zadat URI file:, kdybyste přidali obrázky nebo jinou funkčnost, ve které chcete použít relativní odkazy URI.

Pokaždé, když přidáte widget, musíte pro něj zavolat gtk_widget_show, aby byl viditelný. Když zavoláte gtk_widget_show_all pro kontejnerový widget, jako je GtkBox, zobrazí GTK+ automaticky všechny widgety uvnitř kontejneru do libovolné hloubky. Občas nemusíte chtít gtk_widget_show_all volat, třeba když chcete dynamicky skrývat a zobrazovat některé widgety v reakci na události.

Nakonec musíme v boxu zavolat gtk_widget_show_all, jinak nebude žádný vytvořený widget viditelný. (Okno je zobrazeno ve funkci main pomocí gtk_widget_show.)

Sestavte a spusťte vývěsku znovu. Měli byste vidět okno s textovým vstupním polem a webové zobrazení. Zatím to nic nedělá, protože vstupní pole a webové zobrazení o sobě navzájem nic neví.

Zaháčkování signálů

Nyní chcete vývěsku naučit něco udělat, když zadáte text do textového vstupního pole. To se provede tak, že se napojí funkce zpětného volání na signál "activate" objektu entry. GTK+ vyšle signále "activate", kdykoliv uživatel ve vstupním poli zmáčkne Enter. Následující kód přidejte do create_window kamkoliv za definici entry a view:

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

Potom můžete totiž definovat entry_activate_cb. Nadefinujte jej následovně kdekoliv nad 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, ""); }

První věc, kterou uděláte, je, že získáte objekt WebKitDOMDocument, který představuje dokument HTML zobrazený ve widgetu view. Třídy a metody DOM v knihovně WebKit umožňují procházet a upravovat dokument HTML a fungují velmi podobně jako API k DOM, které můžete znát z jazyka JavaScript.

Jakmile máme dokument, chceme se dostat k prvku body, protože do něj můžeme přidat prvky div. Funkce webkit_dom_document_query_selector umožňuje najít prvek v dokumentu pomocí selektorů CSS. Tím si ušetříte psaní jednotvárných smyček pro procházení dokumentu.

V dalším kroku vytvoříme nový prvek div, ve kterém bude zpráva. Každý prvek, který vytvoříte, musí být připojen do dokumentu, takže funkce, která prvky vytváří, přebírá jako první argument WebKitDOMDocument. Pak nastavíte textový obsah prvku na obsah z textového vstupního pole. Protože gtk_entry_get_text vrací const gchar*, nemusíte výsledek uvolňovat z paměti.

Nakonec přidáme nový prvek div do těla a vymažeme textové vstupní pole, takže můžete napsat něco dalšího. Sestavte a spusťte program znovu a otestujte si jej.

Vytvoření hezčího vzhledu pomocí CSS

V tuto chvíli je program plně funkční, ale ne moc hezký. Můžeme ostylovat zobrazení zpráv pomocí CSS, podobně jako to můžete udělat s kteroukoliv stránkou v HTML. Existuje mnoho způsobů, jak připojit stylopis do stránky: Mohli byste jej přidat do počátečního dokumentu HTML. Mohli byste jej vložit pomocí atributu style v prvku div. Mohli byste jej i sestrojit pomoci API k DOM.

V této lekci připojíme CSS pomocí vlastnosti user-stylesheet-uri objektu WebKitWebSetting připojeného do vašeho webového zobrazení. Ve složitějších aplikacích byste asi chtěli soubor HTML ukládat a načítat. Udržením stylopisu mimo HTML znamená, že může měnit styl přímo ve své aplikaci, bez zásahu do uživatelských souborů. Normálně by vám stačilo nainstalovat soubor se stylopisem spolu s vaší aplikací, ale aby pro potřeby této ukázky zůstalo vše uchováno v jednom souboru, použijeme trik nazvaný datová URI. Nejprve nadefinujeme CSS jako statický řetězec poblíž začátku vašeho souboru.

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

Vše, co máme v tomto příkladu, jsou prvky div uvnitř prvku body. Kdybyste vytvořili složitější HTML, mohli byste použít cokoliv by CSS bylo potřeba. Jestli jste s CSS obeznámeni, můžete si opravdu zkusit nějaké změny, aby se vám vzhled víc líbil.

Aby se použilo CSS, nastavte user-stylesheet-uri ve funkci create_window kdekoliv za definicí view.

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

Rovněž zajistěte přidání deklarací proměnných pro tmp a css na začátku create_window.

gchar *tmp, *css;

Datová URI začíná data: a některými informacemi o typu obsahu a kódování dat. Skutečná data následují za čárkou, v tomto případě zakódovaná v Base64. Narozdíl od jiných schémat URI, jako je http:, ftp: a file:, schéma URI data: nespecifikuje, kde najít soubor k načtení. Místo toho poskytuje rovnou celý obsah souboru.

Předchozí kód nejprve zakóduje vaši definici CSS v Base64 a pak ji zkombinuje s pevným řetězcem, aby vytvořil datovou URI. Funkce g_strconcat může přebírat libovolný počet řetězcových argumentů a spojit je dohromady, proto jí musíte jako poslední argument předat NULL, aby věděla kdy přestat. A až stylopis správně nastavíte, nezapomeňte uvolnit tyto dočasné řetězce z paměti.

Sestavte a spusťte program znovu. Měl by fungovat úplně stejně jako na konci předchozí části, vyjma toho, že zprávy jsou hezky ostylované pomocí okrajů a pozadí s jemným přechodem.

Jak se naučit více

V této lekci jsme si ukázali, jak vytvořit základní aplikaci pomocí knihoven GTK+ a WebKit, včetně zobrazení dokumentu a manipulace s jeho obsahem. Pro vytvoření reálné aplikace byste nejspíše museli udělat něco navíc. Zkuste si přidat vlastní funkčnost. Zde je pár nápadů:

Pokud máte CSS rádi, zkuste si změnit styl zobrazených zpráv. S CSS se snadno začíná, ale i roste k mocnějšímu využití. Na Internetu je k dispozici nepřeberné množství výukových materiálů k CSS a téměř vše, co můžete udělat na webu, můžete udělat i v této aplikaci.

V současné stavu přijdete o všechny své zprávy, když vývěsku zavřete. Zkuste obsah v HTML ukládat po každém příspěvku a načítat jej z uloženého souboru (když existuje) při spuštění.

Až budete mít své zprávy uchované po dlouhou dobu, možná vás začne zajímat, kdy vlastně byly zveřejněny. Přidejte ke každé zprávě při jejím zveřejnění časové razítko. Možná budete potřebovat vytvořit další synovský prvek div s jinou třídou, abyste to mohli ostylovat pomocí CSS.

Tento program uchovává zprávy navždy. Popřemýšlejte o způsobu, jak by uživatel mohl zprávy mazat. Třeba můžete chtít, aby zprávy samy mizely, když jsou příliš staré nebo když množství zpráv před nimi dosáhne určitého počtu. Nebo můžete ke každé zprávě přidat odkaz na její smazání. Mohli byste také přepsat kontextovou nabídku, která se objeví po kliknutí pravým tlačítkem. Tyto funkce znamenají hlubší prozkoumání API k DOM knihovny WebKit.