diff options
Diffstat (limited to 'frontends/gtk/scaffolding.c')
-rw-r--r-- | frontends/gtk/scaffolding.c | 2869 |
1 files changed, 841 insertions, 2028 deletions
diff --git a/frontends/gtk/scaffolding.c b/frontends/gtk/scaffolding.c index 8c46fd884..f9d4f6d67 100644 --- a/frontends/gtk/scaffolding.c +++ b/frontends/gtk/scaffolding.c @@ -1,6 +1,5 @@ /* - * Copyright 2006 Rob Kendrick <rjek@rjek.com> - * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -17,92 +16,51 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <assert.h> +#include <gtk/gtk.h> #include <stdbool.h> -#include <stdio.h> -#include <errno.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> -#include <gtk/gtk.h> -#include <gdk-pixbuf/gdk-pixbuf.h> #include "utils/utils.h" -#include "utils/dirent.h" -#include "utils/messages.h" -#include "utils/corestrings.h" #include "utils/log.h" -#include "utils/nsoption.h" -#include "utils/file.h" +#include "utils/messages.h" #include "utils/nsurl.h" -#include "netsurf/content.h" -#include "netsurf/keypress.h" +#include "utils/nsoption.h" #include "netsurf/browser_window.h" -#include "netsurf/plotters.h" #include "desktop/browser_history.h" #include "desktop/hotlist.h" -#include "desktop/print.h" -#include "desktop/save_complete.h" -#ifdef WITH_PDF_EXPORT -#include "desktop/font_haru.h" -#include "desktop/save_pdf.h" -#endif -#include "desktop/save_text.h" -#include "desktop/searchweb.h" -#include "desktop/search.h" #include "gtk/compat.h" -#include "gtk/warn.h" -#include "gtk/cookies.h" -#include "gtk/completion.h" -#include "gtk/preferences.h" -#include "gtk/about.h" -#include "gtk/viewsource.h" -#include "gtk/bitmap.h" -#include "gtk/gui.h" -#include "gtk/global_history.h" +#include "gtk/toolbar_items.h" +#include "gtk/menu.h" #include "gtk/local_history.h" -#include "gtk/hotlist.h" +#include "gtk/gui.h" #include "gtk/download.h" -#include "gtk/menu.h" -#include "gtk/plotters.h" -#include "gtk/print.h" -#include "gtk/search.h" -#include "gtk/throbber.h" -#include "gtk/toolbar.h" #include "gtk/window.h" -#include "gtk/gdk.h" -#include "gtk/scaffolding.h" +#include "gtk/warn.h" #include "gtk/tabs.h" -#include "gtk/schedule.h" -#include "gtk/viewdata.h" #include "gtk/resources.h" -#include "gtk/layout_pango.h" - -/** Macro to define a handler for menu, button and activate events. */ -#define MULTIHANDLER(q)\ -static gboolean nsgtk_on_##q##_activate(struct nsgtk_scaffolding *g);\ -static gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *widget, gpointer data)\ -{\ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;\ - return nsgtk_on_##q##_activate(g);\ -}\ -static gboolean nsgtk_on_##q##_activate_button(GtkButton *widget, gpointer data)\ -{\ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data;\ - return nsgtk_on_##q##_activate(g);\ -}\ -static gboolean nsgtk_on_##q##_activate(struct nsgtk_scaffolding *g) - -/** Macro to define a handler for menu events. */ -#define MENUHANDLER(q)\ -static gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *widget, gpointer data) - -/** Macro to define a handler for button events. */ -#define BUTTONHANDLER(q)\ -static gboolean nsgtk_on_##q##_activate(GtkButton *widget, gpointer data) - -/** Core scaffolding structure. */ +#include "gtk/scaffolding.h" + + +/** + * menu entry context + */ +struct nsgtk_menu { + GtkWidget *main; /* main menu entry */ + GtkWidget *burger; /* right click menu */ + GtkWidget *popup; /* popup menu entry */ + /** + * menu item handler + */ + gboolean (*mhandler)(GtkMenuItem *widget, gpointer data); + const char *iconname; /* name of the icon to use */ + bool sensitivity; /* menu item is sensitive */ +}; + +/** + * Core scaffolding structure. + */ struct nsgtk_scaffolding { /** global linked list of scaffolding for gui interface adjustments */ struct nsgtk_scaffolding *next, *prev; @@ -115,45 +73,37 @@ struct nsgtk_scaffolding { /** scaffold container window */ GtkWindow *window; - bool fullscreen; /**< flag for the scaffold window fullscreen status */ /** tab widget holding displayed pages */ GtkNotebook *notebook; - /** entry widget holding the url of the current displayed page */ - GtkWidget *url_bar; - GtkEntryCompletion *url_bar_completion; /**< Completions for url_bar */ - - /** Activity throbber */ - GtkImage *throbber; - int throb_frame; /**< Current frame of throbber animation */ - - struct gtk_search *search; - /** Web search widget */ - GtkWidget *webSearchEntry; - - /** controls toolbar */ - GtkToolbar *tool_bar; - struct nsgtk_button_connect *buttons[PLACEHOLDER_BUTTON]; - int offset; - int toolbarmem; - int toolbarbase; - int historybase; + /** handler id for tabs remove callback */ + gulong tabs_remove_handler_id; /** menu bar hierarchy */ struct nsgtk_bar_submenu *menu_bar; + /** burger menu hierarchy */ + struct nsgtk_burger_menu *burger_menu; + /** right click popup menu hierarchy */ - struct nsgtk_popup_menu *menu_popup; + struct nsgtk_popup_menu *popup_menu; /** link popup menu */ struct nsgtk_link_menu *link_menu; + + /** menu entries widgets for sensitivity adjustment */ + struct nsgtk_menu menus[PLACEHOLDER_BUTTON]; }; -/** current scaffold for model dialogue use */ +/** + * current scaffold for model dialogue use + */ static struct nsgtk_scaffolding *scaf_current; -/** global list for interface changes */ +/** + * global list for interface changes + */ static struct nsgtk_scaffolding *scaf_list = NULL; /** @@ -167,45 +117,31 @@ static struct browser_window_features current_menu_features; * Helper to hide popup menu entries by grouping. * * \param menu The popup menu to modify. - * \param submenu flag to indicate if submenus should be hidden. * \param nav flag to indicate if navigation entries should be hidden. * \param cnp flag to indicate if cut and paste entries should be hidden. * \param custom flag to indicate if menu customisation is hidden. */ static void -popup_menu_hide(struct nsgtk_popup_menu *menu, - bool submenu, - bool nav, - bool cnp, - bool custom) +popup_menu_hide(struct nsgtk_popup_menu *menu, bool nav, bool cnp) { - if (submenu) { - gtk_widget_hide(GTK_WIDGET(menu->file_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->edit_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->view_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->nav_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->help_menuitem)); - - gtk_widget_hide(menu->first_separator); - } - if (nav) { gtk_widget_hide(GTK_WIDGET(menu->back_menuitem)); gtk_widget_hide(GTK_WIDGET(menu->forward_menuitem)); gtk_widget_hide(GTK_WIDGET(menu->stop_menuitem)); gtk_widget_hide(GTK_WIDGET(menu->reload_menuitem)); + + gtk_widget_hide(menu->first_separator); } if (cnp) { gtk_widget_hide(GTK_WIDGET(menu->cut_menuitem)); gtk_widget_hide(GTK_WIDGET(menu->copy_menuitem)); gtk_widget_hide(GTK_WIDGET(menu->paste_menuitem)); - } - if (custom) { - gtk_widget_hide(GTK_WIDGET(menu->customize_menuitem)); + gtk_widget_hide(menu->second_separator); } + } @@ -213,48 +149,32 @@ popup_menu_hide(struct nsgtk_popup_menu *menu, * Helper to show popup menu entries by grouping. * * \param menu The popup menu to modify. - * \param submenu flag to indicate if submenus should be visible. * \param nav flag to indicate if navigation entries should be visible. * \param cnp flag to indicate if cut and paste entries should be visible. * \param custom flag to indicate if menu customisation is visible. */ static void -popup_menu_show(struct nsgtk_popup_menu *menu, - bool submenu, - bool nav, - bool cnp, - bool custom) +popup_menu_show(struct nsgtk_popup_menu *menu, bool nav, bool cnp) { - if (submenu) { - gtk_widget_show(GTK_WIDGET(menu->file_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->edit_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->view_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->nav_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->help_menuitem)); - - gtk_widget_show(menu->first_separator); - } - if (nav) { gtk_widget_show(GTK_WIDGET(menu->back_menuitem)); gtk_widget_show(GTK_WIDGET(menu->forward_menuitem)); gtk_widget_show(GTK_WIDGET(menu->stop_menuitem)); gtk_widget_show(GTK_WIDGET(menu->reload_menuitem)); + + gtk_widget_show(menu->first_separator); } if (cnp) { gtk_widget_show(GTK_WIDGET(menu->cut_menuitem)); gtk_widget_show(GTK_WIDGET(menu->copy_menuitem)); gtk_widget_show(GTK_WIDGET(menu->paste_menuitem)); - } - if (custom) { - gtk_widget_show(GTK_WIDGET(menu->customize_menuitem)); + gtk_widget_show(menu->second_separator); } -} +} -/* event handlers and support functions for them */ /** * resource cleanup function for window destruction. @@ -273,6 +193,18 @@ static void scaffolding_window_destroy(GtkWidget *widget, gpointer data) nsgtk_local_history_hide(); + /* ensure scaffolding being destroyed is not current */ + if (scaf_current == gs) { + scaf_current = NULL; + /* attempt to select nearest scaffold instead of just selecting the first */ + if (gs->prev != NULL) { + scaf_current = gs->prev; + } else if (gs->next != NULL) { + scaf_current = gs->next; + } + } + + /* remove scaffolding from list */ if (gs->prev != NULL) { gs->prev->next = gs->next; } else { @@ -284,6 +216,16 @@ static void scaffolding_window_destroy(GtkWidget *widget, gpointer data) NSLOG(netsurf, INFO, "scaffold list head: %p", scaf_list); + /* ensure menu resources are freed */ + nsgtk_menu_bar_destroy(gs->menu_bar); + nsgtk_burger_menu_destroy(gs->burger_menu); + nsgtk_popup_menu_destroy(gs->popup_menu); + nsgtk_link_menu_destroy(gs->link_menu); + + g_signal_handler_disconnect(gs->notebook, gs->tabs_remove_handler_id); + + free(gs); + if (scaf_list == NULL) { /* no more open windows - stop the browser */ nsgtk_complete = true; @@ -326,100 +268,74 @@ static void scaffolding_update_context(struct nsgtk_scaffolding *g) { struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - g->buttons[BACK_BUTTON]->sensitivity = - browser_window_history_back_available(bw); - g->buttons[FORWARD_BUTTON]->sensitivity = - browser_window_history_forward_available(bw); + g->menus[BACK_BUTTON].sensitivity = + browser_window_history_back_available(bw); + g->menus[FORWARD_BUTTON].sensitivity = + browser_window_history_forward_available(bw); nsgtk_scaffolding_set_sensitivity(g); - /* update the url bar, particularly necessary when tabbing */ - browser_window_refresh_url_bar(bw); - nsgtk_local_history_hide(); } /** - * Make the throbber run. - * - * scheduled callback to update the throbber - * - * \param p The context passed when scheduled. - */ -static void nsgtk_throb(void *p) -{ - struct nsgtk_scaffolding *g = p; - - if (g->throb_frame >= (nsgtk_throbber->nframes - 1)) { - g->throb_frame = 1; - } else { - g->throb_frame++; - } - - gtk_image_set_from_pixbuf(g->throbber, - nsgtk_throbber->framedata[g->throb_frame]); - - nsgtk_schedule(100, nsgtk_throb, p); -} - - -/** * edit the sensitivity of focused widget * + * \todo this needs to update toolbar sensitivity + * * \param g The scaffolding context. */ static guint -nsgtk_scaffolding_update_edit_actions_sensitivity( - struct nsgtk_scaffolding *g) +nsgtk_scaffolding_update_edit_actions_sensitivity(struct nsgtk_scaffolding *g) { GtkWidget *widget = gtk_window_get_focus(g->window); - gboolean has_selection; if (GTK_IS_EDITABLE(widget)) { + gboolean has_selection; has_selection = gtk_editable_get_selection_bounds( - GTK_EDITABLE (widget), NULL, NULL); - - g->buttons[COPY_BUTTON]->sensitivity = has_selection; - g->buttons[CUT_BUTTON]->sensitivity = has_selection; - g->buttons[PASTE_BUTTON]->sensitivity = true; + GTK_EDITABLE(widget), NULL, NULL); + g->menus[COPY_BUTTON].sensitivity = has_selection; + g->menus[CUT_BUTTON].sensitivity = has_selection; + g->menus[PASTE_BUTTON].sensitivity = true; } else { struct browser_window *bw = - nsgtk_get_browser_window(g->top_level); + nsgtk_get_browser_window(g->top_level); browser_editor_flags edit_f = - browser_window_get_editor_flags(bw); - - g->buttons[COPY_BUTTON]->sensitivity = - edit_f & BW_EDITOR_CAN_COPY; - g->buttons[CUT_BUTTON]->sensitivity = - edit_f & BW_EDITOR_CAN_CUT; - g->buttons[PASTE_BUTTON]->sensitivity = - edit_f & BW_EDITOR_CAN_PASTE; + browser_window_get_editor_flags(bw); + + g->menus[COPY_BUTTON].sensitivity = + edit_f & BW_EDITOR_CAN_COPY; + g->menus[CUT_BUTTON].sensitivity = + edit_f & BW_EDITOR_CAN_CUT; + g->menus[PASTE_BUTTON].sensitivity = + edit_f & BW_EDITOR_CAN_PASTE; } nsgtk_scaffolding_set_sensitivity(g); - return ((g->buttons[COPY_BUTTON]->sensitivity) | - (g->buttons[CUT_BUTTON]->sensitivity) | - (g->buttons[PASTE_BUTTON]->sensitivity)); + + return ((g->menus[COPY_BUTTON].sensitivity) | + (g->menus[CUT_BUTTON].sensitivity) | + (g->menus[PASTE_BUTTON].sensitivity)); } /** * make edit actions sensitive * + * \todo toolbar sensitivity + * * \param g The scaffolding context. */ static void -nsgtk_scaffolding_enable_edit_actions_sensitivity( - struct nsgtk_scaffolding *g) +nsgtk_scaffolding_enable_edit_actions_sensitivity(struct nsgtk_scaffolding *g) { - - g->buttons[PASTE_BUTTON]->sensitivity = true; - g->buttons[COPY_BUTTON]->sensitivity = true; - g->buttons[CUT_BUTTON]->sensitivity = true; + g->menus[PASTE_BUTTON].sensitivity = true; + g->menus[COPY_BUTTON].sensitivity = true; + g->menus[CUT_BUTTON].sensitivity = true; nsgtk_scaffolding_set_sensitivity(g); - popup_menu_show(g->menu_popup, false, false, true, false); + popup_menu_show(g->popup_menu, false, true); } /* signal handling functions for the toolbar, URL bar, and menu bar */ @@ -456,6 +372,7 @@ nsgtk_window_edit_menu_hidden(GtkWidget *widget, return TRUE; } + /** * gtk event handler for popup menu being hidden. * @@ -463,79 +380,10 @@ nsgtk_window_edit_menu_hidden(GtkWidget *widget, * \param g scaffolding handle * \return TRUE to indicate event handled */ -static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget, - struct nsgtk_scaffolding *g) -{ - nsgtk_scaffolding_enable_edit_actions_sensitivity(g); - return TRUE; -} - -/* exported interface documented in gtk/scaffolding.h */ -gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data) -{ - struct nsgtk_scaffolding *g = data; - nserror ret; - nsurl *url; - - ret = search_web_omni(gtk_entry_get_text(GTK_ENTRY(g->url_bar)), - SEARCH_WEB_OMNI_NONE, - &url); - if (ret == NSERROR_OK) { - ret = browser_window_navigate(nsgtk_get_browser_window(g->top_level), - url, NULL, BW_NAVIGATE_HISTORY, - NULL, NULL, NULL); - nsurl_unref(url); - } - if (ret != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(ret), 0); - } - - return TRUE; -} - - -/** - * update handler for URL entry widget - * - * \param widget The widget receiving the delete event - * \param event The event - * \param data The context pointer passed when the connection was made. - * \return TRUE to indicate signal handled. - */ -gboolean -nsgtk_window_url_changed(GtkWidget *widget, - GdkEventKey *event, - gpointer data) -{ - return nsgtk_completion_update(GTK_ENTRY(widget)); -} - - -/** - * Event handler for popup menu on toolbar. - * - * \param toolbar The toolbar being clicked - * \param x The x coordinate where the click happened - * \param y The x coordinate where the click happened - * \param button the buttons being pressed - * \param data The context pointer passed when the connection was made. - * \return TRUE to indicate event handled. - */ static gboolean -nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, - gint x, - gint y, - gint button, - gpointer data) +nsgtk_window_popup_menu_hidden(GtkWidget *widget, struct nsgtk_scaffolding *g) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - - /* set visibility for right-click popup menu */ - popup_menu_hide(g->menu_popup, true, false, true, false); - popup_menu_show(g->menu_popup, false, false, false, true); - - nsgtk_menu_popup_at_pointer(g->menu_popup->popup_menu, NULL); - + nsgtk_scaffolding_enable_edit_actions_sensitivity(g); return TRUE; } @@ -543,6 +391,9 @@ nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, /** * Update the menus when the number of tabs changes. * + * \todo toolbar sensitivity + * \todo next/previous tab ought to only be visible if there is such a tab + * * \param notebook The notebook all the tabs are in * \param page The newly added page container widget * \param page_num The index of the newly added page @@ -556,12 +407,18 @@ nsgtk_window_tabs_add(GtkNotebook *notebook, { gboolean visible = gtk_notebook_get_show_tabs(g->notebook); g_object_set(g->menu_bar->view_submenu->tabs_menuitem, - "visible", visible, NULL); - g_object_set(g->menu_popup->view_submenu->tabs_menuitem, - "visible", visible, NULL); - g->buttons[NEXTTAB_BUTTON]->sensitivity = visible; - g->buttons[PREVTAB_BUTTON]->sensitivity = visible; - g->buttons[CLOSETAB_BUTTON]->sensitivity = visible; + "visible", + visible, + NULL); + g_object_set(g->burger_menu->view_submenu->tabs_menuitem, + "visible", + visible, + NULL); + + g->menus[NEXTTAB_BUTTON].sensitivity = visible; + g->menus[PREVTAB_BUTTON].sensitivity = visible; + g->menus[CLOSETAB_BUTTON].sensitivity = visible; + nsgtk_scaffolding_set_sensitivity(g); } @@ -569,6 +426,8 @@ nsgtk_window_tabs_add(GtkNotebook *notebook, /** * Update the menus when the number of tabs changes. * + * \todo toolbar sensitivity + * * \param notebook The notebook all the tabs are in * \param page The page container widget being removed * \param page_num The index of the removed page @@ -580,6 +439,8 @@ nsgtk_window_tabs_remove(GtkNotebook *notebook, guint page_num, struct nsgtk_scaffolding *gs) { + gboolean visible; + /* if the scaffold is being destroyed it is not useful to * update the state, further many of the widgets may have * already been destroyed. @@ -594,472 +455,46 @@ nsgtk_window_tabs_remove(GtkNotebook *notebook, return; } - gboolean visible = gtk_notebook_get_show_tabs(gs->notebook); - g_object_set(gs->menu_bar->view_submenu->tabs_menuitem, "visible", visible, NULL); - g_object_set(gs->menu_popup->view_submenu->tabs_menuitem, "visible", visible, NULL); - gs->buttons[NEXTTAB_BUTTON]->sensitivity = visible; - gs->buttons[PREVTAB_BUTTON]->sensitivity = visible; - gs->buttons[CLOSETAB_BUTTON]->sensitivity = visible; - nsgtk_scaffolding_set_sensitivity(gs); -} - -/** - * Handle opening a file path. - * - * \param filename The filename to open. - */ -static void nsgtk_openfile_open(const char *filename) -{ - struct browser_window *bw; - char *urltxt; - nsurl *url; - nserror error; - - bw = nsgtk_get_browser_window(scaf_current->top_level); - - urltxt = malloc(strlen(filename) + FILE_SCHEME_PREFIX_LEN + 1); - - if (urltxt != NULL) { - sprintf(urltxt, FILE_SCHEME_PREFIX"%s", filename); - - error = nsurl_create(urltxt, &url); - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } else { - browser_window_navigate(bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); - } - free(urltxt); - } -} - -/* signal handlers for menu entries */ - -MULTIHANDLER(newwindow) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - const char *addr; - nsurl *url; - nserror error; - - if (nsoption_charp(homepage_url) != NULL) { - addr = nsoption_charp(homepage_url); - } else { - addr = NETSURF_HOMEPAGE; - } - - error = nsurl_create(addr, &url); - if (error == NSERROR_OK) { - error = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - bw, - NULL); - nsurl_unref(url); - } - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } - - return TRUE; -} - -/* exported interface documented in gtk/scaffolding.h */ -nserror nsgtk_scaffolding_new_tab(struct gui_window *gw) -{ - struct browser_window *bw = nsgtk_get_browser_window(gw); - nsurl *url = NULL; - nserror error; - - if (!nsoption_bool(new_blank)) { - const char *addr; - if (nsoption_charp(homepage_url) != NULL) { - addr = nsoption_charp(homepage_url); - } else { - addr = NETSURF_HOMEPAGE; - } - error = nsurl_create(addr, &url); - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } - } - - error = browser_window_create(BW_CREATE_HISTORY | - BW_CREATE_TAB, - url, - NULL, - bw, - NULL); - if (url != NULL) { - nsurl_unref(url); - } - return error; -} + visible = gtk_notebook_get_show_tabs(gs->notebook); + g_object_set(gs->menu_bar->view_submenu->tabs_menuitem, + "visible", visible, NULL); + g_object_set(gs->burger_menu->view_submenu->tabs_menuitem, + "visible", visible, NULL); -MULTIHANDLER(newtab) -{ - nserror error; + gs->menus[NEXTTAB_BUTTON].sensitivity = visible; + gs->menus[PREVTAB_BUTTON].sensitivity = visible; + gs->menus[CLOSETAB_BUTTON].sensitivity = visible; - error = nsgtk_scaffolding_new_tab(g->top_level); - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } - return TRUE; + nsgtk_scaffolding_set_sensitivity(gs); } -MULTIHANDLER(openfile) -{ - GtkWidget *dlgOpen; - gint response; - - scaf_current = g; - dlgOpen = gtk_file_chooser_dialog_new("Open File", - scaf_current->window, - GTK_FILE_CHOOSER_ACTION_OPEN, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_OPEN, GTK_RESPONSE_OK, - NULL, NULL); - - response = gtk_dialog_run(GTK_DIALOG(dlgOpen)); - if (response == GTK_RESPONSE_OK) { - gchar *filename; - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlgOpen)); - - nsgtk_openfile_open((const char *)filename); - - g_free(filename); - } - gtk_widget_destroy(dlgOpen); - return TRUE; -} +/* signal handlers for menu entries */ /** - * callback to determine if a path is a directory. - * - * \param info The path information - * \param data context pointer set to NULL - * \return TRUE if path is a directory else false + * handle menu activate signals by calling toolbar item activation */ -static gboolean -nsgtk_filter_directory(const GtkFileFilterInfo *info, - gpointer data) -{ - DIR *d = opendir(info->filename); - if (d == NULL) - return FALSE; - closedir(d); - return TRUE; -} - -MULTIHANDLER(savepage) -{ - if (!browser_window_has_content(nsgtk_get_browser_window(g->top_level))) - return FALSE; - - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkcompleteSave"), g->window, - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - DIR *d; - char *path; - nserror res; - GtkFileFilter *filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "Directories"); - gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, - nsgtk_filter_directory, NULL, NULL); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fc), filter); - - res = nsurl_nice(browser_window_access_url( - nsgtk_get_browser_window(g->top_level)), &path, false); - if (res != NSERROR_OK) { - path = strdup(messages_get("SaveText")); - if (path == NULL) { - nsgtk_warning("NoMemory", 0); - return FALSE; - } - } - - if (access(path, F_OK) != 0) - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), path); - free(path); - - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc), - TRUE); - - if (gtk_dialog_run(GTK_DIALOG(fc)) != GTK_RESPONSE_ACCEPT) { - gtk_widget_destroy(fc); - return TRUE; - } - - path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); - d = opendir(path); - if (d == NULL) { - NSLOG(netsurf, INFO, - "Unable to open directory %s for complete save: %s", - path, - strerror(errno)); - if (errno == ENOTDIR) - nsgtk_warning("NoDirError", path); - else - nsgtk_warning("gtkFileError", path); - gtk_widget_destroy(fc); - g_free(path); - return TRUE; - } - closedir(d); - save_complete(browser_window_get_content(nsgtk_get_browser_window( - g->top_level)), path, NULL); - g_free(path); - - gtk_widget_destroy(fc); - - return TRUE; -} - - -MULTIHANDLER(pdf) -{ -#ifdef WITH_PDF_EXPORT - - GtkWidget *save_dialog; - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - struct print_settings *settings; - char filename[PATH_MAX]; - char dirname[PATH_MAX]; - char *url_name; - nserror res; - - NSLOG(netsurf, INFO, "Print preview (generating PDF) started."); - - res = nsurl_nice(browser_window_access_url(bw), &url_name, true); - if (res != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(res), 0); - return TRUE; - } - - strncpy(filename, url_name, PATH_MAX); - strncat(filename, ".pdf", PATH_MAX - strlen(filename)); - filename[PATH_MAX - 1] = '\0'; - - free(url_name); - - strncpy(dirname, option_downloads_directory, PATH_MAX); - strncat(dirname, "/", PATH_MAX - strlen(dirname)); - dirname[PATH_MAX - 1] = '\0'; - - /* this way the scale used by PDF functions is synchronised with that - * used by the all-purpose print interface - */ - haru_nsfont_set_scale((float)option_export_scale / 100); - - save_dialog = gtk_file_chooser_dialog_new("Export to PDF", g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - dirname); - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - filename); - - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - - settings = print_make_settings(PRINT_OPTIONS, - (const char *) filename, &haru_nsfont); - g_free(filename); - - if (settings == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - gtk_widget_destroy(save_dialog); - return TRUE; - } - - /* This will clean up the print_settings object for us */ - print_basic_run(browser_window_get_content(bw), - &pdf_printer, settings); - } - - gtk_widget_destroy(save_dialog); - -#endif /* WITH_PDF_EXPORT */ - - return TRUE; -} - -MULTIHANDLER(plaintext) -{ - if (!browser_window_has_content(nsgtk_get_browser_window(g->top_level))) - return FALSE; - - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkplainSave"), g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - char *filename; - nserror res; - - res = nsurl_nice(browser_window_access_url( - nsgtk_get_browser_window(g->top_level)), - &filename, false); - if (res != NSERROR_OK) { - filename = strdup(messages_get("SaveText")); - if (filename == NULL) { - nsgtk_warning("NoMemory", 0); - return FALSE; - } - } - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), filename); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc), - TRUE); +#define TOOLBAR_ITEM_p(identifier, name) \ + static gboolean \ +nsgtk_on_##name##_activate_menu(GtkMenuItem *widget, gpointer data) \ +{ \ + struct nsgtk_scaffolding *gs = (struct nsgtk_scaffolding *)data;\ + nsgtk_window_item_activate(gs->top_level, identifier); \ + return TRUE; \ +} +#define TOOLBAR_ITEM_y(identifier, name) +#define TOOLBAR_ITEM_n(identifier, name) +#define TOOLBAR_ITEM(identifier, name, sensitivity, clicked, activate, label, iconame) \ + TOOLBAR_ITEM_ ## activate(identifier, name) +#include "gtk/toolbar_items.h" +#undef TOOLBAR_ITEM_y +#undef TOOLBAR_ITEM_n +#undef TOOLBAR_ITEM_p +#undef TOOLBAR_ITEM - free(filename); - if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) { - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); - save_as_text(browser_window_get_content( - nsgtk_get_browser_window( - g->top_level)), filename); - g_free(filename); - } - - gtk_widget_destroy(fc); - return TRUE; -} - -MULTIHANDLER(drawfile) -{ - return TRUE; -} - -MULTIHANDLER(postscript) -{ - return TRUE; -} - -MULTIHANDLER(printpreview) -{ - return TRUE; -} - - -MULTIHANDLER(print) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - - GtkPrintOperation *print_op; - GtkPageSetup *page_setup; - GtkPrintSettings *print_settings; - GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR; - struct print_settings *nssettings; - char *settings_fname = NULL; - - print_op = gtk_print_operation_new(); - if (print_op == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - return TRUE; - } - - /* use previously saved settings if any */ - netsurf_mkpath(&settings_fname, NULL, 2, nsgtk_config_home, "Print"); - if (settings_fname != NULL) { - print_settings = gtk_print_settings_new_from_file(settings_fname, NULL); - if (print_settings != NULL) { - gtk_print_operation_set_print_settings(print_op, - print_settings); - - /* We're not interested in the settings any more */ - g_object_unref(print_settings); - } - } - - content_to_print = browser_window_get_content(bw); - - page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL); - if (page_setup == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - free(settings_fname); - g_object_unref(print_op); - return TRUE; - } - gtk_print_operation_set_default_page_setup(print_op, page_setup); - - nssettings = print_make_settings(PRINT_DEFAULT, NULL, nsgtk_layout_table); - - g_signal_connect(print_op, "begin_print", - G_CALLBACK(gtk_print_signal_begin_print), nssettings); - g_signal_connect(print_op, "draw_page", - G_CALLBACK(gtk_print_signal_draw_page), NULL); - g_signal_connect(print_op, "end_print", - G_CALLBACK(gtk_print_signal_end_print), nssettings); - - if (content_get_type(browser_window_get_content(bw)) != - CONTENT_TEXTPLAIN) { - res = gtk_print_operation_run(print_op, - GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, - g->window, - NULL); - } - - /* if the settings were used save them for future use */ - if (settings_fname != NULL) { - if (res == GTK_PRINT_OPERATION_RESULT_APPLY) { - /* Do not increment the settings reference */ - print_settings = - gtk_print_operation_get_print_settings(print_op); - - gtk_print_settings_to_file(print_settings, - settings_fname, - NULL); - } - free(settings_fname); - } - - /* Our print_settings object is destroyed by the end print handler */ - g_object_unref(page_setup); - g_object_unref(print_op); - - return TRUE; -} - -MULTIHANDLER(closewindow) -{ - gtk_widget_destroy(GTK_WIDGET(g->window)); - return TRUE; -} - -MULTIHANDLER(quit) -{ - struct nsgtk_scaffolding *gs; - - if (nsgtk_check_for_downloads(g->window) == false) { - gs = scaf_list; - while (gs != NULL) { - gtk_widget_destroy(GTK_WIDGET(gs->window)); - gs = gs->next; - } - } - - return TRUE; -} - -MENUHANDLER(savelink) +static gboolean +nsgtk_on_savelink_activate_menu(GtkMenuItem *widget, gpointer data) { struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *) data; struct gui_window *gui = g->top_level; @@ -1083,10 +518,12 @@ MENUHANDLER(savelink) return TRUE; } + /** * Handler for opening new window from a link. attached to the popup menu. */ -MENUHANDLER(link_openwin) +static gboolean +nsgtk_on_link_openwin_activate_menu(GtkMenuItem *widget, gpointer data) { struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *) data; struct gui_window *gui = g->top_level; @@ -1105,10 +542,12 @@ MENUHANDLER(link_openwin) return TRUE; } + /** * Handler for opening new tab from a link. attached to the popup menu. */ -MENUHANDLER(link_opentab) +static gboolean +nsgtk_on_link_opentab_activate_menu(GtkMenuItem *widget, gpointer data) { struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *) data; struct gui_window *gui = g->top_level; @@ -1118,8 +557,6 @@ MENUHANDLER(link_opentab) if (current_menu_features.link == NULL) return FALSE; - temp_open_background = 1; - err = browser_window_create(BW_CREATE_CLONE | BW_CREATE_HISTORY | BW_CREATE_TAB, @@ -1128,15 +565,15 @@ MENUHANDLER(link_opentab) nsgtk_warning(messages_get_errorcode(err), 0); } - temp_open_background = -1; - return TRUE; } + /** * Handler for bookmarking a link. attached to the popup menu. */ -MENUHANDLER(link_bookmark) +static gboolean +nsgtk_on_link_bookmark_activate_menu(GtkMenuItem *widget, gpointer data) { if (current_menu_features.link == NULL) return FALSE; @@ -1146,10 +583,12 @@ MENUHANDLER(link_bookmark) return TRUE; } + /** * Handler for copying a link. attached to the popup menu. */ -MENUHANDLER(link_copy) +static gboolean +nsgtk_on_link_copy_activate_menu(GtkMenuItem *widget, gpointer data) { GtkClipboard *clipboard; @@ -1164,624 +603,346 @@ MENUHANDLER(link_copy) } -MULTIHANDLER(cut) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - GtkWidget *focused = gtk_window_get_focus(g->window); - - /* If the url bar has focus, let gtk handle it */ - if (GTK_IS_EDITABLE (focused)) - gtk_editable_cut_clipboard (GTK_EDITABLE(g->url_bar)); - else - browser_window_key_press(bw, NS_KEY_CUT_SELECTION); - - return TRUE; -} - -MULTIHANDLER(copy) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - GtkWidget *focused = gtk_window_get_focus(g->window); - - /* If the url bar has focus, let gtk handle it */ - if (GTK_IS_EDITABLE (focused)) - gtk_editable_copy_clipboard(GTK_EDITABLE(g->url_bar)); - else - browser_window_key_press(bw, NS_KEY_COPY_SELECTION); - - return TRUE; -} - -MULTIHANDLER(paste) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - GtkWidget *focused = gtk_window_get_focus(g->window); - - /* If the url bar has focus, let gtk handle it */ - if (GTK_IS_EDITABLE (focused)) - gtk_editable_paste_clipboard (GTK_EDITABLE (focused)); - else - browser_window_key_press(bw, NS_KEY_PASTE); - - return TRUE; -} - -MULTIHANDLER(delete) -{ - return TRUE; -} - -MENUHANDLER(customize) +static gboolean nsgtk_on_find_activate_menu(GtkMenuItem *widget, gpointer data) { struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - nsgtk_toolbar_customization_init(g); - return TRUE; -} - -MULTIHANDLER(selectall) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - if (nsgtk_widget_has_focus(GTK_WIDGET(g->url_bar))) { - NSLOG(netsurf, INFO, "Selecting all URL bar text"); - gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1); - } else { - NSLOG(netsurf, INFO, "Selecting all document text"); - browser_window_key_press(bw, NS_KEY_SELECT_ALL); - } + nsgtk_window_search_toggle(g->top_level); return TRUE; } -MULTIHANDLER(find) +static nserror get_bar_show(bool *menu, bool *tool) { - nsgtk_scaffolding_toggle_search_bar_visibility(g); - return TRUE; -} + const char *cur_bar_show; -MULTIHANDLER(preferences) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - GtkWidget* wndpreferences; + *menu = false; + *tool = false; - wndpreferences = nsgtk_preferences(bw, g->window); - if (wndpreferences != NULL) { - gtk_widget_show(GTK_WIDGET(wndpreferences)); + cur_bar_show = nsoption_charp(bar_show); + if (cur_bar_show != NULL) { + if (strcmp(cur_bar_show, "menu/tool") == 0) { + *menu = true; + *tool = true; + } else if (strcmp(cur_bar_show, "menu") == 0) { + *menu = true; + } else if (strcmp(cur_bar_show, "tool") == 0) { + *tool = true; + } } - return TRUE; -} - -MULTIHANDLER(zoomplus) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - float old_scale = nsgtk_get_scale_for_gui(g->top_level); - - browser_window_set_scale(bw, old_scale + 0.05, true); - - return TRUE; -} - -MULTIHANDLER(zoomnormal) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - - browser_window_set_scale(bw, 1.0, true); - - return TRUE; + return NSERROR_OK; } -MULTIHANDLER(zoomminus) +static nserror set_bar_show(const char *bar, bool show) { - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - float old_scale = nsgtk_get_scale_for_gui(g->top_level); + bool menu; + bool tool; + const char *new_bar_show; - browser_window_set_scale(bw, old_scale - 0.05, true); + get_bar_show(&menu, &tool); - return TRUE; -} + if (strcmp(bar, "menu") == 0) { + menu = show; + } else if (strcmp(bar, "tool") == 0) { + tool = show; + } -MULTIHANDLER(fullscreen) -{ - if (g->fullscreen) { - gtk_window_unfullscreen(g->window); + if ((menu == true) && (tool == true)) { + new_bar_show = "menu/tool"; + } else if (menu == true) { + new_bar_show = "menu"; + } else if (tool == true) { + new_bar_show = "tool"; } else { - gtk_window_fullscreen(g->window); + new_bar_show = "none"; } + nsoption_set_charp(bar_show, strdup(new_bar_show)); - g->fullscreen = !g->fullscreen; - - return TRUE; + return NSERROR_OK; } -MULTIHANDLER(viewsource) +static gboolean +nsgtk_on_menubar_activate_menu(GtkMenuItem *widget, gpointer data) { - nserror ret; + struct nsgtk_scaffolding *gs = (struct nsgtk_scaffolding *)data; + GtkCheckMenuItem *bmcmi; /* burger menu check */ + GtkCheckMenuItem *mbcmi; /* menu bar check */ + GtkCheckMenuItem *tbcmi; /* popup menu check */ - ret = nsgtk_viewsource(g->window, nsgtk_get_browser_window(g->top_level)); - if (ret != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(ret), 0); - } - - return TRUE; -} - -MENUHANDLER(menubar) -{ - GtkWidget *w; - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; + bmcmi = GTK_CHECK_MENU_ITEM(gs->burger_menu->view_submenu->toolbars_submenu->menubar_menuitem); + mbcmi = GTK_CHECK_MENU_ITEM(gs->menu_bar->view_submenu->toolbars_submenu->menubar_menuitem); + tbcmi = GTK_CHECK_MENU_ITEM(gs->popup_menu->toolbars_submenu->menubar_menuitem); - /* if the menubar is not being shown the popup menu shows the - * menubar entries instead. - */ + /* ensure menubar and burger menu checkboxes are both updated */ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { - /* need to synchronise menus as gtk grumbles when one menu - * is attached to both headers */ - w = GTK_WIDGET(g->menu_popup->view_submenu->toolbars_submenu->menubar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) - == FALSE) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - TRUE); - - w = GTK_WIDGET(g->menu_bar->view_submenu->toolbars_submenu->menubar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) - == FALSE) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - TRUE); - - gtk_widget_show(GTK_WIDGET(g->menu_bar->bar_menu)); - - popup_menu_show(g->menu_popup, false, true, true, true); - popup_menu_hide(g->menu_popup, true, false, false, false); - } else { - w = GTK_WIDGET(g->menu_popup->view_submenu->toolbars_submenu->menubar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - FALSE); - - w = GTK_WIDGET(g->menu_bar->view_submenu->toolbars_submenu->menubar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - FALSE); - - gtk_widget_hide(GTK_WIDGET(g->menu_bar->bar_menu)); - - popup_menu_show(g->menu_popup, true, true, true, true); + if (gtk_check_menu_item_get_active(bmcmi) == FALSE) { + gtk_check_menu_item_set_active(bmcmi, TRUE); + } - } - return TRUE; -} + if (gtk_check_menu_item_get_active(mbcmi) == FALSE) { + gtk_check_menu_item_set_active(mbcmi, TRUE); + } -MENUHANDLER(toolbar) -{ - GtkWidget *w; - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; + if (gtk_check_menu_item_get_active(tbcmi) == FALSE) { + gtk_check_menu_item_set_active(tbcmi, TRUE); + } - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { - w = GTK_WIDGET(g->menu_popup->view_submenu->toolbars_submenu->toolbar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) - == FALSE) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - TRUE); - - w = GTK_WIDGET(g->menu_bar->view_submenu->toolbars_submenu->toolbar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)) - == FALSE) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - TRUE); - gtk_widget_show(GTK_WIDGET(g->tool_bar)); + gtk_widget_show(GTK_WIDGET(gs->menu_bar->bar_menu)); + set_bar_show("menu", true); } else { - w = GTK_WIDGET(g->menu_popup->view_submenu->toolbars_submenu->toolbar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - FALSE); - w = GTK_WIDGET(g->menu_bar->view_submenu->toolbars_submenu->toolbar_menuitem); - if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), - FALSE); - gtk_widget_hide(GTK_WIDGET(g->tool_bar)); - } - - return TRUE; -} - -MULTIHANDLER(downloads) -{ - nsgtk_download_show(g->window); - - return TRUE; -} - -MULTIHANDLER(savewindowsize) -{ - int x,y,w,h; - char *choices = NULL; + if (gtk_check_menu_item_get_active(bmcmi) == TRUE) { + gtk_check_menu_item_set_active(bmcmi, FALSE); + } - gtk_window_get_position(g->window, &x, &y); - gtk_window_get_size(g->window, &w, &h); + if (gtk_check_menu_item_get_active(mbcmi) == TRUE) { + gtk_check_menu_item_set_active(mbcmi, FALSE); + } - nsoption_set_int(window_width, w); - nsoption_set_int(window_height, h); - nsoption_set_int(window_x, x); - nsoption_set_int(window_y, y); + if (gtk_check_menu_item_get_active(tbcmi) == TRUE) { + gtk_check_menu_item_set_active(tbcmi, FALSE); + } - netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); - if (choices != NULL) { - nsoption_write(choices, NULL, NULL); - free(choices); + gtk_widget_hide(GTK_WIDGET(gs->menu_bar->bar_menu)); + set_bar_show("menu", false); } - return TRUE; } -MULTIHANDLER(toggledebugging) -{ - struct browser_window *bw; - - bw = nsgtk_get_browser_window(g->top_level); - - browser_window_debug(bw, CONTENT_DEBUG_REDRAW); - - nsgtk_reflow_all_windows(); - - return TRUE; -} -MULTIHANDLER(debugboxtree) +static gboolean +nsgtk_on_toolbar_activate_menu(GtkMenuItem *widget, gpointer data) { - gchar *fname; - gint handle; - FILE *f; - struct browser_window *bw; + struct nsgtk_scaffolding *gs = (struct nsgtk_scaffolding *)data; + GtkCheckMenuItem *bmcmi; /* burger menu check */ + GtkCheckMenuItem *mbcmi; /* menu bar check */ + GtkCheckMenuItem *tbcmi; /* popup menu check */ - handle = g_file_open_tmp("nsgtkboxtreeXXXXXX", &fname, NULL); - if ((handle == -1) || (fname == NULL)) { - return TRUE; - } - close(handle); /* in case it was binary mode */ - - /* save data to temporary file */ - f = fopen(fname, "w"); - if (f == NULL) { - nsgtk_warning("Error saving box tree dump.", - "Unable to open file for writing."); - unlink(fname); - return TRUE; - } - - bw = nsgtk_get_browser_window(g->top_level); + bmcmi = GTK_CHECK_MENU_ITEM(gs->burger_menu->view_submenu->toolbars_submenu->toolbar_menuitem); + mbcmi = GTK_CHECK_MENU_ITEM(gs->menu_bar->view_submenu->toolbars_submenu->toolbar_menuitem); + tbcmi = GTK_CHECK_MENU_ITEM(gs->popup_menu->toolbars_submenu->toolbar_menuitem); - browser_window_debug_dump(bw, f, CONTENT_DEBUG_RENDER); + /* ensure menubar and burger menu checkboxes are both updated */ + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) { + if (gtk_check_menu_item_get_active(bmcmi) == FALSE) { + gtk_check_menu_item_set_active(bmcmi, TRUE); + } - fclose(f); + if (gtk_check_menu_item_get_active(mbcmi) == FALSE) { + gtk_check_menu_item_set_active(mbcmi, TRUE); + } - nsgtk_viewfile("Box Tree Debug", "boxtree", fname); + if (gtk_check_menu_item_get_active(tbcmi) == FALSE) { + gtk_check_menu_item_set_active(tbcmi, TRUE); + } - g_free(fname); + nsgtk_window_toolbar_show(gs, true); + set_bar_show("tool", true); + } else { + if (gtk_check_menu_item_get_active(bmcmi) == TRUE) { + gtk_check_menu_item_set_active(bmcmi, FALSE); + } - return TRUE; -} + if (gtk_check_menu_item_get_active(mbcmi) == TRUE) { + gtk_check_menu_item_set_active(mbcmi, FALSE); + } -MULTIHANDLER(debugdomtree) -{ - gchar *fname; - gint handle; - FILE *f; - struct browser_window *bw; + if (gtk_check_menu_item_get_active(tbcmi) == TRUE) { + gtk_check_menu_item_set_active(tbcmi, FALSE); + } - handle = g_file_open_tmp("nsgtkdomtreeXXXXXX", &fname, NULL); - if ((handle == -1) || (fname == NULL)) { - return TRUE; + nsgtk_window_toolbar_show(gs, false); + set_bar_show("tool", false); } - close(handle); /* in case it was binary mode */ - - /* save data to temporary file */ - f = fopen(fname, "w"); - if (f == NULL) { - nsgtk_warning("Error saving box tree dump.", - "Unable to open file for writing."); - unlink(fname); - return TRUE; - } - - bw = nsgtk_get_browser_window(g->top_level); - - browser_window_debug_dump(bw, f, CONTENT_DEBUG_DOM); - - fclose(f); - - nsgtk_viewfile("DOM Tree Debug", "domtree", fname); - - g_free(fname); - return TRUE; } -MULTIHANDLER(stop) +static gboolean +nsgtk_on_nexttab_activate_menu(GtkMenuItem *widget, gpointer data) { - struct browser_window *bw = - nsgtk_get_browser_window(g->top_level); + struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - browser_window_stop(bw); + nsgtk_tab_next(g->notebook); return TRUE; } -MULTIHANDLER(reload) -{ - struct browser_window *bw = - nsgtk_get_browser_window(g->top_level); - if (bw == NULL) - return TRUE; - - /* clear potential search effects */ - browser_window_search_clear(bw); - browser_window_reload(bw, true); - - return TRUE; -} - -MULTIHANDLER(back) +static gboolean +nsgtk_on_prevtab_activate_menu(GtkMenuItem *widget, gpointer data) { - struct browser_window *bw = - nsgtk_get_browser_window(g->top_level); - - if ((bw == NULL) || (!browser_window_history_back_available(bw))) - return TRUE; - - /* clear potential search effects */ - browser_window_search_clear(bw); + struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - browser_window_history_back(bw, false); - scaffolding_update_context(g); + nsgtk_tab_prev(g->notebook); return TRUE; } -MULTIHANDLER(forward) -{ - struct browser_window *bw = - nsgtk_get_browser_window(g->top_level); - - if ((bw == NULL) || (!browser_window_history_forward_available(bw))) - return TRUE; - - /* clear potential search effects */ - browser_window_search_clear(bw); - - browser_window_history_forward(bw, false); - scaffolding_update_context(g); - - return TRUE; -} -MULTIHANDLER(home) +/** + * menu signal handler for activation on close tab item + */ +static gboolean +nsgtk_on_closetab_activate_menu(GtkMenuItem *widget, gpointer data) { - static const char *addr = NETSURF_HOMEPAGE; - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - nsurl *url; - nserror error; - - if (nsoption_charp(homepage_url) != NULL) { - addr = nsoption_charp(homepage_url); - } + struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - error = nsurl_create(addr, &url); - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } else { - browser_window_navigate(bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); - } + nsgtk_tab_close_current(g->notebook); return TRUE; } -MULTIHANDLER(localhistory) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - nserror res; +/* end of menu callback handlers */ - res = nsgtk_local_history_present(g->window, bw); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Unable to initialise local history window."); +/** + * attach gtk signal handlers for menus + */ +static void nsgtk_menu_connect_signals(struct nsgtk_scaffolding *g) +{ + int idx; /* item index */ + for (idx = BACK_BUTTON; idx < PLACEHOLDER_BUTTON; idx++) { + if (g->menus[idx].main != NULL) { + g_signal_connect(g->menus[idx].main, + "activate", + G_CALLBACK(g->menus[idx].mhandler), + g); + } + if (g->menus[idx].burger != NULL) { + g_signal_connect(g->menus[idx].burger, + "activate", + G_CALLBACK(g->menus[idx].mhandler), + g); + } + if (g->menus[idx].popup != NULL) { + g_signal_connect(g->menus[idx].popup, + "activate", + G_CALLBACK(g->menus[idx].mhandler), + g); + } } - return TRUE; } -MULTIHANDLER(globalhistory) -{ - nserror res; - res = nsgtk_global_history_present(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Unable to initialise global history window."); - } - return TRUE; -} -MULTIHANDLER(addbookmarks) +/** + * Create and connect handlers to bar menu. + * + * \param gs scaffolding to attach popup menu to. + * \param group The accelerator group to use for the popup. + * \param showmenu if the bar menu should be shown + * \param showtool if the toolabar should be shown + * \return menu structure on success or NULL on error. + */ +static struct nsgtk_bar_submenu * +create_scaffolding_bar_menu(struct nsgtk_scaffolding *gs, + GtkAccelGroup *group, + bool showmenu, + bool showtool) { - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); + GtkMenuShell *menushell; + struct nsgtk_bar_submenu *nmenu; - if (bw == NULL || !browser_window_has_content(bw)) - return TRUE; - hotlist_add_url(browser_window_access_url(bw)); - return TRUE; -} + menushell = GTK_MENU_SHELL(gtk_builder_get_object(gs->builder, + "menubar")); -MULTIHANDLER(showbookmarks) -{ - nserror res; - res = nsgtk_hotlist_present(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise bookmark window."); + nmenu = nsgtk_menu_bar_create(menushell, group); + if (nmenu == NULL) { + return NULL; } - return TRUE; -} -MULTIHANDLER(showcookies) -{ - nserror res; - res = nsgtk_cookies_present(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise cookies window."); + /* set menu bar visibility */ + if (showmenu) { + gtk_widget_show(GTK_WIDGET(nmenu->bar_menu)); + } else { + gtk_widget_hide(GTK_WIDGET(nmenu->bar_menu)); } - return TRUE; -} -MULTIHANDLER(openlocation) -{ - gtk_widget_grab_focus(GTK_WIDGET(g->url_bar)); - return TRUE; -} + /* set checks correct way on toolbar submenu */ + gtk_check_menu_item_set_active(nmenu->view_submenu->toolbars_submenu->menubar_menuitem, showmenu); + gtk_check_menu_item_set_active(nmenu->view_submenu->toolbars_submenu->toolbar_menuitem, showtool); -MULTIHANDLER(nexttab) -{ - nsgtk_tab_next(g->notebook); + /* bar menu signal handlers for edit controls */ + g_signal_connect(nmenu->edit_submenu->edit, + "show", + G_CALLBACK(nsgtk_window_edit_menu_shown), + gs); - return TRUE; -} + g_signal_connect(nmenu->edit_submenu->edit, + "hide", + G_CALLBACK(nsgtk_window_edit_menu_hidden), + gs); -MULTIHANDLER(prevtab) -{ + /* + * attach signal handlers for menubar and toolbar visibility toggling + */ + g_signal_connect(nmenu->view_submenu->toolbars_submenu->menubar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_menubar_activate_menu), + gs); - nsgtk_tab_prev(g->notebook); + g_signal_connect(nmenu->view_submenu->toolbars_submenu->toolbar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_toolbar_activate_menu), + gs); - return TRUE; -} -MULTIHANDLER(closetab) -{ - nsgtk_tab_close_current(g->notebook); - - return TRUE; + return nmenu; } -MULTIHANDLER(contents) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - nsurl *url; - nserror error; - - error = nsurl_create("http://www.netsurf-browser.org/documentation/", &url); - if (error != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(error), 0); - } else { - browser_window_navigate(bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); - } - return TRUE; -} - -MULTIHANDLER(guide) +/** + * Create and connect handlers to burger menu. + * + * \param g scaffolding to attach popup menu to. + * \param group The accelerator group to use for the popup. + * \param showbar if the bar menu should be shown + * \param showtool if the toolabar should be shown + * \return menu structure on success or NULL on error. + */ +static struct nsgtk_burger_menu * +create_scaffolding_burger_menu(struct nsgtk_scaffolding *gs, + GtkAccelGroup *group, + bool showbar, + bool showtool) { - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - nsurl *url; + struct nsgtk_burger_menu *nmenu; - if (nsurl_create("http://www.netsurf-browser.org/documentation/guide", &url) != NSERROR_OK) { - nsgtk_warning("NoMemory", 0); - } else { - browser_window_navigate(bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); - } + nmenu = nsgtk_burger_menu_create(group); - return TRUE; -} - -MULTIHANDLER(info) -{ - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - nsurl *url; - - if (nsurl_create("http://www.netsurf-browser.org/documentation/info", &url) != NSERROR_OK) { - nsgtk_warning("NoMemory", 0); - } else { - browser_window_navigate(bw, - url, - NULL, - BW_NAVIGATE_HISTORY, - NULL, - NULL, - NULL); - nsurl_unref(url); + if (nmenu == NULL) { + return NULL; } - return TRUE; -} - -MULTIHANDLER(about) -{ - nsgtk_about_dialog_init(g->window); - return TRUE; -} + /* set checks correct way on toolbar submenu */ + gtk_check_menu_item_set_active(nmenu->view_submenu->toolbars_submenu->menubar_menuitem, showbar); + gtk_check_menu_item_set_active(nmenu->view_submenu->toolbars_submenu->toolbar_menuitem, showtool); -BUTTONHANDLER(history) -{ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - return nsgtk_on_localhistory_activate(g); + g_signal_connect(nmenu->view_submenu->toolbars_submenu->menubar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_menubar_activate_menu), + gs); + g_signal_connect(nmenu->view_submenu->toolbars_submenu->toolbar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_toolbar_activate_menu), + gs); + return nmenu; } -#undef MULTIHANDLER -#undef CHECKHANDLER -#undef BUTTONHANDLER - -static void nsgtk_attach_menu_handlers(struct nsgtk_scaffolding *g) -{ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if (g->buttons[i]->main != NULL) { - g_signal_connect(g->buttons[i]->main, "activate", - G_CALLBACK(g->buttons[i]->mhandler), g); - } - if (g->buttons[i]->rclick != NULL) { - g_signal_connect(g->buttons[i]->rclick, "activate", - G_CALLBACK(g->buttons[i]->mhandler), g); - } - if (g->buttons[i]->popup != NULL) { - g_signal_connect(g->buttons[i]->popup, "activate", - G_CALLBACK(g->buttons[i]->mhandler), g); - } - } -#define CONNECT_CHECK(q)\ - g_signal_connect(g->menu_bar->view_submenu->toolbars_submenu->q##_menuitem, "toggled", G_CALLBACK(nsgtk_on_##q##_activate_menu), g);\ - g_signal_connect(g->menu_popup->view_submenu->toolbars_submenu->q##_menuitem, "toggled", G_CALLBACK(nsgtk_on_##q##_activate_menu), g) - CONNECT_CHECK(menubar); - CONNECT_CHECK(toolbar); -#undef CONNECT_CHECK - -} /** * Create and connect handlers to popup menu. * - * \param g scaffolding to attach popup menu to. + * \param gs scaffolding to attach popup menu to. * \param group The accelerator group to use for the popup. + * \param showbar if the bar menu should be shown + * \param showtool if the toolabar should be shown * \return menu structure on success or NULL on error. */ static struct nsgtk_popup_menu * -nsgtk_new_scaffolding_popup(struct nsgtk_scaffolding *g, GtkAccelGroup *group) +create_scaffolding_popup_menu(struct nsgtk_scaffolding *gs, + GtkAccelGroup *group, + bool showbar, + bool showtool) { struct nsgtk_popup_menu *nmenu; @@ -1790,28 +951,31 @@ nsgtk_new_scaffolding_popup(struct nsgtk_scaffolding *g, GtkAccelGroup *group) if (nmenu == NULL) { return NULL; } + /* set checks correct way on toolbar submenu */ + gtk_check_menu_item_set_active(nmenu->toolbars_submenu->menubar_menuitem, showbar); + gtk_check_menu_item_set_active(nmenu->toolbars_submenu->toolbar_menuitem, showtool); - g_signal_connect(nmenu->popup_menu, "hide", - G_CALLBACK(nsgtk_window_popup_menu_hidden), g); - - g_signal_connect(nmenu->cut_menuitem, "activate", - G_CALLBACK(nsgtk_on_cut_activate_menu), g); - - g_signal_connect(nmenu->copy_menuitem, "activate", - G_CALLBACK(nsgtk_on_copy_activate_menu), g); + g_signal_connect(nmenu->popup_menu, + "hide", + G_CALLBACK(nsgtk_window_popup_menu_hidden), + gs); - g_signal_connect(nmenu->paste_menuitem, "activate", - G_CALLBACK(nsgtk_on_paste_activate_menu), g); - - g_signal_connect(nmenu->customize_menuitem, "activate", - G_CALLBACK(nsgtk_on_customize_activate_menu), g); + g_signal_connect(nmenu->toolbars_submenu->menubar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_menubar_activate_menu), + gs); + g_signal_connect(nmenu->toolbars_submenu->toolbar_menuitem, + "toggled", + G_CALLBACK(nsgtk_on_toolbar_activate_menu), + gs); /* set initial popup menu visibility */ - popup_menu_hide(nmenu, true, false, false, true); + popup_menu_hide(nmenu, false, false); return nmenu; } + /** * Create and connect handlers to link popup menu. * @@ -1820,7 +984,7 @@ nsgtk_new_scaffolding_popup(struct nsgtk_scaffolding *g, GtkAccelGroup *group) * \return true on success or false on error. */ static struct nsgtk_link_menu * -nsgtk_new_scaffolding_link_popup(struct nsgtk_scaffolding *g, GtkAccelGroup *group) +create_scaffolding_link_menu(struct nsgtk_scaffolding *g, GtkAccelGroup *group) { struct nsgtk_link_menu *nmenu; @@ -1830,482 +994,261 @@ nsgtk_new_scaffolding_link_popup(struct nsgtk_scaffolding *g, GtkAccelGroup *gro return NULL; } - g_signal_connect(nmenu->save_menuitem, "activate", - G_CALLBACK(nsgtk_on_savelink_activate_menu), g); + g_signal_connect(nmenu->save_menuitem, + "activate", + G_CALLBACK(nsgtk_on_savelink_activate_menu), + g); - g_signal_connect(nmenu->opentab_menuitem, "activate", - G_CALLBACK(nsgtk_on_link_opentab_activate_menu), g); + g_signal_connect(nmenu->opentab_menuitem, + "activate", + G_CALLBACK(nsgtk_on_link_opentab_activate_menu), + g); - g_signal_connect(nmenu->openwin_menuitem, "activate", - G_CALLBACK(nsgtk_on_link_openwin_activate_menu), g); + g_signal_connect(nmenu->openwin_menuitem, + "activate", + G_CALLBACK(nsgtk_on_link_openwin_activate_menu), + g); - g_signal_connect(nmenu->bookmark_menuitem, "activate", - G_CALLBACK(nsgtk_on_link_bookmark_activate_menu), g); + g_signal_connect(nmenu->bookmark_menuitem, + "activate", + G_CALLBACK(nsgtk_on_link_bookmark_activate_menu), + g); - g_signal_connect(nmenu->copy_menuitem, "activate", - G_CALLBACK(nsgtk_on_link_copy_activate_menu), g); + g_signal_connect(nmenu->copy_menuitem, + "activate", + G_CALLBACK(nsgtk_on_link_copy_activate_menu), + g); return nmenu; } -/* exported interface documented in gtk/scaffolding.h */ -struct nsgtk_scaffolding *nsgtk_current_scaffolding(void) -{ - if (scaf_current == NULL) { - scaf_current = scaf_list; - } - return scaf_current; -} /** - * init the array g->buttons[] + * initialiase the menu signal handlers ready for connection */ -static void nsgtk_scaffolding_toolbar_init(struct nsgtk_scaffolding *g) -{ -#define ITEM_MAIN(p, q, r)\ - g->buttons[p##_BUTTON]->main = g->menu_bar->q->r##_menuitem;\ - g->buttons[p##_BUTTON]->rclick = g->menu_popup->q->r##_menuitem;\ - g->buttons[p##_BUTTON]->mhandler = nsgtk_on_##r##_activate_menu;\ - g->buttons[p##_BUTTON]->bhandler = nsgtk_on_##r##_activate_button;\ - g->buttons[p##_BUTTON]->dataplus = nsgtk_toolbar_##r##_button_data;\ - g->buttons[p##_BUTTON]->dataminus = nsgtk_toolbar_##r##_toolbar_button_data - -#define ITEM_SUB(p, q, r, s)\ - g->buttons[p##_BUTTON]->main =\ - g->menu_bar->q->r##_submenu->s##_menuitem;\ - g->buttons[p##_BUTTON]->rclick =\ - g->menu_popup->q->r##_submenu->s##_menuitem;\ - g->buttons[p##_BUTTON]->mhandler =\ - nsgtk_on_##s##_activate_menu;\ - g->buttons[p##_BUTTON]->bhandler =\ - nsgtk_on_##s##_activate_button;\ - g->buttons[p##_BUTTON]->dataplus =\ - nsgtk_toolbar_##s##_button_data;\ - g->buttons[p##_BUTTON]->dataminus =\ - nsgtk_toolbar_##s##_toolbar_button_data - -#define ITEM_BUTTON(p, q)\ - g->buttons[p##_BUTTON]->bhandler =\ - nsgtk_on_##q##_activate;\ - g->buttons[p##_BUTTON]->dataplus =\ - nsgtk_toolbar_##q##_button_data;\ - g->buttons[p##_BUTTON]->dataminus =\ - nsgtk_toolbar_##q##_toolbar_button_data - -#define ITEM_POP(p, q) \ - g->buttons[p##_BUTTON]->popup = g->menu_popup->q##_menuitem - -#define SENSITIVITY(q) \ - g->buttons[q##_BUTTON]->sensitivity = false - -#define ITEM_ITEM(p, q)\ - g->buttons[p##_ITEM]->dataplus =\ - nsgtk_toolbar_##q##_button_data;\ - g->buttons[p##_ITEM]->dataminus =\ - nsgtk_toolbar_##q##_toolbar_button_data - - ITEM_ITEM(WEBSEARCH, websearch); - ITEM_ITEM(THROBBER, throbber); - ITEM_MAIN(NEWWINDOW, file_submenu, newwindow); - ITEM_MAIN(NEWTAB, file_submenu, newtab); - ITEM_MAIN(OPENFILE, file_submenu, openfile); - ITEM_MAIN(PRINT, file_submenu, print); - ITEM_MAIN(CLOSEWINDOW, file_submenu, closewindow); - ITEM_MAIN(SAVEPAGE, file_submenu, savepage); - ITEM_MAIN(PRINTPREVIEW, file_submenu, printpreview); - ITEM_MAIN(PRINT, file_submenu, print); - ITEM_MAIN(QUIT, file_submenu, quit); - ITEM_MAIN(CUT, edit_submenu, cut); - ITEM_MAIN(COPY, edit_submenu, copy); - ITEM_MAIN(PASTE, edit_submenu, paste); - ITEM_MAIN(DELETE, edit_submenu, delete); - ITEM_MAIN(SELECTALL, edit_submenu, selectall); - ITEM_MAIN(FIND, edit_submenu, find); - ITEM_MAIN(PREFERENCES, edit_submenu, preferences); - ITEM_MAIN(STOP, view_submenu, stop); - ITEM_POP(STOP, stop); - ITEM_MAIN(RELOAD, view_submenu, reload); - ITEM_POP(RELOAD, reload); - ITEM_MAIN(FULLSCREEN, view_submenu, fullscreen); - ITEM_MAIN(DOWNLOADS, tools_submenu, downloads); - ITEM_MAIN(SAVEWINDOWSIZE, view_submenu, savewindowsize); - ITEM_MAIN(BACK, nav_submenu, back); - ITEM_POP(BACK, back); - ITEM_MAIN(FORWARD, nav_submenu, forward); - ITEM_POP(FORWARD, forward); - ITEM_MAIN(HOME, nav_submenu, home); - ITEM_MAIN(LOCALHISTORY, nav_submenu, localhistory); - ITEM_MAIN(GLOBALHISTORY, nav_submenu, globalhistory); - ITEM_MAIN(ADDBOOKMARKS, nav_submenu, addbookmarks); - ITEM_MAIN(SHOWBOOKMARKS, nav_submenu, showbookmarks); - ITEM_MAIN(SHOWCOOKIES, tools_submenu, showcookies); - ITEM_MAIN(OPENLOCATION, nav_submenu, openlocation); - ITEM_MAIN(CONTENTS, help_submenu, contents); - ITEM_MAIN(INFO, help_submenu, info); - ITEM_MAIN(GUIDE, help_submenu, guide); - ITEM_MAIN(ABOUT, help_submenu, about); - ITEM_SUB(PLAINTEXT, file_submenu, export, plaintext); - ITEM_SUB(PDF, file_submenu, export, pdf); - ITEM_SUB(DRAWFILE, file_submenu, export, drawfile); - ITEM_SUB(POSTSCRIPT, file_submenu, export, postscript); - ITEM_SUB(ZOOMPLUS, view_submenu, scaleview, zoomplus); - ITEM_SUB(ZOOMMINUS, view_submenu, scaleview, zoomminus); - ITEM_SUB(ZOOMNORMAL, view_submenu, scaleview, zoomnormal); - ITEM_SUB(NEXTTAB, view_submenu, tabs, nexttab); - ITEM_SUB(PREVTAB, view_submenu, tabs, prevtab); - ITEM_SUB(CLOSETAB, view_submenu, tabs, closetab); - - /* development submenu */ - ITEM_SUB(VIEWSOURCE, tools_submenu, developer, viewsource); - ITEM_SUB(TOGGLEDEBUGGING, tools_submenu, developer, toggledebugging); - ITEM_SUB(SAVEBOXTREE, tools_submenu, developer, debugboxtree); - ITEM_SUB(SAVEDOMTREE, tools_submenu, developer, debugdomtree); - ITEM_BUTTON(HISTORY, history); - - /* disable items that make no sense initially, as well as - * as-yet-unimplemented items */ - SENSITIVITY(BACK); - SENSITIVITY(FORWARD); - SENSITIVITY(STOP); - SENSITIVITY(PRINTPREVIEW); - SENSITIVITY(DELETE); - SENSITIVITY(DRAWFILE); - SENSITIVITY(POSTSCRIPT); - SENSITIVITY(NEXTTAB); - SENSITIVITY(PREVTAB); - SENSITIVITY(CLOSETAB); -#ifndef WITH_PDF_EXPORT - SENSITIVITY(PDF); -#endif - -#undef ITEM_MAIN -#undef ITEM_SUB -#undef ITEM_BUTTON -#undef ITEM_POP -#undef SENSITIVITY +static nserror nsgtk_menu_initialise(struct nsgtk_scaffolding *g) +{ +#define TOOLBAR_ITEM_p(identifier, name, iconame) \ + g->menus[identifier].mhandler = nsgtk_on_##name##_activate_menu; \ + g->menus[identifier].iconname = iconame; +#define TOOLBAR_ITEM_y(identifier, name, iconame) \ + g->menus[identifier].mhandler = nsgtk_on_##name##_activate_menu; \ + g->menus[identifier].iconname = iconame; +#define TOOLBAR_ITEM_n(identifier, name, iconame) \ + g->menus[identifier].mhandler = NULL; \ + g->menus[identifier].iconname = iconame; +#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \ + g->menus[identifier].sensitivity = snstvty; \ + TOOLBAR_ITEM_ ## activate(identifier, name, iconame) +#include "gtk/toolbar_items.h" +#undef TOOLBAR_ITEM_y +#undef TOOLBAR_ITEM_n +#undef TOOLBAR_ITEM + + /* items on menubar, burger */ +#define ITEM_MB(p, q, r) \ + g->menus[p##_BUTTON].main = g->menu_bar->r##_submenu->q##_menuitem; \ + g->menus[p##_BUTTON].burger = g->burger_menu->r##_submenu->q##_menuitem + + /* items on menubar, burger and context popup submenu */ +#define ITEM_MBP(p, q, r) \ + g->menus[p##_BUTTON].main = g->menu_bar->r##_submenu->q##_menuitem; \ + g->menus[p##_BUTTON].burger = g->burger_menu->r##_submenu->q##_menuitem; \ + g->menus[p##_BUTTON].popup = g->popup_menu->r##_submenu->q##_menuitem + + /* items on menubar, burger and context popup */ +#define ITEM_MBp(p, q, r) \ + g->menus[p##_BUTTON].main = g->menu_bar->r##_submenu->q##_menuitem; \ + g->menus[p##_BUTTON].burger = g->burger_menu->r##_submenu->q##_menuitem; \ + g->menus[p##_BUTTON].popup = g->popup_menu->q##_menuitem + + + /* file menu */ + ITEM_MB(NEWWINDOW, newwindow, file); + ITEM_MB(NEWTAB, newtab, file); + ITEM_MB(OPENFILE, openfile, file); + ITEM_MB(CLOSEWINDOW, closewindow, file); + ITEM_MB(PRINTPREVIEW, printpreview, file); + ITEM_MB(PRINT, print, file); + ITEM_MB(QUIT, quit, file); + /* file - export submenu */ + ITEM_MB(SAVEPAGE, savepage, file_submenu->export); + ITEM_MB(PLAINTEXT, plaintext, file_submenu->export); + ITEM_MB(PDF, pdf, file_submenu->export); + + /* edit menu */ + ITEM_MBp(CUT, cut, edit); + ITEM_MBp(COPY, copy, edit); + ITEM_MBp(PASTE, paste, edit); + ITEM_MB(DELETE, delete, edit); + ITEM_MB(SELECTALL, selectall, edit); + ITEM_MB(FIND, find, edit); + ITEM_MB(PREFERENCES, preferences, edit); + + /* view menu */ + ITEM_MB(FULLSCREEN, fullscreen, view); + ITEM_MB(SAVEWINDOWSIZE, savewindowsize, view); + /* view - scale submenu */ + ITEM_MB(ZOOMPLUS, zoomplus, view_submenu->scaleview); + ITEM_MB(ZOOMMINUS, zoomminus, view_submenu->scaleview); + ITEM_MB(ZOOMNORMAL, zoomnormal, view_submenu->scaleview); + /* view - tabs submenu */ + ITEM_MB(NEXTTAB, nexttab, view_submenu->tabs); + ITEM_MB(PREVTAB, prevtab, view_submenu->tabs); + ITEM_MB(CLOSETAB, closetab, view_submenu->tabs); + /* view - toolbars submenu */ + ITEM_MB(CUSTOMIZE, customize, view_submenu->toolbars); + g->menus[CUSTOMIZE_BUTTON].popup = g->popup_menu->toolbars_submenu->customize_menuitem; + + /* navigation menu */ + ITEM_MBp(BACK, back, nav); + ITEM_MBp(FORWARD, forward, nav); + ITEM_MBp(STOP, stop, nav); + ITEM_MBp(RELOAD, reload, nav); + ITEM_MB(HOME, home, nav); + ITEM_MB(LOCALHISTORY, localhistory, nav); + ITEM_MB(GLOBALHISTORY, globalhistory, nav); + ITEM_MB(ADDBOOKMARKS, addbookmarks, nav); + ITEM_MB(SHOWBOOKMARKS, showbookmarks, nav); + ITEM_MB(OPENLOCATION, openlocation, nav); + + /* tools menu */ + ITEM_MBP(DOWNLOADS, downloads, tools); + ITEM_MBP(SHOWCOOKIES, showcookies, tools); + /* tools > developer submenu */ + ITEM_MBP(VIEWSOURCE, viewsource, tools_submenu->developer); + ITEM_MBP(TOGGLEDEBUGGING, toggledebugging, tools_submenu->developer); + ITEM_MBP(SAVEBOXTREE, debugboxtree, tools_submenu->developer); + ITEM_MBP(SAVEDOMTREE, debugdomtree, tools_submenu->developer); + + /* help menu */ + ITEM_MB(CONTENTS, contents, help); + ITEM_MB(GUIDE, guide, help); + ITEM_MB(INFO, info, help); + ITEM_MB(ABOUT, about, help); + + +#undef ITEM_MB +#undef ITEM_MBp +#undef ITEM_MBP + return NSERROR_OK; } -static void nsgtk_scaffolding_initial_sensitivity(struct nsgtk_scaffolding *g) + +static void nsgtk_menu_set_sensitivity(struct nsgtk_scaffolding *g) { + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if (g->buttons[i]->main != NULL) - gtk_widget_set_sensitive(GTK_WIDGET( - g->buttons[i]->main), - g->buttons[i]->sensitivity); - if (g->buttons[i]->rclick != NULL) + if (g->menus[i].main != NULL) { gtk_widget_set_sensitive(GTK_WIDGET( - g->buttons[i]->rclick), - g->buttons[i]->sensitivity); - if ((g->buttons[i]->location != -1) && - (g->buttons[i]->button != NULL)) + g->menus[i].main), + g->menus[i].sensitivity); + } + if (g->menus[i].burger != NULL) { gtk_widget_set_sensitive(GTK_WIDGET( - g->buttons[i]->button), - g->buttons[i]->sensitivity); - if (g->buttons[i]->popup != NULL) + g->menus[i].burger), + g->menus[i].sensitivity); + } + if (g->menus[i].popup != NULL) { gtk_widget_set_sensitive(GTK_WIDGET( - g->buttons[i]->popup), - g->buttons[i]->sensitivity); + g->menus[i].popup), + g->menus[i].sensitivity); + } } - gtk_widget_set_sensitive(GTK_WIDGET(g->menu_bar->view_submenu->images_menuitem), FALSE); } -void nsgtk_scaffolding_toolbars(struct nsgtk_scaffolding *g, int tbi) -{ - switch (tbi) { - /* case 0 is 'unset' [from fresh install / clearing options] - * see above */ - - case 1: /* Small icons */ - /* main toolbar */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->tool_bar), - GTK_ICON_SIZE_SMALL_TOOLBAR); - /* search toolbar */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->search->bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->search->bar), - GTK_ICON_SIZE_SMALL_TOOLBAR); - break; - - case 2: /* Large icons */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->tool_bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - /* search toolbar */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->search->bar), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->search->bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - break; - - case 3: /* Large icons with text */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->tool_bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - /* search toolbar */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->search->bar), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(g->search->bar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - break; - - case 4: /* Text icons only */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), - GTK_TOOLBAR_TEXT); - /* search toolbar */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->search->bar), - GTK_TOOLBAR_TEXT); - default: - break; - } -} - -/* exported interface documented in gtk/scaffolding.h */ -struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) +/* set menu items to have icons */ +static void nsgtk_menu_set_icons(struct nsgtk_scaffolding *g) { - struct nsgtk_scaffolding *gs; - int i; - GtkAccelGroup *group; - - gs = calloc(1, sizeof(*gs)); - if (gs == NULL) { - return NULL; - } - - NSLOG(netsurf, INFO, - "Constructing a scaffold of %p for gui_window %p", gs, toplevel); - - gs->top_level = toplevel; - - /* Construct UI widgets */ - if (nsgtk_builder_new_from_resname("netsurf", &gs->builder) != NSERROR_OK) { - free(gs); - return NULL; - } - - gtk_builder_connect_signals(gs->builder, NULL); - -/** Obtain a GTK widget handle from UI builder object */ -#define GET_WIDGET(x) GTK_WIDGET (gtk_builder_get_object(gs->builder, (x))) - - gs->window = GTK_WINDOW(GET_WIDGET("wndBrowser")); - gs->notebook = GTK_NOTEBOOK(GET_WIDGET("notebook")); - gs->tool_bar = GTK_TOOLBAR(GET_WIDGET("toolbar")); - - gs->search = malloc(sizeof(struct gtk_search)); - if (gs->search == NULL) { - free(gs); - return NULL; - } - - gs->search->bar = GTK_TOOLBAR(GET_WIDGET("searchbar")); - gs->search->entry = GTK_ENTRY(GET_WIDGET("searchEntry")); - - gs->search->buttons[0] = GTK_TOOL_BUTTON(GET_WIDGET("searchBackButton")); - gs->search->buttons[1] = GTK_TOOL_BUTTON(GET_WIDGET("searchForwardButton")); - gs->search->buttons[2] = GTK_TOOL_BUTTON(GET_WIDGET("closeSearchButton")); - gs->search->checkAll = GTK_CHECK_BUTTON(GET_WIDGET("checkAllSearch")); - gs->search->caseSens = GTK_CHECK_BUTTON(GET_WIDGET("caseSensButton")); - -#undef GET_WIDGET - - /* allocate buttons */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - gs->buttons[i] = calloc(1, sizeof(struct nsgtk_button_connect)); - if (gs->buttons[i] == NULL) { - for (i-- ; i >= BACK_BUTTON; i--) { - free(gs->buttons[i]); - } - free(gs); - return NULL; + GtkWidget *img; + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + /* ensure there is an icon name */ + if (g->menus[i].iconname == NULL) { + continue; } - gs->buttons[i]->location = -1; - gs->buttons[i]->sensitivity = true; - } - - /* here custom toolbutton adding code */ - gs->offset = 0; - gs->toolbarmem = 0; - gs->toolbarbase = 0; - gs->historybase = 0; - nsgtk_toolbar_customization_load(gs); - nsgtk_toolbar_set_physical(gs); - - group = gtk_accel_group_new(); - gtk_window_add_accel_group(gs->window, group); - - gs->menu_bar = nsgtk_menu_bar_create(GTK_MENU_SHELL(gtk_builder_get_object(gs->builder, "menubar")), group); - - - /* set this window's size and position to what's in the options, or - * or some sensible default if they're not set yet. - */ - if (nsoption_int(window_width) > 0) { - gtk_window_move(gs->window, - nsoption_int(window_x), - nsoption_int(window_y)); - gtk_window_resize(gs->window, - nsoption_int(window_width), - nsoption_int(window_height)); - } else { - /* Set to 1000x700, so we're very likely to fit even on - * 1024x768 displays, not being able to take into account - * window furniture or panels. - */ - gtk_window_set_default_size(gs->window, 1000, 700); - } - - /* Default toolbar button type uses system defaults */ - if (nsoption_int(button_type) == 0) { - GtkSettings *settings = gtk_settings_get_default(); - GtkIconSize tooliconsize; - GtkToolbarStyle toolbarstyle; - - g_object_get(settings, - "gtk-toolbar-icon-size", &tooliconsize, - "gtk-toolbar-style", &toolbarstyle, NULL); - - switch (toolbarstyle) { - case GTK_TOOLBAR_ICONS: - if (tooliconsize == GTK_ICON_SIZE_SMALL_TOOLBAR) { - nsoption_set_int(button_type, 1); - } else { - nsoption_set_int(button_type, 2); - } - break; - case GTK_TOOLBAR_TEXT: - nsoption_set_int(button_type, 4); - break; - - case GTK_TOOLBAR_BOTH: - case GTK_TOOLBAR_BOTH_HORIZ: - /* no labels in default configuration */ - default: - /* No system default, so use large icons */ - nsoption_set_int(button_type, 2); - break; + if (g->menus[i].main != NULL) { + img = gtk_image_new_from_icon_name(g->menus[i].iconname, + GTK_ICON_SIZE_MENU); + nsgtk_image_menu_item_set_image(GTK_WIDGET(g->menus[i].main), img); + } + if (g->menus[i].burger != NULL) { + img = gtk_image_new_from_icon_name(g->menus[i].iconname, + GTK_ICON_SIZE_MENU); + nsgtk_image_menu_item_set_image(GTK_WIDGET(g->menus[i].burger), img); + } + if (g->menus[i].popup != NULL) { + img = gtk_image_new_from_icon_name(g->menus[i].iconname, + GTK_ICON_SIZE_MENU); + nsgtk_image_menu_item_set_image(GTK_WIDGET(g->menus[i].popup), img); } } +} - nsgtk_scaffolding_toolbars(gs, nsoption_int(button_type)); - - gtk_toolbar_set_show_arrow(gs->tool_bar, TRUE); - gtk_widget_show_all(GTK_WIDGET(gs->tool_bar)); - nsgtk_tab_init(gs); - - gtk_widget_set_size_request(GTK_WIDGET( - gs->buttons[HISTORY_BUTTON]->button), 20, -1); - - - /* set up URL bar completion */ - gs->url_bar_completion = nsgtk_url_entry_completion_new(gs); - - /* set up the throbber. */ - gs->throb_frame = 0; - - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - g_signal_connect_after(gs->notebook, "page-added", - G_CALLBACK(nsgtk_window_tabs_add), gs); - g_signal_connect_after(gs->notebook, "page-removed", - G_CALLBACK(nsgtk_window_tabs_remove), gs); - - /* connect main window signals to their handlers. */ - CONNECT(gs->window, "delete-event", - scaffolding_window_delete_event, gs); - - CONNECT(gs->window, "destroy", scaffolding_window_destroy, gs); - - /* toolbar URL bar menu bar search bar signal handlers */ - CONNECT(gs->menu_bar->edit_submenu->edit, "show", - nsgtk_window_edit_menu_shown, gs); - CONNECT(gs->menu_bar->edit_submenu->edit, "hide", - nsgtk_window_edit_menu_hidden, gs); - - CONNECT(gs->search->buttons[1], "clicked", - nsgtk_search_forward_button_clicked, gs); - - CONNECT(gs->search->buttons[0], "clicked", - nsgtk_search_back_button_clicked, gs); - - CONNECT(gs->search->entry, "changed", nsgtk_search_entry_changed, gs); - - CONNECT(gs->search->entry, "activate", nsgtk_search_entry_activate, gs); - - CONNECT(gs->search->entry, "key-press-event", - nsgtk_search_entry_key, gs); - CONNECT(gs->search->buttons[2], "clicked", - nsgtk_search_close_button_clicked, gs); +/** + * create and initialise menus + * + * There are four menus held by the scaffolding: + * + * 1. Main menubar menu. + * This can be hidden which causes the right click popup context menu + * to use the burger menu. + * 2. Burger menu. + * This can be opened from a burger icon on the toolbar. + * 3. popup context menu. + * This is opened by right mouse clicking on the toolbar or browser area + * 4. link context menu + * Opened like the other popup menu when the mouse is over a link in the + * browser area + * + * The cut, copy, paste, delete and back, forwards, stop, reload groups of + * menu entries are context sensitive and must be updated as appropriate + * when a menu is opened which contains those groups. + */ +static nserror nsgtk_menus_create(struct nsgtk_scaffolding *gs) +{ + GtkAccelGroup *group; + bool showmenu; /* show menubar */ + bool showtool; /* show toolbar */ - CONNECT(gs->search->caseSens, "toggled", - nsgtk_search_entry_changed, gs); + get_bar_show(&showmenu, &showtool); - CONNECT(gs->tool_bar, "popup-context-menu", - nsgtk_window_tool_bar_clicked, gs); + group = gtk_accel_group_new(); - /* create popup menu */ - gs->menu_popup = nsgtk_new_scaffolding_popup(gs, group); + gtk_window_add_accel_group(gs->window, group); - gs->link_menu = nsgtk_new_scaffolding_link_popup(gs, group); + gs->menu_bar = create_scaffolding_bar_menu(gs, group, showmenu, showtool); + gs->burger_menu = create_scaffolding_burger_menu(gs, group, showmenu, showtool); + gs->popup_menu = create_scaffolding_popup_menu(gs, group, showmenu, showtool); + gs->link_menu = create_scaffolding_link_menu(gs, group); /* set up the menu signal handlers */ - nsgtk_scaffolding_toolbar_init(gs); - nsgtk_toolbar_connect_all(gs); - nsgtk_attach_menu_handlers(gs); - - nsgtk_scaffolding_initial_sensitivity(gs); + nsgtk_menu_initialise(gs); + nsgtk_menu_set_icons(gs); + nsgtk_menu_connect_signals(gs); + nsgtk_menu_set_sensitivity(gs); - gs->fullscreen = false; - - /* attach to the list */ - if (scaf_list) { - scaf_list->prev = gs; - } - gs->next = scaf_list; - gs->prev = NULL; - scaf_list = gs; - - /* set icon images */ - nsgtk_theme_implement(gs); - - /* set web search provider */ - search_web_select_provider(nsoption_int(search_provider)); - - /* finally, show the window. */ - gtk_widget_show(GTK_WIDGET(gs->window)); - - NSLOG(netsurf, INFO, "creation complete"); - - return gs; + return NSERROR_OK; } + /* exported function documented in gtk/scaffolding.h */ -void nsgtk_window_set_title(struct gui_window *gw, const char *title) +void nsgtk_scaffolding_set_title(struct gui_window *gw, const char *title) { struct nsgtk_scaffolding *gs = nsgtk_get_scaffold(gw); int title_len; char *newtitle; - if ((title == NULL) || (title[0] == '\0')) { - if (gs->top_level != gw) { - gtk_window_set_title(gs->window, "NetSurf"); - } + /* only set window title if top level window */ + if (gs->top_level != gw) { return; } - nsgtk_tab_set_title(gw, title); - - if (gs->top_level != gw) { - /* not top level window so do not set window title */ + if (title == NULL || title[0] == '\0') { + gtk_window_set_title(gs->window, "NetSurf"); return; } @@ -2320,213 +1263,48 @@ void nsgtk_window_set_title(struct gui_window *gw, const char *title) gtk_window_set_title(gs->window, newtitle); free(newtitle); -} - -nserror gui_window_set_url(struct gui_window *gw, nsurl *url) -{ - struct nsgtk_scaffolding *g; - size_t idn_url_l; - char *idn_url_s = NULL; - - g = nsgtk_get_scaffold(gw); - if (g->top_level == gw) { - if (nsoption_bool(display_decoded_idn) == true) { - if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) - idn_url_s = NULL; - } - - gtk_entry_set_text(GTK_ENTRY(g->url_bar), idn_url_s ? idn_url_s : nsurl_access(url)); - - if(idn_url_s) - free(idn_url_s); - - gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1); - } - return NSERROR_OK; -} - -void gui_window_start_throbber(struct gui_window* _g) -{ - struct nsgtk_scaffolding *g = nsgtk_get_scaffold(_g); - g->buttons[STOP_BUTTON]->sensitivity = true; - g->buttons[RELOAD_BUTTON]->sensitivity = false; - nsgtk_scaffolding_set_sensitivity(g); - - scaffolding_update_context(g); - - nsgtk_schedule(100, nsgtk_throb, g); -} - -void gui_window_stop_throbber(struct gui_window* _g) -{ - struct nsgtk_scaffolding *g = nsgtk_get_scaffold(_g); - if (g == NULL) - return; - scaffolding_update_context(g); - nsgtk_schedule(-1, nsgtk_throb, g); - if (g->buttons[STOP_BUTTON] != NULL) - g->buttons[STOP_BUTTON]->sensitivity = false; - if (g->buttons[RELOAD_BUTTON] != NULL) - g->buttons[RELOAD_BUTTON]->sensitivity = true; - - nsgtk_scaffolding_set_sensitivity(g); - - if ((g->throbber == NULL) || (nsgtk_throbber == NULL) || - (nsgtk_throbber->framedata == NULL) || - (nsgtk_throbber->framedata[0] == NULL)) - return; - gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[0]); } -/** - * set favicon - */ -void -nsgtk_scaffolding_set_icon(struct gui_window *gw) +/* exported interface documented in scaffolding.h */ +nserror nsgtk_scaffolding_throbber(struct gui_window* gw, bool active) { - struct nsgtk_scaffolding *sc = nsgtk_get_scaffold(gw); - GdkPixbuf *icon_pixbuf = nsgtk_get_icon(gw); - - /* check icon needs to be shown */ - if ((icon_pixbuf == NULL) || - (sc->top_level != gw)) { - return; + struct nsgtk_scaffolding *gs = nsgtk_get_scaffold(gw); + if (active) { + gs->menus[STOP_BUTTON].sensitivity = true; + gs->menus[RELOAD_BUTTON].sensitivity = false; + } else { + gs->menus[STOP_BUTTON].sensitivity = false; + gs->menus[RELOAD_BUTTON].sensitivity = true; } + scaffolding_update_context(gs); - nsgtk_entry_set_icon_from_pixbuf(sc->url_bar, - GTK_ENTRY_ICON_PRIMARY, - icon_pixbuf); - - gtk_widget_show_all(GTK_WIDGET(sc->buttons[URL_BAR_ITEM]->button)); + return NSERROR_OK; } -static void -nsgtk_scaffolding_set_websearch(struct nsgtk_scaffolding *g, const char *content) -{ - /** \todo this code appears technically correct, though - * currently has no effect at all. - */ - PangoLayout *lo = gtk_entry_get_layout(GTK_ENTRY(g->webSearchEntry)); - if (lo != NULL) { - pango_layout_set_font_description(lo, NULL); - PangoFontDescription *desc = pango_font_description_new(); - if (desc != NULL) { - pango_font_description_set_style(desc, - PANGO_STYLE_ITALIC); - pango_font_description_set_family(desc, "Arial"); - pango_font_description_set_weight(desc, - PANGO_WEIGHT_ULTRALIGHT); - pango_font_description_set_size(desc, - 10 * PANGO_SCALE); - pango_layout_set_font_description(lo, desc); - } - - PangoAttrList *list = pango_attr_list_new(); - if (list != NULL) { - PangoAttribute *italic = pango_attr_style_new( - PANGO_STYLE_ITALIC); - if (italic != NULL) { - italic->start_index = 0; - italic->end_index = strlen(content); - } - PangoAttribute *grey = pango_attr_foreground_new( - 0x7777, 0x7777, 0x7777); - if (grey != NULL) { - grey->start_index = 0; - grey->end_index = strlen(content); - } - pango_attr_list_insert(list, italic); - pango_attr_list_insert(list, grey); - pango_layout_set_attributes(lo, list); - pango_attr_list_unref(list); - } - pango_layout_set_text(lo, content, -1); - } -/* an alternative method */ -/* char *parse = malloc(strlen(content) + 1); - PangoAttrList *list = pango_layout_get_attributes(lo); - char *markup = g_strconcat("<span foreground='#777777'><i>", content, - "</i></span>", NULL); - pango_parse_markup(markup, -1, 0, &list, &parse, NULL, NULL); - gtk_widget_show_all(g->webSearchEntry); -*/ - gtk_entry_set_visibility(GTK_ENTRY(g->webSearchEntry), TRUE); - gtk_entry_set_text(GTK_ENTRY(g->webSearchEntry), content); -} -/** - * GTK UI callback when search provider details are updated. - * - * \param provider_name The providers name. - * \param provider_bitmap The bitmap representing the provider. - * \return NSERROR_OK on success else error code. - */ -static nserror -gui_search_web_provider_update(const char *provider_name, - struct bitmap *provider_bitmap) +/* exported interface documented in gtk/scaffolding.h */ +nserror nsgtk_scaffolding_destroy_all(void) { - struct nsgtk_scaffolding *current; - GdkPixbuf *srch_pixbuf = NULL; - char *searchcontent; - - NSLOG(netsurf, INFO, "name:%s bitmap %p", provider_name, - provider_bitmap); - - if (provider_bitmap != NULL) { - srch_pixbuf = nsgdk_pixbuf_get_from_surface(provider_bitmap->surface, 16, 16); - - if (srch_pixbuf == NULL) { - return NSERROR_NOMEM; - } - } - - /* setup the search content name */ - searchcontent = malloc(strlen(provider_name) + SLEN("Search ") + 1); - if (searchcontent != NULL) { - sprintf(searchcontent, "Search %s", provider_name); - } - - /* set the search provider parameters up in each scaffold */ - for (current = scaf_list; current != NULL; current = current->next) { - if (current->webSearchEntry == NULL) { - continue; - } + struct nsgtk_scaffolding *gs; - /* add ico to each window's toolbar */ - if (srch_pixbuf != NULL) { - nsgtk_entry_set_icon_from_pixbuf(current->webSearchEntry, - GTK_ENTRY_ICON_PRIMARY, - srch_pixbuf); - } else { - nsgtk_entry_set_icon_from_stock(current->webSearchEntry, - GTK_ENTRY_ICON_PRIMARY, - NSGTK_STOCK_FIND); - } + gs = scaf_list; + assert(gs != NULL); - /* set search entry text */ - if (searchcontent != NULL) { - nsgtk_scaffolding_set_websearch(current, searchcontent); - } else { - nsgtk_scaffolding_set_websearch(current, provider_name); - } + if (nsgtk_check_for_downloads(gs->window) == true) { + return NSERROR_INVALID; } - free(searchcontent); - - if (srch_pixbuf != NULL) { - g_object_unref(srch_pixbuf); + /* iterate all scaffolding windows and destroy them */ + while (gs != NULL) { + struct nsgtk_scaffolding *next = gs->next; + gtk_widget_destroy(GTK_WIDGET(gs->window)); + gs = next; } - return NSERROR_OK; } -static struct gui_search_web_table search_web_table = { - .provider_update = gui_search_web_provider_update, -}; - -struct gui_search_web_table *nsgtk_search_web_table = &search_web_table; /* exported interface documented in gtk/scaffolding.h */ GtkWindow* nsgtk_scaffolding_window(struct nsgtk_scaffolding *g) @@ -2540,41 +1318,14 @@ GtkNotebook* nsgtk_scaffolding_notebook(struct nsgtk_scaffolding *g) return g->notebook; } -/* exported interface documented in gtk/scaffolding.h */ -GtkWidget *nsgtk_scaffolding_urlbar(struct nsgtk_scaffolding *g) -{ - return g->url_bar; -} - -/* exported interface documented in gtk/scaffolding.h */ -GtkWidget *nsgtk_scaffolding_websearch(struct nsgtk_scaffolding *g) -{ - return g->webSearchEntry; -} - -/* exported interface documented in gtk/scaffolding.h */ -GtkToolbar *nsgtk_scaffolding_toolbar(struct nsgtk_scaffolding *g) -{ - return g->tool_bar; -} - -/* exported interface documented in gtk/scaffolding.h */ -struct nsgtk_button_connect * -nsgtk_scaffolding_button(struct nsgtk_scaffolding *g, int i) -{ - return g->buttons[i]; -} - -/* exported interface documented in gtk/scaffolding.h */ -struct gtk_search *nsgtk_scaffolding_search(struct nsgtk_scaffolding *g) -{ - return g->search; -} /* exported interface documented in gtk/scaffolding.h */ -GtkMenuBar *nsgtk_scaffolding_menu_bar(struct nsgtk_scaffolding *g) +GtkMenuBar *nsgtk_scaffolding_menu_bar(struct nsgtk_scaffolding *gs) { - return g->menu_bar->bar_menu; + if (gs == NULL) { + return NULL; + } + return gs->menu_bar->bar_menu; } /* exported interface documented in gtk/scaffolding.h */ @@ -2586,54 +1337,6 @@ struct nsgtk_scaffolding *nsgtk_scaffolding_iterate(struct nsgtk_scaffolding *g) return g->next; } -/* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_reset_offset(struct nsgtk_scaffolding *g) -{ - g->offset = 0; -} - -/* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_update_url_bar_ref(struct nsgtk_scaffolding *g) -{ - g->url_bar = GTK_WIDGET(gtk_bin_get_child(GTK_BIN( - nsgtk_scaffolding_button(g, URL_BAR_ITEM)->button))); - - gtk_entry_set_completion(GTK_ENTRY(g->url_bar), - g->url_bar_completion); -} - -/* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_update_throbber_ref(struct nsgtk_scaffolding *g) -{ - g->throbber = GTK_IMAGE(gtk_bin_get_child( - GTK_BIN(g->buttons[THROBBER_ITEM]->button))); -} - -/* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_update_websearch_ref(struct nsgtk_scaffolding *g) -{ - g->webSearchEntry = gtk_bin_get_child(GTK_BIN( - g->buttons[WEBSEARCH_ITEM]->button)); -} - -/* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_toggle_search_bar_visibility(struct nsgtk_scaffolding *g) -{ - gboolean vis; - struct browser_window *bw = nsgtk_get_browser_window(g->top_level); - - g_object_get(G_OBJECT(g->search->bar), "visible", &vis, NULL); - if (vis) { - if (bw != NULL) { - browser_window_search_clear(bw); - } - - gtk_widget_hide(GTK_WIDGET(g->search->bar)); - } else { - gtk_widget_show(GTK_WIDGET(g->search->bar)); - gtk_widget_grab_focus(GTK_WIDGET(g->search->entry)); - } -} /* exported interface documented in gtk/scaffolding.h */ struct gui_window *nsgtk_scaffolding_top_level(struct nsgtk_scaffolding *g) @@ -2641,6 +1344,7 @@ struct gui_window *nsgtk_scaffolding_top_level(struct nsgtk_scaffolding *g) return g->top_level; } + /* exported interface documented in gtk/scaffolding.h */ void nsgtk_scaffolding_set_top_level(struct gui_window *gw) { @@ -2656,44 +1360,33 @@ void nsgtk_scaffolding_set_top_level(struct gui_window *gw) sc = nsgtk_get_scaffold(gw); assert(sc != NULL); + scaf_current = sc; + sc->top_level = gw; - /* Synchronise the history (will also update the URL bar) */ + /* Synchronise the history */ scaffolding_update_context(sc); - /* clear effects of potential searches */ - browser_window_search_clear(bw); - - nsgtk_scaffolding_set_icon(gw); - /* Ensure the window's title bar is updated */ - nsgtk_window_set_title(gw, browser_window_get_title(bw)); - + nsgtk_scaffolding_set_title(gw, browser_window_get_title(bw)); } + /* exported interface documented in scaffolding.h */ void nsgtk_scaffolding_set_sensitivity(struct nsgtk_scaffolding *g) { int i; -#define SENSITIVITY(q)\ - i = q##_BUTTON;\ - if (g->buttons[i]->main != NULL)\ - gtk_widget_set_sensitive(GTK_WIDGET(\ - g->buttons[i]->main),\ - g->buttons[i]->sensitivity);\ - if (g->buttons[i]->rclick != NULL)\ - gtk_widget_set_sensitive(GTK_WIDGET(\ - g->buttons[i]->rclick),\ - g->buttons[i]->sensitivity);\ - if ((g->buttons[i]->location != -1) && \ - (g->buttons[i]->button != NULL))\ - gtk_widget_set_sensitive(GTK_WIDGET(\ - g->buttons[i]->button),\ - g->buttons[i]->sensitivity);\ - if (g->buttons[i]->popup != NULL)\ - gtk_widget_set_sensitive(GTK_WIDGET(\ - g->buttons[i]->popup),\ - g->buttons[i]->sensitivity); +#define SENSITIVITY(q) \ + i = q##_BUTTON; \ + if (g->menus[i].main != NULL) \ + gtk_widget_set_sensitive(GTK_WIDGET(g->menus[i].main), \ + g->menus[i].sensitivity); \ + if (g->menus[i].burger != NULL) \ + gtk_widget_set_sensitive(GTK_WIDGET(g->menus[i].burger), \ + g->menus[i].sensitivity); \ + if (g->menus[i].popup != NULL) \ + gtk_widget_set_sensitive(GTK_WIDGET(g->menus[i].popup), \ + g->menus[i].sensitivity); SENSITIVITY(STOP) SENSITIVITY(RELOAD) @@ -2706,85 +1399,205 @@ void nsgtk_scaffolding_set_sensitivity(struct nsgtk_scaffolding *g) SENSITIVITY(PREVTAB) SENSITIVITY(CLOSETAB) #undef SENSITIVITY + } /* exported interface documented in gtk/scaffolding.h */ -void nsgtk_scaffolding_context_menu(struct nsgtk_scaffolding *g, - gdouble x, - gdouble y) +nserror nsgtk_scaffolding_toolbar_context_menu(struct nsgtk_scaffolding *gs) +{ + /* set visibility for right-click popup menu */ + popup_menu_hide(gs->popup_menu, false, true); + + nsgtk_menu_popup_at_pointer(gs->popup_menu->popup_menu, NULL); + + return NSERROR_OK; +} + + +/* exported interface documented in gtk/scaffolding.h */ +nserror nsgtk_scaffolding_burger_menu(struct nsgtk_scaffolding *gs) +{ + nsgtk_menu_popup_at_pointer(gs->burger_menu->burger_menu, NULL); + + return NSERROR_OK; +} + + +/* exported interface documented in gtk/scaffolding.h */ +void +nsgtk_scaffolding_context_menu(struct nsgtk_scaffolding *g, + gdouble x, + gdouble y) { GtkMenu *gtkmenu; + struct browser_window *bw; + + bw = nsgtk_get_browser_window(g->top_level); /* update the global context menu features */ - browser_window_get_features(nsgtk_get_browser_window(g->top_level), - x, y, ¤t_menu_features); + browser_window_get_features(bw, x, y, ¤t_menu_features); if (current_menu_features.link != NULL) { /* menu is opening over a link */ gtkmenu = g->link_menu->link_menu; } else { - gtkmenu = g->menu_popup->popup_menu; + gtkmenu = g->popup_menu->popup_menu; nsgtk_scaffolding_update_edit_actions_sensitivity(g); - if (!(g->buttons[COPY_BUTTON]->sensitivity)) { - gtk_widget_hide(GTK_WIDGET(g->menu_popup->copy_menuitem)); + if (!(g->menus[COPY_BUTTON].sensitivity)) { + gtk_widget_hide(GTK_WIDGET(g->popup_menu->copy_menuitem)); } else { - gtk_widget_show(GTK_WIDGET(g->menu_popup->copy_menuitem)); + gtk_widget_show(GTK_WIDGET(g->popup_menu->copy_menuitem)); } - if (!(g->buttons[CUT_BUTTON]->sensitivity)) { - gtk_widget_hide(GTK_WIDGET(g->menu_popup->cut_menuitem)); + if (!(g->menus[CUT_BUTTON].sensitivity)) { + gtk_widget_hide(GTK_WIDGET(g->popup_menu->cut_menuitem)); } else { - gtk_widget_show(GTK_WIDGET(g->menu_popup->cut_menuitem)); + gtk_widget_show(GTK_WIDGET(g->popup_menu->cut_menuitem)); } - if (!(g->buttons[PASTE_BUTTON]->sensitivity)) { - gtk_widget_hide(GTK_WIDGET(g->menu_popup->paste_menuitem)); + if (!(g->menus[PASTE_BUTTON].sensitivity)) { + gtk_widget_hide(GTK_WIDGET(g->popup_menu->paste_menuitem)); } else { - gtk_widget_show(GTK_WIDGET(g->menu_popup->paste_menuitem)); + gtk_widget_show(GTK_WIDGET(g->popup_menu->paste_menuitem)); } - /* hide customise */ - popup_menu_hide(g->menu_popup, false, false, false, true); } nsgtk_menu_popup_at_pointer(gtkmenu, NULL); } -/** - * reallocate width for history button, reallocate buttons right of history; - * memorise base of history button / toolbar - */ -void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget, - GtkAllocation *alloc, gpointer data) +/* exported interface documented in gtk/scaffolding.h */ +struct nsgtk_scaffolding *nsgtk_current_scaffolding(void) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - int i = nsgtk_toolbar_get_id_from_widget(widget, g); - if (i == -1) - return; - if ((g->toolbarmem == alloc->x) || - (g->buttons[i]->location < - g->buttons[HISTORY_BUTTON]->location)) - /* no reallocation after first adjustment, no reallocation for buttons - * left of history button */ - return; - if (widget == GTK_WIDGET(g->buttons[HISTORY_BUTTON]->button)) { - if (alloc->width == 20) - return; - - g->toolbarbase = alloc->y + alloc->height; - g->historybase = alloc->x + 20; - if (g->offset == 0) - g->offset = alloc->width - 20; - alloc->width = 20; - } else if (g->buttons[i]->location <= - g->buttons[URL_BAR_ITEM]->location) { - alloc->x -= g->offset; - if (i == URL_BAR_ITEM) - alloc->width += g->offset; + if (scaf_current == NULL) { + scaf_current = scaf_list; } - g->toolbarmem = alloc->x; - gtk_widget_size_allocate(widget, alloc); + return scaf_current; +} + +/* exported interface documented in gtk/scaffolding.h */ +struct nsgtk_scaffolding *nsgtk_scaffolding_from_notebook(GtkNotebook *notebook) +{ + struct nsgtk_scaffolding *gs; + gs = scaf_list; + while (gs != NULL) { + if (gs->notebook == notebook) { + break; + } + gs = gs->next; + } + return gs; +} + +/* exported interface documented in gtk/scaffolding.h */ +struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) +{ + nserror res; + struct nsgtk_scaffolding *gs; + + gs = calloc(1, sizeof(*gs)); + if (gs == NULL) { + return NULL; + } + + NSLOG(netsurf, INFO, + "Constructing a scaffold of %p for gui_window %p", gs, toplevel); + + gs->top_level = toplevel; + + /* Construct UI widgets */ + if (nsgtk_builder_new_from_resname("netsurf", &gs->builder) != NSERROR_OK) { + free(gs); + return NULL; + } + + gtk_builder_connect_signals(gs->builder, NULL); + + /* containing window setup */ + gs->window = GTK_WINDOW(gtk_builder_get_object(gs->builder, + "wndBrowser")); + + /** + * set this window's size and position to what's in the options, or + * some sensible default if they are not set yet. + */ + if (nsoption_int(window_width) > 0) { + gtk_window_move(gs->window, + nsoption_int(window_x), + nsoption_int(window_y)); + gtk_window_resize(gs->window, + nsoption_int(window_width), + nsoption_int(window_height)); + } else { + /* Set to 1000x700, so we're very likely to fit even on + * 1024x768 displays, not being able to take into account + * window furniture or panels. + */ + gtk_window_set_default_size(gs->window, 1000, 700); + } + + g_signal_connect(gs->window, + "delete-event", + G_CALLBACK(scaffolding_window_delete_event), + gs); + + g_signal_connect(gs->window, + "destroy", + G_CALLBACK(scaffolding_window_destroy), + gs); + + + /* notebook */ + res = nsgtk_notebook_create(gs->builder, &gs->notebook); + if (res != NSERROR_OK) { + free(gs); + return NULL; + } + + g_signal_connect_after(gs->notebook, + "page-added", + G_CALLBACK(nsgtk_window_tabs_add), + gs); + gs->tabs_remove_handler_id = g_signal_connect_after(gs->notebook, + "page-removed", + G_CALLBACK(nsgtk_window_tabs_remove), + gs); + + + res = nsgtk_menus_create(gs); + if (res != NSERROR_OK) { + free(gs); + return NULL; + } + + /* attach to the list */ + if (scaf_list) { + scaf_list->prev = gs; + } + gs->next = scaf_list; + gs->prev = NULL; + scaf_list = gs; + + /* finally, show the window. */ + gtk_widget_show(GTK_WIDGET(gs->window)); + + NSLOG(netsurf, INFO, "creation complete"); + + return gs; +} + +/* exported interface documented in gtk/scaffolding.h */ +nserror nsgtk_scaffolding_position_page_info(struct nsgtk_scaffolding *gs, + struct nsgtk_pi_window *win) +{ + return nsgtk_window_position_page_info(gs->top_level, win); +} + +/* exported interface documented in gtk/scaffolding.h */ +nserror nsgtk_scaffolding_position_local_history(struct nsgtk_scaffolding *gs) +{ + return nsgtk_window_position_local_history(gs->top_level); } |