summaryrefslogtreecommitdiff
path: root/frontends/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/gtk')
-rw-r--r--frontends/gtk/Makefile205
-rw-r--r--frontends/gtk/Makefile.defaults42
-rw-r--r--frontends/gtk/about.c157
-rw-r--r--frontends/gtk/about.h24
-rw-r--r--frontends/gtk/bitmap.c540
-rw-r--r--frontends/gtk/bitmap.h35
-rw-r--r--frontends/gtk/compat.c640
-rw-r--r--frontends/gtk/compat.h296
-rw-r--r--frontends/gtk/completion.c157
-rw-r--r--frontends/gtk/completion.h46
-rw-r--r--frontends/gtk/cookies.c219
-rw-r--r--frontends/gtk/cookies.h37
-rw-r--r--frontends/gtk/download.c865
-rw-r--r--frontends/gtk/download.h41
-rw-r--r--frontends/gtk/fetch.c260
-rw-r--r--frontends/gtk/fetch.h28
-rw-r--r--frontends/gtk/gdk.c124
-rw-r--r--frontends/gtk/gdk.h35
-rw-r--r--frontends/gtk/gettext.c43
-rw-r--r--frontends/gtk/gettext.h32
-rw-r--r--frontends/gtk/gui.c1161
-rw-r--r--frontends/gtk/gui.h45
-rw-r--r--frontends/gtk/history.c273
-rw-r--r--frontends/gtk/history.h39
-rw-r--r--frontends/gtk/hotlist.c280
-rw-r--r--frontends/gtk/hotlist.h40
-rw-r--r--frontends/gtk/layout_pango.c309
-rw-r--r--frontends/gtk/layout_pango.h43
-rw-r--r--frontends/gtk/login.c232
-rw-r--r--frontends/gtk/login.h31
-rw-r--r--frontends/gtk/menu.c585
-rw-r--r--frontends/gtk/menu.h227
-rw-r--r--frontends/gtk/options.h72
-rw-r--r--frontends/gtk/plotters.c538
-rw-r--r--frontends/gtk/plotters.h40
-rw-r--r--frontends/gtk/preferences.c1030
-rw-r--r--frontends/gtk/preferences.h28
-rw-r--r--frontends/gtk/print.c613
-rw-r--r--frontends/gtk/print.h50
l---------frontends/gtk/res/Messages1
l---------frontends/gtk/res/SearchEngines1
l---------frontends/gtk/res/adblock.css1
-rw-r--r--frontends/gtk/res/arrow_down_8x32.pngbin0 -> 206 bytes
l---------frontends/gtk/res/ca-bundle.txt1
-rw-r--r--frontends/gtk/res/cookies.gtk2.ui174
-rw-r--r--frontends/gtk/res/cookies.gtk3.ui206
l---------frontends/gtk/res/credits.html1
l---------frontends/gtk/res/de/welcome.html1
l---------frontends/gtk/res/default.css1
-rw-r--r--frontends/gtk/res/default.icobin0 -> 1406 bytes
-rw-r--r--frontends/gtk/res/downloads.gtk2.ui175
-rw-r--r--frontends/gtk/res/downloads.gtk3.ui175
l---------frontends/gtk/res/en/credits.html1
l---------frontends/gtk/res/en/licence.html1
l---------frontends/gtk/res/en/maps.html1
l---------frontends/gtk/res/en/welcome.html1
l---------frontends/gtk/res/favicon.png1
-rw-r--r--frontends/gtk/res/history.gtk2.ui242
-rw-r--r--frontends/gtk/res/history.gtk3.ui238
-rw-r--r--frontends/gtk/res/hotlist.gtk2.ui217
-rw-r--r--frontends/gtk/res/hotlist.gtk3.ui255
l---------frontends/gtk/res/icons1
l---------frontends/gtk/res/internal.css1
l---------frontends/gtk/res/it/credits.html1
l---------frontends/gtk/res/it/licence.html1
l---------frontends/gtk/res/it/welcome.html1
l---------frontends/gtk/res/ja/welcome.html1
-rw-r--r--frontends/gtk/res/languages261
l---------frontends/gtk/res/licence.html1
-rw-r--r--frontends/gtk/res/login.gtk2.ui223
-rw-r--r--frontends/gtk/res/login.gtk3.ui223
l---------frontends/gtk/res/maps.html1
-rw-r--r--frontends/gtk/res/menu_cursor.pngbin0 -> 255 bytes
-rw-r--r--frontends/gtk/res/menu_cursor.xbm6
-rw-r--r--frontends/gtk/res/menu_cursor_mask.xbm6
-rw-r--r--frontends/gtk/res/menu_cursor_mask.xpm22
-rw-r--r--frontends/gtk/res/messages.gresource.xml10
-rw-r--r--frontends/gtk/res/netsurf-16x16.xpm211
-rw-r--r--frontends/gtk/res/netsurf-gtk.desktop68
-rw-r--r--frontends/gtk/res/netsurf.gresource.xml70
-rw-r--r--frontends/gtk/res/netsurf.gtk2.ui212
-rw-r--r--frontends/gtk/res/netsurf.gtk3.ui207
l---------frontends/gtk/res/netsurf.png1
-rw-r--r--frontends/gtk/res/netsurf.xpm317
l---------frontends/gtk/res/nl/credits.html1
l---------frontends/gtk/res/nl/licence.html1
l---------frontends/gtk/res/nl/welcome.html1
-rw-r--r--frontends/gtk/res/options.gtk2.ui3004
-rw-r--r--frontends/gtk/res/options.gtk3.ui3057
-rw-r--r--frontends/gtk/res/password.gtk2.ui415
-rw-r--r--frontends/gtk/res/password.gtk3.ui415
l---------frontends/gtk/res/quirks.css1
-rw-r--r--frontends/gtk/res/ssl.gtk2.ui202
-rw-r--r--frontends/gtk/res/ssl.gtk3.ui181
-rw-r--r--frontends/gtk/res/tabcontents.gtk2.ui92
-rw-r--r--frontends/gtk/res/tabcontents.gtk3.ui92
-rw-r--r--frontends/gtk/res/throbber/throbber0.pngbin0 -> 507 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber1.pngbin0 -> 802 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber2.pngbin0 -> 790 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber3.pngbin0 -> 808 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber4.pngbin0 -> 797 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber5.pngbin0 -> 797 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber6.pngbin0 -> 819 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber7.pngbin0 -> 792 bytes
-rw-r--r--frontends/gtk/res/throbber/throbber8.pngbin0 -> 814 bytes
-rw-r--r--frontends/gtk/res/toolbar.gtk2.ui189
-rw-r--r--frontends/gtk/res/toolbar.gtk3.ui189
-rw-r--r--frontends/gtk/res/viewdata.gtk2.ui204
-rw-r--r--frontends/gtk/res/viewdata.gtk3.ui239
-rw-r--r--frontends/gtk/res/warning.gtk2.ui77
-rw-r--r--frontends/gtk/res/warning.gtk3.ui77
l---------frontends/gtk/res/welcome.html1
-rw-r--r--frontends/gtk/resources.c600
-rw-r--r--frontends/gtk/resources.h109
-rw-r--r--frontends/gtk/scaffolding.c2811
-rw-r--r--frontends/gtk/scaffolding.h252
-rw-r--r--frontends/gtk/schedule.c136
-rw-r--r--frontends/gtk/schedule.h26
-rw-r--r--frontends/gtk/search.c245
-rw-r--r--frontends/gtk/search.h36
-rw-r--r--frontends/gtk/selection.c96
-rw-r--r--frontends/gtk/selection.h24
-rw-r--r--frontends/gtk/sexy_icon_entry.c982
-rw-r--r--frontends/gtk/sexy_icon_entry.h100
-rw-r--r--frontends/gtk/ssl_cert.c135
-rw-r--r--frontends/gtk/ssl_cert.h36
-rw-r--r--frontends/gtk/tabs.c416
-rw-r--r--frontends/gtk/tabs.h42
-rw-r--r--frontends/gtk/throbber.c91
-rw-r--r--frontends/gtk/throbber.h35
-rw-r--r--frontends/gtk/toolbar.c1416
-rw-r--r--frontends/gtk/toolbar.h96
-rw-r--r--frontends/gtk/treeview.c586
-rw-r--r--frontends/gtk/treeview.h38
-rw-r--r--frontends/gtk/viewdata.c990
-rw-r--r--frontends/gtk/viewdata.h48
-rw-r--r--frontends/gtk/viewsource.c82
-rw-r--r--frontends/gtk/viewsource.h25
-rw-r--r--frontends/gtk/warn.h32
-rw-r--r--frontends/gtk/window.c1337
-rw-r--r--frontends/gtk/window.h48
141 files changed, 32309 insertions, 0 deletions
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
new file mode 100644
index 000000000..7f8ffc16a
--- /dev/null
+++ b/frontends/gtk/Makefile
@@ -0,0 +1,205 @@
+#
+# Makefile for NetSurf GTK target
+#
+# This file is part of NetSurf
+#
+# ----------------------------------------------------------------------------
+# GTK flag setup (using pkg-config)
+# ----------------------------------------------------------------------------
+
+# define additional CFLAGS and LDFLAGS requirements for pkg-configed libs here
+NETSURF_FEATURE_RSVG_CFLAGS := -DWITH_RSVG
+NETSURF_FEATURE_VIDEO_CFLAGS := -DWITH_VIDEO
+
+$(eval $(call pkg_config_find_and_add_enabled,RSVG,librsvg-2.0,SVG))
+$(eval $(call pkg_config_find_and_add_enabled,VIDEO,gstreamer-0.10,Video))
+
+# GTK and GLIB flags to disable depricated usage
+GTKDEPFLAGS := -DG_DISABLE_SINGLE_INCLUDES \
+ -DG_DISABLE_DEPRECATED \
+ -DGTK_DISABLE_SINGLE_INCLUDES \
+ -DGTK_MULTIHEAD_SAFE \
+ -DPANGO_DISABLE_DEPRECATED
+
+# later editions of gtk 2 deprecate interfaces we rely upon for cursors
+# -DGDK_PIXBUF_DISABLE_DEPRECATED
+
+# libsexy currently means we cannot enable this
+# -DGDK_DISABLE_DEPRECATED
+
+# gtk3 is depricating interfaces we use a lot
+ifeq ($(NETSURF_GTK_MAJOR),2)
+GTKDEPFLAGS += -DGTK_DISABLE_DEPRECATED
+endif
+
+
+GTKCFLAGS := -std=c99 -Dgtk -Dnsgtk -g \
+ $(GTKDEPFLAGS) \
+ -D_BSD_SOURCE \
+ -D_DEFAULT_SOURCE \
+ -D_XOPEN_SOURCE=600 \
+ -D_POSIX_C_SOURCE=200809L \
+ -D_NETBSD_SOURCE \
+ -DGTK_RESPATH=\"$(NETSURF_GTK_RESOURCES)\"
+
+# non optional pkg-configed libs
+$(eval $(call pkg_config_find_and_add,gtk+-$(NETSURF_GTK_MAJOR).0,GTK-$(NETSURF_GTK_MAJOR)))
+$(eval $(call pkg_config_find_and_add,gthread-2.0,GThread2))
+$(eval $(call pkg_config_find_and_add,gmodule-2.0,GModule2))
+
+
+CFLAGS += $(GTKCFLAGS)
+LDFLAGS += -lm
+
+# ---------------------------------------------------------------------------
+# Target setup
+# ---------------------------------------------------------------------------
+
+# Path to GTK resources
+NSGTK_RESOURCES_DIR := $(FRONTEND_RESOURCES_DIR)
+
+# The gtk binary target
+EXETARGET := nsgtk
+
+# The filter and target for split messages
+MESSAGES_FILTER=gtk
+MESSAGES_TARGET=$(NSGTK_RESOURCES_DIR)
+
+# ---------------------------------------------------------------------------
+# Windows flag setup
+# ---------------------------------------------------------------------------
+
+ifeq ($(HOST),Windows_NT)
+ CFLAGS += -U__STRICT_ANSI__
+endif
+
+# ----------------------------------------------------------------------------
+# Builtin resource handling
+# ----------------------------------------------------------------------------
+
+# builtin resource sources
+S_RESOURCE :=
+
+# Glib prior to 2.32 does not have GResource handling.
+#
+# This uses pkg-config to check for the minimum required version for
+# this feature in a way similar to the pkg_config_find_and_add_enabled
+# macro. Note we check for gmodule-2.0 which is a specific part of
+# glib we require.
+#
+# It would be nice if we could check for this functionality rather
+# than "knowing" the version but there does not appear to be a simple
+# way to implement that.
+#
+NETSURF_FEATURE_GRESOURCE_AVAILABLE := $(shell $(PKG_CONFIG) --atleast-version=2.32 gmodule-2.0 && echo yes)
+ifneq (,$(filter $(NETSURF_USE_GRESOURCE),AUTO YES))
+ifeq ($(NETSURF_FEATURE_GRESOURCE_AVAILABLE),yes)
+
+# Gresource use has been enabled
+NETSURF_FEATURE_GRESOURCE_ENABLED := yes
+
+#resource compiler tool
+GLIB_COMPILE_RESOURCES := glib-compile-resources
+CFLAGS += -DWITH_GRESOURCE
+
+NETSURF_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/netsurf.gresource.xml
+MESSAGES_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/messages.gresource.xml
+
+# generate the netsurf gresource source files
+$(OBJROOT)/netsurf_gresource.c: $(NETSURF_GRESOURCE_XML) $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir $(NSGTK_RESOURCES_DIR) --generate-dependencies $(NETSURF_GRESOURCE_XML))
+ $(VQ)echo "GRESORCE: $<"
+ $(Q)$(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir $(NSGTK_RESOURCES_DIR) --target=$@ $<
+
+S_RESOURCE += $(OBJROOT)/netsurf_gresource.c
+
+# generate the messages gresource source file
+$(OBJROOT)/messages_gresource.c: $(MESSAGES_GRESOURCE_XML) $(addsuffix /Messages,$(addprefix $(MESSAGES_TARGET)/,$(MESSAGES_LANGUAGES)))
+ $(VQ)echo "GRESORCE: $<"
+ $(Q)$(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir $(NSGTK_RESOURCES_DIR) --target=$@ $<
+
+S_RESOURCE += $(OBJROOT)/messages_gresource.c
+
+
+endif
+endif
+
+# Build pixbufs as inlines if enabled
+ifneq (,$(filter $(NETSURF_USE_INLINE_PIXBUF),AUTO YES))
+ifneq ($(NETSURF_FEATURE_GRESOURCE_ENABLED),yes)
+
+CFLAGS += -DWITH_BUILTIN_PIXBUF
+
+GTK_IMAGE_favicon := favicon.png
+GTK_IMAGE_netsurf := netsurf.xpm
+GTK_IMAGE_menu_cursor := menu_cursor.png
+
+# 1: input file
+# 2: output file
+# 3: bitmap name
+define convert_image
+
+# add converted pixbuf to builtin resource sources
+S_RESOURCE += $(2)
+
+$(2): $(1)
+ $(VQ)echo " INLINE: ${3}"
+ $(Q)echo "#include <gdk-pixbuf/gdk-pixdata.h>" > $(2)
+ $(Q)gdk-pixbuf-csource --extern --raw --name=$(3) $(1) >> $(2) || \
+ ( rm -f $(2) && false )
+
+endef
+
+$(eval $(foreach V,$(filter GTK_IMAGE_%,$(.VARIABLES)),$(call convert_image,$(addprefix $(NSGTK_RESOURCES_DIR)/,$($(V))),$(OBJROOT)/$(patsubst GTK_IMAGE_%,%,$(V)).c,$(patsubst GTK_IMAGE_%,%,$(V))_pixdata)))
+endif
+endif
+
+# ----------------------------------------------------------------------------
+# Source file setup
+# ----------------------------------------------------------------------------
+
+# S_FRONTEND are sources purely for the GTK frontend
+S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c \
+ treeview.c scaffolding.c gdk.c completion.c login.c throbber.c \
+ selection.c history.c window.c fetch.c download.c menu.c \
+ print.c search.c tabs.c toolbar.c gettext.c \
+ compat.c cookies.c hotlist.c viewdata.c viewsource.c \
+ preferences.c about.c ssl_cert.c resources.c
+
+# This is the final source build list
+# Note this is deliberately *not* expanded here as common and image
+# are not yet available
+SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_RESOURCE) $(S_FRONTEND)
+
+# ----------------------------------------------------------------------------
+# Install target
+# ----------------------------------------------------------------------------
+
+GTK_RESOURCES_LIST := \
+ languages SearchEngines toolbarIndices ca-bundle.txt \
+ default.css adblock.css quirks.css internal.css \
+ credits.html licence.html welcome.html maps.html Messages \
+ default.ico favicon.png netsurf.png netsurf.xpm netsurf-16x16.xpm \
+ arrow_down_8x32.png
+
+GTK_RESOURCES_LIST := \
+ $(addprefix $(NSGTK_RESOURCES_DIR)/, $(GTK_RESOURCES_LIST)) \
+ $(wildcard $(NSGTK_RESOURCES_DIR)/*.gtk$(NETSURF_GTK_MAJOR).ui)
+
+# translations with more than just Messages files
+GTK_TRANSLATIONS_HTML := de en fr it ja nl
+
+install-gtk:
+ $(Q)mkdir -p $(DESTDIR)$(NETSURF_GTK_BIN)
+ $(Q)install nsgtk $(DESTDIR)$(NETSURF_GTK_BIN)netsurf
+ $(Q)mkdir -p $(DESTDIR)$(NETSURF_GTK_RESOURCES)icons
+ $(Q)install -m 0644 $(NSGTK_RESOURCES_DIR)/icons/*.png $(DESTDIR)$(NETSURF_GTK_RESOURCES)/icons
+ $(Q)mkdir -p $(DESTDIR)$(NETSURF_GTK_RESOURCES)throbber
+ $(Q)install -m 0644 $(NSGTK_RESOURCES_DIR)/throbber/*.png $(DESTDIR)$(NETSURF_GTK_RESOURCES)/throbber
+ $(Q)tar -c -h -C $(NSGTK_RESOURCES_DIR) -f - $(GTK_TRANSLATIONS_HTML) | tar -xv -C $(DESTDIR)$(NETSURF_GTK_RESOURCES) -f -
+ $(Q)install -m 0644 $(GTK_RESOURCES_LIST) $(DESTDIR)$(NETSURF_GTK_RESOURCES)
+
+# ----------------------------------------------------------------------------
+# Package target
+# ----------------------------------------------------------------------------
+
+package-gtk:
diff --git a/frontends/gtk/Makefile.defaults b/frontends/gtk/Makefile.defaults
new file mode 100644
index 000000000..fc352a020
--- /dev/null
+++ b/frontends/gtk/Makefile.defaults
@@ -0,0 +1,42 @@
+# ----------------------------------------------------------------------------
+# GTK-specific options
+# ----------------------------------------------------------------------------
+
+# Where to search for NetSurf's resources after looking in ~/.netsurf and
+# $NETSURFRES. It must have a trailing /
+NETSURF_GTK_RESOURCES := $(PREFIX)/share/netsurf/:./frontends/gtk/res/
+
+# Where to install the netsurf binary
+NETSURF_GTK_BIN := $(PREFIX)/bin/
+
+# Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_RSVG := AUTO
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := AUTO
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := AUTO
+
+# Enable the use of GLib compiled in resource handling. This requires
+# GLib 2.32 or later
+# Valid options: YES, NO, AUTO
+NETSURF_USE_GRESOURCE := AUTO
+
+# Enable the use of compiled in inline pixbuf. This is depricated
+# since GLib 2.32. The automatic selection is disabled if GRESOURCE
+# handling is enabled
+# Valid options: YES, NO, AUTO
+NETSURF_USE_INLINE_PIXBUF := AUTO
+
+# Enable building the source object cache filesystem based backing store.
+NETSURF_FS_BACKING_STORE := YES
+
+# Set default GTK version to build for (2 or 3)
+NETSURF_GTK_MAJOR ?= 2
+
+# Optimisation levels
+CFLAGS += -O2
diff --git a/frontends/gtk/about.c b/frontends/gtk/about.c
new file mode 100644
index 000000000..d57afea7f
--- /dev/null
+++ b/frontends/gtk/about.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file gtk/about.c
+ *
+ * Implementation of gtk about dialog.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+#include "utils/nsurl.h"
+#include "desktop/browser.h"
+#include "desktop/version.h"
+
+#include "gtk/warn.h"
+#include "gtk/compat.h"
+#include "gtk/about.h"
+
+#define ABOUT_RESPONSE_ID_LICENCE 1
+#define ABOUT_RESPONSE_ID_CREDITS 2
+
+
+/**
+ * Open a url and a browser window/tab
+ *
+ * \param url_text The text of the url to open
+ */
+static void about_open(const char *url_text)
+{
+ nsurl *url;
+ nserror ret;
+ enum browser_window_create_flags flags = BW_CREATE_HISTORY;
+
+ if (nsoption_bool(show_single_tab) == true) {
+ flags |= BW_CREATE_TAB;
+ }
+
+ ret = nsurl_create(url_text, &url);
+ if (ret == NSERROR_OK) {
+ ret = browser_window_create(flags, url, NULL, NULL, NULL);
+ nsurl_unref(url);
+ }
+
+ if (ret != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(ret), 0);
+ }
+}
+
+/**
+ * About dialog response handling.
+ *
+ * \param dialog The dialog widget
+ * \param response_id The response ID from the user clicking.
+ * \param user_data The value from the signal connection.
+ */
+static void
+nsgtk_about_dialog_response(GtkDialog *dialog,
+ gint response_id,
+ gpointer user_data)
+{
+ switch (response_id) {
+
+ case ABOUT_RESPONSE_ID_LICENCE:
+ about_open("about:credits");
+ break;
+
+ case ABOUT_RESPONSE_ID_CREDITS:
+ about_open("about:licence");
+ break;
+ }
+
+ /* close about dialog */
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+void nsgtk_about_dialog_init(GtkWindow *parent)
+{
+ GtkWidget *dialog, *vbox, *label;
+ gchar *name_string;
+ GList *pixbufs;
+
+ /* Create the dialog */
+ dialog = gtk_dialog_new_with_buttons("About NetSurf",
+ parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ "Licence", ABOUT_RESPONSE_ID_LICENCE,
+ "Credits", ABOUT_RESPONSE_ID_CREDITS,
+ "Close", GTK_RESPONSE_CANCEL,
+ NULL, NULL);
+
+ vbox = nsgtk_vbox_new(FALSE, 8);
+
+ gtk_box_pack_start(GTK_BOX(nsgtk_dialog_get_content_area(GTK_DIALOG(dialog))), vbox, TRUE, TRUE, 0);
+
+ /* NetSurf icon */
+ pixbufs = gtk_window_get_default_icon_list();
+ if (pixbufs != NULL) {
+ GtkWidget *image;
+
+ image = nsgtk_image_new_from_pixbuf_icon(GDK_PIXBUF(g_list_nth_data(pixbufs, 0)),
+ GTK_ICON_SIZE_DIALOG);
+ g_list_free(pixbufs);
+
+ gtk_box_pack_start(GTK_BOX(vbox), image, FALSE, FALSE, 0);
+ }
+
+ /* version string */
+ label = gtk_label_new (NULL);
+ name_string = g_markup_printf_escaped("<span size=\"xx-large\" weight=\"bold\">NetSurf %s</span>", netsurf_version);
+ gtk_label_set_markup (GTK_LABEL (label), name_string);
+ g_free(name_string);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ label = gtk_label_new(messages_get("AboutDesc"));
+ gtk_label_set_selectable(GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ label = gtk_label_new(messages_get("NetSurfCopyright"));
+ gtk_label_set_selectable(GTK_LABEL(label), TRUE);
+ gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+ gtk_box_pack_start(GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ /* Remove separator */
+ nsgtk_dialog_set_has_separator(GTK_DIALOG (dialog), FALSE);
+
+ /* Ensure that the dialog box response is processed. */
+ g_signal_connect_swapped(dialog,
+ "response",
+ G_CALLBACK(nsgtk_about_dialog_response),
+ dialog);
+
+ /* Add the label, and show everything we've added to the dialog. */
+ gtk_widget_show_all(dialog);
+}
diff --git a/frontends/gtk/about.h b/frontends/gtk/about.h
new file mode 100644
index 000000000..bf3c9f58d
--- /dev/null
+++ b/frontends/gtk/about.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2008 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_GTK_ABOUT_H
+#define NETSURF_GTK_ABOUT_H
+
+void nsgtk_about_dialog_init(GtkWindow *parent);
+
+#endif
diff --git a/frontends/gtk/bitmap.c b/frontends/gtk/bitmap.c
new file mode 100644
index 000000000..f8dcf1d17
--- /dev/null
+++ b/frontends/gtk/bitmap.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Generic bitmap handling (GDK / GTK+ implementation).
+ *
+ * This implements the interface given by desktop/bitmap.h using GdkPixbufs.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "content/content.h"
+#include "image/bitmap.h"
+#include "desktop/plotters.h"
+
+#include "gtk/scaffolding.h"
+#include "gtk/plotters.h"
+#include "gtk/bitmap.h"
+
+
+/**
+ * Create a bitmap.
+ *
+ * \param width width of image in pixels
+ * \param height width of image in pixels
+ * \param state a flag word indicating the initial state
+ * \return an opaque struct bitmap, or NULL on memory exhaustion
+ */
+static void *bitmap_create(int width, int height, unsigned int state)
+{
+ struct bitmap *gbitmap;
+
+ gbitmap = calloc(1, sizeof(struct bitmap));
+ if (gbitmap != NULL) {
+ if ((state & BITMAP_OPAQUE) != 0) {
+ gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
+ } else {
+ gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ }
+
+ if (cairo_surface_status(gbitmap->surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(gbitmap->surface);
+ free(gbitmap);
+ gbitmap = NULL;
+ }
+ }
+
+ return gbitmap;
+}
+
+
+/**
+ * Sets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param opaque whether the bitmap should be plotted opaque
+ */
+static void bitmap_set_opaque(void *vbitmap, bool opaque)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ cairo_format_t fmt;
+ cairo_surface_t *nsurface = NULL;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ if (opaque == false) {
+ /* opaque to transparent */
+ nsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ cairo_image_surface_get_width(gbitmap->surface),
+ cairo_image_surface_get_height(gbitmap->surface));
+
+ }
+
+ } else {
+ if (opaque == true) {
+ /* transparent to opaque */
+ nsurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ cairo_image_surface_get_width(gbitmap->surface),
+ cairo_image_surface_get_height(gbitmap->surface));
+
+ }
+ }
+
+ if (nsurface != NULL) {
+ if (cairo_surface_status(nsurface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(nsurface);
+ } else {
+ memcpy(cairo_image_surface_get_data(nsurface),
+ cairo_image_surface_get_data(gbitmap->surface),
+ cairo_image_surface_get_stride(gbitmap->surface) * cairo_image_surface_get_height(gbitmap->surface));
+ cairo_surface_destroy(gbitmap->surface);
+ gbitmap->surface = nsurface;
+
+ cairo_surface_mark_dirty(gbitmap->surface);
+
+ }
+
+ }
+}
+
+
+/**
+ * Tests whether a bitmap has an opaque alpha channel
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return whether the bitmap is opaque
+ */
+static bool bitmap_test_opaque(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ unsigned char *pixels;
+ int pcount;
+ int ploop;
+
+ assert(gbitmap);
+
+ pixels = cairo_image_surface_get_data(gbitmap->surface);
+
+ pcount = cairo_image_surface_get_stride(gbitmap->surface) *
+ cairo_image_surface_get_height(gbitmap->surface);
+
+ for (ploop = 3; ploop < pcount; ploop += 4) {
+ if (pixels[ploop] != 0xff) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Gets whether a bitmap should be plotted opaque
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static bool bitmap_get_opaque(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ cairo_format_t fmt;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ return true;
+ }
+
+ return false;
+}
+
+
+/**
+ * Return a pointer to the pixel data in a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return pointer to the pixel buffer
+ *
+ * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end
+ * of rows. The width of a row in bytes is given by bitmap_get_rowstride().
+ */
+static unsigned char *bitmap_get_buffer(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ int pixel_loop;
+ int pixel_count;
+ uint8_t *pixels;
+ uint32_t t, r, g, b;
+ cairo_format_t fmt;
+
+ assert(gbitmap);
+
+ cairo_surface_flush(gbitmap->surface);
+ pixels = cairo_image_surface_get_data(gbitmap->surface);
+
+ if (!gbitmap->converted)
+ return pixels;
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+ pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
+ cairo_image_surface_get_height(gbitmap->surface);
+
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ /* Opaque image */
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+ /* Cairo surface is ARGB, written in native endian */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ b = pixels[4 * pixel_loop + 0];
+ g = pixels[4 * pixel_loop + 1];
+ r = pixels[4 * pixel_loop + 2];
+ t = pixels[4 * pixel_loop + 3];
+#else
+ t = pixels[4 * pixel_loop + 0];
+ r = pixels[4 * pixel_loop + 1];
+ g = pixels[4 * pixel_loop + 2];
+ b = pixels[4 * pixel_loop + 3];
+#endif
+
+ /* Core bitmaps always have a component order of rgba,
+ * regardless of system endianness */
+ pixels[4 * pixel_loop + 0] = r;
+ pixels[4 * pixel_loop + 1] = g;
+ pixels[4 * pixel_loop + 2] = b;
+ pixels[4 * pixel_loop + 3] = t;
+ }
+ } else {
+ /* Alpha image: de-multiply alpha */
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ b = pixels[4 * pixel_loop + 0];
+ g = pixels[4 * pixel_loop + 1];
+ r = pixels[4 * pixel_loop + 2];
+ t = pixels[4 * pixel_loop + 3];
+#else
+ t = pixels[4 * pixel_loop + 0];
+ r = pixels[4 * pixel_loop + 1];
+ g = pixels[4 * pixel_loop + 2];
+ b = pixels[4 * pixel_loop + 3];
+#endif
+
+ if (t != 0) {
+ r = (r << 8) / t;
+ g = (g << 8) / t;
+ b = (b << 8) / t;
+
+ r = (r > 255) ? 255 : r;
+ g = (g > 255) ? 255 : g;
+ b = (b > 255) ? 255 : b;
+ } else {
+ r = g = b = 0;
+ }
+
+ pixels[4 * pixel_loop + 0] = r;
+ pixels[4 * pixel_loop + 1] = g;
+ pixels[4 * pixel_loop + 2] = b;
+ pixels[4 * pixel_loop + 3] = t;
+ }
+ }
+
+ gbitmap->converted = false;
+
+ return (unsigned char *) pixels;
+}
+
+
+/**
+ * Find the width of a pixel row in bytes.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return width of a pixel row in the bitmap
+ */
+static size_t bitmap_get_rowstride(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return cairo_image_surface_get_stride(gbitmap->surface);
+}
+
+
+/**
+ * Find the bytes per pixel of a bitmap
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \return bytes per pixel
+ */
+static size_t bitmap_get_bpp(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return 4;
+}
+
+
+
+/**
+ * Free a bitmap.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static void bitmap_destroy(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ if (gbitmap->surface != NULL) {
+ cairo_surface_destroy(gbitmap->surface);
+ }
+ if (gbitmap->scsurface != NULL) {
+ cairo_surface_destroy(gbitmap->scsurface);
+ }
+ free(gbitmap);
+}
+
+
+/**
+ * Save a bitmap in the platform's native format.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ * \param path pathname for file
+ * \param flags modify the behaviour of the save
+ * \return true on success, false on error and error reported
+ */
+static bool bitmap_save(void *vbitmap, const char *path, unsigned flags)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return false;
+}
+
+
+/**
+ * The bitmap image has changed, so flush any persistant cache.
+ *
+ * \param vbitmap a bitmap, as returned by bitmap_create()
+ */
+static void bitmap_modified(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ int pixel_loop;
+ int pixel_count;
+ uint8_t *pixels;
+ uint32_t t, r, g, b;
+ cairo_format_t fmt;
+
+ assert(gbitmap);
+
+ fmt = cairo_image_surface_get_format(gbitmap->surface);
+
+ pixel_count = cairo_image_surface_get_width(gbitmap->surface) *
+ cairo_image_surface_get_height(gbitmap->surface);
+ pixels = cairo_image_surface_get_data(gbitmap->surface);
+
+ if (gbitmap->converted) {
+ cairo_surface_mark_dirty(gbitmap->surface);
+ return;
+ }
+
+ if (fmt == CAIRO_FORMAT_RGB24) {
+ /* Opaque image */
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+ /* Core bitmaps always have a component order of rgba,
+ * regardless of system endianness */
+ r = pixels[4 * pixel_loop + 0];
+ g = pixels[4 * pixel_loop + 1];
+ b = pixels[4 * pixel_loop + 2];
+ t = pixels[4 * pixel_loop + 3];
+
+ /* Cairo surface is ARGB, written in native endian */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ pixels[4 * pixel_loop + 0] = b;
+ pixels[4 * pixel_loop + 1] = g;
+ pixels[4 * pixel_loop + 2] = r;
+ pixels[4 * pixel_loop + 3] = t;
+#else
+ pixels[4 * pixel_loop + 0] = t;
+ pixels[4 * pixel_loop + 1] = r;
+ pixels[4 * pixel_loop + 2] = g;
+ pixels[4 * pixel_loop + 3] = b;
+#endif
+ }
+ } else {
+ /* Alpha image: pre-multiply alpha */
+ for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) {
+ r = pixels[4 * pixel_loop + 0];
+ g = pixels[4 * pixel_loop + 1];
+ b = pixels[4 * pixel_loop + 2];
+ t = pixels[4 * pixel_loop + 3];
+
+ if (t != 0) {
+ r = ((r * (t + 1)) >> 8) & 0xff;
+ g = ((g * (t + 1)) >> 8) & 0xff;
+ b = ((b * (t + 1)) >> 8) & 0xff;
+ } else {
+ r = g = b = 0;
+ }
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ pixels[4 * pixel_loop + 0] = b;
+ pixels[4 * pixel_loop + 1] = g;
+ pixels[4 * pixel_loop + 2] = r;
+ pixels[4 * pixel_loop + 3] = t;
+#else
+ pixels[4 * pixel_loop + 0] = t;
+ pixels[4 * pixel_loop + 1] = r;
+ pixels[4 * pixel_loop + 2] = g;
+ pixels[4 * pixel_loop + 3] = b;
+#endif
+ }
+ }
+
+ cairo_surface_mark_dirty(gbitmap->surface);
+
+ gbitmap->converted = true;
+}
+
+/* exported interface documented in gtk/bitmap.h */
+int nsgtk_bitmap_get_width(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return cairo_image_surface_get_width(gbitmap->surface);
+}
+
+/* exported interface documented in gtk/bitmap.h */
+int nsgtk_bitmap_get_height(void *vbitmap)
+{
+ struct bitmap *gbitmap = (struct bitmap *)vbitmap;
+ assert(gbitmap);
+
+ return cairo_image_surface_get_height(gbitmap->surface);
+}
+
+/**
+ * Render content into a bitmap.
+ *
+ * \param bitmap The bitmap to draw to
+ * \param content The content to render
+ * \return true on success and bitmap updated else false
+ */
+static nserror
+bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content)
+{
+ cairo_surface_t *dsurface = bitmap->surface;
+ cairo_surface_t *surface;
+ cairo_t *old_cr;
+ gint dwidth, dheight;
+ int cwidth, cheight;
+ struct redraw_context ctx = {
+ .interactive = false,
+ .background_images = true,
+ .plot = &nsgtk_plotters
+ };
+
+ assert(content);
+ assert(bitmap);
+
+ dwidth = cairo_image_surface_get_width(dsurface);
+ dheight = cairo_image_surface_get_height(dsurface);
+
+ /* Calculate size of buffer to render the content into */
+ /* Get the width from the content width, unless it exceeds 1024,
+ * in which case we use 1024. This means we never create excessively
+ * large render buffers for huge contents, which would eat memory and
+ * cripple performance.
+ */
+ cwidth = min(max(content_get_width(content), dwidth), 1024);
+
+ /* The height is set in proportion with the width, according to the
+ * aspect ratio of the required thumbnail. */
+ cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth;
+
+ /* Create surface to render into */
+ surface = cairo_surface_create_similar(dsurface, CAIRO_CONTENT_COLOR_ALPHA, cwidth, cheight);
+
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(surface);
+ return false;
+ }
+
+ old_cr = current_cr;
+ current_cr = cairo_create(surface);
+
+ /* render the content */
+ content_scaled_redraw(content, cwidth, cheight, &ctx);
+
+ cairo_destroy(current_cr);
+ current_cr = old_cr;
+
+ cairo_t *cr = cairo_create(dsurface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale (cr, (double)dwidth / cwidth, (double)dheight / cheight);
+ cairo_set_source_surface (cr, surface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0 alpha,
+ * which would occur with the default EXTEND_NONE. Use
+ * EXTEND_PAD for 1.2 or newer (2)
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ cairo_surface_destroy(surface);
+
+ return NSERROR_OK;
+}
+
+
+static struct gui_bitmap_table bitmap_table = {
+ .create = bitmap_create,
+ .destroy = bitmap_destroy,
+ .set_opaque = bitmap_set_opaque,
+ .get_opaque = bitmap_get_opaque,
+ .test_opaque = bitmap_test_opaque,
+ .get_buffer = bitmap_get_buffer,
+ .get_rowstride = bitmap_get_rowstride,
+ .get_width = nsgtk_bitmap_get_width,
+ .get_height = nsgtk_bitmap_get_height,
+ .get_bpp = bitmap_get_bpp,
+ .save = bitmap_save,
+ .modified = bitmap_modified,
+ .render = bitmap_render,
+};
+
+struct gui_bitmap_table *nsgtk_bitmap_table = &bitmap_table;
diff --git a/frontends/gtk/bitmap.h b/frontends/gtk/bitmap.h
new file mode 100644
index 000000000..0f46d19a8
--- /dev/null
+++ b/frontends/gtk/bitmap.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2006 Daniel Silverstone <dsilvers@digital-scurf.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NS_GTK_BITMAP_H
+#define NS_GTK_BITMAP_H
+
+#include <cairo.h>
+
+extern struct gui_bitmap_table *nsgtk_bitmap_table;
+
+struct bitmap {
+ cairo_surface_t *surface; /* original cairo surface */
+ cairo_surface_t *scsurface; /* scaled surface */
+ bool converted; /** set if the surface data has been converted */
+};
+
+int nsgtk_bitmap_get_width(void *vbitmap);
+int nsgtk_bitmap_get_height(void *vbitmap);
+
+#endif /* NS_GTK_BITMAP_H */
diff --git a/frontends/gtk/compat.c b/frontends/gtk/compat.c
new file mode 100644
index 000000000..4c5524b0e
--- /dev/null
+++ b/frontends/gtk/compat.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright 2010 Rob Kendrick <rjek@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Compatibility functions for older GTK versions implementation
+ */
+
+#include <stdint.h>
+
+#include "gtk/compat.h"
+
+#ifdef _SEXY_ICON_ENTRY_H_
+#include "gtk/sexy_icon_entry.c"
+
+/*
+ * exported interface documented in gtk/compat.h
+ *
+ * Only required for the lib sexy interface before 2.16
+ */
+GtkStateType nsgtk_widget_get_state(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,18,0)
+ return gtk_widget_get_state(widget);
+#else
+ return GTK_WIDGET_STATE(widget);
+#endif
+}
+
+
+#endif
+
+void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus)
+{
+#if GTK_CHECK_VERSION(2,22,0)
+ gtk_widget_set_can_focus(widget, can_focus);
+#else
+ if (can_focus == TRUE)
+ GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
+ else
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_FOCUS);
+#endif
+}
+
+gboolean nsgtk_widget_has_focus(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,20,0)
+ return gtk_widget_has_focus(widget);
+#else
+ return GTK_WIDGET_HAS_FOCUS(widget);
+#endif
+}
+
+gboolean nsgtk_widget_get_visible(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,20,0)
+ return gtk_widget_get_visible(widget);
+#else
+ return GTK_WIDGET_VISIBLE(widget);
+#endif
+}
+
+gboolean nsgtk_widget_get_realized(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,20,0)
+ return gtk_widget_get_realized(widget);
+#else
+ return GTK_WIDGET_REALIZED(widget);
+#endif
+}
+
+gboolean nsgtk_widget_get_mapped(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,20,0)
+ return gtk_widget_get_mapped(widget);
+#else
+ return GTK_WIDGET_MAPPED(widget);
+#endif
+}
+
+gboolean nsgtk_widget_is_drawable(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,18,0)
+ return gtk_widget_is_drawable(widget);
+#else
+ return GTK_WIDGET_DRAWABLE(widget);
+#endif
+}
+
+void nsgtk_dialog_set_has_separator(GtkDialog *dialog, gboolean setting)
+{
+#if GTK_CHECK_VERSION(2,21,8)
+ /* Deprecated */
+#else
+ gtk_dialog_set_has_separator(dialog, setting);
+#endif
+}
+
+GtkWidget *nsgtk_combo_box_text_new(void)
+{
+#if GTK_CHECK_VERSION(2,24,0)
+ return gtk_combo_box_text_new();
+#else
+ return gtk_combo_box_new_text();
+#endif
+}
+
+void nsgtk_combo_box_text_append_text(GtkWidget *combo_box, const gchar *text)
+{
+#if GTK_CHECK_VERSION(2,24,0)
+ gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), text);
+#else
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), text);
+#endif
+
+}
+
+gchar *nsgtk_combo_box_text_get_active_text(GtkWidget *combo_box)
+{
+#if GTK_CHECK_VERSION(2,24,0)
+ return gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo_box));
+#else
+ return gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo_box));
+#endif
+}
+
+GtkWidget *nsgtk_entry_new(void)
+{
+#if GTK_CHECK_VERSION(2,16,0)
+ return gtk_entry_new();
+#else
+ return GTK_WIDGET(sexy_icon_entry_new());
+#endif
+}
+
+void nsgtk_entry_set_icon_from_pixbuf(GtkWidget *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkPixbuf *pixbuf)
+{
+#if GTK_CHECK_VERSION(2,16,0)
+ gtk_entry_set_icon_from_pixbuf(GTK_ENTRY(entry), icon_pos, pixbuf);
+#else
+ GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(pixbuf));
+
+ if (image != NULL) {
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ (SexyIconEntryPosition)icon_pos,
+ image);
+
+ g_object_unref(image);
+ }
+
+#endif
+}
+
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_entry_set_icon_from_stock(GtkWidget *entry,
+ GtkEntryIconPosition icon_pos,
+ const gchar *id)
+{
+#ifdef NSGTK_USE_ICON_NAME
+ gtk_entry_set_icon_from_icon_name(GTK_ENTRY(entry), icon_pos, id);
+#else
+#if GTK_CHECK_VERSION(2,16,0)
+ gtk_entry_set_icon_from_stock(GTK_ENTRY(entry), icon_pos, id);
+#else
+ GtkImage *image = GTK_IMAGE(gtk_image_new_from_stock(id,
+ GTK_ICON_SIZE_LARGE_TOOLBAR));
+
+ if (image != NULL) {
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ (SexyIconEntryPosition)icon_pos,
+ image);
+ g_object_unref(image);
+ }
+#endif
+#endif
+}
+
+
+/* exported interface documented in gtk/compat.h */
+GtkWidget *nsgtk_image_new_from_stock(const gchar *id, GtkIconSize size)
+{
+#ifdef NSGTK_USE_ICON_NAME
+ return gtk_image_new_from_icon_name(id, size);
+#else
+ return gtk_image_new_from_stock(id, size);
+#endif
+}
+
+
+/* exported interface documented in gtk/compat.h */
+GtkWidget *nsgtk_button_new_from_stock(const gchar *stock_id)
+{
+#ifdef NSGTK_USE_ICON_NAME
+ return gtk_button_new_with_label(stock_id);
+#else
+ return gtk_button_new_from_stock(stock_id);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+gboolean nsgtk_stock_lookup(const gchar *stock_id, GtkStockItem *item)
+{
+#ifdef NSGTK_USE_ICON_NAME
+ return FALSE;
+#else
+ return gtk_stock_lookup(stock_id, item);
+#endif
+}
+
+
+void nsgtk_widget_override_background_color(GtkWidget *widget,
+ GtkStateFlags state,
+ uint16_t a,
+ uint16_t r,
+ uint16_t g,
+ uint16_t b)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ GdkRGBA colour;
+ colour.alpha = (double)a / 0xffff;
+ colour.red = (double)r / 0xffff;
+ colour.green = (double)g / 0xffff;
+ colour.blue = (double)b / 0xffff;
+ gtk_widget_override_background_color(widget, state, &colour);
+#else
+ GdkColor colour;
+ colour.pixel = a;
+ colour.red = r;
+ colour.green = g;
+ colour.blue = b;
+ gtk_widget_modify_bg(widget, state, &colour );
+#endif
+}
+
+GtkAdjustment *nsgtk_layout_get_vadjustment(GtkLayout *layout)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(layout));
+#else
+ return gtk_layout_get_vadjustment(layout);
+#endif
+}
+
+GtkAdjustment *nsgtk_layout_get_hadjustment(GtkLayout *layout)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_scrollable_get_hadjustment(GTK_SCROLLABLE(layout));
+#else
+ return gtk_layout_get_hadjustment(layout);
+#endif
+}
+
+static void nsgtk_layout_set_adjustment_step_increment(GtkAdjustment *adj,
+ int value)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ gtk_adjustment_set_step_increment(adj, value);
+#else
+ adj->step_increment = value;
+#endif
+}
+
+void nsgtk_layout_set_hadjustment(GtkLayout *layout, GtkAdjustment *adj)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_scrollable_set_hadjustment(GTK_SCROLLABLE(layout), adj);
+#else
+ gtk_layout_set_hadjustment(layout, adj);
+#endif
+ nsgtk_layout_set_adjustment_step_increment(adj, 8);
+}
+
+void nsgtk_layout_set_vadjustment(GtkLayout *layout, GtkAdjustment *adj)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_scrollable_set_vadjustment(GTK_SCROLLABLE(layout), adj);
+#else
+ gtk_layout_set_vadjustment(layout, adj);
+#endif
+ nsgtk_layout_set_adjustment_step_increment(adj, 8);
+}
+
+GtkWidget *nsgtk_hbox_new(gboolean homogeneous, gint spacing)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_box_new(GTK_ORIENTATION_HORIZONTAL, spacing);
+#else
+ return gtk_hbox_new(homogeneous, spacing);
+#endif
+}
+
+GtkWidget *nsgtk_vbox_new(gboolean homogeneous, gint spacing)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing);
+#else
+ return gtk_vbox_new(homogeneous, spacing);
+#endif
+}
+
+GtkStateFlags nsgtk_widget_get_state_flags(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_widget_get_state_flags(widget);
+#else
+#if GTK_CHECK_VERSION(2,18,0)
+ return gtk_widget_get_state(widget);
+#else
+ return 0; /* FIXME */
+#endif
+#endif
+}
+
+GtkStyleContext *nsgtk_widget_get_style_context(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_widget_get_style_context(widget);
+#else
+ return widget->style;
+#endif
+}
+
+const PangoFontDescription* nsgtk_style_context_get_font(GtkStyleContext *style,
+ GtkStateFlags state)
+{
+#if GTK_CHECK_VERSION(3,8,0)
+ const PangoFontDescription* fontdesc = NULL;
+ gtk_style_context_get(style, state, GTK_STYLE_PROPERTY_FONT, &fontdesc, NULL);
+ return fontdesc;
+#else
+#if GTK_CHECK_VERSION(3,0,0)
+ return gtk_style_context_get_font(style, state);
+#else
+ return style->font_desc;
+#endif
+#endif
+}
+
+gulong nsgtk_connect_draw_event(GtkWidget *widget,
+ GCallback callback,
+ gpointer g)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ return g_signal_connect(G_OBJECT(widget), "draw", callback, g);
+#else
+ return g_signal_connect(G_OBJECT(widget), "expose_event", callback, g);
+#endif
+}
+
+void nsgdk_cursor_unref(GdkCursor *cursor)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ g_object_unref(cursor);
+#else
+ gdk_cursor_unref(cursor);
+#endif
+}
+
+void nsgtk_widget_modify_font(GtkWidget *widget,
+ PangoFontDescription *font_desc)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+/* FIXME */
+ return;
+#else
+ gtk_widget_modify_font(widget, font_desc);
+#endif
+}
+
+GdkWindow *nsgtk_widget_get_window(GtkWidget *widget)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_widget_get_window(widget);
+#else
+ return widget->window;
+#endif
+}
+
+GtkWidget *nsgtk_dialog_get_content_area(GtkDialog *dialog)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_dialog_get_content_area(dialog);
+#else
+ return dialog->vbox;
+#endif
+}
+
+gboolean nsgtk_show_uri(GdkScreen *screen,
+ const gchar *uri,
+ guint32 timestamp,
+ GError **error)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_show_uri(screen, uri, timestamp, error);
+#else
+ return FALSE; /* FIXME */
+#endif
+}
+
+GdkWindow *nsgtk_layout_get_bin_window(GtkLayout *layout)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_layout_get_bin_window(layout);
+#else
+ return layout->bin_window;
+#endif
+}
+
+gdouble nsgtk_adjustment_get_step_increment(GtkAdjustment *adjustment)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_adjustment_get_step_increment(adjustment);
+#else
+ return adjustment->step_increment;
+#endif
+}
+
+gdouble nsgtk_adjustment_get_upper(GtkAdjustment *adjustment)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_adjustment_get_upper(adjustment);
+#else
+ return adjustment->upper;
+#endif
+}
+
+gdouble nsgtk_adjustment_get_lower(GtkAdjustment *adjustment)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_adjustment_get_lower(adjustment);
+#else
+ return adjustment->lower;
+#endif
+}
+
+gdouble nsgtk_adjustment_get_page_increment(GtkAdjustment *adjustment)
+{
+#if GTK_CHECK_VERSION(2,14,0)
+ return gtk_adjustment_get_page_increment(adjustment);
+#else
+ return adjustment->page_increment;
+#endif
+}
+
+void nsgtk_widget_get_allocation(GtkWidget *widget, GtkAllocation *allocation)
+{
+#if GTK_CHECK_VERSION(2,18,0)
+ gtk_widget_get_allocation(widget, allocation);
+#else
+ allocation->x = widget->allocation.x;
+ allocation->y = widget->allocation.y;
+ allocation->width = widget->allocation.width;
+ allocation->height = widget->allocation.height;
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+GtkWidget *nsgtk_image_new_from_pixbuf_icon(GdkPixbuf *pixbuf, GtkIconSize size)
+{
+#if GTK_CHECK_VERSION(3,10,0)
+ return gtk_image_new_from_pixbuf(pixbuf);
+#else
+ GtkIconSet *icon_set;
+ GtkWidget *image;
+
+ icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
+
+ image = gtk_image_new_from_icon_set(icon_set, size);
+
+ gtk_icon_set_unref(icon_set);
+
+ return image;
+#endif
+}
+
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_window_set_opacity(GtkWindow *window, gdouble opacity)
+{
+#if GTK_CHECK_VERSION(3,8,0)
+ gtk_widget_set_opacity(GTK_WIDGET(window), opacity);
+#else
+ gtk_window_set_opacity(window, opacity);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_scrolled_window_add_with_viewport(GtkScrolledWindow *window,
+ GtkWidget *child)
+{
+#if GTK_CHECK_VERSION(3,8,0)
+ gtk_container_add(GTK_CONTAINER(window), child);
+#else
+ gtk_scrolled_window_add_with_viewport(window, child);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+GtkWidget *nsgtk_image_menu_item_new_with_mnemonic(const gchar *label)
+{
+#if GTK_CHECK_VERSION(3,10,0)
+ return gtk_menu_item_new_with_mnemonic(label);
+#else
+ return gtk_image_menu_item_new_with_mnemonic(label);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_image_menu_item_set_image(GtkWidget *image_menu_item, GtkWidget *image)
+{
+#if !GTK_CHECK_VERSION(3,10,0)
+ gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(image_menu_item), image);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+gboolean nsgtk_icon_size_lookup_for_settings(GtkSettings *settings,
+ GtkIconSize size,
+ gint *width,
+ gint *height)
+{
+#if GTK_CHECK_VERSION(3,10,0)
+ return gtk_icon_size_lookup(size, width, height);
+#else
+ return gtk_icon_size_lookup_for_settings(settings, size, width, height);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_widget_set_alignment(GtkWidget *widget, GtkAlign halign, GtkAlign valign)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_set_halign(widget, halign);
+ gtk_widget_set_valign(widget, valign);
+#else
+ gfloat x, y;
+ switch(halign) {
+ case GTK_ALIGN_START:
+ x = 0.0;
+ break;
+
+ case GTK_ALIGN_END:
+ x = 1.0;
+ break;
+
+ default:
+ x = 0.5;
+ break;
+ }
+
+ switch(valign) {
+ case GTK_ALIGN_START:
+ y = 0.0;
+ break;
+
+ case GTK_ALIGN_END:
+ y = 1.0;
+ break;
+
+ default:
+ y = 0.5;
+ break;
+ }
+
+ gtk_misc_set_alignment(GTK_MISC(widget), x, y);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+void nsgtk_widget_set_margins(GtkWidget *widget, gint hmargin, gint vmargin)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+#if GTK_CHECK_VERSION(3,12,0)
+ gtk_widget_set_margin_start(widget, hmargin);
+ gtk_widget_set_margin_end(widget, hmargin);
+#else
+ gtk_widget_set_margin_left(widget, hmargin);
+ gtk_widget_set_margin_right(widget, hmargin);
+#endif
+ gtk_widget_set_margin_top(widget, vmargin);
+ gtk_widget_set_margin_bottom(widget, vmargin);
+#else
+ gtk_misc_set_padding(GTK_MISC(widget), hmargin, vmargin);
+#endif
+}
+
+/* exported interface documented in gtk/compat.h */
+guint
+nsgtk_builder_add_from_resource(GtkBuilder *builder,
+ const gchar *resource_path,
+ GError **error)
+{
+ guint ret;
+
+#ifdef WITH_GRESOURCE
+#if GTK_CHECK_VERSION(3,4,0)
+ ret = gtk_builder_add_from_resource(builder, resource_path, error);
+#else
+ GBytes *data;
+ const gchar *buffer;
+ gsize buffer_length;
+
+ g_assert(error && *error == NULL);
+
+ data = g_resources_lookup_data(resource_path, 0, error);
+ if (data == NULL) {
+ return 0;
+ }
+
+ buffer_length = 0;
+ buffer = g_bytes_get_data(data, &buffer_length);
+ g_assert(buffer != NULL);
+
+ ret = gtk_builder_add_from_string(builder, buffer, buffer_length, error);
+
+ g_bytes_unref(data);
+#endif
+#else
+ ret = 0; /* return an error as GResource not supported before GLIB 2.32 */
+#endif
+ return ret;
+}
diff --git a/frontends/gtk/compat.h b/frontends/gtk/compat.h
new file mode 100644
index 000000000..9554b0cba
--- /dev/null
+++ b/frontends/gtk/compat.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2010 Rob Kendrick <rjek@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Compatibility functions for older GTK versions (interface)
+ */
+
+#ifndef NETSURF_GTK_COMPAT_H_
+#define NETSURF_GTK_COMPAT_H_
+
+#include <stdint.h>
+
+#include <gtk/gtk.h>
+
+/* gtk 3.10 depricated the use of stock names */
+#if GTK_CHECK_VERSION(3,10,0)
+#define NSGTK_USE_ICON_NAME
+#else
+#undef NSGTK_USE_ICON_NAME
+#endif
+
+/* icon names instead of stock */
+#ifdef NSGTK_USE_ICON_NAME
+#define NSGTK_STOCK_ADD "list-add"
+#define NSGTK_STOCK_CANCEL "_Cancel"
+#define NSGTK_STOCK_CLEAR "edit-clear"
+#define NSGTK_STOCK_CLOSE "window-close"
+#define NSGTK_STOCK_FIND "edit-find"
+#define NSGTK_STOCK_GO_BACK "go-previous"
+#define NSGTK_STOCK_GO_FORWARD "go-next"
+#define NSGTK_STOCK_HOME "go-home"
+#define NSGTK_STOCK_INFO "dialog-information"
+#define NSGTK_STOCK_REFRESH "view-refresh"
+#define NSGTK_STOCK_SAVE "document-save"
+#define NSGTK_STOCK_SAVE_AS "document-save-as"
+#define NSGTK_STOCK_STOP "process-stop"
+#define NSGTK_STOCK_OK "_OK"
+#define NSGTK_STOCK_OPEN "_Open"
+#else
+#define NSGTK_STOCK_ADD GTK_STOCK_ADD
+#define NSGTK_STOCK_CANCEL GTK_STOCK_CANCEL
+#define NSGTK_STOCK_CLEAR GTK_STOCK_CLEAR
+#define NSGTK_STOCK_CLOSE GTK_STOCK_CLOSE
+#define NSGTK_STOCK_FIND GTK_STOCK_FIND
+#define NSGTK_STOCK_GO_BACK GTK_STOCK_GO_BACK
+#define NSGTK_STOCK_GO_FORWARD GTK_STOCK_GO_FORWARD
+#define NSGTK_STOCK_HOME GTK_STOCK_HOME
+#define NSGTK_STOCK_INFO GTK_STOCK_INFO
+#define NSGTK_STOCK_REFRESH GTK_STOCK_REFRESH
+#define NSGTK_STOCK_SAVE GTK_STOCK_SAVE
+#define NSGTK_STOCK_SAVE_AS GTK_STOCK_SAVE_AS
+#define NSGTK_STOCK_STOP GTK_STOCK_STOP
+#define NSGTK_STOCK_OK GTK_STOCK_OK
+#define NSGTK_STOCK_OPEN GTK_STOCK_OPEN
+#endif
+
+/* widget alignment only available since 3.0 */
+#if !GTK_CHECK_VERSION(3,0,0)
+typedef enum {
+ GTK_ALIGN_FILL,
+ GTK_ALIGN_START,
+ GTK_ALIGN_END,
+ GTK_ALIGN_CENTER,
+ GTK_ALIGN_BASELINE
+} GtkAlign;
+#endif
+
+/**
+ * Set the alignment of a widget.
+ *
+ * sets both the horizontal and vertical alignement of a widget
+ *
+ * @note this type of alignemnt was not available prior to GTK 3.0 so
+ * we emulate it using gtk_misc_set_alignment.
+ *
+ * \param widget The widget to set alignent on.
+ * \param halign The horizontal alignment to set.
+ * \param valign The vertical alignment to set
+ */
+void nsgtk_widget_set_alignment(GtkWidget *widget, GtkAlign halign, GtkAlign valign);
+
+/**
+ * Set the margins of a widget
+ *
+ * Sets the margin all round a widget.
+ *
+ * @note this type of margin was not available prior to GTK 3.0 so
+ * we emulate it using gtk_misc_set_padding.
+ *
+ * \param widget The widget to set alignent on.
+ * \param hmargin The horizontal margin.
+ * \param vmargin The vertical margin.
+ */
+void nsgtk_widget_set_margins(GtkWidget *widget, gint hmargin, gint vmargin);
+
+void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus);
+gboolean nsgtk_widget_has_focus(GtkWidget *widget);
+gboolean nsgtk_widget_get_visible(GtkWidget *widget);
+gboolean nsgtk_widget_get_realized(GtkWidget *widget);
+gboolean nsgtk_widget_get_mapped(GtkWidget *widget);
+gboolean nsgtk_widget_is_drawable(GtkWidget *widget);
+void nsgtk_dialog_set_has_separator(GtkDialog *dialog, gboolean setting);
+GtkWidget *nsgtk_combo_box_text_new(void);
+void nsgtk_combo_box_text_append_text(GtkWidget *combo_box, const gchar *text);
+gchar *nsgtk_combo_box_text_get_active_text(GtkWidget *combo_box);
+
+/**
+ * creates a new image widget of an appropriate icon size from a pixbuf.
+ *
+ * \param pixbuf The pixbuf to use as a source.
+ * \param size The size of icon to create
+ * \return An image widget.
+ */
+GtkWidget *nsgtk_image_new_from_pixbuf_icon(GdkPixbuf *pixbuf, GtkIconSize size);
+
+/* GTK prior to 2.16 needs the sexy interface for icons */
+#if !GTK_CHECK_VERSION(2,16,0)
+
+#include "gtk/sexy_icon_entry.h"
+
+typedef enum {
+ GTK_ENTRY_ICON_PRIMARY = SEXY_ICON_ENTRY_PRIMARY,
+ GTK_ENTRY_ICON_SECONDARY = SEXY_ICON_ENTRY_SECONDARY
+} GtkEntryIconPosition;
+
+GtkStateType nsgtk_widget_get_state(GtkWidget *widget);
+
+#endif
+
+#if GTK_CHECK_VERSION (2, 90, 7)
+#define GDK_KEY(symbol) GDK_KEY_##symbol
+#else
+#include <gdk/gdkkeysyms.h>
+#define GDK_KEY(symbol) GDK_##symbol
+#endif
+
+#if !GTK_CHECK_VERSION(3,0,0)
+typedef GtkStateType GtkStateFlags;
+typedef GtkStyle GtkStyleContext;
+
+#if GTK_CHECK_VERSION(2,22,0)
+enum {
+ GTK_IN_DESTRUCTION = 1 << 0,
+};
+#define GTK_OBJECT_FLAGS(obj) (GTK_OBJECT (obj)->flags)
+#endif
+
+#define gtk_widget_in_destruction(widget) \
+ (GTK_OBJECT_FLAGS(GTK_OBJECT(widget)) & GTK_IN_DESTRUCTION)
+
+#endif
+
+
+/**
+ * Sets the icon shown in the entry at the specified position from a
+ * stock image.
+ *
+ * Compatability interface for original deprecated in GTK 3.10
+ *
+ * \param entry The entry widget to set the icon on.
+ * \param icon_pos The position of the icon.
+ * \param stock_id the name of the stock item.
+ */
+void nsgtk_entry_set_icon_from_stock(GtkWidget *entry, GtkEntryIconPosition icon_pos, const gchar *stock_id);
+
+/**
+ * Creates a GtkImage displaying a stock icon.
+ *
+ * Compatability interface for original deprecated in GTK 3.10
+ *
+ * \param stock_id the name of the stock item.
+ * \param size The size of icon to create.
+ * \return The created image widget or NULL on error
+ */
+GtkWidget *nsgtk_image_new_from_stock(const gchar *stock_id, GtkIconSize size);
+
+/**
+ * Creates a new GtkButton containing the image and text from a stock item.
+ *
+ * Compatability interface for original deprecated in GTK 3.10
+ *
+ * \param stock_id the name of the stock item
+ */
+GtkWidget *nsgtk_button_new_from_stock(const gchar *stock_id);
+
+/**
+ * Fills item with the registered values for stock_id.
+ *
+ * Compatability interface for original deprecated in GTK 3.10
+ *
+ * \param stock_id the name of the stock item.
+ * \param item The structure to update if the stock_id was known.
+ * \return TRUE if stock_id was known.
+ */
+gboolean nsgtk_stock_lookup(const gchar *stock_id, GtkStockItem *item);
+
+void nsgtk_window_set_opacity(GtkWindow *window, gdouble opacity);
+
+void nsgtk_scrolled_window_add_with_viewport(GtkScrolledWindow *window, GtkWidget *child);
+
+GtkWidget *nsgtk_entry_new(void);
+
+void nsgtk_entry_set_icon_from_pixbuf(GtkWidget *entry, GtkEntryIconPosition icon_pos, GdkPixbuf *pixbuf);
+
+void nsgtk_widget_override_background_color(GtkWidget *widget, GtkStateFlags state, uint16_t a, uint16_t r, uint16_t g, uint16_t b);
+GtkWidget* nsgtk_hbox_new(gboolean homogeneous, gint spacing);
+GtkWidget* nsgtk_vbox_new(gboolean homogeneous, gint spacing);
+GtkStateFlags nsgtk_widget_get_state_flags(GtkWidget *widget);
+GtkStyleContext* nsgtk_widget_get_style_context(GtkWidget *widget);
+const PangoFontDescription* nsgtk_style_context_get_font(GtkStyleContext *style, GtkStateFlags state);
+gulong nsgtk_connect_draw_event(GtkWidget *widget, GCallback callback, gpointer g);
+void nsgdk_cursor_unref(GdkCursor *cursor);
+void nsgtk_widget_modify_font(GtkWidget *widget, PangoFontDescription *font_desc);
+GdkWindow *nsgtk_widget_get_window(GtkWidget *widget);
+GtkWidget *nsgtk_dialog_get_content_area(GtkDialog *dialog);
+gboolean nsgtk_show_uri(GdkScreen *screen, const gchar *uri, guint32 timestamp, GError **error);
+GdkWindow *nsgtk_layout_get_bin_window(GtkLayout *layout);
+void nsgtk_widget_get_allocation(GtkWidget *widget, GtkAllocation *allocation);
+
+gboolean nsgtk_icon_size_lookup_for_settings (GtkSettings *settings, GtkIconSize size, gint *width, gint *height);
+
+GtkAdjustment *nsgtk_layout_get_vadjustment(GtkLayout *layout);
+GtkAdjustment *nsgtk_layout_get_hadjustment(GtkLayout *layout);
+void nsgtk_layout_set_hadjustment(GtkLayout *layout, GtkAdjustment *adj);
+void nsgtk_layout_set_vadjustment(GtkLayout *layout, GtkAdjustment *adj);
+gdouble nsgtk_adjustment_get_step_increment(GtkAdjustment *adjustment);
+gdouble nsgtk_adjustment_get_upper(GtkAdjustment *adjustment);
+gdouble nsgtk_adjustment_get_lower(GtkAdjustment *adjustment);
+gdouble nsgtk_adjustment_get_page_increment(GtkAdjustment *adjustment);
+
+/* menu compatability */
+
+/**
+ * Creates a new GtkImageMenuItem containing a label.
+ *
+ * Compatability interface for original deprecated in GTK 3.10.
+ * @note post 3.10 this creates a GtkMenuItem.
+ *
+ * \param label The text of the button, with an underscore in front of
+ * the mnemonic character.
+ * \return a new GtkMenuItem
+ */
+GtkWidget *nsgtk_image_menu_item_new_with_mnemonic(const gchar *label);
+
+/**
+ * Sets the image of image_menu_item to the given widget.
+ *
+ * Compatability interface for original deprecated in GTK 3.10.
+ * @note post 3.10 this is empty as menu creation generates GtkMenuItem.
+ *
+ * \param image_menu_item The image menu entry item.
+ * \param image The image to set.
+ */
+void nsgtk_image_menu_item_set_image(GtkWidget *image_menu_item, GtkWidget *image);
+
+
+/**
+ * Parses a resource file containing a GtkBuilder UI definition and
+ * merges it with the current contents of builder.
+ *
+ * Compatability interface as this did not exist prior to GTK 3.4
+ *
+ * GTK prior to 3.4 can have the resources in a GResource but
+ * gtk_builder cannot directly instantiate from them
+ *
+ * GTK 3.4 onwards can use gtk_builder_add_from_resource() to add
+ * directly from resources. The gtk_builder_new_ type operations
+ * cannot be used because they are only available post 3.10 and handle
+ * all errors by aborting the application
+ *
+ * @note prior to GLIB 2.32 resources did not exist and this wrapper
+ * returns the error code.
+ *
+ * \param builder a GtkBuilder
+ * \param resource_path the path of the resource file to parse
+ * \param error return location for an error, or NULL.
+ * \return A positive value on success, 0 if an error occurred.
+ */
+guint nsgtk_builder_add_from_resource(GtkBuilder *builder, const gchar *resource_path, GError **error);
+
+#endif /* NETSURF_GTK_COMPAT_H */
diff --git a/frontends/gtk/completion.c b/frontends/gtk/completion.c
new file mode 100644
index 000000000..6dde728b3
--- /dev/null
+++ b/frontends/gtk/completion.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of url entry completion.
+ */
+
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+#include "content/urldb.h"
+#include "desktop/searchweb.h"
+#include "desktop/browser.h"
+
+#include "gtk/warn.h"
+#include "gtk/window.h"
+#include "gtk/completion.h"
+
+GtkListStore *nsgtk_completion_list;
+
+/**
+ * completion row matcher
+ */
+static gboolean nsgtk_completion_match(GtkEntryCompletion *completion,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ /* the completion list is modified to only contain valid
+ * entries so this simply returns TRUE to indicate all rows
+ * are in the list should be shown.
+ */
+ return TRUE;
+
+}
+
+
+/**
+ * callback for each entry to add to completion list
+ */
+static bool
+nsgtk_completion_udb_callback(nsurl *url, const struct url_data *data)
+{
+ GtkTreeIter iter;
+
+ if (data->visits != 0) {
+ gtk_list_store_append(nsgtk_completion_list, &iter);
+ gtk_list_store_set(nsgtk_completion_list, &iter, 0,
+ nsurl_access(url), -1);
+ }
+ return true;
+}
+
+/**
+ * event handler for when a completion suggestion is selected.
+ */
+static gboolean
+nsgtk_completion_match_select(GtkEntryCompletion *widget,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GValue value = {0, };
+ struct nsgtk_scaffolding *g = user_data;
+ struct browser_window *bw = nsgtk_get_browser_window(nsgtk_scaffolding_top_level(g));
+ nserror ret;
+ nsurl *url;
+
+ gtk_tree_model_get_value(model, iter, 0, &value);
+
+ ret = search_web_omni(g_value_get_string(&value),
+ SEARCH_WEB_OMNI_NONE,
+ &url);
+
+ g_value_unset(&value);
+
+ if (ret == NSERROR_OK) {
+ ret = browser_window_navigate(bw,
+ url, NULL, BW_NAVIGATE_HISTORY,
+ NULL, NULL, NULL);
+ nsurl_unref(url);
+ }
+ if (ret != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(ret), 0);
+ }
+
+ return TRUE;
+}
+
+/* exported interface documented in completion.h */
+void nsgtk_completion_init(void)
+{
+ nsgtk_completion_list = gtk_list_store_new(1, G_TYPE_STRING);
+
+}
+
+/* exported interface documented in completion.h */
+gboolean nsgtk_completion_update(GtkEntry *entry)
+{
+ gtk_list_store_clear(nsgtk_completion_list);
+
+ if (nsoption_bool(url_suggestion) == true) {
+ urldb_iterate_partial(gtk_entry_get_text(entry),
+ nsgtk_completion_udb_callback);
+ }
+
+ return TRUE;
+}
+
+/* exported interface documented in completion.h */
+GtkEntryCompletion *nsgtk_url_entry_completion_new(struct nsgtk_scaffolding *gs)
+{
+ GtkEntryCompletion *completion;
+
+ completion = gtk_entry_completion_new();
+ gtk_entry_completion_set_match_func(completion,
+ nsgtk_completion_match, NULL, NULL);
+
+ gtk_entry_completion_set_model(completion,
+ GTK_TREE_MODEL(nsgtk_completion_list));
+
+ gtk_entry_completion_set_text_column(completion, 0);
+
+ gtk_entry_completion_set_minimum_key_length(completion, 1);
+
+ /* enable popup for completion */
+ gtk_entry_completion_set_popup_completion(completion, TRUE);
+
+ /* when selected callback */
+ g_signal_connect(G_OBJECT(completion), "match-selected",
+ G_CALLBACK(nsgtk_completion_match_select), gs);
+
+ g_object_set(G_OBJECT(completion),
+ "popup-set-width", TRUE,
+ "popup-single-match", TRUE,
+ NULL);
+
+ return completion;
+}
diff --git a/frontends/gtk/completion.h b/frontends/gtk/completion.h
new file mode 100644
index 000000000..9a1db293d
--- /dev/null
+++ b/frontends/gtk/completion.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to url entry completion.
+ */
+
+#ifndef _NETSURF_GTK_COMPLETION_H_
+#define _NETSURF_GTK_COMPLETION_H_
+
+struct nsgtk_scaffolding;
+
+/**
+ * initialise completion list store
+ */
+void nsgtk_completion_init(void);
+
+/**
+ * update completion list store.
+ */
+gboolean nsgtk_completion_update(GtkEntry *entry);
+
+/**
+ * create a new entry completion on a scaffold.
+ *
+ * \param gs The scaffoliding which the url entry is in.
+ */
+GtkEntryCompletion *nsgtk_url_entry_completion_new(struct nsgtk_scaffolding *gs);
+
+#endif
diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c
new file mode 100644
index 000000000..f8f989347
--- /dev/null
+++ b/frontends/gtk/cookies.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Cookies (implementation).
+ */
+
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "desktop/cookie_manager.h"
+#include "desktop/plot_style.h"
+#include "desktop/tree.h"
+#include "desktop/textinput.h"
+
+#include "gtk/cookies.h"
+#include "gtk/plotters.h"
+#include "gtk/scaffolding.h"
+#include "gtk/treeview.h"
+#include "gtk/resources.h"
+
+#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
+ GtkMenuItem *widget, gpointer g)
+#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) }
+#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \
+ gpointer g)
+
+struct menu_events {
+ const char *widget;
+ GCallback handler;
+};
+
+/* edit menu */
+MENUPROTO(delete_selected);
+MENUPROTO(delete_all);
+MENUPROTO(select_all);
+MENUPROTO(clear_selection);
+
+/* view menu*/
+MENUPROTO(expand_all);
+MENUPROTO(expand_domains);
+MENUPROTO(expand_cookies);
+MENUPROTO(collapse_all);
+MENUPROTO(collapse_domains);
+MENUPROTO(collapse_cookies);
+
+
+static struct menu_events menu_events[] = {
+
+ /* edit menu */
+ MENUEVENT(delete_selected),
+ MENUEVENT(delete_all),
+ MENUEVENT(select_all),
+ MENUEVENT(clear_selection),
+
+ /* view menu*/
+ MENUEVENT(expand_all),
+ MENUEVENT(expand_domains),
+ MENUEVENT(expand_cookies),
+ MENUEVENT(collapse_all),
+ MENUEVENT(collapse_domains),
+ MENUEVENT(collapse_cookies),
+
+ {NULL, NULL}
+};
+
+static struct nsgtk_treeview *cookies_treeview;
+static GtkBuilder *cookie_builder;
+GtkWindow *wndCookies;
+
+/**
+ * Connects menu events in the cookies window.
+ */
+static void nsgtk_cookies_init_menu(void)
+{
+ struct menu_events *event = menu_events;
+ GtkWidget *w;
+
+ while (event->widget != NULL) {
+ w = GTK_WIDGET(gtk_builder_get_object(cookie_builder, event->widget));
+ if (w == NULL) {
+ LOG("Unable to connect menu widget ""%s""", event->widget); } else {
+ g_signal_connect(G_OBJECT(w), "activate", event->handler, cookies_treeview);
+ }
+ event++;
+ }
+}
+
+/* exported interface documented in gtk/cookies.h */
+nserror nsgtk_cookies_init(void)
+{
+ GtkScrolledWindow *scrolled;
+ GtkDrawingArea *drawing_area;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("cookies", &cookie_builder);
+ if (res != NSERROR_OK) {
+ LOG("Cookie UI builder init failed");
+ return res;
+ }
+
+ gtk_builder_connect_signals(cookie_builder, NULL);
+
+ wndCookies = GTK_WINDOW(gtk_builder_get_object(cookie_builder,
+ "wndCookies"));
+
+ scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(cookie_builder,
+ "cookiesScrolled"));
+
+ drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(cookie_builder,
+ "cookiesDrawingArea"));
+
+ cookies_treeview = nsgtk_treeview_create(TREE_COOKIES,
+ wndCookies,
+ scrolled,
+ drawing_area);
+ if (cookies_treeview == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+#define CONNECT(obj, sig, callback, ptr) \
+ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
+
+ CONNECT(wndCookies, "delete_event", gtk_widget_hide_on_delete, NULL);
+ CONNECT(wndCookies, "hide", nsgtk_tree_window_hide, cookies_treeview);
+
+ nsgtk_cookies_init_menu();
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Destroys the cookies window and performs any other necessary cleanup actions.
+ */
+void nsgtk_cookies_destroy(void)
+{
+ /** \todo what about cookie_builder? */
+ nsgtk_treeview_destroy(cookies_treeview);
+}
+
+
+/* edit menu */
+MENUHANDLER(delete_selected)
+{
+ cookie_manager_keypress(NS_KEY_DELETE_LEFT);
+ return TRUE;
+}
+
+MENUHANDLER(delete_all)
+{
+ cookie_manager_keypress(NS_KEY_SELECT_ALL);
+ cookie_manager_keypress(NS_KEY_DELETE_LEFT);
+ return TRUE;
+}
+
+MENUHANDLER(select_all)
+{
+ cookie_manager_keypress(NS_KEY_SELECT_ALL);
+ return TRUE;
+}
+
+MENUHANDLER(clear_selection)
+{
+ cookie_manager_keypress(NS_KEY_CLEAR_SELECTION);
+ return TRUE;
+}
+
+/* view menu*/
+MENUHANDLER(expand_all)
+{
+ cookie_manager_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(expand_domains)
+{
+ cookie_manager_expand(true);
+ return TRUE;
+}
+
+MENUHANDLER(expand_cookies)
+{
+ cookie_manager_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_all)
+{
+ cookie_manager_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_domains)
+{
+ cookie_manager_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_cookies)
+{
+ cookie_manager_contract(false);
+ return TRUE;
+}
diff --git a/frontends/gtk/cookies.h b/frontends/gtk/cookies.h
new file mode 100644
index 000000000..2d5c56d52
--- /dev/null
+++ b/frontends/gtk/cookies.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Cookies (interface).
+ */
+
+#ifndef __NSGTK_COOKIES_H__
+#define __NSGTK_COOKIES_H__
+
+extern GtkWindow *wndCookies;
+
+/**
+ * Creates the window for the cookies tree.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror nsgtk_cookies_init(void);
+
+void nsgtk_cookies_destroy(void);
+
+#endif /* __NSGTK_COOKIES_H__ */
diff --git a/frontends/gtk/download.c b/frontends/gtk/download.c
new file mode 100644
index 000000000..b7eea2584
--- /dev/null
+++ b/frontends/gtk/download.c
@@ -0,0 +1,865 @@
+/*
+ * Copyright 2008 Michael Lester <element3260@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <glib/gstdio.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "utils/nsurl.h"
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+#include "utils/string.h"
+#include "desktop/download.h"
+#include "desktop/gui_download.h"
+
+#include "gtk/warn.h"
+#include "gtk/scaffolding.h"
+#include "gtk/window.h"
+#include "gtk/compat.h"
+#include "gtk/resources.h"
+#include "gtk/download.h"
+
+#define UPDATE_RATE 500 /* In milliseconds */
+
+struct download_context;
+
+enum {
+ NSGTK_DOWNLOAD_PROGRESS,
+ NSGTK_DOWNLOAD_INFO,
+ NSGTK_DOWNLOAD_REMAINING,
+ NSGTK_DOWNLOAD_SPEED,
+ NSGTK_DOWNLOAD_PULSE,
+ NSGTK_DOWNLOAD_STATUS,
+ NSGTK_DOWNLOAD,
+
+ NSGTK_DOWNLOAD_N_COLUMNS
+};
+
+typedef enum {
+ NSGTK_DOWNLOAD_NONE,
+ NSGTK_DOWNLOAD_WORKING,
+ NSGTK_DOWNLOAD_ERROR,
+ NSGTK_DOWNLOAD_COMPLETE,
+ NSGTK_DOWNLOAD_CANCELED
+} nsgtk_download_status;
+
+typedef enum {
+ NSGTK_DOWNLOAD_PAUSE = 1 << 0,
+ NSGTK_DOWNLOAD_RESUME = 1 << 1,
+ NSGTK_DOWNLOAD_CANCEL = 1 << 2,
+ NSGTK_DOWNLOAD_CLEAR = 1 << 3
+} nsgtk_download_actions;
+
+struct gui_download_window {
+ struct download_context *ctx;
+ nsgtk_download_actions sensitivity;
+ nsgtk_download_status status;
+
+ GString *name;
+ GString *time_left;
+ gint size_total;
+ gint size_downloaded;
+ gint progress;
+ gfloat time_remaining;
+ gfloat start_time;
+ gfloat speed;
+
+ GtkTreeRowReference *row;
+ GIOChannel *write;
+ GError *error;
+};
+
+typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl);
+
+static GtkWindow *nsgtk_download_window, *nsgtk_download_parent;
+static GtkProgressBar *nsgtk_download_progress_bar;
+
+static GtkTreeView *nsgtk_download_tree;
+static GtkListStore *nsgtk_download_store;
+static GtkTreeSelection *nsgtk_download_selection;
+static GtkTreeIter nsgtk_download_iter;
+
+static GTimer *nsgtk_downloads_timer;
+static GList *nsgtk_downloads_list;
+static GtkButton *nsgtk_download_button_pause;
+static GtkButton *nsgtk_download_button_clear;
+static GtkButton *nsgtk_download_button_cancel;
+static GtkButton *nsgtk_download_button_resume;
+static gint nsgtk_downloads_num_active;
+static const gchar* status_messages[] = { NULL, "gtkWorking", "gtkError",
+ "gtkComplete", "gtkCanceled" };
+
+
+
+static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile)
+{
+ GtkTreeView *treeview;
+ GtkCellRenderer *renderer;
+
+ treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile, "treeDownloads"));
+
+ /* Progress column */
+ renderer = gtk_cell_renderer_progress_new();
+ gtk_tree_view_insert_column_with_attributes (treeview, -1,
+ messages_get("gtkProgress"), renderer, "value",
+ NSGTK_DOWNLOAD_PROGRESS, "pulse", NSGTK_DOWNLOAD_PULSE,
+ "text", NSGTK_DOWNLOAD_STATUS, NULL);
+
+ /* Information column */
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD_CHAR,
+ "wrap-width", 300, NULL);
+ gtk_tree_view_insert_column_with_attributes (treeview, -1,
+ messages_get("gtkDetails"), renderer, "text",
+ NSGTK_DOWNLOAD_INFO, NULL);
+ gtk_tree_view_column_set_expand(gtk_tree_view_get_column(treeview,
+ NSGTK_DOWNLOAD_INFO), TRUE);
+
+ /* Time remaining column */
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes (treeview, -1,
+ messages_get("gtkRemaining"), renderer, "text",
+ NSGTK_DOWNLOAD_REMAINING, NULL);
+
+ /* Speed column */
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes (treeview, -1,
+ messages_get("gtkSpeed"), renderer, "text",
+ NSGTK_DOWNLOAD_SPEED, NULL);
+
+ return treeview;
+}
+
+static gint
+nsgtk_download_sort(GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer userdata)
+{
+ struct gui_download_window *dl1, *dl2;
+
+ gtk_tree_model_get(model, a, NSGTK_DOWNLOAD, &dl1, -1);
+ gtk_tree_model_get(model, b, NSGTK_DOWNLOAD, &dl2, -1);
+
+ return dl1->status - dl2->status;
+}
+
+static void
+nsgtk_download_sensitivity_update_buttons(nsgtk_download_actions sensitivity)
+{
+ /* Glade seems to pack the buttons in an arbitrary order */
+ enum { PAUSE_BUTTON, CLEAR_BUTTON, CANCEL_BUTTON, RESUME_BUTTON };
+
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_pause),
+ sensitivity & NSGTK_DOWNLOAD_PAUSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_clear),
+ sensitivity & NSGTK_DOWNLOAD_CLEAR);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_cancel),
+ sensitivity & NSGTK_DOWNLOAD_CANCEL);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_resume),
+ sensitivity & NSGTK_DOWNLOAD_RESUME);
+}
+
+static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection)
+{
+ GtkTreeIter iter;
+ GList *rows;
+ gboolean selected = gtk_tree_selection_count_selected_rows(selection);
+ GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store);
+ nsgtk_download_actions sensitivity = 0;
+ struct gui_download_window *dl;
+
+ if (selected) {
+ rows = gtk_tree_selection_get_selected_rows(selection, &model);
+ while (rows != NULL) {
+ gtk_tree_model_get_iter(model, &iter,
+ (GtkTreePath*)rows->data);
+ gtk_tree_model_get(model, &iter, NSGTK_DOWNLOAD,
+ &dl, -1);
+ sensitivity |= dl->sensitivity;
+ rows = rows->next;
+ }
+ } else {
+ rows = nsgtk_downloads_list;
+ while (rows != NULL) {
+ dl = rows->data;
+ sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR);
+ rows = rows->next;
+ }
+ }
+
+
+ nsgtk_download_sensitivity_update_buttons(sensitivity);
+}
+
+static void nsgtk_download_do(nsgtk_download_selection_action action)
+{
+ GList *rows, *dls = NULL;
+ GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store);
+ gboolean selection_exists = gtk_tree_selection_count_selected_rows(
+ nsgtk_download_selection);
+
+ if (selection_exists) {
+ rows = gtk_tree_selection_get_selected_rows(
+ nsgtk_download_selection, &model);
+ while (rows != NULL) {
+ struct gui_download_window *dl;
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(
+ nsgtk_download_store),
+ &nsgtk_download_iter,
+ (GtkTreePath*)rows->data);
+ gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_download_store),
+ &nsgtk_download_iter, NSGTK_DOWNLOAD,
+ &dl, -1);
+ dls = g_list_prepend(dls, dl);
+
+ rows = rows->next;
+ }
+ g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL);
+ g_list_foreach(rows, (GFunc)g_free, NULL);
+ g_list_free(rows);
+ } else
+ dls = g_list_copy(nsgtk_downloads_list);
+
+ g_list_foreach(dls, (GFunc)action, NULL);
+ g_list_free(dls);
+}
+
+static gchar* nsgtk_download_info_to_string(struct gui_download_window *dl)
+{
+ gchar *size_info = g_strdup_printf(messages_get("gtkSizeInfo"),
+ human_friendly_bytesize(dl->size_downloaded),
+ dl->size_total == 0 ? messages_get("gtkUnknownSize") :
+ human_friendly_bytesize(dl->size_total));
+
+ gchar *r;
+
+ if (dl->status != NSGTK_DOWNLOAD_ERROR)
+ r = g_strdup_printf("%s\n%s", dl->name->str, size_info);
+ else
+ r = g_strdup_printf("%s\n%s", dl->name->str,
+ dl->error->message);
+
+ g_free(size_info);
+
+ return r;
+}
+
+static gchar* nsgtk_download_time_to_string(gint seconds)
+{
+ gint hours, minutes;
+
+ if (seconds < 0)
+ return g_strdup("-");
+
+ hours = seconds / 3600;
+ seconds -= hours * 3600;
+ minutes = seconds / 60;
+ seconds -= minutes * 60;
+
+ if (hours > 0)
+ return g_strdup_printf("%u:%02u:%02u", hours, minutes,
+ seconds);
+ else
+ return g_strdup_printf("%u:%02u", minutes, seconds);
+}
+
+static void nsgtk_download_store_update_item (struct gui_download_window *dl)
+{
+ gchar *info = nsgtk_download_info_to_string(dl);
+ char *human = human_friendly_bytesize(dl->speed);
+ char speed[strlen(human) + SLEN("/s") + 1];
+ sprintf(speed, "%s/s", human);
+ gchar *time = nsgtk_download_time_to_string(dl->time_remaining);
+ gboolean pulse = dl->status == NSGTK_DOWNLOAD_WORKING;
+
+ /* Updates iter (which is needed to set and get data) with the dl row */
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store),
+ &nsgtk_download_iter,
+ gtk_tree_row_reference_get_path(dl->row));
+
+ gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter,
+ NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1,
+ NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress,
+ NSGTK_DOWNLOAD_INFO, info,
+ NSGTK_DOWNLOAD_SPEED, dl->speed == 0 ? "-" : speed,
+ NSGTK_DOWNLOAD_REMAINING, time,
+ NSGTK_DOWNLOAD, dl,
+ -1);
+
+ g_free(info);
+ g_free(time);
+}
+
+static gboolean nsgtk_download_update(gboolean force_update)
+{
+ /* Be sure we need to update */
+ if (!nsgtk_widget_get_visible(GTK_WIDGET(nsgtk_download_window)))
+ return TRUE;
+
+ GList *list;
+ gchar *text;
+ gboolean update, pulse_mode = FALSE;
+ gint downloaded = 0, total = 0, dls = 0;
+ gfloat percent, elapsed = g_timer_elapsed(nsgtk_downloads_timer, NULL);
+ nsgtk_downloads_num_active = 0;
+
+ for (list = nsgtk_downloads_list; list != NULL; list = list->next) {
+ struct gui_download_window *dl = list->data;
+ update = force_update;
+
+ switch (dl->status) {
+ case NSGTK_DOWNLOAD_WORKING:
+ pulse_mode = TRUE;
+
+ case NSGTK_DOWNLOAD_NONE:
+ dl->speed = dl->size_downloaded /
+ (elapsed - dl->start_time);
+ if (dl->status == NSGTK_DOWNLOAD_NONE) {
+ dl->time_remaining = (dl->size_total -
+ dl->size_downloaded)/
+ dl->speed;
+ dl->progress = (gfloat)
+ dl->size_downloaded /
+ dl->size_total * 100;
+ } else
+ dl->progress++;
+
+ nsgtk_downloads_num_active++;
+ update = TRUE;
+
+ case NSGTK_DOWNLOAD_COMPLETE:
+ downloaded += dl->size_downloaded;
+ total += dl->size_total;
+ dls++;
+
+ default:
+ ;//Do nothing
+
+ }
+ if (update)
+ nsgtk_download_store_update_item(dl);
+ }
+
+ if (pulse_mode) {
+ text = g_strdup_printf(
+ messages_get(nsgtk_downloads_num_active > 1 ?
+ "gtkProgressBarPulse" :
+ "gtkProgressBarPulseSingle"),
+ nsgtk_downloads_num_active);
+ gtk_progress_bar_pulse(nsgtk_download_progress_bar);
+ gtk_progress_bar_set_text(nsgtk_download_progress_bar, text);
+ } else {
+ percent = total != 0 ? (gfloat)downloaded / total : 0;
+ text = g_strdup_printf(messages_get("gtkProgressBar"),
+ floor(percent*100), dls);
+ gtk_progress_bar_set_fraction(nsgtk_download_progress_bar,
+ percent);
+ gtk_progress_bar_set_text(nsgtk_download_progress_bar, text);
+ }
+
+ g_free(text);
+
+ if (nsgtk_downloads_num_active == 0)
+ return FALSE; /* Returning FALSE here cancels the g_timeout */
+ else
+ return TRUE;
+}
+
+static void nsgtk_download_store_clear_item(struct gui_download_window *dl)
+{
+ if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) {
+ nsgtk_downloads_list = g_list_remove(nsgtk_downloads_list, dl);
+
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store),
+ &nsgtk_download_iter,
+ gtk_tree_row_reference_get_path(dl->row));
+ gtk_list_store_remove(nsgtk_download_store,
+ &nsgtk_download_iter);
+
+ download_context_destroy(dl->ctx);
+ g_string_free(dl->name, TRUE);
+ g_string_free(dl->time_left, TRUE);
+ g_free(dl);
+
+ nsgtk_download_sensitivity_evaluate(nsgtk_download_selection);
+ nsgtk_download_update(FALSE);
+ }
+}
+
+static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree,
+ GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model(tree);
+
+ if (gtk_tree_model_get_iter(model, &iter, path)) {
+ /* TODO: This will be a context action (pause, start, clear) */
+ nsgtk_download_do(nsgtk_download_store_clear_item);
+ }
+}
+
+static void nsgtk_download_change_sensitivity(struct gui_download_window *dl,
+ nsgtk_download_actions sensitivity)
+{
+ dl->sensitivity = sensitivity;
+ nsgtk_download_sensitivity_evaluate(nsgtk_download_selection);
+}
+
+static void nsgtk_download_change_status (
+ struct gui_download_window *dl, nsgtk_download_status status)
+{
+ dl->status = status;
+ if (status != NSGTK_DOWNLOAD_NONE) {
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store),
+ &nsgtk_download_iter,
+ gtk_tree_row_reference_get_path(dl->row));
+
+ gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter,
+ NSGTK_DOWNLOAD_STATUS,
+ messages_get(status_messages[status]), -1);
+ }
+}
+
+static void nsgtk_download_store_cancel_item (struct gui_download_window *dl)
+{
+ if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) {
+ dl->speed = 0;
+ dl->size_downloaded = 0;
+ dl->progress = 0;
+ dl->time_remaining = -1;
+ nsgtk_download_change_sensitivity(dl, NSGTK_DOWNLOAD_CLEAR);
+ nsgtk_download_change_status(dl, NSGTK_DOWNLOAD_CANCELED);
+
+ download_context_abort(dl->ctx);
+
+ g_unlink(download_context_get_filename(dl->ctx));
+
+ nsgtk_download_update(TRUE);
+ }
+}
+
+static gboolean nsgtk_download_hide(GtkWidget *window)
+{
+ gtk_widget_hide(window);
+ return TRUE;
+}
+
+/* exported interface documented in gtk/download.h */
+nserror nsgtk_download_init(void)
+{
+ GtkBuilder* builder;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("downloads", &builder);
+ if (res != NSERROR_OK) {
+ LOG("Download UI builder init failed");
+ return res;
+ }
+
+ gtk_builder_connect_signals(builder, NULL);
+
+ nsgtk_download_button_pause = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPause"));
+ nsgtk_download_button_clear = GTK_BUTTON(gtk_builder_get_object(builder, "buttonClear"));
+ nsgtk_download_button_cancel = GTK_BUTTON(gtk_builder_get_object(builder, "buttonCancel"));
+ nsgtk_download_button_resume = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPlay"));
+
+ nsgtk_download_progress_bar = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progressBar"));
+ nsgtk_download_window = GTK_WINDOW(gtk_builder_get_object(builder, "wndDownloads"));
+ nsgtk_download_parent = NULL;
+
+ gtk_window_set_transient_for(GTK_WINDOW(nsgtk_download_window),
+ nsgtk_download_parent);
+ gtk_window_set_destroy_with_parent(GTK_WINDOW(nsgtk_download_window),
+ FALSE);
+
+ nsgtk_downloads_timer = g_timer_new();
+
+ nsgtk_download_tree = nsgtk_download_tree_view_new(builder);
+
+ nsgtk_download_store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS,
+ G_TYPE_INT, /* % complete */
+ G_TYPE_STRING, /* Description */
+ G_TYPE_STRING, /* Time remaining */
+ G_TYPE_STRING, /* Speed */
+ G_TYPE_INT, /* Pulse */
+ G_TYPE_STRING, /* Status */
+ G_TYPE_POINTER /* Download structure */
+ );
+
+
+ gtk_tree_view_set_model(nsgtk_download_tree,
+ GTK_TREE_MODEL(nsgtk_download_store));
+
+ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(nsgtk_download_store),
+ NSGTK_DOWNLOAD_STATUS,
+ (GtkTreeIterCompareFunc) nsgtk_download_sort, NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id(
+ GTK_TREE_SORTABLE(nsgtk_download_store),
+ NSGTK_DOWNLOAD_STATUS, GTK_SORT_ASCENDING);
+
+ g_object_unref(nsgtk_download_store);
+
+ nsgtk_download_selection =
+ gtk_tree_view_get_selection(nsgtk_download_tree);
+ gtk_tree_selection_set_mode(nsgtk_download_selection,
+ GTK_SELECTION_MULTIPLE);
+
+ g_signal_connect(G_OBJECT(nsgtk_download_selection), "changed",
+ G_CALLBACK(nsgtk_download_sensitivity_evaluate), NULL);
+ g_signal_connect(nsgtk_download_tree, "row-activated",
+ G_CALLBACK(nsgtk_download_tree_view_row_activated),
+ NULL);
+ g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"),
+ "clicked",
+ G_CALLBACK(nsgtk_download_do),
+ nsgtk_download_store_clear_item);
+ g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"),
+ "clicked",
+ G_CALLBACK(nsgtk_download_do),
+ nsgtk_download_store_cancel_item);
+ g_signal_connect(G_OBJECT(nsgtk_download_window), "delete-event",
+ G_CALLBACK(nsgtk_download_hide), NULL);
+
+ return NSERROR_OK;
+}
+
+void nsgtk_download_destroy ()
+{
+ nsgtk_download_do(nsgtk_download_store_cancel_item);
+}
+
+bool nsgtk_check_for_downloads (GtkWindow *parent)
+{
+ if (nsgtk_downloads_num_active != 0) {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new_with_markup(parent,
+ GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "<big><b>%s</b></big>\n\n"
+ "<small>%s</small>", messages_get("gtkQuit"),
+ messages_get("gtkDownloadsRunning"));
+ gtk_dialog_add_buttons(GTK_DIALOG(dialog), "gtk-cancel",
+ GTK_RESPONSE_CANCEL, "gtk-quit",
+ GTK_RESPONSE_CLOSE, NULL);
+
+ gint response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ if (response == GTK_RESPONSE_CANCEL)
+ return true;
+ }
+
+ return false;
+}
+
+void nsgtk_download_show(GtkWindow *parent)
+{
+ gtk_window_set_transient_for(nsgtk_download_window,
+ nsgtk_download_parent);
+ gtk_window_present(nsgtk_download_window);
+}
+
+static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *domain,
+ const gchar *size)
+{
+ enum { GTK_RESPONSE_DOWNLOAD, GTK_RESPONSE_SAVE_AS };
+ GtkWidget *dialog;
+ char *destination = NULL;
+ gchar *message = g_strdup(messages_get("gtkStartDownload"));
+ gchar *info = g_strdup_printf(messages_get("gtkInfo"), filename,
+ domain, size);
+
+ dialog = gtk_message_dialog_new_with_markup(nsgtk_download_parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
+ "<span size=\"x-large\" weight=\"ultrabold\">%s</span>"
+ "\n\n<small>%s</small>",
+ message, info);
+
+ gtk_dialog_add_buttons(GTK_DIALOG(dialog), NSGTK_STOCK_SAVE,
+ GTK_RESPONSE_DOWNLOAD, NSGTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL, NSGTK_STOCK_SAVE_AS,
+ GTK_RESPONSE_SAVE_AS, NULL);
+
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ g_free(message);
+ g_free(info);
+
+ switch (result) {
+ case GTK_RESPONSE_SAVE_AS: {
+ dialog = gtk_file_chooser_dialog_new
+ (messages_get("gtkSave"),
+ nsgtk_download_parent,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_current_name
+ (GTK_FILE_CHOOSER(dialog), filename);
+ gtk_file_chooser_set_current_folder
+ (GTK_FILE_CHOOSER(dialog),
+ nsoption_charp(downloads_directory));
+ gtk_file_chooser_set_do_overwrite_confirmation
+ (GTK_FILE_CHOOSER(dialog),
+ nsoption_bool(request_overwrite));
+
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (result == GTK_RESPONSE_ACCEPT)
+ destination = gtk_file_chooser_get_filename
+ (GTK_FILE_CHOOSER(dialog));
+ gtk_widget_destroy(dialog);
+ break;
+ }
+ case GTK_RESPONSE_DOWNLOAD: {
+ destination = malloc(strlen(nsoption_charp(downloads_directory))
+ + strlen(filename) + SLEN("/") + 1);
+ if (destination == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ break;
+ }
+ sprintf(destination, "%s/%s",
+ nsoption_charp(downloads_directory), filename);
+ /* Test if file already exists and display overwrite
+ * confirmation if needed */
+ if (g_file_test(destination, G_FILE_TEST_EXISTS) &&
+ nsoption_bool(request_overwrite)) {
+ message = g_strdup_printf(messages_get(
+ "gtkOverwrite"), filename);
+ info = g_strdup_printf(messages_get(
+ "gtkOverwriteInfo"),
+ nsoption_charp(downloads_directory));
+
+ dialog = gtk_message_dialog_new_with_markup(
+ nsgtk_download_parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_CANCEL,
+ "<b>%s</b>",message);
+ gtk_message_dialog_format_secondary_markup(
+ GTK_MESSAGE_DIALOG(dialog),
+ "%s", info);
+
+ GtkWidget *button = gtk_dialog_add_button(
+ GTK_DIALOG(dialog),
+ "_Replace",
+ GTK_RESPONSE_DOWNLOAD);
+ gtk_button_set_image(GTK_BUTTON(button),
+ nsgtk_image_new_from_stock(
+ NSGTK_STOCK_SAVE,
+ GTK_ICON_SIZE_BUTTON));
+
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (result == GTK_RESPONSE_CANCEL)
+ destination = NULL;
+
+ gtk_widget_destroy(dialog);
+ g_free(message);
+ g_free(info);
+ }
+ break;
+ }
+ }
+ return destination;
+}
+
+
+static gboolean nsgtk_download_handle_error (GError *error)
+{
+ if (error != NULL) {
+ GtkWidget*dialog;
+ gchar *message = g_strdup_printf(messages_get("gtkFileError"),
+ error->message);
+
+ dialog = gtk_message_dialog_new_with_markup
+ (nsgtk_download_parent,
+ GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ "<big><b>%s</b></big>\n\n"
+ "<small>%s</small>", messages_get("gtkFailed"),
+ message);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void nsgtk_download_store_create_item (struct gui_download_window *dl)
+{
+ nsgtk_download_store_update_item(dl);
+ /* The iter has already been updated to this row */
+ gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter,
+ NSGTK_DOWNLOAD, dl, -1);
+}
+
+static struct gui_download_window *
+gui_download_window_create(download_context *ctx, struct gui_window *gui)
+{
+ nsurl *url = download_context_get_url(ctx);
+ unsigned long total_size = download_context_get_total_length(ctx);
+ gchar *domain;
+ gchar *destination;
+ gboolean unknown_size = total_size == 0;
+ const char *size = (total_size == 0 ?
+ messages_get("gtkUnknownSize") :
+ human_friendly_bytesize(total_size));
+
+ nsgtk_download_parent =
+ nsgtk_scaffolding_window(nsgtk_get_scaffold(gui));
+
+ struct gui_download_window *download = malloc(sizeof *download);
+ if (download == NULL) {
+ return NULL;
+ }
+
+ /* set the domain to the host component of the url if it exists */
+ if (nsurl_has_component(url, NSURL_HOST)) {
+ domain = g_strdup(lwc_string_data(nsurl_get_component(url, NSURL_HOST)));
+ } else {
+ domain = g_strdup(messages_get("gtkUnknownHost"));
+ }
+ if (domain == NULL) {
+ free(download);
+ return NULL;
+ }
+
+ /* show the dialog */
+ destination = nsgtk_download_dialog_show(
+ download_context_get_filename(ctx), domain, size);
+ if (destination == NULL) {
+ g_free(domain);
+ free(download);
+ return NULL;
+ }
+
+ /* Add the new row and store the reference to it (which keeps track of
+ * the tree changes) */
+ gtk_list_store_prepend(nsgtk_download_store, &nsgtk_download_iter);
+ download->row = gtk_tree_row_reference_new(
+ GTK_TREE_MODEL(nsgtk_download_store),
+ gtk_tree_model_get_path(
+ GTK_TREE_MODEL(nsgtk_download_store),
+ &nsgtk_download_iter));
+
+ download->ctx = ctx;
+ download->name = g_string_new(download_context_get_filename(ctx));
+ download->time_left = g_string_new("");
+ download->size_total = total_size;
+ download->size_downloaded = 0;
+ download->speed = 0;
+ download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL);
+ download->time_remaining = -1;
+ download->status = NSGTK_DOWNLOAD_NONE;
+ download->progress = 0;
+ download->error = NULL;
+ download->write =
+ g_io_channel_new_file(destination, "w", &download->error);
+
+ if (nsgtk_download_handle_error(download->error)) {
+ g_string_free(download->name, TRUE);
+ g_string_free(download->time_left, TRUE);
+ free(download);
+ return NULL;
+ }
+ g_io_channel_set_encoding(download->write, NULL, &download->error);
+
+ nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL);
+
+ nsgtk_download_store_create_item(download);
+ nsgtk_download_show(nsgtk_download_parent);
+
+ if (unknown_size)
+ nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING);
+
+ if (nsgtk_downloads_num_active == 0) {
+ g_timeout_add(UPDATE_RATE,
+ (GSourceFunc) nsgtk_download_update, FALSE);
+ }
+
+ nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download);
+
+ return download;
+}
+
+
+static nserror gui_download_window_data(struct gui_download_window *dw,
+ const char *data, unsigned int size)
+{
+ g_io_channel_write_chars(dw->write, data, size, NULL, &dw->error);
+ if (dw->error != NULL) {
+ dw->speed = 0;
+ dw->time_remaining = -1;
+
+ nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR);
+ nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_ERROR);
+
+ nsgtk_download_update(TRUE);
+
+ gtk_window_present(nsgtk_download_window);
+
+ return NSERROR_SAVE_FAILED;
+ }
+ dw->size_downloaded += size;
+
+ return NSERROR_OK;
+}
+
+
+static void gui_download_window_error(struct gui_download_window *dw,
+ const char *error_msg)
+{
+}
+
+
+static void gui_download_window_done(struct gui_download_window *dw)
+{
+ g_io_channel_shutdown(dw->write, TRUE, &dw->error);
+ g_io_channel_unref(dw->write);
+
+ dw->speed = 0;
+ dw->time_remaining = -1;
+ dw->progress = 100;
+ dw->size_total = dw->size_downloaded;
+ nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR);
+ nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE);
+
+ if (nsoption_bool(downloads_clear))
+ nsgtk_download_store_clear_item(dw);
+ else
+ nsgtk_download_update(TRUE);
+}
+
+
+static struct gui_download_table download_table = {
+ .create = gui_download_window_create,
+ .data = gui_download_window_data,
+ .error = gui_download_window_error,
+ .done = gui_download_window_done,
+};
+
+struct gui_download_table *nsgtk_download_table = &download_table;
diff --git a/frontends/gtk/download.h b/frontends/gtk/download.h
new file mode 100644
index 000000000..0b1097655
--- /dev/null
+++ b/frontends/gtk/download.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008 Michael Lester <element3260@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTK_DOWNLOAD_H
+#define GTK_DOWNLOAD_H
+
+#include <gtk/gtk.h>
+
+/**
+ * download operation table for gtk
+ */
+struct gui_download_table *nsgtk_download_table;
+
+/**
+ * Initialise download window ready for use.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror nsgtk_download_init(void);
+
+void nsgtk_download_destroy (void);
+bool nsgtk_check_for_downloads(GtkWindow *parent);
+void nsgtk_download_show(GtkWindow *parent);
+void nsgtk_download_add(gchar *url, gchar *destination);
+
+#endif
diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c
new file mode 100644
index 000000000..06770b6b2
--- /dev/null
+++ b/frontends/gtk/fetch.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2007, 2014 Vincent Sanders <vince@netsurf-browser.org>
+ * Copyright 2007 Rob Kendrick <rjek@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <gtk/gtk.h>
+
+#include "utils/hashtable.h"
+#include "utils/log.h"
+#include "utils/filepath.h"
+#include "utils/file.h"
+#include "utils/nsurl.h"
+#include "desktop/gui_fetch.h"
+
+#include "gtk/gui.h"
+#include "gtk/resources.h"
+#include "gtk/fetch.h"
+
+#define HASH_SIZE 117
+#define MAX_LINE_LEN 256
+
+static struct hash_table *mime_hash = NULL;
+
+void gtk_fetch_filetype_init(const char *mimefile)
+{
+ struct stat statbuf;
+ FILE *fh = NULL;
+
+ mime_hash = hash_create(HASH_SIZE);
+
+ /* first, check to see if /etc/mime.types in preference */
+
+ if ((stat("/etc/mime.types", &statbuf) == 0) &&
+ S_ISREG(statbuf.st_mode)) {
+ mimefile = "/etc/mime.types";
+ }
+
+ fh = fopen(mimefile, "r");
+
+ /* Some OSes (mentioning no Solarises) have a worthlessly tiny
+ * /etc/mime.types that don't include essential things, so we
+ * pre-seed our hash with the essentials. These will get
+ * over-ridden if they are mentioned in the mime.types file.
+ */
+
+ hash_add(mime_hash, "css", "text/css");
+ hash_add(mime_hash, "htm", "text/html");
+ hash_add(mime_hash, "html", "text/html");
+ hash_add(mime_hash, "jpg", "image/jpeg");
+ hash_add(mime_hash, "jpeg", "image/jpeg");
+ hash_add(mime_hash, "gif", "image/gif");
+ hash_add(mime_hash, "png", "image/png");
+ hash_add(mime_hash, "jng", "image/jng");
+ hash_add(mime_hash, "mng", "image/mng");
+ hash_add(mime_hash, "webp", "image/webp");
+ hash_add(mime_hash, "spr", "image/x-riscos-sprite");
+
+ if (fh == NULL) {
+ LOG("Unable to open a mime.types file, so using a minimal one for you.");
+ return;
+ }
+
+ while (feof(fh) == 0) {
+ char line[MAX_LINE_LEN], *ptr, *type, *ext;
+
+ if (fgets(line, sizeof(line), fh) == NULL)
+ break;
+
+ if ((feof(fh) == 0) && line[0] != '#') {
+ ptr = line;
+
+ /* search for the first non-whitespace character */
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ /* is this line empty other than leading whitespace? */
+ if (*ptr == '\n' || *ptr == '\0') {
+ continue;
+ }
+
+ type = ptr;
+
+ /* search for the first non-whitespace char or NUL or
+ * NL */
+ while (*ptr && (!isspace(*ptr)) && *ptr != '\n') {
+ ptr++;
+ }
+
+ if (*ptr == '\0' || *ptr == '\n') {
+ /* this mimetype has no extensions - read next
+ * line.
+ */
+ continue;
+ }
+
+ *ptr++ = '\0';
+
+ /* search for the first non-whitespace character which
+ * will be the first filename extenion */
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ while (true) {
+ ext = ptr;
+
+ /* search for the first whitespace char or
+ * NUL or NL which is the end of the ext.
+ */
+ while (*ptr &&
+ (!isspace(*ptr)) &&
+ *ptr != '\n') {
+ ptr++;
+ }
+
+ if (*ptr == '\0' || *ptr == '\n') {
+ /* special case for last extension on
+ * the line
+ */
+ *ptr = '\0';
+ hash_add(mime_hash, ext, type);
+ break;
+ }
+
+ *ptr++ = '\0';
+ hash_add(mime_hash, ext, type);
+
+ /* search for the first non-whitespace char or
+ * NUL or NL, to find start of next ext.
+ */
+ while (*ptr &&
+ (isspace(*ptr)) &&
+ *ptr != '\n') {
+ ptr++;
+ }
+ }
+ }
+ }
+
+ fclose(fh);
+}
+
+void gtk_fetch_filetype_fin(void)
+{
+ hash_destroy(mime_hash);
+}
+
+const char *fetch_filetype(const char *unix_path)
+{
+ struct stat statbuf;
+ char *ext;
+ const char *ptr;
+ char *lowerchar;
+ const char *type;
+ int l;
+
+ /* stat the path to attempt to determine if the file is special */
+ if (stat(unix_path, &statbuf) == 0) {
+ /* stat suceeded so can check for directory */
+
+ if (S_ISDIR(statbuf.st_mode)) {
+ return "application/x-netsurf-directory";
+ }
+ }
+
+ l = strlen(unix_path);
+
+ /* Hacky RISC OS compatibility */
+ if ((3 < l) && (strcasecmp(unix_path + l - 4, ",f79") == 0)) {
+ return "text/css";
+ } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",faf") == 0)) {
+ return "text/html";
+ } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",b60") == 0)) {
+ return "image/png";
+ } else if ((3 < l) && (strcasecmp(unix_path + l - 4, ",ff9") == 0)) {
+ return "image/x-riscos-sprite";
+ }
+
+ if (strchr(unix_path, '.') == NULL) {
+ /* no extension anywhere! */
+ return "text/plain";
+ }
+
+ ptr = unix_path + strlen(unix_path);
+ while (*ptr != '.' && *ptr != '/') {
+ ptr--;
+ }
+
+ if (*ptr != '.') {
+ return "text/plain";
+ }
+
+ ext = strdup(ptr + 1); /* skip the . */
+
+ /* the hash table only contains lower-case versions - make sure this
+ * copy is lower case too.
+ */
+ lowerchar = ext;
+ while (*lowerchar) {
+ *lowerchar = tolower(*lowerchar);
+ lowerchar++;
+ }
+
+ type = hash_get(mime_hash, ext);
+ free(ext);
+
+ if (type == NULL) {
+ type = "text/plain";
+ }
+
+ return type;
+}
+
+
+static nsurl *nsgtk_get_resource_url(const char *path)
+{
+ char buf[PATH_MAX];
+ nsurl *url = NULL;
+
+ /* favicon.ico -> favicon.png */
+ if (strcmp(path, "favicon.ico") == 0) {
+ nsurl_create("resource:favicon.png", &url);
+ } else {
+ netsurf_path_to_nsurl(filepath_sfind(respaths, buf, path), &url);
+ }
+
+ return url;
+}
+
+static struct gui_fetch_table fetch_table = {
+ .filetype = fetch_filetype,
+
+ .get_resource_url = nsgtk_get_resource_url,
+ .get_resource_data = nsgtk_data_from_resname,
+};
+
+struct gui_fetch_table *nsgtk_fetch_table = &fetch_table;
diff --git a/frontends/gtk/fetch.h b/frontends/gtk/fetch.h
new file mode 100644
index 000000000..a095adbf9
--- /dev/null
+++ b/frontends/gtk/fetch.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_GTK_FETCH_H
+#define NETSURF_GTK_FETCH_H
+
+struct gui_fetch_table *nsgtk_fetch_table;
+
+void gtk_fetch_filetype_init(const char *mimefile);
+void gtk_fetch_filetype_fin(void);
+const char *fetch_filetype(const char *unix_path);
+
+#endif
diff --git a/frontends/gtk/gdk.c b/frontends/gtk/gdk.c
new file mode 100644
index 000000000..9ed90bd8e
--- /dev/null
+++ b/frontends/gtk/gdk.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "utils/log.h"
+
+#include "gtk/gdk.h"
+
+static void
+convert_alpha(guchar *dest_data,
+ int dest_stride,
+ guchar *src_data,
+ int src_stride,
+ int width,
+ int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) src_data;
+
+ for (x = 0; x < width; x++) {
+ guint alpha = src[x] >> 24;
+
+ if (alpha == 0) {
+ dest_data[x * 4 + 0] = 0;
+ dest_data[x * 4 + 1] = 0;
+ dest_data[x * 4 + 2] = 0;
+ } else {
+ dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ }
+ dest_data[x * 4 + 3] = alpha;
+ }
+
+ src_data += src_stride;
+ dest_data += dest_stride;
+ }
+}
+
+
+GdkPixbuf *
+nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int scwidth, int scheight)
+{
+ int width, height; /* source width and height */
+ cairo_surface_t *scsurface; /* scaled surface */
+ cairo_t *cr; /* cairo context for scaled surface */
+ GdkPixbuf *pixbuf; /* The result pixel buffer */
+
+ /* create pixmap */
+ pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, scwidth, scheight);
+ if (pixbuf == NULL) {
+ return NULL;
+ }
+
+ memset(gdk_pixbuf_get_pixels(pixbuf),
+ 0xff,
+ gdk_pixbuf_get_rowstride(pixbuf) * scheight);
+
+ /* scale cairo surface into new surface the target size */
+ cairo_surface_flush(surface); /* ensure source surface is ready */
+
+ /* get source surface dimensions */
+ width = cairo_image_surface_get_width(surface);
+ height = cairo_image_surface_get_height(surface);
+
+ /* scaled surface always has an alpha chanel for ease */
+ scsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, scwidth, scheight);
+ if (cairo_surface_status(scsurface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(scsurface);
+ g_object_unref(pixbuf);
+ LOG("Surface creation failed");
+ return NULL;
+ }
+
+ cr = cairo_create(scsurface);
+
+ /* Scale *before* setting the source surface */
+ cairo_scale(cr, (double)scwidth / width, (double)scheight / height);
+ cairo_set_source_surface(cr, surface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of overlaying */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ /* copy data from surface into pixmap */
+ convert_alpha(gdk_pixbuf_get_pixels(pixbuf),
+ gdk_pixbuf_get_rowstride(pixbuf),
+ cairo_image_surface_get_data(scsurface),
+ cairo_image_surface_get_stride(scsurface),
+ scwidth, scheight);
+
+ cairo_surface_destroy(scsurface);
+
+ return pixbuf;
+}
+
diff --git a/frontends/gtk/gdk.h b/frontends/gtk/gdk.h
new file mode 100644
index 000000000..2fcee07f1
--- /dev/null
+++ b/frontends/gtk/gdk.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * GDK support functions for missing interfaces
+ */
+
+#ifndef NETSURF_GTK_GDK_H_
+#define NETSURF_GTK_GDK_H_
+
+#include <gtk/gtk.h>
+
+/** obtain a pixbuf of the specified size from a cairo surface.
+ *
+ * This is the same as the GTK+ 3 gdk_pixbuf_get_from_surface but
+ * actually works and is available on gtk 2
+ */
+GdkPixbuf *nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int width, int height);
+
+#endif /* NETSURF_GTK_GDK_H */
diff --git a/frontends/gtk/gettext.c b/frontends/gtk/gettext.c
new file mode 100644
index 000000000..a9f6f48be
--- /dev/null
+++ b/frontends/gtk/gettext.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 Vincent Sanders <vince@kyllikki.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Localised gettext message support (implementation).
+ *
+ * Wrappers for gettext to the internal native language message support.
+ */
+
+#include <stdlib.h>
+
+#include "utils/messages.h"
+#include "gtk/gettext.h"
+
+char *gettext(const char *msgid)
+{
+ return dcgettext(NULL, msgid, 0);
+}
+
+char *dgettext(const char *domainname, const char *msgid)
+{
+ return dcgettext(domainname, msgid, 0);
+}
+
+char *dcgettext(const char *domainname, const char *msgid, int category)
+{
+ return (void *)messages_get(msgid);
+}
diff --git a/frontends/gtk/gettext.h b/frontends/gtk/gettext.h
new file mode 100644
index 000000000..726ba356e
--- /dev/null
+++ b/frontends/gtk/gettext.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Localised message support (interface).
+ *
+ * Provide gettext interface to the utility localisation routines
+ */
+
+#ifndef _NETSURF_GTK_GETTEXT_MESSAGES_H_
+#define _NETSURF_GTK_GETTEXT_MESSAGES_H_
+
+char *gettext(const char *msgid);
+char *dgettext(const char *domainname, const char *msgid);
+char *dcgettext(const char *domainname, const char *msgid, int category);
+
+#endif
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
new file mode 100644
index 000000000..e705918bc
--- /dev/null
+++ b/frontends/gtk/gui.c
@@ -0,0 +1,1161 @@
+/*
+ * Copyright 2004-2010 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2010-2016 Vincent Sanders <vince@netsurf-browser.org>
+ * Copyright 2004-2009 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ * Copyright 2006-2009 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ * Copyright 2006-2008 Rob Kendrick <rjek@netsurf-browser.org>
+ * Copyright 2008 John Tytgat <joty@netsurf-browser.org>
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <gtk/gtk.h>
+
+#include "utils/filepath.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/file.h"
+#include "utils/nsoption.h"
+#include "content/fetchers.h"
+#include "content/hlcache.h"
+#include "content/urldb.h"
+#include "content/backing_store.h"
+#include "desktop/browser.h"
+#include "desktop/save_complete.h"
+#include "desktop/save_pdf.h"
+#include "desktop/searchweb.h"
+#include "desktop/textinput.h"
+#include "desktop/tree.h"
+#include "desktop/gui_misc.h"
+#include "desktop/netsurf.h"
+
+#include "gtk/compat.h"
+#include "gtk/warn.h"
+#include "gtk/completion.h"
+#include "gtk/cookies.h"
+#include "gtk/download.h"
+#include "gtk/fetch.h"
+#include "gtk/gui.h"
+#include "gtk/history.h"
+#include "gtk/hotlist.h"
+#include "gtk/throbber.h"
+#include "gtk/treeview.h"
+#include "gtk/window.h"
+#include "gtk/schedule.h"
+#include "gtk/selection.h"
+#include "gtk/search.h"
+#include "gtk/ssl_cert.h"
+#include "gtk/bitmap.h"
+#include "gtk/resources.h"
+#include "gtk/login.h"
+#include "gtk/layout_pango.h"
+
+bool nsgtk_complete = false;
+
+char *toolbar_indices_file_location;
+
+char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+
+GdkPixbuf *favicon_pixbuf; /** favicon default pixbuf */
+GdkPixbuf *win_default_icon_pixbuf; /** default window icon pixbuf */
+GdkPixbuf *arrow_down_pixbuf; /** arrow down pixbuf */
+
+GtkBuilder *warning_builder;
+
+char **respaths; /** resource search path vector */
+
+/**
+ * Cause an abnormal program termination.
+ *
+ * \note This never returns and is intended to terminate without any cleanup.
+ *
+ * \param error The message to display to the user.
+ */
+static void die(const char * const error)
+{
+ fprintf(stderr, "%s", error);
+ exit(EXIT_FAILURE);
+}
+
+/**
+ * Create an array of valid paths to search for resources.
+ *
+ * The idea is that all the complex path computation to find resources
+ * is performed here, once, rather than every time a resource is
+ * searched for.
+ */
+static char **
+nsgtk_init_resource_path(const char *config_home)
+{
+ char *resource_path;
+ int resource_path_len;
+ const gchar * const *langv;
+ char **pathv; /* resource path string vector */
+ char **respath; /* resource paths vector */
+
+ if (config_home != NULL) {
+ resource_path_len = snprintf(NULL, 0,
+ "%s:${NETSURFRES}:%s",
+ config_home,
+ GTK_RESPATH);
+ resource_path = malloc(resource_path_len + 1);
+ if (resource_path == NULL) {
+ return NULL;
+ }
+ snprintf(resource_path, resource_path_len + 1,
+ "%s:${NETSURFRES}:%s",
+ config_home,
+ GTK_RESPATH);
+ } else {
+ resource_path_len = snprintf(NULL, 0,
+ "${NETSURFRES}:%s",
+ GTK_RESPATH);
+ resource_path = malloc(resource_path_len + 1);
+ if (resource_path == NULL) {
+ return NULL;
+ }
+ snprintf(resource_path,
+ resource_path_len + 1,
+ "${NETSURFRES}:%s",
+ GTK_RESPATH);
+ }
+
+ pathv = filepath_path_to_strvec(resource_path);
+
+ langv = g_get_language_names();
+
+ respath = filepath_generate(pathv, langv);
+
+ filepath_free_strvec(pathv);
+
+ free(resource_path);
+
+ return respath;
+}
+
+
+/**
+ * Set option defaults for gtk frontend.
+ *
+ * @param defaults The option table to update.
+ * @return error status.
+ */
+static nserror set_defaults(struct nsoption_s *defaults)
+{
+ char *fname;
+
+ /* cookie file default */
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_file, fname);
+ }
+
+ /* cookie jar default */
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_jar, fname);
+ }
+
+ /* url database default */
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs");
+ if (fname != NULL) {
+ nsoption_setnull_charp(url_file, fname);
+ }
+
+ /* bookmark database default */
+ fname = NULL;
+ netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist");
+ if (fname != NULL) {
+ nsoption_setnull_charp(hotlist_path, fname);
+ }
+
+ /* download directory default */
+ fname = getenv("HOME");
+ if (fname != NULL) {
+ nsoption_setnull_charp(downloads_directory, strdup(fname));
+ }
+
+ /* default path to certificates */
+ nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs"));
+
+ if ((nsoption_charp(cookie_file) == NULL) ||
+ (nsoption_charp(cookie_jar) == NULL) ||
+ (nsoption_charp(url_file) == NULL) ||
+ (nsoption_charp(hotlist_path) == NULL) ||
+ (nsoption_charp(downloads_directory) == NULL) ||
+ (nsoption_charp(ca_path) == NULL)) {
+ LOG("Failed initialising default resource paths");
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* set default font names */
+ nsoption_set_charp(font_sans, strdup("Sans"));
+ nsoption_set_charp(font_serif, strdup("Serif"));
+ nsoption_set_charp(font_mono, strdup("Monospace"));
+ nsoption_set_charp(font_cursive, strdup("Serif"));
+ nsoption_set_charp(font_fantasy, strdup("Serif"));
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Initialize GTK interface.
+ */
+static nserror nsgtk_init(int argc, char** argv, char **respath)
+{
+ char buf[PATH_MAX];
+ char *resource_filename;
+ char *addr = NULL;
+ nsurl *url;
+ nserror error;
+
+ error = nsgtk_builder_new_from_resname("warning", &warning_builder);
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise warning dialog");
+ return error;
+ }
+
+ gtk_builder_connect_signals(warning_builder, NULL);
+
+ /* set default icon if its available */
+ error = nsgdk_pixbuf_new_from_resname("netsurf.xpm",
+ &win_default_icon_pixbuf);
+ if (error == NSERROR_OK) {
+ LOG("Seting default window icon");
+ gtk_window_set_default_icon(win_default_icon_pixbuf);
+ }
+
+ /* Search engine sources */
+ resource_filename = filepath_find(respath, "SearchEngines");
+ search_web_init(resource_filename);
+ if (resource_filename != NULL) {
+ LOG("Using '%s' as Search Engines file", resource_filename);
+ free(resource_filename);
+ }
+
+ /* Default favicon */
+ error = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf);
+ if (error != NSERROR_OK) {
+ favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ false, 8, 16, 16);
+ }
+
+ /* arrow down icon */
+ error = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png",
+ &arrow_down_pixbuf);
+ if (error != NSERROR_OK) {
+ arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ false, 8, 8, 32);
+ }
+
+ /* Toolbar inicies file */
+ toolbar_indices_file_location = filepath_find(respath,
+ "toolbarIndices");
+ LOG("Using '%s' as custom toolbar settings file",
+ toolbar_indices_file_location);
+
+ /* initialise throbber */
+ error = nsgtk_throbber_init();
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise throbber.");
+ return error;
+ }
+
+ /* Initialise completions - cannot fail */
+ nsgtk_completion_init();
+
+ filepath_sfinddef(respath, buf, "mime.types", "/etc/");
+ gtk_fetch_filetype_init(buf);
+
+ save_complete_init();
+
+ urldb_load(nsoption_charp(url_file));
+ urldb_load_cookies(nsoption_charp(cookie_file));
+
+ /* The tree view system needs to know the screen's DPI, so we
+ * find that out here, rather than when we create a first browser
+ * window.
+ */
+ browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default()));
+ LOG("Set CSS DPI to %d", browser_get_dpi());
+
+ /* Initialise top level UI elements */
+ error = nsgtk_history_init();
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise global history window.");
+ return error;
+ }
+
+ error = nsgtk_download_init();
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise download window.");
+ return error;
+ }
+
+ error = nsgtk_cookies_init();
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise cookies window.");
+ return error;
+ }
+
+ error = nsgtk_hotlist_init();
+ if (error != NSERROR_OK) {
+ LOG("Unable to initialise hotlist window.");
+ return error;
+ }
+
+ /* If there is a url specified on the command line use it */
+ if (argc > 1) {
+ struct stat fs;
+ if (stat(argv[1], &fs) == 0) {
+ size_t addrlen;
+ char *rp = realpath(argv[1], NULL);
+ assert(rp != NULL);
+
+ /* calculate file url length including terminator */
+ addrlen = SLEN("file://") + strlen(rp) + 1;
+ addr = malloc(addrlen);
+ assert(addr != NULL);
+ snprintf(addr, addrlen, "file://%s", rp);
+ free(rp);
+ } else {
+ addr = strdup(argv[1]);
+ }
+ }
+ if (addr != NULL) {
+ /* managed to set up based on local launch */
+ } else if (nsoption_charp(homepage_url) != NULL) {
+ addr = strdup(nsoption_charp(homepage_url));
+ } else {
+ addr = strdup(NETSURF_HOMEPAGE);
+ }
+
+ /* create an initial browser window */
+ error = nsurl_create(addr, &url);
+ if (error == NSERROR_OK) {
+ error = browser_window_create(BW_CREATE_HISTORY,
+ url,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+
+ free(addr);
+
+ return error;
+}
+
+
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
+
+ return true;
+}
+
+
+/**
+ * Run the gtk event loop.
+ *
+ * The same as the standard gtk_main loop except this ensures active
+ * FD are added to the gtk poll event set.
+ */
+static void nsgtk_main(void)
+{
+ fd_set read_fd_set, write_fd_set, exc_fd_set;
+ int max_fd;
+ GPollFD *fd_list[1000];
+ unsigned int fd_count;
+
+ while (!nsgtk_complete) {
+ max_fd = -1;
+ fd_count = 0;
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&exc_fd_set);
+
+ fetcher_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd);
+ for (int i = 0; i <= max_fd; i++) {
+ if (FD_ISSET(i, &read_fd_set)) {
+ GPollFD *fd = malloc(sizeof *fd);
+ fd->fd = i;
+ fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+ g_main_context_add_poll(0, fd, 0);
+ fd_list[fd_count++] = fd;
+ }
+ if (FD_ISSET(i, &write_fd_set)) {
+ GPollFD *fd = malloc(sizeof *fd);
+ fd->fd = i;
+ fd->events = G_IO_OUT | G_IO_ERR;
+ g_main_context_add_poll(0, fd, 0);
+ fd_list[fd_count++] = fd;
+ }
+ if (FD_ISSET(i, &exc_fd_set)) {
+ GPollFD *fd = malloc(sizeof *fd);
+ fd->fd = i;
+ fd->events = G_IO_ERR;
+ g_main_context_add_poll(0, fd, 0);
+ fd_list[fd_count++] = fd;
+ }
+ }
+
+ schedule_run();
+
+ gtk_main_iteration();
+
+ for (unsigned int i = 0; i != fd_count; i++) {
+ g_main_context_remove_poll(0, fd_list[i]);
+ free(fd_list[i]);
+ }
+ }
+}
+
+
+static void gui_quit(void)
+{
+ LOG("Quitting GUI");
+
+ /* Ensure all scaffoldings are destroyed before we go into exit */
+ nsgtk_download_destroy();
+ urldb_save_cookies(nsoption_charp(cookie_jar));
+ urldb_save(nsoption_charp(url_file));
+ nsgtk_cookies_destroy();
+ nsgtk_history_destroy();
+ nsgtk_hotlist_destroy();
+
+ free(toolbar_indices_file_location);
+
+ free(nsgtk_config_home);
+
+ gtk_fetch_filetype_fin();
+}
+
+static nserror gui_launch_url(struct nsurl *url)
+{
+ gboolean ok;
+ GError *error = NULL;
+
+ ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error);
+ if (ok == TRUE) {
+ return NSERROR_OK;
+ }
+
+ if (error) {
+ nsgtk_warning(messages_get("URIOpenError"), error->message);
+ g_error_free(error);
+ }
+ return NSERROR_NO_FETCH_HANDLER;
+}
+
+/* exported function documented in gtk/warn.h */
+nserror nsgtk_warning(const char *warning, const char *detail)
+{
+ char buf[300]; /* 300 is the size the RISC OS GUI uses */
+ static GtkWindow *nsgtk_warning_window;
+ GtkLabel *WarningLabel;
+
+ LOG("%s %s", warning, detail ? detail : "");
+ fflush(stdout);
+
+ nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
+ WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder,
+ "labelWarning"));
+
+ snprintf(buf, sizeof(buf), "%s %s", messages_get(warning),
+ detail ? detail : "");
+ buf[sizeof(buf) - 1] = 0;
+
+ gtk_label_set_text(WarningLabel, buf);
+
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window));
+
+ return NSERROR_OK;
+}
+
+
+static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data)
+{
+ char **owner_pass = ((void **)data)[0];
+ char **user_pass = ((void **)data)[1];
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ char *op, *op1;
+ char *up, *up1;
+
+ op = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword"))));
+ op1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword1"))));
+ up = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword"))));
+ up1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword1"))));
+
+
+ if (op[0] == '\0') {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "Owner password must be at least 1 character long:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, up)) {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "User and owner passwords must be different:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, op1) && !strcmp(up, up1)) {
+
+ *owner_pass = op;
+ if (up[0] == '\0')
+ free(up);
+ else
+ *user_pass = up;
+
+ free(data);
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+ } else {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")), "Passwords not confirmed:");
+ free(op);
+ free(up);
+ }
+
+ free(op1);
+ free(up1);
+}
+
+static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data)
+{
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ free(data);
+
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+}
+
+static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
+{
+ GtkButton *ok, *no;
+ GtkWindow *wnd;
+ void **data;
+ GtkBuilder *password_builder;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("password", &password_builder);
+ if (res != NSERROR_OK) {
+ LOG("Password UI builder init failed");
+ return;
+ }
+
+ gtk_builder_connect_signals(password_builder, NULL);
+
+ wnd = GTK_WINDOW(gtk_builder_get_object(password_builder,
+ "wndPDFPassword"));
+
+ data = malloc(5 * sizeof(void *));
+
+ *owner_pass = NULL;
+ *user_pass = NULL;
+
+ data[0] = owner_pass;
+ data[1] = user_pass;
+ data[2] = wnd;
+ data[3] = password_builder;
+ data[4] = path;
+
+ ok = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFSetPassword"));
+ no = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFNoPassword"));
+
+ g_signal_connect(G_OBJECT(ok), "clicked",
+ G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data);
+ g_signal_connect(G_OBJECT(no), "clicked",
+ G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data);
+
+ gtk_widget_show(GTK_WIDGET(wnd));
+}
+
+
+uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
+{
+ /* this function will need to become much more complex to support
+ * everything that the RISC OS version does. But this will do for
+ * now. I hope.
+ */
+ switch (key->keyval) {
+
+ case GDK_KEY(Tab):
+ return NS_KEY_TAB;
+
+ case GDK_KEY(BackSpace):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_START;
+ else
+ return NS_KEY_DELETE_LEFT;
+ case GDK_KEY(Delete):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_END;
+ else
+ return NS_KEY_DELETE_RIGHT;
+ case GDK_KEY(Linefeed): return 13;
+ case GDK_KEY(Return): return 10;
+ case GDK_KEY(Left): return NS_KEY_LEFT;
+ case GDK_KEY(Right): return NS_KEY_RIGHT;
+ case GDK_KEY(Up): return NS_KEY_UP;
+ case GDK_KEY(Down): return NS_KEY_DOWN;
+ case GDK_KEY(Home):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_TEXT_START;
+ else
+ return NS_KEY_LINE_START;
+ case GDK_KEY(End):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_TEXT_END;
+ else
+ return NS_KEY_LINE_END;
+ case GDK_KEY(Page_Up):
+ return NS_KEY_PAGE_UP;
+ case GDK_KEY(Page_Down):
+ return NS_KEY_PAGE_DOWN;
+ case 'a':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_SELECT_ALL;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'u':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_LINE;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'c':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_COPY_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'v':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_PASTE;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'x':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_CUT_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'Z':
+ case 'y':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_REDO;
+ return gdk_keyval_to_unicode(key->keyval);
+ case 'z':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_UNDO;
+ return gdk_keyval_to_unicode(key->keyval);
+ case GDK_KEY(Escape):
+ return NS_KEY_ESCAPE;
+
+ /* Modifiers - do nothing for now */
+ case GDK_KEY(Shift_L):
+ case GDK_KEY(Shift_R):
+ case GDK_KEY(Control_L):
+ case GDK_KEY(Control_R):
+ case GDK_KEY(Caps_Lock):
+ case GDK_KEY(Shift_Lock):
+ case GDK_KEY(Meta_L):
+ case GDK_KEY(Meta_R):
+ case GDK_KEY(Alt_L):
+ case GDK_KEY(Alt_R):
+ case GDK_KEY(Super_L):
+ case GDK_KEY(Super_R):
+ case GDK_KEY(Hyper_L):
+ case GDK_KEY(Hyper_R):
+ return 0;
+
+ default:
+ return gdk_keyval_to_unicode(key->keyval);
+ }
+}
+
+
+/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname = NULL;
+ struct stat dirname_stat;
+
+ ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;
+}
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ LOG("\"%s\"", config_home);
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG("\"%s\"", config_home);
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home = NULL;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ LOG("Attempting to create configuration directory");
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ LOG("\"%s\"", config_home);
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Get the path to the cache directory.
+ *
+ * @param cache_home_out Path to cache directory.
+ * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
+ */
+static nserror get_cache_home(char **cache_home_out)
+{
+ nserror ret;
+ char *xdg_cache_dir;
+ char *cache_home;
+ char *home_dir;
+
+ /* $XDG_CACHE_HOME defines the base directory relative to
+ * which user specific non-essential data files should be
+ * stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ /* If $XDG_CACHE_HOME is either not set or empty, a
+ * default equal to $HOME/.cache should be used.
+ */
+
+ home_dir = getenv("HOME");
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG("\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+ return NSERROR_OK;
+}
+
+static nserror create_cache_home(char **cache_home_out)
+{
+ char *cache_home = NULL;
+ char *home_dir;
+ char *xdg_cache_dir;
+ nserror ret;
+
+ LOG("Attempting to create configuration directory");
+
+ /* $XDG_CACHE_HOME defines the base directory
+ * relative to which user specific cache files
+ * should be stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(cache_home);
+ if (ret != NSERROR_OK) {
+ free(cache_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ cache_home[strlen(cache_home) - 1] = 0;
+
+ LOG("\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+
+ return NSERROR_OK;
+}
+
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices = NULL;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (ret == NSERROR_OK) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
+static struct gui_misc_table nsgtk_misc_table = {
+ .schedule = nsgtk_schedule,
+ .warning = nsgtk_warning,
+
+ .quit = gui_quit,
+ .launch_url = gui_launch_url,
+ .cert_verify = gtk_cert_verify,
+ .login = gui_401login_open,
+ .pdf_password = nsgtk_pdf_password,
+};
+
+
+static nserror nsgtk_messages_init(char **respaths)
+{
+ const char *messages;
+ nserror ret;
+ const uint8_t *data;
+ size_t data_size;
+
+ ret = nsgtk_data_from_resname("Messages", &data, &data_size);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_inline(data, data_size);
+ } else {
+ /* Obtain path to messages */
+ ret = nsgtk_path_from_resname("Messages", &messages);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_file(messages);
+ }
+ }
+ return ret;
+}
+
+/**
+ * Main entry point from OS.
+ */
+int main(int argc, char** argv)
+{
+ char *cache_home = NULL;
+ nserror ret;
+ struct netsurf_table nsgtk_table = {
+ .misc = &nsgtk_misc_table,
+ .window = nsgtk_window_table,
+ .clipboard = nsgtk_clipboard_table,
+ .download = nsgtk_download_table,
+ .fetch = nsgtk_fetch_table,
+ .llcache = filesystem_llcache_table,
+ .search = nsgtk_search_table,
+ .search_web = nsgtk_search_web_table,
+ .bitmap = nsgtk_bitmap_table,
+ .layout = nsgtk_layout_table,
+ };
+
+ ret = netsurf_register(&nsgtk_table);
+ if (ret != NSERROR_OK) {
+ die("NetSurf operation table failed registration\n");
+ }
+
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG("Unable to locate a configuration directory.");
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
+ gtk_init(&argc, &argv);
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, &argc, argv);
+
+ /* build the common resource path list */
+ respaths = nsgtk_init_resource_path(nsgtk_config_home);
+ if (respaths == NULL) {
+ fprintf(stderr, "Unable to locate resources\n");
+ return 1;
+ }
+
+ /* initialise the gtk resource handling */
+ ret = nsgtk_init_resources(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "GTK resources failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return 1;
+ }
+
+ /* Initialise user options */
+ ret = nsgtk_option_init(&argc, argv);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Options failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return 1;
+ }
+
+ /* Initialise translated messages */
+ ret = nsgtk_messages_init(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Unable to load translated messages (%s)\n",
+ messages_get_errorcode(ret));
+ LOG("Unable to load translated messages");
+ /** \todo decide if message load faliure should be fatal */
+ }
+
+ /* Locate the correct user cache directory path */
+ ret = get_cache_home(&cache_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no cache directory exists yet so try to create one */
+ ret = create_cache_home(&cache_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG("Unable to locate a cache directory.");
+ }
+
+ /* core initialisation */
+ ret = netsurf_init(cache_home);
+ free(cache_home);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return 1;
+ }
+
+ /* run the browser */
+ ret = nsgtk_init(argc, argv, respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
+ messages_get_errorcode(ret));
+ } else {
+ nsgtk_main();
+ }
+
+ /* common finalisation */
+ netsurf_exit();
+
+ /* finalise options */
+ nsoption_finalise(nsoptions, nsoptions_default);
+
+ return 0;
+}
diff --git a/frontends/gtk/gui.h b/frontends/gtk/gui.h
new file mode 100644
index 000000000..b6a6dc994
--- /dev/null
+++ b/frontends/gtk/gui.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTK_GUI_H
+#define GTK_GUI_H
+
+struct nsurl;
+
+/** toolbar arrangement file path. */
+extern char *toolbar_indices_file_location;
+
+/** Directory where all configuration files are held. */
+extern char *nsgtk_config_home;
+
+/** favicon default pixbuf */
+extern GdkPixbuf *favicon_pixbuf;
+
+/** arrow down pixbuf */
+extern GdkPixbuf *arrow_down_pixbuf;
+
+/** resource search path vector */
+extern char **respaths;
+
+/** input conversion. */
+uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *eventkey);
+
+/** set when no windows remain open. */
+extern bool nsgtk_complete;
+
+#endif /* GTK_GUI_H */
diff --git a/frontends/gtk/history.c b/frontends/gtk/history.c
new file mode 100644
index 000000000..9c5c0b5e4
--- /dev/null
+++ b/frontends/gtk/history.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "desktop/global_history.h"
+#include "desktop/plot_style.h"
+#include "desktop/tree.h"
+#include "desktop/textinput.h"
+
+#include "gtk/plotters.h"
+#include "gtk/scaffolding.h"
+#include "gtk/treeview.h"
+#include "gtk/compat.h"
+#include "gtk/resources.h"
+#include "gtk/history.h"
+
+#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
+ GtkMenuItem *widget, gpointer g)
+#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) }
+#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \
+ gpointer g)
+
+struct menu_events {
+ const char *widget;
+ GCallback handler;
+};
+
+/* file menu*/
+MENUPROTO(export);
+
+/* edit menu */
+MENUPROTO(delete_selected);
+MENUPROTO(delete_all);
+MENUPROTO(select_all);
+MENUPROTO(clear_selection);
+
+/* view menu*/
+MENUPROTO(expand_all);
+MENUPROTO(expand_directories);
+MENUPROTO(expand_addresses);
+MENUPROTO(collapse_all);
+MENUPROTO(collapse_directories);
+MENUPROTO(collapse_addresses);
+
+MENUPROTO(launch);
+
+static struct menu_events menu_events[] = {
+
+ /* file menu*/
+ MENUEVENT(export),
+
+ /* edit menu */
+ MENUEVENT(delete_selected),
+ MENUEVENT(delete_all),
+ MENUEVENT(select_all),
+ MENUEVENT(clear_selection),
+
+ /* view menu*/
+ MENUEVENT(expand_all),
+ MENUEVENT(expand_directories),
+ MENUEVENT(expand_addresses),
+ MENUEVENT(collapse_all),
+ MENUEVENT(collapse_directories),
+ MENUEVENT(collapse_addresses),
+
+ MENUEVENT(launch),
+ {NULL, NULL}
+};
+
+static struct nsgtk_treeview *global_history_window;
+static GtkBuilder *history_builder;
+GtkWindow *wndHistory;
+
+/**
+ * Connects menu events in the global history window.
+ */
+static void nsgtk_history_init_menu(void)
+{
+ struct menu_events *event = menu_events;
+ GtkWidget *w;
+
+ while (event->widget != NULL) {
+ w = GTK_WIDGET(gtk_builder_get_object(history_builder,
+ event->widget));
+ if (w == NULL) {
+ LOG("Unable to connect menu widget ""%s""",
+ event->widget);
+ } else {
+ g_signal_connect(G_OBJECT(w),
+ "activate",
+ event->handler,
+ global_history_window);
+ }
+ event++;
+ }
+}
+
+/* exported interface, documented in gtk/history.h */
+nserror nsgtk_history_init(void)
+{
+ GtkWindow *window;
+ GtkScrolledWindow *scrolled;
+ GtkDrawingArea *drawing_area;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("history", &history_builder);
+ if (res != NSERROR_OK) {
+ LOG("History UI builder init failed");
+ return res;
+ }
+ gtk_builder_connect_signals(history_builder, NULL);
+
+ wndHistory = GTK_WINDOW(gtk_builder_get_object(history_builder,
+ "wndHistory"));
+
+ window = wndHistory;
+
+ scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(history_builder,
+ "globalHistoryScrolled"));
+
+ drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(history_builder,
+ "globalHistoryDrawingArea"));
+
+ global_history_window = nsgtk_treeview_create(TREE_HISTORY,
+ window,
+ scrolled,
+ drawing_area);
+ if (global_history_window == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+#define CONNECT(obj, sig, callback, ptr) \
+ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
+
+ CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL);
+ CONNECT(window, "hide", nsgtk_tree_window_hide, global_history_window);
+
+ nsgtk_history_init_menu();
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Destroys the global history window and performs any other necessary cleanup
+ * actions.
+ */
+void nsgtk_history_destroy(void)
+{
+ /** \todo what about history_builder? */
+ nsgtk_treeview_destroy(global_history_window);
+}
+
+
+/* file menu */
+MENUHANDLER(export)
+{
+ GtkWidget *save_dialog;
+ save_dialog = gtk_file_chooser_dialog_new("Save File",
+ wndHistory,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog),
+ getenv("HOME") ? getenv("HOME") : "/");
+
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
+ "history.html");
+
+ if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) {
+ gchar *filename = gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(save_dialog));
+
+ global_history_export(filename, NULL);
+ g_free(filename);
+ }
+
+ gtk_widget_destroy(save_dialog);
+
+ return TRUE;
+}
+
+/* edit menu */
+MENUHANDLER(delete_selected)
+{
+ global_history_keypress(NS_KEY_DELETE_LEFT);
+ return TRUE;
+}
+
+MENUHANDLER(delete_all)
+{
+ global_history_keypress(NS_KEY_SELECT_ALL);
+ global_history_keypress(NS_KEY_DELETE_LEFT);
+ return TRUE;
+}
+
+MENUHANDLER(select_all)
+{
+ global_history_keypress(NS_KEY_SELECT_ALL);
+ return TRUE;
+}
+
+MENUHANDLER(clear_selection)
+{
+ global_history_keypress(NS_KEY_CLEAR_SELECTION);
+ return TRUE;
+}
+
+/* view menu*/
+MENUHANDLER(expand_all)
+{
+ global_history_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(expand_directories)
+{
+ global_history_expand(true);
+ return TRUE;
+}
+
+MENUHANDLER(expand_addresses)
+{
+ global_history_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_all)
+{
+ global_history_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_directories)
+{
+ global_history_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_addresses)
+{
+ global_history_contract(false);
+ return TRUE;
+}
+
+MENUHANDLER(launch)
+{
+ global_history_keypress(NS_KEY_CR);
+ return TRUE;
+}
diff --git a/frontends/gtk/history.h b/frontends/gtk/history.h
new file mode 100644
index 000000000..c0f7db2bd
--- /dev/null
+++ b/frontends/gtk/history.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NSGTK_HISTORY_H__
+#define __NSGTK_HISTORY_H__
+
+#include <gtk/gtk.h>
+
+extern GtkWindow *wndHistory;
+
+/**
+ * Creates the window for the global history tree.
+ *
+ * \return NSERROR_OK on sucess else appropriate error code.
+ */
+nserror nsgtk_history_init(void);
+
+/**
+ * Free global resources associated with the gtk history window.
+ */
+void nsgtk_history_destroy(void);
+
+#endif /* __NSGTK_HISTORY_H__ */
diff --git a/frontends/gtk/hotlist.c b/frontends/gtk/hotlist.c
new file mode 100644
index 000000000..06fd5cd69
--- /dev/null
+++ b/frontends/gtk/hotlist.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "desktop/hotlist.h"
+#include "desktop/tree.h"
+
+#include "gtk/plotters.h"
+#include "gtk/scaffolding.h"
+#include "gtk/treeview.h"
+#include "gtk/compat.h"
+#include "gtk/resources.h"
+#include "gtk/hotlist.h"
+
+#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
+ GtkMenuItem *widget, gpointer g)
+#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) }
+#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \
+ gpointer g)
+
+struct menu_events {
+ const char *widget;
+ GCallback handler;
+};
+
+
+/* file menu*/
+MENUPROTO(export);
+MENUPROTO(new_folder);
+MENUPROTO(new_entry);
+
+/* edit menu */
+MENUPROTO(edit_selected);
+MENUPROTO(delete_selected);
+MENUPROTO(select_all);
+MENUPROTO(clear_selection);
+
+/* view menu*/
+MENUPROTO(expand_all);
+MENUPROTO(expand_directories);
+MENUPROTO(expand_addresses);
+MENUPROTO(collapse_all);
+MENUPROTO(collapse_directories);
+MENUPROTO(collapse_addresses);
+
+MENUPROTO(launch);
+
+static struct menu_events menu_events[] = {
+
+ /* file menu*/
+ MENUEVENT(export),
+ MENUEVENT(new_folder),
+ MENUEVENT(new_entry),
+
+ /* edit menu */
+ MENUEVENT(edit_selected),
+ MENUEVENT(delete_selected),
+ MENUEVENT(select_all),
+ MENUEVENT(clear_selection),
+
+ /* view menu*/
+ MENUEVENT(expand_all),
+ MENUEVENT(expand_directories),
+ MENUEVENT(expand_addresses),
+ MENUEVENT(collapse_all),
+ MENUEVENT(collapse_directories),
+ MENUEVENT(collapse_addresses),
+
+ MENUEVENT(launch),
+ {NULL, NULL}
+};
+
+static struct nsgtk_treeview *hotlist_treeview;
+static GtkBuilder *hotlist_builder;
+GtkWindow *wndHotlist;
+
+/**
+ * Connects menu events in the hotlist window.
+ */
+static void nsgtk_hotlist_init_menu(void)
+{
+ struct menu_events *event = menu_events;
+ GtkWidget *w;
+
+ while (event->widget != NULL) {
+ w = GTK_WIDGET(gtk_builder_get_object(hotlist_builder, event->widget));
+ if (w == NULL) {
+ LOG("Unable to connect menu widget ""%s""", event->widget); } else {
+ g_signal_connect(G_OBJECT(w), "activate", event->handler, hotlist_treeview);
+ }
+ event++;
+ }
+}
+
+/* exported interface docuemnted in gtk/hotlist.h */
+nserror nsgtk_hotlist_init(void)
+{
+ GtkWindow *window;
+ GtkScrolledWindow *scrolled;
+ GtkDrawingArea *drawing_area;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("hotlist", &hotlist_builder);
+ if (res != NSERROR_OK) {
+ LOG("Cookie UI builder init failed");
+ return res;
+ }
+
+ gtk_builder_connect_signals(hotlist_builder, NULL);
+
+ wndHotlist = GTK_WINDOW(gtk_builder_get_object(hotlist_builder, "wndHotlist"));
+ window = wndHotlist;
+
+ scrolled = GTK_SCROLLED_WINDOW(gtk_builder_get_object(hotlist_builder,
+ "hotlistScrolled"));
+
+ drawing_area = GTK_DRAWING_AREA(gtk_builder_get_object(hotlist_builder,
+ "hotlistDrawingArea"));
+
+
+ tree_hotlist_path = nsoption_charp(hotlist_path);
+ hotlist_treeview = nsgtk_treeview_create(TREE_HOTLIST, window,
+ scrolled, drawing_area);
+
+ if (hotlist_treeview == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+#define CONNECT(obj, sig, callback, ptr) \
+ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
+
+ CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL);
+ CONNECT(window, "hide", nsgtk_tree_window_hide, hotlist_treeview);
+
+ nsgtk_hotlist_init_menu();
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Destroys the hotlist window and performs any other necessary cleanup actions.
+ */
+void nsgtk_hotlist_destroy(void)
+{
+ /** \todo what about hotlist_builder? */
+ nsgtk_treeview_destroy(hotlist_treeview);
+}
+
+
+/* file menu*/
+MENUHANDLER(export)
+{
+ GtkWidget *save_dialog;
+ save_dialog = gtk_file_chooser_dialog_new("Save File",
+ wndHotlist,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog),
+ getenv("HOME") ? getenv("HOME") : "/");
+
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
+ "hotlist.html");
+
+ if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) {
+ gchar *filename = gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(save_dialog));
+
+ hotlist_export(filename, NULL);
+ g_free(filename);
+ }
+
+ gtk_widget_destroy(save_dialog);
+
+ return TRUE;
+}
+
+MENUHANDLER(new_folder)
+{
+ hotlist_add_folder(NULL, false, 0);
+ return TRUE;
+}
+
+MENUHANDLER(new_entry)
+{
+ hotlist_add_entry(NULL, NULL, false, 0);
+ return TRUE;
+}
+
+/* edit menu */
+MENUHANDLER(edit_selected)
+{
+ hotlist_edit_selection();
+ return TRUE;
+}
+
+MENUHANDLER(delete_selected)
+{
+ hotlist_keypress(NS_KEY_DELETE_LEFT);
+ return TRUE;
+}
+
+MENUHANDLER(select_all)
+{
+ hotlist_keypress(NS_KEY_SELECT_ALL);
+ return TRUE;
+}
+
+MENUHANDLER(clear_selection)
+{
+ hotlist_keypress(NS_KEY_CLEAR_SELECTION);
+ return TRUE;
+}
+
+/* view menu*/
+MENUHANDLER(expand_all)
+{
+ hotlist_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(expand_directories)
+{
+ hotlist_expand(true);
+ return TRUE;
+}
+
+MENUHANDLER(expand_addresses)
+{
+ hotlist_expand(false);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_all)
+{
+ hotlist_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_directories)
+{
+ hotlist_contract(true);
+ return TRUE;
+}
+
+MENUHANDLER(collapse_addresses)
+{
+ hotlist_contract(false);
+ return TRUE;
+}
+
+MENUHANDLER(launch)
+{
+ hotlist_keypress(NS_KEY_CR);
+ return TRUE;
+}
diff --git a/frontends/gtk/hotlist.h b/frontends/gtk/hotlist.h
new file mode 100644
index 000000000..01e5a86c5
--- /dev/null
+++ b/frontends/gtk/hotlist.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * GTK hotlist (interface).
+ */
+
+#ifndef __NSGTK_HOTLIST_H__
+#define __NSGTK_HOTLIST_H__
+
+#include <gtk/gtk.h>
+
+extern GtkWindow *wndHotlist;
+
+/**
+ * Initialise the gtk specific hotlist (bookmarks) display.
+ *
+ * \return NSERROR_OK on success else appropriate error code on faliure.
+ */
+nserror nsgtk_hotlist_init(void);
+
+
+void nsgtk_hotlist_destroy(void);
+
+#endif /* __NSGTK_HOTLIST_H__ */
diff --git a/frontends/gtk/layout_pango.c b/frontends/gtk/layout_pango.c
new file mode 100644
index 000000000..49b629399
--- /dev/null
+++ b/frontends/gtk/layout_pango.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK implementation of layout handling using pango.
+ *
+ * Pango is used handle and render fonts.
+ */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "desktop/gui_layout.h"
+
+#include "gtk/layout_pango.h"
+#include "gtk/plotters.h"
+
+static PangoContext *nsfont_pango_context = NULL;
+static PangoLayout *nsfont_pango_layout = NULL;
+
+static inline void nsfont_pango_check(void)
+{
+ if (nsfont_pango_context == NULL) {
+ LOG("Creating nsfont_pango_context.");
+ nsfont_pango_context = gdk_pango_context_get();
+ }
+
+ if (nsfont_pango_layout == NULL) {
+ LOG("Creating nsfont_pango_layout.");
+ nsfont_pango_layout = pango_layout_new(nsfont_pango_context);
+ }
+}
+
+/**
+ * Measure the width of a string.
+ *
+ * \param[in] fstyle plot style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[out] width updated to width of string[0..length)
+ * \return NSERROR_OK and width updated or appropriate error code on faliure
+ */
+static nserror
+nsfont_width(const plot_font_style_t *fstyle,
+ const char *string,
+ size_t length,
+ int *width)
+{
+ PangoFontDescription *desc;
+
+ if (length == 0) {
+ *width = 0;
+ return NSERROR_OK;
+ }
+
+ nsfont_pango_check();
+
+ desc = nsfont_style_to_description(fstyle);
+ pango_layout_set_font_description(nsfont_pango_layout, desc);
+ pango_font_description_free(desc);
+
+ pango_layout_set_text(nsfont_pango_layout, string, length);
+
+ pango_layout_get_pixel_size(nsfont_pango_layout, width, 0);
+
+ /* LOG("fstyle: %p string:\"%.*s\", length: %u, width: %dpx",
+ fstyle, length, string, length, *width);
+ */
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param[in] fstyle style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[in] x coordinate to search for
+ * \param[out] char_offset updated to offset in string of actual_x, [0..length]
+ * \param[out] actual_x updated to x coordinate of character closest to x
+ * \return NSERROR_OK and char_offset and actual_x updated or appropriate
+ * error code on faliure
+ */
+static nserror
+nsfont_position_in_string(const plot_font_style_t *fstyle,
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
+{
+ int index;
+ PangoFontDescription *desc;
+ PangoRectangle pos;
+
+ nsfont_pango_check();
+
+ desc = nsfont_style_to_description(fstyle);
+ pango_layout_set_font_description(nsfont_pango_layout, desc);
+ pango_font_description_free(desc);
+
+ pango_layout_set_text(nsfont_pango_layout, string, length);
+
+ if (pango_layout_xy_to_index(nsfont_pango_layout,
+ x * PANGO_SCALE,
+ 0, &index, 0) == FALSE) {
+ index = length;
+ }
+
+ pango_layout_index_to_pos(nsfont_pango_layout, index, &pos);
+
+ *char_offset = index;
+ *actual_x = PANGO_PIXELS(pos.x);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param[in] fstyle style for this text
+ * \param[in] string UTF-8 string to measure
+ * \param[in] length length of string, in bytes
+ * \param[in] x width available
+ * \param[out] char_offset updated to offset in string of actual_x, [1..length]
+ * \param[out] actual_x updated to x coordinate of character closest to x
+ * \return NSERROR_OK or appropriate error code on faliure
+ *
+ * On exit, char_offset indicates first character after split point.
+ *
+ * \note char_offset of 0 must never be returned.
+ *
+ * Returns:
+ * char_offset giving split point closest to x, where actual_x <= x
+ * else
+ * char_offset giving split point closest to x, where actual_x > x
+ *
+ * Returning char_offset == length means no split possible
+ */
+static nserror
+nsfont_split(const plot_font_style_t *fstyle,
+ const char *string,
+ size_t length,
+ int x,
+ size_t *char_offset,
+ int *actual_x)
+{
+ int index = length;
+ PangoFontDescription *desc;
+ PangoContext *context;
+ PangoLayout *layout;
+ PangoLayoutLine *line;
+
+ context = gdk_pango_context_get();
+ layout = pango_layout_new(context);
+
+ desc = nsfont_style_to_description(fstyle);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+
+ pango_layout_set_text(layout, string, length);
+
+ /* Limit width of layout to the available width */
+ pango_layout_set_width(layout, x * PANGO_SCALE);
+
+ /* Request word wrapping */
+ pango_layout_set_wrap(layout, PANGO_WRAP_WORD);
+
+ /* Prevent pango treating linebreak characters as line breaks */
+ pango_layout_set_single_paragraph_mode(layout, TRUE);
+
+ /* Obtain the second line of the layout (if there is one) */
+ line = pango_layout_get_line(layout, 1);
+ if (line != NULL) {
+ /* Pango split the text. The line's start_index indicates the
+ * start of the character after the line break. */
+ index = line->start_index;
+ }
+
+ g_object_unref(layout);
+ g_object_unref(context);
+
+ *char_offset = index;
+ /* Obtain the pixel offset of the split character */
+ nsfont_width(fstyle, string, index, actual_x);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Render a string.
+ *
+ * \param x x coordinate
+ * \param y y coordinate
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param fstyle plot style for this text
+ * \return true on success, false on error and error reported
+ */
+bool nsfont_paint(int x, int y, const char *string, size_t length,
+ const plot_font_style_t *fstyle)
+{
+ PangoFontDescription *desc;
+ PangoLayout *layout;
+ PangoLayoutLine *line;
+
+ if (length == 0)
+ return true;
+
+ layout = pango_cairo_create_layout(current_cr);
+
+ desc = nsfont_style_to_description(fstyle);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+
+ pango_layout_set_text(layout, string, length);
+
+ line = pango_layout_get_line_readonly(layout, 0);
+ cairo_move_to(current_cr, x, y);
+ nsgtk_set_colour(fstyle->foreground);
+ pango_cairo_show_layout_line(current_cr, line);
+
+ g_object_unref(layout);
+
+ return true;
+}
+
+
+/* exported interface documented in gtk/layout_pango.h */
+PangoFontDescription *
+nsfont_style_to_description(const plot_font_style_t *fstyle)
+{
+ unsigned int size;
+ PangoFontDescription *desc;
+ PangoStyle style = PANGO_STYLE_NORMAL;
+
+ switch (fstyle->family) {
+ case PLOT_FONT_FAMILY_SERIF:
+ desc = pango_font_description_from_string(nsoption_charp(font_serif));
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ desc = pango_font_description_from_string(nsoption_charp(font_mono));
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ desc = pango_font_description_from_string(nsoption_charp(font_cursive));
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ desc = pango_font_description_from_string(nsoption_charp(font_fantasy));
+ break;
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ default:
+ desc = pango_font_description_from_string(nsoption_charp(font_sans));
+ break;
+ }
+
+ size = (fstyle->size * PANGO_SCALE) / FONT_SIZE_SCALE;
+
+ if (fstyle->flags & FONTF_ITALIC)
+ style = PANGO_STYLE_ITALIC;
+ else if (fstyle->flags & FONTF_OBLIQUE)
+ style = PANGO_STYLE_OBLIQUE;
+
+ pango_font_description_set_style(desc, style);
+
+ pango_font_description_set_weight(desc, (PangoWeight) fstyle->weight);
+
+ pango_font_description_set_size(desc, size);
+
+ if (fstyle->flags & FONTF_SMALLCAPS) {
+ pango_font_description_set_variant(desc,
+ PANGO_VARIANT_SMALL_CAPS);
+ } else {
+ pango_font_description_set_variant(desc, PANGO_VARIANT_NORMAL);
+ }
+
+ return desc;
+}
+
+static struct gui_layout_table layout_table = {
+ .width = nsfont_width,
+ .position = nsfont_position_in_string,
+ .split = nsfont_split,
+};
+
+struct gui_layout_table *nsgtk_layout_table = &layout_table;
diff --git a/frontends/gtk/layout_pango.h b/frontends/gtk/layout_pango.h
new file mode 100644
index 000000000..137cebe68
--- /dev/null
+++ b/frontends/gtk/layout_pango.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to GTK layout handling using pango.
+ */
+
+#ifndef _NETSURF_GTK_LAYOUT_PANGO_H_
+#define _NETSURF_GTK_LAYOUT_PANGO_H_
+
+#include <stdbool.h>
+
+struct plot_font_style;
+
+extern struct gui_layout_table *nsgtk_layout_table;
+
+bool nsfont_paint(int x, int y, const char *string, size_t length, const struct plot_font_style *fstyle);
+
+/**
+ * Convert a plot style to a PangoFontDescription.
+ *
+ * \param fstyle plot style for this text
+ * \return A new Pango font description
+ */
+PangoFontDescription *nsfont_style_to_description(const struct plot_font_style *fstyle);
+
+#endif
diff --git a/frontends/gtk/login.c b/frontends/gtk/login.c
new file mode 100644
index 000000000..ee77052d7
--- /dev/null
+++ b/frontends/gtk/login.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "content/urldb.h"
+
+#include "gtk/resources.h"
+#include "gtk/login.h"
+
+/** login window session data */
+struct session_401 {
+ nsurl *url; /**< URL being fetched */
+ lwc_string *host; /**< Host for user display */
+ char *realm; /**< Authentication realm */
+ nserror (*cb)(bool proceed, void *pw); /**< Continuation callback */
+ void *cbpw; /**< Continuation data */
+ GtkBuilder *x; /**< Our builder windows */
+ GtkWindow *wnd; /**< The login window itself */
+ GtkEntry *user; /**< Widget with username */
+ GtkEntry *pass; /**< Widget with password */
+};
+
+/**
+ * Destroy login window and free all associated resources
+ *
+ * \param session The login window session to destroy.
+ */
+static void destroy_login_window(struct session_401 *session)
+{
+ nsurl_unref(session->url);
+ lwc_string_unref(session->host);
+ free(session->realm);
+ gtk_widget_destroy(GTK_WIDGET(session->wnd));
+ g_object_unref(G_OBJECT(session->x));
+ free(session);
+}
+
+
+/**
+ * process next signal in entry widgets.
+ *
+ * \param w current widget
+ * \param data next widget
+ */
+static void nsgtk_login_next(GtkWidget *w, gpointer data)
+{
+ gtk_widget_grab_focus(GTK_WIDGET(data));
+}
+
+
+/**
+ * handler called when navigation is continued
+ *
+ * \param w current widget
+ * \param data login window session
+ */
+static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data)
+{
+ /* close the window and destroy it, having continued the fetch
+ * assoicated with it.
+ */
+
+ struct session_401 *session = (struct session_401 *)data;
+ const gchar *user = gtk_entry_get_text(session->user);
+ const gchar *pass = gtk_entry_get_text(session->pass);
+ char *auth;
+
+ auth = malloc(strlen(user) + strlen(pass) + 2);
+ sprintf(auth, "%s:%s", user, pass);
+ urldb_set_auth_details(session->url, session->realm, auth);
+ free(auth);
+
+ session->cb(true, session->cbpw);
+
+ destroy_login_window(session);
+}
+
+
+/**
+ * handler called when navigation is cancelled
+ *
+ * \param w widget
+ * \param data login window session
+ */
+static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data)
+{
+ struct session_401 *session = (struct session_401 *) data;
+
+ session->cb(false, session->cbpw);
+
+ /* close and destroy the window */
+ destroy_login_window(session);
+}
+
+
+/**
+ * create a new instance of the login window
+ *
+ * creates login window and handles to all the widgets we're
+ * interested in.
+ *
+ * \param url The url causing the login.
+ * \param host the host being logged into
+ * \param realm realmm the login relates to
+ * \param cb callback when complete
+ * \param cbpw data to pass to callback
+ * \return NSERROR_OK on sucessful window creation or error code on faliure.
+ */
+static nserror
+create_login_window(nsurl *url,
+ lwc_string *host,
+ const char *realm,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ struct session_401 *session;
+ GtkWindow *wnd;
+ GtkLabel *lhost, *lrealm;
+ GtkEntry *euser, *epass;
+ GtkButton *bok, *bcan;
+ GtkBuilder* builder;
+ nserror res;
+
+ session = calloc(1, sizeof(struct session_401));
+ if (session == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ res = nsgtk_builder_new_from_resname("login", &builder);
+ if (res != NSERROR_OK) {
+ free(session);
+ return res;
+ }
+
+ gtk_builder_connect_signals(builder, NULL);
+
+ wnd = GTK_WINDOW(gtk_builder_get_object(builder, "wndLogin"));
+ lhost = GTK_LABEL(gtk_builder_get_object(builder, "labelLoginHost"));
+ lrealm = GTK_LABEL(gtk_builder_get_object(builder, "labelLoginRealm"));
+ euser = GTK_ENTRY(gtk_builder_get_object(builder, "entryLoginUser"));
+ epass = GTK_ENTRY(gtk_builder_get_object(builder, "entryLoginPass"));
+ bok = GTK_BUTTON(gtk_builder_get_object(builder, "buttonLoginOK"));
+ bcan = GTK_BUTTON(gtk_builder_get_object(builder, "buttonLoginCan"));
+
+ /* create and fill in our session structure */
+ session->url = nsurl_ref(url);
+ session->host = lwc_string_ref(host);
+ session->realm = strdup(realm ? realm : "Secure Area");
+ session->cb = cb;
+ session->cbpw = cbpw;
+ session->x = builder;
+ session->wnd = wnd;
+ session->user = euser;
+ session->pass = epass;
+
+ /* fill in our new login window */
+
+ gtk_label_set_text(GTK_LABEL(lhost), lwc_string_data(host));
+ gtk_label_set_text(lrealm, realm);
+ gtk_entry_set_text(euser, "");
+ gtk_entry_set_text(epass, "");
+
+ /* attach signal handlers to the Login and Cancel buttons in our new
+ * window to call functions in this file to process the login
+ */
+ g_signal_connect(G_OBJECT(bok), "clicked",
+ G_CALLBACK(nsgtk_login_ok_clicked), (gpointer)session);
+ g_signal_connect(G_OBJECT(bcan), "clicked",
+ G_CALLBACK(nsgtk_login_cancel_clicked),
+ (gpointer)session);
+
+ /* attach signal handlers to the entry boxes such that pressing
+ * enter in one progresses the focus onto the next widget.
+ */
+
+ g_signal_connect(G_OBJECT(euser), "activate",
+ G_CALLBACK(nsgtk_login_next), (gpointer)epass);
+ g_signal_connect(G_OBJECT(epass), "activate",
+ G_CALLBACK(nsgtk_login_next), (gpointer)bok);
+
+ /* make sure the username entry box currently has the focus */
+ gtk_widget_grab_focus(GTK_WIDGET(euser));
+
+ /* finally, show the window */
+ gtk_widget_show(GTK_WIDGET(wnd));
+
+ return NSERROR_OK;
+}
+
+
+/* exported function documented in gtk/login.h */
+void gui_401login_open(nsurl *url,
+ const char *realm,
+ nserror (*cb)(bool proceed, void *pw),
+ void *cbpw)
+{
+ lwc_string *host;
+ nserror res;
+
+ host = nsurl_get_component(url, NSURL_HOST);
+ assert(host != NULL);
+
+ res = create_login_window(url, host, realm, cb, cbpw);
+ if (res != NSERROR_OK) {
+ LOG("Login init failed");
+
+ /* creating login failed so cancel navigation */
+ cb(false, cbpw);
+ }
+
+ lwc_string_unref(host);
+}
diff --git a/frontends/gtk/login.h b/frontends/gtk/login.h
new file mode 100644
index 000000000..00c29000c
--- /dev/null
+++ b/frontends/gtk/login.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Login interfaces.
+ */
+
+#ifndef __NSGTK_LOGIN_H__
+#define __NSGTK_LOGIN_H__
+
+/**
+ * login window request.
+ */
+extern void gui_401login_open(struct nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw);
+
+#endif
diff --git a/frontends/gtk/menu.c b/frontends/gtk/menu.c
new file mode 100644
index 000000000..a93ef9385
--- /dev/null
+++ b/frontends/gtk/menu.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "utils/messages.h"
+
+#include "gtk/compat.h"
+#include "gtk/menu.h"
+#include "gtk/warn.h"
+
+/**
+ * Adds image menu item to a menu.
+ *
+ * \param menu the menu to add the item to
+ * \param item_out a pointer to the item's location in the menu struct
+ * \param message the menu item I18n lookup value
+ * \param messageAccel the menu item accelerator I18n lookup value
+ * \param group the 'global' in a gtk sense accelerator group
+ * \return true if sucessful and \a item_out updated else false.
+ */
+
+static bool nsgtk_menu_add_image_item(GtkMenu *menu,
+ GtkWidget **item_out, const char *message,
+ const char *messageAccel, GtkAccelGroup *group)
+{
+ unsigned int key;
+ GdkModifierType mod;
+ GtkWidget *item;
+
+ item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message));
+ if (item == NULL) {
+ return false;
+ }
+
+ gtk_accelerator_parse(messages_get(messageAccel), &key, &mod);
+ if (key > 0) {
+ gtk_widget_add_accelerator(item, "activate", group, key, mod,
+ GTK_ACCEL_VISIBLE);
+ }
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_show(item);
+
+ *item_out = item;
+
+ return true;
+}
+
+#define NEW_MENU(n, m) \
+ n = malloc(sizeof(*n)); \
+ if (n == NULL) { \
+ return NULL; \
+ } \
+ n->m##_menu = GTK_MENU(gtk_menu_new())
+
+#define IMAGE_ITEM(p, q, r, s, t)\
+ nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\
+ #r "Accel", t)
+
+#define CHECK_ITEM(p, q, r, s)\
+ s->q##_menuitem = GTK_CHECK_MENU_ITEM(\
+ gtk_check_menu_item_new_with_mnemonic(\
+ messages_get(#r)));\
+ if ((s->q##_menuitem != NULL) && (s->p##_menu != NULL)) {\
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->p##_menu),\
+ GTK_WIDGET(s->q##_menuitem));\
+ gtk_widget_show(GTK_WIDGET(s->q##_menuitem));\
+ }
+
+#define SET_SUBMENU(q, r) \
+ do { \
+ r->q##_submenu = nsgtk_menu_##q##_submenu(group); \
+ if ((r->q##_submenu != NULL) && \
+ (r->q##_submenu->q##_menu != NULL) && \
+ (r->q##_menuitem != NULL)) { \
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(r->q##_menuitem), \
+ GTK_WIDGET(r->q##_submenu->q##_menu)); \
+ } \
+ } while(0)
+
+#define ADD_NAMED_SEP(q, r, s) \
+ do { \
+ s->r##_separator = gtk_separator_menu_item_new(); \
+ if ((s->r##_separator != NULL) && (s->q##_menu != NULL)) { \
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->q##_menu), s->r##_separator); \
+ gtk_widget_show(s->r##_separator); \
+ } \
+ } while(0)
+
+#define ADD_SEP(q, r) \
+ do { \
+ GtkWidget *w = gtk_separator_menu_item_new(); \
+ if ((w != NULL) && (r->q##_menu != NULL)) { \
+ gtk_menu_shell_append(GTK_MENU_SHELL(r->q##_menu), w); \
+ gtk_widget_show(w); \
+ } \
+ } while(0)
+
+#define ATTACH_PARENT(parent, msgname, menuv, group) \
+ do { \
+ /* create top level menu entry and attach to parent */ \
+ menuv = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(messages_get(#msgname))); \
+ gtk_menu_shell_append(parent, GTK_WIDGET(menuv)); \
+ gtk_widget_show(GTK_WIDGET(menuv)); \
+ /* attach submenu to parent */ \
+ gtk_menu_item_set_submenu(menuv, GTK_WIDGET(menuv##_menu)); \
+ gtk_menu_set_accel_group(menuv##_menu, group); \
+ } while(0)
+
+/**
+* creates an export submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_export_submenu *ret = malloc(sizeof(struct
+ nsgtk_export_submenu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->export_menu = GTK_MENU(gtk_menu_new());
+ if (ret->export_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(export, plaintext, gtkPlainText, ret, group);
+ IMAGE_ITEM(export, drawfile, gtkDrawFile, ret, group);
+ IMAGE_ITEM(export, postscript, gtkPostScript, ret, group);
+ IMAGE_ITEM(export, pdf, gtkPDF, ret, group);
+ return ret;
+}
+
+/**
+* creates a scaleview submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_scaleview_submenu *ret =
+ malloc(sizeof(struct nsgtk_scaleview_submenu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->scaleview_menu = GTK_MENU(gtk_menu_new());
+ if (ret->scaleview_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(scaleview, zoomplus, gtkZoomPlus, ret, group);
+ IMAGE_ITEM(scaleview, zoomnormal, gtkZoomNormal, ret, group);
+ IMAGE_ITEM(scaleview, zoomminus, gtkZoomMinus, ret, group);
+ return ret;
+}
+
+/**
+* creates a tab navigation submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct nsgtk_tabs_submenu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->tabs_menu = GTK_MENU(gtk_menu_new());
+ if (ret->tabs_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(tabs, nexttab, gtkNextTab, ret, group);
+ IMAGE_ITEM(tabs, prevtab, gtkPrevTab, ret, group);
+ IMAGE_ITEM(tabs, closetab, gtkCloseTab, ret, group);
+
+ return ret;
+}
+
+/**
+* creates an images submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_images_submenu *nsgtk_menu_images_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_images_submenu *ret =
+ malloc(sizeof(struct nsgtk_images_submenu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->images_menu = GTK_MENU(gtk_menu_new());
+ if (ret->images_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ CHECK_ITEM(images, foregroundimages, gtkForegroundImages, ret)
+ CHECK_ITEM(images, backgroundimages, gtkBackgroundImages, ret)
+ return ret;
+}
+
+/**
+* creates a toolbars submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_toolbars_submenu *nsgtk_menu_toolbars_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_toolbars_submenu *ret =
+ malloc(sizeof(struct nsgtk_toolbars_submenu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->toolbars_menu = GTK_MENU(gtk_menu_new());
+ if (ret->toolbars_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ CHECK_ITEM(toolbars, menubar, gtkMenuBar, ret)
+ if (ret->menubar_menuitem != NULL)
+ gtk_check_menu_item_set_active(ret->menubar_menuitem, TRUE);
+ CHECK_ITEM(toolbars, toolbar, gtkToolBar, ret)
+ if (ret->toolbar_menuitem != NULL)
+ gtk_check_menu_item_set_active(ret->toolbar_menuitem, TRUE);
+ return ret;
+}
+
+/**
+* creates a debugging submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_developer_submenu *nsgtk_menu_developer_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_developer_submenu *dmenu =
+ malloc(sizeof(struct nsgtk_developer_submenu));
+ if (dmenu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ dmenu->developer_menu = GTK_MENU(gtk_menu_new());
+ if (dmenu->developer_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(dmenu);
+ return NULL;
+ }
+
+ IMAGE_ITEM(developer, viewsource, gtkPageSource, dmenu, group);
+ IMAGE_ITEM(developer, toggledebugging, gtkToggleDebugging, dmenu, group);
+ IMAGE_ITEM(developer, debugboxtree, gtkDebugBoxTree, dmenu, group);
+ IMAGE_ITEM(developer, debugdomtree, gtkDebugDomTree, dmenu, group);
+
+ return dmenu;
+}
+
+/**
+ * creates the file menu
+ *
+ * \param group The gtk 'global' accelerator reference
+ * \return The new file menu or NULL on error
+ */
+static struct nsgtk_file_menu *nsgtk_menu_file_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_file_menu *fmenu;
+
+ fmenu = malloc(sizeof(struct nsgtk_file_menu));
+ if (fmenu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+
+ fmenu->file_menu = GTK_MENU(gtk_menu_new());
+ if (fmenu->file_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(fmenu);
+ return NULL;
+ }
+
+ IMAGE_ITEM(file, newwindow, gtkNewWindow, fmenu, group);
+ IMAGE_ITEM(file, newtab, gtkNewTab, fmenu, group);
+ IMAGE_ITEM(file, openfile, gtkOpenFile, fmenu, group);
+ IMAGE_ITEM(file, closewindow, gtkCloseWindow, fmenu, group);
+ ADD_SEP(file, fmenu);
+ IMAGE_ITEM(file, savepage, gtkSavePage, fmenu, group);
+ IMAGE_ITEM(file, export, gtkExport, fmenu, group);
+ ADD_SEP(file, fmenu);
+ IMAGE_ITEM(file, printpreview, gtkPrintPreview, fmenu, group);
+ IMAGE_ITEM(file, print, gtkPrint, fmenu, group);
+ ADD_SEP(file, fmenu);
+ IMAGE_ITEM(file, quit, gtkQuitMenu, fmenu, group);
+ SET_SUBMENU(export, fmenu);
+
+ return fmenu;
+}
+
+/**
+* creates an edit menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_edit_menu *nsgtk_menu_edit_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_edit_menu *ret = malloc(sizeof(struct nsgtk_edit_menu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->edit_menu = GTK_MENU(gtk_menu_new());
+ if (ret->edit_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(edit, cut, gtkCut, ret, group);
+ IMAGE_ITEM(edit, copy, gtkCopy, ret, group);
+ IMAGE_ITEM(edit, paste, gtkPaste, ret, group);
+ IMAGE_ITEM(edit, delete, gtkDelete, ret, group);
+ ADD_SEP(edit, ret);
+ IMAGE_ITEM(edit, selectall, gtkSelectAll, ret, group);
+ ADD_SEP(edit, ret);
+ IMAGE_ITEM(edit, find, gtkFind, ret, group);
+ ADD_SEP(edit, ret);
+ IMAGE_ITEM(edit, preferences, gtkPreferences, ret, group);
+
+ return ret;
+}
+
+/**
+* creates a view menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_view_menu *nsgtk_menu_view_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_view_menu *ret = malloc(sizeof(struct nsgtk_view_menu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->view_menu = GTK_MENU(gtk_menu_new());
+ if (ret->view_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(view, stop, gtkStop, ret, group);
+ IMAGE_ITEM(view, reload, gtkReload, ret, group);
+ ADD_SEP(view, ret);
+ IMAGE_ITEM(view, scaleview, gtkScaleView, ret, group);
+ IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group);
+ ADD_SEP(view, ret);
+ IMAGE_ITEM(view, images, gtkImages, ret, group);
+ IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group);
+ IMAGE_ITEM(view, tabs, gtkTabs, ret, group);
+ ADD_SEP(view, ret);
+ IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group);
+ SET_SUBMENU(scaleview, ret);
+ SET_SUBMENU(images, ret);
+ SET_SUBMENU(toolbars, ret);
+ SET_SUBMENU(tabs, ret);
+
+
+ return ret;
+}
+
+/**
+* creates a nav menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_nav_menu *ret = malloc(sizeof(struct nsgtk_nav_menu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->nav_menu = GTK_MENU(gtk_menu_new());
+ if (ret->nav_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+
+ IMAGE_ITEM(nav, back, gtkBack, ret, group);
+ IMAGE_ITEM(nav, forward, gtkForward, ret, group);
+ IMAGE_ITEM(nav, home, gtkHome, ret, group);
+ ADD_SEP(nav, ret);
+ IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group);
+ IMAGE_ITEM(nav, globalhistory, gtkGlobalHistory, ret, group);
+ ADD_SEP(nav, ret);
+ IMAGE_ITEM(nav, addbookmarks, gtkAddBookMarks, ret, group);
+ IMAGE_ITEM(nav, showbookmarks, gtkShowBookMarks, ret, group);
+ ADD_SEP(nav, ret);
+ IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group);
+
+
+ return ret;
+}
+
+/**
+ * creates the tools menu
+ * \param group the 'global' in a gtk sense accelerator reference
+ */
+static struct nsgtk_tools_menu *nsgtk_menu_tools_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_tools_menu *ret = malloc(sizeof(struct nsgtk_tools_menu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->tools_menu = GTK_MENU(gtk_menu_new());
+ if (ret->tools_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+
+ IMAGE_ITEM(tools, downloads, gtkDownloads, ret, group);
+ IMAGE_ITEM(tools, showcookies, gtkShowCookies, ret, group);
+ IMAGE_ITEM(tools, developer, gtkDeveloper, ret, group);
+ SET_SUBMENU(developer, ret);
+
+ return ret;
+}
+
+/**
+ * creates a help menu
+ * \param group the 'global' in a gtk sense accelerator reference
+ */
+static struct nsgtk_help_menu *nsgtk_menu_help_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_help_menu *ret = malloc(sizeof(struct nsgtk_help_menu));
+ if (ret == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->help_menu = GTK_MENU(gtk_menu_new());
+ if (ret->help_menu == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(help, contents, gtkContents, ret, group);
+ IMAGE_ITEM(help, guide, gtkGuide, ret, group);
+ IMAGE_ITEM(help, info, gtkUserInformation, ret, group);
+ ADD_SEP(help, ret);
+ IMAGE_ITEM(help, about, gtkAbout, ret, group);
+
+ return ret;
+}
+
+
+/**
+ * Generate menubar menus.
+ *
+ * Generate the main menu structure and attach it to a menubar widget.
+ */
+struct nsgtk_bar_submenu *
+nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkAccelGroup *group)
+{
+ struct nsgtk_bar_submenu *nmenu;
+
+ nmenu = calloc(1, sizeof(struct nsgtk_bar_submenu));
+ if (nmenu == NULL) {
+ return NULL;
+ }
+
+ /* create sub menus */
+ nmenu->file_submenu = nsgtk_menu_file_submenu(group);
+ nmenu->edit_submenu = nsgtk_menu_edit_submenu(group);
+ nmenu->view_submenu = nsgtk_menu_view_submenu(group);
+ nmenu->nav_submenu = nsgtk_menu_nav_submenu(group);
+ nmenu->tools_submenu = nsgtk_menu_tools_submenu(group);
+ nmenu->help_submenu = nsgtk_menu_help_submenu(group);
+
+ if (menubar != NULL) {
+ nmenu->bar_menu = GTK_MENU_BAR(menubar);
+
+ /* attach menus to menubar */
+ ATTACH_PARENT(menubar, gtkFile, nmenu->file_submenu->file, group);
+ ATTACH_PARENT(menubar, gtkEdit, nmenu->edit_submenu->edit, group);
+ ATTACH_PARENT(menubar, gtkView, nmenu->view_submenu->view, group);
+ ATTACH_PARENT(menubar, gtkNavigate, nmenu->nav_submenu->nav, group);
+ ATTACH_PARENT(menubar, gtkTools, nmenu->tools_submenu->tools, group);
+ ATTACH_PARENT(menubar, gtkHelp, nmenu->help_submenu->help, group);
+ }
+
+ return nmenu;
+}
+
+/* exported function documented in gtk/menu.h */
+struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group)
+{
+ struct nsgtk_popup_menu *nmenu;
+
+ NEW_MENU(nmenu, popup);
+
+ IMAGE_ITEM(popup, file, gtkFile, nmenu, group);
+ SET_SUBMENU(file, nmenu);
+
+ IMAGE_ITEM(popup, edit, gtkEdit, nmenu, group);
+ SET_SUBMENU(edit, nmenu);
+
+ IMAGE_ITEM(popup, view, gtkView, nmenu, group);
+ SET_SUBMENU(view, nmenu);
+
+ IMAGE_ITEM(popup, nav, gtkNavigate, nmenu, group);
+ SET_SUBMENU(nav, nmenu);
+
+ IMAGE_ITEM(popup, tools, gtkTools, nmenu, group);
+ SET_SUBMENU(tools, nmenu);
+
+ IMAGE_ITEM(popup, help, gtkHelp, nmenu, group);
+ SET_SUBMENU(help, nmenu);
+
+ ADD_NAMED_SEP(popup, first, nmenu);
+
+ IMAGE_ITEM(popup, back, gtkBack, nmenu, group);
+ IMAGE_ITEM(popup, forward, gtkForward, nmenu, group);
+
+ ADD_NAMED_SEP(popup, third, nmenu);
+
+ IMAGE_ITEM(popup, stop, gtkStop, nmenu, group);
+ IMAGE_ITEM(popup, reload, gtkReload, nmenu, group);
+ IMAGE_ITEM(popup, cut, gtkCut, nmenu, group);
+ IMAGE_ITEM(popup, copy, gtkCopy, nmenu, group);
+ IMAGE_ITEM(popup, paste, gtkPaste, nmenu, group);
+ IMAGE_ITEM(popup, customize, gtkCustomize, nmenu, group);
+
+ return nmenu;
+}
+
+
+/* exported function documented in gtk/menu.h */
+struct nsgtk_link_menu *
+nsgtk_link_menu_create(GtkAccelGroup *group)
+{
+ struct nsgtk_link_menu *nmenu;
+
+ NEW_MENU(nmenu, link);
+
+ IMAGE_ITEM(link, opentab, gtkOpentab, nmenu, group);
+ IMAGE_ITEM(link, openwin, gtkOpenwin, nmenu, group);
+
+ ADD_SEP(link, nmenu);
+
+ IMAGE_ITEM(link, save, gtkSavelink, nmenu, group);
+ IMAGE_ITEM(link, bookmark, gtkBookmarklink, nmenu, group);
+ IMAGE_ITEM(link, copy, gtkCopylink, nmenu, group);
+
+ return nmenu;
+}
diff --git a/frontends/gtk/menu.h b/frontends/gtk/menu.h
new file mode 100644
index 000000000..5da5cb1b2
--- /dev/null
+++ b/frontends/gtk/menu.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _NETSURF_GTK_MENU_H_
+#define _NETSURF_GTK_MENU_H_
+
+#include <gtk/gtk.h>
+
+struct nsgtk_file_menu {
+ GtkMenuItem *file; /* File menu item on menubar */
+ GtkMenu *file_menu;
+ GtkWidget *newwindow_menuitem;
+ GtkWidget *newtab_menuitem;
+ GtkWidget *openfile_menuitem;
+ GtkWidget *closewindow_menuitem;
+ GtkWidget *savepage_menuitem;
+ GtkWidget *export_menuitem;
+ struct nsgtk_export_submenu *export_submenu;
+ GtkWidget *printpreview_menuitem;
+ GtkWidget *print_menuitem;
+ GtkWidget *quit_menuitem;
+};
+
+struct nsgtk_edit_menu {
+ GtkMenuItem *edit; /* Edit menu item on menubar */
+ GtkMenu *edit_menu;
+ GtkWidget *cut_menuitem;
+ GtkWidget *copy_menuitem;
+ GtkWidget *paste_menuitem;
+ GtkWidget *delete_menuitem;
+ GtkWidget *selectall_menuitem;
+ GtkWidget *find_menuitem;
+ GtkWidget *preferences_menuitem;
+};
+
+struct nsgtk_view_menu {
+ GtkMenuItem *view; /* View menu item on menubar */
+ GtkMenu *view_menu; /* gtk menu attached to menu item */
+ GtkWidget *stop_menuitem;
+ GtkWidget *reload_menuitem;
+ GtkWidget *scaleview_menuitem;
+ struct nsgtk_scaleview_submenu *scaleview_submenu;
+ GtkWidget *fullscreen_menuitem;
+ GtkWidget *images_menuitem;
+ struct nsgtk_images_submenu *images_submenu;
+ GtkWidget *toolbars_menuitem;
+ struct nsgtk_toolbars_submenu *toolbars_submenu;
+ GtkWidget *tabs_menuitem;
+ struct nsgtk_tabs_submenu *tabs_submenu;
+ GtkWidget *savewindowsize_menuitem;
+};
+
+struct nsgtk_nav_menu {
+ GtkMenuItem *nav; /* Nav menu item on menubar */
+ GtkMenu *nav_menu;
+ GtkWidget *back_menuitem;
+ GtkWidget *forward_menuitem;
+ GtkWidget *home_menuitem;
+ GtkWidget *localhistory_menuitem;
+ GtkWidget *globalhistory_menuitem;
+ GtkWidget *addbookmarks_menuitem;
+ GtkWidget *showbookmarks_menuitem;
+ GtkWidget *openlocation_menuitem;
+};
+
+struct nsgtk_tools_menu {
+ GtkMenuItem *tools; /* Tools menu item on menubar */
+ GtkMenu *tools_menu;
+
+ GtkWidget *showcookies_menuitem;
+ GtkWidget *downloads_menuitem;
+ GtkWidget *developer_menuitem;
+ struct nsgtk_developer_submenu *developer_submenu;
+};
+
+struct nsgtk_help_menu {
+ GtkMenuItem *help; /* Help menu item on menubar */
+ GtkMenu *help_menu;
+ GtkWidget *contents_menuitem;
+ GtkWidget *guide_menuitem;
+ GtkWidget *info_menuitem;
+ GtkWidget *about_menuitem;
+};
+
+
+struct nsgtk_export_submenu {
+ GtkMenu *export_menu;
+ GtkWidget *plaintext_menuitem;
+ GtkWidget *drawfile_menuitem;
+ GtkWidget *postscript_menuitem;
+ GtkWidget *pdf_menuitem;
+};
+
+struct nsgtk_scaleview_submenu {
+ GtkMenu *scaleview_menu;
+ GtkWidget *zoomplus_menuitem;
+ GtkWidget *zoomminus_menuitem;
+ GtkWidget *zoomnormal_menuitem;
+};
+
+struct nsgtk_tabs_submenu {
+ GtkMenu *tabs_menu;
+ GtkWidget *nexttab_menuitem;
+ GtkWidget *prevtab_menuitem;
+ GtkWidget *closetab_menuitem;
+};
+
+struct nsgtk_images_submenu {
+ GtkMenu *images_menu;
+ GtkCheckMenuItem *foregroundimages_menuitem;
+ GtkCheckMenuItem *backgroundimages_menuitem;
+};
+
+struct nsgtk_toolbars_submenu {
+ GtkMenu *toolbars_menu;
+ GtkCheckMenuItem *menubar_menuitem;
+ GtkCheckMenuItem *toolbar_menuitem;
+};
+
+struct nsgtk_developer_submenu {
+ GtkMenu *developer_menu;
+
+ GtkWidget *viewsource_menuitem;
+ GtkWidget *toggledebugging_menuitem;
+ GtkWidget *debugboxtree_menuitem;
+ GtkWidget *debugdomtree_menuitem;
+};
+
+
+struct nsgtk_bar_submenu {
+ GtkMenuBar *bar_menu;
+ struct nsgtk_file_menu *file_submenu;
+ struct nsgtk_edit_menu *edit_submenu;
+ struct nsgtk_view_menu *view_submenu;
+ struct nsgtk_nav_menu *nav_submenu;
+ struct nsgtk_tabs_submenu *tabs_submenu;
+ struct nsgtk_tools_menu *tools_submenu;
+ struct nsgtk_help_menu *help_submenu;
+};
+
+struct nsgtk_popup_menu {
+ GtkMenu *popup_menu;
+
+ GtkWidget *file_menuitem;
+ struct nsgtk_file_menu *file_submenu;
+
+ GtkWidget *edit_menuitem;
+ struct nsgtk_edit_menu *edit_submenu;
+
+ GtkWidget *view_menuitem;
+ struct nsgtk_view_menu *view_submenu;
+
+ GtkWidget *nav_menuitem;
+ struct nsgtk_nav_menu *nav_submenu;
+
+ GtkWidget *tabs_menuitem;
+ struct nsgtk_tabs_submenu *tabs_submenu;
+
+ GtkWidget *tools_menuitem;
+ struct nsgtk_tools_menu *tools_submenu;
+
+ GtkWidget *help_menuitem;
+ struct nsgtk_help_menu *help_submenu;
+
+ GtkWidget *first_separator;
+
+ /* navigation entries */
+ GtkWidget *back_menuitem;
+ GtkWidget *forward_menuitem;
+
+ GtkWidget *third_separator;
+
+ /* view entries */
+ GtkWidget *stop_menuitem;
+ GtkWidget *reload_menuitem;
+
+ GtkWidget *cut_menuitem;
+ GtkWidget *copy_menuitem;
+ GtkWidget *paste_menuitem;
+ GtkWidget *customize_menuitem;
+
+};
+
+struct nsgtk_link_menu {
+ GtkMenu *link_menu;
+
+ GtkWidget *opentab_menuitem;
+ GtkWidget *openwin_menuitem;
+
+ GtkWidget *save_menuitem;
+ GtkWidget *bookmark_menuitem;
+ GtkWidget *copy_menuitem;
+};
+
+/**
+ * Create main menu bar.
+ */
+struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkAccelGroup *group);
+
+/**
+ * Generate right click menu menu.
+ *
+ */
+struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group);
+
+/**
+ * Generate context sensitive popup menu for link.
+ *
+ */
+struct nsgtk_link_menu *nsgtk_link_menu_create(GtkAccelGroup *group);
+
+
+#endif
diff --git a/frontends/gtk/options.h b/frontends/gtk/options.h
new file mode 100644
index 000000000..ac642c153
--- /dev/null
+++ b/frontends/gtk/options.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_GTK_OPTIONS_H_
+#define _NETSURF_GTK_OPTIONS_H_
+
+/* currently nothing here */
+
+#endif
+
+/* High quality image scaling */
+NSOPTION_BOOL(render_resample, true)
+
+/* clear downloads */
+NSOPTION_BOOL(downloads_clear, false)
+
+/* prompt before overwriting downloads */
+NSOPTION_BOOL(request_overwrite, true)
+
+/* location to download files to */
+NSOPTION_STRING(downloads_directory, NULL)
+
+/* where to store URL database */
+NSOPTION_STRING(url_file, NULL)
+
+/* Always show tabs even if there is only one */
+NSOPTION_BOOL(show_single_tab, false)
+
+/* size of buttons */
+NSOPTION_INTEGER(button_type, 0)
+
+/* disallow popup windows */
+NSOPTION_BOOL(disable_popups, false)
+
+/* disable content plugins */
+NSOPTION_BOOL(disable_plugins, false)
+
+/* number of days to keep history data */
+NSOPTION_INTEGER(history_age, 0)
+
+/* show urls in local history browser */
+NSOPTION_BOOL(hover_urls, false)
+
+/* bring new tabs to front */
+NSOPTION_BOOL(focus_new, false)
+
+/* new tabs are blank instead of homepage */
+NSOPTION_BOOL(new_blank, false)
+
+/* path to save hotlist file */
+NSOPTION_STRING(hotlist_path, NULL)
+
+/* Developer information viewer display method */
+NSOPTION_INTEGER(developer_view, 0)
+
+/* where tabs are positioned */
+NSOPTION_INTEGER(position_tab, 0)
diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c
new file mode 100644
index 000000000..1d8c19827
--- /dev/null
+++ b/frontends/gtk/plotters.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * GTK and Cairo plotter implementations.
+ *
+ * Uses Cairo drawing primitives to render browser output.
+ * \todo remove the use of the gdk structure for clipping
+ */
+
+#include <math.h>
+#include <assert.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "desktop/plotters.h"
+#include "utils/nsoption.h"
+
+#include "gtk/layout_pango.h"
+#include "gtk/plotters.h"
+#include "gtk/scaffolding.h"
+#include "gtk/bitmap.h"
+
+GtkWidget *current_widget;
+cairo_t *current_cr;
+
+static GdkRectangle cliprect;
+
+struct plotter_table plot;
+
+/** Set cairo context colour to nsgtk colour. */
+void nsgtk_set_colour(colour c)
+{
+ cairo_set_source_rgba(current_cr,
+ (c & 0xff) / 255.0,
+ ((c & 0xff00) >> 8) / 255.0,
+ ((c & 0xff0000) >> 16) / 255.0,
+ 1.0);
+}
+
+/** Set cairo context to solid plot operation. */
+static inline void nsgtk_set_solid(void)
+{
+ double dashes = 0;
+ cairo_set_dash(current_cr, &dashes, 0, 0);
+}
+
+/** Set cairo context to dotted plot operation. */
+static inline void nsgtk_set_dotted(void)
+{
+ double cdashes[] = { 1.0, 2.0 };
+ cairo_set_dash(current_cr, cdashes, 2, 0);
+}
+
+/** Set cairo context to dashed plot operation. */
+static inline void nsgtk_set_dashed(void)
+{
+ double cdashes[] = { 8.0, 2.0 };
+ cairo_set_dash(current_cr, cdashes, 2, 0);
+}
+
+/** Set clipping area for subsequent plot operations. */
+static bool nsgtk_plot_clip(const struct rect *clip)
+{
+ cairo_reset_clip(current_cr);
+ cairo_rectangle(current_cr, clip->x0, clip->y0,
+ clip->x1 - clip->x0, clip->y1 - clip->y0);
+ cairo_clip(current_cr);
+
+ cliprect.x = clip->x0;
+ cliprect.y = clip->y0;
+ cliprect.width = clip->x1 - clip->x0;
+ cliprect.height = clip->y1 - clip->y0;
+
+ return true;
+}
+
+
+static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+{
+ nsgtk_set_colour(style->fill_colour);
+ nsgtk_set_solid();
+
+ cairo_set_line_width(current_cr, 1);
+ cairo_arc(current_cr, x, y, radius,
+ (angle1 + 90) * (M_PI / 180),
+ (angle2 + 90) * (M_PI / 180));
+ cairo_stroke(current_cr);
+
+ return true;
+}
+
+static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style)
+{
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_set_colour(style->fill_colour);
+ nsgtk_set_solid();
+ cairo_set_line_width(current_cr, 0);
+ cairo_arc(current_cr, x, y, radius, 0, M_PI * 2);
+ cairo_fill(current_cr);
+ cairo_stroke(current_cr);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_set_dashed();
+ break;
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(current_cr, 1);
+ else
+ cairo_set_line_width(current_cr, style->stroke_width);
+
+ cairo_arc(current_cr, x, y, radius, 0, M_PI * 2);
+
+ cairo_stroke(current_cr);
+ }
+
+ return true;
+}
+
+static bool
+nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ nsgtk_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_set_dashed();
+ break;
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_set_colour(style->stroke_colour);
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(current_cr, 1);
+ else
+ cairo_set_line_width(current_cr, style->stroke_width);
+
+ /* core expects horizontal and vertical lines to be on pixels, not
+ * between pixels */
+ cairo_move_to(current_cr, (x0 == x1) ? x0 + 0.5 : x0,
+ (y0 == y1) ? y0 + 0.5 : y0);
+ cairo_line_to(current_cr, (x0 == x1) ? x1 + 0.5 : x1,
+ (y0 == y1) ? y1 + 0.5 : y1);
+ cairo_stroke(current_cr);
+
+ return true;
+}
+
+/** Plot a caret.
+ *
+ * @note It is assumed that the plotters have been set up.
+ */
+void nsgtk_plot_caret(int x, int y, int h)
+{
+ nsgtk_set_solid(); /* solid line */
+ nsgtk_set_colour(0); /* black */
+ cairo_set_line_width(current_cr, 1); /* thin line */
+
+ /* core expects horizontal and vertical lines to be on pixels, not
+ * between pixels */
+ cairo_move_to(current_cr, x + 0.5, y);
+ cairo_line_to(current_cr, x + 0.5, y + h - 1);
+ cairo_stroke(current_cr);
+}
+
+static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_set_colour(style->fill_colour);
+ nsgtk_set_solid();
+
+ cairo_set_line_width(current_cr, 0);
+ cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_fill(current_cr);
+ cairo_stroke(current_cr);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_set_dashed();
+ break;
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(current_cr, 1);
+ else
+ cairo_set_line_width(current_cr, style->stroke_width);
+
+ cairo_rectangle(current_cr, x0 + 0.5, y0 + 0.5, x1 - x0, y1 - y0);
+ cairo_stroke(current_cr);
+ }
+ return true;
+}
+
+static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+{
+ unsigned int i;
+
+ nsgtk_set_colour(style->fill_colour);
+ nsgtk_set_solid();
+
+ cairo_set_line_width(current_cr, 0);
+ cairo_move_to(current_cr, p[0], p[1]);
+ for (i = 1; i != n; i++) {
+ cairo_line_to(current_cr, p[i * 2], p[i * 2 + 1]);
+ }
+ cairo_fill(current_cr);
+ cairo_stroke(current_cr);
+
+ return true;
+}
+
+
+
+
+static bool nsgtk_plot_text(int x, int y, const char *text, size_t length,
+ const struct plot_font_style *fstyle)
+{
+ return nsfont_paint(x, y, text, length, fstyle);
+}
+
+
+
+static bool nsgtk_plot_pixbuf(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg)
+{
+ int x0, y0, x1, y1;
+ int dsrcx, dsrcy, dwidth, dheight;
+ int bmwidth, bmheight;
+
+ cairo_surface_t *bmsurface = bitmap->surface;
+
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
+ if ((x > (cliprect.x + cliprect.width)) ||
+ ((x + width) < cliprect.x) ||
+ (y > (cliprect.y + cliprect.height)) ||
+ ((y + height) < cliprect.y)) {
+ /* Image completely outside clip region */
+ return true;
+ }
+
+ /* Get clip rectangle / image rectangle edge differences */
+ x0 = cliprect.x - x;
+ y0 = cliprect.y - y;
+ x1 = (x + width) - (cliprect.x + cliprect.width);
+ y1 = (y + height) - (cliprect.y + cliprect.height);
+
+ /* Set initial draw geometry */
+ dsrcx = x;
+ dsrcy = y;
+ dwidth = width;
+ dheight = height;
+
+ /* Manually clip draw coordinates to area of image to be rendered */
+ if (x0 > 0) {
+ /* Clip left */
+ dsrcx += x0;
+ dwidth -= x0;
+ }
+ if (y0 > 0) {
+ /* Clip top */
+ dsrcy += y0;
+ dheight -= y0;
+ }
+ if (x1 > 0) {
+ /* Clip right */
+ dwidth -= x1;
+ }
+ if (y1 > 0) {
+ /* Clip bottom */
+ dheight -= y1;
+ }
+
+ if (dwidth == 0 || dheight == 0)
+ /* Nothing to plot */
+ return true;
+
+ bmwidth = cairo_image_surface_get_width(bmsurface);
+ bmheight = cairo_image_surface_get_height(bmsurface);
+
+ /* Render the bitmap */
+ if ((bmwidth == width) && (bmheight == height)) {
+ /* Bitmap is not scaled */
+ /* Plot the bitmap */
+ cairo_set_source_surface(current_cr, bmsurface, x, y);
+ cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(current_cr);
+
+ } else {
+ /* Bitmap is scaled */
+ if ((bitmap->scsurface != NULL) &&
+ ((cairo_image_surface_get_width(bitmap->scsurface) != width) ||
+ (cairo_image_surface_get_height(bitmap->scsurface) != height))){
+ cairo_surface_destroy(bitmap->scsurface);
+ bitmap->scsurface = NULL;
+ }
+
+ if (bitmap->scsurface == NULL) {
+ bitmap->scsurface = cairo_surface_create_similar(bmsurface,CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ cairo_t *cr = cairo_create(bitmap->scsurface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale(cr, (double)width / bmwidth, (double)height / bmheight);
+ cairo_set_source_surface(cr, bmsurface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer (2)
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr),
+ CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of
+ * overlaying
+ */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ }
+ /* Plot the scaled bitmap */
+ cairo_set_source_surface(current_cr, bitmap->scsurface, x, y);
+ cairo_rectangle(current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(current_cr);
+
+
+ }
+
+ return true;
+}
+
+static bool nsgtk_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags)
+{
+ int doneheight = 0, donewidth = 0;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
+
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just pass it on */
+ return nsgtk_plot_pixbuf(x, y, width, height, bitmap, bg);
+ }
+
+ if (y > cliprect.y) {
+ doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
+ } else {
+ doneheight = y;
+ }
+
+ while (doneheight < (cliprect.y + cliprect.height)) {
+ if (x > cliprect.x) {
+ donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
+ } else {
+ donewidth = x;
+ }
+
+ while (donewidth < (cliprect.x + cliprect.width)) {
+ nsgtk_plot_pixbuf(donewidth, doneheight,
+ width, height, bitmap, bg);
+ donewidth += width;
+ if (!repeat_x)
+ break;
+ }
+ doneheight += height;
+
+ if (!repeat_y)
+ break;
+ }
+
+ return true;
+}
+
+static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float width,
+ colour c, const float transform[6])
+{
+ unsigned int i;
+ cairo_matrix_t old_ctm, n_ctm;
+
+ if (n == 0)
+ return true;
+
+ if (p[0] != PLOTTER_PATH_MOVE) {
+ LOG("Path does not start with move");
+ return false;
+ }
+
+
+ /* Save CTM */
+ cairo_get_matrix(current_cr, &old_ctm);
+
+ /* Set up line style and width */
+ cairo_set_line_width(current_cr, 1);
+ nsgtk_set_solid();
+
+ /* Load new CTM */
+ n_ctm.xx = transform[0];
+ n_ctm.yx = transform[1];
+ n_ctm.xy = transform[2];
+ n_ctm.yy = transform[3];
+ n_ctm.x0 = transform[4];
+ n_ctm.y0 = transform[5];
+
+ cairo_set_matrix(current_cr, &n_ctm);
+
+ /* Construct path */
+ for (i = 0; i < n; ) {
+ if (p[i] == PLOTTER_PATH_MOVE) {
+ cairo_move_to(current_cr, p[i+1], p[i+2]);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_CLOSE) {
+ cairo_close_path(current_cr);
+ i++;
+ } else if (p[i] == PLOTTER_PATH_LINE) {
+ cairo_line_to(current_cr, p[i+1], p[i+2]);
+ i += 3;
+ } else if (p[i] == PLOTTER_PATH_BEZIER) {
+ cairo_curve_to(current_cr, p[i+1], p[i+2],
+ p[i+3], p[i+4],
+ p[i+5], p[i+6]);
+ i += 7;
+ } else {
+ LOG("bad path command %f", p[i]);
+ /* Reset matrix for safety */
+ cairo_set_matrix(current_cr, &old_ctm);
+ return false;
+ }
+ }
+
+ /* Restore original CTM */
+ cairo_set_matrix(current_cr, &old_ctm);
+
+ /* Now draw path */
+ if (fill != NS_TRANSPARENT) {
+ nsgtk_set_colour(fill);
+
+ if (c != NS_TRANSPARENT) {
+ /* Fill & Stroke */
+ cairo_fill_preserve(current_cr);
+ nsgtk_set_colour(c);
+ cairo_stroke(current_cr);
+ } else {
+ /* Fill only */
+ cairo_fill(current_cr);
+ }
+ } else if (c != NS_TRANSPARENT) {
+ /* Stroke only */
+ nsgtk_set_colour(c);
+ cairo_stroke(current_cr);
+ }
+
+ return true;
+}
+
+/** GTK plotter table */
+const struct plotter_table nsgtk_plotters = {
+ .clip = nsgtk_plot_clip,
+ .arc = nsgtk_plot_arc,
+ .disc = nsgtk_plot_disc,
+ .line = nsgtk_plot_line,
+ .rectangle = nsgtk_plot_rectangle,
+ .polygon = nsgtk_plot_polygon,
+ .path = nsgtk_plot_path,
+ .bitmap = nsgtk_plot_bitmap,
+ .text = nsgtk_plot_text,
+ .option_knockout = true
+};
+
+
+
diff --git a/frontends/gtk/plotters.h b/frontends/gtk/plotters.h
new file mode 100644
index 000000000..c88a8da0c
--- /dev/null
+++ b/frontends/gtk/plotters.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Target independent plotting (GDK / GTK+ interface).
+ */
+
+#ifndef NETSURF_GTK_PLOTTERS_H
+#define NETSURF_GTK_PLOTTERS_H 1
+
+#include <gtk/gtk.h>
+
+struct plotter_table;
+
+extern const struct plotter_table nsgtk_plotters;
+
+/* make sure this is NULL if no redraw is in progress */
+extern GtkWidget *current_widget;
+extern cairo_t *current_cr;
+
+void nsgtk_set_colour(colour c);
+void nsgtk_plot_caret(int x, int y, int h);
+
+#endif /* NETSURF_GTK_PLOTTERS_H */
+
diff --git a/frontends/gtk/preferences.c b/frontends/gtk/preferences.c
new file mode 100644
index 000000000..3efb9eddd
--- /dev/null
+++ b/frontends/gtk/preferences.c
@@ -0,0 +1,1030 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+#include <string.h>
+
+#include "utils/messages.h"
+#include "utils/nsoption.h"
+#include "utils/file.h"
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "desktop/browser.h"
+#include "desktop/searchweb.h"
+
+#include "gtk/compat.h"
+#include "gtk/window.h"
+#include "gtk/gui.h"
+#include "gtk/scaffolding.h"
+#include "gtk/resources.h"
+#include "gtk/preferences.h"
+
+/* private prefs */
+struct ppref {
+ /** dialog handle created when window first accessed */
+ GObject *dialog;
+
+ struct browser_window *bw;
+
+ /* widgets which are accessed from outside their own signal handlers */
+ GtkEntry *entryHomePageURL;
+ GtkEntry *entryProxyHost;
+ GtkEntry *entryProxyUser;
+ GtkEntry *entryProxyPassword;
+ GtkEntry *entryProxyNoproxy;
+ GtkSpinButton *spinProxyPort;
+
+ /* dynamic list stores */
+ GtkListStore *content_language;
+ GtkListStore *search_providers;
+};
+
+static struct ppref ppref;
+
+
+/* Set netsurf option based on toggle button state
+ *
+ * This works for any widget which subclasses togglebutton (checkbox,
+ * radiobutton etc.)
+ */
+#define TOGGLEBUTTON_SIGNALS(WIDGET, OPTION) \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_toggled(GtkToggleButton *togglebutton, \
+ struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_toggled(GtkToggleButton *togglebutton, \
+ struct ppref *priv) \
+{ \
+ nsoption_set_bool(OPTION, \
+ gtk_toggle_button_get_active(togglebutton)); \
+} \
+ \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, \
+ struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, \
+ struct ppref *priv) \
+{ \
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), \
+ nsoption_bool(OPTION)); \
+}
+
+#define SPINBUTTON_SIGNALS(WIDGET, OPTION, MULTIPLIER) \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
+ struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
+ struct ppref *priv) \
+{ \
+ nsoption_set_int(OPTION, \
+ round(gtk_spin_button_get_value(spinbutton) * MULTIPLIER)); \
+} \
+ \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
+{ \
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), \
+ ((gdouble)nsoption_int(OPTION)) / MULTIPLIER); \
+}
+
+#define SPINBUTTON_UINT_SIGNALS(WIDGET, OPTION, MULTIPLIER) \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
+ struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
+ struct ppref *priv) \
+{ \
+ nsoption_set_uint(OPTION, \
+ round(gtk_spin_button_get_value(spinbutton) * MULTIPLIER)); \
+} \
+ \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
+{ \
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), \
+ ((gdouble)nsoption_uint(OPTION)) / MULTIPLIER); \
+}
+
+#define ENTRY_SIGNALS(WIDGET, OPTION) \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_changed(GtkEditable *editable, struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_changed(GtkEditable *editable, struct ppref *priv)\
+{ \
+ nsoption_set_charp(OPTION, \
+ strdup(gtk_entry_get_text(GTK_ENTRY(editable)))); \
+} \
+ \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
+G_MODULE_EXPORT void \
+nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
+{ \
+ const char *OPTION; \
+ OPTION = nsoption_charp(OPTION); \
+ if (OPTION != NULL) { \
+ gtk_entry_set_text(GTK_ENTRY(widget), OPTION); \
+ } \
+}
+
+/* GTK module requires these to be exported symbols so these all need
+ * forward declaring to avoid warnings
+ */
+G_MODULE_EXPORT void nsgtk_preferences_comboProxyType_changed(GtkComboBox *combo, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboProxyType_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboboxLoadImages_changed(GtkComboBox *combo, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboboxLoadImages_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboDefault_changed(GtkComboBox *combo, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboDefault_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_fontPreview_clicked(GtkButton *button, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboboxLanguage_changed(GtkComboBox *combo, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_checkShowSingleTab_toggled(GtkToggleButton *togglebutton, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_checkShowSingleTab_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboTabPosition_changed(GtkComboBox *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboTabPosition_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboDeveloperView_changed(GtkComboBox *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboDeveloperView_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboButtonType_changed(GtkComboBox *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboButtonType_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_setDefaultPage_clicked(GtkButton *button, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_comboSearch_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_fileChooserDownloads_selectionchanged(GtkFileChooser *chooser, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid);
+G_MODULE_EXPORT gboolean nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg, struct ppref *priv);
+G_MODULE_EXPORT void nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv);
+
+
+/********* PDF **********/
+
+/* Appearance */
+
+/* no images in output */
+TOGGLEBUTTON_SIGNALS(checkSuppressImages, suppress_images)
+
+/* no background images */
+TOGGLEBUTTON_SIGNALS(checkRemoveBackgrounds, remove_backgrounds)
+
+/* scale to fit page */
+TOGGLEBUTTON_SIGNALS(checkFitPage, enable_loosening)
+
+/* port */
+SPINBUTTON_SIGNALS(spinExportScale, export_scale, 1.0)
+
+/* Margins */
+SPINBUTTON_SIGNALS(spinMarginTop, margin_top, 1.0)
+SPINBUTTON_SIGNALS(spinMarginBottom, margin_bottom, 1.0)
+SPINBUTTON_SIGNALS(spinMarginLeft, margin_left, 1.0)
+SPINBUTTON_SIGNALS(spinMarginRight, margin_right, 1.0)
+
+
+/* Generation */
+
+/* output is compressed */
+TOGGLEBUTTON_SIGNALS(checkCompressPDF, enable_PDF_compression)
+
+/* output has a password */
+TOGGLEBUTTON_SIGNALS(checkPasswordPDF, enable_PDF_password)
+
+/********* Network **********/
+
+/* HTTP proxy */
+static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
+{
+ gboolean host;
+ gboolean port;
+ gboolean user;
+ gboolean pass;
+ gboolean noproxy;
+
+ switch (proxyval) {
+ case 0: /* no proxy */
+ host = FALSE;
+ port = FALSE;
+ user = FALSE;
+ pass = FALSE;
+ noproxy = FALSE;
+ break;
+
+ case 1: /* proxy with no auth */
+ host = TRUE;
+ port = TRUE;
+ user = FALSE;
+ pass = FALSE;
+ noproxy = TRUE;
+ break;
+
+ case 2: /* proxy with basic auth */
+ host = TRUE;
+ port = TRUE;
+ user = TRUE;
+ pass = TRUE;
+ noproxy = TRUE;
+ break;
+
+ case 3: /* proxy with ntlm auth */
+ host = TRUE;
+ port = TRUE;
+ user = TRUE;
+ pass = TRUE;
+ noproxy = TRUE;
+ break;
+
+ case 4: /* system proxy */
+ host = FALSE;
+ port = FALSE;
+ user = FALSE;
+ pass = FALSE;
+ noproxy = FALSE;
+ break;
+
+ default:
+ return;
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyHost), host);
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->spinProxyPort), port);
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyUser), user);
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyPassword), pass);
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyNoproxy), noproxy);
+
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboProxyType_changed(GtkComboBox *combo, struct ppref *priv)
+{
+ int proxy_sel;
+ proxy_sel = gtk_combo_box_get_active(combo);
+
+ switch (proxy_sel) {
+ case 0: /* no proxy */
+ nsoption_set_bool(http_proxy, false);
+ break;
+
+ case 1: /* proxy with no auth */
+ nsoption_set_bool(http_proxy, true);
+ nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NONE);
+ break;
+
+ case 2: /* proxy with basic auth */
+ nsoption_set_bool(http_proxy, true);
+ nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_BASIC);
+ break;
+
+ case 3: /* proxy with ntlm auth */
+ nsoption_set_bool(http_proxy, true);
+ nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NTLM);
+ break;
+
+ case 4: /* system proxy */
+ nsoption_set_bool(http_proxy, true);
+ nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NONE);
+ break;
+ }
+
+ set_proxy_widgets_sensitivity(proxy_sel, priv);
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboProxyType_realize(GtkWidget *widget, struct ppref *priv)
+{
+ int proxytype = 0; /* no proxy by default */
+
+ if (nsoption_bool(http_proxy) == true) {
+ /* proxy type combo box starts with disabled, to allow
+ * for this the http_proxy option needs combining with
+ * the http_proxy_auth option
+ */
+ proxytype = nsoption_int(http_proxy_auth) + 1;
+ if (nsoption_charp(http_proxy_host) == NULL) {
+ /* set to use a proxy without a host, turn proxy off */
+ proxytype = 0;
+ } else if (((proxytype == 2) ||
+ (proxytype == 3)) &&
+ ((nsoption_charp(http_proxy_auth_user) == NULL) ||
+ (nsoption_charp(http_proxy_auth_pass) == NULL))) {
+ /* authentication selected with empty credentials, turn proxy off */
+ proxytype = 0;
+ }
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), proxytype);
+
+ set_proxy_widgets_sensitivity(proxytype, priv);
+}
+
+/* host */
+ENTRY_SIGNALS(entryProxyHost, http_proxy_host)
+
+/* port */
+SPINBUTTON_SIGNALS(spinProxyPort, http_proxy_port, 1.0)
+
+/* user */
+ENTRY_SIGNALS(entryProxyUser, http_proxy_auth_user)
+
+/* password */
+ENTRY_SIGNALS(entryProxyPassword, http_proxy_auth_pass)
+
+/* no proxy */
+ENTRY_SIGNALS(entryProxyNoproxy, http_proxy_noproxy)
+
+/* Fetching */
+
+/* maximum fetchers */
+SPINBUTTON_SIGNALS(spinMaxFetchers, max_fetchers, 1.0)
+
+/* fetches per host */
+SPINBUTTON_SIGNALS(spinFetchesPerHost, max_fetchers_per_host, 1.0)
+
+/* cached connections */
+SPINBUTTON_SIGNALS(spinCachedConnections, max_cached_fetch_handles, 1.0)
+
+
+/********* Privacy **********/
+
+/* General */
+
+/* enable referral submission */
+TOGGLEBUTTON_SIGNALS(checkSendReferer, send_referer)
+
+/* send do not track */
+TOGGLEBUTTON_SIGNALS(checkSendDNT, do_not_track)
+
+/* History */
+
+/* local history shows url tooltips */
+TOGGLEBUTTON_SIGNALS(checkHoverURLs, hover_urls)
+
+/* remember browsing history */
+SPINBUTTON_SIGNALS(spinHistoryAge, history_age, 1.0)
+
+/* Cache */
+
+/* memory cache size */
+SPINBUTTON_SIGNALS(spinMemoryCacheSize, memory_cache_size, (1024*1024))
+
+/* disc cache size */
+SPINBUTTON_UINT_SIGNALS(spinDiscCacheSize, disc_cache_size, (1024*1024))
+
+
+/* disc cache age */
+SPINBUTTON_SIGNALS(spinDiscCacheAge, disc_cache_age, 1.0)
+
+
+/********* Content **********/
+
+/* Control */
+
+
+/* prevent popups */
+TOGGLEBUTTON_SIGNALS(checkDisablePopups, disable_popups)
+
+/* hide adverts */
+TOGGLEBUTTON_SIGNALS(checkHideAdverts, block_advertisements)
+
+/* enable javascript */
+TOGGLEBUTTON_SIGNALS(checkEnableJavascript, enable_javascript)
+
+/* disable plugins */
+TOGGLEBUTTON_SIGNALS(checkDisablePlugins, disable_plugins)
+
+/* high quality image scaling */
+TOGGLEBUTTON_SIGNALS(checkResampleImages, render_resample)
+
+/* load and display of images */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboboxLoadImages_changed(GtkComboBox *combo,
+ struct ppref *priv)
+{
+ int img_sel;
+ /* get the row number for the selection */
+ img_sel = gtk_combo_box_get_active(combo);
+ switch (img_sel) {
+ case 0:
+ /* background and foreground */
+ nsoption_set_bool(foreground_images, true);
+ nsoption_set_bool(background_images, true);
+ break;
+
+ case 1:
+ /* foreground only */
+ nsoption_set_bool(foreground_images, true);
+ nsoption_set_bool(background_images, false);
+ break;
+
+ case 2:
+ /* background only */
+ nsoption_set_bool(foreground_images, false);
+ nsoption_set_bool(background_images, true);
+ break;
+
+ case 3:
+ /* no images */
+ nsoption_set_bool(foreground_images, false);
+ nsoption_set_bool(background_images, false);
+ break;
+ }
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboboxLoadImages_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ if (nsoption_bool(foreground_images)) {
+ if (nsoption_bool(background_images)) {
+ /* background and foreground */
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0);
+ } else {
+ /* foreground only */
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 1);
+ }
+ } else {
+ if (nsoption_bool(background_images)) {
+ /* background only */
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 2);
+ } else {
+ /* no images */
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 3);
+ }
+ }
+}
+
+/* Animation */
+
+/* enable animation */
+TOGGLEBUTTON_SIGNALS(checkEnableAnimations, animate_images)
+
+/* frame time */
+SPINBUTTON_SIGNALS(spinAnimationSpeed, minimum_gif_delay, 100.0)
+
+/* Fonts */
+
+/* default font */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboDefault_changed(GtkComboBox *combo, struct ppref *priv)
+{
+ int font_sel;
+ /* get the row number for the selection */
+ font_sel = gtk_combo_box_get_active(combo);
+ if ((font_sel >= 0) && (font_sel <= 4)) {
+ nsoption_set_int(font_default, font_sel);
+ }
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboDefault_realize(GtkWidget *widget, struct ppref *priv)
+{
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
+ nsoption_int(font_default));
+}
+
+/* default font size */
+SPINBUTTON_SIGNALS(spinDefaultSize, font_size, 10.0)
+
+/* preview - actually reflow all views */
+G_MODULE_EXPORT void
+nsgtk_preferences_fontPreview_clicked(GtkButton *button, struct ppref *priv)
+{
+ nsgtk_reflow_all_windows();
+}
+
+
+/* Language */
+
+/* accept language */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboboxLanguage_changed(GtkComboBox *combo,
+ struct ppref *priv)
+{
+ gchar *lang = NULL;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ /* Obtain currently selected item from combo box.
+ * If nothing is selected, do nothing.
+ */
+ if (gtk_combo_box_get_active_iter(combo, &iter)) {
+ /* Obtain data model from combo box. */
+ model = gtk_combo_box_get_model(combo);
+
+ /* Obtain string from model. */
+ gtk_tree_model_get(model, &iter, 0, &lang, -1);
+ }
+
+ if (lang != NULL) {
+ nsoption_set_charp(accept_language, strdup(lang));
+ g_free(lang);
+ }
+}
+
+/**
+ * populate language combo from data
+ */
+static nserror
+comboboxLanguage_add_from_data(GtkListStore *liststore,
+ GtkComboBox *combobox,
+ const char *accept_language,
+ const uint8_t *data,
+ size_t data_size)
+{
+ int active_language = -1;
+ GtkTreeIter iter;
+ int combo_row_count = 0;
+ const uint8_t *s;
+ const uint8_t *nl;
+ char buf[50];
+ int bufi = 0;
+
+ gtk_list_store_clear(liststore);
+ s = data;
+
+ while (s < (data + data_size)) {
+ /* find nl and copy buffer */
+ for (nl = s; nl < data + data_size; nl++) {
+ if ((*nl == '\n') || (bufi == (sizeof(buf) - 2))) {
+ buf[bufi] = 0; /* null terminate */
+ break;
+ }
+ buf[bufi++] = *nl;
+ }
+ if (bufi > 0) {
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, buf, -1 );
+
+ if (strcmp(buf, accept_language) == 0) {
+ active_language = combo_row_count;
+ }
+
+ combo_row_count++;
+ }
+ bufi = 0;
+ s = nl + 1; /* skip newline */
+ }
+
+ /* if configured language was not in list, add it */
+ if (active_language == -1) {
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, accept_language, -1);
+ active_language = combo_row_count;
+ }
+
+ gtk_combo_box_set_active(combobox, active_language);
+
+ return NSERROR_OK;
+}
+
+/**
+ * populate language combo from file
+ */
+static nserror
+comboboxLanguage_add_from_file(GtkListStore *liststore,
+ GtkComboBox *combobox,
+ const char *accept_language,
+ const char *file_location)
+{
+ int active_language = -1;
+ GtkTreeIter iter;
+ int combo_row_count = 0;
+ FILE *fp;
+ char buf[50];
+
+ fp = fopen(file_location, "r");
+ if (fp == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ gtk_list_store_clear(liststore);
+
+ LOG("Used %s for languages", file_location);
+ while (fgets(buf, sizeof(buf), fp)) {
+ /* Ignore blank lines */
+ if (buf[0] == '\0')
+ continue;
+
+ /* Remove trailing \n */
+ buf[strlen(buf) - 1] = '\0';
+
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, buf, -1 );
+
+ if (strcmp(buf, accept_language) == 0) {
+ active_language = combo_row_count;
+ }
+
+ combo_row_count++;
+ }
+
+ /* if configured language was not in list, add it */
+ if (active_language == -1) {
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter, 0, accept_language, -1);
+ active_language = combo_row_count;
+ }
+
+ fclose(fp);
+
+ gtk_combo_box_set_active(combobox, active_language);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Fill content language list store.
+ */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ nserror res;
+ const uint8_t *data;
+ size_t data_size;
+ const char *languages_file;
+ const char *accept_language;
+
+ if (priv->content_language == NULL) {
+ LOG("content language list store unavailable");
+ return;
+ }
+
+ /* get current accept language */
+ accept_language = nsoption_charp(accept_language);
+ if (accept_language == NULL) {
+ accept_language = "en";
+ }
+
+ /* attempt to read languages from inline resource */
+ res = nsgtk_data_from_resname("languages", &data, &data_size);
+ if (res == NSERROR_OK) {
+ res = comboboxLanguage_add_from_data(priv->content_language,
+ GTK_COMBO_BOX(widget),
+ accept_language,
+ data,
+ data_size);
+ } else {
+ /* attempt to read languages from file */
+ res = nsgtk_path_from_resname("languages", &languages_file);
+ if (res == NSERROR_OK) {
+ res = comboboxLanguage_add_from_file(priv->content_language,
+ GTK_COMBO_BOX(widget),
+ accept_language,
+ languages_file);
+ }
+ }
+ if (res != NSERROR_OK) {
+ LOG("error populatiung languages combo");
+ }
+}
+
+
+/********* Apperance **********/
+
+/* Tabs */
+
+/* always show tab bar */
+G_MODULE_EXPORT void
+nsgtk_preferences_checkShowSingleTab_toggled(GtkToggleButton *togglebutton,
+ struct ppref *priv)
+{
+ nsoption_set_bool(show_single_tab,
+ gtk_toggle_button_get_active(togglebutton));
+ nsgtk_reflow_all_windows();
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_checkShowSingleTab_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
+ nsoption_bool(show_single_tab));
+}
+
+/* switch to newly opened tabs immediately */
+TOGGLEBUTTON_SIGNALS(checkFocusNew, focus_new)
+
+/* newly opened tabs are blank */
+TOGGLEBUTTON_SIGNALS(checkNewBlank, new_blank)
+
+/* tab position */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboTabPosition_changed(GtkComboBox *widget,
+ struct ppref *priv)
+{
+ struct nsgtk_scaffolding *current;
+
+ /* set the option */
+ nsoption_set_int(position_tab, gtk_combo_box_get_active(widget));
+
+ /* update all notebooks in all scaffolds */
+ current = nsgtk_scaffolding_iterate(NULL);
+ while (current) {
+ nsgtk_scaffolding_reset_offset(current);
+
+ nsgtk_reflow_all_windows();
+
+ current = nsgtk_scaffolding_iterate(current);
+ }
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboTabPosition_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
+ nsoption_int(position_tab));
+}
+
+/* Tools */
+
+/* developer view opening */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboDeveloperView_changed(GtkComboBox *widget,
+ struct ppref *priv)
+{
+ /* set the option */
+ nsoption_set_int(developer_view, gtk_combo_box_get_active(widget));
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboDeveloperView_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
+ nsoption_int(developer_view));
+}
+
+
+/* URLbar */
+
+/* show recently visited urls as you type */
+TOGGLEBUTTON_SIGNALS(checkDisplayRecentURLs, url_suggestion)
+
+/* Toolbar */
+
+/* button position */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboButtonType_changed(GtkComboBox *widget,
+ struct ppref *priv)
+{
+ struct nsgtk_scaffolding *current;
+
+ nsoption_set_int(button_type, gtk_combo_box_get_active(widget) + 1);
+
+ current = nsgtk_scaffolding_iterate(NULL);
+ while (current != NULL) {
+ nsgtk_scaffolding_reset_offset(current);
+
+ nsgtk_scaffolding_toolbars(current, nsoption_int(button_type));
+
+ current = nsgtk_scaffolding_iterate(current);
+ }
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboButtonType_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
+ nsoption_int(button_type) - 1);
+}
+
+
+
+/************ Main ************/
+
+/* Startup */
+
+/* entry HomePageURL widget */
+ENTRY_SIGNALS(entryHomePageURL, homepage_url)
+
+/* put current page into homepage url */
+G_MODULE_EXPORT void
+nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv)
+{
+ const gchar *url = nsurl_access(browser_window_get_url(priv->bw));
+
+ if (priv->entryHomePageURL != NULL) {
+ gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url);
+ nsoption_set_charp(homepage_url, strdup(url));
+ }
+}
+
+/* put default page into homepage */
+G_MODULE_EXPORT void
+nsgtk_preferences_setDefaultPage_clicked(GtkButton *button, struct ppref *priv)
+{
+ const gchar *url = NETSURF_HOMEPAGE;
+
+ if (priv->entryHomePageURL != NULL) {
+ gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url);
+ nsoption_set_charp(homepage_url, strdup(url));
+ }
+}
+
+/* Search */
+
+/* Url Search widget */
+TOGGLEBUTTON_SIGNALS(checkUrlSearch, search_url_bar)
+
+/* provider combo */
+G_MODULE_EXPORT void
+nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv)
+{
+ int provider;
+
+ provider = gtk_combo_box_get_active(widget);
+
+ /* set the option */
+ nsoption_set_int(search_provider, provider);
+
+ /* set search provider */
+ search_web_select_provider(provider);
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_comboSearch_realize(GtkWidget *widget, struct ppref *priv)
+{
+ int iter;
+ const char *name;
+ int provider = nsoption_int(search_provider);
+
+ if (priv->search_providers != NULL) {
+ gtk_list_store_clear(priv->search_providers);
+ for (iter = search_web_iterate_providers(0, &name);
+ iter != -1;
+ iter = search_web_iterate_providers(iter, &name)) {
+ gtk_list_store_insert_with_values(priv->search_providers,
+ NULL, -1,
+ 0, name, -1);
+ }
+ }
+
+ gtk_combo_box_set_active(GTK_COMBO_BOX(widget), provider);
+}
+
+
+/* Downloads */
+
+/* clear downloads */
+TOGGLEBUTTON_SIGNALS(checkClearDownloads, downloads_clear)
+
+/* request overwite */
+TOGGLEBUTTON_SIGNALS(checkRequestOverwrite, request_overwrite)
+
+/* download location
+ *
+ * note selection-changed is used instead of file-set as the returned
+ * filename when that signal are used is incorrect. Though this signal
+ * does update frequently often with the same data.
+ */
+G_MODULE_EXPORT void
+nsgtk_preferences_fileChooserDownloads_selectionchanged(GtkFileChooser *chooser,
+ struct ppref *priv)
+{
+ gchar *dir;
+ dir = gtk_file_chooser_get_filename(chooser);
+ nsoption_set_charp(downloads_directory, strdup(dir));
+ g_free(dir);
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
+ struct ppref *priv)
+{
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget),
+ nsoption_charp(downloads_directory));
+}
+
+
+/************* Dialog window ***********/
+
+/* dialog close and destroy events */
+G_MODULE_EXPORT void
+nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
+{
+ char *choices = NULL;
+
+ if (resid == GTK_RESPONSE_CLOSE) {
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+ gtk_widget_hide(GTK_WIDGET(dlg));
+ }
+}
+
+G_MODULE_EXPORT gboolean
+nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
+ struct ppref *priv)
+{
+ char *choices = NULL;
+
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
+ gtk_widget_hide(GTK_WIDGET(dlg));
+
+ /* Delt with it by hiding window, no need to destory widget by
+ * default.
+ */
+ return TRUE;
+}
+
+G_MODULE_EXPORT void
+nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
+{
+ char *choices = NULL;
+
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+}
+
+
+/* exported interface documented in gtk/preferences.h */
+GtkWidget* nsgtk_preferences(struct browser_window *bw, GtkWindow *parent)
+{
+ GtkBuilder *preferences_builder;
+ struct ppref *priv = &ppref;
+ nserror res;
+
+ priv->bw = bw; /* for setting "current" page */
+
+ /* memoised dialog creation */
+ if (priv->dialog != NULL) {
+ gtk_window_set_transient_for(GTK_WINDOW(priv->dialog), parent);
+ return GTK_WIDGET(priv->dialog);
+ }
+
+ res = nsgtk_builder_new_from_resname("options", &preferences_builder);
+ if (res != NSERROR_OK) {
+ LOG("Preferences UI builder init failed");
+ return NULL;
+ }
+
+ priv->dialog = gtk_builder_get_object(preferences_builder,
+ "dialogPreferences");
+ if (priv->dialog == NULL) {
+ LOG("Unable to get object for preferences dialog");
+ /* release builder as were done with it */
+ g_object_unref(G_OBJECT(preferences_builder));
+ return NULL;
+ }
+
+ /* need to explicitly obtain handles for some widgets enabling
+ * updates by other widget events
+ */
+#define GB(TYPE, NAME) GTK_##TYPE(gtk_builder_get_object(preferences_builder, #NAME))
+ priv->entryHomePageURL = GB(ENTRY, entryHomePageURL);
+ priv->content_language = GB(LIST_STORE, liststore_content_language);
+ priv->search_providers = GB(LIST_STORE, liststore_search_provider);
+ priv->entryProxyHost = GB(ENTRY, entryProxyHost);
+ priv->spinProxyPort = GB(SPIN_BUTTON, spinProxyPort);
+ priv->entryProxyUser = GB(ENTRY, entryProxyUser);
+ priv->entryProxyPassword = GB(ENTRY, entryProxyPassword);
+ priv->entryProxyNoproxy = GB(ENTRY, entryProxyNoproxy);
+#undef GB
+
+ /* connect all signals ready to use */
+ gtk_builder_connect_signals(preferences_builder, priv);
+
+ /* release builder as were done with it */
+ g_object_unref(G_OBJECT(preferences_builder));
+
+ /* mark dialog as transient on parent */
+ gtk_window_set_transient_for(GTK_WINDOW(priv->dialog), parent);
+
+ return GTK_WIDGET(priv->dialog);
+}
+
diff --git a/frontends/gtk/preferences.h b/frontends/gtk/preferences.h
new file mode 100644
index 000000000..9fe469e24
--- /dev/null
+++ b/frontends/gtk/preferences.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_GTK_PREFERENCES_H
+#define NETSURF_GTK_PREFERENCES_H
+
+#include <gtk/gtk.h>
+
+/** Initialise prefernces window
+ */
+GtkWidget* nsgtk_preferences(struct browser_window *bw, GtkWindow *parent);
+
+#endif
diff --git a/frontends/gtk/print.c b/frontends/gtk/print.c
new file mode 100644
index 000000000..a6e639996
--- /dev/null
+++ b/frontends/gtk/print.c
@@ -0,0 +1,613 @@
+/*
+ * Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+ /** \file
+ * GTK printing (implementation).
+ * All the functions and structures necessary for printing( signal handlers,
+ * plotters, printer) are here.
+ * Most of the plotters have been copied from the gtk_plotters.c file.
+ */
+
+#include "utils/config.h"
+
+#include <math.h>
+#include <assert.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "content/content.h"
+#include "content/hlcache.h"
+#include "utils/nsoption.h"
+#include "desktop/plotters.h"
+#include "desktop/print.h"
+#include "desktop/printer.h"
+
+#include "gtk/layout_pango.h"
+#include "gtk/bitmap.h"
+#include "gtk/print.h"
+#include "gtk/scaffolding.h"
+
+/* Globals */
+cairo_t *gtk_print_current_cr;
+static struct print_settings* settings;
+hlcache_handle *content_to_print;
+static GdkRectangle cliprect;
+
+static inline void nsgtk_print_set_colour(colour c)
+{
+ int r, g, b;
+
+ r = c & 0xff;
+ g = (c & 0xff00) >> 8;
+ b = (c & 0xff0000) >> 16;
+
+#ifdef FIXME
+ GdkColor colour;
+ colour.red = r | (r << 8);
+ colour.green = g | (g << 8);
+ colour.blue = b | (b << 8);
+ colour.pixel = (r << 16) | (g << 8) | b;
+ gdk_colormap_alloc_color(gdk_colormap_get_system(), &colour, true, true);
+#endif
+ cairo_set_source_rgba(gtk_print_current_cr, r / 255.0,
+ g / 255.0, b / 255.0, 1.0);
+}
+
+
+
+static bool gtk_print_font_paint(int x, int y,
+ const char *string, size_t length,
+ const plot_font_style_t *fstyle)
+{
+ PangoFontDescription *desc;
+ PangoLayout *layout;
+ gint size;
+ PangoLayoutLine *line;
+
+ if (length == 0)
+ return true;
+
+ desc = nsfont_style_to_description(fstyle);
+ size = (gint) ((double) pango_font_description_get_size(desc) *
+ settings->scale);
+
+ if (pango_font_description_get_size_is_absolute(desc))
+ pango_font_description_set_absolute_size(desc, size);
+ else
+ pango_font_description_set_size(desc, size);
+
+ layout = pango_cairo_create_layout(gtk_print_current_cr);
+
+ pango_layout_set_font_description(layout, desc);
+ pango_layout_set_text(layout, string, length);
+
+ line = pango_layout_get_line(layout, 0);
+
+ cairo_move_to(gtk_print_current_cr, x, y);
+ nsgtk_print_set_colour(fstyle->foreground);
+ pango_cairo_show_layout_line(gtk_print_current_cr, line);
+
+ g_object_unref(layout);
+ pango_font_description_free(desc);
+
+ return true;
+}
+
+
+/** Set cairo context to solid plot operation. */
+static inline void nsgtk_print_set_solid(void)
+{
+ double dashes = 0;
+ cairo_set_dash(gtk_print_current_cr, &dashes, 0, 0);
+}
+
+/** Set cairo context to dotted plot operation. */
+static inline void nsgtk_print_set_dotted(void)
+{
+ double cdashes[] = { 1.0, 2.0 };
+ cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0);
+}
+
+/** Set cairo context to dashed plot operation. */
+static inline void nsgtk_print_set_dashed(void)
+{
+ double cdashes[] = { 8.0, 2.0 };
+ cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0);
+}
+
+/** Set clipping area for subsequent plot operations. */
+static bool nsgtk_print_plot_clip(const struct rect *clip)
+{
+ LOG("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", clip->x0, clip->y0, clip->x1, clip->y1);
+
+ /* Normalize cllipping area - to prevent overflows.
+ * See comment in pdf_plot_fill. */
+ int clip_x0 = min(max(clip->x0, 0), settings->page_width);
+ int clip_y0 = min(max(clip->y0, 0), settings->page_height);
+ int clip_x1 = min(max(clip->x1, 0), settings->page_width);
+ int clip_y1 = min(max(clip->y1, 0), settings->page_height);
+
+ cairo_reset_clip(gtk_print_current_cr);
+ cairo_rectangle(gtk_print_current_cr, clip_x0, clip_y0,
+ clip_x1 - clip_x0, clip_y1 - clip_y0);
+ cairo_clip(gtk_print_current_cr);
+
+ cliprect.x = clip_x0;
+ cliprect.y = clip_y0;
+ cliprect.width = clip_x1 - clip_x0;
+ cliprect.height = clip_y1 - clip_y0;
+
+ return true;
+}
+
+static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style)
+{
+ nsgtk_print_set_colour(style->fill_colour);
+ nsgtk_print_set_solid();
+
+ cairo_set_line_width(gtk_print_current_cr, 1);
+ cairo_arc(gtk_print_current_cr, x, y, radius,
+ (angle1 + 90) * (M_PI / 180),
+ (angle2 + 90) * (M_PI / 180));
+ cairo_stroke(gtk_print_current_cr);
+
+ return true;
+}
+
+static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *style)
+{
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_print_set_colour(style->fill_colour);
+ nsgtk_print_set_solid();
+ cairo_set_line_width(gtk_print_current_cr, 0);
+ cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2);
+ cairo_fill(gtk_print_current_cr);
+ cairo_stroke(gtk_print_current_cr);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_print_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_print_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_print_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_print_set_dashed();
+ break;
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(gtk_print_current_cr, 1);
+ else
+ cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+
+ cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2);
+
+ cairo_stroke(gtk_print_current_cr);
+ }
+ return true;
+}
+
+static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ nsgtk_print_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_print_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_print_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_print_set_dashed();
+ break;
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(gtk_print_current_cr, 1);
+ else
+ cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+
+ cairo_move_to(gtk_print_current_cr, x0 + 0.5, y0 + 0.5);
+ cairo_line_to(gtk_print_current_cr, x1 + 0.5, y1 + 0.5);
+ cairo_stroke(gtk_print_current_cr);
+
+ return true;
+}
+
+static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style)
+{
+ LOG("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0, y0, x1, y1);
+
+ if (style->fill_type != PLOT_OP_TYPE_NONE) {
+
+ nsgtk_print_set_colour(style->fill_colour);
+ nsgtk_print_set_solid();
+
+ /* Normalize boundaries of the area - to prevent overflows.
+ * See comment in pdf_plot_fill. */
+ x0 = min(max(x0, 0), settings->page_width);
+ y0 = min(max(y0, 0), settings->page_height);
+ x1 = min(max(x1, 0), settings->page_width);
+ y1 = min(max(y1, 0), settings->page_height);
+
+ cairo_set_line_width(gtk_print_current_cr, 0);
+ cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_fill(gtk_print_current_cr);
+ cairo_stroke(gtk_print_current_cr);
+ }
+
+ if (style->stroke_type != PLOT_OP_TYPE_NONE) {
+ nsgtk_print_set_colour(style->stroke_colour);
+
+ switch (style->stroke_type) {
+ case PLOT_OP_TYPE_SOLID: /**< Solid colour */
+ default:
+ nsgtk_print_set_solid();
+ break;
+
+ case PLOT_OP_TYPE_DOT: /**< Doted plot */
+ nsgtk_print_set_dotted();
+ break;
+
+ case PLOT_OP_TYPE_DASH: /**< dashed plot */
+ nsgtk_print_set_dashed();
+ break;
+ }
+
+ if (style->stroke_width == 0)
+ cairo_set_line_width(gtk_print_current_cr, 1);
+ else
+ cairo_set_line_width(gtk_print_current_cr, style->stroke_width);
+
+ cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_stroke(gtk_print_current_cr);
+ }
+
+ return true;
+}
+
+static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_style_t *style)
+{
+ unsigned int i;
+
+ LOG("Plotting polygon.");
+
+ nsgtk_print_set_colour(style->fill_colour);
+ nsgtk_print_set_solid();
+
+ cairo_set_line_width(gtk_print_current_cr, 0);
+ cairo_move_to(gtk_print_current_cr, p[0], p[1]);
+
+ LOG("Starting line at: %i\t%i", p[0], p[1]);
+
+ for (i = 1; i != n; i++) {
+ cairo_line_to(gtk_print_current_cr, p[i * 2], p[i * 2 + 1]);
+ LOG("Drawing line to: %i\t%i", p[i * 2], p[i * 2 + 1]);
+ }
+
+ cairo_fill(gtk_print_current_cr);
+ cairo_stroke(gtk_print_current_cr);
+
+ return true;
+}
+
+
+static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill,
+ float width, colour c, const float transform[6])
+{
+ /* Only the internal SVG renderer uses this plot call currently,
+ * and the GTK version uses librsvg. Thus, we ignore this complexity,
+ * and just return true obliviously. */
+
+ return true;
+}
+
+
+static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg)
+{
+ int x0, y0, x1, y1;
+ int dsrcx, dsrcy, dwidth, dheight;
+ int bmwidth, bmheight;
+
+ cairo_surface_t *bmsurface = bitmap->surface;
+
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
+ if ((x > (cliprect.x + cliprect.width)) ||
+ ((x + width) < cliprect.x) ||
+ (y > (cliprect.y + cliprect.height)) ||
+ ((y + height) < cliprect.y)) {
+ /* Image completely outside clip region */
+ return true;
+ }
+
+ /* Get clip rectangle / image rectangle edge differences */
+ x0 = cliprect.x - x;
+ y0 = cliprect.y - y;
+ x1 = (x + width) - (cliprect.x + cliprect.width);
+ y1 = (y + height) - (cliprect.y + cliprect.height);
+
+ /* Set initial draw geometry */
+ dsrcx = x;
+ dsrcy = y;
+ dwidth = width;
+ dheight = height;
+
+ /* Manually clip draw coordinates to area of image to be rendered */
+ if (x0 > 0) {
+ /* Clip left */
+ dsrcx += x0;
+ dwidth -= x0;
+ }
+ if (y0 > 0) {
+ /* Clip top */
+ dsrcy += y0;
+ dheight -= y0;
+ }
+ if (x1 > 0) {
+ /* Clip right */
+ dwidth -= x1;
+ }
+ if (y1 > 0) {
+ /* Clip bottom */
+ dheight -= y1;
+ }
+
+ if (dwidth == 0 || dheight == 0)
+ /* Nothing to plot */
+ return true;
+
+ bmwidth = cairo_image_surface_get_width(bmsurface);
+ bmheight = cairo_image_surface_get_height(bmsurface);
+
+ /* Render the bitmap */
+ if ((bmwidth == width) && (bmheight == height)) {
+ /* Bitmap is not scaled */
+ /* Plot the bitmap */
+ cairo_set_source_surface(gtk_print_current_cr, bmsurface, x, y);
+ cairo_rectangle(gtk_print_current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(gtk_print_current_cr);
+
+ } else {
+ /* Bitmap is scaled */
+ if ((bitmap->scsurface != NULL) &&
+ ((cairo_image_surface_get_width(bitmap->scsurface) != width) ||
+ (cairo_image_surface_get_height(bitmap->scsurface) != height))){
+ cairo_surface_destroy(bitmap->scsurface);
+ bitmap->scsurface = NULL;
+ }
+
+ if (bitmap->scsurface == NULL) {
+ bitmap->scsurface = cairo_surface_create_similar(bmsurface,CAIRO_CONTENT_COLOR_ALPHA, width, height);
+ cairo_t *cr = cairo_create(bitmap->scsurface);
+
+ /* Scale *before* setting the source surface (1) */
+ cairo_scale(cr, (double)width / bmwidth, (double)height / bmheight);
+ cairo_set_source_surface(cr, bmsurface, 0, 0);
+
+ /* To avoid getting the edge pixels blended with 0
+ * alpha, which would occur with the default
+ * EXTEND_NONE. Use EXTEND_PAD for 1.2 or newer (2)
+ */
+ cairo_pattern_set_extend(cairo_get_source(cr),
+ CAIRO_EXTEND_REFLECT);
+
+ /* Replace the destination with the source instead of
+ * overlaying
+ */
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ /* Do the actual drawing */
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ }
+ /* Plot the scaled bitmap */
+ cairo_set_source_surface(gtk_print_current_cr, bitmap->scsurface, x, y);
+ cairo_rectangle(gtk_print_current_cr, dsrcx, dsrcy, dwidth, dheight);
+ cairo_fill(gtk_print_current_cr);
+
+ }
+
+ return true;
+}
+
+
+static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height,
+ struct bitmap *bitmap, colour bg,
+ bitmap_flags_t flags)
+{
+ int doneheight = 0, donewidth = 0;
+ bool repeat_x = (flags & BITMAPF_REPEAT_X);
+ bool repeat_y = (flags & BITMAPF_REPEAT_Y);
+
+ if (!(repeat_x || repeat_y)) {
+ /* Not repeating at all, so just pass it on */
+ return nsgtk_print_plot_pixbuf(x, y, width, height, bitmap, bg);
+ }
+
+ width = nsgtk_bitmap_get_width(bitmap);
+ height = nsgtk_bitmap_get_height(bitmap);
+
+ /* Bail early if we can */
+ if (width == 0 || height == 0)
+ /* Nothing to plot */
+ return true;
+
+ if (y > cliprect.y) {
+ doneheight = (cliprect.y - height) + ((y - cliprect.y) % height);
+ } else {
+ doneheight = y;
+ }
+
+ while (doneheight < (cliprect.y + cliprect.height)) {
+ if (x > cliprect.x) {
+ donewidth = (cliprect.x - width) + ((x - cliprect.x) % width);
+ } else {
+ donewidth = x;
+ }
+
+ while (donewidth < (cliprect.x + cliprect.width)) {
+ nsgtk_print_plot_pixbuf(donewidth, doneheight,
+ width, height, bitmap, bg);
+ donewidth += width;
+ if (!repeat_x)
+ break;
+ }
+ doneheight += height;
+
+ if (!repeat_y)
+ break;
+ }
+
+ return true;
+}
+
+static bool nsgtk_print_plot_text(int x, int y, const char *text, size_t length,
+ const plot_font_style_t *fstyle)
+{
+ return gtk_print_font_paint(x, y, text, length, fstyle);
+}
+
+/** GTK print plotter table */
+static const struct plotter_table nsgtk_print_plotters = {
+ .clip = nsgtk_print_plot_clip,
+ .arc = nsgtk_print_plot_arc,
+ .disc = nsgtk_print_plot_disc,
+ .line = nsgtk_print_plot_line,
+ .rectangle = nsgtk_print_plot_rectangle,
+ .polygon = nsgtk_print_plot_polygon,
+ .path = nsgtk_print_plot_path,
+ .bitmap = nsgtk_print_plot_bitmap,
+ .text = nsgtk_print_plot_text,
+ .option_knockout = false,
+};
+
+static bool gtk_print_begin(struct print_settings* settings)
+{
+ return true;
+}
+
+static bool gtk_print_next_page(void)
+{
+ return true;
+}
+
+static void gtk_print_end(void)
+{
+}
+
+static const struct printer gtk_printer = {
+ &nsgtk_print_plotters,
+ gtk_print_begin,
+ gtk_print_next_page,
+ gtk_print_end
+};
+
+/**
+ * Handle the begin_print signal from the GtkPrintOperation
+ *
+ * \param operation the operation which emited the signal
+ * \param context the print context used to set up the pages
+ * \param user_data nothing in here
+ */
+void gtk_print_signal_begin_print (GtkPrintOperation *operation,
+ GtkPrintContext *context, gpointer user_data)
+{
+ int page_number;
+ double height_on_page, height_to_print;
+
+ LOG("Begin print");
+
+ settings = user_data;
+
+ settings->margins[MARGINTOP] = 0;
+ settings->margins[MARGINLEFT] = 0;
+ settings->margins[MARGINBOTTOM] = 0;
+ settings->margins[MARGINRIGHT] = 0;
+ settings->page_width = gtk_print_context_get_width(context);
+ settings->page_height = gtk_print_context_get_height(context);
+ settings->scale = 0.7; /* at 0.7 the pages look the best */
+ settings->font_func = nsgtk_layout_table;
+
+ if (print_set_up(content_to_print, &gtk_printer,
+ settings, &height_to_print) == false) {
+ gtk_print_operation_cancel(operation);
+
+ } else {
+
+ LOG("page_width: %f ;page_height: %f; content height: %lf", settings->page_width, settings->page_height, height_to_print);
+
+ height_on_page = settings->page_height;
+ height_on_page = height_on_page -
+ FIXTOFLT(FSUB(settings->margins[MARGINTOP],
+ settings->margins[MARGINBOTTOM]));
+ height_to_print *= settings->scale;
+
+ page_number = height_to_print / height_on_page;
+
+ if (height_to_print - page_number * height_on_page > 0)
+ page_number += 1;
+
+ gtk_print_operation_set_n_pages(operation, page_number);
+ }
+}
+
+/**
+ * Handle the draw_page signal from the GtkPrintOperation.
+ * This function changes only the cairo context to print on.
+ */
+void gtk_print_signal_draw_page(GtkPrintOperation *operation,
+ GtkPrintContext *context, gint page_nr, gpointer user_data)
+{
+ LOG("Draw Page");
+ gtk_print_current_cr = gtk_print_context_get_cairo_context(context);
+ print_draw_next_page(&gtk_printer, settings);
+}
+
+/**
+ * Handle the end_print signal from the GtkPrintOperation.
+ * This functions calls only the print_cleanup function from the print interface
+ */
+void gtk_print_signal_end_print(GtkPrintOperation *operation,
+ GtkPrintContext *context, gpointer user_data)
+{
+ LOG("End print");
+ print_cleanup(content_to_print, &gtk_printer, user_data);
+}
+
+
diff --git a/frontends/gtk/print.h b/frontends/gtk/print.h
new file mode 100644
index 000000000..d44fad31f
--- /dev/null
+++ b/frontends/gtk/print.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ /** \file
+ * GTK printing (interface).
+ */
+
+#ifndef NETSURF_GTK_PRINT_PLOTTERS_H
+#define NETSURF_GTK_PRINT_PLOTTERS_H
+
+
+#include <gtk/gtk.h>
+
+struct hlcache_handle;
+
+extern cairo_t *gtk_print_current_cr;
+
+extern struct hlcache_handle *content_to_print;
+
+
+/*handlers for signals from the GTK print operation*/
+void gtk_print_signal_begin_print(GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gpointer user_data);
+
+void gtk_print_signal_draw_page(GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gint page_nr,
+ gpointer user_data);
+
+void gtk_print_signal_end_print(GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gpointer user_data);
+
+#endif
diff --git a/frontends/gtk/res/Messages b/frontends/gtk/res/Messages
new file mode 120000
index 000000000..75bfdf53d
--- /dev/null
+++ b/frontends/gtk/res/Messages
@@ -0,0 +1 @@
+en/Messages \ No newline at end of file
diff --git a/frontends/gtk/res/SearchEngines b/frontends/gtk/res/SearchEngines
new file mode 120000
index 000000000..3dc819c2a
--- /dev/null
+++ b/frontends/gtk/res/SearchEngines
@@ -0,0 +1 @@
+../../../resources/SearchEngines \ No newline at end of file
diff --git a/frontends/gtk/res/adblock.css b/frontends/gtk/res/adblock.css
new file mode 120000
index 000000000..ff2485622
--- /dev/null
+++ b/frontends/gtk/res/adblock.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/AdBlock,f79 \ No newline at end of file
diff --git a/frontends/gtk/res/arrow_down_8x32.png b/frontends/gtk/res/arrow_down_8x32.png
new file mode 100644
index 000000000..475b4ff61
--- /dev/null
+++ b/frontends/gtk/res/arrow_down_8x32.png
Binary files differ
diff --git a/frontends/gtk/res/ca-bundle.txt b/frontends/gtk/res/ca-bundle.txt
new file mode 120000
index 000000000..0b0e416ad
--- /dev/null
+++ b/frontends/gtk/res/ca-bundle.txt
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/ca-bundle \ No newline at end of file
diff --git a/frontends/gtk/res/cookies.gtk2.ui b/frontends/gtk/res/cookies.gtk2.ui
new file mode 100644
index 000000000..86f15c765
--- /dev/null
+++ b/frontends/gtk/res/cookies.gtk2.ui
@@ -0,0 +1,174 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.6 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkWindow" id="wndCookies">
+ <property name="title" translatable="yes">Cookies - NetSurf</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">2</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Delete" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">D_elete all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ <accelerator key="A" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ <accelerator key="U" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu5">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_domains">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Domains</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_cookies">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Cookies</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu6">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_domains">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Domains</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_cookies">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Cookies</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="cookiesScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkViewport" id="cookiesViewport">
+ <property name="visible">True</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <object class="GtkDrawingArea" id="cookiesDrawingArea">
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/cookies.gtk3.ui b/frontends/gtk/res/cookies.gtk3.ui
new file mode 100644
index 000000000..44dcb80b8
--- /dev/null
+++ b/frontends/gtk/res/cookies.gtk3.ui
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndCookies">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Cookies</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">D_elete all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_domains">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Domains</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_cookies">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Cookies</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_domains">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Domains</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_cookies">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Cookies</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="cookiesScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport" id="cookiesViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="cookiesDrawingArea">
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/credits.html b/frontends/gtk/res/credits.html
new file mode 120000
index 000000000..ca85d3d27
--- /dev/null
+++ b/frontends/gtk/res/credits.html
@@ -0,0 +1 @@
+en/credits.html \ No newline at end of file
diff --git a/frontends/gtk/res/de/welcome.html b/frontends/gtk/res/de/welcome.html
new file mode 120000
index 000000000..98a53b215
--- /dev/null
+++ b/frontends/gtk/res/de/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/de/welcome.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/default.css b/frontends/gtk/res/default.css
new file mode 120000
index 000000000..a8579eb7c
--- /dev/null
+++ b/frontends/gtk/res/default.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/CSS,f79 \ No newline at end of file
diff --git a/frontends/gtk/res/default.ico b/frontends/gtk/res/default.ico
new file mode 100644
index 000000000..1cb432828
--- /dev/null
+++ b/frontends/gtk/res/default.ico
Binary files differ
diff --git a/frontends/gtk/res/downloads.gtk2.ui b/frontends/gtk/res/downloads.gtk2.ui
new file mode 100644
index 000000000..1e71328a4
--- /dev/null
+++ b/frontends/gtk/res/downloads.gtk2.ui
@@ -0,0 +1,175 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkWindow" id="wndDownloads">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="title" translatable="yes">Downloads - NetSurf</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">500</property>
+ <property name="default_height">300</property>
+ <property name="destroy_with_parent">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeDownloads">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="search_column">2</property>
+ <property name="show_expanders">False</property>
+ <property name="rubber_banding">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHSeparator" id="hseparator1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">2</property>
+ <property name="bottom_padding">2</property>
+ <property name="left_padding">2</property>
+ <property name="right_padding">2</property>
+ <child>
+ <object class="GtkProgressBar" id="progressBar">
+ <property name="visible">True</property>
+ <property name="show_text">True</property>
+ <property name="text" translatable="yes">0% of 0 files</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="buttonPause">
+ <property name="label">gtk-media-pause</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonPlay">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-media-play</property>
+ <property name="icon-size">2</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Resume</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonCancel">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonClear">
+ <property name="label">gtk-clear</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/downloads.gtk3.ui b/frontends/gtk/res/downloads.gtk3.ui
new file mode 100644
index 000000000..1e71328a4
--- /dev/null
+++ b/frontends/gtk/res/downloads.gtk3.ui
@@ -0,0 +1,175 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkWindow" id="wndDownloads">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="title" translatable="yes">Downloads - NetSurf</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">500</property>
+ <property name="default_height">300</property>
+ <property name="destroy_with_parent">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeDownloads">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="search_column">2</property>
+ <property name="show_expanders">False</property>
+ <property name="rubber_banding">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHSeparator" id="hseparator1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">2</property>
+ <property name="bottom_padding">2</property>
+ <property name="left_padding">2</property>
+ <property name="right_padding">2</property>
+ <child>
+ <object class="GtkProgressBar" id="progressBar">
+ <property name="visible">True</property>
+ <property name="show_text">True</property>
+ <property name="text" translatable="yes">0% of 0 files</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="buttonPause">
+ <property name="label">gtk-media-pause</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonPlay">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-media-play</property>
+ <property name="icon-size">2</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Resume</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonCancel">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonClear">
+ <property name="label">gtk-clear</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/en/credits.html b/frontends/gtk/res/en/credits.html
new file mode 120000
index 000000000..252516fd7
--- /dev/null
+++ b/frontends/gtk/res/en/credits.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/credits.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/en/licence.html b/frontends/gtk/res/en/licence.html
new file mode 120000
index 000000000..79f73669b
--- /dev/null
+++ b/frontends/gtk/res/en/licence.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/en/maps.html b/frontends/gtk/res/en/maps.html
new file mode 120000
index 000000000..bb3ffcbe7
--- /dev/null
+++ b/frontends/gtk/res/en/maps.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/maps.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/en/welcome.html b/frontends/gtk/res/en/welcome.html
new file mode 120000
index 000000000..601099223
--- /dev/null
+++ b/frontends/gtk/res/en/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/favicon.png b/frontends/gtk/res/favicon.png
new file mode 120000
index 000000000..5a8b3433c
--- /dev/null
+++ b/frontends/gtk/res/favicon.png
@@ -0,0 +1 @@
+../../../resources/favicon.png \ No newline at end of file
diff --git a/frontends/gtk/res/history.gtk2.ui b/frontends/gtk/res/history.gtk2.ui
new file mode 100644
index 000000000..2b89ecb4b
--- /dev/null
+++ b/frontends/gtk/res/history.gtk2.ui
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndHistory">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Global History</property>
+ <property name="window_position">center</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <property name="type_hint">utility</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="export">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Export</property>
+ <property name="use_underline">True</property>
+ <accelerator key="E" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Delete" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">D_elete all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ <accelerator key="A" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ <accelerator key="U" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="launch">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Launch</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="globalHistoryScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkViewport" id="globalHistoryViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <object class="GtkDrawingArea" id="globalHistoryDrawingArea">
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/history.gtk3.ui b/frontends/gtk/res/history.gtk3.ui
new file mode 100644
index 000000000..7fa598f1e
--- /dev/null
+++ b/frontends/gtk/res/history.gtk3.ui
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndHistory">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Global History</property>
+ <property name="window_position">center</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <property name="type_hint">utility</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="export">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Export</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">D_elete all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="launch">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Launch</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="globalHistoryScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport" id="globalHistoryViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="globalHistoryDrawingArea">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/hotlist.gtk2.ui b/frontends/gtk/res/hotlist.gtk2.ui
new file mode 100644
index 000000000..af0fd5696
--- /dev/null
+++ b/frontends/gtk/res/hotlist.gtk2.ui
@@ -0,0 +1,217 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.6 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkWindow" id="wndHotlist">
+ <property name="title" translatable="yes">Bookmarks - NetSurf</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">2</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="export">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Export</property>
+ <property name="use_underline">True</property>
+ <accelerator key="E" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="new_folder">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">New _folder</property>
+ <property name="use_underline">True</property>
+ <accelerator key="M" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="new_entry">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">New _entry</property>
+ <property name="use_underline">True</property>
+ <accelerator key="N" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="edit_selected">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ <accelerator key="Delete" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ <accelerator key="A" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ <accelerator key="U" signal="activate" modifiers="GDK_MOD1_MASK"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu5">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_directories">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_addresses">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu6">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_directories">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_addresses">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="launch">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Launch</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="hotlistScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkViewport" id="hotlistViewport">
+ <property name="visible">True</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <object class="GtkDrawingArea" id="hotlistDrawingArea">
+ <property name="visible">True</property>
+ <property name="app_paintable">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/hotlist.gtk3.ui b/frontends/gtk/res/hotlist.gtk3.ui
new file mode 100644
index 000000000..b0e075c4b
--- /dev/null
+++ b/frontends/gtk/res/hotlist.gtk3.ui
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndHotlist">
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">NetSurf Bookmarks</property>
+ <property name="window_position">mouse</property>
+ <property name="default_width">600</property>
+ <property name="default_height">500</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="export">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Export</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="new_folder">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">New _folder</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="new_entry">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">New _entry</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="edit_selected">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="delete_selected">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Delete</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="select_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Select all</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="clear_selection">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Clear selection</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Expand</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="expand_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="expand_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Collapse</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkMenuItem" id="collapse_all">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_All</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_directories">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Directories</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="collapse_addresses">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Add_resses</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="launch">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_Launch</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="hotlistScrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport" id="hotlistViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="hotlistDrawingArea">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/icons b/frontends/gtk/res/icons
new file mode 120000
index 000000000..187efd6f9
--- /dev/null
+++ b/frontends/gtk/res/icons
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/Icons/ \ No newline at end of file
diff --git a/frontends/gtk/res/internal.css b/frontends/gtk/res/internal.css
new file mode 120000
index 000000000..17f9f1504
--- /dev/null
+++ b/frontends/gtk/res/internal.css
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/internal.css,f79 \ No newline at end of file
diff --git a/frontends/gtk/res/it/credits.html b/frontends/gtk/res/it/credits.html
new file mode 120000
index 000000000..64b78982e
--- /dev/null
+++ b/frontends/gtk/res/it/credits.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/it/credits.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/it/licence.html b/frontends/gtk/res/it/licence.html
new file mode 120000
index 000000000..4abc825d3
--- /dev/null
+++ b/frontends/gtk/res/it/licence.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/it/licence.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/it/welcome.html b/frontends/gtk/res/it/welcome.html
new file mode 120000
index 000000000..59cef0551
--- /dev/null
+++ b/frontends/gtk/res/it/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/it/welcome.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/ja/welcome.html b/frontends/gtk/res/ja/welcome.html
new file mode 120000
index 000000000..a2556ee4e
--- /dev/null
+++ b/frontends/gtk/res/ja/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/ja/welcome.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/languages b/frontends/gtk/res/languages
new file mode 100644
index 000000000..4927e03a0
--- /dev/null
+++ b/frontends/gtk/res/languages
@@ -0,0 +1,261 @@
+aa
+ab
+ae
+af
+ak
+am
+an
+ar
+ar-ae
+ar-bh
+ar-dz
+ar-eg
+ar-iq
+ar-jo
+ar-kw
+ar-lb
+ar-ly
+ar-ma
+ar-om
+ar-qa
+ar-sa
+ar-sy
+ar-tn
+ar-ye
+as
+ast
+av
+az
+ba
+be
+bg
+bh
+bi
+bm
+bn
+bo
+br
+bs
+ca
+ce
+ch
+co
+cr
+cs
+cu
+cv
+cy
+da
+de
+de-at
+de-ch
+de-de
+de-li
+de-lu
+dv
+dz
+ee
+el
+en
+en-au
+en-bz
+en-ca
+en-gb
+en-ie
+en-jm
+en-nz
+en-ph
+en-tt
+en-us
+en-za
+en-zw
+eo
+es
+es-ar
+es-bo
+es-cl
+es-co
+es-cr
+es-do
+es-ec
+es-es
+es-gt
+es-hn
+es-mx
+es-ni
+es-pa
+es-pe
+es-pr
+es-py
+es-sv
+es-uy
+es-ve
+et
+eu
+fa
+fa-ir
+ff
+fi
+fj
+fo
+fr
+fr-be
+fr-ca
+fr-ch
+fr-fr
+fr-lu
+fr-mc
+fur
+fy
+ga
+gd
+gl
+gn
+gu
+gv
+ha
+he
+hi
+ho
+hsb
+hr
+ht
+hu
+hy
+hz
+ia
+id
+ie
+ig
+ii
+ik
+io
+is
+it
+it-ch
+iu
+ja
+jv
+ka
+kg
+ki
+kk
+kl
+km
+kn
+ko
+ko-kp
+ko-kr
+kok
+kr
+ks
+ku
+kv
+kw
+ky
+la
+lb
+lg
+li
+ln
+lo
+lt
+lu
+lv
+mg
+mh
+mi
+mk
+mk-mk
+ml
+mn
+mo
+mr
+ms
+mt
+my
+na
+nb
+nd
+ne
+ng
+nl
+nl-be
+nn
+no
+nr
+nso
+nv
+ny
+oc
+oj
+om
+or
+os
+pa
+pa-in
+pa-pk
+pi
+pl
+ps
+pt
+pt-br
+qu
+rm
+rn
+ro
+ro-mo
+ru
+ru-mo
+sa
+sc
+sd
+sg
+si
+sk
+sl
+so
+sq
+sr
+ss
+st
+su
+sv
+sv-fi
+sv-se
+sw
+ta
+te
+tg
+th
+ti
+tig
+tk
+tl
+tlh
+tn
+to
+tr
+ts
+tt
+tw
+ty
+ug
+uk
+ur
+uz
+ve
+vi
+vo
+wa
+wo
+xh
+yi
+yo
+za
+zh
+zh-cn
+zh-hk
+zh-sg
+zh-tw
+zu
diff --git a/frontends/gtk/res/licence.html b/frontends/gtk/res/licence.html
new file mode 120000
index 000000000..86f8c54bf
--- /dev/null
+++ b/frontends/gtk/res/licence.html
@@ -0,0 +1 @@
+en/licence.html \ No newline at end of file
diff --git a/frontends/gtk/res/login.gtk2.ui b/frontends/gtk/res/login.gtk2.ui
new file mode 100644
index 000000000..552b173ed
--- /dev/null
+++ b/frontends/gtk/res/login.gtk2.ui
@@ -0,0 +1,223 @@
+<?xml version="1.0"?>
+<!--*- mode: xml -*-->
+<interface>
+ <object class="GtkDialog" id="wndLogin">
+ <property name="title" translatable="yes">Site Authentication</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="border_width">3</property>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="yalign">0.10000000149011612</property>
+ <property name="xpad">12</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-authentication</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table5">
+ <property name="visible">True</property>
+ <property name="border_width">1</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">11</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="labelLoginHost">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">moo.yoo.com</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label57">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label56">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Username</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Host</property>
+ </object>
+ <packing>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Realm</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelLoginRealm">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">my sekr3t area</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryLoginPass">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="text" translatable="yes">opensesame</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryLoginUser">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="text" translatable="yes">sesame</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">1</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <object class="GtkButton" id="buttonLoginCan">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonLoginOK">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <child>
+ <object class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-ok</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label49">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">buttonLoginCan</action-widget>
+ <action-widget response="-5">buttonLoginOK</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/login.gtk3.ui b/frontends/gtk/res/login.gtk3.ui
new file mode 100644
index 000000000..552b173ed
--- /dev/null
+++ b/frontends/gtk/res/login.gtk3.ui
@@ -0,0 +1,223 @@
+<?xml version="1.0"?>
+<!--*- mode: xml -*-->
+<interface>
+ <object class="GtkDialog" id="wndLogin">
+ <property name="title" translatable="yes">Site Authentication</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="border_width">3</property>
+ <child>
+ <object class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="yalign">0.10000000149011612</property>
+ <property name="xpad">12</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-authentication</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table5">
+ <property name="visible">True</property>
+ <property name="border_width">1</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">11</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <object class="GtkLabel" id="labelLoginHost">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">moo.yoo.com</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label57">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label56">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Username</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Host</property>
+ </object>
+ <packing>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Realm</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelLoginRealm">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">my sekr3t area</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryLoginPass">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="text" translatable="yes">opensesame</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryLoginUser">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="text" translatable="yes">sesame</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="padding">1</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <object class="GtkButton" id="buttonLoginCan">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonLoginOK">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <child>
+ <object class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-ok</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label49">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">buttonLoginCan</action-widget>
+ <action-widget response="-5">buttonLoginOK</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/maps.html b/frontends/gtk/res/maps.html
new file mode 120000
index 000000000..a32f725fb
--- /dev/null
+++ b/frontends/gtk/res/maps.html
@@ -0,0 +1 @@
+en/maps.html \ No newline at end of file
diff --git a/frontends/gtk/res/menu_cursor.png b/frontends/gtk/res/menu_cursor.png
new file mode 100644
index 000000000..ccbbbd2d4
--- /dev/null
+++ b/frontends/gtk/res/menu_cursor.png
Binary files differ
diff --git a/frontends/gtk/res/menu_cursor.xbm b/frontends/gtk/res/menu_cursor.xbm
new file mode 100644
index 000000000..1257ac1f4
--- /dev/null
+++ b/frontends/gtk/res/menu_cursor.xbm
@@ -0,0 +1,6 @@
+#define menu_cursor_width 16
+#define menu_cursor_height 16
+static char menu_cursor_bits[] = {
+ 0x00, 0x00, 0x80, 0x7F, 0x88, 0x40, 0x9E, 0x5E, 0x88, 0x40, 0x80, 0x56,
+ 0x80, 0x40, 0x80, 0x5A, 0x80, 0x40, 0x80, 0x5E, 0x80, 0x40, 0x80, 0x56,
+ 0x80, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00 };
diff --git a/frontends/gtk/res/menu_cursor_mask.xbm b/frontends/gtk/res/menu_cursor_mask.xbm
new file mode 100644
index 000000000..09789d51b
--- /dev/null
+++ b/frontends/gtk/res/menu_cursor_mask.xbm
@@ -0,0 +1,6 @@
+#define menu_cursor_mask_width 16
+#define menu_cursor_mask_height 16
+static char menu_cursor_mask_bits[] = {
+ 0xC0, 0xFF, 0xC8, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xC8, 0xFF,
+ 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF,
+ 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0x00, 0x00 };
diff --git a/frontends/gtk/res/menu_cursor_mask.xpm b/frontends/gtk/res/menu_cursor_mask.xpm
new file mode 100644
index 000000000..985d46cc6
--- /dev/null
+++ b/frontends/gtk/res/menu_cursor_mask.xpm
@@ -0,0 +1,22 @@
+/* XPM */
+static char * menu_cursor_mask_xpm[] = {
+"16 16 3 1",
+" c None",
+". c #FFFFFF",
+"+ c #000000",
+" ..........",
+" . .++++++++.",
+"...+. .+......+.",
+".++++..+.++++.+.",
+"...+. .+......+.",
+" . .+.++.+.+.",
+" .+......+.",
+" .+.+.++.+.",
+" .+......+.",
+" .+.++++.+.",
+" .+......+.",
+" .+.++.+.+.",
+" .+......+.",
+" .++++++++.",
+" ..........",
+" "};
diff --git a/frontends/gtk/res/messages.gresource.xml b/frontends/gtk/res/messages.gresource.xml
new file mode 100644
index 000000000..684a10862
--- /dev/null
+++ b/frontends/gtk/res/messages.gresource.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/netsurf">
+ <file>Messages</file>
+ <file>nl/Messages</file>
+ <file>de/Messages</file>
+ <file>fr/Messages</file>
+ <file>it/Messages</file>
+ </gresource>
+</gresources>
diff --git a/frontends/gtk/res/netsurf-16x16.xpm b/frontends/gtk/res/netsurf-16x16.xpm
new file mode 100644
index 000000000..7880f7aae
--- /dev/null
+++ b/frontends/gtk/res/netsurf-16x16.xpm
@@ -0,0 +1,211 @@
+/* XPM */
+static char *netsurf___x__[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 189 2",
+" c #02530B521130",
+". c #02C50E711619",
+"X c #02AF106B198E",
+"o c #02D913641E8A",
+"O c #04D913E91D9D",
+"+ c #042B14C01F86",
+"@ c #124A1BC61F1D",
+"# c #097F17941FC4",
+"$ c #03CE193E2759",
+"% c #04451CED2D68",
+"& c #0BDC1D8727E6",
+"* c #10D2247A2F43",
+"= c #069C27663D09",
+"- c #180C2AED33E3",
+"; c #1AEC2D37353A",
+": c #16F12D9C3927",
+"> c #20AD32C039B7",
+", c #0A2A2E04451D",
+"< c #0C1A306A47D4",
+"1 c #1D6E39A1482F",
+"2 c #060A341B5355",
+"3 c #0B773D945E4D",
+"4 c #20B93C4949C5",
+"5 c #07B03F0A6460",
+"6 c #2332407A4E57",
+"7 c #253040AD4CF8",
+"8 c #33854FAB5A6E",
+"9 c #15494CF97003",
+"0 c #19F855EA7B34",
+"q c #1E7F57237923",
+"w c #21344D986676",
+"e c #422B60856A1E",
+"r c #09DA58208D29",
+"t c #11AC562C82BA",
+"y c #0A6A5CB99496",
+"u c #18A265959712",
+"i c #17B8662E9805",
+"p c #11A66358990E",
+"a c #224A65BB8E98",
+"s c #342C75079947",
+"d c #3487766A9B6F",
+"f c #35B478C99F4B",
+"g c #0BFA6509A06D",
+"h c #0F9175B8BA3A",
+"j c #1AAA7C1DBB21",
+"k c #289374DBA2C1",
+"l c #200E76DFADCA",
+"z c #269D7B1FAF00",
+"x c #32E57D4FA875",
+"c c #299F805AB558",
+"v c #2DF28A1CC027",
+"b c #345A83F3B216",
+"n c #3151843FB58D",
+"m c #59C882138E75",
+"M c #5F5E8AAC9842",
+"N c #51998AF6A4C9",
+"B c #5F5A96AEACF5",
+"V c #43048E07B597",
+"C c #65129940AC1C",
+"Z c #6C1AA2A1B60E",
+"A c #7A87AEC9BD67",
+"S c #125084AAD039",
+"D c #163388A1D450",
+"F c #1BF88E3BD899",
+"G c #17BD8EB6DCB2",
+"H c #220A83D0C214",
+"J c #29678B9EC6ED",
+"K c #3F59A336DDC8",
+"L c #198792ECE247",
+"P c #11B295CDED75",
+"I c #132A98BFF1CB",
+"U c #25099D91EB08",
+"Y c #29299E0AE8BB",
+"T c #1412A137FE21",
+"R c #191EA60AFFFF",
+"E c #1C73A663FFFF",
+"W c #2E68A1C2E7B3",
+"Q c #2C05A14AEAC1",
+"! c #2E32A597F03F",
+"~ c #39BBA7F4E929",
+"^ c #23A0A4D1F872",
+"/ c #25C6A4E4F6A5",
+"( c #2965A4CCF3B1",
+") c #236CA4BAF891",
+"_ c #23A1A6A2FA96",
+"` c #2018A8FDFFFF",
+"' c #25F5AB89FFFF",
+"] c #2B0BACCDFECB",
+"[ c #2AEBAD69FFF4",
+"{ c #2E7EAC78FC88",
+"} c #37FCADAFF4EB",
+"| c #3B7FAF4EF4E9",
+" . c #303DAB56F8E3",
+".. c #3354B0E8FFFF",
+"X. c #3607B294FFCE",
+"o. c #3978B4A2FFF7",
+"O. c #414EA3E7DD4D",
+"+. c #5643A8B7D325",
+"@. c #52B4AADCD9F0",
+"#. c #60F0B145D82C",
+"$. c #6F40B9C2DA92",
+"%. c #71EFBCB5DD40",
+"&. c #482FB26FEEA5",
+"*. c #5E59B526E061",
+"=. c #413CB50EFA06",
+"-. c #40FAB7C7FF64",
+";. c #411FB840FF4A",
+":. c #43C4B9CAFFFA",
+">. c #4AB5BB61FFFF",
+",. c #4A0ABCF3FFFF",
+"<. c #4BB1BD9AFFB4",
+"1. c #4D02BE43FFE0",
+"2. c #542DBA39F2D5",
+"3. c #5682BD17F583",
+"4. c #6545BFABECE0",
+"5. c #7AD1C155DCC5",
+"6. c #512AC23DFFFF",
+"7. c #5584C279FF9A",
+"8. c #5642C44BFFFF",
+"9. c #57E0C1FCF97C",
+"0. c #5C81C618FFB3",
+"q. c #5F65C55DFFFF",
+"w. c #5FA0C7BFFFCB",
+"e. c #6BD0C37FEDBC",
+"r. c #6FB7C6C0EF7B",
+"t. c #7055C5DCEDC7",
+"y. c #7A3ECB76EEA8",
+"u. c #63C4C2A1F626",
+"i. c #64A9C5C0F7C3",
+"p. c #6B3AC4CBF902",
+"a. c #621EC925FFE9",
+"s. c #6557C9F1FE6D",
+"d. c #67BACC2FFFFE",
+"f. c #66B4CD66FFFF",
+"g. c #69E9CD27FFFC",
+"h. c #6E23CD02FFBA",
+"j. c #6E50CFA0FFFF",
+"k. c #7093CC80FFBB",
+"l. c #6E47D0E6FFFF",
+"z. c #7269D1B2FFFF",
+"x. c #73B7D323FFFF",
+"c. c #7383D389FFFF",
+"v. c #7F08D0B1FFA4",
+"b. c #7A4CD5C8FFFF",
+"n. c #7C1BD6A7FFFF",
+"m. c #7CBAD75AFFFF",
+"M. c #8CB9CF6EE5B6",
+"N. c #9678D359E3DC",
+"B. c #8911D5A7F360",
+"V. c #829DD7A7FFFF",
+"C. c #8092DA47FFFF",
+"Z. c #814DDA85FFFF",
+"A. c #839BDA7BFFFF",
+"S. c #85D6DB65FFFF",
+"D. c #86DFDAB4FFFD",
+"F. c #8EE1DDADFC14",
+"G. c #8CC8DC55FFFE",
+"H. c #894DDD3BFFFE",
+"J. c #89CCDDD9FFFF",
+"K. c #8AFCDE12FFFC",
+"L. c #8D41DF48FFF9",
+"P. c #8D5FE05DFFFF",
+"I. c #8FB7E05EFFEA",
+"U. c #9808DD11F202",
+"Y. c #A445E007FF52",
+"T. c #96ADE3E2FFB6",
+"R. c #9705E548FFFF",
+"E. c #9DB5E153FFFD",
+"W. c #9914E507FFB9",
+"Q. c #9A08E660FFF3",
+"!. c #9A40E858FFFF",
+"~. c #A7C7E568F44C",
+"^. c #A7C5E6F4F48B",
+"/. c #A3A6EB6AFFFB",
+"(. c #A652EC53FFFA",
+"). c #A408ED75FFFF",
+"_. c #B2C9E411FFBB",
+"`. c #B047E69AFFFB",
+"'. c #B8E2E8BFFFF5",
+"]. c #D6CBF231FFFF",
+"[. c #DE35F506FFFC",
+"{. c #E029F512FFFF",
+"}. c #E57AF80BFFFE",
+"|. c #E6C5F71DFFE9",
+" X c #E735F794FFF7",
+".X c #E895F7DEFFEE",
+"XX c #E9B0F91EFFFE",
+"oX c gray100",
+"OX c None",
+/* pixels */
+"OXOXOXOXOXOX; 7 6 : OXOXOXOXOXOX",
+"OXOXOXOX> C 5.y.r.*.V w OXOXOXOX",
+"OXOX@ e M ).R.J.m.l.V.u.f & OXOX",
+"OXOXm ^.~.(.W.K.D.`.[.].Y.k OXOX",
+"OX8 U.A N./.T.H.G.}.oXoX{.p.9 OX",
+"OXB !.Z M.Q.I.A.E.XXoXoX|.q.H O ",
+"- %.P.B.F.L.S.n.z.'. X.X_.>.U , ",
+"4 t.C.N $.Z.b.z.g.h.k.v.-...^ 3 ",
+"1 4.c.#.e.x.j.d.w.7.<.;.X.[ F = ",
+"* @.f.i.+.s.a.0.7.1.:.o.{ _ p . ",
+"OXd 9.3.s 2.8.6.,.=.} ! u G h X ",
+"OX# b &.x O.K n | z l / L I 5 OX",
+"OXOXq ~ v a c J .( ) E T y OXOX",
+"OXOXOX0 W Q Y ] ' ` R P r o OXOX",
+"OXOXOXOX< i j t D S g 2 OXOXOXOX",
+"OXOXOXOXOXOX+ % $ OXOXOXOXOXOX"
+};
diff --git a/frontends/gtk/res/netsurf-gtk.desktop b/frontends/gtk/res/netsurf-gtk.desktop
new file mode 100644
index 000000000..4c21d5537
--- /dev/null
+++ b/frontends/gtk/res/netsurf-gtk.desktop
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Name=NetSurf Web Browser
+Name[ca]=Navegador web NetSurf
+Name[cs]=NetSurf Webový prohlížeč
+Name[es]=Navegador web NetSurf
+Name[fa]=مرورگر اینترنتی NetSurf
+Name[fi]=NetSurf-selain
+Name[fr]=Navigateur Web NetSurf
+Name[hu]=NetSurf webböngésző
+Name[it]=NetSurf Browser Web
+Name[ja]=NetSurf ウェブ・ブラウザ
+Name[ko]=NetSurf 웹 브라우저
+Name[nb]=NetSurf Nettleser
+Name[nl]=NetSurf webbrowser
+Name[nn]=NetSurf Nettlesar
+Name[no]=NetSurf Nettleser
+Name[pl]=Przeglądarka WWW NetSurf
+Name[pt]=NetSurf Navegador Web
+Name[pt_BR]=Navegador Web NetSurf
+Name[sk]=Internetový prehliadač NetSurf
+Comment=Browse the World Wide Web
+Comment[ca]=Navegueu per el web
+Comment[cs]=Prohlížení stránek World Wide Webu
+Comment[de]=Im Internet surfen
+Comment[es]=Navegue por la web
+Comment[fa]=صفحات شبکه جهانی اینترنت را مرور نمایید
+Comment[fi]=Selaa Internetin WWW-sivuja
+Comment[fr]=Navigue sur Internet
+Comment[hu]=A világháló böngészése
+Comment[it]=Esplora il web
+Comment[ja]=ウェブを閲覧します
+Comment[ko]=웹을 돌아 다닙니다
+Comment[nb]=Surf på nettet
+Comment[nl]=Verken het internet
+Comment[nn]=Surf på nettet
+Comment[no]=Surf på nettet
+Comment[pl]=Przeglądanie stron WWW
+Comment[pt]=Navegue na Internet
+Comment[pt_BR]=Navegue na Internet
+Comment[sk]=Prehliadanie internetu
+GenericName=Web Browser
+GenericName[ca]=Navegador web
+GenericName[cs]=Webový prohlížeč
+GenericName[es]=Navegador web
+GenericName[fa]=مرورگر اینترنتی
+GenericName[fi]=WWW-selain
+GenericName[fr]=Navigateur Web
+GenericName[hu]=Webböngésző
+GenericName[it]=Browser Web
+GenericName[ja]=ウェブ・ブラウザ
+GenericName[ko]=웹 브라우저
+GenericName[nb]=Nettleser
+GenericName[nl]=Webbrowser
+GenericName[nn]=Nettlesar
+GenericName[no]=Nettleser
+GenericName[pl]=Przeglądarka WWW
+GenericName[pt]=Navegador Web
+GenericName[pt_BR]=Navegador Web
+GenericName[sk]=Internetový prehliadač
+Exec=netsurf-gtk %u
+Terminal=false
+X-MultipleArgs=false
+Type=Application
+Icon=netsurf.png
+Categories=Network;
+MimeType=text/html;text/xml;application/xhtml+xml;application/xml;image/gif;image/jpeg;image/png
+StartupWMClass=NetSurf-bin
+StartupNotify=true
diff --git a/frontends/gtk/res/netsurf.gresource.xml b/frontends/gtk/res/netsurf.gresource.xml
new file mode 100644
index 000000000..c7626b053
--- /dev/null
+++ b/frontends/gtk/res/netsurf.gresource.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/netsurf">
+ <file>cookies.gtk2.ui</file>
+ <file>history.gtk3.ui</file>
+ <file>netsurf.gtk2.ui</file>
+ <file>password.gtk3.ui</file>
+ <file>toolbar.gtk2.ui</file>
+ <file>warning.gtk3.ui</file>
+ <file>cookies.gtk3.ui</file>
+ <file>hotlist.gtk2.ui</file>
+ <file>netsurf.gtk3.ui</file>
+ <file>ssl.gtk2.ui</file>
+ <file>toolbar.gtk3.ui</file>
+ <file>downloads.gtk2.ui</file>
+ <file>hotlist.gtk3.ui</file>
+ <file>options.gtk2.ui</file>
+ <file>ssl.gtk3.ui</file>
+ <file>viewdata.gtk2.ui</file>
+ <file>downloads.gtk3.ui</file>
+ <file>login.gtk2.ui</file>
+ <file>options.gtk3.ui</file>
+ <file>tabcontents.gtk2.ui</file>
+ <file>viewdata.gtk3.ui</file>
+ <file>history.gtk2.ui</file>
+ <file>login.gtk3.ui</file>
+ <file>password.gtk2.ui</file>
+ <file>tabcontents.gtk3.ui</file>
+ <file>warning.gtk2.ui</file>
+ <file preprocess="to-pixdata">favicon.png</file>
+ <file preprocess="to-pixdata">netsurf.xpm</file>
+ <file preprocess="to-pixdata">menu_cursor.png</file>
+ <file preprocess="to-pixdata">throbber/throbber0.png</file>
+ <file preprocess="to-pixdata">throbber/throbber1.png</file>
+ <file preprocess="to-pixdata">throbber/throbber2.png</file>
+ <file preprocess="to-pixdata">throbber/throbber3.png</file>
+ <file preprocess="to-pixdata">throbber/throbber4.png</file>
+ <file preprocess="to-pixdata">throbber/throbber5.png</file>
+ <file preprocess="to-pixdata">throbber/throbber6.png</file>
+ <file preprocess="to-pixdata">throbber/throbber7.png</file>
+ <file preprocess="to-pixdata">throbber/throbber8.png</file>
+ <file>credits.html</file>
+ <file>it/credits.html</file>
+ <file>nl/credits.html</file>
+ <file>licence.html</file>
+ <file>it/licence.html</file>
+ <file>nl/licence.html</file>
+ <file>welcome.html</file>
+ <file>de/welcome.html</file>
+ <file>it/welcome.html</file>
+ <file>ja/welcome.html</file>
+ <file>nl/welcome.html</file>
+ <file>maps.html</file>
+ <file>adblock.css</file>
+ <file>default.css</file>
+ <file>internal.css</file>
+ <file>quirks.css</file>
+ <file>netsurf.png</file>
+ <file>default.ico</file>
+ <file>arrow_down_8x32.png</file>
+ <file>icons/arrow-l.png</file>
+ <file>icons/content.png</file>
+ <file>icons/directory2.png</file>
+ <file>icons/directory.png</file>
+ <file>icons/hotlist-add.png</file>
+ <file>icons/hotlist-rmv.png</file>
+ <file>icons/search.png</file>
+ <file>languages</file>
+ </gresource>
+</gresources>
diff --git a/frontends/gtk/res/netsurf.gtk2.ui b/frontends/gtk/res/netsurf.gtk2.ui
new file mode 100644
index 000000000..68812b364
--- /dev/null
+++ b/frontends/gtk/res/netsurf.gtk2.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0"?>
+<!--Generated with glade3 3.4.5 on Wed Apr 7 17:10:28 2010 -->
+<interface>
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="upper">100</property>
+ <property name="lower">0</property>
+ <property name="page_increment">10</property>
+ <property name="step_increment">26</property>
+ <property name="page_size">10</property>
+ <property name="value">0.5357142857142857</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="upper">100</property>
+ <property name="lower">0</property>
+ <property name="page_increment">10</property>
+ <property name="step_increment">26</property>
+ <property name="page_size">10</property>
+ <property name="value">0</property>
+ </object>
+ <object class="GtkUIManager" id="uimanager1">
+ <ui>
+ <menubar name="menubar"/>
+ </ui>
+ </object>
+ <object class="GtkWindow" id="wndBrowser">
+ <property name="title" translatable="yes">NetSurf</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <child>
+ <object class="GtkVBox" id="vbox14">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuBar" constructor="uimanager1" id="menubar">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="searchbar">
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ <child>
+ <object class="GtkToolButton" id="closeSearchButton">
+ <property name="visible">True</property>
+ <property name="stock_id">gtk-close</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="searchLabelItem">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="searchlabel">
+ <property name="visible">True</property>
+ <property name="xpad">4</property>
+ <property name="label" translatable="yes">Match</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="toolSearch">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkEntry" id="searchEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="searchBackButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Search _Back</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-back</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="searchForwardButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Search _Forward</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-forward</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="checkAllSearchItem">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkCheckButton" id="checkAllSearch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip-text" translatable="yes">show all matches</property>
+ <property name="label" translatable="yes">All </property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="caseSensItem">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkCheckButton" id="caseSensButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip-text" translatable="yes">Match case when searching</property>
+ <property name="label" translatable="yes">Case</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <property name="scrollable">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/netsurf.gtk3.ui b/frontends/gtk/res/netsurf.gtk3.ui
new file mode 100644
index 000000000..ce47c6370
--- /dev/null
+++ b/frontends/gtk/res/netsurf.gtk3.ui
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkWindow" id="wndBrowser">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="toolbar_style">both</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="searchbar">
+ <property name="can_focus">False</property>
+ <property name="toolbar_style">both</property>
+ <child>
+ <object class="GtkToolButton" id="closeSearchButton">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">gtk-close</property>
+ <property name="stock_id">gtk-close</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="searchLabelItem">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <child>
+ <object class="GtkLabel" id="searchlabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xpad">4</property>
+ <property name="label" translatable="yes">Match</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="toolSearch">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <child>
+ <object class="GtkEntry" id="searchEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="searchBackButton">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Search _Back</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-back</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="searchForwardButton">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="label" translatable="yes">Search _Forward</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-forward</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="checkAllSearchItem">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <child>
+ <object class="GtkCheckButton" id="checkAllSearch">
+ <property name="label" translatable="yes">All</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="caseSensItem">
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_action_appearance">False</property>
+ <child>
+ <object class="GtkCheckButton" id="caseSensButton">
+ <property name="label" translatable="yes">Case</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <property name="scrollable">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child type="tab">
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/frontends/gtk/res/netsurf.png b/frontends/gtk/res/netsurf.png
new file mode 120000
index 000000000..905512c25
--- /dev/null
+++ b/frontends/gtk/res/netsurf.png
@@ -0,0 +1 @@
+../../../!NetSurf/Resources/netsurf.png,b60 \ No newline at end of file
diff --git a/frontends/gtk/res/netsurf.xpm b/frontends/gtk/res/netsurf.xpm
new file mode 100644
index 000000000..7061727d6
--- /dev/null
+++ b/frontends/gtk/res/netsurf.xpm
@@ -0,0 +1,317 @@
+/* XPM */
+static char *netsurf[] = {
+/* columns rows colors chars-per-pixel */
+"132 135 176 2",
+" c black",
+". c #010101",
+"X c #010202",
+"o c #030406",
+"O c #040A0D",
+"+ c #060E14",
+"@ c #08141A",
+"# c #081720",
+"$ c #091B27",
+"% c #0F2430",
+"& c #142E3D",
+"* c #143548",
+"= c #153C53",
+"- c #194662",
+"; c #1E516E",
+": c #1D577A",
+"> c #175B87",
+", c #1A6595",
+"< c #1E6B9C",
+"1 c #26709C",
+"2 c #33789E",
+"3 c #3188BD",
+"4 c #3E89B3",
+"5 c #1F92DD",
+"6 c #0E9CFD",
+"7 c #0E9DFF",
+"8 c #0F9EFF",
+"9 c #1A95E7",
+"0 c #1898ED",
+"q c #1299F4",
+"w c #119BF9",
+"e c #119FFF",
+"r c #14A0FF",
+"t c #15A1FF",
+"y c #17A2FF",
+"u c #18A3FF",
+"i c #1AA3FE",
+"p c #1BA4FE",
+"a c #1CA5FE",
+"s c #1EA5FE",
+"d c #1FA6FE",
+"f c #268AC9",
+"g c #218ED3",
+"h c #20A6FE",
+"j c #21A7FE",
+"k c #23A8FE",
+"l c #24A8FE",
+"z c #25A8FE",
+"x c #26A9FE",
+"c c #27AAFE",
+"v c #28AAFE",
+"b c #2AABFF",
+"n c #2BACFF",
+"m c #2CADFF",
+"M c #2EAEFF",
+"N c #2FAEFF",
+"B c #31AFFE",
+"V c #31AFFF",
+"C c #32B0FF",
+"Z c #34B1FF",
+"A c #35B2FF",
+"S c #36B2FF",
+"D c #37B2FF",
+"F c #3AB2FB",
+"G c #38B3FE",
+"H c #39B3FE",
+"J c #3AB3FC",
+"K c #3BB4FE",
+"L c #3CB5FE",
+"P c #3DB5FE",
+"I c #3EB6FF",
+"U c #3FB7FF",
+"Y c #4182A4",
+"T c #4789AB",
+"R c #43B7FB",
+"E c #40B7FF",
+"W c #44B6FA",
+"Q c #42B8FE",
+"! c #44B9FE",
+"~ c #46BAFF",
+"^ c #47BAFF",
+"/ c #48BBFF",
+"( c #49BCFF",
+") c #4ABCFF",
+"_ c #4CBDFF",
+"` c #4EBEFF",
+"' c #50BFFE",
+"] c #50BFFF",
+"[ c #51BFFF",
+"{ c #5ABFF7",
+"} c #52C0FE",
+"| c #54C1FE",
+" . c #56C2FF",
+".. c #57C3FF",
+"X. c #58C3FE",
+"o. c #58C3FF",
+"O. c #5CC1F8",
+"+. c #5DC4FD",
+"@. c #5CC5FE",
+"#. c #5DC5FE",
+"$. c #5DC6FF",
+"%. c #5EC6FF",
+"&. c #5FC7FF",
+"*. c #61C8FF",
+"=. c #62C8FF",
+"-. c #63C9FF",
+";. c #65CAFF",
+":. c #66CBFF",
+">. c #67CBFF",
+",. c #68CCFF",
+"<. c #69CDFF",
+"1. c #6BCDFF",
+"2. c #6CCEFF",
+"3. c #6DCEFF",
+"4. c #6FCFFF",
+"5. c #70D0FF",
+"6. c #72D1FF",
+"7. c #73D1FF",
+"8. c #74D2FF",
+"9. c #76D3FF",
+"0. c #77D3FF",
+"q. c #78D4FF",
+"w. c #79D5FF",
+"e. c #7AD5FF",
+"r. c #7CD6FF",
+"t. c #7ED7FF",
+"y. c #7FD8FF",
+"u. c #81CBE7",
+"i. c #82CBE7",
+"p. c #83CEEB",
+"a. c #81D4F7",
+"s. c #84D3F4",
+"d. c #80D7FE",
+"f. c #80D8FF",
+"g. c #84DAFF",
+"h. c #85DAFF",
+"j. c #86DBFF",
+"k. c #87DBFF",
+"l. c #89DCFF",
+"z. c #8ADDFF",
+"x. c #8BDEFF",
+"c. c #8DDEFF",
+"v. c #8EDEFF",
+"b. c #8FDFFF",
+"n. c #91E0FF",
+"m. c #92E1FF",
+"M. c #93E2FF",
+"N. c #95E3FF",
+"B. c #97E3FF",
+"V. c #98E4FF",
+"C. c #99E4FE",
+"Z. c #9BE5FE",
+"A. c #9CE6FE",
+"S. c #9EE6FF",
+"D. c #9FE7FF",
+"F. c #A1E8FF",
+"G. c #A3E9FF",
+"H. c #A5EBFF",
+"J. c #A6ECFF",
+"K. c #A8EDFF",
+"L. c #ABEEFF",
+"P. c #ADEFFF",
+"I. c #B0F0FF",
+"U. c #B3F1FF",
+"Y. c #B7F2FF",
+"T. c #C7F3FF",
+"R. c #DCF6FF",
+"E. c #EAF8FF",
+"W. c #F1FAFF",
+"Q. c #F8FCFF",
+"!. c #FCFEFF",
+"~. c #FDFEFF",
+"^. c #FEFEFF",
+"/. c #FEFFFF",
+"(. c gray100",
+"). c None",
+/* pixels */
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O & ; 2 T O.O.a.r.e.e.e.q.9.9.4.{ { T 2 ; % O ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). @ - T r.l.k.k.k.y.t.t.t.t.r.e.e.q.9.8.8.8.8.4.4.1.1.1.{ T ; # ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). = Y p.v.x.x.s.v.k.k.k.a.g.t.y.t.r.e.e.q.9.8.8.8.2.4.4.4.4.,.,.;.;.;.O.4 = o ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % 2 u.m.m.v.v.c.x.x.l.k.k.k.k.g.t.y.t.t.r.e.e.q.9.8.8.8.8.4.4.1.1.,.,.;.;.-.-.-.{ 2 & ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O ; u.B.m.m.m.m.m.v.c.c.x.x.x.k.k.k.g.g.g.t.t.r.e.e.q.9.9.8.8.2.2.8.2.1.1.,.,.;.;.-.*.*.$.$.! : + ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O : p.C.C.B.B.B.m.m.m.m.c.c.c.c.x.k.l.k.k.g.y.g.t.t.r.e.e.q.q.8.9.2.2.4.2.1.1.1.,.;.;.-.-.-.&.$.$.+.O.2 @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).). + 2 s.A.A.C.C.C.B.m.N.m.M.m.m.m.c.l.x.x.l.k.k.g.g.t.f.t.r.r.e.q.9.9.8.8.8.8.8.1.2.,.,.,.;.-.-.&.&.&.$.+... .| 2 @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).). = p.F.F.A.A.A.C.C.C.C.N.N.m.m.m.m.v.v.c.x.l.l.g.k.g.t.f.f.t.r.e.e.q.9.8.8.8.2.8.2.2.1.,.,.,.;.-.&.-.&.+.+....... .` 1 O ).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).). ; A.F.F.A.A.A.A.C.C.C.N.N.N.m.m.m.v.c.x.x.l.k.k.g.g.f.f.t.r.e.e.q.9.q.8.8.8.2.2.2.1.,.,.;.;.-.-.&.&.$.+.$..... .| | W = ).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).). o T F.F.F.A.F.S.A.A.C.C.C.N.M.M.m.m.c.c.c.x.l.k.k.g.g.f.f.f.t.t.e.e.q.9.9.8.5.5.4.1.1.1.;.,.-.-.-.-.$.*.$.+.o. . . .| | ` T # ).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).). * & p.F.F.F.A.F.F.A.A.A.C.C.N.N.M.M.m.m.c.c.x.x.k.k.k.g.h.f.f.t.r.r.e.q.9.9.8.5.5.4.4.4.1.1.;.,.;.-.-.&.$.$.+. . . . .| | ` ` W ; ).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).). 2 A. % J.J.F.J.F.F.S.F.F.A.A.C.C.C.N.M.m.m.c.c.c.x.x.l.k.k.f.t.t.t.t.r.e.q.0.9.9.8.5.4.4.1.1.,.,.;.-.-.&.-.$.$.$.o.+... .| | ` ) ) ) 2 O ).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).). @ u.J.T ; J.J.J.F.J.F.F.F.A.A.D.C.N.C.N.M.M.m.m.m.x.x.x.l.k.k.k.k.f.f.t.r.r.q.0.9.5.5.5.5.4.4.1.,.,.;.;.-.-.&.$.$.+.o. ... .| | ` | [ ) ( 5 $ ).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).). & p.K.K.: T J.J.J.J.F.G.F.F.F.F.A.A.N.C.C.N.M.m.m.c.c.c.x.x.l.k.g.g.t.t.t.r.r.q.0.0.9.8.5.5.4.3.1.,.,.,.;.-.-.&.h.k.+.$.o. . . .| ` ` ` | ( ( W - ).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).). = F.K.P.K.& p.K.J.J.J.J.F.F.F.A.F.D.A.A.C.C.N.M.M.m.m.c.c.x.l.l.k.k.g.g.g.t.r.r.r.e.0.9.9.5.5.4.4.1.1.,.;.,.-.-.,.Q./.8.o.o.o. .[ ` | | ` ) ) ( ( ( ; ).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).). ; J.K.P.P.F. % K.P.K.J.J.J.G.G.G.F.A.D.A.A.C.C.N.N.M.m.m.m.v.x.x.l.k.g.g.t.y.t.t.r.q.0.0.9.7.9.5.4.4.2.1.,.,.;.;.-.F././.T.$.o.o. . .| ) ` ) ) ) ( ( ! ! , ).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).). : K.K.P.P.P.u. ; P.K.P.K.K.J.J.J.G.F.F.D.D.D.C.C.N.N.M.m.m.c.v.c.x.l.k.k.g.k.y.t.r.r.r.0.0.9.9.5.5.4.4.2.1.,.;.,.;.,.W./././.l.o. . . . .| | ` ) ) ( ( ^ ! Q 1 ).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).). Y K.K.P.P.P.I.Y T P.P.P.K.K.J.J.J.F.G.F.D.D.A.A.N.N.N.N.M.m.m.c.c.c.x.l.k.g.g.y.t.t.t.r.w.q.q.8.7.5.5.4.2.1.,.,.;.;.F././././.E.+. . . .| | ) ` ) ) ) ( / ! ! W 2 ).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).). 2 K.P.P.P.P.P.I.P.u.T ; % i.I.I.P.P.P.K.J.J.J.G.F.D.D.D.A.C.C.N.N.m.m.m.c.c.x.l.l.g.k.g.y.t.t.r.r.w.q.8.8.7.5.5.5.2.1.,.,.;.;.E./././././.P. . . .| | | ) ) ` ( 1.K.0.! E Q 1 ).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).). ; J.K.P.P.P.I.I.U.U.U.U.U.U.U.I.I.P.P.P.K.J.J.J.G.G.D.D.D.A.D.C.C.N.N.m.N.c.c.x.l.l.g.k.g.y.g.t.r.r.r.q.q.8.7.5.5.5.2.2.,.,.;.C./././././././.4.o.o.| | ) | $.C.R././.U.! ! U L > ).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).). * F.J.K.K.P.I.I.U.U.U.U.U.U.U.U.U.I.I.P.K.K.J.J.J.G.G.D.D.D.D.C.N.C.N.m.m.m.c.c.x.x.l.k.k.k.y.t.t.r.r.q.q.8.8.9.5.5.5.2.2.,.,.;.E./././././././.T.o.[ | .v.T./.!././.!.k.! E Q L L - ).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).). & C.J.K.K.P.P.I.I.U.U.U.Y.Y.Y.U.U.U.I.I.P.P.P.K.J.G.J.F.D.D.D.A.C.C.N.N.M.m.m.m.c.x.l.l.k.k.g.y.y.y.r.r.r.M.R.U.C.9.5.5.2.2.1.,.v.!././././././././.k.d.T././././././././.+.! ! E E L G * ).).).).).).).).).).).).).",
+").).).).).).).).).).).).). + p.J.J.K.P.P.P.I.I.U.U.Y.Y.Y.Y.Y.U.U.U.I.P.P.K.K.J.J.J.F.F.D.D.A.D.N.C.N.M.m.m.c.c.x.x.l.z.g.g.y.g.y.r.r.r.L./.!././.R.U.m.2.1.>.R./././././././././././././././././././.W.! ! E E E L L F $ ).).).).).).).).).).).).",
+").).).).).).).).).).).).). T G.J.J.K.K.P.P.I.I.U.U.Y.Y.Y.Y.Y.U.U.I.I.P.P.P.K.J.J.J.G.F.D.D.A.D.C.C.N.M.m.M.c.c.x.x.l.k.k.g.y.t.y.t.r.q.r.!./././././././.R.T././././././././././././././././././././.Y.! ! ! E L L L K g o ).).).).).).).).).).).).",
+").).).).).).).).).).).). ; J.G.J.J.K.K.P.P.I.I.U.U.U.Y.Y.Y.U.U.U.I.I.P.P.P.K.J.G.J.G.F.D.D.D.C.N.C.N.M.m.M.c.c.x.l.l.k.g.g.y.t.y.r.r.r.q.T.!././././././././.!././././././././././././././././././.Q.v.! ! E E E L L K G , ).).).).).).).).).).).",
+").).).).).).).).).).). & A.J.F.J.J.J.J.L.P.P.I.U.U.U.U.U.U.U.U.U.I.I.P.P.P.K.J.J.F.F.F.D.D.A.A.N.C.N.M.m.m.c.c.x.l.l.k.k.h.f.f.f.r.r.r.0.A.^././././././././././././././././././././././././././././.*.! ! E E E L L L G D * ).).).).).).).).).).",
+").).).).).).).).).).). O u.A.F.F.J.J.J.K.K.P.P.I.I.U.U.U.U.U.U.U.I.I.P.P.K.K.J.J.J.F.J.D.D.D.A.A.C.N.N.M.m.m.m.c.x.x.l.k.k.f.f.f.r.r.r.0.0.0.Q./././././././././././././././././././././././././././.W.! ! ! E E L L L P G D B @ ).).).).).).).).).).",
+").).).).).).).).).). Y F.D.F.J.J.J.J.K.L.P.P.P.I.I.I.U.U.U.U.I.I.I.P.P.K.K.J.J.J.G.F.D.D.D.A.C.C.C.N.m.m.m.c.c.x.l.l.k.k.h.f.f.r.r.r.e.0.9.T.^././././././././././././././././././././././././././.T./ ! ! ! E E L L G G D D 1 ).).).).).).).).).",
+").).).).).).).).).). $ N.D.D.F.F.G.J.J.K.K.L.L.P.P.I.I.I.I.I.I.I.I.P.P.P.K.J.J.J.G.G.F.D.D.A.D.C.N.N.M.N.m.m.c.c.x.x.l.k.f.h.f.f.f.r.e.e.e.9.n.^./././././././././././././././././././././././././.Q.K.! ! ! E E L L L G D D B V & ).).).).).).).).).",
+").).).).).).).).). T A.F.D.D.F.F.J.J.J.J.K.L.L.T : T i.J.I.I.P.P.P.K.K.K.J.J.G.G.G.F.D.D.A.C.C.N.N.M.m.m.m.v.v.l.x.k.k.g.g.t.f.f.r.e.e.e.9.9.W./././././././././././././././././././././././././.^.^.R.g.W E E P P P G G D D V g ).).).).).).).).",
+").).).).).).).).). ; C.A.A.D.D.F.F.F.J.J.J.K.K.L.& K.P.P.P.P.K.K.J.J.J.F.G.F.A.D.D.A.C.C.C.N.M.m.m.c.c.x.x.k.k.k.g.f.f.f.r.r.e.0.0.9.8.Y./././././././././././././././././././././././././././././.E.v.W P P G G G D V V N - ).).).).).).).).",
+").).).).).).).). o u.C.C.A.D.D.F.F.F.J.G.J.J.J.K.+ % P.K.K.P.K.K.K.J.J.G.F.F.F.F.D.A.D.C.C.N.M.M.m.m.m.l.x.x.l.k.k.g.f.f.f.r.r.e.9.9.9.8.h./././././././././././././././././././././././././././././././.W.n.^ P G G D D V V b + ).).).).).).).",
+").).).).).).).). ; B.C.C.A.A.D.D.D.F.F.G.J.G.K.A. = K.K.K.K.J.J.K.G.J.G.G.F.F.A.A.A.C.C.N.N.M.m.m.c.v.v.x.l.l.k.k.k.f.f.r.r.r.e.0.9.8.8.B.^./././././././././././././././././././././././././././././././.!.Q.F./ G D V V V N : ).).).).).).).",
+").).).).).).). p.B.N.C.C.D.A.D.D.F.F.G.G.G.J.r. ; J.J.J.J.J.J.J.F.G.G.F.F.S.F.A.C.C.C.N.N.M.m.N.c.x.x.z.z.z.g.g.g.g.t.t.r.r.q.0.0.h.R./././././././././././././././././././././././././././././././././././.Q./.2.A C C V N 0 O ).).).).).).",
+").).).).).).). ; N.N.N.N.C.C.D.D.D.D.F.F.G.G.K.i. 2 J.J.G.J.J.J.G.G.F.F.F.A.A.A.A.C.C.N.N.N.M.m.m.c.c.x.z.z.g.k.g.t.y.y.t.r.r.q.0.Y./././././././././././././././././././././././././././././././././././././.Q.E.&.A C C N N m ; ).).).).).).",
+").).).).).). r.m.B.B.N.C.C.A.A.D.D.D.F.F.G.G.Y X Y J.G.J.J.G.G.G.F.F.S.F.S.A.A.C.C.C.N.M.M.m.M.c.c.x.x.z.k.k.g.g.g.t.t.r.r.q.D.W././././././././././././././././././././././././././././././././././././.^./.G.U A A C C V N m 9 o ).).).).).",
+").).).).).). = n.m.m.m.N.C.C.C.A.A.D.D.A.F.G.G.Y X T G.G.G.F.G.F.F.F.A.F.S.A.A.A.C.C.N.N.M.m.m.c.c.c.x.z.z.k.g.g.g.t.t.t.r.k.R././././././././././././././././././././././././././././././././././././././.T.o.G K A C C V V N m N - ).).).).).",
+").).).).).). X X T n.n.n.n.N.N.C.C.C.A.A.A.F.A.F.A.: u.F.F.F.F.F.A.F.A.A.F.A.A.C.C.N.C.N.M.M.m.m.c.c.x.x.x.k.k.k.g.f.f.t.t.N./.!./././././././././././././././././././././././././././././././././././.Q.W.r.P G G A A D V V V N m b f ).).).).).",
+").).).).). X @ s.n.n.C.n.m.B.N.N.C.C.A.A.Z.F.S.F.; u.F.F.F.F.A.F.F.F.A.A.A.C.C.C.C.N.m.M.m.M.c.c.c.x.l.l.k.k.g.g.f.f.t.r.m.W././././././././././././././././././././././././././././././././././.^.^.G./ L P P G A A D V V N m m b b # ).).).).",
+").).).).). - n.b.M.n.n.m.m.B.m.C.B.C.C.A.A.A.F.= B.A.F.F.A.A.F.A.A.A.C.C.B.C.B.N.M.M.m.m.c.c.c.x.l.l.k.k.g.g.g.f.f.t.r.e.e.J.E././././././././././././././././././././././././././././././././.^.*.E E L L P G A A V V V N m N N b : ).).).).",
+").).).).). e.b.b.s.n.n.m.m.m.B.B.B.C.C.C.C.A.A.* F.F.A.A.A.A.A.A.C.C.B.C.C.m.B.M.M.m.m.c.m.c.x.x.x.l.k.k.g.t.t.f.t.e.e.e.e.9.9.A.R././././././././././././././././././././././././././././././.Q.r.E L L L P G K A A V N N m b b b g ).).).).",
+").).).). % x.l.x.c.c.c.M.m.m.M.M.N.N.C.C.C.C.C.C.D.D.A.A.A.A.A.A.C.A.C.C.C.N.C.N.N.M.M.M.m.m.c.m.l.c.x.x.k.k.k.g.g.g.t.t.t.r.e.e.q.9.8.8.8.m.R./././././././././././././././././././././././././././././.T.Q L L L K K D V V C V N m m b c c % ).).).",
+").).).). 2 l.x.x.x.c.c.c.m.m.m.M.M.N.N.N.C.N.C.N.C.C.C.C.C.C.C.C.C.C.C.C.C.C.N.N.M.m.m.m.m.m.c.v.v.c.l.k.k.k.g.g.y.y.t.t.r.e.e.q.9.9.8.8.4.2.4.l.T././././././././././././././././././././././././././././.) E L J A A D V C V N N m m b c c > ).).).",
+").).).). T k.k.x.x.x.c.c.c.m.m.m.M.M.M.N.N.N.N.C.C.C.C.C.N.C.C.N.C.N.C.N.N.N.M.M.M.m.m.m.c.m.c.c.x.x.l.k.k.k.g.y.g.t.t.r.e.e.e.q.9.8.8.2.8.4.4.1.1.J.!./././././././././././././././././././././././././.!.N.L L L J D A A C V N m m m b c c f ).).).",
+").).).). O a.k.k.l.l.x.x.c.c.c.m.m.m.m.M.N.m.N.N.N.N.N.N.B.B.N.C.N.N.N.N.M.M.M.M.m.m.m.m.c.v.v.l.x.l.l.k.k.g.g.g.y.y.t.t.r.e.e.q.8.8.8.8.8.2.4.1.1.,.T./././././././././././././././././././././././././././.R.L L L A D A C C V N m b b b c c k + ).).",
+").).). * g.k.g.k.l.x.l.x.c.c.c.c.m.m.m.m.m.m.M.M.M.M.M.N.N.N.m.B.M.M.M.M.M.m.m.m.m.c.c.c.x.x.x.x.l.k.k.k.g.g.g.f.t.t.r.r.e.q.9.9.8.8.8.2.4.4.4.1.,.W././././././././././././././././././././././././././././.;.K K A D A V V V N N b m b c c k * ).).",
+").).). 2 k.g.k.k.k.l.l.l.x.x.c.c.m.v.m.m.m.m.m.m.M.M.M.M.M.m.m.m.m.m.m.m.M.m.m.c.m.c.c.c.x.x.x.l.k.k.k.g.k.t.y.t.t.r.r.e.e.q.9.8.8.8.2.8.4.1.1.1.e././././././././././././././././././././././././././././.W.P.K A G D A V V V N m m b c c c k > ).).",
+").).). O.t.g.g.k.k.k.l.l.x.x.x.c.c.v.c.c.m.m.m.m.m.M.M.m.m.m.m.m.m.m.m.m.c.m.c.c.c.c.x.x.l.x.k.k.k.k.g.g.t.f.t.t.t.e.e.e.q.9.9.8.8.4.2.4.4.1.1.;.A.!./././././././././././././././././././.Q././././././././.Q.U K A A A V V V m m m b c c k k g ).).",
+").).). X a.f.t.t.g.g.k.k.k.l.x.l.x.l.v.v.c.c.c.c.m.c.c.M.m.m.m.m.m.c.m.c.c.c.c.c.c.x.x.x.x.l.k.g.k.g.g.g.t.g.t.t.r.r.e.e.q.q.9.8.8.8.4.4.4.1.4.;.1.T././././././././././././././././././././.C.U.W./.W././././.Q.g.K A A V V V N m b b b c c k k k o ).).",
+").).). $ d.f.f.f.f.h.h.k.k.k.k.l.x.z.x.x.x.x.x.c.c.c.c.c.c.c.c.m.c.c.c.c.c.c.x.x.x.x.x.k.l.k.k.k.g.g.g.g.t.y.t.r.e.e.e.q.9.9.8.8.8.8.2.8.1.1.,.,.,.W./././././././././.W.^./././././././.^.T./ ! ! *.C.T./.Q.E.!.T.D A A V V V N b N v v c c k k j $ ).).",
+").). = r.r.f.f.f.f.h.f.k.k.k.k.z.k.z.z.z.x.x.x.x.c.c.c.v.v.v.v.c.c.c.x.x.x.l.x.x.k.k.k.k.k.g.g.k.t.t.y.t.t.r.r.e.q.q.q.9.8.8.8.4.2.8.2.4.1.,.,.9./././././././.E.K.1.8.^./././././././.^.9./ / ! ! ! L Q 8.F.R.R.A A A V V N b N v N v c j k j j * ).",
+").). : r.r.t.t.f.f.f.f.g.g.k.k.k.k.x.k.l.x.x.l.x.x.x.x.x.x.l.x.x.x.x.l.l.x.l.l.z.k.g.k.k.g.g.g.g.t.t.t.r.r.r.r.q.q.9.q.8.8.8.4.2.2.2.2.1.,.,.,.A./././.!.Q.U.w.$. .o. .P./././././././.R./ / ! ! E E E U K K K J D V C C V N b b b v v c j k j d ; ).",
+").). Y e.r.r.t.t.f.f.f.t.g.g.g.k.g.k.k.k.l.l.l.Y ; ; = & s.x.l.l.l.l.l.l.l.k.k.g.k.k.g.g.k.t.t.y.y.t.t.r.r.r.w.q.q.8.8.8.8.8.2.4.8.1.1.,.,.,.;.T././.T.x.&.&.+.+. .o. .+.W././././././.d.! / W ! ! E L U K K A D D C V V V N N b b v c c j k j d , ).",
+").). T e.e.e.e.r.r.t.f.t.g.t.k.g.g.g.k.k.k.k.g.; r.l.l.l.h.k.k.k.k.k.k.k.g.g.g.t.y.y.g.t.t.r.r.r.r.q.q.q.8.8.8.8.4.2.8.4.4.1.,.>.1.;.;.9.A.;.*.&.$.$.$.o.o. . .[ k./././././.E.( / ! ! ! ! L E L L K K A A C C V N N m v v v v j c j d d f ).",
+").). { q.e.e.e.r.r.t.r.t.t.t.g.t.g.g.g.g.g.k.k.; i.h.h.k.k.k.k.k.g.g.g.g.g.g.y.t.g.y.t.t.r.r.w.w.w.q.q.q.8.8.8.4.4.4.4.4.1.1.,.1.>.;.;.*.*.*.*.$.$.+...o. . . . .[ T././././.v./ / ! ! E E E L K K K A A C C V V N m b N v v c z j j d d g ).",
+").). { 9.9.e.e.e.r.r.r.t.t.y.y.y.g.t.t.g.k.g.k.2 T h.h.h.h.f.k.g.g.g.t.t.y.g.t.t.t.t.r.r.r.r.w.q.q.q.8.8.8.8.8.2.4.4.1.1.1.,.,.;.;.;.-.-.*.$.$.+.+.+.o. . . . .[ [ ;./././.Q.) / / ! Q ! L L L U K K A A A C V V m m m v v c c j c j d d 9 ).",
+").). 5.8.9.9.q.e.e.e.r.r.r.t.t.y.y.t.g.t.t.t.t.T Y h.h.f.k.f.f.t.t.y.g.y.y.t.t.t.r.r.r.r.w.q.q.q.8.q.8.8.8.2.2.8.4.4.1.1.,.,.1.;.;.-.-.*.*.*.$.+.+.+.o. . . .[ [ [ [ K.!.!.B./ ! ! ! Q E E E L K A K A A V C V N m m b v c c z j j d d d 0 ).",
+").). 8.8.8.9.8.q.q.q.e.e.r.r.r.r.t.r.f.f.f.f.f.{ ; f.f.f.f.f.f.f.f.t.f.t.t.r.r.r.e.e.e.e.q.q.9.q.8.8.8.8.2.5.5.4.4.1.1.,.,.,.,.-.-.-.-.&.&.$.$.+....... . .| | ) | ) | E.!.[ / / ! Q Q E L L L K A K A A V V V N m b m v c c k k j d d p p ).",
+").). O 8.8.8.8.8.9.9.q.q.e.e.e.e.r.r.r.r.t.t.t.t.u. = f.f.f.t.f.f.t.t.t.t.r.r.r.e.e.e.e.q.q.9.9.8.8.8.8.8.8.8.2.2.1.1.1.,.,.;.;.;.-.-.&.-.&.$.$.$.+. ..... .| | | | ) ) ( ;.-.! ! ! ! Q E L E L L K A A C C V N N m m b b c c c k j d d d i i O ).",
+").). @ 2.4.8.8.8.8.9.9.9.q.q.e.e.e.e.e.r.r.r.r.r.r.O % t.t.t.t.r.r.r.r.r.r.r.e.e.e.e.q.q.9.9.9.8.8.8.8.8.2.2.2.5.2.1.1.,.,.;.,.;.-.-.-.&.&.$.$.$.+...+. . .| ` | ` ` | ) ) ( / / ! ! Q Q E E L L L A K A A C V V N m m m b c c k k j j d p p y + ).",
+").). @ 4.4.4.8.8.8.8.8.8.9.q.q.q.e.e.e.e.e.e.r.r.r.% + r.r.r.r.r.e.r.e.e.e.e.e.q.q.e.9.9.9.8.8.8.8.8.2.8.2.2.8.2.2.1.,.1.;.,.;.-.-.-.&.&.$.$.+.$. ... . . .| | ` ` ) ` ) ) / ( ! ! ! Q E L L L L G K A C C C V V N m b b c c c k k j d d p p i @ ).",
+").). O 4.4.4.2.8.8.8.8.8.8.9.9.9.9.q.q.q.e.e.e.e.e.* r.e.e.e.e.e.e.e.q.q.q.q.9.9.9.9.8.8.9.8.8.8.2.2.8.2.2.2.2.2.,.,.,.;.-.-.-.&.&.&.$.$.+.+..... . . .| | | | ) ) ` ( ( ( ! ! ! W E E E L L P G K A C C V N N m b m b c c k k d d d d p p y O ).",
+").). 4.1.4.8.2.2.8.8.8.8.8.8.8.9.8.9.9.q.q.q.q.e.: Y e.q.e.q.q.e.e.q.q.9.9.9.8.8.8.8.8.8.2.4.2.2.8.2.4.2.2.:.:.,.,.,.;.-.-.-.-.&.&.$.+.+....... . . .| [ ) | [ ) ) ( ( / / ! Q Q E L L L P G G A C C C V N m m b b c c c k k k d d p p y y ).",
+").). O.1.4.4.4.2.8.2.8.8.8.8.8.8.8.8.9.9.9.9.9.9.T O * : Y O.e.9.9.9.9.9.9.9.9.8.8.8.9.8.8.8.4.2.8.2.8.2.2.4.1.:.2.:.:.;.,.-.-.-.-.&.&.&.$.+.+......... .| | | ) | | ) ` ) ( ( ! ! ! Q E L L L P G G G A A C V V N m b m b c c k k k d d d p p p q ).",
+").). { 1.1.1.4.2.8.2.8.2.2.4.8.8.8.8.8.8.8.8.8.9.9.9.9.e.q.q.q.9.9.9.8.8.8.8.8.8.8.8.8.8.8.2.4.4.8.2.2.2.1.1.1.2.:.:.;.-.;.-.-.-.&.&.$.$.$.+...+... ... .| ) [ | ) ) ) ) ( ( ! ! ! ! Q E E P P G G D D C C C V N m m m b c c c k k d d d p p y 9 9 ).",
+").). { ,.,.1.1.2.2.2.2.2.8.2.8.2.8.8.2.9.8.8.8.8.8.8.8.9.9.9.6.9.6.6.9.8.8.8.8.2.8.8.2.4.4.8.2.2.2.2.2.2.,.,.,.,.;.;.;.;.;.;.&.&.&.$.$.$.$...........| | | ` | ) ) ) ) ( ^ ^ ! Q Q Q Q L E L L K A A V V V V V N m b b v c c c j j d d d i p w $ % ).",
+").). T ,.,.,.1.1.2.2.2.4.4.4.8.2.8.2.8.2.8.8.8.8.2.8.8.7.7.6.9.7.7.6.6.8.8.4.4.8.2.2.8.4.4.2.2.2.2.4.1.,.,.,.,.;.;.;.;.-.;.&.&.&.$.$.+.+...........| | ` | ` ` ` ` ( ( ( ( ^ ! ! Q Q L L L L L K A A D V V V V m m m b v c z j j j d d p p y = ).",
+").). Y ,.;.,.,.,.1.1.2.1.1.4.2.4.4.2.8.8.2.2.8.2.2.8.2.7.7.3.3.3.7.3.6.8.2.8.2.4.4.4.2.1.1.4.1.1.1.,.,.,.,.;.;.;.;.&.;.&.&.&.&.&.$.+.+......... .| | | | ` ` ` ) ( ( ( ^ ^ ! ! Q Q Q L L L G G K A V D V V V N N b b b c c j z j j d d p i - ).",
+").). : -.,.;.,.,.,.,.,.1.1.1.1.1.1.4.4.2.8.2.2.8.4.4.4.3.3.3.7.3.3.7.3.2.8.2.2.4.1.1.1.1.1.1.,.,.,.,.,.;.,.;.;.;.;.;.&.-.&.&.$.$.$.+. .......| | | | ` ` | ` ( ` ( ( ( ^ Q Q Q Q U U L L L G G A A A V V V N b b b b c c c c j j d d p p : ).",
+").). = -.;.;.,.,.,.,.,.,.,.,.,.1.1.4.1.2.2.2.2.2.8.2.2.4.4.4.4.7.3.6.3.2.2.2.2.2.1.1.1.,.,.,.,.,.;.,.-.;.;.-.;.;.&.&.&.&.&.$.$.$.+...+... . .| | | ` ` ` ` ` ` ( ( ^ ^ ! ! Q Q Q L U L P P D D D V V V V N m m b b c c z z j j d d d p - ).",
+").).). % -.-.-.;.-.-.,.,.,.,.,.,.,.,.1.1.2.2.2.2.2.2.2.2.2.2.2.1.1.1.3.1.2.1.1.1.1.,.,.,.,.,.,.;.;.,.;.;.-.;.-.&.&.;.&.&.$.$.$.+......... . .| | | ` ` | ` _ _ ( ( ^ ^ ^ ! Q Q Q L U L L P G D D D V V V V N m m m b c c z j c j d d i = ).).",
+").).). o $.&.-.-.-.-.;.;.,.-.,.,.,.,.,.,.,.,.2.:.2.,.:.2.1.1.1.1.,.1.1.,.,.,.,.,.,.,.,.,.,.-.,.,.;.-.-.-.;.&.-.&.&.&.$.$.$.+.+......... . .| | ` ` | ) ` _ _ ( ( ( ^ ^ Q Q Q U U U L K K G G D D V V V V N m m b b c c c z j j d d 0 & O o ).).",
+").).). g -.&.-.-.-.-.-.;.;.-.,.-.,.;.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.;.,.,.-.,.,.;.;.-.-.-.-.-.-.&.&.&.&.$.$.$.$.$....... . . .| | | ` | ) | ) ` ( ( ^ ^ ^ ! Q Q Q U L L K K K G D D B V V V V m m m b b c c k j j d d d - O , ).).",
+").).). 2 $.*.*.*.*.*.;.;.-.-.;.;.;.;.;.,.;.;.,.,.;.,.,.,.,.,.;.;.1.;.;.,.;.;.,.;.;.;.;.;.;.&.;.&.&.&.&.&.&.&.$.$.+.+.$........... .| | | [ [ | ) ) ) ) ) ) / / / ! ! E Q U U U K K K A A A C C V V N N N n N v c c c k c j d d p 0 $ + g , ).).",
+").).). * $.$.$.$.*.*.*.-.&.-.-.-.-.;.;.;.;.;.;.;.;.;.;.,.;.T : # 2 ;.;.;.;.;.;.-.-.-.-.&.;.&.;.&.;.&.&.&.&.$.+.+.+.| ........| .| | | | ) ) [ [ ) ( ( ) ( ! / ! ! E ! U U K K K K K A A A C C V N N m v n v v c c j k j d d p p i g O # 5 e = ).).",
+").).). + $.$.$.$.$.$.*.&.-.-.&.&.;.-.;.;.;.;.&.;.;.;.;.O.O $ -.-.-.-.-.-.-.-.-.&.&.;.&.&.&.&.&.$.$.$.+.$...+...........| | ` ` ` | | ) [ ) ) ) ( ( / ! ! ! Q ! E U L L L K A K A A V C V V N N b N v v v c j k j j d d p i y y < * 0 y e O ).).",
+").).).). T $.$.$.$.$.$.&.&.&.&.&.-.&.&.&.&.&.;.&.;.;.;.-.$ T -.-.-.-.&.&.-.&.-.&.&.&.$.$.$.$.$.+.+........... ...| | | | | ` | ) | ) ) ) ) ( ( / ! ! ! Q Q E L U L L K A K A A A C V V N m b N N v c c c j k j d d d i i y y y y e 8 g ).).).",
+").).).). > o.$.$.+.$.$.$.$.$.$.&.&.&.&.&.;.&.&.;.&.&.&.-.2 - -.&.-.&.&.&.&.&.$.$.$.$.$.$.+.+.+.| ............ .| | ) | ` | ` ) [ ) ) ) ( / ( ! ! ! ! Q Q Q L L L L K K K A A C V C V V N b b b v v c c k k j j d p p i y y y y y e e > ).).).",
+").).).). & o.o.o.o.$.+.+.$.$.$.$.$.$.&.$.&.$.$.&.&.&.&.$.{ o O.&.&.&.$.$.$.$.$.$.+.$.+.+.............| ....| | | | | | | ) | ) ) ) ) ) / ( ! ! ! Q Q Q E L E L L K A J A A A C C V N N b N b b v c z > 5 j d d p d p y y y y e e e 8 & ).).).",
+").).).).). W .o.o. .o...+.$.+.+.+.+.$.$.$.$.$.$.$.&.$.$.$.= 2 &.$.$.$.$.+.$.+.+.$.+.............| ....| | | | ) | | ` ) | ( ) ) ) / ( / ! ! ! Q Q Q L L L L L K K K A A C C C V V N m N b v c c , @ = j d d d i i i y y e y e e 5 ).).).",
+").).).).). : . . .o. ...........$.+.+.$.$.+.$.$.$.+.$.$.$.4 % $.+.+.+.+.$................. . .....| | ` | ` ` | ) ) | ) ` ) ( ( / / ! / ! ! Q Q Q Q L E L L L K A A A A C C V V N m m v v c > + g d d i i i y y y e e e 8 > ).).).).",
+").).).).). # | . . . . . .....+. ......... .$.+.$.+.$.+.+.+.@ 4 ....+...............| ...... .| | | | ` } } ` ) | ) ) ) ) ) / / / / ! ! ! Q Q Q L Q L K K K A K D V C C C V V N m m m 5 ; + * d p i y i i y y e e 8 8 $ ).).).).",
+").).).).).). 4 .| | . . . . .........+. .+............... .: * ..............| ......| | | | | | ` ` } ` ` _ ) ) ) ) ( ( ( / / ! ! ! Q Q Q E L L L L K K A K D D A V C V V N m m 3 = $ 0 p i i y e e e e e 8 g ).).).).).",
+").).).).).). - | | | | | | . . . . . .| .......... . ..... .W o 4 .. . . . . ...| | | | | ` ` ` ` ` } ` ` _ _ ) ) ) ) / / ( ! ! ! ! E W E E L L L L L L K A D A A V C N V N m m b % @ , i p i y y i y e e 8 8 8 - ).).).).).",
+").).).).).). W | ) [ [ | | | | | | . . . . . . . .| ... . .; O : R . . .| | | | | ` | ` | ` | | ` ` ` _ _ _ _ ) ( ( ( / / ! ! ! ! E ! E L E E L L L G A D D D A C C V N N m m b m , $ < d d p i y y y e i e e 8 7 9 O ).).).).).",
+").).).).).).). + 4 ) | | [ [ | | | | | | | | | | | | | | | | | W + : W | .| | | | | | | | ` | | ` ` _ ` ` _ _ _ ( _ ( ( ( ( ! / ! ! ! E ! E E L L L L L L G G G D D V V V V V N m m m b b 0 & < d d d p i y y y y e y e e 8 7 : ).).).).).).",
+").).).).).).). % 2 ( [ ) | ) | ) | | ` | | | | [ | | ` | | .) | | | | ) | ) | | ) ` ` ` ` ` ` ` _ _ _ _ _ _ _ ^ ^ ( / ! ! ! ! Q Q E E E E E L L G P G G G D B 1 3 C V V N m m b m b c c * o - g k d d d p p y y y y e e e 8 8 8 q O ).).).).).).",
+").).).).).).).). + ; 4 | | ) | ` ` ` ) | ) | [ | ) | ` | | [ | ) ) | | | ) | ) | ` ` ` _ _ _ _ _ ( _ ^ _ ^ ^ ^ ^ ! ! ! ! Q Q Q Q E E L L L L P G G G 3 : % * V V N m m m b b b c c 5 0 k k d d d p p i y y y y e e e 8 8 8 > ).).).).).).).",
+").).).).).).).). $ : W ` ` ` | ` ` | | ) ` | ` | ) | ) [ | | ) ) | ) | ) ) _ _ _ _ _ _ _ ( ( ( ^ ^ ^ ^ ^ ! ! ! ! Q Q E E L E L L L P 5 1 ; & o + N N m m m b b c c c k k k k d d d p p i i y i y e e e 8 8 8 w + ).).).).).).).",
+").).).).).).).).). o W ) ) [ ) [ [ ) ) | ) [ ) | [ ) | | ) | [ ) ) ) ) [ ) ) ) ( ( ) ( / / ^ ( ^ ^ ^ ! ^ Q Q Q Q Q Q L L U L K U K , f b N v n v c c c k k k k d d d d i i i y y y e e e e e 8 8 : ).).).).).).).",
+").).).).).).).).). * ( ) ) [ ) ) ) ) [ ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ( ( ) ) ) ( / / / / / ^ ^ ^ Q ! ! Q Q Q G U L L U L L L K K A f > N v N v c c c k k k k d d d p i i y y y y y e e e 8 7 8 5 o ).).).).).).).).",
+").).).).).).).).).). O 1 ( ( ( ( ) ) ) ) ) ) W $ % - ; 1 1 2 f f f W ( ( / / ( / / / ! / 5 f 1 1 > - - % % # : L Q L L K K K K K K V X # - < v b v n v v z z k k d d d d p p i y y y e y e e e 8 7 7 8 * ).).).).).).).).",
+").).).).).).).).).). > : % F / / / / / / / ( ) ) g P / / / ( / / ! / ! ! - - L L L L K J K A A A A % X # = < 5 N N b N b v c c c c j k k d d d p p i i y y i y e e e 8 7 7 7 < ).).).).).).).).).",
+").).).).).).).).).).). O G ! F ! / ! / ! / / ( ( ( ( 3 W / / ! ! ! ! ! ! ! ! ; % L L L K A A A D V A C < > 3 v V N b b N b b v v c c c z j z k d d d p p i y y y e e e e 8 8 7 7 8 q # ).).).).).).).).).).",
+").).).).).).).).).).). & ! ! ! ! ! ! ! ! / ! / ! ! , W ! 2 # 3 ! ! Q Q ! E ; + L G A K K D A D A V C V V V N N b N N b b b v c c c j z j j d d d p p i y y i y e y e e 8 7 7 7 8 - ).).).).).).).).).).",
+").).).).).).).).).).).). : ! Q Q Q ! ! ! ! ! ! ! ! 2 % @ g & @ G ! Q E E E ; % % - F G A A A A A C V V V V V N m N N b N v v c c c j j j j j d d d p p p y y y y e e e e 8 7 7 7 7 , ).).).).).).).).).).).",
+").).).).).).).).).).).).). 3 E Q Q Q Q ! Q Q Q Q Q ! Q Q Q G f 2 1 1 : - - O = E Q L L E 2 : 1 1 f f 9 L J A G G D D A A A C V V V V V N N m m b b b v v c c z z j c j j d j d p p p y y y y e y e e 8 8 7 7 7 g O ).).).).).).).).).).).",
+").).).).).).).).).).).).). + F E L E L Q E E E E ! Q Q Q Q Q Q Q Q Q U Q U 1 1 L L L L L L L K K K K A K K D D A D D V V V V V V N N m m m b m b b b c c c c j j j j d d p p p i y y y e e i e e e 7 7 7 7 w $ ).).).).).).).).).).).).",
+").).).).).).).).).).).).).). & F E E E L L E E L E L U L L Q L L L L L L U U * + G L L L L L K K K D K A A A V D A V V V V V V N N b m m m b b b c c c c k k j j j j j p d i p y y y y y y e e e 7 7 7 7 7 7 - ).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).). * G L L L E L E L L E L U U L Q L L Q U L L L J + * L L K K A A K D D A A A C D V V V V V V V N b N b b m b b b c c c c k k k d j d d p p p i y y y y y e e e e 8 7 7 8 8 8 > ).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).). - L L L L L L L L L L L L K L L L L L L K U K 1 < A K A K A A V D A A C C V V V V V N N N N b b N b b b b c c c k k k k d d d d d d p i i y y y y e y e e 8 7 7 7 8 8 , ).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).). : K K K K L G L P K K K K K K K L L K K K K K = o g D A A A D A A V V V C V V N N N m m m N b N v v v c c c c k k k d k d d d p p i i y i y y y e y e 8 8 7 7 7 7 7 < ).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).). , G G G G G G G K K K D K A K A K D A D A K N @ $ V V D V V V V A V V V V N N m m m b m v N v v v v z c j k k k k d d d d d p p y i y i y e e y e e 8 7 7 7 8 8 f o ).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).). : G D D D G D A A K A D D A K A K D D A A A 3 > D V V V V V V V V N N N m N m m b m b v v v v c c c j j c j j d d d d p p i y y y i e e e e e 8 8 7 7 7 7 7 < o ).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).). - V D V D D A A A A V D A V D V D V A C A C : + 3 V V V V V V V V N N N b m m b m b b b c v c c z c j j j j j d d d d p i p p y y y y i e y 8 e e 8 8 7 7 7 7 , ).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).). = B D V D A C A A A C A V C C C C C C C C V ; 5 N V N V V N N N b b N N v m b m b v c c c c z c z j j j j d d d d d i p p y y y y i y e e e 8 8 7 7 7 8 8 8 > ).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).). & N V V C V V C C V C V C C C V V V V V V V V N N N N N m N b N b b b N b b b c c c c c z j j j c j j d d d d i p p y p y y y y e e e e e 8 7 7 7 7 7 8 - ).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).). + 3 V V V V V V V V V V V V V N V N N N N N m b N N b m b b b N b v v c c c c c c k k j c j j j j d d d p p i i y y y y y e y e e e 8 8 8 7 7 7 7 9 % ).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).). > N N N N V N N N N N N N N m m m m m m m m b b b m b b b b c c c c k c c k k k k j j j j d d d p p p i i i y y y y e y e e e 8 8 7 7 7 7 7 < + ).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).). * 0 N m b N N b m m m m m m N m m b m b b N v b b b c c c c c c c k k k k k d k d d d d p j p p i y y y y i e i e y e e e 8 7 7 7 7 7 7 : ).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).). O , m b b b N b m m b m b b b b m b b v v v v c c c c c c j k k k k k k d d d d d d d p p p i i y y y e i e e e 8 e 8 8 7 7 7 7 7 f $ ).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).). % g b b b m b m b b b b b b c c c c c c c c c c k g k k k k k d k d d d d p d i p i i i i y y y i e y e e e 8 8 7 7 7 7 7 q - ).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).). X ; c v b b c c c b c c c c c c c c c k k k d = o f j k k d d d d d d p i i i i i y y y y i e e e e e e e 8 8 8 7 7 7 , + ).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).). O : 0 c c c c c c c c c c k k k k k k 0 & + 5 d d d p d d d p i i y y y y y y e y e e e e e 8 8 7 7 8 8 8 , $ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). O ; 0 c z j j c k k k k k k k k d @ # 9 d d p p i p i y i y y y y y e y y e e e 8 e 7 7 7 8 7 , $ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). o - f j k k k k d d j k d d d : % 0 i p p y y i y y y y y y e y e e e e 8 8 7 7 7 9 > # ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). $ > 9 k d d k d d d d d d = % w y p y y y y y e e y e y e e e 8 8 8 7 w < * ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). & > g d d d d p d p i & * w y y y y y y e y e e e e 8 8 8 0 < - O ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). + = , 5 i p p i 6 % * w y e e e e e 8 e e 8 q < : % ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). % = : < f # = y e y g f < , - & @ ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). o ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).). ).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).",
+").).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).).)."
+};
diff --git a/frontends/gtk/res/nl/credits.html b/frontends/gtk/res/nl/credits.html
new file mode 120000
index 000000000..9c983987a
--- /dev/null
+++ b/frontends/gtk/res/nl/credits.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/nl/credits.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/nl/licence.html b/frontends/gtk/res/nl/licence.html
new file mode 120000
index 000000000..8a10d2073
--- /dev/null
+++ b/frontends/gtk/res/nl/licence.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/nl/licence.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/nl/welcome.html b/frontends/gtk/res/nl/welcome.html
new file mode 120000
index 000000000..6b2ba7742
--- /dev/null
+++ b/frontends/gtk/res/nl/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/nl/welcome.html,faf \ No newline at end of file
diff --git a/frontends/gtk/res/options.gtk2.ui b/frontends/gtk/res/options.gtk2.ui
new file mode 100644
index 000000000..d5542ba5d
--- /dev/null
+++ b/frontends/gtk/res/options.gtk2.ui
@@ -0,0 +1,3004 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="dialogPreferences">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">preferencesTitle</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <signal name="destroy" handler="nsgtk_preferences_dialogPreferences_destroy" swapped="no"/>
+ <signal name="delete-event" handler="nsgtk_preferences_dialogPreferences_deleteevent" swapped="no"/>
+ <signal name="response" handler="nsgtk_preferences_dialogPreferences_response" swapped="no"/>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="vbox_dialog">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">edge</property>
+ <child>
+ <object class="GtkButton" id="help">
+ <property name="label">gtk-help</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="close">
+ <property name="label">gtk-close</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkNotebook" id="notebook1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox_main">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="frame_main_startup">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label_startup_page">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesStartupPage</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryHomePageURL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="changed" handler="nsgtk_preferences_entryHomePageURL_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_entryHomePageURL_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkButton" id="setDefaultPage">
+ <property name="label" translatable="yes">preferencesStartupPageDefault</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="nsgtk_preferences_setDefaultPage_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="setCurrentPage">
+ <property name="label" translatable="yes">preferencesStartupPageCurrent</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="nsgtk_preferences_setCurrentPage_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label_main_startup">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesStartup</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_main_search">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkUrlSearch">
+ <property name="label" translatable="yes">preferencesSearchURLBar</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkUrlSearch_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkUrlSearch_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesSearchProvider</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboSearch">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_search_provider</property>
+ <signal name="changed" handler="nsgtk_preferences_comboSearch_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboSearch_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesSearch</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_main_downloads">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkClearDownloads">
+ <property name="label" translatable="yes">preferencesDownloadsRemove</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkClearDownloads_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkClearDownloads_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkRequestOverwrite">
+ <property name="label" translatable="yes">preferencesDownloadsConfirm</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkRequestOverwrite_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkRequestOverwrite_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesDownloadsLocation</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserButton" id="fileChooserDownloads">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="action">select-folder</property>
+ <signal name="selection-changed" handler="nsgtk_preferences_fileChooserDownloads_selectionchanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_fileChooserDownloads_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesDownloads</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesMainTabtitle</property>
+ </object>
+ <packing>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox_appearance">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="frame_appearance_tabs">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkShowSingleTab">
+ <property name="label" translatable="yes">preferencesTabsAlways</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkShowSingleTab_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkShowSingleTab_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkFocusNew">
+ <property name="label" translatable="yes">preferencesTabsSwitch</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkFocusNew_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkFocusNew_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkNewBlank">
+ <property name="label" translatable="yes">preferencesTabsNewly</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkNewBlank_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkNewBlank_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesTabsPosition</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboTabPosition">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_tab_position</property>
+ <signal name="changed" handler="nsgtk_preferences_comboTabPosition_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboTabPosition_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesTabs</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_appearance_tools">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesDeveloperView</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboboxDeveloperView">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_developer_view</property>
+ <signal name="changed" handler="nsgtk_preferences_comboDeveloperView_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboDeveloperView_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext10"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesTools</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_appearance_url">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkDisplayRecentURLs">
+ <property name="label" translatable="yes">preferencesURLbarDisplay</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkDisplayRecentURLs_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkDisplayRecentURLs_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesURLbar</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">7</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_appearance_toolbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesToolbarButtons</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboButtonType">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_toolbar_buttontype</property>
+ <signal name="changed" handler="nsgtk_preferences_comboButtonType_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboButtonType_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext3"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesToolbar</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesAppearanceTabtitle</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox_content">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="frame_content_control">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkDisablePopups">
+ <property name="label" translatable="yes">preferencesControlPrevent</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkDisablePopups_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkDisablePopups_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkHideAdverts">
+ <property name="label" translatable="yes">preferencesControlHide</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkHideAdverts_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkHideAdverts_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkEnableJavascript">
+ <property name="label" translatable="yes">preferencesControlEnable</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkEnableJavascript_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkEnableJavascript_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkDisablePlugins">
+ <property name="label" translatable="yes">preferencesControlDisable</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkDisablePlugins_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkDisablePlugins_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkResampleImages">
+ <property name="label" translatable="yes">preferencesControlHigh</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkResampleImages_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkResampleImages_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesControlLoad</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboboxLoadImages">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_image_loading</property>
+ <signal name="changed" handler="nsgtk_preferences_comboboxLoadImages_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboboxLoadImages_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext4"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesControl</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_content_animation">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkEnableAnimations">
+ <property name="label" translatable="yes">preferencesAnimationEnable</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkEnableAnimations_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkEnableAnimations_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesAnimationMinimum</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinAnimationSpeed">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesAnimationMinimumTooltip</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_animation_time</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">if-valid</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinAnimationSpeed_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinAnimationSpeed_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label18">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesAnimation</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_content_fonts">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label26">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesFontsDefault</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboDefault">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">liststore_defaultfont</property>
+ <signal name="changed" handler="nsgtk_preferences_comboDefault_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboDefault_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext5"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label27">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesFontsSize</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinDefaultSize">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesFontsSizeTooltip</property>
+ <property name="max_length">4</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">4</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_font_default_size</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">1</property>
+ <property name="numeric">True</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinDefaultSize_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinDefaultSize_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="fontPreview">
+ <property name="label" translatable="yes">preferencesFontsPreview</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="image">image1</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="nsgtk_preferences_fontPreview_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label20">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesFonts</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_content_font">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label21">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesLanguagePreferred</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboboxLanguage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesLanguagePreferredTooltip</property>
+ <property name="model">liststore_content_language</property>
+ <signal name="changed" handler="nsgtk_preferences_comboboxLanguage_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboboxLanguage_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext7">
+ <property name="xalign">0</property>
+ </object>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext8">
+ <property name="xalign">1</property>
+ </object>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesLanguage</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesContentTabtitle</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox_privacy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="frame_privacy_general">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment20">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkSendReferer">
+ <property name="label" translatable="yes">preferencesGeneralReferral</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkSendReferer_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkSendReferer_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="checkSendDNT">
+ <property name="label" translatable="yes">preferencesGeneralDNT</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkSendDNT_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkSendDNT_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label61">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesGeneral</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_privacy_history">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkHoverURLs">
+ <property name="label" translatable="yes">preferencesHistoryShow</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="nsgtk_preferences_checkHoverURLs_toggled" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_checkHoverURLs_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox14">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label28">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesHistoryRemember</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinHistoryAge">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">4</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">4</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_history_age</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">if-valid</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinHistoryAge_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinHistoryAge_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesHistoryDays</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesHistory</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame_privacy_cache">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment13">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox12">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label30">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesCacheMemory</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label31">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesCacheDisc</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label34">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesCacheExpire</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinMemoryCacheSize">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">5</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_cache_memory_size</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinMemoryCacheSize_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinMemoryCacheSize_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinDiscCacheSize">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">5</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_cache_disc_size</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinDiscCacheSize_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinDiscCacheSize_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinDiscCacheAge">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">3</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_disc_cache_age</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinDiscCacheAge_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinDiscCacheAge_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">MB</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">MB</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label35">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesHistoryDays</property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox17">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkButton" id="buttonCacheMaintenance">
+ <property name="label" translatable="yes">preferencesCacheMaintenance</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label24">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesCache</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child type="tab">
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">preferencesPrivacyTabtitle</property>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox_network">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkFrame" id="frame_network_proxy">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label42">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesProxyType</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label43">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesProxyHost</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label44">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesProxyUsername</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label45">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesProxyPassword</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="comboProxyType">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyTypeTooltip</property>
+ <property name="model">liststore_proxy_type</property>
+ <signal name="changed" handler="nsgtk_preferences_comboProxyType_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_comboProxyType_realize" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext6"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox19">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="entryProxyHost">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyHostTooltip</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="changed" handler="nsgtk_preferences_entryProxyHost_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_entryProxyHost_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label46">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label">:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spinProxyPort">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyPortTooltip</property>
+ <property name="max_length">5</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">5</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment_proxy_port</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">if-valid</property>
+ <signal name="value-changed" handler="nsgtk_preferences_spinProxyPort_valuechanged" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_spinProxyPort_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryProxyUser">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyUsernameTooltip</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="changed" handler="nsgtk_preferences_entryProxyUser_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_entryProxyUser_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryProxyPassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyPasswordTooltip</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">●</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <signal name="changed" handler="nsgtk_preferences_entryProxyPassword_changed" swapped="no"/>
+ <signal name="realize" handler="nsgtk_preferences_entryProxyPassword_realize" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">preferencesProxyNoproxy</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="entryProxyNoproxy">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_tooltip">True</property>
+ <property name="tooltip_text" translatable="yes">preferencesProxyNoproxyTooltip</property>
+ <property name="caps_lock_warning">False</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</p