summaryrefslogtreecommitdiff
path: root/gtk/toolbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/toolbar.c')
-rw-r--r--gtk/toolbar.c1113
1 files changed, 1113 insertions, 0 deletions
diff --git a/gtk/toolbar.c b/gtk/toolbar.c
new file mode 100644
index 000000000..b8ad9bcdb
--- /dev/null
+++ b/gtk/toolbar.c
@@ -0,0 +1,1113 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include "desktop/searchweb.h"
+#include "gtk/toolbar.h"
+#include "gtk/gui.h"
+#include "gtk/scaffolding.h"
+#include "gtk/search.h"
+#include "gtk/theme.h"
+#include "gtk/throbber.h"
+#include "gtk/window.h"
+#include "gtk/sexy_icon_entry.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.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 */
+ GladeXML *glade; /* 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
+
+/* the 'standard' width of a button that makes sufficient of its label
+visible */
+#define NSGTK_BUTTON_WIDTH 111
+
+/* 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 */
+#define NSGTK_WEBSEARCH_WIDTH 150
+
+static struct nsgtk_toolbar_custom_store store;
+static struct nsgtk_toolbar_custom_store *window = &store;
+
+static void nsgtk_toolbar_close(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_window_open(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i,
+ struct nsgtk_theme *theme);
+static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget);
+static gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext
+ *drag_context, gint x, gint y, guint time, gpointer data);
+gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext
+ *gdc, gint x, gint y, GtkSelectionData *selection, guint info,
+ guint time, gpointer data);
+static void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint
+ time, gpointer data);
+static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event,
+ gpointer data);
+static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data);
+static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data);
+static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data);
+static void nsgtk_toolbar_cast(nsgtk_scaffolding *g);
+static GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i, struct nsgtk_theme *theme);
+static void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i);
+static void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i);
+static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data);
+static nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(
+ nsgtk_scaffolding *g, int i);
+
+/**
+ * change behaviour of scaffoldings while editing toolbar; all buttons as
+ * well as window clicks are desensitized; then buttons in the front window
+ * are changed to movable buttons
+ */
+void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ edit_mode = true;
+
+ 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));
+ gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout(
+ nsgtk_scaffolding_top_level(list))),
+ GTK_STATE_NORMAL, &((GdkColor)
+ {0, 0xEEEE, 0xEEEE, 0xEEEE}));
+
+ 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);
+ }
+
+ /* 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);
+
+ /* 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);
+}
+
+/**
+ * create store window
+ */
+void nsgtk_toolbar_window_open(nsgtk_scaffolding *g)
+{
+ int x = 0, y = 0;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ return;
+ }
+ window->glade = glade_xml_new(glade_toolbar_file_location,
+ "toolbarwindow", NULL);
+ if (window->glade == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ }
+ glade_xml_signal_autoconnect(window->glade);
+
+ window->window = glade_xml_get_widget(window->glade, "toolbarwindow");
+ if (window->window == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ free(theme);
+ return;
+ }
+ window->widgetvbox = glade_xml_get_widget(window->glade, "widgetvbox");
+ if (window->widgetvbox == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ free(theme);
+ return;
+ }
+
+ window->numberh = NSGTK_STORE_WIDTH; /* preset to width [in buttons] of */
+ /* store to cause creation of a new toolbar */
+ window->currentbutton = -1;
+ /* 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) {
+ warn_user(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);
+ }
+ free(theme);
+ gtk_window_set_transient_for(GTK_WINDOW(window->window),
+ nsgtk_scaffolding_window(g));
+ gtk_window_set_title(GTK_WINDOW(window->window), messages_get(
+ "gtkToolBarTitle"));
+ gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE);
+ gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY);
+ gtk_widget_show_all(window->window);
+ gtk_window_set_position(GTK_WINDOW(window->window),
+ GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_get_position(nsgtk_scaffolding_window(g), &x, &y);
+ gtk_window_move(GTK_WINDOW(window->window), x, y + 100);
+ g_signal_connect(glade_xml_get_widget(window->glade, "cancelbutton"),
+ "clicked", G_CALLBACK(
+ nsgtk_toolbar_cancel_clicked), g);
+ g_signal_connect(glade_xml_get_widget(window->glade, "okbutton"),
+ "clicked", G_CALLBACK(nsgtk_toolbar_persist), g);
+ g_signal_connect(glade_xml_get_widget(window->glade, "resetbutton"),
+ "clicked", G_CALLBACK(nsgtk_toolbar_reset), g);
+ g_signal_connect(window->window, "delete-event",
+ G_CALLBACK(nsgtk_toolbar_delete), g);
+ g_signal_connect(window->window, "drag-drop",
+ G_CALLBACK(nsgtk_toolbar_store_return), g);
+ g_signal_connect(window->window, "drag-motion",
+ G_CALLBACK(nsgtk_toolbar_store_action), g);
+}
+
+/**
+ * when titlebar / alt-F4 window close event happens
+ */
+gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event,
+ gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (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];
+ }
+ nsgtk_toolbar_set_physical(g);
+ nsgtk_toolbar_connect_all(g);
+ nsgtk_toolbar_close(g);
+ nsgtk_scaffolding_set_sensitivity(g);
+ gtk_widget_destroy(window->window);
+ return TRUE;
+}
+
+/**
+ * when cancel button is clicked
+ */
+gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (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];
+ }
+ nsgtk_toolbar_set_physical(g);
+ nsgtk_toolbar_connect_all(g);
+ nsgtk_toolbar_close(g);
+ nsgtk_scaffolding_set_sensitivity(g);
+ gtk_widget_destroy(window->window);
+ return TRUE;
+}
+
+/**
+ * when 'save settings' button is clicked
+ */
+gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ /* 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
+ */
+gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (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);
+ }
+ return TRUE;
+}
+
+/**
+ * set toolbar logical -> physical; physically visible toolbar buttons are made
+ * to correspond to the logically stored schema in terms of location
+ * visibility etc
+ */
+void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g)
+{
+ int i;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ /* 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);
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)));
+ free(theme);
+}
+
+/**
+ * cleanup code physical update of all toolbars; resensitize
+ * \param g the 'front' scaffolding that called customize
+ */
+void nsgtk_toolbar_close(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ while (list) {
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(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);
+ }
+ nsgtk_toolbar_connect_all(list);
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(
+ list)));
+ nsgtk_scaffolding_set_sensitivity(list);
+ gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout(
+ nsgtk_scaffolding_top_level(list))),
+ GTK_STATE_NORMAL, &((GdkColor)
+ {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));
+ if ((gui_window_get_browser_window(nsgtk_scaffolding_top_level(
+ list))->current_content != NULL) &&
+ (content_get_url(gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ current_content) != NULL))
+ browser_window_refresh_url_bar(
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list)),
+ content_get_url(
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ current_content),
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ frag_id);
+
+ 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));
+ if (search_web_ico())
+ gui_window_set_search_ico(search_web_ico());
+}
+
+/**
+ * callback function to iterate toolbar's widgets
+ */
+void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), widget);
+}
+
+/**
+ * add item to toolbar
+ * \param g the scaffolding whose toolbar an item is added to
+ * \param i the location in the toolbar
+ * the function should be called, when multiple items are being added,
+ * in ascending order
+ */
+void nsgtk_toolbar_add_item_to_toolbar(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;
+ }
+}
+
+/**
+ * physically add widgets to store window
+ */
+bool nsgtk_toolbar_add_store_widget(GtkWidget *widget)
+{
+ if (window->numberh >= NSGTK_STORE_WIDTH) {
+ window->currentbar = gtk_toolbar_new();
+ if (window->currentbar == NULL) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ 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;
+ }
+ 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;
+}
+
+/**
+ * called when a widget is dropped onto the toolbar
+ */
+gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *gdc, gint x,
+ gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g),
+ x, y);
+ int q, i;
+ if (window->currentbutton == -1)
+ return TRUE;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ 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) {
+ warn_user("NoMemory", 0);
+ 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++;
+ }
+ nsgtk_scaffolding_button(g, window->currentbutton)->location = ind;
+
+ /* complete action */
+ gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g),
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button, ind);
+ gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button), TRUE);
+ gtk_drag_source_set(GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button),
+ GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY);
+ nsgtk_toolbar_temp_connect(g, window->currentbutton);
+ gtk_widget_show_all(GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button));
+ window->currentbutton = -1;
+ return TRUE;
+}
+
+/**
+ * connected to toolbutton drop; perhaps one day it'll work properly so it may
+ * replace the global current_button
+ */
+
+gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, GtkSelectionData *selection, guint info,
+ guint time, gpointer data)
+{
+ return FALSE;
+}
+
+/**
+ * called when a widget is dropped onto the store window
+ */
+gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ int q, i;
+
+ 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--;
+ }
+ 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;
+}
+/**
+ * called when hovering an item above the toolbar
+ */
+gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x,
+ gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (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;
+}
+
+/**
+ * called when hovering above the store
+ */
+gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data)
+{
+ return FALSE;
+}
+/**
+ * called when hovering stops
+ */
+void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time,
+ gpointer data)
+{
+ gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0);
+}
+
+/**
+ * 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
+ */
+GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i, struct nsgtk_theme *theme)
+{
+ switch(i) {
+
+/* gtk_tool_button_new() accepts NULL args */
+#define MAKE_STOCKBUTTON(p, q) case p##_BUTTON: {\
+ GtkStockItem item;\
+ char *label = NULL;\
+ gtk_stock_lookup(#q, &item);\
+ if (item.label != NULL)\
+ label = remove_underscores(item.label, false);\
+ GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\
+ theme->image[p##_BUTTON]), label));\
+ if (label != NULL) {\
+ free(label);\
+ label = NULL;\
+ }\
+ return w;\
+ }
+
+ MAKE_STOCKBUTTON(HOME, gtk-home)
+ MAKE_STOCKBUTTON(BACK, gtk-go-back)
+ MAKE_STOCKBUTTON(FORWARD, gtk-go-forward)
+ MAKE_STOCKBUTTON(STOP, gtk-stop)
+ MAKE_STOCKBUTTON(RELOAD, gtk-refresh)
+#undef MAKE_STOCKBUTTON
+ case HISTORY_BUTTON:
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ theme->image[HISTORY_BUTTON]), ""));
+ case URL_BAR_ITEM: {
+ char imagefile[strlen(res_dir_location) + SLEN("favicon.png")
+ + 1];
+ sprintf(imagefile, "%sfavicon.png", res_dir_location);
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_file(
+ imagefile));
+ GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new());
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+
+ if ((entry == NULL) || (w == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+
+ if (image != NULL)
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE(image));
+
+ gtk_container_add(GTK_CONTAINER(w), entry);
+ gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE);
+ return w;
+ }
+ case THROBBER_ITEM: {
+ if (edit_mode)
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ gtk_image_new_from_pixbuf(
+ nsgtk_throbber->framedata[0])),
+ "[throbber]"));
+ if ((nsgtk_throbber == NULL) || (nsgtk_throbber->framedata ==
+ NULL) || (nsgtk_throbber->framedata[0] ==
+ NULL))
+ return NULL;
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_pixbuf(
+ nsgtk_throbber->framedata[0]));
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+ GtkWidget *al = GTK_WIDGET(gtk_alignment_new(0.5, 0.5, 1, 1));
+ if ((w == NULL) || (al == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ gtk_alignment_set_padding(GTK_ALIGNMENT(al), 0, 0, 3, 3);
+ if (image != NULL)
+ gtk_container_add(GTK_CONTAINER(al), image);
+ gtk_container_add(GTK_CONTAINER(w), al);
+ return w;
+ }
+ case WEBSEARCH_ITEM: {
+ if (edit_mode)
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ gtk_image_new_from_stock("gtk-find",
+ GTK_ICON_SIZE_LARGE_TOOLBAR)),
+ "[websearch]"));
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_stock(
+ "gtk-info", GTK_ICON_SIZE_LARGE_TOOLBAR));
+ GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new());
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+
+ if ((entry == NULL) || (w == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+
+ gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH,
+ -1);
+ if (image != NULL)
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE(image));
+
+ gtk_container_add(GTK_CONTAINER(w), entry);
+ return w;
+ }
+
+/* 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);\
+ GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\
+ theme->image[p##_BUTTON]), label));\
+ if (label != NULL)\
+ free(label);\
+ return w;\
+ }
+
+ 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, gtkSaveBoxTree)
+ MAKE_MENUBUTTON(SAVEDOMTREE, gtkSaveDomTree)
+ 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)
+ default:
+ return NULL;
+#undef MAKE_MENUBUTTON
+ }
+}
+
+/**
+ * \return toolbar item id when a widget is an element of the scaffolding
+ * else -1
+ */
+int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, nsgtk_scaffolding *g)
+{
+ 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;
+ }
+ }
+ return -1;
+}
+
+/**
+ * \return toolbar item id from location when there is an item at that logical
+ * location; else -1
+ */
+nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(nsgtk_scaffolding *g,
+ int i)
+{
+ int q;
+ for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++)
+ if (nsgtk_scaffolding_button(g, q)->location == i)
+ return q;
+ return -1;
+}
+
+/**
+ * connect 'normal' handlers to toolbar buttons
+ */
+
+void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g)
+{
+ 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);
+ }
+}
+
+/**
+ * add handlers to factory widgets
+ * \param g the scaffolding to attach handlers to
+ * \param i the toolbar item id
+ */
+void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, nsgtk_toolbar_button i)
+{
+ 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);
+ break;
+ case THROBBER_ITEM:
+ nsgtk_scaffolding_update_throbber_ref(g);
+ 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);
+ 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;
+ }
+}
+
+#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(saveboxtree, SAVEBOXTREE, window)
+DATAHANDLER(savedomtree, 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
+
+/**
+ * connect temporary handler for toolbar edit events
+ */
+void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, nsgtk_toolbar_button i)
+{
+ if ((i == URL_BAR_ITEM) ||
+ (nsgtk_scaffolding_button(g, i)->button == NULL) ||
+ (nsgtk_scaffolding_button(g, i)->dataminus == NULL))
+ return;
+ g_signal_connect(nsgtk_scaffolding_button(g, i)->button,
+ "drag-data-get", G_CALLBACK(nsgtk_scaffolding_button(
+ g, i)->dataminus), g);
+}
+
+/**
+ * load toolbar settings from file; file is a set of fields arranged as
+ * <itemreference>;<itemlocation>|<itemreference>;<itemlocation>| etc
+ */
+void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g)
+{
+ int i, ii;
+ char *val;
+ char buffer[SLEN("11;|") * 2 * PLACEHOLDER_BUTTON]; /* numbers 0-99 */
+ buffer[0] = '\0';
+ char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ nsgtk_scaffolding_button(g, i)->location =
+ (i <= THROBBER_ITEM) ? i : -1;
+ FILE *f = fopen(toolbar_indices_file_location, "r");
+ if (f == NULL) {
+ warn_user(messages_get("gtkFileError"),
+ toolbar_indices_file_location);
+ return;
+ }
+ val = fgets(buffer, sizeof buffer, f);
+ if (val == NULL)
+ LOG(("empty read toolbar settings"));
+ fclose(f);
+ i = BACK_BUTTON;
+ ii = BACK_BUTTON;
+ buffer1 = strtok_r(buffer, "|", &ptr);
+ while (buffer1 != NULL) {
+ subbuffer = strtok_r(buffer1, ";", &pter);
+ i = atoi(subbuffer);
+ subbuffer = strtok_r(NULL, ";", &pter);
+ ii = atoi(subbuffer);
+ if ((i >= BACK_BUTTON) && (i < PLACEHOLDER_BUTTON) &&
+ (ii >= -1) && (ii < PLACEHOLDER_BUTTON)) {
+ nsgtk_scaffolding_button(g, i)->location = ii;
+ }
+ buffer1 = strtok_r(NULL, "|", &ptr);
+ }
+}
+
+/**
+ * cast toolbar settings to all scaffoldings referenced from the global linked
+ * list of gui_windows
+ */
+void nsgtk_toolbar_cast(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ 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;
+ 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);
+ }
+}
+
+/**
+ * save toolbar settings to file
+ */
+void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g)
+{
+ int i;
+ FILE *f = fopen(toolbar_indices_file_location, "w");
+ if (f == NULL){
+ warn_user("gtkFileError", toolbar_indices_file_location);
+ return;
+ }
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ fprintf(f, "%d;%d|", i, nsgtk_scaffolding_button(g, i)->location);
+ }
+ fclose(f);
+}
+