In diesem Tutorial lernen Sie, wie:
How to display a web page with WebKit.
How to manipulate the contents of a web page using WebKit's DOM functions.
This tutorial assumes you are familiar with the C programming language and have a basic understanding of GTK+, including how to create and place widgets and how to connect callback functions to signals. See to learn the basics of GTK+.
The GNOME platform includes WebKitGTK+, built on top of the powerful WebKit HTML framework. WebKit is used throughout GNOME, not just to view web pages on the Internet, but also to create rich user interfaces that can be easily styled with CSS.
In this tutorial, you will create a simple message board using WebKit. The message board will allow you to enter some text and have it added to a list of messages in HTML. Before you begin, you need to set up a project in Anjuta.
In Anjuta, click
Select
Fill out your details on the
Disable the
You need to tell Anjuta you're using WebKitGTK+ on this project.
On the
After you finish the new project assistant, open the file
gtk/gtk.h
, add the following line:
#include <webkit/webkit.h>
Verify that everything works by building what you have so far.
Click
You should now be able to run the program. Click
Now that you can show a window, it's time to start working with WebKit.
For this tutorial, you'll create a text entry and a web view and pack
them both into a window. Find the function create_window
and
replace it with the following:
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;
}
You first create a GtkWindow
object and set its title and
default size. You also connect the gtk_main_quit
function to the
delete-event
signal. The delete-event
signal is
emitted when the window is closed. The gtk_main_quit
function is
part of GTK, and it quits the application.
You then create a vertical box and add it to the window. A window can only
hold a single child widget, so you need to use a box to add multiple widgets.
The second argument to gtk_box_new
sets the amount of padding
(in pixels) between each child, and the next line puts a six-pixel border
around the entire thing.
You next create a GtkEntry
object and pack it into the box.
The third and fourth arguments to gtk_box_pack_start
specify that
the entry shouldn't take up any extra space the box has available. The fourth
argument is the amount of padding you want around the entry. In this case,
you set the padding to zero, because you're allowing the box to handle all
the padding.
Before you add a web view, you have to create a scrolled window to put it
inside of. The scrolled window will place scrollbars on the right and bottom
when necessary, and prevent your web view from filling your entire screen.
This time, you pass TRUE
and TRUE
to
gtk_box_pack_start
to allow the scrolled window (and thus, the
web view) to use any extra space available in the box.
Finally, you create a WebKitWebView
and add it to the scrolled
window. Then load a very basic HTML page into the web view by calling
webkit_web_view_load_string
with the following arguments:
WEBKIT_WEB_VIEW (view)
The view itself. Because view
is typed as a
GtkWidget*
, you have to use WEBKIT_WEB_VIEW
to safely cast the object.
"<html><body></body></html>"
The simplest HTML file you could possibly write.
"text/html"
The MIME type of the content you provided. In this case, you're using plain HTML.
"UTF-8"
The character encoding of the content you provided. Although you only used ASCII characters, it's a good idea to specify UTF-8. UTF-8 is used as the default encoding throughout the GNOME platform.
NULL
The base URI. You don't need it in this simple example, but you might
want to provide a
Every time you add a widget, you have to call gtk_widget_show
on it for it to be visible. If you call gtk_widget_show_all
on
a container widget like a GtkBox
, GTK+ will automatically show
all the widgets inside the container, to any depth. Sometimes you don't
want to call gtk_widget_show_all
, such as when you want to
dynamically hide and show some widgets in response to events.
Finally, you have to call gtk_widget_show_all
on the box.
Otherwise, none of the widgets you created will be visible. (The window is
shown in the main
function with gtk_widget_show
.)
Build and run the message board again. You should see a window with a text entry and a web view. It doesn't do anything yet because the text entry and the web view don't know anything about each other.
Now you want to make the message board actually do something
when you enter text into the text entry. To do this, connect a callback
function to the activate
signal of entry
. GTK+
emits the activate
signal whenever the user presses
create_window
,
anywhere after both entry
and view
have been defined:
g_signal_connect (entry, "activate", G_CALLBACK (entry_activate_cb), view);
You then have to actually define entry_activate_cb
. Define
it as follows, anywhere above 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, "");
}
The first thing you do is get a WebKitDOMDocument
object
that represents the HTML document displayed in view
. The DOM
classes and methods in WebKit allow you to inspect and manipulate the HTML
document, and work very similarly to the DOM APIs you might already know
from JavaScript.
Once you have the document, you want to get the body
element
so that you can add div
elements to it. The
webkit_dom_document_query_selector
function lets you find an
element in the document using CSS selectors. This keeps you from having to
write tedious loops to traverse the document.
Next, you create a new div
element to hold the message. Every
element you create has to be attached to a document, so the function to create
an element takes the WebKitDOMDocument
as its first arguments.
You then set the text content of the element to the contents of the text entry.
Because gtk_entry_get_text
returns a const gchar*
,
you don't have to free the result.
Finally, you append the new div
element to the body and
clear out the text entry so you can type something new. Build and run the
program again and test it for yourself.
At this point, your program is completely functional, but not very pretty.
You can style the message display with CSS, just like you can with any other
HTML page. There are many ways you could attach some CSS to the page: You
could add it in the initial HTML document. You could inline it in the
style
attribute of the div
elements. You could
even programmatically construct it using the DOM APIs.
In this tutorial, you'll attach the CSS using the user-stylesheet-uri
property of the WebKitWebSetting
object attached to your web view.
In a more complete application, you would want to save and load your HTML file.
Keeping the style information outside the actual HTML means that you can change
the styling completely within your application, without having to change users'
files. You would normally just install a file along with your application, but
just to keep everything in one file for this demo, we'll use a trick called a
data URI. First, define the CSS as a static string near the top of your file.
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;"
"}";
All you have in this example are div
elements inside a
body
element. If you created more complicated HTML, you could
use whatever CSS is necessary. In fact, if you're comfortable with CSS, you
should trying changing this to something you like better.
To apply the CSS, you set the user-stylesheet-uri
in the
create_window
function, anywhere after view
has
already been defined.
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);
Also, make sure to add variable declarations for tmp
and css
to the top of create_window
.
gchar *tmp, *css;
A data URI starts with
The code above first encodes your CSS definitions in Base64, then
combines that with a fixed string to create a data URI. The
g_strconcat
function can take any number of string arguments
and concatenate them all together, so you have to pass NULL
as the final argument so it knows when to stop. And don't forget to free
those temporary strings after you set the stylesheet property.
Build and run the program again. It should now work exactly the same as at the end of the last section, except the messages will be nicely styled with a border and a subtle background gradient.
This tutorial showed you how to create a basic application using GTK+ and WebKit, including showing a document and manipulating its contents. To create a real application, you probably want to do a little bit more. Try adding features on your own. Here are a few ideas:
If you're comfortable with CSS, try changing the style of the message display. CSS is easy to get started with, but increasingly more powerful. There is a wealth of CSS tutorials on the Internet, and just about everything you can do on the web, you can do in this application.
Right now, you lose all your messages whenever you close the message board. Try saving the HTML contents after each post, and loading the saved file (if it exists) on startup.
If you keep your messages around for a long time, you'll start
wondering when you posted them. Add a timestamp to each message when it's
posted. You'll probably want to create some additional child div
elements with different classes that you can style in the CSS.
This program keeps messages around forever. Think about ways you could allow the user to delete messages. Perhaps you want messages to disappear automatically after they're too old, or after there are a certain number of messages before them. Or you could add a link in each message to delete it. You could even override the context menu when you right-click on a message. These features involve exploring WebKit's DOM API more.