netsurf/gtk/toolbar.c
Vincent Sanders 7d9c9dba36 Split utils header into string functions and everything else
split out the string handling API from the rest of the utils header
and fix up all the fallout.
2016-04-21 22:36:21 +01:00

1416 lines
41 KiB
C

/*
* 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/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) {
warn_user("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)) {
warn_user(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)) {
warn_user(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) {
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 */
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) {
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);
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) {
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;
}
/**
* 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){
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);
}
/**
* 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) {
warn_user(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");
warn_user(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) {
warn_user(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) {
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(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) {
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);
}
/**
* \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) {
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);
}
}