summaryrefslogtreecommitdiff
path: root/frontends/gtk/toolbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/gtk/toolbar.c')
-rw-r--r--frontends/gtk/toolbar.c4564
1 files changed, 3479 insertions, 1085 deletions
diff --git a/frontends/gtk/toolbar.c b/frontends/gtk/toolbar.c
index e93bd49f9..6ec41cc1d 100644
--- a/frontends/gtk/toolbar.c
+++ b/frontends/gtk/toolbar.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,18 +16,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/**
+ * \file
+ * implementation of toolbar to control browsing context
+ */
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include <gtk/gtk.h>
-#include "netsurf/browser_window.h"
-#include "desktop/searchweb.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsoption.h"
#include "utils/file.h"
+#include "utils/nsurl.h"
+#include "utils/corestrings.h"
+#include "desktop/browser_history.h"
+#include "desktop/searchweb.h"
+#include "desktop/search.h"
+#include "desktop/save_complete.h"
+#include "desktop/save_text.h"
+#include "desktop/print.h"
+#include "desktop/hotlist.h"
+#include "netsurf/content.h"
+#include "netsurf/browser_window.h"
+#include "netsurf/keypress.h"
+#include "gtk/toolbar_items.h"
+#include "gtk/completion.h"
#include "gtk/gui.h"
#include "gtk/warn.h"
#include "gtk/search.h"
@@ -36,63 +54,203 @@
#include "gtk/window.h"
#include "gtk/compat.h"
#include "gtk/resources.h"
+#include "gtk/schedule.h"
+#include "gtk/local_history.h"
+#include "gtk/global_history.h"
+#include "gtk/viewsource.h"
+#include "gtk/download.h"
+#include "gtk/viewdata.h"
+#include "gtk/tabs.h"
+#include "gtk/print.h"
+#include "gtk/layout_pango.h"
+#include "gtk/preferences.h"
+#include "gtk/hotlist.h"
+#include "gtk/cookies.h"
+#include "gtk/about.h"
+#include "gtk/gdk.h"
+#include "gtk/bitmap.h"
+#include "gtk/page_info.h"
#include "gtk/toolbar.h"
-static GtkTargetEntry entry = {(char *)"nsgtk_button_data",
- GTK_TARGET_SAME_APP, 0};
-
-static bool edit_mode = false;
-
-struct nsgtk_toolbar_custom_store {
- GtkWidget *window;
- GtkWidget *store_buttons[PLACEHOLDER_BUTTON];
- GtkWidget *widgetvbox;
- GtkWidget *currentbar;
- char numberh; /* current horizontal location while adding */
- GtkBuilder *builder; /* button widgets to store */
- int buttonlocations[PLACEHOLDER_BUTTON];
- int currentbutton;
- bool fromstore;
-};
-/* the number of buttons that fit in the width of the store window */
-#define NSGTK_STORE_WIDTH 6
+/**
+ * button location indicating button is not to be shown
+ */
+#define INACTIVE_LOCATION (-1)
-/* the 'standard' width of a button that makes sufficient of its label
-visible */
-#define NSGTK_BUTTON_WIDTH 111
+/**
+ * time (in ms) between throbber animation frame updates
+ */
+#define THROBBER_FRAME_TIME (100)
-/* the 'standard' height of a button that fits as many toolbars as
-possible into the store */
+/**
+ * the minimum number of columns in the tool store
+ */
+#define NSGTK_MIN_STORE_COLUMNS 4
+
+/**
+ * the 'standard' width of a button that makes sufficient of its label visible
+ */
+#define NSGTK_BUTTON_WIDTH 120
+
+/**
+ * the 'standard' height of a button that fits as many toolbars as
+ * possible into the store
+ */
#define NSGTK_BUTTON_HEIGHT 70
-/* the 'normal' width of the websearch bar */
+/**
+ * the 'normal' width of the websearch bar
+ */
#define NSGTK_WEBSEARCH_WIDTH 150
-static struct nsgtk_toolbar_custom_store store;
-static struct nsgtk_toolbar_custom_store *window = &store;
+/**
+ * toolbar item context
+ */
+struct nsgtk_toolbar_item {
+
+ /**
+ * GTK widget in the toolbar
+ */
+ GtkToolItem *button;
+
+ /**
+ * location index in toolbar
+ */
+ int location;
+
+ /**
+ * if the item is currently sensitive in the toolbar
+ */
+ bool sensitivity;
+
+ /**
+ * textural name used in serialising items
+ */
+ const char *name;
+
+ /**
+ * button clicked on toolbar handler
+ */
+ gboolean (*clicked)(GtkWidget *widget, gpointer data);
+
+ /**
+ * handler when dragging from customisation toolbox to toolbar
+ */
+ void *dataplus;
+
+ /**
+ * handler when dragging from toolbar to customisation toolbox
+ */
+ void *dataminus;
+};
+/**
+ * Location focus state machine
+ *
+ * 1. If we don't care, we're in LFS_IDLE
+ * 2. When we create a new toolbar, we can put it into
+ * LFS_WANT which means that we want the url bar to focus
+ * 3. When we start throbbing if we're in LFS_WANT we move to LFS_THROB
+ * 4. When we stop throbbing, if we're in LFS_THROB we move to LFS_LAST
+ *
+ * While not in LFS_IDLE, if the url bar is updated and we previously had it
+ * fully selected then we reselect it all. If we're in LFS_LAST we move to
+ * LFS_IDLE at that point.
+ */
+typedef enum {
+ LFS_IDLE, /**< Nothing to do */
+ LFS_WANT, /**< Want focus, will apply */
+ LFS_THROB, /**< Want focus, we have started throbbing */
+ LFS_LAST, /**< Last chance for a focus update */
+} nsgtk_toolbar_location_focus_state;
-enum image_sets {
- IMAGE_SET_MAIN_MENU = 0,
- IMAGE_SET_RCLICK_MENU,
- IMAGE_SET_POPUP_MENU,
- IMAGE_SET_BUTTONS,
- IMAGE_SET_COUNT
+/**
+ * control toolbar context
+ */
+struct nsgtk_toolbar {
+ /** gtk toolbar widget */
+ GtkToolbar *widget;
+
+ /* toolbar size allocation context */
+ int offset;
+ int toolbarmem;
+ int toolbarbase;
+ int historybase;
+
+ /**
+ * Toolbar item contexts
+ */
+ struct nsgtk_toolbar_item items[PLACEHOLDER_BUTTON];
+
+ /**
+ * Current frame of throbber animation
+ */
+ int throb_frame;
+
+ /**
+ * Web search widget
+ */
+ GtkWidget *webSearchEntry;
+
+ /**
+ * callback to obtain a browser window for navigation
+ */
+ struct browser_window *(*get_bw)(void *ctx);
+
+ /**
+ * context passed to get_bw function
+ */
+ void *get_ctx;
+
+ /**
+ * Location focus state machine, current state
+ */
+ nsgtk_toolbar_location_focus_state loc_focus;
};
-typedef enum search_buttons {
- SEARCH_BACK_BUTTON = 0,
- SEARCH_FORWARD_BUTTON,
- SEARCH_CLOSE_BUTTON,
- SEARCH_BUTTONS_COUNT
-} nsgtk_search_buttons;
-
-struct nsgtk_theme {
- GtkImage *image[PLACEHOLDER_BUTTON];
- GtkImage *searchimage[SEARCH_BUTTONS_COUNT];
- /* apng throbber element */
+
+/**
+ * toolbar cusomisation context
+ */
+struct nsgtk_toolbar_customisation {
+ /**
+ * first entry is a toolbar widget so a customisation widget
+ * can be cast to toolbar and back.
+ */
+ struct nsgtk_toolbar toolbar;
+
+ /**
+ * The top level container (tabBox)
+ */
+ GtkWidget *container;
+
+ /**
+ * The vertical box into which the available tools are shown
+ */
+ GtkBox *toolbox;
+
+ /**
+ * widget handles for items in the customisation toolbox area
+ */
+ GtkToolItem *items[PLACEHOLDER_BUTTON];
+
+ /**
+ * which item is being dragged
+ */
+ int dragitem; /* currentbutton */
+ /**
+ * true if item being dragged onto toolbar, false if from toolbar
+ */
+ bool dragfrom; /*fromstore */
+
};
+
+/* forward declaration */
+static nserror toolbar_item_create(nsgtk_toolbar_button id,
+ struct nsgtk_toolbar_item *item_out);
+
+
/**
* returns a string without its underscores
*
@@ -122,1372 +280,3608 @@ static char *remove_underscores(const char *s, bool replacespace)
/**
- * get default image for buttons / menu items from gtk stock items.
- *
- * \param tbbutton button reference
- * \param iconsize The size of icons to select.
- * \param usedef Use the default image if not found.
- * \return default images.
- */
-static GtkImage *
-nsgtk_theme_image_default(nsgtk_toolbar_button tbbutton,
- GtkIconSize iconsize,
- bool usedef)
-{
- GtkImage *image; /* The GTK image to return */
-
- switch(tbbutton) {
-
-#define BUTTON_IMAGE(p, q) \
- case p##_BUTTON: \
- image = GTK_IMAGE(nsgtk_image_new_from_stock(q, iconsize)); \
- break
-
- BUTTON_IMAGE(BACK, NSGTK_STOCK_GO_BACK);
- BUTTON_IMAGE(FORWARD, NSGTK_STOCK_GO_FORWARD);
- BUTTON_IMAGE(STOP, NSGTK_STOCK_STOP);
- BUTTON_IMAGE(RELOAD, NSGTK_STOCK_REFRESH);
- BUTTON_IMAGE(HOME, NSGTK_STOCK_HOME);
- BUTTON_IMAGE(NEWWINDOW, "gtk-new");
- BUTTON_IMAGE(NEWTAB, "gtk-new");
- BUTTON_IMAGE(OPENFILE, NSGTK_STOCK_OPEN);
- BUTTON_IMAGE(CLOSETAB, NSGTK_STOCK_CLOSE);
- BUTTON_IMAGE(CLOSEWINDOW, NSGTK_STOCK_CLOSE);
- BUTTON_IMAGE(SAVEPAGE, NSGTK_STOCK_SAVE_AS);
- BUTTON_IMAGE(PRINTPREVIEW, "gtk-print-preview");
- BUTTON_IMAGE(PRINT, "gtk-print");
- BUTTON_IMAGE(QUIT, "gtk-quit");
- BUTTON_IMAGE(CUT, "gtk-cut");
- BUTTON_IMAGE(COPY, "gtk-copy");
- BUTTON_IMAGE(PASTE, "gtk-paste");
- BUTTON_IMAGE(DELETE, "gtk-delete");
- BUTTON_IMAGE(SELECTALL, "gtk-select-all");
- BUTTON_IMAGE(FIND, NSGTK_STOCK_FIND);
- BUTTON_IMAGE(PREFERENCES, "gtk-preferences");
- BUTTON_IMAGE(ZOOMPLUS, "gtk-zoom-in");
- BUTTON_IMAGE(ZOOMMINUS, "gtk-zoom-out");
- BUTTON_IMAGE(ZOOMNORMAL, "gtk-zoom-100");
- BUTTON_IMAGE(FULLSCREEN, "gtk-fullscreen");
- BUTTON_IMAGE(VIEWSOURCE, "gtk-index");
- BUTTON_IMAGE(CONTENTS, "gtk-help");
- BUTTON_IMAGE(ABOUT, "gtk-about");
-#undef BUTTON_IMAGE
+ * create throbber toolbar item widget
+ *
+ * create a gtk entry widget with a completion attached
+ */
+static GtkToolItem *
+make_toolbar_item_throbber(bool sensitivity, bool edit)
+{
+ nserror res;
+ GtkToolItem *item;
+ GdkPixbuf *pixbuf;
+ GtkWidget *image;
- case HISTORY_BUTTON:
- image = GTK_IMAGE(gtk_image_new_from_pixbuf(arrow_down_pixbuf));
- break;
+ res = nsgtk_throbber_get_frame(0, &pixbuf);
+ if (res != NSERROR_OK) {
+ return NULL;
+ }
- default:
- image = NULL;
- break;
+ if (edit) {
+ const char *msg;
+ msg = messages_get("ToolThrob");
+ item = gtk_tool_button_new(
+ GTK_WIDGET(gtk_image_new_from_pixbuf(pixbuf)),
+ msg);
+ } else {
+ item = gtk_tool_item_new();
+
+ image = gtk_image_new_from_pixbuf(pixbuf);
+ if (image != NULL) {
+ nsgtk_widget_set_alignment(image,
+ GTK_ALIGN_CENTER,
+ GTK_ALIGN_CENTER);
+ nsgtk_widget_set_margins(image, 3, 0);
+
+ gtk_container_add(GTK_CONTAINER(item), image);
+ }
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity);
+
+ return item;
+}
+
+
+/**
+ * create url bar toolbar item widget
+ *
+ * create a gtk entry widget with a completion attached
+ *
+ * \param sensitivity if the entry should be created sensitive to input
+ * \param edit if the entry should be editable
+ */
+static GtkToolItem *
+make_toolbar_item_url_bar(bool sensitivity, bool edit)
+{
+ GtkToolItem *item;
+ GtkWidget *entry;
+ GtkEntryCompletion *completion;
+
+ entry = nsgtk_entry_new();
+ if (entry == NULL) {
+ return NULL;
}
+ nsgtk_entry_set_icon_from_icon_name(entry,
+ GTK_ENTRY_ICON_PRIMARY,
+ "page-info-internal");
+
+ if (edit) {
+ gtk_entry_set_width_chars(GTK_ENTRY(entry), 9);
+
+ item = gtk_tool_button_new(NULL, "URL");
+ gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), entry);
+ } else {
+ completion = gtk_entry_completion_new();
+ if (completion != NULL) {
+ gtk_entry_set_completion(GTK_ENTRY(entry), completion);
+ }
+
+ item = gtk_tool_item_new();
+ if (item == NULL) {
+ return NULL;
+ }
+
+ gtk_container_add(GTK_CONTAINER(item), entry);
+ gtk_tool_item_set_expand(item, TRUE);
- if (usedef && (image == NULL)) {
- image = GTK_IMAGE(nsgtk_image_new_from_stock("gtk-missing-image", iconsize));
}
+ gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(entry), sensitivity);
- return image;
+ return item;
}
+
/**
- * Get default image for search buttons / menu items from gtk stock items
+ * create web search toolbar item widget
+ */
+static GtkToolItem *
+make_toolbar_item_websearch(bool sensitivity, bool edit)
+{
+ GtkToolItem *item;
+ nserror res;
+ GtkWidget *entry;
+ struct bitmap *bitmap;
+ GdkPixbuf *pixbuf = NULL;
+
+ res = search_web_get_provider_bitmap(&bitmap);
+ if ((res == NSERROR_OK) && (bitmap != NULL)) {
+ pixbuf = nsgdk_pixbuf_get_from_surface(bitmap->surface, 32, 32);
+ }
+
+ entry = nsgtk_entry_new();
+
+ if (entry == NULL) {
+ return NULL;
+ }
+
+ if (pixbuf != NULL) {
+ nsgtk_entry_set_icon_from_pixbuf(entry,
+ GTK_ENTRY_ICON_PRIMARY,
+ pixbuf);
+ g_object_unref(pixbuf);
+ } else {
+ nsgtk_entry_set_icon_from_icon_name(entry,
+ GTK_ENTRY_ICON_PRIMARY,
+ NSGTK_STOCK_INFO);
+ }
+
+ if (edit) {
+ gtk_entry_set_width_chars(GTK_ENTRY(entry), 9);
+
+ item = gtk_tool_button_new(NULL, "Web Search");
+ gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item),
+ entry);
+ } else {
+ gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, -1);
+
+ item = gtk_tool_item_new();
+ if (item == NULL) {
+ return NULL;
+ }
+
+ gtk_container_add(GTK_CONTAINER(item), entry);
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(entry), sensitivity);
+
+ return item;
+}
+
+
+/**
+ * create local history toolbar item widget
+ */
+static GtkToolItem *
+make_toolbar_item_history(bool sensitivity, bool edit)
+{
+ GtkToolItem *item;
+ const char *msg = "H";
+ char *label = NULL;
+
+ if (edit) {
+ msg = messages_get("gtkLocalHistory");
+ }
+ label = remove_underscores(msg, false);
+ item = gtk_tool_button_new(NULL, label);
+ if (label != NULL) {
+ free(label);
+ }
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "local-history");
+
+ /* set history widget minimum width */
+ gtk_widget_set_size_request(GTK_WIDGET(item), 20, -1);
+ gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity);
+
+ return item;
+}
+
+
+/**
+ * create generic button toolbar item widget
+ */
+static GtkToolItem *
+make_toolbar_item_button(const char *labelmsg,
+ const char *iconname,
+ bool sensitivity,
+ bool edit)
+{
+ GtkToolItem *item;
+ char *label = NULL;
+
+ label = remove_underscores(messages_get(labelmsg), false);
+
+ item = gtk_tool_button_new(NULL, label);
+ if (label != NULL) {
+ free(label);
+ }
+
+ if (item != NULL) {
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), iconname);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity);
+ if (edit) {
+ nsgtk_widget_set_margins(GTK_WIDGET(item), 0, 0);
+ }
+ }
+
+ return item;
+}
+
+
+/**
+ * widget factory for creation of toolbar item widgets
*
- * \param tbbutton search button reference
- * \param iconsize The size of icons to select.
- * \param usedef Use the default image if not found.
- * \return default search image.
+ * \param i the id of the widget
+ * \param theme the theme to make the widgets from
+ * \return gtk widget
*/
+static GtkToolItem *
+make_toolbar_item(nsgtk_toolbar_button itemid, bool sensitivity)
+{
+ GtkToolItem *toolitem = NULL;
+
+ switch(itemid) {
+#define TOOLBAR_ITEM_y(identifier, label, iconame)
+#define TOOLBAR_ITEM_n(identifier, label, iconame)
+#define TOOLBAR_ITEM_t(identifier, label, iconame) \
+ case identifier: \
+ toolitem = make_toolbar_item_button(#label, iconame, sensitivity, false); \
+ break;
+#define TOOLBAR_ITEM_b(identifier, label, iconame) \
+ case identifier: \
+ toolitem = make_toolbar_item_button(#label, iconame, sensitivity, false); \
+ break;
+#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \
+ TOOLBAR_ITEM_ ## clicked(identifier, label, iconame)
+
+#include "gtk/toolbar_items.h"
+
+#undef TOOLBAR_ITEM_t
+#undef TOOLBAR_ITEM_b
+#undef TOOLBAR_ITEM_n
+#undef TOOLBAR_ITEM_y
+#undef TOOLBAR_ITEM
+
+ case HISTORY_BUTTON:
+ toolitem = make_toolbar_item_history(sensitivity, false);
+ break;
+
+ case URL_BAR_ITEM:
+ toolitem = make_toolbar_item_url_bar(sensitivity, false);
+ break;
-static GtkImage *
-nsgtk_theme_searchimage_default(nsgtk_search_buttons tbbutton,
- GtkIconSize iconsize,
- bool usedef)
+ case THROBBER_ITEM:
+ toolitem = make_toolbar_item_throbber(sensitivity, false);
+ break;
+
+ case WEBSEARCH_ITEM:
+ toolitem = make_toolbar_item_websearch(sensitivity, false);
+ break;
+
+ default:
+ break;
+
+ }
+ return toolitem;
+}
+
+
+/**
+ * widget factory for creation of toolbar item widgets for the toolbox
+ *
+ * \param itemid the id of the widget
+ * \return gtk tool item widget
+ */
+static GtkToolItem *
+make_toolbox_item(nsgtk_toolbar_button itemid, bool bar)
{
- GtkImage *image;
+ GtkToolItem *toolitem = NULL;
+
+ switch(itemid) {
+#define TOOLBAR_ITEM_y(identifier, label, iconame)
+#define TOOLBAR_ITEM_n(identifier, label, iconame)
+#define TOOLBAR_ITEM_t(identifier, label, iconame) \
+ case identifier: \
+ if (bar) { \
+ toolitem = make_toolbar_item_button(#label, iconame, true, true); \
+ } \
+ break;
+#define TOOLBAR_ITEM_b(identifier, label, iconame) \
+ case identifier: \
+ toolitem = make_toolbar_item_button(#label, iconame, true, true); \
+ break;
+#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \
+ TOOLBAR_ITEM_ ## clicked(identifier, label, iconame)
+
+#include "gtk/toolbar_items.h"
- switch (tbbutton) {
+#undef TOOLBAR_ITEM_t
+#undef TOOLBAR_ITEM_b
+#undef TOOLBAR_ITEM_n
+#undef TOOLBAR_ITEM_y
+#undef TOOLBAR_ITEM
+
+ case HISTORY_BUTTON:
+ toolitem = make_toolbar_item_history(true, true);
+ break;
- case (SEARCH_BACK_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(
- NSGTK_STOCK_GO_BACK, iconsize));
+ case URL_BAR_ITEM:
+ toolitem = make_toolbar_item_url_bar(false, true);
break;
- case (SEARCH_FORWARD_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(
- NSGTK_STOCK_GO_FORWARD, iconsize));
+ case THROBBER_ITEM:
+ toolitem = make_toolbar_item_throbber(true, true);
break;
- case (SEARCH_CLOSE_BUTTON):
- image = GTK_IMAGE(nsgtk_image_new_from_stock(
- NSGTK_STOCK_CLOSE, iconsize));
+ case WEBSEARCH_ITEM:
+ toolitem = make_toolbar_item_websearch(false, true);
break;
default:
- image = NULL;
+ break;
+
}
+ return toolitem;
+}
+
+
+/**
+ * target entry for drag source
+ */
+static GtkTargetEntry target_entry = {
+ (char *)"nsgtk_button_data",
+ GTK_TARGET_SAME_APP,
+ 0
+};
+
- if (usedef && (image == NULL)) {
- image = GTK_IMAGE(nsgtk_image_new_from_stock(
- "gtk-missing-image", iconsize));
+/**
+ * find the toolbar item with a given location.
+ *
+ * \param tb the toolbar instance
+ * \param locaction the location to search for
+ * \return the item id for a location
+ */
+static nsgtk_toolbar_button
+itemid_from_location(struct nsgtk_toolbar *tb, int location)
+{
+ int iidx;
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ if (tb->items[iidx].location == location) {
+ break;
+ }
}
+ return iidx;
+}
+
- return image;
+/**
+ * save toolbar settings to file
+ */
+static nserror
+nsgtk_toolbar_customisation_save(struct nsgtk_toolbar *tb)
+{
+ int iidx; /* item index */
+ char *order; /* item ordering */
+ char *start; /* start of next item name to be output */
+ int orderlen = 0; /* length of item ordering */
+ nsgtk_toolbar_button itemid;
+ int location;
+ char *choices = NULL;
+
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ if (tb->items[iidx].location != INACTIVE_LOCATION) {
+ orderlen += strlen(tb->items[iidx].name);
+ orderlen++; /* allow for separator */
+ }
+ }
+
+ /* ensure there are some items to store */
+ if (orderlen == 0) {
+ return NSERROR_INVALID;
+ }
+
+ order = malloc(orderlen);
+ if (order == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ start = order;
+
+ for (location = BACK_BUTTON;
+ location < PLACEHOLDER_BUTTON;
+ location++) {
+ int written;
+ itemid = itemid_from_location(tb, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ /* no more filled locations */
+ break;
+ }
+ written = snprintf(start,
+ orderlen - (start - order),
+ "%s/",
+ tb->items[itemid].name);
+ if ((written < 0) ||
+ (written >= orderlen - (start - order))) {
+ free(order);
+ return NSERROR_UNKNOWN;
+ }
+ start += written;
+
+ if ((start - order) >= orderlen) {
+ break;
+ }
+ }
+
+ order[orderlen - 1] = 0;
+
+ nsoption_set_charp(toolbar_items, order);
+
+ /* ensure choices are saved */
+ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
+ return NSERROR_OK;
}
+
/**
- * initialise a theme structure with gtk images
+ * connect signals to a toolbar item in a customisation toolbar
*
- * \param iconsize The size of icon to load
- * \param usedef use the default gtk icon if unset
+ * \param tb The toolbar
+ * \param itemid The item id within to toolbar to connect
+ * \param NSERROR_OK on success
*/
-static struct nsgtk_theme *nsgtk_theme_load(GtkIconSize iconsize, bool usedef)
+static nserror
+toolbar_item_connect_signals(struct nsgtk_toolbar *tb, int itemid)
{
- struct nsgtk_theme *theme;
- int btnloop;
+ /* set toolbar items to be a drag source */
+ gtk_tool_item_set_use_drag_window(tb->items[itemid].button, TRUE);
+ gtk_drag_source_set(GTK_WIDGET(tb->items[itemid].button),
+ GDK_BUTTON1_MASK,
+ &target_entry,
+ 1,
+ GDK_ACTION_COPY);
+ g_signal_connect(tb->items[itemid].button,
+ "drag-data-get",
+ G_CALLBACK(tb->items[itemid].dataminus),
+ tb);
+ return NSERROR_OK;
+}
- theme = malloc(sizeof(struct nsgtk_theme));
- if (theme == NULL) {
- return NULL;
+
+/**
+ * customisation container handler for drag drop signal
+ *
+ * called when a widget is dropped onto the store window
+ */
+static gboolean
+customisation_container_drag_drop_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ gint x, gint y,
+ guint time,
+ gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ tbc = (struct nsgtk_toolbar_customisation *)data;
+ int location;
+ int itemid;
+
+ if ((tbc->dragfrom) || (tbc->dragitem == -1)) {
+ tbc->dragitem = -1;
+ return FALSE;
}
- for (btnloop = BACK_BUTTON;
- btnloop < PLACEHOLDER_BUTTON ;
- btnloop++) {
- theme->image[btnloop] = nsgtk_theme_image_default(btnloop,
- iconsize,
- usedef);
+ if (tbc->toolbar.items[tbc->dragitem].location == INACTIVE_LOCATION) {
+ tbc->dragitem = -1;
+ gtk_drag_finish(gdc, TRUE, TRUE, time);
+ return FALSE;
+
}
- for (btnloop = SEARCH_BACK_BUTTON;
- btnloop < SEARCH_BUTTONS_COUNT;
- btnloop++) {
- theme->searchimage[btnloop] =
- nsgtk_theme_searchimage_default(btnloop,
- iconsize,
- usedef);
+ /* update the locations for all the subsequent toolbar items */
+ for (location = tbc->toolbar.items[tbc->dragitem].location;
+ location < PLACEHOLDER_BUTTON;
+ location++) {
+ itemid = itemid_from_location(&tbc->toolbar, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ break;
+ }
+ tbc->toolbar.items[itemid].location--;
}
- return theme;
-}
+ /* remove existing item */
+ tbc->toolbar.items[tbc->dragitem].location = -1;
+ gtk_container_remove(GTK_CONTAINER(tbc->toolbar.widget),
+ GTK_WIDGET(tbc->toolbar.items[tbc->dragitem].button));
+
+ tbc->dragitem = -1;
+ gtk_drag_finish(gdc, TRUE, TRUE, time);
+ return FALSE;
+}
-/* exported function documented in gtk/toolbar.h */
-void nsgtk_theme_implement(struct nsgtk_scaffolding *g)
+/**
+ * customisation container handler for drag motion signal
+ *
+ * called when hovering above the store
+ */
+static gboolean
+customisation_container_drag_motion_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ gint x, gint y,
+ guint time,
+ gpointer data)
{
- struct nsgtk_theme *theme[IMAGE_SET_COUNT];
- int i;
- struct nsgtk_button_connect *button;
- struct gtk_search *search;
+ return FALSE;
+}
- theme[IMAGE_SET_MAIN_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false);
- theme[IMAGE_SET_RCLICK_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false);
- theme[IMAGE_SET_POPUP_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false);
- theme[IMAGE_SET_BUTTONS] = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false);
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) ||
- (i == WEBSEARCH_ITEM))
- continue;
+/**
+ * customisation toolbar handler for drag drop signal
+ *
+ * called when a widget is dropped onto the toolbar
+ */
+static gboolean
+customisation_toolbar_drag_drop_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ gint x,
+ gint y,
+ guint time,
+ gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ tbc = (struct nsgtk_toolbar_customisation *)data;
+ gint position; /* drop position in toolbar */
+ int location;
+ int itemid;
+ struct nsgtk_toolbar_item *dragitem; /* toolbar item being dragged */
+
+ position = gtk_toolbar_get_drop_index(tbc->toolbar.widget, x, y);
+ if (tbc->dragitem == -1) {
+ return TRUE;
+ }
- button = nsgtk_scaffolding_button(g, i);
- if (button == NULL)
- continue;
+ /* pure conveiance variable */
+ dragitem = &tbc->toolbar.items[tbc->dragitem];
- /* gtk_image_menu_item_set_image accepts NULL image */
- if ((button->main != NULL) &&
- (theme[IMAGE_SET_MAIN_MENU] != NULL)) {
- nsgtk_image_menu_item_set_image(
- GTK_WIDGET(button->main),
- GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->image[i]));
- gtk_widget_show_all(GTK_WIDGET(button->main));
+ /* deal with replacing existing item in toolbar */
+ if (dragitem->location != INACTIVE_LOCATION) {
+ if (dragitem->location < position) {
+ position--;
}
- if ((button->rclick != NULL) &&
- (theme[IMAGE_SET_RCLICK_MENU] != NULL)) {
- nsgtk_image_menu_item_set_image(GTK_WIDGET(button->rclick),
- GTK_WIDGET(
- theme[IMAGE_SET_RCLICK_MENU]->
- image[i]));
- gtk_widget_show_all(GTK_WIDGET(button->rclick));
+
+ /* update the locations for all the subsequent toolbar items */
+ for (location = dragitem->location;
+ location < PLACEHOLDER_BUTTON;
+ location++) {
+ itemid = itemid_from_location(&tbc->toolbar, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ break;
+ }
+ tbc->toolbar.items[itemid].location--;
}
- if ((button->popup != NULL) &&
- (theme[IMAGE_SET_POPUP_MENU] != NULL)) {
- nsgtk_image_menu_item_set_image(GTK_WIDGET(button->popup),
- GTK_WIDGET(
- theme[IMAGE_SET_POPUP_MENU]->
- image[i]));
- gtk_widget_show_all(GTK_WIDGET(button->popup));
+
+ /* remove existing item */
+ dragitem->location = INACTIVE_LOCATION;
+ gtk_container_remove(GTK_CONTAINER(tbc->toolbar.widget),
+ GTK_WIDGET(dragitem->button));
+ }
+
+
+ dragitem->button = make_toolbox_item(tbc->dragitem, true);
+
+ if (dragitem->button == NULL) {
+ nsgtk_warning("NoMemory", 0);
+ return TRUE;
+ }
+
+ /* update locations */
+ for (location = PLACEHOLDER_BUTTON; location >= position; location--) {
+ itemid = itemid_from_location(&tbc->toolbar, location);
+ if (itemid != PLACEHOLDER_BUTTON) {
+ tbc->toolbar.items[itemid].location++;
}
- if ((button->location != -1) && (button->button != NULL) &&
- (theme[IMAGE_SET_BUTTONS] != NULL)) {
- gtk_tool_button_set_icon_widget(
- GTK_TOOL_BUTTON(button->button),
- GTK_WIDGET(
- theme[IMAGE_SET_BUTTONS]->
- image[i]));
- gtk_widget_show_all(GTK_WIDGET(button->button));
+ }
+ dragitem->location = position;
+
+ gtk_toolbar_insert(tbc->toolbar.widget,
+ dragitem->button,
+ dragitem->location);
+
+ toolbar_item_connect_signals(&tbc->toolbar, tbc->dragitem);
+ gtk_widget_show_all(GTK_WIDGET(dragitem->button));
+ tbc->dragitem = -1;
+ return TRUE;
+}
+
+
+/**
+ * customisation toolbar handler for drag data received signal
+ *
+ * connected to toolbutton drop; perhaps one day it'll work properly
+ * so it may replace the global current_button
+ */
+static gboolean
+customisation_toolbar_drag_data_received_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time,
+ gpointer data)
+{
+ return FALSE;
+}
+
+
+/**
+ * customisation toolbar handler for drag motion signal
+ *
+ * called when hovering an item above the toolbar
+ */
+static gboolean
+customisation_toolbar_drag_motion_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ gint x,
+ gint y,
+ guint time,
+ gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ GtkToolItem *item;
+ gint position; /* position in toolbar */
+
+ item = gtk_tool_button_new(NULL, NULL);
+ position = gtk_toolbar_get_drop_index(tb->widget, x, y);
+
+ gtk_toolbar_set_drop_highlight_item(tb->widget, item, position);
+
+ return FALSE; /* drag not in drop zone */
+}
+
+
+/**
+ * customisation toolbar handler for drag leave signal
+ *
+ * called when hovering stops
+ */
+static void
+customisation_toolbar_drag_leave_cb(GtkWidget *widget,
+ GdkDragContext *gdc,
+ guint time,
+ gpointer data)
+{
+ gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0);
+}
+
+
+/**
+ * create a new browser window
+ *
+ * creates a browser window with default url depending on user choices.
+ *
+ * \param bw The browser window to pass for existing window/
+ * \param intab true if the new window should be in a tab else false
+ * for new window.
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+nsgtk_browser_window_create(struct browser_window *bw, bool intab)
+{
+ nserror res = NSERROR_OK;
+ nsurl *url = NULL;
+ int flags = BW_CREATE_HISTORY | BW_CREATE_FOREGROUND | BW_CREATE_FOCUS_LOCATION;
+
+ if (intab) {
+ flags |= BW_CREATE_TAB;
+ }
+
+ if (!nsoption_bool(new_blank)) {
+ const char *addr;
+ if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ } else {
+ addr = NETSURF_HOMEPAGE;
}
+ res = nsurl_create(addr, &url);
+ }
+
+ if (res == NSERROR_OK) {
+ res = browser_window_create(flags, url, NULL, bw, NULL);
+ }
+
+ if (url != NULL) {
+ nsurl_unref(url);
+ }
+
+ return res;
+}
+
+
+/**
+ * Apply the user toolbar button settings from configuration
+ *
+ * GTK specific user option string is a set of fields arranged as
+ * [itemreference];[itemlocation]|[itemreference];[itemlocation]| etc
+ *
+ * \param tb The toolbar to apply customisation to
+ * \param NSERROR_OK on success else error code.
+ */
+static nserror
+apply_user_button_customisation(struct nsgtk_toolbar *tb)
+{
+ const char *tbitems; /* item order user config */
+ const char *start;
+ const char *end;
+ int iidx; /* item index */
+ int location = 0; /* location index */
+
+ /* set all button locations to inactive */
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ tb->items[iidx].location = INACTIVE_LOCATION;
}
- /* set search bar images */
- search = nsgtk_scaffolding_search(g);
- if ((search != NULL) && (theme[IMAGE_SET_MAIN_MENU] != NULL)) {
- /* gtk_tool_button_set_icon_widget accepts NULL image */
- if (search->buttons[SEARCH_BACK_BUTTON] != NULL) {
- gtk_tool_button_set_icon_widget(
- search->buttons[SEARCH_BACK_BUTTON],
- GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
- searchimage[SEARCH_BACK_BUTTON]));
- gtk_widget_show_all(GTK_WIDGET(
- search->buttons[SEARCH_BACK_BUTTON]));
+ tbitems = nsoption_charp(toolbar_items);
+ if (tbitems == NULL) {
+ tbitems = "";
+ }
+
+ end = tbitems;
+ while (*end != 0) {
+ start = end;
+ while ((*end != 0) && (*end !='/')) {
+ end++;
}
- if (search->buttons[SEARCH_FORWARD_BUTTON] != NULL) {
- gtk_tool_button_set_icon_widget(
- search->buttons[SEARCH_FORWARD_BUTTON],
- GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
- searchimage[SEARCH_FORWARD_BUTTON]));
- gtk_widget_show_all(GTK_WIDGET(
- search->buttons[
- SEARCH_FORWARD_BUTTON]));
+
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ if (((ssize_t)strlen(tb->items[iidx].name) == (end - start)) &&
+ (strncmp(tb->items[iidx].name, start, end - start) == 0)) {
+ tb->items[iidx].location = location++;
+ break;
+ }
}
- if (search->buttons[SEARCH_CLOSE_BUTTON] != NULL) {
- gtk_tool_button_set_icon_widget(
- search->buttons[SEARCH_CLOSE_BUTTON],
- GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
- searchimage[SEARCH_CLOSE_BUTTON]));
- gtk_widget_show_all(GTK_WIDGET(
- search->buttons[SEARCH_CLOSE_BUTTON]));
+
+ if (*end == '/') {
+ end++;
}
}
- for (i = 0; i < IMAGE_SET_COUNT; i++) {
- if (theme[i] != NULL) {
- free(theme[i]);
- }
+ if (location == 0) {
+ /* completely failed to create any buttons so use defaults */
+ tb->items[BACK_BUTTON].location = location++;
+ tb->items[HISTORY_BUTTON].location = location++;
+ tb->items[FORWARD_BUTTON].location = location++;
+ tb->items[RELOADSTOP_BUTTON].location = location++;
+ tb->items[URL_BAR_ITEM].location = location++;
+ tb->items[WEBSEARCH_ITEM].location = location++;
+ tb->items[OPENMENU_BUTTON].location = location++;
+ tb->items[THROBBER_ITEM].location = location++;
}
+
+
+ return NSERROR_OK;
}
/**
- * callback function to iterate toolbar's widgets
+ * callback function to remove a widget from a container
*/
-static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data)
+static void container_remove_widget(GtkWidget *widget, gpointer data)
{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)),
- widget);
+ GtkContainer *container = GTK_CONTAINER(data);
+ gtk_container_remove(container, widget);
}
+
/**
- * connect temporary handler for toolbar edit events
+ * populates a toolbar with widgets in correct order
*
- * \param g The scaffolding
- * \param bi The button index
+ * \param tb toolbar
+ * \return NSERROR_OK on success else error code.
*/
-static void nsgtk_toolbar_temp_connect(struct nsgtk_scaffolding *g,
- nsgtk_toolbar_button bi)
+static nserror populate_gtk_toolbar_widget(struct nsgtk_toolbar *tb)
{
- struct nsgtk_button_connect *bc;
+ int location; /* location index */
+ int itemid;
+
+ /* clear the toolbar container of all widgets */
+ gtk_container_foreach(GTK_CONTAINER(tb->widget),
+ container_remove_widget,
+ tb->widget);
+
+ /* add widgets to toolbar */
+ for (location = 0; location < PLACEHOLDER_BUTTON; location++) {
+ itemid = itemid_from_location(tb, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ break;
+ }
+ tb->items[itemid].button =
+ make_toolbar_item(itemid,
+ tb->items[itemid].sensitivity);
+
+ gtk_toolbar_insert(tb->widget,
+ tb->items[itemid].button,
+ location);
+ }
- if (bi != URL_BAR_ITEM) {
- bc = nsgtk_scaffolding_button(g, bi);
- if ((bc->button != NULL) && (bc->dataminus != NULL)) {
- g_signal_connect(bc->button,
- "drag-data-get",
- G_CALLBACK(bc->dataminus),
- g);
+ gtk_widget_show_all(GTK_WIDGET(tb->widget));
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * populates the customization toolbar with widgets in correct order
+ *
+ * \param tb toolbar
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror customisation_toolbar_populate(struct nsgtk_toolbar *tb)
+{
+ int location; /* location index */
+ int itemid;
+
+ /* clear the toolbar container of all widgets */
+ gtk_container_foreach(GTK_CONTAINER(tb->widget),
+ container_remove_widget,
+ tb->widget);
+
+ /* add widgets to toolbar */
+ for (location = 0; location < PLACEHOLDER_BUTTON; location++) {
+ itemid = itemid_from_location(tb, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ break;
}
+ tb->items[itemid].button = make_toolbox_item(itemid, true);
+
+ gtk_toolbar_insert(tb->widget,
+ tb->items[itemid].button,
+ location);
}
+
+ gtk_widget_show_all(GTK_WIDGET(tb->widget));
+
+ return NSERROR_OK;
}
+
/**
- * get scaffolding button index of button at location
+ * find the toolbar item with a given gtk widget.
*
- * \return toolbar item id from location when there is an item at that logical
- * location; else -1
+ * \param tb the toolbar instance
+ * \param toolitem the tool item widget to search for
+ * \return the item id matching the widget
*/
static nsgtk_toolbar_button
-nsgtk_toolbar_get_id_at_location(struct nsgtk_scaffolding *g, int i)
+itemid_from_gtktoolitem(struct nsgtk_toolbar *tb, GtkToolItem *toolitem)
{
- int q;
- for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) {
- if (nsgtk_scaffolding_button(g, q)->location == i) {
- return q;
+ int iidx;
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ if ((tb->items[iidx].location != INACTIVE_LOCATION) &&
+ (tb->items[iidx].button == toolitem)) {
+ break;
}
}
- return -1;
+ return iidx;
}
+
/**
- * widget factory for creation of toolbar item widgets
- * \param g the reference scaffolding
- * \param i the id of the widget
- * \param theme the theme to make the widgets from
+ * set a toolbar items sensitivity
+ *
+ * note this does not set menu items sensitivity
*/
-static GtkWidget *
-nsgtk_toolbar_make_widget(struct nsgtk_scaffolding *g,
- nsgtk_toolbar_button i,
- struct nsgtk_theme *theme)
-{
- GtkWidget *w = NULL;
-
- switch(i) {
-
-/* gtk_tool_button_new() accepts NULL args */
-#define MAKE_STOCKBUTTON(p, q) \
- case p##_BUTTON: { \
- GtkStockItem item; \
- char *label = NULL; \
- if (nsgtk_stock_lookup(q, &item) && \
- (item.label != NULL) && \
- ((label = remove_underscores(item.label, false)) != NULL)) { \
- w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \
- theme->image[p##_BUTTON]), label)); \
- free(label); \
- } else { \
- w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \
- theme->image[p##_BUTTON]), q)); \
- } \
- break; \
+static nserror
+set_item_sensitivity(struct nsgtk_toolbar_item *item, bool sensitivity)
+{
+ if (item->sensitivity != sensitivity) {
+ /* item requires sensitivity changing */
+ item->sensitivity = sensitivity;
+
+ if ((item->location != -1) && (item->button != NULL)) {
+ gtk_widget_set_sensitive(GTK_WIDGET(item->button),
+ item->sensitivity);
+ }
}
- MAKE_STOCKBUTTON(HOME, NSGTK_STOCK_HOME)
- MAKE_STOCKBUTTON(BACK, NSGTK_STOCK_GO_BACK)
- MAKE_STOCKBUTTON(FORWARD, NSGTK_STOCK_GO_FORWARD)
- MAKE_STOCKBUTTON(STOP, NSGTK_STOCK_STOP)
- MAKE_STOCKBUTTON(RELOAD, NSGTK_STOCK_REFRESH)
-#undef MAKE_STOCKBUTTON
+ return NSERROR_OK;
+}
- case HISTORY_BUTTON:
- w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
- theme->image[HISTORY_BUTTON]), "H"));
- break;
- case URL_BAR_ITEM: {
- GtkWidget *entry = nsgtk_entry_new();
- w = GTK_WIDGET(gtk_tool_item_new());
+/**
+ * set an item to its alternative action
+ *
+ * this is currently only used for the stop/reload button where we
+ * also reuse the item sensitivity for the state indicator.
+ *
+ * \param tb the toolbar instance
+ */
+static nserror set_item_action(struct nsgtk_toolbar *tb, int itemid, bool alt)
+{
+ const char *iconname;
+ char *label = NULL;
+
+ if (itemid != RELOADSTOP_BUTTON) {
+ return NSERROR_INVALID;
+ }
+ if (tb->items[itemid].location == -1) {
+ return NSERROR_OK;
+ }
+ tb->items[itemid].sensitivity = alt;
- if ((entry == NULL) || (w == NULL)) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- return NULL;
- }
+ if (tb->items[itemid].button == NULL) {
+ return NSERROR_INVALID;
+ }
- nsgtk_entry_set_icon_from_pixbuf(entry,
- GTK_ENTRY_ICON_PRIMARY,
- favicon_pixbuf);
+ if (tb->items[itemid].sensitivity) {
+ iconname = NSGTK_STOCK_REFRESH;
+ label = remove_underscores(messages_get("Reload"), false);
+
+ } else {
+ iconname = NSGTK_STOCK_STOP;
+ label = remove_underscores(messages_get("gtkStop"), false);
- gtk_container_add(GTK_CONTAINER(w), entry);
- gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE);
- break;
}
+ gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb->items[itemid].button),
+ label);
- case THROBBER_ITEM: {
- if ((nsgtk_throbber == NULL) ||
- (nsgtk_throbber->framedata == NULL) ||
- (nsgtk_throbber->framedata[0] == NULL)) {
- return NULL;
+ gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb->items[itemid].button),
+ iconname);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(tb->items[itemid].button), TRUE);
+
+ if (label != NULL) {
+ free(label);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * cause the toolbar browsing context to navigate to a new url.
+ *
+ * \param tb the toolbar context.
+ * \param urltxt The url string.
+ * \return NSERROR_OK on success else appropriate error code.
+ */
+static nserror
+toolbar_navigate_to_url(struct nsgtk_toolbar *tb, const char *urltxt)
+{
+ struct browser_window *bw;
+ nsurl *url;
+ nserror res;
+
+ res = nsurl_create(urltxt, &url);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ res = browser_window_navigate(bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+
+ return res;
+}
+
+
+/**
+ * run a gtk file chooser as a save dialog to obtain a path
+ */
+static nserror
+nsgtk_saveas_dialog(struct browser_window *bw,
+ const char *title,
+ GtkWindow *parent,
+ bool folder,
+ gchar **path_out)
+{
+ nserror res;
+ GtkWidget *fc; /* file chooser widget */
+ GtkFileChooserAction action;
+ char *path; /* proposed path */
+
+ if (!browser_window_has_content(bw)) {
+ /* cannot save a page with no content */
+ return NSERROR_INVALID;
+ }
+
+ if (folder) {
+ action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
+ } else {
+ action = GTK_FILE_CHOOSER_ACTION_SAVE;
+ }
+
+ fc = gtk_file_chooser_dialog_new(title,
+ parent,
+ action,
+ NSGTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ NSGTK_STOCK_SAVE,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ /* set a default file name */
+ res = nsurl_nice(browser_window_access_url(bw), &path, false);
+ if (res != NSERROR_OK) {
+ path = strdup(messages_get("SaveText"));
+ if (path == NULL) {
+ gtk_widget_destroy(fc);
+ return NSERROR_NOMEM;
}
+ }
- if (edit_mode) {
- w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
- gtk_image_new_from_pixbuf(
- nsgtk_throbber->framedata[0])),
- "[throbber]"));
- } else {
- GtkWidget *image;
+ if ((!folder) || (access(path, F_OK) != 0)) {
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), path);
+ }
+ free(path);
- w = GTK_WIDGET(gtk_tool_item_new());
+ /* confirm overwriting */
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc), TRUE);
- image = gtk_image_new_from_pixbuf(nsgtk_throbber->framedata[0]);
- if (image != NULL) {
- nsgtk_widget_set_alignment(image,
- GTK_ALIGN_CENTER,
- GTK_ALIGN_CENTER);
- nsgtk_widget_set_margins(image, 3, 0);
+ /* run the dialog to let user select path */
+ if (gtk_dialog_run(GTK_DIALOG(fc)) != GTK_RESPONSE_ACCEPT) {
+ gtk_widget_destroy(fc);
+ return NSERROR_NOT_FOUND;
+ }
- gtk_container_add(GTK_CONTAINER(w), image);
- }
+ *path_out = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
+
+ gtk_widget_destroy(fc);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * connect all signals to widgets in a customisation
+ */
+static nserror
+toolbar_customisation_connect_signals(struct nsgtk_toolbar *tb)
+{
+ int iidx;
+
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ /* skip inactive items in toolbar */
+ if (tb->items[iidx].location != INACTIVE_LOCATION) {
+ toolbar_item_connect_signals(tb, iidx);
}
- break;
}
- case WEBSEARCH_ITEM: {
- if (edit_mode)
- return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
- nsgtk_image_new_from_stock(NSGTK_STOCK_FIND,
- GTK_ICON_SIZE_LARGE_TOOLBAR)),
- "[websearch]"));
+ /* add move button listeners */
+ g_signal_connect(tb->widget,
+ "drag-drop",
+ G_CALLBACK(customisation_toolbar_drag_drop_cb),
+ tb);
+ g_signal_connect(tb->widget,
+ "drag-data-received",
+ G_CALLBACK(customisation_toolbar_drag_data_received_cb),
+ tb);
+ g_signal_connect(tb->widget,
+ "drag-motion",
+ G_CALLBACK(customisation_toolbar_drag_motion_cb),
+ tb);
+ g_signal_connect(tb->widget,
+ "drag-leave",
+ G_CALLBACK(customisation_toolbar_drag_leave_cb),
+ tb);
+
+ /* set data types */
+ gtk_drag_dest_set(GTK_WIDGET(tb->widget),
+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+ &target_entry,
+ 1,
+ GDK_ACTION_COPY);
+
+ return NSERROR_OK;
+}
+
+
+static void
+item_size_allocate_cb(GtkWidget *widget,
+ GdkRectangle *alloc,
+ gpointer user_data)
+{
+ if (alloc->width > NSGTK_BUTTON_WIDTH) {
+ alloc->width = NSGTK_BUTTON_WIDTH;
+ }
+ if (alloc->height > NSGTK_BUTTON_HEIGHT) {
+ alloc->height = NSGTK_BUTTON_HEIGHT;
+ }
+ gtk_widget_set_allocation(widget, alloc);
+}
+
- GtkWidget *entry = nsgtk_entry_new();
+/**
+ * add a row to a toolbar customisation toolbox
+ *
+ * \param tbc The toolbar customisation context
+ * \param startitem The item index of the beginning of the row
+ * \param enditem The item index of the beginning of the next row
+ * \return NSERROR_OK on successs else error
+ */
+static nserror
+add_toolbox_row(struct nsgtk_toolbar_customisation *tbc,
+ int startitem,
+ int enditem)
+{
+ GtkToolbar *rowbar;
+ int iidx;
- w = GTK_WIDGET(gtk_tool_item_new());
+ rowbar = GTK_TOOLBAR(gtk_toolbar_new());
+ if (rowbar == NULL) {
+ return NSERROR_NOMEM;
+ }
- if ((entry == NULL) || (w == NULL)) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- return NULL;
+ gtk_toolbar_set_style(rowbar, GTK_TOOLBAR_BOTH);
+ gtk_toolbar_set_icon_size(rowbar, GTK_ICON_SIZE_LARGE_TOOLBAR);
+ gtk_box_pack_start(tbc->toolbox, GTK_WIDGET(rowbar), FALSE, FALSE, 0);
+
+ for (iidx = startitem; iidx < enditem; iidx++) {
+ if (tbc->items[iidx] == NULL) {
+ /* skip any widgets that failed to initialise */
+ continue;
}
+ gtk_widget_set_size_request(GTK_WIDGET(tbc->items[iidx]),
+ NSGTK_BUTTON_WIDTH,
+ NSGTK_BUTTON_HEIGHT);
+ gtk_tool_item_set_use_drag_window(tbc->items[iidx], TRUE);
+ gtk_drag_source_set(GTK_WIDGET(tbc->items[iidx]),
+ GDK_BUTTON1_MASK,
+ &target_entry,
+ 1,
+ GDK_ACTION_COPY);
+ g_signal_connect(tbc->items[iidx],
+ "drag-data-get",
+ G_CALLBACK(tbc->toolbar.items[iidx].dataplus),
+ &tbc->toolbar);
+ g_signal_connect(tbc->items[iidx],
+ "size-allocate",
+ G_CALLBACK(item_size_allocate_cb),
+ NULL);
+ gtk_toolbar_insert(rowbar, tbc->items[iidx], -1);
+ }
+ return NSERROR_OK;
+}
- gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, -1);
- nsgtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY,
- NSGTK_STOCK_INFO);
+/**
+ * creates widgets in customisation toolbox
+ *
+ * \param tbc The toolbar customisation context
+ * \param width The width to layout the toolbox to
+ * \return NSERROR_OK on success else error code.
+ */
+static nserror
+toolbar_customisation_create_toolbox(struct nsgtk_toolbar_customisation *tbc,
+ int width)
+{
+ int columns; /* number of items in a single row */
+ int curcol; /* current column in creation */
+ int iidx; /* item index */
+ int startidx; /* index of item at start of row */
+
+ /* ensure there are a minimum number of items per row */
+ columns = width / NSGTK_BUTTON_WIDTH;
+ if (columns < NSGTK_MIN_STORE_COLUMNS) {
+ columns = NSGTK_MIN_STORE_COLUMNS;
+ }
- gtk_container_add(GTK_CONTAINER(w), entry);
- break;
+ curcol = 0;
+ for (iidx = startidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ if (curcol >= columns) {
+ add_toolbox_row(tbc, startidx, iidx);
+ curcol = 0;
+ startidx = iidx;
+ }
+ tbc->items[iidx] = make_toolbox_item(iidx, false);
+ if (tbc->items[iidx] != NULL) {
+ curcol++;
+ }
+ }
+ if (curcol > 0) {
+ add_toolbox_row(tbc, startidx, iidx);
}
-/* gtk_tool_button_new accepts NULL args */
-#define MAKE_MENUBUTTON(p, q) \
- case p##_BUTTON: { \
- char *label = NULL; \
- label = remove_underscores(messages_get(#q), false); \
- w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \
- theme->image[p##_BUTTON]), label)); \
- if (label != NULL) \
- free(label); \
- break; \
- }
-
- MAKE_MENUBUTTON(NEWWINDOW, gtkNewWindow)
- MAKE_MENUBUTTON(NEWTAB, gtkNewTab)
- MAKE_MENUBUTTON(OPENFILE, gtkOpenFile)
- MAKE_MENUBUTTON(CLOSETAB, gtkCloseTab)
- MAKE_MENUBUTTON(CLOSEWINDOW, gtkCloseWindow)
- MAKE_MENUBUTTON(SAVEPAGE, gtkSavePage)
- MAKE_MENUBUTTON(PRINTPREVIEW, gtkPrintPreview)
- MAKE_MENUBUTTON(PRINT, gtkPrint)
- MAKE_MENUBUTTON(QUIT, gtkQuitMenu)
- MAKE_MENUBUTTON(CUT, gtkCut)
- MAKE_MENUBUTTON(COPY, gtkCopy)
- MAKE_MENUBUTTON(PASTE, gtkPaste)
- MAKE_MENUBUTTON(DELETE, gtkDelete)
- MAKE_MENUBUTTON(SELECTALL, gtkSelectAll)
- MAKE_MENUBUTTON(PREFERENCES, gtkPreferences)
- MAKE_MENUBUTTON(ZOOMPLUS, gtkZoomPlus)
- MAKE_MENUBUTTON(ZOOMMINUS, gtkZoomMinus)
- MAKE_MENUBUTTON(ZOOMNORMAL, gtkZoomNormal)
- MAKE_MENUBUTTON(FULLSCREEN, gtkFullScreen)
- MAKE_MENUBUTTON(VIEWSOURCE, gtkViewSource)
- MAKE_MENUBUTTON(CONTENTS, gtkContents)
- MAKE_MENUBUTTON(ABOUT, gtkAbout)
- MAKE_MENUBUTTON(PDF, gtkPDF)
- MAKE_MENUBUTTON(PLAINTEXT, gtkPlainText)
- MAKE_MENUBUTTON(DRAWFILE, gtkDrawFile)
- MAKE_MENUBUTTON(POSTSCRIPT, gtkPostScript)
- MAKE_MENUBUTTON(FIND, gtkFind)
- MAKE_MENUBUTTON(DOWNLOADS, gtkDownloads)
- MAKE_MENUBUTTON(SAVEWINDOWSIZE, gtkSaveWindowSize)
- MAKE_MENUBUTTON(TOGGLEDEBUGGING, gtkToggleDebugging)
- MAKE_MENUBUTTON(SAVEBOXTREE, gtkDebugBoxTree)
- MAKE_MENUBUTTON(SAVEDOMTREE, gtkDebugDomTree)
- MAKE_MENUBUTTON(LOCALHISTORY, gtkLocalHistory)
- MAKE_MENUBUTTON(GLOBALHISTORY, gtkGlobalHistory)
- MAKE_MENUBUTTON(ADDBOOKMARKS, gtkAddBookMarks)
- MAKE_MENUBUTTON(SHOWBOOKMARKS, gtkShowBookMarks)
- MAKE_MENUBUTTON(SHOWCOOKIES, gtkShowCookies)
- MAKE_MENUBUTTON(OPENLOCATION, gtkOpenLocation)
- MAKE_MENUBUTTON(NEXTTAB, gtkNextTab)
- MAKE_MENUBUTTON(PREVTAB, gtkPrevTab)
- MAKE_MENUBUTTON(GUIDE, gtkGuide)
- MAKE_MENUBUTTON(INFO, gtkUserInformation)
-#undef MAKE_MENUBUTTON
+ return NSERROR_OK;
+}
- default:
- break;
+/**
+ * update toolbar in customisation to user settings
+ */
+static nserror
+customisation_toolbar_update(struct nsgtk_toolbar_customisation *tbc)
+{
+ nserror res;
+
+ res = apply_user_button_customisation(&tbc->toolbar);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* populate toolbar widget */
+ res = customisation_toolbar_populate(&tbc->toolbar);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* ensure icon sizes and text labels on toolbar are set */
+ res = nsgtk_toolbar_restyle(&tbc->toolbar);
+ if (res != NSERROR_OK) {
+ return res;
}
- return w;
+
+ /* attach handlers to toolbar widgets */
+ res = toolbar_customisation_connect_signals(&tbc->toolbar);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ return NSERROR_OK;
}
+
/**
- * called when a widget is dropped onto the toolbar
+ * customisation apply handler for clicked signal
+ *
+ * when 'save settings' button is clicked
+ */
+static gboolean
+customisation_apply_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ tbc = (struct nsgtk_toolbar_customisation *)data;
+
+ /* save state to file, update toolbars for all windows */
+ nsgtk_toolbar_customisation_save(&tbc->toolbar);
+ nsgtk_window_toolbar_update();
+ gtk_widget_destroy(tbc->container);
+
+ return TRUE;
+}
+
+
+/**
+ * customisation reset handler for clicked signal
+ *
+ * when 'reload defaults' button is clicked
*/
static gboolean
-nsgtk_toolbar_data(GtkWidget *widget,
- GdkDragContext *gdc,
- gint x,
- gint y,
- guint time,
- gpointer data)
-{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g),
- x, y);
- int q, i;
- if (window->currentbutton == -1)
+customisation_reset_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ tbc = (struct nsgtk_toolbar_customisation *)data;
+
+ customisation_toolbar_update(tbc);
+
+ return TRUE;
+}
+
+
+/**
+ * customisation container destroy handler
+ */
+static void customisation_container_destroy_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ tbc = (struct nsgtk_toolbar_customisation *)data;
+
+ free(tbc);
+}
+
+/*
+ * Toolbar button clicked handlers
+ */
+
+/**
+ * create a toolbar customisation tab
+ *
+ * this is completely different approach to previous implementation. it
+ * is not modal and the toolbar configuration is performed completely
+ * within the tab. once the user is happy they can apply the change or
+ * cancel as they see fit while continuing to use the browser as usual.
+ */
+static gboolean cutomize_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar_customisation *tbc;
+ nserror res;
+ GtkBuilder *builder;
+ GtkNotebook *notebook; /* notebook containing widget */
+ GtkAllocation notebook_alloc; /* notebook size allocation */
+ int iidx; /* item index */
+
+ /* obtain the notebook being added to */
+ notebook = GTK_NOTEBOOK(gtk_widget_get_ancestor(widget,
+ GTK_TYPE_NOTEBOOK));
+ if (notebook == NULL) {
return TRUE;
- struct nsgtk_theme *theme =
- nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false);
- if (theme == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
+ }
+
+ /* create builder */
+ res = nsgtk_builder_new_from_resname("toolbar", &builder);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Toolbar UI builder init failed");
return TRUE;
}
- if (nsgtk_scaffolding_button(g, window->currentbutton)->location
- != -1) {
- /* widget was already in the toolbar; so replace */
- if (nsgtk_scaffolding_button(g, window->currentbutton)->
- location < ind)
- ind--;
- gtk_container_remove(GTK_CONTAINER(
- nsgtk_scaffolding_toolbar(g)), GTK_WIDGET(
- nsgtk_scaffolding_button(g,
- window->currentbutton)->button));
- /* 'move' all widgets further right than the original location,
- * one place to the left in logical schema */
- for (i = nsgtk_scaffolding_button(g, window->currentbutton)->
- location + 1; i < PLACEHOLDER_BUTTON; i++) {
- q = nsgtk_toolbar_get_id_at_location(g, i);
- if (q == -1)
- continue;
- nsgtk_scaffolding_button(g, q)->location--;
- }
- nsgtk_scaffolding_button(g, window->currentbutton)->
- location = -1;
- }
- nsgtk_scaffolding_button(g, window->currentbutton)->button =
- GTK_TOOL_ITEM(nsgtk_toolbar_make_widget(g,
- window->currentbutton, theme));
- free(theme);
- if (nsgtk_scaffolding_button(g, window->currentbutton)->button
- == NULL) {
- nsgtk_warning("NoMemory", 0);
+ gtk_builder_connect_signals(builder, NULL);
+
+ /* create nsgtk_toolbar_customisation which has nsgtk_toolbar
+ * at the front so we can reuse functions that take
+ * nsgtk_toolbar
+ */
+ tbc = calloc(1, sizeof(struct nsgtk_toolbar_customisation));
+ if (tbc == NULL) {
+ g_object_unref(builder);
return TRUE;
}
- /* update logical schema */
- nsgtk_scaffolding_reset_offset(g);
- /* 'move' all widgets further right than the new location, one place to
- * the right in logical schema */
- for (i = PLACEHOLDER_BUTTON - 1; i >= ind; i--) {
- q = nsgtk_toolbar_get_id_at_location(g, i);
- if (q == -1)
- continue;
- nsgtk_scaffolding_button(g, q)->location++;
+
+ /* get container box widget which forms a page of the tabs */
+ tbc->container = GTK_WIDGET(gtk_builder_get_object(builder, "customisation"));
+ if (tbc->container == NULL) {
+ goto cutomize_button_clicked_cb_error;
}
- nsgtk_scaffolding_button(g, window->currentbutton)->location = ind;
- /* complete action */
- GtkToolItem *current_button;
+ /* vertical box for the toolbox to drag items into and out of */
+ tbc->toolbox = GTK_BOX(gtk_builder_get_object(builder, "toolbox"));
+ if (tbc->toolbox == NULL) {
+ goto cutomize_button_clicked_cb_error;
+ }
- current_button = GTK_TOOL_ITEM(nsgtk_scaffolding_button(g, window->currentbutton)->button);
+ /* customisation toolbar container */
+ tbc->toolbar.widget = GTK_TOOLBAR(gtk_builder_get_object(builder, "toolbar"));
+ if (tbc->toolbar.widget == NULL) {
+ goto cutomize_button_clicked_cb_error;
+ }
- gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), current_button, ind);
+ /* build customisation toolbar */
+ gtk_toolbar_set_show_arrow(tbc->toolbar.widget, TRUE);
- gtk_tool_item_set_use_drag_window(current_button, TRUE);
- gtk_drag_source_set(GTK_WIDGET(current_button),
- GDK_BUTTON1_MASK, &entry, 1,
- GDK_ACTION_COPY);
- nsgtk_toolbar_temp_connect(g, window->currentbutton);
- gtk_widget_show_all(GTK_WIDGET(current_button));
+ for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) {
+ res = toolbar_item_create(iidx, &tbc->toolbar.items[iidx]);
+ if (res != NSERROR_OK) {
+ goto cutomize_button_clicked_cb_error;
+ }
+ }
+
+ res = customisation_toolbar_update(tbc);
+ if (res != NSERROR_OK) {
+ goto cutomize_button_clicked_cb_error;
+ }
+
+ /* use toolbox for widgets to drag to/from */
+ gtk_widget_get_allocation(GTK_WIDGET(notebook), &notebook_alloc);
+
+ res = toolbar_customisation_create_toolbox(tbc, notebook_alloc.width);
+ if (res != NSERROR_OK) {
+ goto cutomize_button_clicked_cb_error;
+ }
+
+ /* configure the container */
+ gtk_drag_dest_set(GTK_WIDGET(tbc->container),
+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+ &target_entry,
+ 1,
+ GDK_ACTION_COPY);
+
+ /* discard button calls destroy */
+ g_signal_connect_swapped(GTK_WIDGET(gtk_builder_get_object(builder,
+ "discard")),
+ "clicked",
+ G_CALLBACK(gtk_widget_destroy),
+ tbc->container);
+
+ /* save and update on apply button */
+ g_signal_connect(GTK_WIDGET(gtk_builder_get_object(builder, "apply")),
+ "clicked",
+ G_CALLBACK(customisation_apply_clicked_cb),
+ tbc);
+
+ g_signal_connect(GTK_WIDGET(gtk_builder_get_object(builder, "reset")),
+ "clicked",
+ G_CALLBACK(customisation_reset_clicked_cb),
+ tbc);
+
+ /* close and cleanup on delete signal */
+ g_signal_connect(tbc->container,
+ "destroy",
+ G_CALLBACK(customisation_container_destroy_cb),
+ tbc);
+
+
+ g_signal_connect(tbc->container,
+ "drag-drop",
+ G_CALLBACK(customisation_container_drag_drop_cb),
+ tbc);
+
+ g_signal_connect(tbc->container,
+ "drag-motion",
+ G_CALLBACK(customisation_container_drag_motion_cb),
+ tbc);
- window->currentbutton = -1;
+ nsgtk_tab_add_page(notebook,
+ tbc->container,
+ false,
+ messages_get("gtkCustomizeToolbarTitle"),
+ favicon_pixbuf);
+
+ /* safe to drop the reference to the builder as the container is
+ * referenced by the notebook now.
+ */
+ g_object_unref(builder);
+
+ return TRUE;
+
+ cutomize_button_clicked_cb_error:
+ free(tbc);
+ g_object_unref(builder);
return TRUE;
+
+}
+
+
+/**
+ * callback for all toolbar items widget size allocation
+ *
+ * handler connected to all toolbar items for the size-allocate signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param alloc The size allocation being set.
+ * \param data The toolbar context passed when the signal was connected
+ */
+static void
+toolbar_item_size_allocate_cb(GtkWidget *widget,
+ GtkAllocation *alloc,
+ gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ nsgtk_toolbar_button itemid;
+
+ itemid = itemid_from_gtktoolitem(tb, GTK_TOOL_ITEM(widget));
+
+ if ((tb->toolbarmem == alloc->x) ||
+ (tb->items[itemid].location < tb->items[HISTORY_BUTTON].location)) {
+ /*
+ * no reallocation after first adjustment,
+ * no reallocation for buttons left of history button
+ */
+ return;
+ }
+
+ if (itemid == HISTORY_BUTTON) {
+ if (alloc->width == 20) {
+ return;
+ }
+
+ tb->toolbarbase = alloc->y + alloc->height;
+ tb->historybase = alloc->x + 20;
+ if (tb->offset == 0) {
+ tb->offset = alloc->width - 20;
+ }
+ alloc->width = 20;
+ } else if (tb->items[itemid].location <= tb->items[URL_BAR_ITEM].location) {
+ alloc->x -= tb->offset;
+ if (itemid == URL_BAR_ITEM) {
+ alloc->width += tb->offset;
+ }
+ }
+ tb->toolbarmem = alloc->x;
+
+ gtk_widget_size_allocate(widget, alloc);
}
+
/**
- * connected to toolbutton drop; perhaps one day it'll work properly so it may
- * replace the global current_button
+ * handler for back tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
static gboolean
-nsgtk_toolbar_move_complete(GtkWidget *widget,
- GdkDragContext *gdc,
- gint x,
- gint y,
- GtkSelectionData *selection,
- guint info,
- guint time,
- gpointer data)
+back_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- return FALSE;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ if ((bw != NULL) && browser_window_history_back_available(bw)) {
+ /* clear potential search effects */
+ browser_window_search_clear(bw);
+
+ browser_window_history_back(bw, false);
+
+ set_item_sensitivity(&tb->items[BACK_BUTTON],
+ browser_window_history_back_available(bw));
+ set_item_sensitivity(&tb->items[FORWARD_BUTTON],
+ browser_window_history_forward_available(bw));
+
+ nsgtk_local_history_hide();
+ }
+ return TRUE;
}
+
/**
- * called when hovering an item above the toolbar
+ * handler for forward tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
static gboolean
-nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x,
- gint y, guint time, gpointer data)
-{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- GtkToolItem *item = gtk_tool_button_new(NULL, NULL);
- if (item != NULL)
- gtk_toolbar_set_drop_highlight_item(
- nsgtk_scaffolding_toolbar(g),
- GTK_TOOL_ITEM(item),
- gtk_toolbar_get_drop_index(
- nsgtk_scaffolding_toolbar(g), x, y));
- return FALSE;
+forward_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ if ((bw != NULL) && browser_window_history_forward_available(bw)) {
+ /* clear potential search effects */
+ browser_window_search_clear(bw);
+
+ browser_window_history_forward(bw, false);
+
+ set_item_sensitivity(&tb->items[BACK_BUTTON],
+ browser_window_history_back_available(bw));
+ set_item_sensitivity(&tb->items[FORWARD_BUTTON],
+ browser_window_history_forward_available(bw));
+ nsgtk_local_history_hide();
+ }
+ return TRUE;
}
+
/**
- * called when hovering stops
+ * handler for stop tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static void
-nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time,
- gpointer data)
+static gboolean
+stop_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0);
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+
+ browser_window_stop(tb->get_bw(tb->get_ctx));
+
+ return TRUE;
+}
+
+
+/**
+ * handler for reload tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+reload_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ /* clear potential search effects */
+ browser_window_search_clear(bw);
+
+ browser_window_reload(bw, true);
+
+ return TRUE;
+}
+
+
+/**
+ * handler for reload/stop tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+reloadstop_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ /* clear potential search effects */
+ browser_window_search_clear(bw);
+
+ if (tb->items[RELOADSTOP_BUTTON].sensitivity) {
+ browser_window_reload(bw, true);
+ } else {
+ browser_window_stop(tb->get_bw(tb->get_ctx));
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for home tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+home_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ nserror res;
+ const char *addr;
+
+ if (nsoption_charp(homepage_url) != NULL) {
+ addr = nsoption_charp(homepage_url);
+ } else {
+ addr = NETSURF_HOMEPAGE;
+ }
+
+ res = toolbar_navigate_to_url(tb, addr);
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * callback for url entry widget activation
+ *
+ * handler connected to url entry widget for the activate signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE to allow activation.
+ */
+static gboolean url_entry_activate_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ nsurl *url;
+
+ res = search_web_omni(gtk_entry_get_text(GTK_ENTRY(widget)),
+ SEARCH_WEB_OMNI_NONE,
+ &url);
+ if (res == NSERROR_OK) {
+ bw = tb->get_bw(tb->get_ctx);
+ res = browser_window_navigate(
+ bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL);
+ nsurl_unref(url);
+ }
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * callback for url entry widget changing
+ *
+ * handler connected to url entry widget for the change signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param event The key change event that changed the entry.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE to allow activation.
+ */
+static gboolean
+url_entry_changed_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ return nsgtk_completion_update(GTK_ENTRY(widget));
}
+
/**
- * add item to toolbar.
+ * callback for url entry widget icon button release
*
- * the function should be called, when multiple items are being added,
- * in ascending order.
+ * handler connected to url entry widget for the icon release signal
*
- * \param g the scaffolding whose toolbar an item is added to.
- * \param i the location in the toolbar.
- * \param theme The theme in use.
+ * \param widget The widget the signal is being delivered to.
+ * \param event The key change event that changed the entry.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE to allow activation.
*/
static void
-nsgtk_toolbar_add_item_to_toolbar(struct nsgtk_scaffolding *g, int i,
- struct nsgtk_theme *theme)
-{
- int q;
- for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++)
- if (nsgtk_scaffolding_button(g, q)->location == i) {
- nsgtk_scaffolding_button(g, q)->button = GTK_TOOL_ITEM(
- nsgtk_toolbar_make_widget(g, q,
- theme));
- gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g),
- nsgtk_scaffolding_button(g, q)->button,
- i);
- break;
- }
+url_entry_icon_release_cb(GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ nsgtk_page_info(bw);
+}
+
+
+/**
+ * handler for web search tool bar entry item activate signal
+ *
+ * handler connected to web search entry widget for the activate signal
+ *
+ * \todo make this user selectable to switch between opening in new
+ * and navigating current window. Possibly improve core search_web interfaces
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean websearch_entry_activate_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ nsurl *url;
+
+ res = search_web_omni(gtk_entry_get_text(GTK_ENTRY(widget)),
+ SEARCH_WEB_OMNI_SEARCHONLY,
+ &url);
+ if (res == NSERROR_OK) {
+ bw = tb->get_bw(tb->get_ctx);
+
+ res = browser_window_create(
+ BW_CREATE_HISTORY | BW_CREATE_TAB | BW_CREATE_FOREGROUND,
+ url,
+ NULL,
+ bw,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
}
/**
- * cleanup code physical update of all toolbars; resensitize
- * \param g the 'front' scaffolding that called customize
+ * handler for web search tool bar item button press signal
+ *
+ * allows a click in the websearch entry field to clear the name of the
+ * provider.
+ *
+ * \todo this does not work well, different behaviour wanted perhaps?
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static void nsgtk_toolbar_close(struct nsgtk_scaffolding *g)
+static gboolean
+websearch_entry_button_press_cb(GtkWidget *widget,
+ GdkEventFocus *f,
+ gpointer data)
{
- int i;
+ gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
+ gtk_widget_grab_focus(GTK_WIDGET(widget));
- struct nsgtk_scaffolding *list;
- struct nsgtk_theme *theme;
+ return TRUE;
+}
- list = nsgtk_scaffolding_iterate(NULL);
- while (list) {
- theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false);
- if (theme == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- continue;
- }
- /* clear toolbar */
- gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(
- list)), nsgtk_toolbar_clear_toolbar, list);
- /* then add items */
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- nsgtk_toolbar_add_item_to_toolbar(list, i, theme);
+
+/**
+ * handler for new window tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+newwindow_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+
+ res = nsgtk_browser_window_create(tb->get_bw(tb->get_ctx), false);
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for new tab tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+newtab_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+
+ res = nsgtk_browser_window_create(tb->get_bw(tb->get_ctx), true);
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+ return TRUE;
+}
+
+
+/**
+ * handler for open file tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+openfile_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *dlgOpen;
+ gint response;
+ GtkWidget *toplevel;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ dlgOpen = gtk_file_chooser_dialog_new("Open File",
+ GTK_WINDOW(toplevel),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NSGTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL, NULL);
+
+ response = gtk_dialog_run(GTK_DIALOG(dlgOpen));
+ if (response == GTK_RESPONSE_OK) {
+ char *urltxt;
+ gchar *filename;
+ nserror res;
+ nsurl *url;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlgOpen));
+
+ urltxt = malloc(strlen(filename) + FILE_SCHEME_PREFIX_LEN + 1);
+ if (urltxt != NULL) {
+ sprintf(urltxt, FILE_SCHEME_PREFIX"%s", filename);
+
+ res = nsurl_create(urltxt, &url);
+ if (res == NSERROR_OK) {
+ bw = tb->get_bw(tb->get_ctx);
+ res = browser_window_navigate(bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+ free(urltxt);
}
- nsgtk_toolbar_connect_all(list);
- gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(
- list)));
- nsgtk_scaffolding_set_sensitivity(list);
- nsgtk_widget_override_background_color(GTK_WIDGET(nsgtk_window_get_layout(nsgtk_scaffolding_top_level(list))), GTK_STATE_NORMAL, 0, 0xFFFF, 0xFFFF, 0xFFFF);
- g_signal_handler_unblock(GTK_WIDGET(
- nsgtk_window_get_layout(
- nsgtk_scaffolding_top_level(list))),
- nsgtk_window_get_signalhandler(
- nsgtk_scaffolding_top_level(list),
- NSGTK_WINDOW_SIGNAL_CLICK));
- g_signal_handler_unblock(GTK_WIDGET(
- nsgtk_window_get_layout(
- nsgtk_scaffolding_top_level(list))),
- nsgtk_window_get_signalhandler(
- nsgtk_scaffolding_top_level(list),
- NSGTK_WINDOW_SIGNAL_REDRAW));
- browser_window_refresh_url_bar(
- nsgtk_get_browser_window(
- nsgtk_scaffolding_top_level(list)));
-
- if (list != g)
- gtk_widget_set_sensitive(GTK_WIDGET(
- nsgtk_scaffolding_window(list)), TRUE);
- free(theme);
- list = nsgtk_scaffolding_iterate(list);
- }
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)),
- TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)),
- TRUE);
- /* update favicon etc */
- nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g));
-
- search_web_select_provider(-1);
-}
-
-/**
- * when cancel button is clicked
- */
-static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data)
-{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
-
- edit_mode = false;
- /* reset g->buttons->location */
- for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- nsgtk_scaffolding_button(g, i)->location =
- window->buttonlocations[i];
- }
- nsgtk_toolbar_set_physical(g);
- nsgtk_toolbar_connect_all(g);
- nsgtk_toolbar_close(g);
- nsgtk_scaffolding_set_sensitivity(g);
- gtk_widget_destroy(window->window);
+
+
+ g_free(filename);
+ }
+
+ gtk_widget_destroy(dlgOpen);
+
+ return TRUE;
+}
+
+
+/**
+ * handler for close window tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+closewindow_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWidget *toplevel;
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+ gtk_widget_destroy(toplevel);
return TRUE;
}
+
/**
- * physically add widgets to store window
+ * handler for full save export tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget)
+static gboolean
+savepage_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- if (window->numberh >= NSGTK_STORE_WIDTH) {
- window->currentbar = gtk_toolbar_new();
- if (window->currentbar == NULL) {
- nsgtk_warning("NoMemory", 0);
- return false;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ DIR *d;
+ gchar *path;
+ nserror res;
+ GtkWidget *toplevel;
+
+ bw = tb->get_bw(tb->get_ctx);
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ res = nsgtk_saveas_dialog(bw,
+ messages_get("gtkcompleteSave"),
+ GTK_WINDOW(toplevel),
+ true,
+ &path);
+ if (res != NSERROR_OK) {
+ return FALSE;
+ }
+
+ d = opendir(path);
+ if (d == NULL) {
+ NSLOG(netsurf, INFO,
+ "Unable to open directory %s for complete save: %s",
+ path,
+ strerror(errno));
+ if (errno == ENOTDIR) {
+ nsgtk_warning("NoDirError", path);
+ } else {
+ nsgtk_warning("gtkFileError", path);
}
- gtk_toolbar_set_style(GTK_TOOLBAR(window->currentbar),
- GTK_TOOLBAR_BOTH);
- gtk_toolbar_set_icon_size(GTK_TOOLBAR(window->currentbar),
- GTK_ICON_SIZE_LARGE_TOOLBAR);
- gtk_box_pack_start(GTK_BOX(window->widgetvbox),
- window->currentbar, FALSE, FALSE, 0);
- window->numberh = 0;
+ g_free(path);
+ return TRUE;
}
- gtk_widget_set_size_request(widget, NSGTK_BUTTON_WIDTH,
- NSGTK_BUTTON_HEIGHT);
- gtk_toolbar_insert(GTK_TOOLBAR(window->currentbar), GTK_TOOL_ITEM(
- widget), window->numberh++);
- gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(widget), TRUE);
- gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &entry, 1,
- GDK_ACTION_COPY);
- gtk_widget_show_all(window->window);
- return true;
+ closedir(d);
+
+ save_complete(browser_window_get_content(bw), path, NULL);
+ g_free(path);
+
+ return TRUE;
}
/**
- * cast toolbar settings to all scaffoldings referenced from the global linked
- * list of gui_windows
+ * handler for pdf export tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static void nsgtk_toolbar_cast(struct nsgtk_scaffolding *g)
+static gboolean
+pdf_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- int i;
- struct nsgtk_scaffolding *list;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *toplevel;
+ gchar *filename;
+ nserror res;
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- window->buttonlocations[i] =
- ((nsgtk_scaffolding_button(g, i)->location
- >= -1) &&
- (nsgtk_scaffolding_button(g, i)->location
- < PLACEHOLDER_BUTTON)) ?
- nsgtk_scaffolding_button(g, i)->location : -1;
+ bw = tb->get_bw(tb->get_ctx);
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ res = nsgtk_saveas_dialog(bw,
+ "Export to PDF",
+ GTK_WINDOW(toplevel),
+ false,
+ &filename);
+ if (res != NSERROR_OK) {
+ return FALSE;
}
- list = nsgtk_scaffolding_iterate(NULL);
- while (list) {
- if (list != g)
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
- nsgtk_scaffolding_button(list, i)->location =
- window->buttonlocations[i];
- list = nsgtk_scaffolding_iterate(list);
+#ifdef WITH_PDF_EXPORT
+ struct print_settings *settings;
+
+ /* this way the scale used by PDF functions is synchronised with that
+ * used by the all-purpose print interface
+ */
+ haru_nsfont_set_scale((float)option_export_scale / 100);
+
+ settings = print_make_settings(PRINT_OPTIONS,
+ (const char *) filename,
+ &haru_nsfont);
+ g_free(filename);
+ if (settings == NULL) {
+ return TRUE;
}
+ /* This will clean up the print_settings object for us */
+ print_basic_run(browser_window_get_content(bw), &pdf_printer, settings);
+#endif
+ return TRUE;
+
}
/**
- * load toolbar settings from file; file is a set of fields arranged as
- * [itemreference];[itemlocation]|[itemreference];[itemlocation]| etc
+ * handler for plain text export tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-void nsgtk_toolbar_customization_load(struct nsgtk_scaffolding *g)
+static gboolean
+plaintext_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- int i, ii;
- char *buffer;
- char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *toplevel;
+ gchar *filename;
+ nserror res;
+
+ bw = tb->get_bw(tb->get_ctx);
- /* default toolbar button order */
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- nsgtk_scaffolding_button(g, i)->location =
- (i <= THROBBER_ITEM) ? i : -1;
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ res = nsgtk_saveas_dialog(bw,
+ messages_get("gtkplainSave"),
+ GTK_WINDOW(toplevel),
+ false,
+ &filename);
+ if (res != NSERROR_OK) {
+ return FALSE;
}
- /* ensure the option is actually set */
- if (nsoption_charp(toolbar_order) == NULL) {
- return;
+
+ save_as_text(browser_window_get_content(bw), filename);
+ g_free(filename);
+
+ return TRUE;
+}
+
+
+/**
+ * handler for print tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+print_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkPrintOperation *print_op;
+ GtkPageSetup *page_setup;
+ GtkPrintSettings *print_settings;
+ GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
+ struct print_settings *nssettings;
+ char *settings_fname = NULL;
+ GtkWidget *toplevel;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ print_op = gtk_print_operation_new();
+ if (print_op == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ return TRUE;
}
- buffer = strdup(nsoption_charp(toolbar_order));
-
- i = BACK_BUTTON;
- ii = BACK_BUTTON;
- buffer1 = strtok_r(buffer, "|", &ptr);
- while (buffer1 != NULL) {
- subbuffer = strtok_r(buffer1, ";", &pter);
- if (subbuffer != NULL) {
- i = atoi(subbuffer);
- subbuffer = strtok_r(NULL, ";", &pter);
- if (subbuffer != NULL) {
- ii = atoi(subbuffer);
- if ((i >= BACK_BUTTON) &&
- (i < PLACEHOLDER_BUTTON) &&
- (ii >= -1) &&
- (ii < PLACEHOLDER_BUTTON)) {
- nsgtk_scaffolding_button(g, i)->location = ii;
- }
- }
+
+ /* use previously saved settings if any */
+ netsurf_mkpath(&settings_fname, NULL, 2, nsgtk_config_home, "Print");
+ if (settings_fname != NULL) {
+ print_settings = gtk_print_settings_new_from_file(settings_fname, NULL);
+ if (print_settings != NULL) {
+ gtk_print_operation_set_print_settings(print_op,
+ print_settings);
+
+ /* We're not interested in the settings any more */
+ g_object_unref(print_settings);
+ }
+ }
+
+ content_to_print = browser_window_get_content(bw);
+
+ page_setup = gtk_print_run_page_setup_dialog(GTK_WINDOW(toplevel),
+ NULL,
+ NULL);
+ if (page_setup == NULL) {
+ nsgtk_warning(messages_get("NoMemory"), 0);
+ free(settings_fname);
+ g_object_unref(print_op);
+ return TRUE;
+ }
+ gtk_print_operation_set_default_page_setup(print_op, page_setup);
+
+ nssettings = print_make_settings(PRINT_DEFAULT,
+ NULL,
+ nsgtk_layout_table);
+
+ g_signal_connect(print_op,
+ "begin_print",
+ G_CALLBACK(gtk_print_signal_begin_print),
+ nssettings);
+ g_signal_connect(print_op,
+ "draw_page",
+ G_CALLBACK(gtk_print_signal_draw_page),
+ NULL);
+ g_signal_connect(print_op,
+ "end_print",
+ G_CALLBACK(gtk_print_signal_end_print),
+ nssettings);
+
+ if (content_get_type(browser_window_get_content(bw)) != CONTENT_TEXTPLAIN) {
+ res = gtk_print_operation_run(print_op,
+ GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+ GTK_WINDOW(toplevel),
+ NULL);
+ }
+
+ /* if the settings were used save them for future use */
+ if (settings_fname != NULL) {
+ if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+ /* Do not increment the settings reference */
+ print_settings = gtk_print_operation_get_print_settings(print_op);
+
+ gtk_print_settings_to_file(print_settings,
+ settings_fname,
+ NULL);
}
- buffer1 = strtok_r(NULL, "|", &ptr);
+ free(settings_fname);
+ }
+
+ /* Our print_settings object is destroyed by the end print handler */
+ g_object_unref(page_setup);
+ g_object_unref(print_op);
+
+ return TRUE;
+}
+
+/**
+ * handler for quit tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+quit_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding_destroy_all();
+ return TRUE;
+}
+
+
+/**
+ * handler for cut tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+cut_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *focused;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
+
+ /* let gtk handle it if focused widget is an editable */
+ if (GTK_IS_EDITABLE(focused)) {
+ gtk_editable_cut_clipboard(GTK_EDITABLE(focused));
+ } else {
+ bw = tb->get_bw(tb->get_ctx);
+ browser_window_key_press(bw, NS_KEY_CUT_SELECTION);
}
- free(buffer);
+ return TRUE;
}
/**
- * save toolbar settings to file
+ * handler for copy tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g)
+static gboolean
+copy_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- char *choices = NULL;
- char *order;
- int order_len = PLACEHOLDER_BUTTON * 12; /* length of order buffer */
- int tbidx;
- char *cur;
- int plen;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *focused;
+ GtkWidget *toplevel;
- order = malloc(order_len);
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
- if (order == NULL) {
- return NSERROR_NOMEM;
+ focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
+
+ /* let gtk handle it if focused widget is an editable */
+ if (GTK_IS_EDITABLE(focused)) {
+ gtk_editable_copy_clipboard(GTK_EDITABLE(focused));
+ } else {
+ bw = tb->get_bw(tb->get_ctx);
+ browser_window_key_press(bw, NS_KEY_COPY_SELECTION);
}
- cur = order;
- for (tbidx = BACK_BUTTON; tbidx < PLACEHOLDER_BUTTON; tbidx++) {
- plen = snprintf(cur,
- order_len,
- "%d;%d|",
- tbidx,
- nsgtk_scaffolding_button(g, tbidx)->location);
- if (plen == order_len) {
- /* ran out of space, bail early */
- NSLOG(netsurf, INFO,
- "toolbar ordering exceeded available space");
- break;
- }
- cur += plen;
- order_len -= plen;
+ return TRUE;
+}
+
+
+/**
+ * handler for paste tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+paste_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *focused;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
+
+ /* let gtk handle it if focused widget is an editable */
+ if (GTK_IS_EDITABLE(focused)) {
+ gtk_editable_paste_clipboard(GTK_EDITABLE(focused));
+ } else {
+ bw = tb->get_bw(tb->get_ctx);
+ browser_window_key_press(bw, NS_KEY_PASTE);
}
- nsoption_set_charp(toolbar_order, order);
+ return TRUE;
+}
+
+
+/**
+ * handler for delete tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+delete_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *focused;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
+
+ /* let gtk handle it if focused widget is an editable */
+ if (GTK_IS_EDITABLE(focused)) {
+ gtk_editable_delete_selection(GTK_EDITABLE(focused));
+ } else {
+ bw = tb->get_bw(tb->get_ctx);
+ browser_window_key_press(bw, NS_KEY_CLEAR_SELECTION);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for select all tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+selectall_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *focused;
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ focused = gtk_window_get_focus(GTK_WINDOW(toplevel));
+
+ /* let gtk handle it if focused widget is an editable */
+ if (GTK_IS_EDITABLE(focused)) {
+ gtk_editable_select_region(GTK_EDITABLE(focused), 0, -1);
+ } else {
+ bw = tb->get_bw(tb->get_ctx);
+ browser_window_key_press(bw, NS_KEY_SELECT_ALL);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for preferences tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+preferences_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *toplevel;
+ GtkWidget *wndpreferences;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+
+ wndpreferences = nsgtk_preferences(bw, GTK_WINDOW(toplevel));
+ if (wndpreferences != NULL) {
+ gtk_widget_show(wndpreferences);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for zoom plus tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+zoomplus_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_set_scale(bw, 0.05, false);
+
+ return TRUE;
+}
+
+
+/**
+ * handler for zoom minus tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+zoomminus_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_set_scale(bw, -0.05, false);
+
+ return TRUE;
+
+}
+
+
+/**
+ * handler for zoom normal tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+zoomnormal_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_set_scale(bw, 1.0, true);
+
+ return TRUE;
+}
+
+
+/**
+ * handler for full screen tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+fullscreen_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWindow *gtkwindow; /* gtk window widget is in */
+ GdkWindow *gdkwindow;
+ GdkWindowState state;
+
+ gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW));
+ gdkwindow = gtk_widget_get_window(GTK_WIDGET(gtkwindow));
+ state = gdk_window_get_state(gdkwindow);
+
+ if (state & GDK_WINDOW_STATE_FULLSCREEN) {
+ gtk_window_unfullscreen(gtkwindow);
+ } else {
+ gtk_window_fullscreen(gtkwindow);
+ }
+ return TRUE;
+}
+
+
+/**
+ * handler for view source tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+viewsource_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWindow *gtkwindow; /* gtk window widget is in */
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW));
+
+ res = nsgtk_viewsource(gtkwindow, bw);
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * handler for show downloads tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+downloads_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWindow *gtkwindow; /* gtk window widget is in */
+ gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW));
+ nsgtk_download_show(gtkwindow);
+ return TRUE;
+}
+
+
+/**
+ * handler for show downloads tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+savewindowsize_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWindow *gtkwindow; /* gtk window widget is in */
+ int x,y,w,h;
+ char *choices = NULL;
+
+ gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW));
+
+ gtk_window_get_position(gtkwindow, &x, &y);
+ gtk_window_get_size(gtkwindow, &w, &h);
+
+ nsoption_set_int(window_width, w);
+ nsoption_set_int(window_height, h);
+ nsoption_set_int(window_x, x);
+ nsoption_set_int(window_y, y);
- /* ensure choices are saved */
netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
}
- return NSERROR_OK;
+ return TRUE;
}
/**
- * when 'save settings' button is clicked
+ * handler for show downloads tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data)
+static gboolean
+toggledebugging_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_debug(bw, CONTENT_DEBUG_REDRAW);
+
+ nsgtk_window_update_all();
- edit_mode = false;
- /* save state to file, update toolbars for all windows */
- nsgtk_toolbar_customization_save(g);
- nsgtk_toolbar_cast(g);
- nsgtk_toolbar_set_physical(g);
- nsgtk_toolbar_close(g);
- gtk_widget_destroy(window->window);
return TRUE;
}
+
/**
- * when 'reload defaults' button is clicked
+ * handler for debug box tree tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data)
+static gboolean
+debugboxtree_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- int i;
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
- nsgtk_scaffolding_button(g, i)->location =
- (i <= THROBBER_ITEM) ? i : -1;
- nsgtk_toolbar_set_physical(g);
- for (i = BACK_BUTTON; i <= THROBBER_ITEM; i++) {
- if (i == URL_BAR_ITEM)
- continue;
- gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
- nsgtk_scaffolding_button(g, i)->button), TRUE);
- gtk_drag_source_set(GTK_WIDGET(
- nsgtk_scaffolding_button(g, i)->button),
- GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY);
- nsgtk_toolbar_temp_connect(g, i);
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ gchar *fname;
+ gint handle;
+ FILE *f;
+
+ handle = g_file_open_tmp("nsgtkboxtreeXXXXXX", &fname, NULL);
+ if ((handle == -1) || (fname == NULL)) {
+ return TRUE;
}
+ close(handle); /* in case it was binary mode */
+
+ /* save data to temporary file */
+ f = fopen(fname, "w");
+ if (f == NULL) {
+ nsgtk_warning("Error saving box tree dump.",
+ "Unable to open file for writing.");
+ unlink(fname);
+ return TRUE;
+ }
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_debug_dump(bw, f, CONTENT_DEBUG_RENDER);
+
+ fclose(f);
+
+ nsgtk_viewfile("Box Tree Debug", "boxtree", fname);
+
+ g_free(fname);
+
return TRUE;
}
+
/**
- * when titlebar / alt-F4 window close event happens
+ * handler for debug dom tree tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event,
- gpointer data)
+static gboolean
+debugdomtree_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- edit_mode = false;
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- /* reset g->buttons->location */
- for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- nsgtk_scaffolding_button(g, i)->location =
- window->buttonlocations[i];
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ gchar *fname;
+ gint handle;
+ FILE *f;
+
+ handle = g_file_open_tmp("nsgtkdomtreeXXXXXX", &fname, NULL);
+ if ((handle == -1) || (fname == NULL)) {
+ return TRUE;
}
- nsgtk_toolbar_set_physical(g);
- nsgtk_toolbar_connect_all(g);
- nsgtk_toolbar_close(g);
- nsgtk_scaffolding_set_sensitivity(g);
- gtk_widget_destroy(window->window);
+ close(handle); /* in case it was binary mode */
+
+ /* save data to temporary file */
+ f = fopen(fname, "w");
+ if (f == NULL) {
+ nsgtk_warning("Error saving box tree dump.",
+ "Unable to open file for writing.");
+ unlink(fname);
+ return TRUE;
+ }
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ browser_window_debug_dump(bw, f, CONTENT_DEBUG_DOM);
+
+ fclose(f);
+
+ nsgtk_viewfile("DOM Tree Debug", "domtree", fname);
+
+ g_free(fname);
+
return TRUE;
+
}
+
/**
- * called when a widget is dropped onto the store window
+ * handler for local history tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
static gboolean
-nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc,
- gint x, gint y, guint time, gpointer data)
+localhistory_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;
- int q, i;
+ nserror res;
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+ GtkWidget *toplevel;
- if ((window->fromstore) || (window->currentbutton == -1)) {
- window->currentbutton = -1;
- return FALSE;
- }
- if (nsgtk_scaffolding_button(g, window->currentbutton)->location
- != -1) {
- /* 'move' all widgets further right, one place to the left
- * in logical schema */
- for (i = nsgtk_scaffolding_button(g, window->currentbutton)->
- location + 1; i < PLACEHOLDER_BUTTON; i++) {
- q = nsgtk_toolbar_get_id_at_location(g, i);
- if (q == -1)
- continue;
- nsgtk_scaffolding_button(g, q)->location--;
+ toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+ if (toplevel != NULL) {
+ bw = tb->get_bw(tb->get_ctx);
+
+ res = nsgtk_local_history_present(GTK_WINDOW(toplevel), bw);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to present local history window.");
}
- gtk_container_remove(GTK_CONTAINER(
- nsgtk_scaffolding_toolbar(g)), GTK_WIDGET(
- nsgtk_scaffolding_button(g,
- window->currentbutton)->button));
- nsgtk_scaffolding_button(g, window->currentbutton)->location
- = -1;
- }
- window->currentbutton = -1;
- gtk_drag_finish(gdc, TRUE, TRUE, time);
- return FALSE;
+ }
+ return TRUE;
}
/**
- * called when hovering above the store
+ * handler for history tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
static gboolean
-nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
- gint x, gint y, guint time, gpointer data)
+history_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- return FALSE;
+ return localhistory_button_clicked_cb(widget, data);
}
+
/**
- * create store window
+ * handler for global history tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
*/
-static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g)
+static gboolean
+globalhistory_button_clicked_cb(GtkWidget *widget, gpointer data)
{
- struct nsgtk_theme *theme;
nserror res;
+ res = nsgtk_global_history_present();
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to initialise global history window.");
+ }
+ return TRUE;
+}
- theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, true);
- if (theme == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- nsgtk_toolbar_cancel_clicked(NULL, g);
- return;
+
+/**
+ * handler for add bookmark tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+addbookmarks_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct browser_window *bw;
+
+ bw = tb->get_bw(tb->get_ctx);
+ if (browser_window_has_content(bw)) {
+ hotlist_add_url(browser_window_access_url(bw));
}
+ return TRUE;
+}
+
- res = nsgtk_builder_new_from_resname("toolbar", &window->builder);
+/**
+ * handler for show bookmark tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+showbookmarks_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ res = nsgtk_hotlist_present();
if (res != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Toolbar UI builder init failed");
- nsgtk_warning("Toolbar UI builder init failed", 0);
- nsgtk_toolbar_cancel_clicked(NULL, g);
- free(theme);
- return;
+ NSLOG(netsurf, INFO, "Unable to initialise bookmark window.");
}
+ return TRUE;
+}
- gtk_builder_connect_signals(window->builder, NULL);
- window->window = GTK_WIDGET(gtk_builder_get_object(
- window->builder, "dialogToolbar"));
- if (window->window == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- nsgtk_toolbar_cancel_clicked(NULL, g);
- free(theme);
- return;
+/**
+ * handler for show cookies tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+showcookies_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ nserror res;
+ res = nsgtk_cookies_present(NULL);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to initialise cookies window.");
}
+ return TRUE;
+}
- gtk_window_set_transient_for(GTK_WINDOW(window->window),
- nsgtk_scaffolding_window(g));
- window->widgetvbox = GTK_WIDGET(gtk_builder_get_object(
- window->builder, "widgetvbox"));
- if (window->widgetvbox == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- nsgtk_toolbar_cancel_clicked(NULL, g);
- free(theme);
- return;
+/**
+ * handler for open location tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+openlocation_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ GtkToolItem *urltitem;
+
+ urltitem = tb->items[URL_BAR_ITEM].button;
+ if (urltitem != NULL) {
+ GtkEntry *entry;
+ entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(urltitem)));
+ gtk_widget_grab_focus(GTK_WIDGET(entry));
}
+ return TRUE;
+}
- /* preset to width [in buttons] of */
- window->numberh = NSGTK_STORE_WIDTH;
- /* store to cause creation of a new toolbar */
- window->currentbutton = -1;
+/**
+ * handler for contents tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+contents_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ nserror res;
- /* load toolbuttons */
- /* add toolbuttons to window */
- /* set event handlers */
- for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- if (i == URL_BAR_ITEM)
- continue;
- window->store_buttons[i] =
- nsgtk_toolbar_make_widget(g, i, theme);
- if (window->store_buttons[i] == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- continue;
- }
- nsgtk_toolbar_add_store_widget(window->store_buttons[i]);
- g_signal_connect(window->store_buttons[i], "drag-data-get",
- G_CALLBACK(
- nsgtk_scaffolding_button(g, i)->dataplus), g);
+ res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/");
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
+
+ return TRUE;
+}
+
+/**
+ * handler for contents tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+guide_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ nserror res;
+
+ res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/guide");
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
}
- free(theme);
+ return TRUE;
+}
+
+
+/**
+ * handler for contents tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean
+info_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ nserror res;
- gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE);
+ res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/info");
+ if (res != NSERROR_OK) {
+ nsgtk_warning(messages_get_errorcode(res), 0);
+ }
- gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION |
- GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY);
+ return TRUE;
+}
- g_signal_connect(GTK_WIDGET(gtk_builder_get_object(
- window->builder, "close")),
- "clicked",
- G_CALLBACK(nsgtk_toolbar_persist),
- g);
- g_signal_connect(GTK_WIDGET(gtk_builder_get_object(
- window->builder, "reset")),
- "clicked",
- G_CALLBACK(nsgtk_toolbar_reset),
- g);
+/**
+ * handler for contents tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE
+ */
+static gboolean about_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ GtkWindow *parent; /* gtk window widget is in */
+
+ parent = GTK_WINDOW(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW));
+
+ nsgtk_about_dialog_init(parent);
+ return TRUE;
+}
+
+/**
+ * handler for openmenu tool bar item clicked signal
+ *
+ * \param widget The widget the signal is being delivered to.
+ * \param data The toolbar context passed when the signal was connected
+ * \return TRUE to indicate signal handled.
+ */
+static gboolean openmenu_button_clicked_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct gui_window *gw;
+ struct nsgtk_scaffolding *gs;
+
+ gw = tb->get_ctx; /** \todo stop assuming the context is a gui window */
- g_signal_connect(window->window, "delete-event",
- G_CALLBACK(nsgtk_toolbar_delete), g);
+ gs = nsgtk_get_scaffold(gw);
- g_signal_connect(window->window, "drag-drop",
- G_CALLBACK(nsgtk_toolbar_store_return), g);
+ nsgtk_scaffolding_burger_menu(gs);
+
+ return TRUE;
+}
- g_signal_connect(window->window, "drag-motion",
- G_CALLBACK(nsgtk_toolbar_store_action), g);
- gtk_widget_show_all(window->window);
+/* define data plus and data minus handlers */
+#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \
+static gboolean \
+nsgtk_toolbar_##name##_data_plus(GtkWidget *widget, \
+ GdkDragContext *cont, \
+ GtkSelectionData *selection, \
+ guint info, \
+ guint time, \
+ gpointer data) \
+{ \
+ struct nsgtk_toolbar_customisation *tbc; \
+ tbc = (struct nsgtk_toolbar_customisation *)data; \
+ tbc->dragitem = identifier; \
+ tbc->dragfrom = true; \
+ return TRUE; \
+} \
+static gboolean \
+nsgtk_toolbar_##name##_data_minus(GtkWidget *widget, \
+ GdkDragContext *cont, \
+ GtkSelectionData *selection, \
+ guint info, \
+ guint time, \
+ gpointer data) \
+{ \
+ struct nsgtk_toolbar_customisation *tbc; \
+ tbc = (struct nsgtk_toolbar_customisation *)data; \
+ tbc->dragitem = identifier; \
+ tbc->dragfrom = false; \
+ return TRUE; \
}
+#include "gtk/toolbar_items.h"
+
+#undef TOOLBAR_ITEM
+
+
/**
- * change behaviour of scaffoldings while editing toolbar
+ * create a toolbar item
*
- * All buttons as well as window clicks are desensitized; then buttons
- * in the front window are changed to movable buttons
+ * create a toolbar item and set up its default handlers
*/
-void nsgtk_toolbar_customization_init(struct nsgtk_scaffolding *g)
+static nserror
+toolbar_item_create(nsgtk_toolbar_button id, struct nsgtk_toolbar_item *item)
{
- int i;
- struct nsgtk_scaffolding *list;
- edit_mode = true;
+ item->location = INACTIVE_LOCATION;
+
+ /* set item defaults from macro */
+ switch (id) {
+#define TOOLBAR_ITEM_t(name) \
+ item->clicked = name##_button_clicked_cb;
+#define TOOLBAR_ITEM_b(name) \
+ item->clicked = name##_button_clicked_cb;
+#define TOOLBAR_ITEM_y(name) \
+ item->clicked = name##_button_clicked_cb;
+#define TOOLBAR_ITEM_n(name) \
+ item->clicked = NULL;
+#define TOOLBAR_ITEM(identifier, iname, snstvty, clicked, activate, label, iconame) \
+ case identifier: \
+ item->name = #iname; \
+ item->sensitivity = snstvty; \
+ item->dataplus = nsgtk_toolbar_##iname##_data_plus; \
+ item->dataminus = nsgtk_toolbar_##iname##_data_minus; \
+ TOOLBAR_ITEM_ ## clicked(iname) \
+ break;
- list = nsgtk_scaffolding_iterate(NULL);
- while (list) {
- g_signal_handler_block(GTK_WIDGET(
- nsgtk_window_get_layout(
- nsgtk_scaffolding_top_level(list))),
- nsgtk_window_get_signalhandler(
- nsgtk_scaffolding_top_level(list),
- NSGTK_WINDOW_SIGNAL_CLICK));
- g_signal_handler_block(GTK_WIDGET(
- nsgtk_window_get_layout(
- nsgtk_scaffolding_top_level(list))),
- nsgtk_window_get_signalhandler(
- nsgtk_scaffolding_top_level(list),
- NSGTK_WINDOW_SIGNAL_REDRAW));
- nsgtk_widget_override_background_color(
- GTK_WIDGET(nsgtk_window_get_layout(
- nsgtk_scaffolding_top_level(list))),
- GTK_STATE_NORMAL, 0, 0xEEEE, 0xEEEE, 0xEEEE);
+#include "gtk/toolbar_items.h"
- if (list == g) {
- list = nsgtk_scaffolding_iterate(list);
- continue;
- }
- /* set sensitive for all gui_windows save g */
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_window(
- list)), FALSE);
- list = nsgtk_scaffolding_iterate(list);
- }
- /* set sensitive for all of g save toolbar */
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)),
- FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)),
- FALSE);
-
- /* set editable aspect for toolbar */
- gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)),
- nsgtk_toolbar_clear_toolbar, g);
- nsgtk_toolbar_set_physical(g);
- /* memorize button locations, set editable */
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- window->buttonlocations[i] = nsgtk_scaffolding_button(g, i)
- ->location;
- if ((window->buttonlocations[i] == -1) || (i == URL_BAR_ITEM))
- continue;
- gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
- nsgtk_scaffolding_button(g, i)->button), TRUE);
- gtk_drag_source_set(GTK_WIDGET(nsgtk_scaffolding_button(
- g, i)->button), GDK_BUTTON1_MASK, &entry, 1,
- GDK_ACTION_COPY);
- nsgtk_toolbar_temp_connect(g, i);
+#undef TOOLBAR_ITEM_t
+#undef TOOLBAR_ITEM_y
+#undef TOOLBAR_ITEM_n
+#undef TOOLBAR_ITEM
+
+ case PLACEHOLDER_BUTTON:
+ return NSERROR_INVALID;
}
- /* add move button listeners */
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
- "drag-drop", G_CALLBACK(nsgtk_toolbar_data), g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
- "drag-data-received", G_CALLBACK(
- nsgtk_toolbar_move_complete), g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
- "drag-motion", G_CALLBACK(nsgtk_toolbar_action), g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
- "drag-leave", G_CALLBACK(
- nsgtk_toolbar_clear), g);
+ return NSERROR_OK;
+}
- /* set data types */
- gtk_drag_dest_set(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
- GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
- &entry, 1, GDK_ACTION_COPY);
- /* open toolbar window */
- nsgtk_toolbar_window_open(g);
+/**
+ * set a toolbar item to a throbber frame number
+ *
+ * \param toolbar_item The toolbar item to update
+ * \param frame The animation frame number to update to
+ * \return NSERROR_OK on success,
+ * NSERROR_INVALID if the toolbar item does not contain an image,
+ * NSERROR_BAD_SIZE if the frame is out of range.
+ */
+static nserror set_throbber_frame(GtkToolItem *toolbar_item, int frame)
+{
+ nserror res;
+ GdkPixbuf *pixbuf;
+ GtkImage *throbber;
+
+ if (toolbar_item == NULL) {
+ /* no toolbar item */
+ return NSERROR_INVALID;
+ }
+
+ res = nsgtk_throbber_get_frame(frame, &pixbuf);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ throbber = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(toolbar_item)));
+
+ gtk_image_set_from_pixbuf(throbber, pixbuf);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Make the throbber run.
+ *
+ * scheduled callback to update the throbber
+ *
+ * \param p The context passed when scheduled.
+ */
+static void next_throbber_frame(void *p)
+{
+ struct nsgtk_toolbar *tb = p;
+ nserror res;
+
+ tb->throb_frame++; /* advance to next frame */
+
+ res = set_throbber_frame(tb->items[THROBBER_ITEM].button,
+ tb->throb_frame);
+ if (res == NSERROR_BAD_SIZE) {
+ tb->throb_frame = 1;
+ res = set_throbber_frame(tb->items[THROBBER_ITEM].button,
+ tb->throb_frame);
+ }
+
+ /* only schedule next frame if there are no errors */
+ if (res == NSERROR_OK) {
+ nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, p);
+ }
}
+
/**
- * set toolbar logical -> physical; physically visible toolbar buttons are made
- * to correspond to the logically stored schema in terms of location
- * visibility etc
+ * connect signal handlers to a gtk toolbar item
*/
-void nsgtk_toolbar_set_physical(struct nsgtk_scaffolding *g)
+static nserror
+toolbar_connect_signal(struct nsgtk_toolbar *tb, nsgtk_toolbar_button itemid)
{
- int i;
- struct nsgtk_theme *theme;
+ struct nsgtk_toolbar_item *item;
+ GtkEntry *entry;
- theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false);
- if (theme == NULL) {
- nsgtk_warning(messages_get("NoMemory"), 0);
- return;
+ item = &tb->items[itemid];
+
+ if (item->button != NULL) {
+ g_signal_connect(item->button,
+ "size-allocate",
+ G_CALLBACK(toolbar_item_size_allocate_cb),
+ tb);
}
- /* simplest is to clear the toolbar then reload it from memory */
- gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)),
- nsgtk_toolbar_clear_toolbar, g);
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- nsgtk_toolbar_add_item_to_toolbar(g, i, theme);
+
+ switch (itemid) {
+ case URL_BAR_ITEM:
+ entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->button)));
+
+ g_signal_connect(GTK_WIDGET(entry),
+ "activate",
+ G_CALLBACK(url_entry_activate_cb),
+ tb);
+ g_signal_connect(GTK_WIDGET(entry),
+ "changed",
+ G_CALLBACK(url_entry_changed_cb),
+ tb);
+ g_signal_connect(GTK_WIDGET(entry),
+ "icon-release",
+ G_CALLBACK(url_entry_icon_release_cb),
+ tb);
+
+ nsgtk_completion_connect_signals(entry,
+ tb->get_bw,
+ tb->get_ctx);
+ break;
+
+
+ case WEBSEARCH_ITEM:
+ entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->button)));
+
+ g_signal_connect(GTK_WIDGET(entry),
+ "activate",
+ G_CALLBACK(websearch_entry_activate_cb),
+ tb);
+ g_signal_connect(GTK_WIDGET(entry),
+ "button-press-event",
+ G_CALLBACK(websearch_entry_button_press_cb),
+ tb);
+ break;
+
+ default:
+ if ((item->clicked != NULL) && (item->button != NULL)) {
+ g_signal_connect(item->button,
+ "clicked",
+ G_CALLBACK(item->clicked),
+ tb);
+ }
+ break;
+
}
- gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)));
- free(theme);
+
+ return NSERROR_OK;
}
/**
- * \return toolbar item id when a widget is an element of the scaffolding
- * else -1
+ * connect all signals to widgets in a toolbar
*/
-int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget,
- struct nsgtk_scaffolding *g)
+static nserror toolbar_connect_signals(struct nsgtk_toolbar *tb)
{
- int i;
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- if ((nsgtk_scaffolding_button(g, i)->location != -1)
- && (widget == GTK_WIDGET(
- nsgtk_scaffolding_button(g, i)->button))) {
- return i;
+ int location; /* location index */
+ nsgtk_toolbar_button itemid; /* item id */
+
+ for (location = BACK_BUTTON; location < PLACEHOLDER_BUTTON; location++) {
+ itemid = itemid_from_location(tb, location);
+ if (itemid == PLACEHOLDER_BUTTON) {
+ /* no more filled locations */
+ break;
}
+ toolbar_connect_signal(tb, itemid);
}
- return -1;
+
+ return NSERROR_OK;
}
/**
- * add handlers to factory widgets
- * \param g the scaffolding to attach handlers to
- * \param i the toolbar item id
+ * signal handler for toolbar context menu
+ *
+ * \param toolbar The toolbar event is being delivered to
+ * \param x The x coordinate where the click happened
+ * \param y The x coordinate where the click happened
+ * \param button the buttons being pressed
+ * \param data The context pointer passed when the connection was made.
+ * \return TRUE to indicate signal handled.
*/
-static void
-nsgtk_toolbar_set_handler(struct nsgtk_scaffolding *g, nsgtk_toolbar_button i)
+static gboolean
+toolbar_popup_context_menu_cb(GtkToolbar *toolbar,
+ gint x,
+ gint y,
+ gint button,
+ gpointer data)
{
- switch(i){
- case URL_BAR_ITEM:
- nsgtk_scaffolding_update_url_bar_ref(g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
- "activate", G_CALLBACK(
- nsgtk_window_url_activate_event), g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
- "changed", G_CALLBACK(
- nsgtk_window_url_changed), g);
+ struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data;
+ struct gui_window *gw;
+ struct nsgtk_scaffolding *gs;
+
+ gw = tb->get_ctx; /** \todo stop assuming the context is a gui window */
+
+ gs = nsgtk_get_scaffold(gw);
+
+ nsgtk_scaffolding_toolbar_context_menu(gs);
+
+ return TRUE;
+}
+
+
+/**
+ * toolbar delete signal handler
+ */
+static void toolbar_destroy_cb(GtkWidget *widget, gpointer data)
+{
+ struct nsgtk_toolbar *tb;
+ tb = (struct nsgtk_toolbar *)data;
+
+ /* ensure any throbber scheduled is stopped */
+ nsgtk_schedule(-1, next_throbber_frame, tb);
+
+ free(tb);
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror
+nsgtk_toolbar_create(GtkBuilder *builder,
+ struct browser_window *(*get_bw)(void *ctx),
+ void *get_ctx,
+ bool want_location_focus,
+ struct nsgtk_toolbar **tb_out)
+{
+ nserror res;
+ struct nsgtk_toolbar *tb;
+ int bidx; /* button index */
+
+ tb = calloc(1, sizeof(struct nsgtk_toolbar));
+ if (tb == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ tb->get_bw = get_bw;
+ tb->get_ctx = get_ctx;
+ /* set the throbber start frame. */
+ tb->throb_frame = 0;
+ if (want_location_focus) {
+ tb->loc_focus = LFS_WANT;
+ } else {
+ tb->loc_focus = LFS_IDLE;
+ }
+
+ tb->widget = GTK_TOOLBAR(gtk_builder_get_object(builder, "toolbar"));
+ gtk_toolbar_set_show_arrow(tb->widget, TRUE);
+
+ g_signal_connect(tb->widget,
+ "popup-context-menu",
+ G_CALLBACK(toolbar_popup_context_menu_cb),
+ tb);
+
+ /* close and cleanup on delete signal */
+ g_signal_connect(tb->widget,
+ "destroy",
+ G_CALLBACK(toolbar_destroy_cb),
+ tb);
+
+ /* allocate button contexts */
+ for (bidx = BACK_BUTTON; bidx < PLACEHOLDER_BUTTON; bidx++) {
+ res = toolbar_item_create(bidx, &tb->items[bidx]);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ }
+
+ res = nsgtk_toolbar_update(tb);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ *tb_out = tb;
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_restyle(struct nsgtk_toolbar *tb)
+{
+ /*
+ * reset toolbar size allocation so icon size change affects
+ * allocated widths.
+ */
+ tb->offset = 0;
+
+ switch (nsoption_int(button_type)) {
+
+ case 1: /* Small icons */
+ gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget),
+ GTK_TOOLBAR_ICONS);
+ gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget),
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
break;
- case THROBBER_ITEM:
- nsgtk_scaffolding_update_throbber_ref(g);
+ case 2: /* Large icons */
+ gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget),
+ GTK_TOOLBAR_ICONS);
+ gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget),
+ GTK_ICON_SIZE_LARGE_TOOLBAR);
break;
- case WEBSEARCH_ITEM:
- nsgtk_scaffolding_update_websearch_ref(g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
- "activate", G_CALLBACK(
- nsgtk_websearch_activate), g);
- g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
- "button-press-event", G_CALLBACK(
- nsgtk_websearch_clear), g);
+ case 3: /* Large icons with text */
+ gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget),
+ GTK_TOOLBAR_BOTH);
+ gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget),
+ GTK_ICON_SIZE_LARGE_TOOLBAR);
+ break;
+
+ case 4: /* Text icons only */
+ gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget),
+ GTK_TOOLBAR_TEXT);
break;
default:
- if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) &&
- (nsgtk_scaffolding_button(g, i)->button != NULL)) {
- g_signal_connect(
- nsgtk_scaffolding_button(g, i)->button,
- "clicked",
- G_CALLBACK(nsgtk_scaffolding_button(
- g, i)->bhandler), g);
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_throbber(struct nsgtk_toolbar *tb, bool active)
+{
+ nserror res;
+ struct browser_window *bw;
+
+ /* Manage the location focus state */
+ switch (tb->loc_focus) {
+ case LFS_IDLE:
+ break;
+ case LFS_WANT:
+ if (active) {
+ tb->loc_focus = LFS_THROB;
+ }
+ break;
+ case LFS_THROB:
+ if (!active) {
+ tb->loc_focus = LFS_LAST;
}
break;
+ case LFS_LAST:
+ break;
+ }
+
+ /* when activating the throbber simply schedule the next frame update */
+ if (active) {
+ nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, tb);
+
+ set_item_sensitivity(&tb->items[STOP_BUTTON], true);
+ set_item_sensitivity(&tb->items[RELOAD_BUTTON], false);
+ set_item_action(tb, RELOADSTOP_BUTTON, false);
+
+ return NSERROR_OK;
+ }
+
+ /* stopping the throbber */
+ nsgtk_schedule(-1, next_throbber_frame, tb);
+ tb->throb_frame = 0;
+ res = set_throbber_frame(tb->items[THROBBER_ITEM].button,
+ tb->throb_frame);
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ /* adjust sensitivity of other items */
+ set_item_sensitivity(&tb->items[STOP_BUTTON], false);
+ set_item_sensitivity(&tb->items[RELOAD_BUTTON], true);
+ set_item_action(tb, RELOADSTOP_BUTTON, true);
+ set_item_sensitivity(&tb->items[BACK_BUTTON],
+ browser_window_history_back_available(bw));
+ set_item_sensitivity(&tb->items[FORWARD_BUTTON],
+ browser_window_history_forward_available(bw));
+ nsgtk_local_history_hide();
+
+ return res;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_page_info_change(struct nsgtk_toolbar *tb)
+{
+ GtkEntry *url_entry;
+ browser_window_page_info_state pistate;
+ struct browser_window *bw;
+ const char *icon_name;
+
+ if (tb->items[URL_BAR_ITEM].button == NULL) {
+ /* no toolbar item */
+ return NSERROR_INVALID;
+ }
+ url_entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tb->items[URL_BAR_ITEM].button)));
+
+ bw = tb->get_bw(tb->get_ctx);
+
+ pistate = browser_window_get_page_info_state(bw);
+
+ switch (pistate) {
+ case PAGE_STATE_INTERNAL:
+ icon_name = "page-info-internal";
+ break;
+
+ case PAGE_STATE_LOCAL:
+ icon_name = "page-info-local";
+ break;
+
+ case PAGE_STATE_INSECURE:
+ icon_name = "page-info-insecure";
+ break;
+
+ case PAGE_STATE_SECURE_OVERRIDE:
+ icon_name = "page-info-warning";
+ break;
+
+ case PAGE_STATE_SECURE_ISSUES:
+ icon_name = "page-info-warning";
+ break;
+
+ case PAGE_STATE_SECURE:
+ icon_name = "page-info-secure";
+ break;
+
+ default:
+ icon_name = "page-info-internal";
+ break;
+ }
+
+ nsgtk_entry_set_icon_from_icon_name(GTK_WIDGET(url_entry),
+ GTK_ENTRY_ICON_PRIMARY,
+ icon_name);
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_set_url(struct nsgtk_toolbar *tb, nsurl *url)
+{
+ size_t idn_url_l;
+ char *idn_url_s = NULL;
+ const char *url_text = NULL;
+ GtkEntry *url_entry;
+
+ if (tb->items[URL_BAR_ITEM].button == NULL) {
+ /* no toolbar item */
+ return NSERROR_INVALID;
+ }
+ url_entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tb->items[URL_BAR_ITEM].button)));
+
+ if (nsoption_bool(display_decoded_idn) == true) {
+ if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) {
+ idn_url_s = NULL;
+ }
+ url_text = idn_url_s;
+ }
+ if (url_text == NULL) {
+ url_text = nsurl_access(url);
+ }
+
+ if (strcmp(url_text, gtk_entry_get_text(url_entry)) != 0) {
+ /* The URL bar content has changed, we need to update it */
+ gint startpos, endpos;
+ bool was_selected;
+ gtk_editable_get_selection_bounds(GTK_EDITABLE(url_entry),
+ &startpos, &endpos);
+ was_selected = gtk_widget_is_focus(GTK_WIDGET(url_entry)) &&
+ startpos == 0 &&
+ endpos == gtk_entry_get_text_length(url_entry);
+ gtk_entry_set_text(url_entry, url_text);
+ if (was_selected && tb->loc_focus != LFS_IDLE) {
+ gtk_widget_grab_focus(GTK_WIDGET(url_entry));
+ if (tb->loc_focus == LFS_LAST) {
+ tb->loc_focus = LFS_IDLE;
+ }
+ }
}
+
+ if (idn_url_s != NULL) {
+ free(idn_url_s);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror
+nsgtk_toolbar_set_websearch_image(struct nsgtk_toolbar *tb, GdkPixbuf *pixbuf)
+{
+ GtkWidget *entry;
+
+ if (tb->items[WEBSEARCH_ITEM].button == NULL) {
+ /* no toolbar item */
+ return NSERROR_INVALID;
+ }
+
+ entry = gtk_bin_get_child(GTK_BIN(tb->items[WEBSEARCH_ITEM].button));
+
+ if (pixbuf != NULL) {
+ nsgtk_entry_set_icon_from_pixbuf(entry,
+ GTK_ENTRY_ICON_PRIMARY,
+ pixbuf);
+ } else {
+ nsgtk_entry_set_icon_from_icon_name(entry,
+ GTK_ENTRY_ICON_PRIMARY,
+ NSGTK_STOCK_INFO);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror
+nsgtk_toolbar_item_activate(struct nsgtk_toolbar *tb,
+ nsgtk_toolbar_button itemid)
+{
+ GtkWidget *widget;
+
+ /* ensure item id in range */
+ if ((itemid < BACK_BUTTON) || (itemid >= PLACEHOLDER_BUTTON)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ if (tb->items[itemid].clicked == NULL) {
+ return NSERROR_INVALID;
+ }
+
+ /*
+ * if item has a widget in the current toolbar use that as the
+ * signal source otherwise use the toolbar widget itself.
+ */
+ if (tb->items[itemid].button != NULL) {
+ widget = GTK_WIDGET(tb->items[itemid].button);
+ } else {
+ widget = GTK_WIDGET(tb->widget);
+ }
+
+ tb->items[itemid].clicked(widget, tb);
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_show(struct nsgtk_toolbar *tb, bool show)
+{
+ if (show) {
+ gtk_widget_show(GTK_WIDGET(tb->widget));
+ } else {
+ gtk_widget_hide(GTK_WIDGET(tb->widget));
+ }
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_update(struct nsgtk_toolbar *tb)
+{
+ nserror res;
+
+ /* setup item locations based on user config */
+ res = apply_user_button_customisation(tb);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* populate toolbar widget */
+ res = populate_gtk_toolbar_widget(tb);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* ensure icon sizes and text labels on toolbar are set */
+ res = nsgtk_toolbar_restyle(tb);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ res = toolbar_connect_signals(tb);
+
+ return res;
}
/**
- * connect 'normal' handlers to toolbar buttons
+ * Find the correct location for popping up a window for the chosen item.
+ *
+ * \param tb The toolbar to select from
+ * \param item_idx The toolbar item to select from
+ * \param out_x Filled with an appropriate X coordinate
+ * \param out_y Filled with an appropriate Y coordinate
*/
-void nsgtk_toolbar_connect_all(struct nsgtk_scaffolding *g)
+static nserror
+nsgtk_toolbar_get_icon_window_position(struct nsgtk_toolbar *tb,
+ int item_idx,
+ int *out_x,
+ int *out_y)
{
- int q, i;
- for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
- q = nsgtk_toolbar_get_id_at_location(g, i);
- if (q == -1)
- continue;
- if (nsgtk_scaffolding_button(g, q)->button != NULL)
- g_signal_connect(
- nsgtk_scaffolding_button(g, q)->button,
- "size-allocate", G_CALLBACK(
- nsgtk_scaffolding_toolbar_size_allocate
- ), g);
- nsgtk_toolbar_set_handler(g, q);
- }
-}
-
-
-#define DATAHANDLER(p, q, r)\
-gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\
- *cont, GtkSelectionData *selection, guint info, guint time,\
- gpointer data)\
-{\
- r->currentbutton = q##_BUTTON;\
- r->fromstore = true;\
- return TRUE;\
-}\
-gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\
- GdkDragContext *cont, GtkSelectionData *selection, guint info,\
- guint time, gpointer data)\
-{\
- r->currentbutton = q##_BUTTON;\
- r->fromstore = false;\
- return TRUE;\
-}
-
-DATAHANDLER(home, HOME, window)
-DATAHANDLER(forward, FORWARD, window)
-DATAHANDLER(back, BACK, window)
-DATAHANDLER(stop, STOP, window)
-DATAHANDLER(reload, RELOAD, window)
-DATAHANDLER(history, HISTORY, window)
-DATAHANDLER(newwindow, NEWWINDOW, window)
-DATAHANDLER(newtab, NEWTAB, window)
-DATAHANDLER(openfile, OPENFILE, window)
-DATAHANDLER(closetab, CLOSETAB, window)
-DATAHANDLER(closewindow, CLOSEWINDOW, window)
-DATAHANDLER(savepage, SAVEPAGE, window)
-DATAHANDLER(printpreview, PRINTPREVIEW, window)
-DATAHANDLER(print, PRINT, window)
-DATAHANDLER(quit, QUIT, window)
-DATAHANDLER(cut, CUT, window)
-DATAHANDLER(copy, COPY, window)
-DATAHANDLER(paste, PASTE, window)
-DATAHANDLER(delete, DELETE, window)
-DATAHANDLER(selectall, SELECTALL, window)
-DATAHANDLER(preferences, PREFERENCES, window)
-DATAHANDLER(zoomplus, ZOOMPLUS, window)
-DATAHANDLER(zoomminus, ZOOMMINUS, window)
-DATAHANDLER(zoomnormal, ZOOMNORMAL, window)
-DATAHANDLER(fullscreen, FULLSCREEN, window)
-DATAHANDLER(viewsource, VIEWSOURCE, window)
-DATAHANDLER(contents, CONTENTS, window)
-DATAHANDLER(about, ABOUT, window)
-DATAHANDLER(pdf, PDF, window)
-DATAHANDLER(plaintext, PLAINTEXT, window)
-DATAHANDLER(drawfile, DRAWFILE, window)
-DATAHANDLER(postscript, POSTSCRIPT, window)
-DATAHANDLER(find, FIND, window)
-DATAHANDLER(downloads, DOWNLOADS, window)
-DATAHANDLER(savewindowsize, SAVEWINDOWSIZE, window)
-DATAHANDLER(toggledebugging, TOGGLEDEBUGGING, window)
-DATAHANDLER(debugboxtree, SAVEBOXTREE, window)
-DATAHANDLER(debugdomtree, SAVEDOMTREE, window)
-DATAHANDLER(localhistory, LOCALHISTORY, window)
-DATAHANDLER(globalhistory, GLOBALHISTORY, window)
-DATAHANDLER(addbookmarks, ADDBOOKMARKS, window)
-DATAHANDLER(showbookmarks, SHOWBOOKMARKS, window)
-DATAHANDLER(showcookies, SHOWCOOKIES, window)
-DATAHANDLER(openlocation, OPENLOCATION, window)
-DATAHANDLER(nexttab, NEXTTAB, window)
-DATAHANDLER(prevtab, PREVTAB, window)
-DATAHANDLER(guide, GUIDE, window)
-DATAHANDLER(info, INFO, window)
-#undef DATAHANDLER
-
-#define DATAHANDLER(p, q, r) \
-gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\
- *cont, GtkSelectionData *selection, guint info, guint time,\
- gpointer data)\
-{\
- r->currentbutton = q##_ITEM;\
- r->fromstore = true;\
- return TRUE;\
-}\
-gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\
- GdkDragContext *cont, GtkSelectionData *selection, guint info,\
- guint time, gpointer data)\
-{\
- r->currentbutton = q##_ITEM;\
- r->fromstore = false;\
- return TRUE;\
-}
-
-DATAHANDLER(throbber, THROBBER, window)
-DATAHANDLER(websearch, WEBSEARCH, window)
-#undef DATAHANDLER
+ struct nsgtk_toolbar_item *item = &tb->items[item_idx];
+ GtkWidget *widget = GTK_WIDGET(item->button);
+ GtkAllocation alloc;
+ gint rootx, rooty, x, y;
+
+ switch (item_idx) {
+ case URL_BAR_ITEM:
+ widget = GTK_WIDGET(gtk_bin_get_child(GTK_BIN(item->button)));
+ break;
+ default:
+ /* Nothing to do here */
+ break;
+ }
+
+ nsgtk_widget_get_allocation(widget, &alloc);
+
+ if (gtk_widget_translate_coordinates(widget,
+ gtk_widget_get_toplevel(widget),
+ 0,
+ alloc.height - 1,
+ &x, &y) != TRUE) {
+ return NSERROR_UNKNOWN;
+ }
+
+ gtk_window_get_position(GTK_WINDOW(gtk_widget_get_toplevel(widget)),
+ &rootx, &rooty);
+
+ *out_x = rootx + x + 4;
+ *out_y = rooty + y + 4;
+
+ return NSERROR_OK;
+}
+
+nserror nsgtk_toolbar_position_page_info(struct nsgtk_toolbar *tb,
+ struct nsgtk_pi_window *win)
+{
+ nserror res;
+ int x, y;
+
+ res = nsgtk_toolbar_get_icon_window_position(tb, URL_BAR_ITEM, &x, &y);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ nsgtk_page_info_set_position(win, x, y);
+
+ return NSERROR_OK;
+}
+
+/* exported interface documented in toolbar.h */
+nserror nsgtk_toolbar_position_local_history(struct nsgtk_toolbar *tb)
+{
+ nserror res;
+ int x, y;
+
+ res = nsgtk_toolbar_get_icon_window_position(tb, HISTORY_BUTTON, &x, &y);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ nsgtk_local_history_set_position(x, y);
+
+ return NSERROR_OK;
+}