diff options
Diffstat (limited to 'frontends/gtk/toolbar.c')
-rw-r--r-- | frontends/gtk/toolbar.c | 1416 |
1 files changed, 1416 insertions, 0 deletions
diff --git a/frontends/gtk/toolbar.c b/frontends/gtk/toolbar.c new file mode 100644 index 000000000..208b5c0b9 --- /dev/null +++ b/frontends/gtk/toolbar.c @@ -0,0 +1,1416 @@ +/* + * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <gtk/gtk.h> + +#include "desktop/browser.h" +#include "desktop/searchweb.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utils.h" + +#include "gtk/gui.h" +#include "gtk/warn.h" +#include "gtk/scaffolding.h" +#include "gtk/search.h" +#include "gtk/throbber.h" +#include "gtk/window.h" +#include "gtk/compat.h" +#include "gtk/resources.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 + +/* 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; + + +enum image_sets { + IMAGE_SET_MAIN_MENU = 0, + IMAGE_SET_RCLICK_MENU, + IMAGE_SET_POPUP_MENU, + IMAGE_SET_BUTTONS, + IMAGE_SET_COUNT +}; + +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 */ +}; + +/** + * returns a string without its underscores + * + * \param s The string to change. + * \param replacespace true to insert a space where there was an underscore + * \return The altered string + */ +static char *remove_underscores(const char *s, bool replacespace) +{ + size_t i, ii, len; + char *ret; + len = strlen(s); + ret = malloc(len + 1); + if (ret == NULL) { + return NULL; + } + for (i = 0, ii = 0; i < len; i++) { + if (s[i] != '_') { + ret[ii++] = s[i]; + } else if (replacespace) { + ret[ii++] = ' '; + } + } + ret[ii] = '\0'; + return ret; +} + + +/** + * get default image for buttons / menu items from gtk stock items. + * + * \param tbbutton button reference + * \param iconsize The size of icons to select. + * \return default images. + */ +static GtkImage * +nsgtk_theme_image_default(nsgtk_toolbar_button tbbutton, GtkIconSize iconsize) +{ + 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 + + case HISTORY_BUTTON: + image = GTK_IMAGE(gtk_image_new_from_pixbuf(arrow_down_pixbuf)); + break; + + default: + image = GTK_IMAGE(nsgtk_image_new_from_stock("gtk-missing-image", + iconsize)); + break; + + } + return image; + +} + +/** + * Get default image for search buttons / menu items from gtk stock items + * + * \param tbbutton search button reference + * \param iconsize The size of icons to select. + * \return default search image. + */ + +static GtkImage * +nsgtk_theme_searchimage_default(nsgtk_search_buttons tbbutton, + GtkIconSize iconsize) +{ + switch (tbbutton) { + + case (SEARCH_BACK_BUTTON): + return GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_GO_BACK, + iconsize)); + case (SEARCH_FORWARD_BUTTON): + return GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_GO_FORWARD, + iconsize)); + case (SEARCH_CLOSE_BUTTON): + return GTK_IMAGE(nsgtk_image_new_from_stock(NSGTK_STOCK_CLOSE, + iconsize)); + default: + return NULL; + } +} + +/** + * initialise a theme structure with gtk images + */ +static struct nsgtk_theme *nsgtk_theme_load(GtkIconSize iconsize) +{ + struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme)); + int btnloop; + + if (theme == NULL) { + nsgtk_warning("NoMemory", 0); + return NULL; + } + + for (btnloop = BACK_BUTTON; btnloop < PLACEHOLDER_BUTTON ; btnloop++) { + theme->image[btnloop] = nsgtk_theme_image_default(btnloop, iconsize); + } + + for (btnloop = SEARCH_BACK_BUTTON; btnloop < SEARCH_BUTTONS_COUNT; btnloop++) { + theme->searchimage[btnloop] = nsgtk_theme_searchimage_default(btnloop, iconsize); + } + return theme; +} + + + +/* exported function documented in gtk/toolbar.h */ +void nsgtk_theme_implement(struct nsgtk_scaffolding *g) +{ + struct nsgtk_theme *theme[IMAGE_SET_COUNT]; + int i; + struct nsgtk_button_connect *button; + struct gtk_search *search; + + theme[IMAGE_SET_MAIN_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU); + theme[IMAGE_SET_RCLICK_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU); + theme[IMAGE_SET_POPUP_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU); + theme[IMAGE_SET_BUTTONS] = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) || + (i == WEBSEARCH_ITEM)) + continue; + + button = nsgtk_scaffolding_button(g, i); + if (button == NULL) + continue; + + /* 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)); + } + 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)); + } + 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)); + } + 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)); + } + } + + /* 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])); + } + 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])); + } + 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])); + } + } + + for (i = 0; i < IMAGE_SET_COUNT; i++) { + if (theme[i] != NULL) { + free(theme[i]); + } + } +} + + +/** + * callback function to iterate toolbar's widgets + */ +static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data) +{ + struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; + gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), + widget); +} + +/** + * connect temporary handler for toolbar edit events + * + * \param g The scaffolding + * \param bi The button index + */ +static void nsgtk_toolbar_temp_connect(struct nsgtk_scaffolding *g, + nsgtk_toolbar_button bi) +{ + struct nsgtk_button_connect *bc; + + 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); + } + } +} + +/** + * get scaffolding button index of button at location + * + * \return toolbar item id from location when there is an item at that logical + * location; else -1 + */ +static nsgtk_toolbar_button +nsgtk_toolbar_get_id_at_location(struct 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; +} + +/** + * 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 + */ +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; \ + } + + 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 + + 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()); + + if ((entry == NULL) || (w == NULL)) { + nsgtk_warning(messages_get("NoMemory"), 0); + return NULL; + } + + nsgtk_entry_set_icon_from_pixbuf(entry, + GTK_ENTRY_ICON_PRIMARY, + favicon_pixbuf); + + gtk_container_add(GTK_CONTAINER(w), entry); + gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE); + break; + } + + case THROBBER_ITEM: { + if ((nsgtk_throbber == NULL) || + (nsgtk_throbber->framedata == NULL) || + (nsgtk_throbber->framedata[0] == NULL)) { + return NULL; + } + + 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; + + w = GTK_WIDGET(gtk_tool_item_new()); + + 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); + + gtk_container_add(GTK_CONTAINER(w), image); + } + } + 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]")); + + GtkWidget *entry = nsgtk_entry_new(); + + w = GTK_WIDGET(gtk_tool_item_new()); + + if ((entry == NULL) || (w == NULL)) { + nsgtk_warning(messages_get("NoMemory"), 0); + return NULL; + } + + gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, -1); + + nsgtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, + NSGTK_STOCK_INFO); + + gtk_container_add(GTK_CONTAINER(w), entry); + break; + } + +/* 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 + + default: + break; + + } + return w; +} + +/** + * called when a widget is dropped onto the toolbar + */ +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) + return TRUE; + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + nsgtk_warning(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) { + nsgtk_warning("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 */ + GtkToolItem *current_button; + + current_button = GTK_TOOL_ITEM(nsgtk_scaffolding_button(g, window->currentbutton)->button); + + gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), current_button, ind); + + 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)); + + + window->currentbutton = -1; + + return TRUE; +} + +/** + * connected to toolbutton drop; perhaps one day it'll work properly so it may + * replace the global current_button + */ +static 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 hovering an item above the toolbar + */ +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; +} + +/** + * called when hovering stops + */ +static void +nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time, + gpointer data) +{ + gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0); +} + +/** + * add item to toolbar. + * + * the function should be called, when multiple items are being added, + * in ascending order. + * + * \param g the scaffolding whose toolbar an item is added to. + * \param i the location in the toolbar. + * \param theme The theme in use. + */ +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; + } +} + +/** + * cleanup code physical update of all toolbars; resensitize + * \param g the 'front' scaffolding that called customize + */ +static void nsgtk_toolbar_close(struct nsgtk_scaffolding *g) +{ + int i; + + struct nsgtk_scaffolding *list; + struct nsgtk_theme *theme; + + list = nsgtk_scaffolding_iterate(NULL); + while (list) { + theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + 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); + } + 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) +{ + 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]; + } + 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; +} + +/** + * physically add widgets to store window + */ +static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget) +{ + if (window->numberh >= NSGTK_STORE_WIDTH) { + window->currentbar = gtk_toolbar_new(); + if (window->currentbar == NULL) { + nsgtk_warning("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; +} + +/** + * save toolbar settings to file + */ +static void nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g) +{ + int i; + FILE *f = fopen(toolbar_indices_file_location, "w"); + if (f == NULL){ + nsgtk_warning("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); +} + +/** + * cast toolbar settings to all scaffoldings referenced from the global linked + * list of gui_windows + */ +static void nsgtk_toolbar_cast(struct nsgtk_scaffolding *g) +{ + int i; + struct nsgtk_scaffolding *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; + } + + 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); + } +} + +/** + * when 'save settings' button is clicked + */ +static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data) +{ + edit_mode = false; + struct nsgtk_scaffolding *g = (struct 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 + */ +static gboolean nsgtk_toolbar_reset(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); + } + return TRUE; +} + +/** + * when titlebar / alt-F4 window close event happens + */ +static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, + 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]; + } + 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; +} + +/** + * called when a widget is dropped onto the store window + */ +static gboolean +nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, guint time, gpointer data) +{ + struct nsgtk_scaffolding *g = (struct 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 above the store + */ +static gboolean +nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, guint time, gpointer data) +{ + return FALSE; +} + +/** + * create store window + */ +static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g) +{ + int x = 0, y = 0; + struct nsgtk_theme *theme; + nserror res; + + theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + nsgtk_warning(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + return; + } + + res = nsgtk_builder_new_from_resname("toolbar", &window->builder); + if (res != NSERROR_OK) { + LOG("Toolbar UI builder init failed"); + nsgtk_warning(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + free(theme); + return; + } + + gtk_builder_connect_signals(window->builder, NULL); + + window->window = GTK_WIDGET(gtk_builder_get_object(window->builder, + "toolbarwindow")); + if (window->window == NULL) { + nsgtk_warning(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + free(theme); + return; + } + + 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; + } + + 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) { + 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); + } + 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(GTK_WIDGET(gtk_builder_get_object(window->builder, + "cancelbutton")), + "clicked", + G_CALLBACK(nsgtk_toolbar_cancel_clicked), + g); + + g_signal_connect(GTK_WIDGET(gtk_builder_get_object(window->builder, + "okbutton")), + "clicked", + G_CALLBACK(nsgtk_toolbar_persist), + g); + + g_signal_connect(GTK_WIDGET(gtk_builder_get_object(window->builder, + "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); +} + +/** + * 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(struct nsgtk_scaffolding *g) +{ + int i; + struct nsgtk_scaffolding *list; + edit_mode = true; + + 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); + + 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); +} + +/** + * 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(struct nsgtk_scaffolding *g) +{ + int i; + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + nsgtk_warning(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); +} + +/** + * \return toolbar item id when a widget is an element of the scaffolding + * else -1 + */ +int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, + struct 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; +} + + +/** + * add handlers to factory widgets + * \param g the scaffolding to attach handlers to + * \param i the toolbar item id + */ +static void +nsgtk_toolbar_set_handler(struct 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; + } +} + +/** + * connect 'normal' handlers to toolbar buttons + */ +void nsgtk_toolbar_connect_all(struct 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); + } +} + + +#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 + + +/** + * load toolbar settings from file; file is a set of fields arranged as + * [itemreference];[itemlocation]|[itemreference];[itemlocation]| etc + */ +void nsgtk_toolbar_customization_load(struct 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) { + nsgtk_warning(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); + } +} |