|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
xmlns:its="http://www.w3.org/2005/11/its"
|
|
Packit |
1470ea |
type="topic"
|
|
Packit |
1470ea |
id="message-board.c">
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<info>
|
|
Packit |
1470ea |
<title type="text">Message board (C)</title>
|
|
Packit |
1470ea |
<link type="guide" xref="c#examples"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<desc>A simple program using WebKitGTK+ and the DOM.</desc>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<revision pkgversion="0.1" version="0.1" date="2010-12-06" status="draft"/>
|
|
Packit |
1470ea |
<credit type="author copyright">
|
|
Packit |
1470ea |
<name>Shaun McCance</name>
|
|
Packit |
1470ea |
<email its:translate="no">shaunm@gnome.org</email>
|
|
Packit |
1470ea |
<years>2010</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
<credit type="editor">
|
|
Packit |
1470ea |
<name>Marta Maria Casetti</name>
|
|
Packit |
1470ea |
<email its:translate="no">mmcasetti@gmail.com</email>
|
|
Packit |
1470ea |
<years>2013</years>
|
|
Packit |
1470ea |
</credit>
|
|
Packit |
1470ea |
</info>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<title>Message board</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<synopsis>
|
|
Packit |
1470ea |
In this tutorial, you will learn:
|
|
Packit |
1470ea |
<list style="compact">
|
|
Packit |
1470ea |
<item>How to display a web page with WebKit. </item>
|
|
Packit |
1470ea |
<item>How to manipulate the contents of a web page using WebKit's DOM
|
|
Packit |
1470ea |
functions.</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
This tutorial assumes you are familiar with the C programming language
|
|
Packit |
1470ea |
and have a basic understanding of GTK+, including how to create and place
|
|
Packit |
1470ea |
widgets and how to connect callback functions to signals. See
|
|
Packit |
1470ea |
xref="image-viewer.c"/> to learn the basics of GTK+.
|
|
Packit |
1470ea |
</synopsis>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<media type="video" mime="video/ogg" src="media/message-board.ogv"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<links type="section"/>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="create">
|
|
Packit |
1470ea |
<title>Create a project in Anjuta</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The GNOME platform includes WebKitGTK+, built on top of the powerful
|
|
Packit |
1470ea |
WebKit HTML framework. WebKit is used throughout GNOME, not just to view
|
|
Packit |
1470ea |
web pages on the Internet, but also to create rich user interfaces that
|
|
Packit |
1470ea |
can be easily styled with CSS.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
In this tutorial, you will create a simple message board using WebKit.
|
|
Packit |
1470ea |
The message board will allow you to enter some text and have it added to a
|
|
Packit |
1470ea |
list of messages in HTML. Before you begin, you need to set up a project in
|
|
Packit |
1470ea |
Anjuta.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<steps>
|
|
Packit |
1470ea |
<item>In Anjuta, click <guiseq><gui>File</gui><gui>New</gui>
|
|
Packit |
1470ea |
<gui>Project</gui></guiseq> to open the new project assistant.</item>
|
|
Packit |
1470ea |
<item>Select <gui>GTK+ (simple)</gui> on the <gui>C</gui> tab,
|
|
Packit |
1470ea |
and click <gui>Continue</gui>.</item>
|
|
Packit |
1470ea |
<item>Fill out your details on the <gui>Basic information</gui> page.
|
|
Packit |
1470ea |
Use <input>message-board</input> for the project name.
|
|
Packit |
1470ea |
Click <gui>Continue</gui>.</item>
|
|
Packit |
1470ea |
<item>Disable the <gui>Use GtkBuilder for user interface</gui> option as
|
|
Packit |
1470ea |
this tutorial builds the user-interface manually.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>You need to tell Anjuta you're using WebKitGTK+ on this project.
|
|
Packit |
1470ea |
On the <gui>Project options</gui> page, select <gui>Configure external
|
|
Packit |
1470ea |
packages</gui>. Click <gui>Continue</gui>. On the <gui>Configure external
|
|
Packit |
1470ea |
packages</gui> page, check <gui>webkitgtk-3.0</gui>.</item>
|
|
Packit |
1470ea |
</steps>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
After you finish the new project assistant, open the file
|
|
Packit |
1470ea |
<file>src/main.c</file> from either the <gui>Project</gui> or the
|
|
Packit |
1470ea |
<gui>File</gui> tab. Anjuta will have filled this in with some basic
|
|
Packit |
1470ea |
GTK+ code from its templates. Since you are creating a WebKit project,
|
|
Packit |
1470ea |
you first need to include the WebKit headers. After the line that
|
|
Packit |
1470ea |
includes gtk/gtk.h , add the following line:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
#include <webkit/webkit.h>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Verify that everything works by building what you have so far.
|
|
Packit |
1470ea |
Click <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> or
|
|
Packit |
1470ea |
just press <keyseq><key>Shift</key><key>F7</key></keyseq>. The first
|
|
Packit |
1470ea |
time you build, you will be asked for some configure options. Just
|
|
Packit |
1470ea |
accept the defaults and click <gui>Execute</gui>.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
You should now be able to run the program. Click <guiseq>
|
|
Packit |
1470ea |
<gui>Run</gui><gui>Execute</gui></guiseq> or just press <key>F3</key>.
|
|
Packit |
1470ea |
You should see an empty window appear.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="webview">
|
|
Packit |
1470ea |
<title>Lay out your window and web view</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Now that you can show a window, it's time to start working with WebKit.
|
|
Packit |
1470ea |
For this tutorial, you'll create a text entry and a web view and pack
|
|
Packit |
1470ea |
them both into a window. Find the function create_window and
|
|
Packit |
1470ea |
replace it with the following:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static GtkWidget*
|
|
Packit |
1470ea |
create_window (void)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
GtkWidget *window, *box, *scroll, *view, *entry;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
Packit |
1470ea |
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
|
|
Packit |
1470ea |
gtk_window_set_title (GTK_WINDOW (window), "Message Board");
|
|
Packit |
1470ea |
g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
Packit |
1470ea |
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
|
|
Packit |
1470ea |
gtk_container_add (GTK_CONTAINER (window), box);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
entry = gtk_entry_new ();
|
|
Packit |
1470ea |
gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 0);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
scroll = gtk_scrolled_window_new (NULL, NULL);
|
|
Packit |
1470ea |
g_object_set (scroll, "shadow-type", GTK_SHADOW_IN, NULL);
|
|
Packit |
1470ea |
gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
view = webkit_web_view_new ();
|
|
Packit |
1470ea |
gtk_container_add (GTK_CONTAINER (scroll), view);
|
|
Packit |
1470ea |
webkit_web_view_load_string (WEBKIT_WEB_VIEW (view),
|
|
Packit |
1470ea |
"<html><body></body></html>",
|
|
Packit |
1470ea |
"text/html",
|
|
Packit |
1470ea |
"UTF-8",
|
|
Packit |
1470ea |
NULL);
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gtk_widget_show_all (GTK_WIDGET (box));
|
|
Packit |
1470ea |
return window;
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
You first create a GtkWindow object and set its title and
|
|
Packit |
1470ea |
default size. You also connect the gtk_main_quit function to the
|
|
Packit |
1470ea |
delete-event signal. The delete-event signal is
|
|
Packit |
1470ea |
emitted when the window is closed. The gtk_main_quit function is
|
|
Packit |
1470ea |
part of GTK, and it quits the application.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
You then create a vertical box and add it to the window. A window can only
|
|
Packit |
1470ea |
hold a single child widget, so you need to use a box to add multiple widgets.
|
|
Packit |
1470ea |
The second argument to gtk_box_new sets the amount of padding
|
|
Packit |
1470ea |
(in pixels) between each child, and the next line puts a six-pixel border
|
|
Packit |
1470ea |
around the entire thing.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
You next create a GtkEntry object and pack it into the box.
|
|
Packit |
1470ea |
The third and fourth arguments to gtk_box_pack_start specify that
|
|
Packit |
1470ea |
the entry shouldn't take up any extra space the box has available. The fourth
|
|
Packit |
1470ea |
argument is the amount of padding you want around the entry. In this case,
|
|
Packit |
1470ea |
you set the padding to zero, because you're allowing the box to handle all
|
|
Packit |
1470ea |
the padding.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Before you add a web view, you have to create a scrolled window to put it
|
|
Packit |
1470ea |
inside of. The scrolled window will place scrollbars on the right and bottom
|
|
Packit |
1470ea |
when necessary, and prevent your web view from filling your entire screen.
|
|
Packit |
1470ea |
This time, you pass TRUE and TRUE to
|
|
Packit |
1470ea |
gtk_box_pack_start to allow the scrolled window (and thus, the
|
|
Packit |
1470ea |
web view) to use any extra space available in the box.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Finally, you create a WebKitWebView and add it to the scrolled
|
|
Packit |
1470ea |
window. Then load a very basic HTML page into the web view by calling
|
|
Packit |
1470ea |
webkit_web_view_load_string with the following arguments:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<terms>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>WEBKIT_WEB_VIEW (view) </title>
|
|
Packit |
1470ea |
The view itself. Because view is typed as a
|
|
Packit |
1470ea |
GtkWidget* , you have to use WEBKIT_WEB_VIEW
|
|
Packit |
1470ea |
to safely cast the object.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>"<html><body></body></html>" </title>
|
|
Packit |
1470ea |
The simplest HTML file you could possibly write.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>"text/html" </title>
|
|
Packit |
1470ea |
The MIME type of the content you provided. In this case, you're
|
|
Packit |
1470ea |
using plain HTML.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>"UTF-8" </title>
|
|
Packit |
1470ea |
The character encoding of the content you provided. Although you only
|
|
Packit |
1470ea |
used ASCII characters, it's a good idea to specify UTF-8. UTF-8 is used
|
|
Packit |
1470ea |
as the default encoding throughout the GNOME platform.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
<item>
|
|
Packit |
1470ea |
<title>NULL </title>
|
|
Packit |
1470ea |
The base URI. You don't need it in this simple example, but you might
|
|
Packit |
1470ea |
want to provide a <sys>file:</sys> URI if you add images or other features
|
|
Packit |
1470ea |
where you want to use relative URI references.
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
</terms>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<note style="sidebar">
|
|
Packit |
1470ea |
Every time you add a widget, you have to call gtk_widget_show
|
|
Packit |
1470ea |
on it for it to be visible. If you call gtk_widget_show_all on
|
|
Packit |
1470ea |
a container widget like a GtkBox , GTK+ will automatically show
|
|
Packit |
1470ea |
all the widgets inside the container, to any depth. Sometimes you don't
|
|
Packit |
1470ea |
want to call gtk_widget_show_all , such as when you want to
|
|
Packit |
1470ea |
dynamically hide and show some widgets in response to events.
|
|
Packit |
1470ea |
</note>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Finally, you have to call gtk_widget_show_all on the box.
|
|
Packit |
1470ea |
Otherwise, none of the widgets you created will be visible. (The window is
|
|
Packit |
1470ea |
shown in the main function with gtk_widget_show .)
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Build and run the message board again. You should see a window with a text
|
|
Packit |
1470ea |
entry and a web view. It doesn't do anything yet because the text entry and
|
|
Packit |
1470ea |
the web view don't know anything about each other.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="signals">
|
|
Packit |
1470ea |
<title>Hook up signals</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Now you want to make the message board actually do something
|
|
Packit |
1470ea |
when you enter text into the text entry. To do this, connect a callback
|
|
Packit |
1470ea |
function to the activate signal of entry . GTK+
|
|
Packit |
1470ea |
emits the activate signal whenever the user presses
|
|
Packit |
1470ea |
<key>Enter</key> in the entry. Add the following into create_window ,
|
|
Packit |
1470ea |
anywhere after both entry and view have been defined:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), view);
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
You then have to actually define entry_activate_cb . Define
|
|
Packit |
1470ea |
it as follows, anywhere above create_window :
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static void
|
|
Packit |
1470ea |
entry_activate_cb (GtkEntry *entry, WebKitWebView *view)
|
|
Packit |
1470ea |
{
|
|
Packit |
1470ea |
WebKitDOMDocument *document;
|
|
Packit |
1470ea |
WebKitDOMElement *body, *div;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
document = webkit_web_view_get_dom_document (view);
|
|
Packit |
1470ea |
body = webkit_dom_document_query_selector (document, "body", NULL);
|
|
Packit |
1470ea |
div = webkit_dom_document_create_element (document, "div", NULL);
|
|
Packit |
1470ea |
webkit_dom_node_set_text_content (WEBKIT_DOM_NODE (div),
|
|
Packit |
1470ea |
gtk_entry_get_text (entry),
|
|
Packit |
1470ea |
NULL);
|
|
Packit |
1470ea |
webkit_dom_node_append_child (WEBKIT_DOM_NODE (body),
|
|
Packit |
1470ea |
WEBKIT_DOM_NODE (div),
|
|
Packit |
1470ea |
NULL);
|
|
Packit |
1470ea |
gtk_entry_set_text (entry, "");
|
|
Packit |
1470ea |
}
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The first thing you do is get a WebKitDOMDocument object
|
|
Packit |
1470ea |
that represents the HTML document displayed in view . The DOM
|
|
Packit |
1470ea |
classes and methods in WebKit allow you to inspect and manipulate the HTML
|
|
Packit |
1470ea |
document, and work very similarly to the DOM APIs you might already know
|
|
Packit |
1470ea |
from JavaScript.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Once you have the document, you want to get the body element
|
|
Packit |
1470ea |
so that you can add div elements to it. The
|
|
Packit |
1470ea |
webkit_dom_document_query_selector function lets you find an
|
|
Packit |
1470ea |
element in the document using CSS selectors. This keeps you from having to
|
|
Packit |
1470ea |
write tedious loops to traverse the document.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<comment>
|
|
Packit |
1470ea |
shaunm
|
|
Packit |
1470ea |
FIXME: Is this true? Does query_selector take CSS, CSSish, or what?
|
|
Packit |
1470ea |
</comment>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Next, you create a new div element to hold the message. Every
|
|
Packit |
1470ea |
element you create has to be attached to a document, so the function to create
|
|
Packit |
1470ea |
an element takes the WebKitDOMDocument as its first arguments.
|
|
Packit |
1470ea |
You then set the text content of the element to the contents of the text entry.
|
|
Packit |
1470ea |
Because gtk_entry_get_text returns a const gchar* ,
|
|
Packit |
1470ea |
you don't have to free the result.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<comment>
|
|
Packit |
1470ea |
shaunm
|
|
Packit |
1470ea |
Not passing the GError**, but we should give it a quick mention and
|
|
Packit |
1470ea |
link to somewhere that explains how GError-handling works.
|
|
Packit |
1470ea |
</comment>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Finally, you append the new div element to the body and
|
|
Packit |
1470ea |
clear out the text entry so you can type something new. Build and run the
|
|
Packit |
1470ea |
program again and test it for yourself.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="css">
|
|
Packit |
1470ea |
<title>Make it look better with CSS</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
At this point, your program is completely functional, but not very pretty.
|
|
Packit |
1470ea |
You can style the message display with CSS, just like you can with any other
|
|
Packit |
1470ea |
HTML page. There are many ways you could attach some CSS to the page: You
|
|
Packit |
1470ea |
could add it in the initial HTML document. You could inline it in the
|
|
Packit |
1470ea |
style attribute of the div elements. You could
|
|
Packit |
1470ea |
even programmatically construct it using the DOM APIs.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
In this tutorial, you'll attach the CSS using the user-stylesheet-uri
|
|
Packit |
1470ea |
property of the WebKitWebSetting object attached to your web view.
|
|
Packit |
1470ea |
In a more complete application, you would want to save and load your HTML file.
|
|
Packit |
1470ea |
Keeping the style information outside the actual HTML means that you can change
|
|
Packit |
1470ea |
the styling completely within your application, without having to change users'
|
|
Packit |
1470ea |
files. You would normally just install a file along with your application, but
|
|
Packit |
1470ea |
just to keep everything in one file for this demo, we'll use a trick called a
|
|
Packit |
1470ea |
data URI. First, define the CSS as a static string near the top of your file.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
static const guchar CSS[] =
|
|
Packit |
1470ea |
"body { margin: 0; padding: 0; }\n"
|
|
Packit |
1470ea |
"div { "
|
|
Packit |
1470ea |
" -webkit-border-radius: 2px;"
|
|
Packit |
1470ea |
" background: -webkit-gradient(linear, 0% 100%, 0% 0%,"
|
|
Packit |
1470ea |
" from(#f1f1f1), to(white));"
|
|
Packit |
1470ea |
" border: solid 1px #c6c6c6;"
|
|
Packit |
1470ea |
" -webkit-box-shadow: 0px 0px 2px #c6c6c6;"
|
|
Packit |
1470ea |
" margin: 12px; padding: 6px;"
|
|
Packit |
1470ea |
"}";
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
All you have in this example are div elements inside a
|
|
Packit |
1470ea |
body element. If you created more complicated HTML, you could
|
|
Packit |
1470ea |
use whatever CSS is necessary. In fact, if you're comfortable with CSS, you
|
|
Packit |
1470ea |
should trying changing this to something you like better.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
To apply the CSS, you set the user-stylesheet-uri in the
|
|
Packit |
1470ea |
create_window function, anywhere after view has
|
|
Packit |
1470ea |
already been defined.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<comment>shaunmg_base64_encode has bad args </comment>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
tmp = g_base64_encode (CSS, strlen((gchar *) CSS));
|
|
Packit |
1470ea |
css = g_strconcat ("data:text/css;charset=utf-8;base64,",
|
|
Packit |
1470ea |
tmp, NULL);
|
|
Packit |
1470ea |
g_object_set (webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view)),
|
|
Packit |
1470ea |
"user-stylesheet-uri", css, NULL);
|
|
Packit |
1470ea |
g_free (css);
|
|
Packit |
1470ea |
g_free (tmp);
|
|
Packit |
1470ea |
]]>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Also, make sure to add variable declarations for tmp
|
|
Packit |
1470ea |
and css to the top of create_window .
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
gchar *tmp, *css;
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
A data URI starts with <sys>data:</sys> and some information about
|
|
Packit |
1470ea |
the content type and how the data is encoded. The actual data follows after
|
|
Packit |
1470ea |
a comma, in this case encoded in Base64. Unlike other URI schemes like
|
|
Packit |
1470ea |
<sys>http:</sys>, <sys>ftp:</sys>, and <sys>file:</sys>, the <sys>data:</sys>
|
|
Packit |
1470ea |
URI scheme doesn't specify where to find a file to load. Rather, it gives
|
|
Packit |
1470ea |
the entire contents of the file.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
The code above first encodes your CSS definitions in Base64, then
|
|
Packit |
1470ea |
combines that with a fixed string to create a data URI. The
|
|
Packit |
1470ea |
g_strconcat function can take any number of string arguments
|
|
Packit |
1470ea |
and concatenate them all together, so you have to pass NULL
|
|
Packit |
1470ea |
as the final argument so it knows when to stop. And don't forget to free
|
|
Packit |
1470ea |
those temporary strings after you set the stylesheet property.
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
Build and run the program again. It should now work exactly the same
|
|
Packit |
1470ea |
as at the end of the last section, except the messages will be nicely
|
|
Packit |
1470ea |
styled with a border and a subtle background gradient.
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<section id="more">
|
|
Packit |
1470ea |
<title>Learn more</title>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
This tutorial showed you how to create a basic application using GTK+
|
|
Packit |
1470ea |
and WebKit, including showing a document and manipulating its contents.
|
|
Packit |
1470ea |
To create a real application, you probably want to do a little bit more.
|
|
Packit |
1470ea |
Try adding features on your own. Here are a few ideas:
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<list>
|
|
Packit |
1470ea |
<item>If you're comfortable with CSS, try changing the style of the
|
|
Packit |
1470ea |
message display. CSS is easy to get started with, but increasingly more
|
|
Packit |
1470ea |
powerful. There is a wealth of CSS tutorials on the Internet, and just
|
|
Packit |
1470ea |
about everything you can do on the web, you can do in this
|
|
Packit |
1470ea |
application.</item>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<item>Right now, you lose all your messages whenever you close the
|
|
Packit |
1470ea |
message board. Try saving the HTML contents after each post, and loading
|
|
Packit |
1470ea |
the saved file (if it exists) on startup.
|
|
Packit |
1470ea |
<comment>
|
|
Packit |
1470ea |
shaunmLink to method to get HTML from DOM and to
|
|
Packit |
1470ea |
GIO APIs.
|
|
Packit |
1470ea |
</comment></item>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<item>If you keep your messages around for a long time, you'll start
|
|
Packit |
1470ea |
wondering when you posted them. Add a timestamp to each message when it's
|
|
Packit |
1470ea |
posted. You'll probably want to create some additional child div
|
|
Packit |
1470ea |
elements with different classes that you can style in the CSS.
|
|
Packit |
1470ea |
<comment>shaunmLink to strftime or something </comment>
|
|
Packit |
1470ea |
</item>
|
|
Packit |
1470ea |
|
|
Packit |
1470ea |
<item>This program keeps messages around forever. Think about ways
|
|
Packit |
1470ea |
you could allow the user to delete messages. Perhaps you want messages
|
|
Packit |
1470ea |
to disappear automatically after they're too old, or after there are a
|
|
Packit |
1470ea |
certain number of messages before them. Or you could add a link in each
|
|
Packit |
1470ea |
message to delete it. You could even override the context menu when you
|
|
Packit |
1470ea |
right-click on a message. These features involve exploring WebKit's DOM
|
|
Packit |
1470ea |
API more.</item>
|
|
Packit |
1470ea |
</list>
|
|
Packit |
1470ea |
</section>
|
|
Packit |
1470ea |
</page>
|