diff options
Diffstat (limited to 'frontends/gtk')
101 files changed, 9410 insertions, 7964 deletions
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile index ec60ce70c..64a0872ba 100644 --- a/frontends/gtk/Makefile +++ b/frontends/gtk/Makefile @@ -11,6 +11,8 @@ NETSURF_FEATURE_RSVG_CFLAGS := -DWITH_RSVG NETSURF_FEATURE_VIDEO_CFLAGS := -DWITH_VIDEO +# determine if the rsvg library API version +RSVG_API := $(shell $(PKG_CONFIG) --atleast-version=2.46 librsvg-2.0 && echo 246) $(eval $(call pkg_config_find_and_add_enabled,RSVG,librsvg-2.0,SVG)) $(eval $(call pkg_config_find_and_add_enabled,VIDEO,gstreamer-0.10,Video)) @@ -32,13 +34,19 @@ ifeq ($(NETSURF_GTK_MAJOR),2) GTKDEPFLAGS += -DGTK_DISABLE_DEPRECATED endif +# C library API control +ifeq ($(HOST),FreeBSD) +CAPIFLAGS := +else +CAPIFLAGS := -D_XOPEN_SOURCE=700 \ + -D_POSIX_C_SOURCE=200809L +endif GTKCFLAGS := -std=c99 -Dgtk -Dnsgtk -g \ $(GTKDEPFLAGS) \ + $(CAPIFLAGS) \ -D_BSD_SOURCE \ -D_DEFAULT_SOURCE \ - -D_XOPEN_SOURCE=600 \ - -D_POSIX_C_SOURCE=200809L \ -D_NETBSD_SOURCE \ -DGTK_RESPATH=\"$(NETSURF_GTK_RES_PATH)\" @@ -59,13 +67,7 @@ LDFLAGS += -lm NSGTK_RESOURCES_DIR := $(FRONTEND_RESOURCES_DIR) # The gtk binary target. -ifeq ($(NETSURF_GTK_MAJOR),2) - # gtk2 builds have no major suffix - EXETARGET := nsgtk -else - # gtk3 and later builds use the major version suffix - EXETARGET := nsgtk$(NETSURF_GTK_MAJOR) -endif +EXETARGET := nsgtk$(NETSURF_GTK_MAJOR) # The filter and target for split messages MESSAGES_FILTER=gtk @@ -109,6 +111,7 @@ GLIB_COMPILE_RESOURCES := glib-compile-resources CFLAGS += -DWITH_GRESOURCE NETSURF_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/netsurf.gresource.xml +UI_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/ui.gresource.xml MESSAGES_GRESOURCE_XML := $(NSGTK_RESOURCES_DIR)/messages.gresource.xml # generate the netsurf gresource source files @@ -118,6 +121,13 @@ $(OBJROOT)/netsurf_gresource.c: $(NETSURF_GRESOURCE_XML) $(shell $(GLIB_COMPILE_ S_RESOURCE += $(OBJROOT)/netsurf_gresource.c +# generate the ui gresource source files +$(OBJROOT)/ui_gresource.c: $(UI_GRESOURCE_XML) $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir $(NSGTK_RESOURCES_DIR)/gtk$(NETSURF_GTK_MAJOR) --generate-dependencies $(UI_GRESOURCE_XML)) + $(VQ)echo "GRESORCE: $<" + $(Q)$(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir $(NSGTK_RESOURCES_DIR)/gtk$(NETSURF_GTK_MAJOR) --target=$@ $< + +S_RESOURCE += $(OBJROOT)/ui_gresource.c + # generate the messages gresource source file $(OBJROOT)/messages_gresource.c: $(MESSAGES_GRESOURCE_XML) $(addsuffix /Messages,$(addprefix $(MESSAGES_TARGET)/,$(MESSAGES_LANGUAGES))) $(VQ)echo "GRESORCE: $<" @@ -164,12 +174,12 @@ endif # ---------------------------------------------------------------------------- # S_FRONTEND are sources purely for the GTK frontend -S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c \ - scaffolding.c gdk.c completion.c login.c throbber.c accelerator.c \ - selection.c window.c fetch.c download.c menu.c print.c \ - search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \ - viewsource.c preferences.c about.c resources.c corewindow.c \ - local_history.c global_history.c cookies.c hotlist.c ssl_cert.c +S_FRONTEND := gui.c misc.c schedule.c layout_pango.c bitmap.c plotters.c \ + scaffolding.c gdk.c completion.c throbber.c accelerator.c \ + selection.c window.c fetch.c download.c menu.c print.c \ + search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \ + viewsource.c preferences.c about.c resources.c corewindow.c \ + local_history.c global_history.c cookies.c hotlist.c page_info.c # This is the final source build list # Note this is deliberately *not* expanded here as common and image @@ -183,16 +193,15 @@ SOURCES = $(S_COMMON) $(S_IMAGE) $(S_BROWSER) $(S_RESOURCE) $(S_FRONTEND) GTK_RESOURCES_LIST := \ languages SearchEngines ca-bundle.txt \ default.css adblock.css quirks.css internal.css \ - credits.html licence.html welcome.html maps.html Messages \ - default.ico favicon.png netsurf.png netsurf.xpm netsurf-16x16.xpm \ - arrow_down_8x32.png + credits.html licence.html welcome.html Messages \ + default.ico favicon.png netsurf.png netsurf.xpm netsurf-16x16.xpm GTK_RESOURCES_LIST := \ $(addprefix $(NSGTK_RESOURCES_DIR)/, $(GTK_RESOURCES_LIST)) \ - $(wildcard $(NSGTK_RESOURCES_DIR)/*.gtk$(NETSURF_GTK_MAJOR).ui) + $(wildcard $(NSGTK_RESOURCES_DIR)/gtk$(NETSURF_GTK_MAJOR)/*.ui) # translations with more than just Messages files -GTK_TRANSLATIONS_HTML := de en fr it ja nl +GTK_TRANSLATIONS_HTML := de en fr it ja nl zh_CN # destination for installed resources is the first entry in the gtk resource path NSGTK_RESOURCES_DESTDIR := $(DESTDIR)$(word 1,$(subst :, ,$(NETSURF_GTK_RES_PATH))) diff --git a/frontends/gtk/Makefile.tools b/frontends/gtk/Makefile.tools new file mode 100644 index 000000000..5331dcc71 --- /dev/null +++ b/frontends/gtk/Makefile.tools @@ -0,0 +1,16 @@ +# -*- mode: makefile-gmake -*- +## +## tool setup for the gtk target +## + +# use native package config +PKG_CONFIG := pkg-config + +# gtk target processing +ifeq ($(SUBTARGET),3) + override NETSURF_GTK_MAJOR := 3 +endif + +ifeq ($(SUBTARGET),2) + override NETSURF_GTK_MAJOR := 2 +endif diff --git a/frontends/gtk/bitmap.c b/frontends/gtk/bitmap.c index 36b614cf9..a995a9e28 100644 --- a/frontends/gtk/bitmap.c +++ b/frontends/gtk/bitmap.c @@ -45,22 +45,25 @@ * Create a bitmap. * * \param width width of image in pixels - * \param height width of image in pixels - * \param state a flag word indicating the initial state + * \param height height of image in pixels + * \param flags flags for bitmap creation * \return an opaque struct bitmap, or NULL on memory exhaustion */ -static void *bitmap_create(int width, int height, unsigned int state) +static void *bitmap_create(int width, int height, enum gui_bitmap_flags flags) { struct bitmap *gbitmap; + if (width == 0 || height == 0) { + return NULL; + } + gbitmap = calloc(1, sizeof(struct bitmap)); if (gbitmap != NULL) { - if ((state & BITMAP_OPAQUE) != 0) { - gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); - } else { - gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + if (flags & BITMAP_OPAQUE) { + gbitmap->opaque = true; } + gbitmap->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); if (cairo_surface_status(gbitmap->surface) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(gbitmap->surface); free(gbitmap); @@ -81,76 +84,8 @@ static void *bitmap_create(int width, int height, unsigned int state) static void bitmap_set_opaque(void *vbitmap, bool opaque) { struct bitmap *gbitmap = (struct bitmap *)vbitmap; - cairo_format_t fmt; - cairo_surface_t *nsurface = NULL; - - assert(gbitmap); - - fmt = cairo_image_surface_get_format(gbitmap->surface); - if (fmt == CAIRO_FORMAT_RGB24) { - if (opaque == false) { - /* opaque to transparent */ - nsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - cairo_image_surface_get_width(gbitmap->surface), - cairo_image_surface_get_height(gbitmap->surface)); - - } - - } else { - if (opaque == true) { - /* transparent to opaque */ - nsurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, - cairo_image_surface_get_width(gbitmap->surface), - cairo_image_surface_get_height(gbitmap->surface)); - - } - } - - if (nsurface != NULL) { - if (cairo_surface_status(nsurface) != CAIRO_STATUS_SUCCESS) { - cairo_surface_destroy(nsurface); - } else { - memcpy(cairo_image_surface_get_data(nsurface), - cairo_image_surface_get_data(gbitmap->surface), - cairo_image_surface_get_stride(gbitmap->surface) * cairo_image_surface_get_height(gbitmap->surface)); - cairo_surface_destroy(gbitmap->surface); - gbitmap->surface = nsurface; - - cairo_surface_mark_dirty(gbitmap->surface); - - } - - } -} - - -/** - * Tests whether a bitmap has an opaque alpha channel - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return whether the bitmap is opaque - */ -static bool bitmap_test_opaque(void *vbitmap) -{ - struct bitmap *gbitmap = (struct bitmap *)vbitmap; - unsigned char *pixels; - int pcount; - int ploop; - - assert(gbitmap); - - pixels = cairo_image_surface_get_data(gbitmap->surface); - - pcount = cairo_image_surface_get_stride(gbitmap->surface) * - cairo_image_surface_get_height(gbitmap->surface); - - for (ploop = 3; ploop < pcount; ploop += 4) { - if (pixels[ploop] != 0xff) { - return false; - } - } - return true; + gbitmap->opaque = opaque; } @@ -162,16 +97,8 @@ static bool bitmap_test_opaque(void *vbitmap) static bool bitmap_get_opaque(void *vbitmap) { struct bitmap *gbitmap = (struct bitmap *)vbitmap; - cairo_format_t fmt; - assert(gbitmap); - - fmt = cairo_image_surface_get_format(gbitmap->surface); - if (fmt == CAIRO_FORMAT_RGB24) { - return true; - } - - return false; + return gbitmap->opaque; } @@ -187,83 +114,13 @@ static bool bitmap_get_opaque(void *vbitmap) static unsigned char *bitmap_get_buffer(void *vbitmap) { struct bitmap *gbitmap = (struct bitmap *)vbitmap; - int pixel_loop; - int pixel_count; uint8_t *pixels; - uint32_t t, r, g, b; - cairo_format_t fmt; assert(gbitmap); cairo_surface_flush(gbitmap->surface); pixels = cairo_image_surface_get_data(gbitmap->surface); - if (!gbitmap->converted) - return pixels; - - fmt = cairo_image_surface_get_format(gbitmap->surface); - pixel_count = cairo_image_surface_get_width(gbitmap->surface) * - cairo_image_surface_get_height(gbitmap->surface); - - if (fmt == CAIRO_FORMAT_RGB24) { - /* Opaque image */ - for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) { - /* Cairo surface is ARGB, written in native endian */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - b = pixels[4 * pixel_loop + 0]; - g = pixels[4 * pixel_loop + 1]; - r = pixels[4 * pixel_loop + 2]; - t = pixels[4 * pixel_loop + 3]; -#else - t = pixels[4 * pixel_loop + 0]; - r = pixels[4 * pixel_loop + 1]; - g = pixels[4 * pixel_loop + 2]; - b = pixels[4 * pixel_loop + 3]; -#endif - - /* Core bitmaps always have a component order of rgba, - * regardless of system endianness */ - pixels[4 * pixel_loop + 0] = r; - pixels[4 * pixel_loop + 1] = g; - pixels[4 * pixel_loop + 2] = b; - pixels[4 * pixel_loop + 3] = t; - } - } else { - /* Alpha image: de-multiply alpha */ - for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - b = pixels[4 * pixel_loop + 0]; - g = pixels[4 * pixel_loop + 1]; - r = pixels[4 * pixel_loop + 2]; - t = pixels[4 * pixel_loop + 3]; -#else - t = pixels[4 * pixel_loop + 0]; - r = pixels[4 * pixel_loop + 1]; - g = pixels[4 * pixel_loop + 2]; - b = pixels[4 * pixel_loop + 3]; -#endif - - if (t != 0) { - r = (r << 8) / t; - g = (g << 8) / t; - b = (b << 8) / t; - - r = (r > 255) ? 255 : r; - g = (g > 255) ? 255 : g; - b = (b > 255) ? 255 : b; - } else { - r = g = b = 0; - } - - pixels[4 * pixel_loop + 0] = r; - pixels[4 * pixel_loop + 1] = g; - pixels[4 * pixel_loop + 2] = b; - pixels[4 * pixel_loop + 3] = t; - } - } - - gbitmap->converted = false; - return (unsigned char *) pixels; } @@ -284,22 +141,6 @@ static size_t bitmap_get_rowstride(void *vbitmap) /** - * Find the bytes per pixel of a bitmap - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return bytes per pixel - */ -static size_t bitmap_get_bpp(void *vbitmap) -{ - struct bitmap *gbitmap = (struct bitmap *)vbitmap; - assert(gbitmap); - - return 4; -} - - - -/** * Free a bitmap. * * \param vbitmap a bitmap, as returned by bitmap_create() @@ -320,23 +161,6 @@ static void bitmap_destroy(void *vbitmap) /** - * Save a bitmap in the platform's native format. - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \param path pathname for file - * \param flags modify the behaviour of the save - * \return true on success, false on error and error reported - */ -static bool bitmap_save(void *vbitmap, const char *path, unsigned flags) -{ - struct bitmap *gbitmap = (struct bitmap *)vbitmap; - assert(gbitmap); - - return false; -} - - -/** * The bitmap image has changed, so flush any persistant cache. * * \param vbitmap a bitmap, as returned by bitmap_create() @@ -344,81 +168,10 @@ static bool bitmap_save(void *vbitmap, const char *path, unsigned flags) static void bitmap_modified(void *vbitmap) { struct bitmap *gbitmap = (struct bitmap *)vbitmap; - int pixel_loop; - int pixel_count; - uint8_t *pixels; - uint32_t t, r, g, b; - cairo_format_t fmt; assert(gbitmap); - fmt = cairo_image_surface_get_format(gbitmap->surface); - - pixel_count = cairo_image_surface_get_width(gbitmap->surface) * - cairo_image_surface_get_height(gbitmap->surface); - pixels = cairo_image_surface_get_data(gbitmap->surface); - - if (gbitmap->converted) { - cairo_surface_mark_dirty(gbitmap->surface); - return; - } - - if (fmt == CAIRO_FORMAT_RGB24) { - /* Opaque image */ - for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) { - /* Core bitmaps always have a component order of rgba, - * regardless of system endianness */ - r = pixels[4 * pixel_loop + 0]; - g = pixels[4 * pixel_loop + 1]; - b = pixels[4 * pixel_loop + 2]; - t = pixels[4 * pixel_loop + 3]; - - /* Cairo surface is ARGB, written in native endian */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - pixels[4 * pixel_loop + 0] = b; - pixels[4 * pixel_loop + 1] = g; - pixels[4 * pixel_loop + 2] = r; - pixels[4 * pixel_loop + 3] = t; -#else - pixels[4 * pixel_loop + 0] = t; - pixels[4 * pixel_loop + 1] = r; - pixels[4 * pixel_loop + 2] = g; - pixels[4 * pixel_loop + 3] = b; -#endif - } - } else { - /* Alpha image: pre-multiply alpha */ - for (pixel_loop=0; pixel_loop < pixel_count; pixel_loop++) { - r = pixels[4 * pixel_loop + 0]; - g = pixels[4 * pixel_loop + 1]; - b = pixels[4 * pixel_loop + 2]; - t = pixels[4 * pixel_loop + 3]; - - if (t != 0) { - r = ((r * (t + 1)) >> 8) & 0xff; - g = ((g * (t + 1)) >> 8) & 0xff; - b = ((b * (t + 1)) >> 8) & 0xff; - } else { - r = g = b = 0; - } - -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - pixels[4 * pixel_loop + 0] = b; - pixels[4 * pixel_loop + 1] = g; - pixels[4 * pixel_loop + 2] = r; - pixels[4 * pixel_loop + 3] = t; -#else - pixels[4 * pixel_loop + 0] = t; - pixels[4 * pixel_loop + 1] = r; - pixels[4 * pixel_loop + 2] = g; - pixels[4 * pixel_loop + 3] = b; -#endif - } - } - cairo_surface_mark_dirty(gbitmap->surface); - - gbitmap->converted = true; } /* exported interface documented in gtk/bitmap.h */ @@ -478,6 +231,10 @@ bitmap_render(struct bitmap *bitmap, struct hlcache_handle *content) * aspect ratio of the required thumbnail. */ cheight = ((cwidth * dheight) + (dwidth / 2)) / dwidth; + /* At this point, we MUST have decided to render something non-zero sized */ + assert(cwidth > 0); + assert(cheight > 0); + /* Create surface to render into */ surface = cairo_surface_create_similar(dsurface, CAIRO_CONTENT_COLOR_ALPHA, cwidth, cheight); @@ -526,13 +283,10 @@ static struct gui_bitmap_table bitmap_table = { .destroy = bitmap_destroy, .set_opaque = bitmap_set_opaque, .get_opaque = bitmap_get_opaque, - .test_opaque = bitmap_test_opaque, .get_buffer = bitmap_get_buffer, .get_rowstride = bitmap_get_rowstride, .get_width = nsgtk_bitmap_get_width, .get_height = nsgtk_bitmap_get_height, - .get_bpp = bitmap_get_bpp, - .save = bitmap_save, .modified = bitmap_modified, .render = bitmap_render, }; diff --git a/frontends/gtk/bitmap.h b/frontends/gtk/bitmap.h index 0f46d19a8..80a0e7a3a 100644 --- a/frontends/gtk/bitmap.h +++ b/frontends/gtk/bitmap.h @@ -26,7 +26,7 @@ extern struct gui_bitmap_table *nsgtk_bitmap_table; struct bitmap { cairo_surface_t *surface; /* original cairo surface */ cairo_surface_t *scsurface; /* scaled surface */ - bool converted; /** set if the surface data has been converted */ + bool opaque; }; int nsgtk_bitmap_get_width(void *vbitmap); diff --git a/frontends/gtk/compat.c b/frontends/gtk/compat.c index 4c5524b0e..bd3f46ee5 100644 --- a/frontends/gtk/compat.c +++ b/frontends/gtk/compat.c @@ -170,18 +170,18 @@ void nsgtk_entry_set_icon_from_pixbuf(GtkWidget *entry, /* exported interface documented in gtk/compat.h */ -void nsgtk_entry_set_icon_from_stock(GtkWidget *entry, - GtkEntryIconPosition icon_pos, - const gchar *id) +void nsgtk_entry_set_icon_from_icon_name(GtkWidget *entry, + GtkEntryIconPosition icon_pos, + const gchar *id) { #ifdef NSGTK_USE_ICON_NAME gtk_entry_set_icon_from_icon_name(GTK_ENTRY(entry), icon_pos, id); #else #if GTK_CHECK_VERSION(2,16,0) - gtk_entry_set_icon_from_stock(GTK_ENTRY(entry), icon_pos, id); + gtk_entry_set_icon_from_icon_name(GTK_ENTRY(entry), icon_pos, id); #else - GtkImage *image = GTK_IMAGE(gtk_image_new_from_stock(id, - GTK_ICON_SIZE_LARGE_TOOLBAR)); + GtkImage *image; + image = GTK_IMAGE(gtk_image_new_from_stock(id, GTK_ICON_SIZE_LARGE_TOOLBAR)); if (image != NULL) { sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry), @@ -216,6 +216,17 @@ GtkWidget *nsgtk_button_new_from_stock(const gchar *stock_id) } /* exported interface documented in gtk/compat.h */ +void nsgtk_button_set_focus_on_click(GtkButton *button, gboolean focus_on_click) +{ +#if GTK_CHECK_VERSION(3,20,0) + gtk_widget_set_focus_on_click(GTK_WIDGET(button), focus_on_click); +#else + gtk_button_set_focus_on_click(button, focus_on_click); +#endif +} + + +/* exported interface documented in gtk/compat.h */ gboolean nsgtk_stock_lookup(const gchar *stock_id, GtkStockItem *item) { #ifdef NSGTK_USE_ICON_NAME @@ -234,12 +245,17 @@ void nsgtk_widget_override_background_color(GtkWidget *widget, uint16_t b) { #if GTK_CHECK_VERSION(3,0,0) +#if GTK_CHECK_VERSION(3,16,0) + /* do nothing - deprecated - must use css styling */ + return; +#else GdkRGBA colour; colour.alpha = (double)a / 0xffff; colour.red = (double)r / 0xffff; colour.green = (double)g / 0xffff; colour.blue = (double)b / 0xffff; gtk_widget_override_background_color(widget, state, &colour); +#endif #else GdkColor colour; colour.pixel = a; @@ -403,15 +419,25 @@ GtkWidget *nsgtk_dialog_get_content_area(GtkDialog *dialog) #endif } +#if GTK_CHECK_VERSION(3,22,0) +#include "gtk/scaffolding.h" +#endif + gboolean nsgtk_show_uri(GdkScreen *screen, const gchar *uri, guint32 timestamp, GError **error) { #if GTK_CHECK_VERSION(2,14,0) +#if GTK_CHECK_VERSION(3,22,0) + GtkWindow *parent; + parent = nsgtk_scaffolding_window(nsgtk_current_scaffolding()); + return gtk_show_uri_on_window(parent, uri, timestamp,error); +#else return gtk_show_uri(screen, uri, timestamp, error); +#endif #else - return FALSE; /* FIXME */ + return FALSE; /** \todo add uri opening for before gtk 2.14 */ #endif } @@ -532,6 +558,17 @@ void nsgtk_image_menu_item_set_image(GtkWidget *image_menu_item, GtkWidget *imag } /* exported interface documented in gtk/compat.h */ +void nsgtk_menu_popup_at_pointer(GtkMenu *menu, const GdkEvent *trigger_event) +{ +#if GTK_CHECK_VERSION(3,22,0) + gtk_menu_popup_at_pointer(menu, trigger_event); +#else + gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); +#endif +} + +/* exported interface documented in gtk/compat.h */ gboolean nsgtk_icon_size_lookup_for_settings(GtkSettings *settings, GtkIconSize size, gint *width, @@ -598,7 +635,9 @@ void nsgtk_widget_set_margins(GtkWidget *widget, gint hmargin, gint vmargin) gtk_widget_set_margin_top(widget, vmargin); gtk_widget_set_margin_bottom(widget, vmargin); #else - gtk_misc_set_padding(GTK_MISC(widget), hmargin, vmargin); + if (GTK_IS_MISC(widget)) { + gtk_misc_set_padding(GTK_MISC(widget), hmargin, vmargin); + } #endif } diff --git a/frontends/gtk/compat.h b/frontends/gtk/compat.h index 9554b0cba..3b2f55094 100644 --- a/frontends/gtk/compat.h +++ b/frontends/gtk/compat.h @@ -16,7 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file +/** + * \file * Compatibility functions for older GTK versions (interface) */ @@ -40,9 +41,6 @@ #define NSGTK_STOCK_CANCEL "_Cancel" #define NSGTK_STOCK_CLEAR "edit-clear" #define NSGTK_STOCK_CLOSE "window-close" -#define NSGTK_STOCK_FIND "edit-find" -#define NSGTK_STOCK_GO_BACK "go-previous" -#define NSGTK_STOCK_GO_FORWARD "go-next" #define NSGTK_STOCK_HOME "go-home" #define NSGTK_STOCK_INFO "dialog-information" #define NSGTK_STOCK_REFRESH "view-refresh" @@ -51,14 +49,12 @@ #define NSGTK_STOCK_STOP "process-stop" #define NSGTK_STOCK_OK "_OK" #define NSGTK_STOCK_OPEN "_Open" +#define NSGTK_STOCK_OPEN_MENU "open-menu" #else #define NSGTK_STOCK_ADD GTK_STOCK_ADD #define NSGTK_STOCK_CANCEL GTK_STOCK_CANCEL #define NSGTK_STOCK_CLEAR GTK_STOCK_CLEAR #define NSGTK_STOCK_CLOSE GTK_STOCK_CLOSE -#define NSGTK_STOCK_FIND GTK_STOCK_FIND -#define NSGTK_STOCK_GO_BACK GTK_STOCK_GO_BACK -#define NSGTK_STOCK_GO_FORWARD GTK_STOCK_GO_FORWARD #define NSGTK_STOCK_HOME GTK_STOCK_HOME #define NSGTK_STOCK_INFO GTK_STOCK_INFO #define NSGTK_STOCK_REFRESH GTK_STOCK_REFRESH @@ -67,6 +63,7 @@ #define NSGTK_STOCK_STOP GTK_STOCK_STOP #define NSGTK_STOCK_OK GTK_STOCK_OK #define NSGTK_STOCK_OPEN GTK_STOCK_OPEN +#define NSGTK_STOCK_OPEN_MENU GTK_STOCK_JUSTIFY_FILL #endif /* widget alignment only available since 3.0 */ @@ -80,6 +77,12 @@ typedef enum { } GtkAlign; #endif +/* value init since gtk 2.30 */ +#ifndef G_VALUE_INIT +#define G_VALUE_INIT { 0, { { 0 } } } +#endif + + /** * Set the alignment of a widget. * @@ -153,6 +156,9 @@ GtkStateType nsgtk_widget_get_state(GtkWidget *widget); typedef GtkStateType GtkStateFlags; typedef GtkStyle GtkStyleContext; +/* gtk 3 changed the enum name for the state flags */ +#define GTK_STATE_FLAG_NORMAL GTK_STATE_NORMAL + #if GTK_CHECK_VERSION(2,22,0) enum { GTK_IN_DESTRUCTION = 1 << 0, @@ -167,16 +173,16 @@ enum { /** - * Sets the icon shown in the entry at the specified position from a - * stock image. + * Sets the icon shown in the entry at the specified position from an + * icon name. * - * Compatability interface for original deprecated in GTK 3.10 + * Compatability interface for original introduced in 2.16 * * \param entry The entry widget to set the icon on. * \param icon_pos The position of the icon. * \param stock_id the name of the stock item. */ -void nsgtk_entry_set_icon_from_stock(GtkWidget *entry, GtkEntryIconPosition icon_pos, const gchar *stock_id); +void nsgtk_entry_set_icon_from_icon_name(GtkWidget *entry, GtkEntryIconPosition icon_pos, const gchar *stock_id); /** * Creates a GtkImage displaying a stock icon. @@ -209,6 +215,16 @@ GtkWidget *nsgtk_button_new_from_stock(const gchar *stock_id); */ gboolean nsgtk_stock_lookup(const gchar *stock_id, GtkStockItem *item); +/** + * Sets whether the button will grab focus when it is clicked with the mouse. + * + * Compatability interface for original deprecated in GTK 3.20 + * + * \param button The button alter + * \param focus_on_click whether the button grabs focus when clicked with the mouse + */ +void nsgtk_button_set_focus_on_click(GtkButton *button, gboolean focus_on_click); + void nsgtk_window_set_opacity(GtkWindow *window, gdouble opacity); void nsgtk_scrolled_window_add_with_viewport(GtkScrolledWindow *window, GtkWidget *child); @@ -268,6 +284,15 @@ GtkWidget *nsgtk_image_menu_item_new_with_mnemonic(const gchar *label); */ void nsgtk_image_menu_item_set_image(GtkWidget *image_menu_item, GtkWidget *image); +/** + * Displays menu and makes it available for selection + * + * Compatability interface for gtk_menu_popup deprecated in GTK 3.22. + * + * \param image_menu_item The image menu entry item. + * \param trigger_event the GdkEvent that initiated this request or NULL if it's the current event. + */ +void nsgtk_menu_popup_at_pointer(GtkMenu *menu, const GdkEvent *trigger_event); /** * Parses a resource file containing a GtkBuilder UI definition and diff --git a/frontends/gtk/completion.c b/frontends/gtk/completion.c index eea0a789f..585a9e511 100644 --- a/frontends/gtk/completion.c +++ b/frontends/gtk/completion.c @@ -21,7 +21,7 @@ * Implementation of url entry completion. */ -#include <gtk/gtk.h> +#include <stdlib.h> #include "utils/log.h" #include "utils/messages.h" @@ -31,13 +31,27 @@ #include "netsurf/browser_window.h" #include "desktop/searchweb.h" +#include "gtk/compat.h" #include "gtk/warn.h" #include "gtk/scaffolding.h" +#include "gtk/toolbar_items.h" #include "gtk/window.h" #include "gtk/completion.h" GtkListStore *nsgtk_completion_list; +struct nsgtk_completion_ctx { + /** + * callback to obtain a browser window for navigation + */ + struct browser_window *(*get_bw)(void *ctx); + + /** + * context passed to get_bw function + */ + void *get_bw_ctx; +}; + /** * completion row matcher */ @@ -51,7 +65,6 @@ static gboolean nsgtk_completion_match(GtkEntryCompletion *completion, * are in the list should be shown. */ return TRUE; - } @@ -78,14 +91,17 @@ static gboolean nsgtk_completion_match_select(GtkEntryCompletion *widget, GtkTreeModel *model, GtkTreeIter *iter, - gpointer user_data) + gpointer data) { - GValue value = {0, }; - struct nsgtk_scaffolding *g = user_data; - struct browser_window *bw = nsgtk_get_browser_window(nsgtk_scaffolding_top_level(g)); + struct nsgtk_completion_ctx *cb_ctx; + GValue value = G_VALUE_INIT; + struct browser_window *bw; nserror ret; nsurl *url; + cb_ctx = data; + bw = cb_ctx->get_bw(cb_ctx->get_bw_ctx); + gtk_tree_model_get_value(model, iter, 0, &value); ret = search_web_omni(g_value_get_string(&value), @@ -128,11 +144,20 @@ gboolean nsgtk_completion_update(GtkEntry *entry) } /* exported interface documented in completion.h */ -GtkEntryCompletion *nsgtk_url_entry_completion_new(struct nsgtk_scaffolding *gs) +nserror +nsgtk_completion_connect_signals(GtkEntry *entry, + struct browser_window *(*get_bw)(void *ctx), + void *get_bw_ctx) { GtkEntryCompletion *completion; + struct nsgtk_completion_ctx *cb_ctx; + + cb_ctx = calloc(1, sizeof(struct nsgtk_completion_ctx)); + cb_ctx->get_bw = get_bw; + cb_ctx->get_bw_ctx = get_bw_ctx; + + completion = gtk_entry_get_completion(entry); - completion = gtk_entry_completion_new(); gtk_entry_completion_set_match_func(completion, nsgtk_completion_match, NULL, NULL); @@ -147,13 +172,15 @@ GtkEntryCompletion *nsgtk_url_entry_completion_new(struct nsgtk_scaffolding *gs) gtk_entry_completion_set_popup_completion(completion, TRUE); /* when selected callback */ - g_signal_connect(G_OBJECT(completion), "match-selected", - G_CALLBACK(nsgtk_completion_match_select), gs); + g_signal_connect(G_OBJECT(completion), + "match-selected", + G_CALLBACK(nsgtk_completion_match_select), + cb_ctx); g_object_set(G_OBJECT(completion), - "popup-set-width", TRUE, - "popup-single-match", TRUE, - NULL); + "popup-set-width", TRUE, + "popup-single-match", TRUE, + NULL); - return completion; + return NSERROR_OK; } diff --git a/frontends/gtk/completion.h b/frontends/gtk/completion.h index 9a1db293d..a81f1301a 100644 --- a/frontends/gtk/completion.h +++ b/frontends/gtk/completion.h @@ -37,10 +37,11 @@ void nsgtk_completion_init(void); gboolean nsgtk_completion_update(GtkEntry *entry); /** - * create a new entry completion on a scaffold. - * - * \param gs The scaffoliding which the url entry is in. + * connect signals on entry completion */ -GtkEntryCompletion *nsgtk_url_entry_completion_new(struct nsgtk_scaffolding *gs); +nserror +nsgtk_completion_connect_signals(GtkEntry *entry, + struct browser_window *(*get_bw)(void *ctx), + void *get_bw_ctx); #endif diff --git a/frontends/gtk/cookies.c b/frontends/gtk/cookies.c index 1f7833cca..0df9719cb 100644 --- a/frontends/gtk/cookies.c +++ b/frontends/gtk/cookies.c @@ -98,6 +98,8 @@ MENUHANDLER(delete_selected) MENUHANDLER(delete_all) { + cookie_manager_keypress(NS_KEY_ESCAPE); + cookie_manager_keypress(NS_KEY_ESCAPE); cookie_manager_keypress(NS_KEY_SELECT_ALL); cookie_manager_keypress(NS_KEY_DELETE_LEFT); return TRUE; @@ -105,6 +107,8 @@ MENUHANDLER(delete_all) MENUHANDLER(select_all) { + cookie_manager_keypress(NS_KEY_ESCAPE); + cookie_manager_keypress(NS_KEY_ESCAPE); cookie_manager_keypress(NS_KEY_SELECT_ALL); return TRUE; } @@ -305,13 +309,14 @@ static nserror nsgtk_cookies_init(void) /* exported function documented gtk/cookies.h */ -nserror nsgtk_cookies_present(void) +nserror nsgtk_cookies_present(const char *search_term) { nserror res; res = nsgtk_cookies_init(); if (res == NSERROR_OK) { gtk_window_present(cookie_window->wnd); + res = cookie_manager_set_search_string(search_term); } return res; } diff --git a/frontends/gtk/cookies.h b/frontends/gtk/cookies.h index c1a68b7f9..b8fc9aba2 100644 --- a/frontends/gtk/cookies.h +++ b/frontends/gtk/cookies.h @@ -28,7 +28,7 @@ * * \return NSERROR_OK on success else appropriate error code on faliure. */ -nserror nsgtk_cookies_present(void); +nserror nsgtk_cookies_present(const char *search_term); /** * Free any resources allocated for the cookie window. diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c index 6ca5d228f..baa4cf155 100644 --- a/frontends/gtk/corewindow.c +++ b/frontends/gtk/corewindow.c @@ -87,6 +87,7 @@ static browser_mouse_state nsgtk_cw_gdkbutton_to_nsstate(GdkEventButton *event) } if (event->state & GDK_MOD1_MASK) { + /* usually alt */ ms |= BROWSER_MOUSE_MOD_3; } @@ -224,6 +225,10 @@ nsgtk_cw_motion_notify_event(GtkWidget *widget, struct nsgtk_corewindow_mouse *mouse = &nsgtk_cw->mouse_state; if (mouse->pressed == false) { + nsgtk_cw->mouse(nsgtk_cw, + BROWSER_MOUSE_HOVER, + event->x, + event->y); return TRUE; } @@ -304,7 +309,7 @@ nsgtk_cw_motion_notify_event(GtkWidget *widget, */ static nserror nsgtk_cw_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey) { - double value; + double value = 0; GtkAdjustment *vscroll; GtkAdjustment *hscroll; GtkAdjustment *scroll = NULL; @@ -588,13 +593,15 @@ nsgtk_cw_invalidate_area(struct core_window *cw, const struct rect *rect) * \param width New widget width. * \param height New widget height. */ -static void +static nserror nsgtk_cw_update_size(struct core_window *cw, int width, int height) { struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; gtk_widget_set_size_request(GTK_WIDGET(nsgtk_cw->drawing_area), width, height); + + return NSERROR_OK; } @@ -604,30 +611,56 @@ nsgtk_cw_update_size(struct core_window *cw, int width, int height) * \param cw core window handle. * \param r rectangle that needs scrolling. */ -static void -nsgtk_cw_scroll_visible(struct core_window *cw, const struct rect *r) +static nserror +nsgtk_cw_set_scroll(struct core_window *cw, int x, int y) { struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; - int y = 0, height = 0, y0, y1; - gdouble page; - GtkAdjustment *vadj; - vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled); + if (nsgtk_cw->scrolled != NULL) { + GtkAdjustment *vadj; + GtkAdjustment *hadj; + + vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled); + hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled); + + assert(vadj != NULL); + assert(hadj != NULL); + + gtk_adjustment_set_value(vadj, y); + gtk_adjustment_set_value(hadj, x); + } + return NSERROR_OK; +} + + +/** + * scroll window core window callback + * + * \param cw core window handle. + * \param r rectangle that needs scrolling. + */ +static nserror +nsgtk_cw_get_scroll(const struct core_window *cw, int *x, int *y) +{ + struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; - assert(vadj); + if (nsgtk_cw->scrolled != NULL) { + GtkAdjustment *vadj; + GtkAdjustment *hadj; - g_object_get(vadj, "page-size", &page, NULL); + vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled); + hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled); - y0 = (int)(gtk_adjustment_get_value(vadj)); - y1 = y0 + page; + assert(vadj != NULL); + assert(hadj != NULL); - if ((y >= y0) && (y + height <= y1)) - return; - if (y + height > y1) - y0 = y0 + (y + height - y1); - if (y < y0) - y0 = y; - gtk_adjustment_set_value(vadj, y0); + *y = (int)(gtk_adjustment_get_value(vadj)); + *x = (int)(gtk_adjustment_get_value(hadj)); + } else { + *x = 0; + *y = 0; + } + return NSERROR_OK; } @@ -638,21 +671,31 @@ nsgtk_cw_scroll_visible(struct core_window *cw, const struct rect *r) * \param[out] width to be set to viewport width in px * \param[out] height to be set to viewport height in px */ -static void -nsgtk_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) +static nserror +nsgtk_cw_get_window_dimensions(const struct core_window *cw, + int *width, int *height) { struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; - GtkAdjustment *vadj; - GtkAdjustment *hadj; - gdouble page; - - hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled); - g_object_get(hadj, "page-size", &page, NULL); - *width = page; - - vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled); - g_object_get(vadj, "page-size", &page, NULL); - *height = page; + if (nsgtk_cw->scrolled != NULL) { + GtkAdjustment *vadj; + GtkAdjustment *hadj; + gdouble page; + + hadj = gtk_scrolled_window_get_hadjustment(nsgtk_cw->scrolled); + g_object_get(hadj, "page-size", &page, NULL); + *width = page; + + vadj = gtk_scrolled_window_get_vadjustment(nsgtk_cw->scrolled); + g_object_get(vadj, "page-size", &page, NULL); + *height = page; + } else { + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(nsgtk_cw->drawing_area), + &allocation); + *width = allocation.width; + *height = allocation.height; + } + return NSERROR_OK; } @@ -662,11 +705,13 @@ nsgtk_cw_get_window_dimensions(struct core_window *cw, int *width, int *height) * \param cw core window handle. * \param ds The new drag status. */ -static void +static nserror nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds) { struct nsgtk_corewindow *nsgtk_cw = (struct nsgtk_corewindow *)cw; nsgtk_cw->drag_status = ds; + + return NSERROR_OK; } @@ -676,7 +721,8 @@ nsgtk_cw_drag_status(struct core_window *cw, core_window_drag_status ds) static struct core_window_callback_table nsgtk_cw_cb_table = { .invalidate = nsgtk_cw_invalidate_area, .update_size = nsgtk_cw_update_size, - .scroll_visible = nsgtk_cw_scroll_visible, + .set_scroll = nsgtk_cw_set_scroll, + .get_scroll = nsgtk_cw_get_scroll, .get_window_dimensions = nsgtk_cw_get_window_dimensions, .drag_status = nsgtk_cw_drag_status }; @@ -730,7 +776,7 @@ nserror nsgtk_corewindow_init(struct nsgtk_corewindow *nsgtk_cw) nsgtk_widget_override_background_color( GTK_WIDGET(nsgtk_cw->drawing_area), - GTK_STATE_NORMAL, + GTK_STATE_FLAG_NORMAL, 0, 0xffff, 0xffff, 0xffff); return NSERROR_OK; diff --git a/frontends/gtk/download.c b/frontends/gtk/download.c index d11036ea8..d1231634d 100644 --- a/frontends/gtk/download.c +++ b/frontends/gtk/download.c @@ -34,6 +34,7 @@ #include "gtk/warn.h" #include "gtk/scaffolding.h" +#include "gtk/toolbar_items.h" #include "gtk/window.h" #include "gtk/compat.h" #include "gtk/resources.h" @@ -64,12 +65,23 @@ typedef enum { } nsgtk_download_status; typedef enum { - NSGTK_DOWNLOAD_PAUSE = 1 << 0, + NSGTK_DOWNLOAD_PAUSE = 1 << 0, NSGTK_DOWNLOAD_RESUME = 1 << 1, - NSGTK_DOWNLOAD_CANCEL = 1 << 2, - NSGTK_DOWNLOAD_CLEAR = 1 << 3 + NSGTK_DOWNLOAD_CANCEL = 1 << 2, + NSGTK_DOWNLOAD_CLEAR = 1 << 3 } nsgtk_download_actions; +static const gchar* status_messages[] = { + NULL, + "gtkWorking", + "gtkError", + "gtkComplete", + "gtkCanceled" +}; + +/** + * context for each download. + */ struct gui_download_window { struct download_context *ctx; nsgtk_download_actions sensitivity; @@ -77,8 +89,8 @@ struct gui_download_window { GString *name; GString *time_left; - gint size_total; - gint size_downloaded; + unsigned long long int size_total; + unsigned long long int size_downloaded; gint progress; gfloat time_remaining; gfloat start_time; @@ -89,26 +101,37 @@ struct gui_download_window { GError *error; }; -typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl); +typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl, + void *user_data); -static GtkWindow *nsgtk_download_window, *nsgtk_download_parent; -static GtkProgressBar *nsgtk_download_progress_bar; +/** + * context for a nsgtk download window. + */ +struct download_window_ctx { + GtkWindow *window; + GtkWindow *parent; + + GtkProgressBar *progress; + + GtkTreeView *tree; + GtkListStore *store; + GtkTreeSelection *selection; + GtkTreeIter iter; -static GtkTreeView *nsgtk_download_tree; -static GtkListStore *nsgtk_download_store; -static GtkTreeSelection *nsgtk_download_selection; -static GtkTreeIter nsgtk_download_iter; + GTimer *timer; + GList *list; + GtkButton *pause; + GtkButton *clear; + GtkButton *cancel; + GtkButton *resume; -static GTimer *nsgtk_downloads_timer; -static GList *nsgtk_downloads_list; -static GtkButton *nsgtk_download_button_pause; -static GtkButton *nsgtk_download_button_clear; -static GtkButton *nsgtk_download_button_cancel; -static GtkButton *nsgtk_download_button_resume; -static gint nsgtk_downloads_num_active; -static const gchar* status_messages[] = { NULL, "gtkWorking", "gtkError", - "gtkComplete", "gtkCanceled" }; + gint num_active; +}; +/** + * global instance of the download window + */ +static struct download_window_ctx dl_ctx; static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile) @@ -116,40 +139,66 @@ static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile) GtkTreeView *treeview; GtkCellRenderer *renderer; - treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile, "treeDownloads")); + treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile, + "treeDownloads")); /* Progress column */ renderer = gtk_cell_renderer_progress_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkProgress"), renderer, "value", - NSGTK_DOWNLOAD_PROGRESS, "pulse", NSGTK_DOWNLOAD_PULSE, - "text", NSGTK_DOWNLOAD_STATUS, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkProgress"), + renderer, + "value", + NSGTK_DOWNLOAD_PROGRESS, + "pulse", + NSGTK_DOWNLOAD_PULSE, + "text", + NSGTK_DOWNLOAD_STATUS, + NULL); /* Information column */ renderer = gtk_cell_renderer_text_new(); - g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD_CHAR, - "wrap-width", 300, NULL); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkDetails"), renderer, "text", - NSGTK_DOWNLOAD_INFO, NULL); - gtk_tree_view_column_set_expand(gtk_tree_view_get_column(treeview, - NSGTK_DOWNLOAD_INFO), TRUE); + g_object_set(G_OBJECT(renderer), + "wrap-mode", + PANGO_WRAP_WORD_CHAR, + "wrap-width", + 300, + NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkDetails"), + renderer, + "text", + NSGTK_DOWNLOAD_INFO, + NULL); + gtk_tree_view_column_set_expand( + gtk_tree_view_get_column(treeview, + NSGTK_DOWNLOAD_INFO), TRUE); /* Time remaining column */ renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkRemaining"), renderer, "text", - NSGTK_DOWNLOAD_REMAINING, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkRemaining"), + renderer, + "text", + NSGTK_DOWNLOAD_REMAINING, + NULL); /* Speed column */ renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkSpeed"), renderer, "text", - NSGTK_DOWNLOAD_SPEED, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkSpeed"), + renderer, + "text", + NSGTK_DOWNLOAD_SPEED, + NULL); return treeview; } + static gint nsgtk_download_sort(GtkTreeModel *model, GtkTreeIter *a, @@ -164,43 +213,52 @@ nsgtk_download_sort(GtkTreeModel *model, return dl1->status - dl2->status; } + static void nsgtk_download_sensitivity_update_buttons(nsgtk_download_actions sensitivity) { /* Glade seems to pack the buttons in an arbitrary order */ enum { PAUSE_BUTTON, CLEAR_BUTTON, CANCEL_BUTTON, RESUME_BUTTON }; - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_pause), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.pause), sensitivity & NSGTK_DOWNLOAD_PAUSE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_clear), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.clear), sensitivity & NSGTK_DOWNLOAD_CLEAR); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_cancel), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.cancel), sensitivity & NSGTK_DOWNLOAD_CANCEL); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_resume), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.resume), sensitivity & NSGTK_DOWNLOAD_RESUME); } + static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection) { GtkTreeIter iter; GList *rows; - gboolean selected = gtk_tree_selection_count_selected_rows(selection); - GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store); + gboolean selected; + GtkTreeModel *model; nsgtk_download_actions sensitivity = 0; struct gui_download_window *dl; + model = GTK_TREE_MODEL(dl_ctx.store); + + selected = gtk_tree_selection_count_selected_rows(selection); if (selected) { rows = gtk_tree_selection_get_selected_rows(selection, &model); while (rows != NULL) { - gtk_tree_model_get_iter(model, &iter, + gtk_tree_model_get_iter(model, + &iter, (GtkTreePath*)rows->data); - gtk_tree_model_get(model, &iter, NSGTK_DOWNLOAD, - &dl, -1); + gtk_tree_model_get(model, + &iter, + NSGTK_DOWNLOAD, + &dl, + -1); sensitivity |= dl->sensitivity; rows = rows->next; } } else { - rows = nsgtk_downloads_list; + rows = dl_ctx.list; while (rows != NULL) { dl = rows->data; sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR); @@ -208,83 +266,121 @@ static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection) } } - nsgtk_download_sensitivity_update_buttons(sensitivity); } + +/** + * Wrapper to GFunc-ify gtk_tree_path_free for g_list_foreach. + */ +static void +nsgtk_download_gfunc__gtk_tree_path_free(gpointer data, gpointer user_data) +{ + gtk_tree_path_free(data); +} + + +/** + * Wrapper to GFunc-ify g_free for g_list_foreach. + */ +static void +nsgtk_download_gfunc__g_free(gpointer data, gpointer user_data) +{ + g_free(data); +} + + static void nsgtk_download_do(nsgtk_download_selection_action action) { GList *rows, *dls = NULL; - GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store); - gboolean selection_exists = gtk_tree_selection_count_selected_rows( - nsgtk_download_selection); + GtkTreeModel *model; + + if (gtk_tree_selection_count_selected_rows(dl_ctx.selection)) { + model = GTK_TREE_MODEL(dl_ctx.store); - if (selection_exists) { - rows = gtk_tree_selection_get_selected_rows( - nsgtk_download_selection, &model); + rows = gtk_tree_selection_get_selected_rows(dl_ctx.selection, + &model); while (rows != NULL) { struct gui_download_window *dl; - gtk_tree_model_get_iter(GTK_TREE_MODEL( - nsgtk_download_store), - &nsgtk_download_iter, + + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, (GtkTreePath*)rows->data); - gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, NSGTK_DOWNLOAD, - &dl, -1); + + gtk_tree_model_get(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, + NSGTK_DOWNLOAD, + &dl, + -1); + dls = g_list_prepend(dls, dl); rows = rows->next; } - g_list_foreach(rows, (GFunc)gtk_tree_path_free, NULL); - g_list_foreach(rows, (GFunc)g_free, NULL); + g_list_foreach(rows, + nsgtk_download_gfunc__gtk_tree_path_free, + NULL); + g_list_foreach(rows, + nsgtk_download_gfunc__g_free, + NULL); g_list_free(rows); - } else - dls = g_list_copy(nsgtk_downloads_list); + } else { + dls = g_list_copy(dl_ctx.list); + } g_list_foreach(dls, (GFunc)action, NULL); g_list_free(dls); } + static gchar* nsgtk_download_info_to_string(struct gui_download_window *dl) { - gchar *size_info = g_strdup_printf(messages_get("gtkSizeInfo"), - human_friendly_bytesize(dl->size_downloaded), - dl->size_total == 0 ? messages_get("gtkUnknownSize") : - human_friendly_bytesize(dl->size_total)); - + gchar *size_info; gchar *r; - if (dl->status != NSGTK_DOWNLOAD_ERROR) + size_info = g_strdup_printf(messages_get("gtkSizeInfo"), + human_friendly_bytesize(dl->size_downloaded), + dl->size_total == 0 ? + messages_get("gtkUnknownSize") : + human_friendly_bytesize(dl->size_total)); + + if (dl->status != NSGTK_DOWNLOAD_ERROR) { r = g_strdup_printf("%s\n%s", dl->name->str, size_info); - else - r = g_strdup_printf("%s\n%s", dl->name->str, - dl->error->message); + } else { + r = g_strdup_printf("%s\n%s", dl->name->str, dl->error->message); + } g_free(size_info); return r; } + static gchar* nsgtk_download_time_to_string(gint seconds) { gint hours, minutes; - if (seconds < 0) + if (seconds < 0) { return g_strdup("-"); + } hours = seconds / 3600; seconds -= hours * 3600; minutes = seconds / 60; seconds -= minutes * 60; - if (hours > 0) - return g_strdup_printf("%u:%02u:%02u", hours, minutes, + if (hours > 0) { + return g_strdup_printf("%u:%02u:%02u", + hours, + minutes, seconds); - else + } else { return g_strdup_printf("%u:%02u", minutes, seconds); + } } -static void nsgtk_download_store_update_item (struct gui_download_window *dl) + +static void nsgtk_download_store_update_item(struct gui_download_window *dl) { gchar *info = nsgtk_download_info_to_string(dl); char *human = human_friendly_bytesize(dl->speed); @@ -294,11 +390,11 @@ static void nsgtk_download_store_update_item (struct gui_download_window *dl) gboolean pulse = dl->status == NSGTK_DOWNLOAD_WORKING; /* Updates iter (which is needed to set and get data) with the dl row */ - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + gtk_list_store_set(dl_ctx.store, &dl_ctx.iter, NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1, NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress, NSGTK_DOWNLOAD_INFO, info, @@ -311,27 +407,32 @@ static void nsgtk_download_store_update_item (struct gui_download_window *dl) g_free(time); } + static gboolean nsgtk_download_update(gboolean force_update) { /* Be sure we need to update */ - if (!nsgtk_widget_get_visible(GTK_WIDGET(nsgtk_download_window))) + if (!nsgtk_widget_get_visible(GTK_WIDGET(dl_ctx.window))) { return TRUE; + } GList *list; gchar *text; gboolean update, pulse_mode = FALSE; - gint downloaded = 0, total = 0, dls = 0; - gfloat percent, elapsed = g_timer_elapsed(nsgtk_downloads_timer, NULL); - nsgtk_downloads_num_active = 0; + unsigned long long int downloaded = 0; + unsigned long long int total = 0; + gint dls = 0; + gfloat percent, elapsed = g_timer_elapsed(dl_ctx.timer, NULL); - for (list = nsgtk_downloads_list; list != NULL; list = list->next) { + dl_ctx.num_active = 0; + + for (list = dl_ctx.list; list != NULL; list = list->next) { struct gui_download_window *dl = list->data; update = force_update; switch (dl->status) { case NSGTK_DOWNLOAD_WORKING: pulse_mode = TRUE; - /* Fall through */ + fallthrough; case NSGTK_DOWNLOAD_NONE: dl->speed = dl->size_downloaded / @@ -340,77 +441,86 @@ static gboolean nsgtk_download_update(gboolean force_update) dl->time_remaining = (dl->size_total - dl->size_downloaded)/ dl->speed; - dl->progress = (gfloat) - dl->size_downloaded / - dl->size_total * 100; - } else + dl->progress = (double)dl->size_downloaded / + (double)dl->size_total * 100; + } else { dl->progress++; + } - nsgtk_downloads_num_active++; + dl_ctx.num_active++; update = TRUE; - /* Fall through */ + fallthrough; case NSGTK_DOWNLOAD_COMPLETE: downloaded += dl->size_downloaded; total += dl->size_total; dls++; + fallthrough; default: ;//Do nothing } - if (update) + if (update) { nsgtk_download_store_update_item(dl); + } } if (pulse_mode) { text = g_strdup_printf( - messages_get(nsgtk_downloads_num_active > 1 ? + messages_get(dl_ctx.num_active > 1 ? "gtkProgressBarPulse" : "gtkProgressBarPulseSingle"), - nsgtk_downloads_num_active); - gtk_progress_bar_pulse(nsgtk_download_progress_bar); - gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); + dl_ctx.num_active); + gtk_progress_bar_pulse(dl_ctx.progress); + gtk_progress_bar_set_text(dl_ctx.progress, text); } else { - percent = total != 0 ? (gfloat)downloaded / total : 0; + percent = total != 0 ? (double)downloaded / (double)total : 0; text = g_strdup_printf(messages_get("gtkProgressBar"), - floor(percent*100), dls); - gtk_progress_bar_set_fraction(nsgtk_download_progress_bar, + floor(percent * 100), dls); + gtk_progress_bar_set_fraction(dl_ctx.progress, percent); - gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); + gtk_progress_bar_set_text(dl_ctx.progress, text); } g_free(text); - if (nsgtk_downloads_num_active == 0) + if (dl_ctx.num_active == 0) { return FALSE; /* Returning FALSE here cancels the g_timeout */ - else + } else { return TRUE; + } } -static void nsgtk_download_store_clear_item(struct gui_download_window *dl) + +static void +nsgtk_download_store_clear_item(struct gui_download_window *dl, void *user_data) { if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) { - nsgtk_downloads_list = g_list_remove(nsgtk_downloads_list, dl); + dl_ctx.list = g_list_remove(dl_ctx.list, dl); - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_remove(nsgtk_download_store, - &nsgtk_download_iter); + gtk_list_store_remove(dl_ctx.store, + &dl_ctx.iter); download_context_destroy(dl->ctx); g_string_free(dl->name, TRUE); g_string_free(dl->time_left, TRUE); g_free(dl); - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); + nsgtk_download_sensitivity_evaluate(dl_ctx.selection); nsgtk_download_update(FALSE); } } -static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, - GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) + +static void +nsgtk_download_tree_view_row_activated(GtkTreeView *tree, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer data) { GtkTreeModel *model; GtkTreeIter iter; @@ -423,29 +533,36 @@ static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, } } -static void nsgtk_download_change_sensitivity(struct gui_download_window *dl, - nsgtk_download_actions sensitivity) + +static void +nsgtk_download_change_sensitivity(struct gui_download_window *dl, + nsgtk_download_actions sensitivity) { dl->sensitivity = sensitivity; - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); + nsgtk_download_sensitivity_evaluate(dl_ctx.selection); } -static void nsgtk_download_change_status ( - struct gui_download_window *dl, nsgtk_download_status status) + +static void +nsgtk_download_change_status(struct gui_download_window *dl, + nsgtk_download_status status) { dl->status = status; if (status != NSGTK_DOWNLOAD_NONE) { - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + gtk_list_store_set(dl_ctx.store, &dl_ctx.iter, NSGTK_DOWNLOAD_STATUS, messages_get(status_messages[status]), -1); } } -static void nsgtk_download_store_cancel_item (struct gui_download_window *dl) + +static void +nsgtk_download_store_cancel_item(struct gui_download_window *dl, + void *user_data) { if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) { dl->speed = 0; @@ -463,148 +580,49 @@ static void nsgtk_download_store_cancel_item (struct gui_download_window *dl) } } + static gboolean nsgtk_download_hide(GtkWidget *window) { gtk_widget_hide(window); return TRUE; } -/* exported interface documented in gtk/download.h */ -nserror nsgtk_download_init(void) -{ - GtkBuilder* builder; - nserror res; - - res = nsgtk_builder_new_from_resname("downloads", &builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Download UI builder init failed"); - return res; - } - - gtk_builder_connect_signals(builder, NULL); - - nsgtk_download_button_pause = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPause")); - nsgtk_download_button_clear = GTK_BUTTON(gtk_builder_get_object(builder, "buttonClear")); - nsgtk_download_button_cancel = GTK_BUTTON(gtk_builder_get_object(builder, "buttonCancel")); - nsgtk_download_button_resume = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPlay")); - - nsgtk_download_progress_bar = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progressBar")); - nsgtk_download_window = GTK_WINDOW(gtk_builder_get_object(builder, "wndDownloads")); - nsgtk_download_parent = NULL; - - gtk_window_set_transient_for(GTK_WINDOW(nsgtk_download_window), - nsgtk_download_parent); - gtk_window_set_destroy_with_parent(GTK_WINDOW(nsgtk_download_window), - FALSE); - - nsgtk_downloads_timer = g_timer_new(); - - nsgtk_download_tree = nsgtk_download_tree_view_new(builder); - - nsgtk_download_store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS, - G_TYPE_INT, /* % complete */ - G_TYPE_STRING, /* Description */ - G_TYPE_STRING, /* Time remaining */ - G_TYPE_STRING, /* Speed */ - G_TYPE_INT, /* Pulse */ - G_TYPE_STRING, /* Status */ - G_TYPE_POINTER /* Download structure */ - ); - - - gtk_tree_view_set_model(nsgtk_download_tree, - GTK_TREE_MODEL(nsgtk_download_store)); - - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(nsgtk_download_store), - NSGTK_DOWNLOAD_STATUS, - (GtkTreeIterCompareFunc) nsgtk_download_sort, NULL, NULL); - gtk_tree_sortable_set_sort_column_id( - GTK_TREE_SORTABLE(nsgtk_download_store), - NSGTK_DOWNLOAD_STATUS, GTK_SORT_ASCENDING); - - g_object_unref(nsgtk_download_store); - - nsgtk_download_selection = - gtk_tree_view_get_selection(nsgtk_download_tree); - gtk_tree_selection_set_mode(nsgtk_download_selection, - GTK_SELECTION_MULTIPLE); - - g_signal_connect(G_OBJECT(nsgtk_download_selection), "changed", - G_CALLBACK(nsgtk_download_sensitivity_evaluate), NULL); - g_signal_connect(nsgtk_download_tree, "row-activated", - G_CALLBACK(nsgtk_download_tree_view_row_activated), - NULL); - g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"), - "clicked", - G_CALLBACK(nsgtk_download_do), - nsgtk_download_store_clear_item); - g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"), - "clicked", - G_CALLBACK(nsgtk_download_do), - nsgtk_download_store_cancel_item); - g_signal_connect(G_OBJECT(nsgtk_download_window), "delete-event", - G_CALLBACK(nsgtk_download_hide), NULL); - - return NSERROR_OK; -} - -void nsgtk_download_destroy () -{ - nsgtk_download_do(nsgtk_download_store_cancel_item); -} - -bool nsgtk_check_for_downloads (GtkWindow *parent) -{ - if (nsgtk_downloads_num_active != 0) { - GtkWidget *dialog; - dialog = gtk_message_dialog_new_with_markup(parent, - GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - "<big><b>%s</b></big>\n\n" - "<small>%s</small>", messages_get("gtkQuit"), - messages_get("gtkDownloadsRunning")); - gtk_dialog_add_buttons(GTK_DIALOG(dialog), "gtk-cancel", - GTK_RESPONSE_CANCEL, "gtk-quit", - GTK_RESPONSE_CLOSE, NULL); - - gint response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - if (response == GTK_RESPONSE_CANCEL) - return true; - } - - return false; -} - -void nsgtk_download_show(GtkWindow *parent) -{ - gtk_window_set_transient_for(nsgtk_download_window, - nsgtk_download_parent); - gtk_window_present(nsgtk_download_window); -} -static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *domain, - const gchar *size) +/** + * Prompt user for downloaded file name + * + * \param filename The original name of the file + * \param domain the domain the file is being downloaded from + * \param size The size of the file being downloaded + */ +static gchar* +nsgtk_download_dialog_show(const gchar *filename, + const gchar *domain, + const gchar *size) { enum { GTK_RESPONSE_DOWNLOAD, GTK_RESPONSE_SAVE_AS }; GtkWidget *dialog; char *destination = NULL; - gchar *message = g_strdup(messages_get("gtkStartDownload")); - gchar *info = g_strdup_printf(messages_get("gtkInfo"), filename, - domain, size); - - dialog = gtk_message_dialog_new_with_markup(nsgtk_download_parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, - "<span size=\"x-large\" weight=\"ultrabold\">%s</span>" - "\n\n<small>%s</small>", - message, info); - - gtk_dialog_add_buttons(GTK_DIALOG(dialog), NSGTK_STOCK_SAVE, - GTK_RESPONSE_DOWNLOAD, NSGTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, NSGTK_STOCK_SAVE_AS, - GTK_RESPONSE_SAVE_AS, NULL); + gchar *message; + gchar *info; + + message = g_strdup(messages_get("gtkStartDownload")); + info = g_strdup_printf(messages_get("gtkInfo"), filename, domain, size); + + dialog = gtk_message_dialog_new_with_markup( + dl_ctx.parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + "<span size=\"x-large\" weight=\"ultrabold\">%s</span>" + "\n\n<small>%s</small>", + message, + info); + + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + NSGTK_STOCK_SAVE, GTK_RESPONSE_DOWNLOAD, + NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NSGTK_STOCK_SAVE_AS, GTK_RESPONSE_SAVE_AS, + NULL); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); @@ -613,13 +631,13 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do switch (result) { case GTK_RESPONSE_SAVE_AS: { - dialog = gtk_file_chooser_dialog_new - (messages_get("gtkSave"), - nsgtk_download_parent, - GTK_FILE_CHOOSER_ACTION_SAVE, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); + dialog = gtk_file_chooser_dialog_new( + messages_get("gtkSave"), + dl_ctx.parent, + GTK_FILE_CHOOSER_ACTION_SAVE, + NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), filename); gtk_file_chooser_set_current_folder @@ -649,30 +667,32 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do * confirmation if needed */ if (g_file_test(destination, G_FILE_TEST_EXISTS) && nsoption_bool(request_overwrite)) { - message = g_strdup_printf(messages_get( - "gtkOverwrite"), filename); - info = g_strdup_printf(messages_get( - "gtkOverwriteInfo"), + GtkWidget *button; + + message = g_strdup_printf(messages_get("gtkOverwrite"), + filename); + info = g_strdup_printf(messages_get("gtkOverwriteInfo"), nsoption_charp(downloads_directory)); dialog = gtk_message_dialog_new_with_markup( - nsgtk_download_parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_CANCEL, - "<b>%s</b>",message); + dl_ctx.parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + "<b>%s</b>", + message); gtk_message_dialog_format_secondary_markup( - GTK_MESSAGE_DIALOG(dialog), - "%s", info); + GTK_MESSAGE_DIALOG(dialog), + "%s", + info); - GtkWidget *button = gtk_dialog_add_button( - GTK_DIALOG(dialog), - "_Replace", - GTK_RESPONSE_DOWNLOAD); + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + "_Replace", + GTK_RESPONSE_DOWNLOAD); gtk_button_set_image(GTK_BUTTON(button), nsgtk_image_new_from_stock( - NSGTK_STOCK_SAVE, - GTK_ICON_SIZE_BUTTON)); + NSGTK_STOCK_SAVE, + GTK_ICON_SIZE_BUTTON)); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_CANCEL) @@ -689,20 +709,24 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do } -static gboolean nsgtk_download_handle_error (GError *error) +static gboolean nsgtk_download_handle_error(GError *error) { + GtkWidget*dialog; + gchar *message; + if (error != NULL) { - GtkWidget*dialog; - gchar *message = g_strdup_printf(messages_get("gtkFileError"), - error->message); - - dialog = gtk_message_dialog_new_with_markup - (nsgtk_download_parent, - GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - "<big><b>%s</b></big>\n\n" - "<small>%s</small>", messages_get("gtkFailed"), - message); + message = g_strdup_printf(messages_get("gtkFileError"), + error->message); + + dialog = gtk_message_dialog_new_with_markup( + dl_ctx.parent, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "<big><b>%s</b></big>\n\n" + "<small>%s</small>", + messages_get("gtkFailed"), + message); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); @@ -711,30 +735,53 @@ static gboolean nsgtk_download_handle_error (GError *error) return FALSE; } -static void nsgtk_download_store_create_item (struct gui_download_window *dl) + +static void nsgtk_download_store_create_item(struct gui_download_window *dl) { nsgtk_download_store_update_item(dl); /* The iter has already been updated to this row */ - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, - NSGTK_DOWNLOAD, dl, -1); + gtk_list_store_set(dl_ctx.store, + &dl_ctx.iter, + NSGTK_DOWNLOAD, + dl, + -1); } + +/** + * Wrapper to GSourceFunc-ify nsgtk_download_update. + */ +static gboolean +nsgtk_download_gsourcefunc__nsgtk_download_update(gpointer user_data) +{ + return nsgtk_download_update(FALSE); +} + + +/** + * core callback on creating a new download + */ static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *gui) { - nsurl *url = download_context_get_url(ctx); - unsigned long total_size = download_context_get_total_length(ctx); + nsurl *url; + unsigned long long int total_size; gchar *domain; gchar *destination; - gboolean unknown_size = total_size == 0; - const char *size = (total_size == 0 ? - messages_get("gtkUnknownSize") : - human_friendly_bytesize(total_size)); + gboolean unknown_size; + struct gui_download_window *download; + const char *size; + + url = download_context_get_url(ctx); + total_size = download_context_get_total_length(ctx); + unknown_size = total_size == 0; + size = (total_size == 0 ? + messages_get("gtkUnknownSize") : + human_friendly_bytesize(total_size)); - nsgtk_download_parent = - nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); + dl_ctx.parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); - struct gui_download_window *download = malloc(sizeof *download); + download = malloc(sizeof *download); if (download == NULL) { return NULL; } @@ -761,12 +808,12 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) /* Add the new row and store the reference to it (which keeps track of * the tree changes) */ - gtk_list_store_prepend(nsgtk_download_store, &nsgtk_download_iter); + gtk_list_store_prepend(dl_ctx.store, &dl_ctx.iter); download->row = gtk_tree_row_reference_new( - GTK_TREE_MODEL(nsgtk_download_store), - gtk_tree_model_get_path( - GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter)); + GTK_TREE_MODEL(dl_ctx.store), + gtk_tree_model_get_path( + GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter)); download->ctx = ctx; download->name = g_string_new(download_context_get_filename(ctx)); @@ -774,13 +821,14 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) download->size_total = total_size; download->size_downloaded = 0; download->speed = 0; - download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL); + download->start_time = g_timer_elapsed(dl_ctx.timer, NULL); download->time_remaining = -1; download->status = NSGTK_DOWNLOAD_NONE; download->progress = 0; download->error = NULL; - download->write = - g_io_channel_new_file(destination, "w", &download->error); + download->write = g_io_channel_new_file(destination, + "w", + &download->error); if (nsgtk_download_handle_error(download->error)) { g_string_free(download->name, TRUE); @@ -793,24 +841,32 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); nsgtk_download_store_create_item(download); - nsgtk_download_show(nsgtk_download_parent); + nsgtk_download_show(dl_ctx.parent); - if (unknown_size) + if (unknown_size) { nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING); + } - if (nsgtk_downloads_num_active == 0) { - g_timeout_add(UPDATE_RATE, - (GSourceFunc) nsgtk_download_update, FALSE); + if (dl_ctx.num_active == 0) { + g_timeout_add( + UPDATE_RATE, + nsgtk_download_gsourcefunc__nsgtk_download_update, + NULL); } - nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download); + dl_ctx.list = g_list_prepend(dl_ctx.list, download); return download; } -static nserror gui_download_window_data(struct gui_download_window *dw, - const char *data, unsigned int size) +/** + * core callback on receipt of data + */ +static nserror +gui_download_window_data(struct gui_download_window *dw, + const char *data, + unsigned int size) { g_io_channel_write_chars(dw->write, data, size, NULL, &dw->error); if (dw->error != NULL) { @@ -822,7 +878,7 @@ static nserror gui_download_window_data(struct gui_download_window *dw, nsgtk_download_update(TRUE); - gtk_window_present(nsgtk_download_window); + gtk_window_present(dl_ctx.window); return NSERROR_SAVE_FAILED; } @@ -832,12 +888,18 @@ static nserror gui_download_window_data(struct gui_download_window *dw, } -static void gui_download_window_error(struct gui_download_window *dw, - const char *error_msg) +/** + * core callback on error + */ +static void +gui_download_window_error(struct gui_download_window *dw, const char *error_msg) { } +/** + * core callback when core download is complete + */ static void gui_download_window_done(struct gui_download_window *dw) { g_io_channel_shutdown(dw->write, TRUE, &dw->error); @@ -850,10 +912,11 @@ static void gui_download_window_done(struct gui_download_window *dw) nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE); - if (nsoption_bool(downloads_clear)) - nsgtk_download_store_clear_item(dw); - else + if (nsoption_bool(downloads_clear)) { + nsgtk_download_store_clear_item(dw, NULL); + } else { nsgtk_download_update(TRUE); + } } @@ -865,3 +928,146 @@ static struct gui_download_table download_table = { }; struct gui_download_table *nsgtk_download_table = &download_table; + + +/* exported interface documented in gtk/download.h */ +nserror nsgtk_download_init(void) +{ + GtkBuilder* builder; + nserror res; + + res = nsgtk_builder_new_from_resname("downloads", &builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Download UI builder init failed"); + return res; + } + + gtk_builder_connect_signals(builder, NULL); + + dl_ctx.pause = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonPause")); + dl_ctx.clear = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonClear")); + dl_ctx.cancel = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonCancel")); + dl_ctx.resume = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonPlay")); + + dl_ctx.progress = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, + "progressBar")); + dl_ctx.window = GTK_WINDOW(gtk_builder_get_object(builder, + "wndDownloads")); + dl_ctx.parent = NULL; + + gtk_window_set_transient_for(GTK_WINDOW(dl_ctx.window), + dl_ctx.parent); + gtk_window_set_destroy_with_parent(GTK_WINDOW(dl_ctx.window), + FALSE); + + dl_ctx.timer = g_timer_new(); + + dl_ctx.tree = nsgtk_download_tree_view_new(builder); + + dl_ctx.store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS, + G_TYPE_INT, /* % complete */ + G_TYPE_STRING, /* Description */ + G_TYPE_STRING, /* Time remaining */ + G_TYPE_STRING, /* Speed */ + G_TYPE_INT, /* Pulse */ + G_TYPE_STRING, /* Status */ + G_TYPE_POINTER /* Download structure */ + ); + + + gtk_tree_view_set_model(dl_ctx.tree, GTK_TREE_MODEL(dl_ctx.store)); + + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(dl_ctx.store), + NSGTK_DOWNLOAD_STATUS, + (GtkTreeIterCompareFunc)nsgtk_download_sort, NULL, NULL); + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dl_ctx.store), + NSGTK_DOWNLOAD_STATUS, + GTK_SORT_ASCENDING); + + g_object_unref(dl_ctx.store); + + dl_ctx.selection = gtk_tree_view_get_selection(dl_ctx.tree); + gtk_tree_selection_set_mode(dl_ctx.selection, GTK_SELECTION_MULTIPLE); + + g_signal_connect(G_OBJECT(dl_ctx.selection), + "changed", + G_CALLBACK(nsgtk_download_sensitivity_evaluate), + NULL); + + g_signal_connect(dl_ctx.tree, + "row-activated", + G_CALLBACK(nsgtk_download_tree_view_row_activated), + NULL); + + g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"), + "clicked", + G_CALLBACK(nsgtk_download_do), + nsgtk_download_store_clear_item); + + g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"), + "clicked", + G_CALLBACK(nsgtk_download_do), + nsgtk_download_store_cancel_item); + + g_signal_connect(G_OBJECT(dl_ctx.window), + "delete-event", + G_CALLBACK(nsgtk_download_hide), + NULL); + + return NSERROR_OK; +} + + +/* exported interface documented in gtk/download.h */ +void nsgtk_download_destroy(void) +{ + nsgtk_download_do(nsgtk_download_store_cancel_item); +} + + +/* exported interface documented in gtk/download.h */ +bool nsgtk_check_for_downloads(GtkWindow *parent) +{ + GtkWidget *dialog; + gint response; + + if (dl_ctx.num_active == 0) { + return false; + } + + dialog = gtk_message_dialog_new_with_markup( + parent, + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + "<big><b>%s</b></big>\n\n" + "<small>%s</small>", + messages_get("gtkQuit"), + messages_get("gtkDownloadsRunning")); + + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + "gtk-cancel", GTK_RESPONSE_CANCEL, + "gtk-quit", GTK_RESPONSE_CLOSE, + NULL); + + response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_CANCEL) { + return true; + } + + return false; +} + + +/* exported interface documented in gtk/download.h */ +void nsgtk_download_show(GtkWindow *parent) +{ + gtk_window_set_transient_for(dl_ctx.window, dl_ctx.parent); + gtk_window_present(dl_ctx.window); +} diff --git a/frontends/gtk/download.h b/frontends/gtk/download.h index 0b1097655..c6dc187e7 100644 --- a/frontends/gtk/download.h +++ b/frontends/gtk/download.h @@ -19,12 +19,11 @@ #ifndef GTK_DOWNLOAD_H #define GTK_DOWNLOAD_H -#include <gtk/gtk.h> - /** * download operation table for gtk */ -struct gui_download_table *nsgtk_download_table; +extern struct gui_download_table *nsgtk_download_table; + /** * Initialise download window ready for use. @@ -33,9 +32,27 @@ struct gui_download_table *nsgtk_download_table; */ nserror nsgtk_download_init(void); -void nsgtk_download_destroy (void); + +/** + * Destroy download window + */ +void nsgtk_download_destroy(void); + + +/** + * Check with user if download is in progress they want to complete + * + * \param parent The parent window for the prompt dialog. + * \return true if the user wants to continue else false. + */ bool nsgtk_check_for_downloads(GtkWindow *parent); + + +/** + * Show the download window + * + * \param parent The parent window to use for the shown window + */ void nsgtk_download_show(GtkWindow *parent); -void nsgtk_download_add(gchar *url, gchar *destination); #endif diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c index b05c1bd95..d77073a63 100644 --- a/frontends/gtk/fetch.c +++ b/frontends/gtk/fetch.c @@ -75,6 +75,7 @@ void gtk_fetch_filetype_init(const char *mimefile) hash_add(mime_hash, "html", "text/html"); hash_add(mime_hash, "jpg", "image/jpeg"); hash_add(mime_hash, "jpeg", "image/jpeg"); + hash_add(mime_hash, "jxl", "image/jxl"); hash_add(mime_hash, "gif", "image/gif"); hash_add(mime_hash, "png", "image/png"); hash_add(mime_hash, "jng", "image/jng"); @@ -117,11 +118,9 @@ void gtk_fetch_filetype_init(const char *mimefile) type = ptr; - /* search for the first non-whitespace char or NUL or + /* search for the first whitespace char or NUL or * NL */ - while (*ptr && - (!ascii_is_space(*ptr)) && - *ptr != '\n') { + while (*ptr && (!ascii_is_space(*ptr))) { ptr++; } @@ -146,9 +145,7 @@ void gtk_fetch_filetype_init(const char *mimefile) /* search for the first whitespace char or * NUL or NL which is the end of the ext. */ - while (*ptr && - (!ascii_is_space(*ptr)) && - *ptr != '\n') { + while (*ptr && (!ascii_is_space(*ptr))) { ptr++; } diff --git a/frontends/gtk/fetch.h b/frontends/gtk/fetch.h index a095adbf9..9175ccdf2 100644 --- a/frontends/gtk/fetch.h +++ b/frontends/gtk/fetch.h @@ -19,7 +19,7 @@ #ifndef NETSURF_GTK_FETCH_H #define NETSURF_GTK_FETCH_H -struct gui_fetch_table *nsgtk_fetch_table; +extern struct gui_fetch_table *nsgtk_fetch_table; void gtk_fetch_filetype_init(const char *mimefile); void gtk_fetch_filetype_fin(void); diff --git a/frontends/gtk/gdk.c b/frontends/gtk/gdk.c index fd82af5b2..fe9a0791c 100644 --- a/frontends/gtk/gdk.c +++ b/frontends/gtk/gdk.c @@ -33,7 +33,8 @@ convert_alpha(guchar *dest_data, int x, y; for (y = 0; y < height; y++) { - guint32 *src = (guint32 *) src_data; + /* this cast is safe, the buffer is appropriately aligned */ + guint32 *src = (void *) src_data; for (x = 0; x < width; x++) { guint alpha = src[x] >> 24; @@ -72,7 +73,7 @@ nsgdk_pixbuf_get_from_surface(cairo_surface_t *surface, int scwidth, int scheigh memset(gdk_pixbuf_get_pixels(pixbuf), 0xff, - gdk_pixbuf_get_rowstride(pixbuf) * scheight); + gdk_pixbuf_get_rowstride(pixbuf) * (size_t)scheight); /* scale cairo surface into new surface the target size */ cairo_surface_flush(surface); /* ensure source surface is ready */ diff --git a/frontends/gtk/global_history.c b/frontends/gtk/global_history.c index f204168d0..33032e567 100644 --- a/frontends/gtk/global_history.c +++ b/frontends/gtk/global_history.c @@ -107,6 +107,8 @@ MENUHANDLER(delete_selected) MENUHANDLER(delete_all) { + global_history_keypress(NS_KEY_ESCAPE); + global_history_keypress(NS_KEY_ESCAPE); global_history_keypress(NS_KEY_SELECT_ALL); global_history_keypress(NS_KEY_DELETE_LEFT); return TRUE; @@ -114,12 +116,16 @@ MENUHANDLER(delete_all) MENUHANDLER(select_all) { + global_history_keypress(NS_KEY_ESCAPE); + global_history_keypress(NS_KEY_ESCAPE); global_history_keypress(NS_KEY_SELECT_ALL); return TRUE; } MENUHANDLER(clear_selection) { + global_history_keypress(NS_KEY_ESCAPE); + global_history_keypress(NS_KEY_ESCAPE); global_history_keypress(NS_KEY_CLEAR_SELECTION); return TRUE; } diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c index 3163be16d..661176ded 100644 --- a/frontends/gtk/gui.c +++ b/frontends/gtk/gui.c @@ -41,13 +41,13 @@ #include "netsurf/keypress.h" #include "netsurf/url_db.h" #include "netsurf/cookie_db.h" +#include "netsurf/browser.h" #include "netsurf/browser_window.h" -#include "netsurf/misc.h" #include "netsurf/netsurf.h" +#include "netsurf/bitmap.h" #include "content/fetch.h" #include "content/backing_store.h" #include "desktop/save_complete.h" -#include "desktop/save_pdf.h" #include "desktop/searchweb.h" #include "desktop/hotlist.h" @@ -62,446 +62,34 @@ #include "gtk/global_history.h" #include "gtk/hotlist.h" #include "gtk/throbber.h" +#include "gtk/toolbar_items.h" #include "gtk/scaffolding.h" #include "gtk/window.h" #include "gtk/schedule.h" #include "gtk/selection.h" #include "gtk/search.h" -#include "gtk/ssl_cert.h" #include "gtk/bitmap.h" +#include "gtk/misc.h" #include "gtk/resources.h" -#include "gtk/login.h" #include "gtk/layout_pango.h" #include "gtk/accelerator.h" bool nsgtk_complete = false; -char *nsgtk_config_home; /* exported global defined in gtk/gui.h */ +/* exported global defined in gtk/gui.h */ +char *nsgtk_config_home; -GdkPixbuf *favicon_pixbuf; /** favicon default pixbuf */ -GdkPixbuf *win_default_icon_pixbuf; /** default window icon pixbuf */ -GdkPixbuf *arrow_down_pixbuf; /** arrow down pixbuf */ +/** favicon default pixbuf */ +GdkPixbuf *favicon_pixbuf; -GtkBuilder *warning_builder; - -char **respaths; /** resource search path vector */ - -/** - * Cause an abnormal program termination. - * - * \note This never returns and is intended to terminate without any cleanup. - * - * \param error The message to display to the user. - */ -static void die(const char * const error) -{ - fprintf(stderr, "%s", error); - exit(EXIT_FAILURE); -} - -/** - * Create an array of valid paths to search for resources. - * - * The idea is that all the complex path computation to find resources - * is performed here, once, rather than every time a resource is - * searched for. - */ -static char ** -nsgtk_init_resource_path(const char *config_home) -{ - char *resource_path; - int resource_path_len; - const gchar * const *langv; - char **pathv; /* resource path string vector */ - char **respath; /* resource paths vector */ - - if (config_home != NULL) { - resource_path_len = snprintf(NULL, 0, - "%s:${NETSURFRES}:%s", - config_home, - GTK_RESPATH); - resource_path = malloc(resource_path_len + 1); - if (resource_path == NULL) { - return NULL; - } - snprintf(resource_path, resource_path_len + 1, - "%s:${NETSURFRES}:%s", - config_home, - GTK_RESPATH); - } else { - resource_path_len = snprintf(NULL, 0, - "${NETSURFRES}:%s", - GTK_RESPATH); - resource_path = malloc(resource_path_len + 1); - if (resource_path == NULL) { - return NULL; - } - snprintf(resource_path, - resource_path_len + 1, - "${NETSURFRES}:%s", - GTK_RESPATH); - } - - pathv = filepath_path_to_strvec(resource_path); - - langv = g_get_language_names(); - - respath = filepath_generate(pathv, langv); - - filepath_free_strvec(pathv); - - free(resource_path); - - return respath; -} - - -/** - * Set option defaults for gtk frontend. - * - * @param defaults The option table to update. - * @return error status. - */ -static nserror set_defaults(struct nsoption_s *defaults) -{ - char *fname; - - /* cookie file default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); - if (fname != NULL) { - nsoption_setnull_charp(cookie_file, fname); - } - - /* cookie jar default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); - if (fname != NULL) { - nsoption_setnull_charp(cookie_jar, fname); - } - - /* url database default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs"); - if (fname != NULL) { - nsoption_setnull_charp(url_file, fname); - } - - /* bookmark database default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist"); - if (fname != NULL) { - nsoption_setnull_charp(hotlist_path, fname); - } - - /* download directory default */ - fname = getenv("HOME"); - if (fname != NULL) { - nsoption_setnull_charp(downloads_directory, strdup(fname)); - } - - /* default path to certificates */ - nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs")); - - if ((nsoption_charp(cookie_file) == NULL) || - (nsoption_charp(cookie_jar) == NULL) || - (nsoption_charp(url_file) == NULL) || - (nsoption_charp(hotlist_path) == NULL) || - (nsoption_charp(downloads_directory) == NULL) || - (nsoption_charp(ca_path) == NULL)) { - NSLOG(netsurf, INFO, - "Failed initialising default resource paths"); - return NSERROR_BAD_PARAMETER; - } - - /* set default font names */ - nsoption_set_charp(font_sans, strdup("Sans")); - nsoption_set_charp(font_serif, strdup("Serif")); - nsoption_set_charp(font_mono, strdup("Monospace")); - nsoption_set_charp(font_cursive, strdup("Serif")); - nsoption_set_charp(font_fantasy, strdup("Serif")); - - return NSERROR_OK; -} - - - - -/** - * Initialize GTK specific parts of the browser. - * - * \param argc The number of arguments on the command line - * \param argv A string vector of command line arguments. - * \respath A string vector of the path elements of resources - */ -static nserror nsgtk_init(int argc, char** argv, char **respath) -{ - char buf[PATH_MAX]; - char *resource_filename; - char *addr = NULL; - nsurl *url; - nserror res; - - /* Initialise gtk accelerator table */ - res = nsgtk_accelerator_init(respaths); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Unable to load gtk accelerator configuration"); - /* not fatal if this does not load */ - } - - /* initialise warning dialog */ - res = nsgtk_builder_new_from_resname("warning", &warning_builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise warning dialog"); - return res; - } - - gtk_builder_connect_signals(warning_builder, NULL); - - /* set default icon if its available */ - res = nsgdk_pixbuf_new_from_resname("netsurf.xpm", - &win_default_icon_pixbuf); - if (res == NSERROR_OK) { - NSLOG(netsurf, INFO, "Seting default window icon"); - gtk_window_set_default_icon(win_default_icon_pixbuf); - } - - /* Search engine sources */ - resource_filename = filepath_find(respath, "SearchEngines"); - search_web_init(resource_filename); - if (resource_filename != NULL) { - NSLOG(netsurf, INFO, "Using '%s' as Search Engines file", - resource_filename); - free(resource_filename); - } - - /* Default favicon */ - res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf); - if (res != NSERROR_OK) { - favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - false, 8, 16, 16); - } - - /* arrow down icon */ - res = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png", - &arrow_down_pixbuf); - if (res != NSERROR_OK) { - arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - false, 8, 8, 32); - } - - /* initialise throbber */ - res = nsgtk_throbber_init(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise throbber."); - return res; - } - - /* Initialise completions - cannot fail */ - nsgtk_completion_init(); - - /* The tree view system needs to know the screen's DPI, so we - * find that out here, rather than when we create a first browser - * window. - */ - browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default())); - NSLOG(netsurf, INFO, "Set CSS DPI to %d", browser_get_dpi()); - - filepath_sfinddef(respath, buf, "mime.types", "/etc/"); - gtk_fetch_filetype_init(buf); - - save_complete_init(); - - urldb_load(nsoption_charp(url_file)); - urldb_load_cookies(nsoption_charp(cookie_file)); - hotlist_init(nsoption_charp(hotlist_path), - nsoption_charp(hotlist_path)); - - /* Initialise top level UI elements */ - res = nsgtk_download_init(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise download window."); - return res; - } - - /* If there is a url specified on the command line use it */ - if (argc > 1) { - struct stat fs; - if (stat(argv[1], &fs) == 0) { - size_t addrlen; - char *rp = realpath(argv[1], NULL); - assert(rp != NULL); - - /* calculate file url length including terminator */ - addrlen = SLEN("file://") + strlen(rp) + 1; - addr = malloc(addrlen); - assert(addr != NULL); - snprintf(addr, addrlen, "file://%s", rp); - free(rp); - } else { - addr = strdup(argv[1]); - } - } - if (addr != NULL) { - /* managed to set up based on local launch */ - } else if (nsoption_charp(homepage_url) != NULL) { - addr = strdup(nsoption_charp(homepage_url)); - } else { - addr = strdup(NETSURF_HOMEPAGE); - } - - /* create an initial browser window */ - res = nsurl_create(addr, &url); - if (res == NSERROR_OK) { - res = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); - nsurl_unref(url); - } - - free(addr); - - return res; -} - - - -/** - * Ensures output logging stream is correctly configured - */ -static bool nslog_stream_configure(FILE *fptr) -{ - /* set log stream to be non-buffering */ - setbuf(fptr, NULL); - - return true; -} - - -/** - * Run the gtk event loop. - * - * The same as the standard gtk_main loop except this ensures active - * FD are added to the gtk poll event set. - */ -static void nsgtk_main(void) -{ - fd_set read_fd_set, write_fd_set, exc_fd_set; - int max_fd; - GPollFD *fd_list[1000]; - unsigned int fd_count; - - while (!nsgtk_complete) { - max_fd = -1; - fd_count = 0; - FD_ZERO(&read_fd_set); - FD_ZERO(&write_fd_set); - FD_ZERO(&exc_fd_set); - - fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); - for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, &read_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - if (FD_ISSET(i, &write_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_OUT | G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - if (FD_ISSET(i, &exc_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - } - - schedule_run(); +/** default window icon pixbuf */ +GdkPixbuf *win_default_icon_pixbuf; - gtk_main_iteration(); - - for (unsigned int i = 0; i != fd_count; i++) { - g_main_context_remove_poll(0, fd_list[i]); - free(fd_list[i]); - } - } -} - - -static void gui_quit(void) -{ - nserror res; - - NSLOG(netsurf, INFO, "Quitting GUI"); - - /* Ensure all scaffoldings are destroyed before we go into exit */ - nsgtk_download_destroy(); - urldb_save_cookies(nsoption_charp(cookie_jar)); - urldb_save(nsoption_charp(url_file)); - - res = nsgtk_cookies_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising cookie viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_local_history_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Error finalising local history viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_global_history_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Error finalising global history viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_hotlist_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising hotlist viewer: %s", - messages_get_errorcode(res)); - } - - res = hotlist_fini(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising hotlist: %s", - messages_get_errorcode(res)); - } - - free(nsgtk_config_home); - - gtk_fetch_filetype_fin(); -} - -static nserror gui_launch_url(struct nsurl *url) -{ - gboolean ok; - GError *error = NULL; +GtkBuilder *warning_builder; - ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error); - if (ok == TRUE) { - return NSERROR_OK; - } +/** resource search path vector */ +char **respaths; - if (error) { - nsgtk_warning(messages_get("URIOpenError"), error->message); - g_error_free(error); - } - return NSERROR_NO_FETCH_HANDLER; -} /* exported function documented in gtk/warn.h */ nserror nsgtk_warning(const char *warning, const char *detail) @@ -518,7 +106,7 @@ nserror nsgtk_warning(const char *warning, const char *detail) "labelWarning")); snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), - detail ? detail : ""); + detail ? detail : ""); buf[sizeof(buf) - 1] = 0; gtk_label_set_text(WarningLabel, buf); @@ -529,129 +117,7 @@ nserror nsgtk_warning(const char *warning, const char *detail) } -static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) -{ - char **owner_pass = ((void **)data)[0]; - char **user_pass = ((void **)data)[1]; - GtkWindow *wnd = ((void **)data)[2]; - GtkBuilder *password_builder = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - char *op, *op1; - char *up, *up1; - - op = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFOwnerPassword")))); - op1 = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFOwnerPassword1")))); - up = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFUserPassword")))); - up1 = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFUserPassword1")))); - - - if (op[0] == '\0') { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), - "Owner password must be at least 1 character long:"); - free(op); - free(up); - } else if (!strcmp(op, up)) { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), - "User and owner passwords must be different:"); - free(op); - free(up); - } else if (!strcmp(op, op1) && !strcmp(up, up1)) { - - *owner_pass = op; - if (up[0] == '\0') - free(up); - else - *user_pass = up; - - free(data); - gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(password_builder)); - - save_pdf(path); - - free(path); - } else { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), "Passwords not confirmed:"); - free(op); - free(up); - } - - free(op1); - free(up1); -} - -static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data) -{ - GtkWindow *wnd = ((void **)data)[2]; - GtkBuilder *password_builder = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - free(data); - - gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(password_builder)); - - save_pdf(path); - - free(path); -} - -static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path) -{ - GtkButton *ok, *no; - GtkWindow *wnd; - void **data; - GtkBuilder *password_builder; - nserror res; - - res = nsgtk_builder_new_from_resname("password", &password_builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Password UI builder init failed"); - return; - } - - gtk_builder_connect_signals(password_builder, NULL); - - wnd = GTK_WINDOW(gtk_builder_get_object(password_builder, - "wndPDFPassword")); - - data = malloc(5 * sizeof(void *)); - - *owner_pass = NULL; - *user_pass = NULL; - - data[0] = owner_pass; - data[1] = user_pass; - data[2] = wnd; - data[3] = password_builder; - data[4] = path; - - ok = GTK_BUTTON(gtk_builder_get_object(password_builder, - "buttonPDFSetPassword")); - no = GTK_BUTTON(gtk_builder_get_object(password_builder, - "buttonPDFNoPassword")); - - g_signal_connect(G_OBJECT(ok), "clicked", - G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data); - g_signal_connect(G_OBJECT(no), "clicked", - G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data); - - gtk_widget_show(GTK_WIDGET(wnd)); -} - - +/* exported interface documented in gtk/gui.h */ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) { /* this function will need to become much more complex to support @@ -666,12 +132,16 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) case GDK_KEY(BackSpace): if (key->state & GDK_SHIFT_MASK) return NS_KEY_DELETE_LINE_START; + else if (key->state & GDK_CONTROL_MASK) + return NS_KEY_DELETE_WORD_LEFT; else return NS_KEY_DELETE_LEFT; case GDK_KEY(Delete): if (key->state & GDK_SHIFT_MASK) return NS_KEY_DELETE_LINE_END; + else if (key->state & GDK_CONTROL_MASK) + return NS_KEY_DELETE_WORD_RIGHT; else return NS_KEY_DELETE_RIGHT; @@ -683,10 +153,14 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) case GDK_KEY(Left): case GDK_KEY(KP_Left): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_WORD_LEFT; return NS_KEY_LEFT; case GDK_KEY(Right): case GDK_KEY(KP_Right): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_WORD_RIGHT; return NS_KEY_RIGHT; case GDK_KEY(Up): @@ -781,6 +255,63 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) /** + * Create an array of valid paths to search for resources. + * + * The idea is that all the complex path computation to find resources + * is performed here, once, rather than every time a resource is + * searched for. + */ +static char ** +nsgtk_init_resource_path(const char *config_home) +{ + char *resource_path; + int resource_path_len; + const gchar * const *langv; + char **pathv; /* resource path string vector */ + char **respath; /* resource paths vector */ + + if (config_home != NULL) { + resource_path_len = snprintf(NULL, 0, + "%s:${NETSURFRES}:%s", + config_home, + GTK_RESPATH); + resource_path = malloc(resource_path_len + 1); + if (resource_path == NULL) { + return NULL; + } + snprintf(resource_path, resource_path_len + 1, + "%s:${NETSURFRES}:%s", + config_home, + GTK_RESPATH); + } else { + resource_path_len = snprintf(NULL, 0, + "${NETSURFRES}:%s", + GTK_RESPATH); + resource_path = malloc(resource_path_len + 1); + if (resource_path == NULL) { + return NULL; + } + snprintf(resource_path, + resource_path_len + 1, + "${NETSURFRES}:%s", + GTK_RESPATH); + } + + pathv = filepath_path_to_strvec(resource_path); + + langv = g_get_language_names(); + + respath = filepath_generate(pathv, langv); + + filepath_free_strvec(pathv); + + free(resource_path); + + return respath; +} + + +/** * create directory name and check it is acessible and a directory. */ static nserror @@ -818,6 +349,7 @@ check_dirname(const char *path, const char *leaf, char **dirname_out) return ret; } + /** * Get the path to the config directory. * @@ -885,6 +417,7 @@ static nserror get_config_home(char **config_home_out) return NSERROR_OK; } + static nserror create_config_home(char **config_home_out) { char *config_home = NULL; @@ -935,6 +468,192 @@ static nserror create_config_home(char **config_home_out) return NSERROR_OK; } + +/** + * Ensures output logging stream is correctly configured + */ +static bool nslog_stream_configure(FILE *fptr) +{ + /* set log stream to be non-buffering */ + setbuf(fptr, NULL); + + return true; +} + + +/** + * Set option defaults for gtk frontend. + * + * \param defaults The option table to update. + * \return error status. + */ +static nserror set_defaults(struct nsoption_s *defaults) +{ + char *fname; + GtkSettings *settings; + GtkIconSize tooliconsize; + GtkToolbarStyle toolbarstyle; + + /* cookie file default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); + if (fname != NULL) { + nsoption_setnull_charp(cookie_file, fname); + } + + /* cookie jar default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); + if (fname != NULL) { + nsoption_setnull_charp(cookie_jar, fname); + } + + /* url database default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs"); + if (fname != NULL) { + nsoption_setnull_charp(url_file, fname); + } + + /* bookmark database default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist"); + if (fname != NULL) { + nsoption_setnull_charp(hotlist_path, fname); + } + + /* download directory default */ + fname = getenv("HOME"); + if (fname != NULL) { + nsoption_setnull_charp(downloads_directory, strdup(fname)); + } + + if ((nsoption_charp(cookie_file) == NULL) || + (nsoption_charp(cookie_jar) == NULL) || + (nsoption_charp(url_file) == NULL) || + (nsoption_charp(hotlist_path) == NULL) || + (nsoption_charp(downloads_directory) == NULL)) { + NSLOG(netsurf, INFO, + "Failed initialising default resource paths"); + return NSERROR_BAD_PARAMETER; + } + + /* set default font names */ + nsoption_set_charp(font_sans, strdup("Sans")); + nsoption_set_charp(font_serif, strdup("Serif")); + nsoption_set_charp(font_mono, strdup("Monospace")); + nsoption_set_charp(font_cursive, strdup("Serif")); + nsoption_set_charp(font_fantasy, strdup("Serif")); + + /* Default toolbar button type to system defaults */ + + settings = gtk_settings_get_default(); + 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; + } + + /* set default items in toolbar */ + nsoption_set_charp(toolbar_items, + strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu")); + + /* set default for menu and tool bar visibility */ + nsoption_set_charp(bar_show, strdup("tool")); + + return NSERROR_OK; +} + + +/** + * Initialise user options + * + * Initialise the browser configuration options. These are set by: + * - set generic defaults suitable for the gtk frontend + * - user choices loaded from Choices file + * - command line parameters + */ +static nserror nsgtk_option_init(int *pargc, char** argv) +{ + nserror ret; + char *choices = NULL; + + /* user options setup */ + ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); + if (ret != NSERROR_OK) { + return ret; + } + + /* Attempt to load the user choices */ + ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); + if (ret == NSERROR_OK) { + nsoption_read(choices, nsoptions); + free(choices); + } + + /* overide loaded options with those from commandline */ + nsoption_commandline(pargc, argv, nsoptions); + + /* ensure all options fall within sensible bounds */ + + /* Attempt to handle nonsense status bar widths. These may exist + * in people's Choices as the GTK front end used to abuse the + * status bar width option by using it for an absolute value in px. + * The GTK front end now correctly uses it as a proportion of window + * width. Here we assume that a value of less than 15% is wrong + * and set to the default two thirds. */ + if (nsoption_int(toolbar_status_size) < 1500) { + nsoption_set_int(toolbar_status_size, 6667); + } + + return NSERROR_OK; +} + + +/** + * initialise message translation + */ +static nserror nsgtk_messages_init(char **respaths) +{ + const char *messages; + nserror ret; + const uint8_t *data; + size_t data_size; + + ret = nsgtk_data_from_resname("Messages", &data, &data_size); + if (ret == NSERROR_OK) { + ret = messages_add_from_inline(data, data_size); + } else { + /* Obtain path to messages */ + ret = nsgtk_path_from_resname("Messages", &messages); + if (ret == NSERROR_OK) { + ret = messages_add_from_file(messages); + } + } + return ret; +} + + /** * Get the path to the cache directory. * @@ -983,6 +702,10 @@ static nserror get_cache_home(char **cache_home_out) return NSERROR_OK; } + +/** + * create a cache directory + */ static nserror create_cache_home(char **cache_home_out) { char *cache_home = NULL; @@ -990,7 +713,7 @@ static nserror create_cache_home(char **cache_home_out) char *xdg_cache_dir; nserror ret; - NSLOG(netsurf, INFO, "Attempting to create configuration directory"); + NSLOG(netsurf, INFO, "Attempting to create cache directory"); /* $XDG_CACHE_HOME defines the base directory * relative to which user specific cache files @@ -1033,98 +756,13 @@ static nserror create_cache_home(char **cache_home_out) return NSERROR_OK; } -static nserror nsgtk_option_init(int *pargc, char** argv) -{ - nserror ret; - char *choices = NULL; - - /* user options setup */ - ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); - if (ret != NSERROR_OK) { - return ret; - } - - /* Attempt to load the user choices */ - ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); - if (ret == NSERROR_OK) { - nsoption_read(choices, nsoptions); - free(choices); - } - - /* overide loaded options with those from commandline */ - nsoption_commandline(pargc, argv, nsoptions); - - /* ensure all options fall within sensible bounds */ - - /* Attempt to handle nonsense status bar widths. These may exist - * in people's Choices as the GTK front end used to abuse the - * status bar width option by using it for an absolute value in px. - * The GTK front end now correctly uses it as a proportion of window - * width. Here we assume that a value of less than 15% is wrong - * and set to the default two thirds. */ - if (nsoption_int(toolbar_status_size) < 1500) { - nsoption_set_int(toolbar_status_size, 6667); - } - - return NSERROR_OK; -} - -static struct gui_misc_table nsgtk_misc_table = { - .schedule = nsgtk_schedule, - .warning = nsgtk_warning, - - .quit = gui_quit, - .launch_url = gui_launch_url, - .cert_verify = gtk_cert_verify, - .login = gui_401login_open, - .pdf_password = nsgtk_pdf_password, -}; - - -static nserror nsgtk_messages_init(char **respaths) -{ - const char *messages; - nserror ret; - const uint8_t *data; - size_t data_size; - - ret = nsgtk_data_from_resname("Messages", &data, &data_size); - if (ret == NSERROR_OK) { - ret = messages_add_from_inline(data, data_size); - } else { - /* Obtain path to messages */ - ret = nsgtk_path_from_resname("Messages", &messages); - if (ret == NSERROR_OK) { - ret = messages_add_from_file(messages); - } - } - return ret; -} /** - * Main entry point from OS. + * GTK specific initialisation */ -int main(int argc, char** argv) +static nserror nsgtk_init(int *pargc, char ***pargv, char **cache_home) { - char *cache_home = NULL; nserror ret; - struct netsurf_table nsgtk_table = { - .misc = &nsgtk_misc_table, - .window = nsgtk_window_table, - .clipboard = nsgtk_clipboard_table, - .download = nsgtk_download_table, - .fetch = nsgtk_fetch_table, - .llcache = filesystem_llcache_table, - .search = nsgtk_search_table, - .search_web = nsgtk_search_web_table, - .bitmap = nsgtk_bitmap_table, - .layout = nsgtk_layout_table, - }; - - ret = netsurf_register(&nsgtk_table); - if (ret != NSERROR_OK) { - die("NetSurf operation table failed registration\n"); - } /* Locate the correct user configuration directory path */ ret = get_config_home(&nsgtk_config_home); @@ -1139,12 +777,12 @@ int main(int argc, char** argv) } /* Initialise gtk */ - gtk_init(&argc, &argv); + gtk_init(pargc, pargv); /* initialise logging. Not fatal if it fails but not much we * can do about it either. */ - nslog_init(nslog_stream_configure, &argc, argv); + nslog_init(nslog_stream_configure, pargc, *pargv); /* build the common resource path list */ respaths = nsgtk_init_resource_path(nsgtk_config_home); @@ -1158,15 +796,15 @@ int main(int argc, char** argv) if (ret != NSERROR_OK) { fprintf(stderr, "GTK resources failed to initialise (%s)\n", messages_get_errorcode(ret)); - return 1; + return ret; } /* Initialise user options */ - ret = nsgtk_option_init(&argc, argv); + ret = nsgtk_option_init(pargc, *pargv); if (ret != NSERROR_OK) { fprintf(stderr, "Options failed to initialise (%s)\n", messages_get_errorcode(ret)); - return 1; + return ret; } /* Initialise translated messages */ @@ -1177,35 +815,353 @@ int main(int argc, char** argv) NSLOG(netsurf, INFO, "Unable to load translated messages"); /** \todo decide if message load faliure should be fatal */ } - + /* Locate the correct user cache directory path */ - ret = get_cache_home(&cache_home); + ret = get_cache_home(cache_home); if (ret == NSERROR_NOT_FOUND) { /* no cache directory exists yet so try to create one */ - ret = create_cache_home(&cache_home); + ret = create_cache_home(cache_home); } if (ret != NSERROR_OK) { NSLOG(netsurf, INFO, "Unable to locate a cache directory."); } - /* core initialisation */ - ret = netsurf_init(cache_home); - free(cache_home); - if (ret != NSERROR_OK) { - fprintf(stderr, "NetSurf core failed to initialise (%s)\n", - messages_get_errorcode(ret)); - return 1; + + return NSERROR_OK; +} + + +#if GTK_CHECK_VERSION(3,14,0) + +/** + * adds named icons into gtk theme + */ +static nserror nsgtk_add_named_icons_to_theme(void) +{ + gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(), + "/org/netsurf/icons"); + return NSERROR_OK; +} + +#else + +static nserror +add_builtin_icon(const char *prefix, const char *name, int x, int y) +{ + GdkPixbuf *pixbuf; + nserror res; + char *resname; + int resnamelen; + + /* resource name string length allowing for / .png and termination */ + resnamelen = strlen(prefix) + strlen(name) + 5 + 1 + 4 + 1; + resname = malloc(resnamelen); + if (resname == NULL) { + return NSERROR_NOMEM; } + snprintf(resname, resnamelen, "icons%s/%s.png", prefix, name); - /* gtk specific initalisation and main run loop */ - ret = nsgtk_init(argc, argv, respaths); - if (ret != NSERROR_OK) { - fprintf(stderr, "NetSurf gtk initialise failed (%s)\n", - messages_get_errorcode(ret)); + res = nsgdk_pixbuf_new_from_resname(resname, &pixbuf); + NSLOG(netsurf, DEEPDEBUG, "%d %s", res, resname); + free(resname); + if (res != NSERROR_OK) { + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, x, y); + } + gtk_icon_theme_add_builtin_icon(name, y, pixbuf); + + return NSERROR_OK; +} + + +/** + * adds named icons into gtk theme + */ +static nserror nsgtk_add_named_icons_to_theme(void) +{ + /* these must also be in gtk/resources.c pixbuf_resource *and* + * gtk/res/netsurf.gresource.xml + */ + add_builtin_icon("", "local-history", 8, 32); + add_builtin_icon("", "show-cookie", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-insecure", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-internal", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-local", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-secure", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-warning", 24, 24); + add_builtin_icon("/48x48/actions", "page-info-insecure", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-internal", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-local", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-secure", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-warning", 48, 48); + + return NSERROR_OK; +} + +#endif + + +/** + * setup GTK specific parts of the browser. + * + * \param argc The number of arguments on the command line + * \param argv A string vector of command line arguments. + * \respath A string vector of the path elements of resources + */ +static nserror nsgtk_setup(int argc, char** argv, char **respath) +{ + char buf[PATH_MAX]; + char *resource_filename; + char *addr = NULL; + nsurl *url; + nserror res; + + /* Initialise gtk accelerator table */ + res = nsgtk_accelerator_init(respaths); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Unable to load gtk accelerator configuration"); + /* not fatal if this does not load */ + } + + /* initialise warning dialog */ + res = nsgtk_builder_new_from_resname("warning", &warning_builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise warning dialog"); + return res; + } + + gtk_builder_connect_signals(warning_builder, NULL); + + /* set default icon if its available */ + res = nsgdk_pixbuf_new_from_resname("netsurf.xpm", + &win_default_icon_pixbuf); + if (res == NSERROR_OK) { + NSLOG(netsurf, INFO, "Seting default window icon"); + gtk_window_set_default_icon(win_default_icon_pixbuf); + } + + /* Search engine sources */ + resource_filename = filepath_find(respath, "SearchEngines"); + search_web_init(resource_filename); + if (resource_filename != NULL) { + NSLOG(netsurf, INFO, "Using '%s' as Search Engines file", + resource_filename); + free(resource_filename); + } + search_web_select_provider(nsoption_int(search_provider)); + + /* Default favicon */ + res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf); + if (res != NSERROR_OK) { + favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, + false, 8, 16, 16); + } + + /* add named icons to gtk theme */ + res = nsgtk_add_named_icons_to_theme(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to add named icons to GTK theme."); + return res; + } + + /* initialise throbber */ + res = nsgtk_throbber_init(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise throbber."); + return res; + } + + /* Initialise completions - cannot fail */ + nsgtk_completion_init(); + + /* The tree view system needs to know the screen's DPI, so we + * find that out here, rather than when we create a first browser + * window. + */ + browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default())); + NSLOG(netsurf, INFO, "Set CSS DPI to %d", browser_get_dpi()); + + bitmap_set_format(&(bitmap_fmt_t) { + .layout = BITMAP_LAYOUT_ARGB8888, + .pma = true, + }); + + filepath_sfinddef(respath, buf, "mime.types", "/etc/"); + gtk_fetch_filetype_init(buf); + + save_complete_init(); + + urldb_load(nsoption_charp(url_file)); + urldb_load_cookies(nsoption_charp(cookie_file)); + hotlist_init(nsoption_charp(hotlist_path), + nsoption_charp(hotlist_path)); + + /* Initialise top level UI elements */ + res = nsgtk_download_init(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise download window."); + return res; + } + + /* If there is a url specified on the command line use it */ + if (argc > 1) { + struct stat fs; + if (stat(argv[1], &fs) == 0) { + size_t addrlen; + char *rp = realpath(argv[1], NULL); + assert(rp != NULL); + + /* calculate file url length including terminator */ + addrlen = SLEN("file://") + strlen(rp) + 1; + addr = malloc(addrlen); + assert(addr != NULL); + snprintf(addr, addrlen, "file://%s", rp); + free(rp); + } else { + addr = strdup(argv[1]); + } + } + if (addr != NULL) { + /* managed to set up based on local launch */ + } else if (nsoption_charp(homepage_url) != NULL) { + addr = strdup(nsoption_charp(homepage_url)); } else { - nsgtk_main(); + addr = strdup(NETSURF_HOMEPAGE); + } + + /* create an initial browser window */ + res = nsurl_create(addr, &url); + if (res == NSERROR_OK) { + res = browser_window_create(BW_CREATE_HISTORY, + url, + NULL, + NULL, + NULL); + nsurl_unref(url); + } + + free(addr); + + return res; +} + + +/** + * Run the gtk event loop. + * + * The same as the standard gtk_main loop except this ensures active + * FD are added to the gtk poll event set. + */ +static void nsgtk_main(void) +{ + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd; + GPollFD *fd_list[1000]; + unsigned int fd_count; + + while (!nsgtk_complete) { + max_fd = -1; + fd_count = 0; + FD_ZERO(&read_fd_set); + FD_ZERO(&write_fd_set); + FD_ZERO(&exc_fd_set); + + while (gtk_events_pending()) + gtk_main_iteration_do(TRUE); + + schedule_run(); + + fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, &read_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &write_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_OUT | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &exc_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + } + + gtk_main_iteration(); + + for (unsigned int i = 0; i != fd_count; i++) { + g_main_context_remove_poll(0, fd_list[i]); + free(fd_list[i]); + } + } +} + + +/** + * finalise the browser + */ +static void nsgtk_finalise(void) +{ + nserror res; + + NSLOG(netsurf, INFO, "Quitting GUI"); + + /* Ensure all scaffoldings are destroyed before we go into exit */ + nsgtk_download_destroy(); + urldb_save_cookies(nsoption_charp(cookie_jar)); + urldb_save(nsoption_charp(url_file)); + + res = nsgtk_cookies_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising cookie viewer: %s", + messages_get_errorcode(res)); + } + + res = nsgtk_local_history_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Error finalising local history viewer: %s", + messages_get_errorcode(res)); } + res = nsgtk_global_history_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Error finalising global history viewer: %s", + messages_get_errorcode(res)); + } + + res = nsgtk_hotlist_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising hotlist viewer: %s", + messages_get_errorcode(res)); + } + + res = hotlist_fini(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising hotlist: %s", + messages_get_errorcode(res)); + } + + res = save_complete_finalise(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising save complete: %s", + messages_get_errorcode(res)); + } + + free(nsgtk_config_home); + + gtk_fetch_filetype_fin(); + /* common finalisation */ netsurf_exit(); @@ -1215,5 +1171,66 @@ int main(int argc, char** argv) /* finalise logging */ nslog_finalise(); +} + + +/** + * Main entry point from OS. + */ +int main(int argc, char** argv) +{ + nserror res; + char *cache_home = NULL; + struct netsurf_table nsgtk_table = { + .misc = nsgtk_misc_table, + .window = nsgtk_window_table, + .clipboard = nsgtk_clipboard_table, + .download = nsgtk_download_table, + .fetch = nsgtk_fetch_table, + .llcache = filesystem_llcache_table, + .search = nsgtk_search_table, + .search_web = nsgtk_search_web_table, + .bitmap = nsgtk_bitmap_table, + .layout = nsgtk_layout_table, + }; + + res = netsurf_register(&nsgtk_table); + if (res != NSERROR_OK) { + fprintf(stderr, + "NetSurf operation table failed registration (%s)\n", + messages_get_errorcode(res)); + return 1; + } + + /* gtk specific initialisation */ + res = nsgtk_init(&argc, &argv, &cache_home); + if (res != NSERROR_OK) { + fprintf(stderr, "NetSurf gtk failed to initialise (%s)\n", + messages_get_errorcode(res)); + return 2; + } + + /* core initialisation */ + res = netsurf_init(cache_home); + free(cache_home); + if (res != NSERROR_OK) { + fprintf(stderr, "NetSurf core failed to initialise (%s)\n", + messages_get_errorcode(res)); + return 3; + } + + /* gtk specific initalisation and main run loop */ + res = nsgtk_setup(argc, argv, respaths); + if (res != NSERROR_OK) { + nsgtk_finalise(); + fprintf(stderr, "NetSurf gtk setup failed (%s)\n", + messages_get_errorcode(res)); + return 4; + } + + nsgtk_main(); + + nsgtk_finalise(); + return 0; } diff --git a/frontends/gtk/gui.h b/frontends/gtk/gui.h index 53e732437..ee82e7a6f 100644 --- a/frontends/gtk/gui.h +++ b/frontends/gtk/gui.h @@ -27,9 +27,6 @@ extern char *nsgtk_config_home; /** favicon default pixbuf */ extern GdkPixbuf *favicon_pixbuf; -/** arrow down pixbuf */ -extern GdkPixbuf *arrow_down_pixbuf; - /** resource search path vector */ extern char **respaths; diff --git a/frontends/gtk/hotlist.c b/frontends/gtk/hotlist.c index 843e47736..b047dc65f 100644 --- a/frontends/gtk/hotlist.c +++ b/frontends/gtk/hotlist.c @@ -170,6 +170,8 @@ MENUHANDLER(delete_selected) MENUHANDLER(select_all) { + hotlist_keypress(NS_KEY_ESCAPE); + hotlist_keypress(NS_KEY_ESCAPE); hotlist_keypress(NS_KEY_SELECT_ALL); return TRUE; } diff --git a/frontends/gtk/layout_pango.c b/frontends/gtk/layout_pango.c index a5964eb37..9e8e94d48 100644 --- a/frontends/gtk/layout_pango.c +++ b/frontends/gtk/layout_pango.c @@ -277,7 +277,7 @@ nsfont_style_to_description(const plot_font_style_t *fstyle) break; } - size = (fstyle->size * PANGO_SCALE) / FONT_SIZE_SCALE; + size = (fstyle->size * PANGO_SCALE) / PLOT_STYLE_SCALE; if (fstyle->flags & FONTF_ITALIC) style = PANGO_STYLE_ITALIC; diff --git a/frontends/gtk/local_history.c b/frontends/gtk/local_history.c index 35b7a4ad6..0d59c468a 100644 --- a/frontends/gtk/local_history.c +++ b/frontends/gtk/local_history.c @@ -35,6 +35,7 @@ #include "gtk/resources.h" #include "gtk/corewindow.h" #include "gtk/local_history.h" +#include "gtk/scaffolding.h" struct nsgtk_local_history_window { struct nsgtk_corewindow core; @@ -158,6 +159,12 @@ nsgtk_local_history_init(struct browser_window *bw, ncwin->wnd = GTK_WINDOW(gtk_builder_get_object(ncwin->builder, "wndHistory")); + /* Configure for transient behaviour */ + gtk_window_set_type_hint(GTK_WINDOW(ncwin->wnd), + GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU); + gtk_window_set_modal(GTK_WINDOW(ncwin->wnd), TRUE); + + ncwin->core.scrolled = GTK_SCROLLED_WINDOW( gtk_builder_get_object(ncwin->builder, "HistoryScrolled")); @@ -171,6 +178,16 @@ nsgtk_local_history_init(struct browser_window *bw, "delete_event", G_CALLBACK(gtk_widget_hide_on_delete), NULL); + /* Ditto if we lose the grab */ + g_signal_connect(G_OBJECT(ncwin->wnd), + "grab-broken-event", + G_CALLBACK(gtk_widget_hide_on_delete), + ncwin); + /* Handle button press events */ + g_signal_connect(G_OBJECT(ncwin->wnd), + "button-press-event", + G_CALLBACK(gtk_widget_hide_on_delete), + ncwin); ncwin->core.draw = nsgtk_local_history_draw; ncwin->core.key = nsgtk_local_history_key; @@ -206,7 +223,11 @@ nserror nsgtk_local_history_present(GtkWindow *parent, int width, height; res = nsgtk_local_history_init(bw, &local_history_window); if (res == NSERROR_OK) { + gtk_window_group_add_window(gtk_window_get_group(parent), + local_history_window->wnd); gtk_window_set_transient_for(local_history_window->wnd, parent); + gtk_window_set_screen(local_history_window->wnd, + gtk_widget_get_screen(GTK_WIDGET(parent))); gtk_window_get_size(parent, &prnt_width, &prnt_height); @@ -224,7 +245,13 @@ nserror nsgtk_local_history_present(GtkWindow *parent, } gtk_window_resize(local_history_window->wnd, width, height); - gtk_window_present(local_history_window->wnd); + /* Attempt to place the window in the right place */ + nsgtk_scaffolding_position_local_history(nsgtk_current_scaffolding()); + + gtk_widget_show(GTK_WIDGET(local_history_window->wnd)); + gtk_widget_grab_focus(GTK_WIDGET(local_history_window->wnd)); + + local_history_scroll_to_cursor(local_history_window->session); } return res; @@ -267,3 +294,11 @@ nserror nsgtk_local_history_destroy(void) return res; } + +/* exported function documented gtk/history.h */ +void nsgtk_local_history_set_position(int x, int y) +{ + NSLOG(netsurf, INFO, "x=%d y=%d", x, y); + + gtk_window_move(local_history_window->wnd, x, y); +} diff --git a/frontends/gtk/local_history.h b/frontends/gtk/local_history.h index 605405ddf..c5b447194 100644 --- a/frontends/gtk/local_history.h +++ b/frontends/gtk/local_history.h @@ -34,6 +34,11 @@ struct browser_window; nserror nsgtk_local_history_present(GtkWindow *parent, struct browser_window *bw); /** + * set the local history window position. + */ +void nsgtk_local_history_set_position(int x, int y); + +/** * hide the local history window from being visible. * * \return NSERROR_OK on success else appropriate error code on faliure. diff --git a/frontends/gtk/login.c b/frontends/gtk/login.c deleted file mode 100644 index 91d8b37f0..000000000 --- a/frontends/gtk/login.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick <rjek@rjek.com> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <string.h> -#include <gtk/gtk.h> - -#include "utils/log.h" -#include "utils/nsurl.h" -#include "netsurf/url_db.h" - -#include "gtk/resources.h" -#include "gtk/login.h" - -/** login window session data */ -struct session_401 { - nsurl *url; /**< URL being fetched */ - lwc_string *host; /**< Host for user display */ - char *realm; /**< Authentication realm */ - nserror (*cb)(bool proceed, void *pw); /**< Continuation callback */ - void *cbpw; /**< Continuation data */ - GtkBuilder *x; /**< Our builder windows */ - GtkWindow *wnd; /**< The login window itself */ - GtkEntry *user; /**< Widget with username */ - GtkEntry *pass; /**< Widget with password */ -}; - -/** - * Destroy login window and free all associated resources - * - * \param session The login window session to destroy. - */ -static void destroy_login_window(struct session_401 *session) -{ - nsurl_unref(session->url); - lwc_string_unref(session->host); - free(session->realm); - gtk_widget_destroy(GTK_WIDGET(session->wnd)); - g_object_unref(G_OBJECT(session->x)); - free(session); -} - - -/** - * process next signal in entry widgets. - * - * \param w current widget - * \param data next widget - */ -static void nsgtk_login_next(GtkWidget *w, gpointer data) -{ - gtk_widget_grab_focus(GTK_WIDGET(data)); -} - - -/** - * handler called when navigation is continued - * - * \param w current widget - * \param data login window session - */ -static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data) -{ - /* close the window and destroy it, having continued the fetch - * assoicated with it. - */ - - struct session_401 *session = (struct session_401 *)data; - const gchar *user = gtk_entry_get_text(session->user); - const gchar *pass = gtk_entry_get_text(session->pass); - char *auth; - - auth = malloc(strlen(user) + strlen(pass) + 2); - sprintf(auth, "%s:%s", user, pass); - urldb_set_auth_details(session->url, session->realm, auth); - free(auth); - - session->cb(true, session->cbpw); - - destroy_login_window(session); -} - - -/** - * handler called when navigation is cancelled - * - * \param w widget - * \param data login window session - */ -static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data) -{ - struct session_401 *session = (struct session_401 *) data; - - session->cb(false, session->cbpw); - - /* close and destroy the window */ - destroy_login_window(session); -} - - -/** - * create a new instance of the login window - * - * creates login window and handles to all the widgets we're - * interested in. - * - * \param url The url causing the login. - * \param host the host being logged into - * \param realm realmm the login relates to - * \param cb callback when complete - * \param cbpw data to pass to callback - * \return NSERROR_OK on sucessful window creation or error code on faliure. - */ -static nserror -create_login_window(nsurl *url, - lwc_string *host, - const char *realm, - nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - struct session_401 *session; - GtkWindow *wnd; - GtkLabel *lhost, *lrealm; - GtkEntry *euser, *epass; - GtkButton *bok, *bcan; - GtkBuilder* builder; - nserror res; - - session = calloc(1, sizeof(struct session_401)); - if (session == NULL) { - return NSERROR_NOMEM; - } - - res = nsgtk_builder_new_from_resname("login", &builder); - if (res != NSERROR_OK) { - free(session); - return res; - } - - gtk_builder_connect_signals(builder, NULL); - - wnd = GTK_WINDOW(gtk_builder_get_object(builder, "wndLogin")); - lhost = GTK_LABEL(gtk_builder_get_object(builder, "labelLoginHost")); - lrealm = GTK_LABEL(gtk_builder_get_object(builder, "labelLoginRealm")); - euser = GTK_ENTRY(gtk_builder_get_object(builder, "entryLoginUser")); - epass = GTK_ENTRY(gtk_builder_get_object(builder, "entryLoginPass")); - bok = GTK_BUTTON(gtk_builder_get_object(builder, "buttonLoginOK")); - bcan = GTK_BUTTON(gtk_builder_get_object(builder, "buttonLoginCan")); - - /* create and fill in our session structure */ - session->url = nsurl_ref(url); - session->host = lwc_string_ref(host); - session->realm = strdup(realm ? realm : "Secure Area"); - session->cb = cb; - session->cbpw = cbpw; - session->x = builder; - session->wnd = wnd; - session->user = euser; - session->pass = epass; - - /* fill in our new login window */ - - gtk_label_set_text(GTK_LABEL(lhost), lwc_string_data(host)); - gtk_label_set_text(lrealm, realm); - gtk_entry_set_text(euser, ""); - gtk_entry_set_text(epass, ""); - - /* attach signal handlers to the Login and Cancel buttons in our new - * window to call functions in this file to process the login - */ - g_signal_connect(G_OBJECT(bok), "clicked", - G_CALLBACK(nsgtk_login_ok_clicked), (gpointer)session); - g_signal_connect(G_OBJECT(bcan), "clicked", - G_CALLBACK(nsgtk_login_cancel_clicked), - (gpointer)session); - - /* attach signal handlers to the entry boxes such that pressing - * enter in one progresses the focus onto the next widget. - */ - - g_signal_connect(G_OBJECT(euser), "activate", - G_CALLBACK(nsgtk_login_next), (gpointer)epass); - g_signal_connect(G_OBJECT(epass), "activate", - G_CALLBACK(nsgtk_login_next), (gpointer)bok); - - /* make sure the username entry box currently has the focus */ - gtk_widget_grab_focus(GTK_WIDGET(euser)); - - /* finally, show the window */ - gtk_widget_show(GTK_WIDGET(wnd)); - - return NSERROR_OK; -} - - -/* exported function documented in gtk/login.h */ -void gui_401login_open(nsurl *url, - const char *realm, - nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - lwc_string *host; - nserror res; - - host = nsurl_get_component(url, NSURL_HOST); - assert(host != NULL); - - res = create_login_window(url, host, realm, cb, cbpw); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Login init failed"); - - /* creating login failed so cancel navigation */ - cb(false, cbpw); - } - - lwc_string_unref(host); -} diff --git a/frontends/gtk/menu.c b/frontends/gtk/menu.c index 6a6033231..03056d2a8 100644 --- a/frontends/gtk/menu.c +++ b/frontends/gtk/menu.c @@ -49,12 +49,12 @@ nsgtk_menu_add_image_item(GtkMenu *menu, GdkModifierType mod; GtkWidget *item; const char *accelerator_desc; /* accelerator key description */ - + item = nsgtk_image_menu_item_new_with_mnemonic(messages_get(message)); if (item == NULL) { return false; } - + accelerator_desc = nsgtk_accelerator_get_desc(message); if (accelerator_desc != NULL) { gtk_accelerator_parse(accelerator_desc, &key, &mod); @@ -85,15 +85,17 @@ nsgtk_menu_add_image_item(GtkMenu *menu, #define IMAGE_ITEM(p, q, r, s, t)\ nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r, t) -#define CHECK_ITEM(p, q, r, s)\ - s->q##_menuitem = GTK_CHECK_MENU_ITEM(\ +#define CHECK_ITEM(p, q, r, s) \ + do { \ + s->q##_menuitem = GTK_CHECK_MENU_ITEM( \ gtk_check_menu_item_new_with_mnemonic(\ messages_get(#r)));\ - if ((s->q##_menuitem != NULL) && (s->p##_menu != NULL)) {\ - gtk_menu_shell_append(GTK_MENU_SHELL(s->p##_menu),\ - GTK_WIDGET(s->q##_menuitem));\ - gtk_widget_show(GTK_WIDGET(s->q##_menuitem));\ - } + if ((s->q##_menuitem != NULL) && (s->p##_menu != NULL)) { \ + gtk_menu_shell_append(GTK_MENU_SHELL(s->p##_menu), \ + GTK_WIDGET(s->q##_menuitem)); \ + gtk_widget_show(GTK_WIDGET(s->q##_menuitem)); \ + } \ + } while(0) #define SET_SUBMENU(q, r) \ do { \ @@ -142,21 +144,23 @@ nsgtk_menu_add_image_item(GtkMenu *menu, static struct nsgtk_export_submenu * nsgtk_menu_export_submenu(GtkAccelGroup *group) { - struct nsgtk_export_submenu *ret = malloc(sizeof(struct - nsgtk_export_submenu)); + struct nsgtk_export_submenu *ret; + ret = malloc(sizeof(struct nsgtk_export_submenu)); + if (ret == NULL) { nsgtk_warning(messages_get("NoMemory"), 0); return NULL; } + ret->export_menu = GTK_MENU(gtk_menu_new()); if (ret->export_menu == NULL) { nsgtk_warning(messages_get("NoMemory"), 0); free(ret); return NULL; } + + IMAGE_ITEM(export, savepage, gtkSavePage, ret, group); IMAGE_ITEM(export, plaintext, gtkPlainText, ret, group); - IMAGE_ITEM(export, drawfile, gtkDrawFile, ret, group); - IMAGE_ITEM(export, postscript, gtkPostScript, ret, group); IMAGE_ITEM(export, pdf, gtkPDF, ret, group); return ret; } @@ -213,57 +217,45 @@ static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group) return ret; } -/** -* creates an images submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ -static struct nsgtk_images_submenu *nsgtk_menu_images_submenu(GtkAccelGroup *group) +/** + * creates a toolbars submenu + * + * \param group the 'global' in a gtk sense accelerator reference + */ +static struct nsgtk_toolbars_submenu * +nsgtk_menu_toolbars_submenu(GtkAccelGroup *group) { - struct nsgtk_images_submenu *ret = - malloc(sizeof(struct nsgtk_images_submenu)); - if (ret == NULL) { + struct nsgtk_toolbars_submenu *tmenu; + + tmenu = malloc(sizeof(struct nsgtk_toolbars_submenu)); + if (tmenu == NULL) { nsgtk_warning(messages_get("NoMemory"), 0); return NULL; } - ret->images_menu = GTK_MENU(gtk_menu_new()); - if (ret->images_menu == NULL) { + + tmenu->toolbars_menu = GTK_MENU(gtk_menu_new()); + if (tmenu->toolbars_menu == NULL) { nsgtk_warning(messages_get("NoMemory"), 0); - free(ret); + free(tmenu); return NULL; } - CHECK_ITEM(images, foregroundimages, gtkForegroundImages, ret) - CHECK_ITEM(images, backgroundimages, gtkBackgroundImages, ret) - return ret; -} - -/** -* creates a toolbars submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ -static struct nsgtk_toolbars_submenu *nsgtk_menu_toolbars_submenu( - GtkAccelGroup *group) -{ - struct nsgtk_toolbars_submenu *ret = - malloc(sizeof(struct nsgtk_toolbars_submenu)); - if (ret == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - return NULL; + CHECK_ITEM(toolbars, menubar, gtkMenuBar, tmenu); + if (tmenu->menubar_menuitem != NULL) { + gtk_check_menu_item_set_active(tmenu->menubar_menuitem, TRUE); } - ret->toolbars_menu = GTK_MENU(gtk_menu_new()); - if (ret->toolbars_menu == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - free(ret); - return NULL; + + CHECK_ITEM(toolbars, toolbar, gtkToolBar, tmenu); + if (tmenu->toolbar_menuitem != NULL) { + gtk_check_menu_item_set_active(tmenu->toolbar_menuitem, TRUE); } - CHECK_ITEM(toolbars, menubar, gtkMenuBar, ret) - if (ret->menubar_menuitem != NULL) - gtk_check_menu_item_set_active(ret->menubar_menuitem, TRUE); - CHECK_ITEM(toolbars, toolbar, gtkToolBar, ret) - if (ret->toolbar_menuitem != NULL) - gtk_check_menu_item_set_active(ret->toolbar_menuitem, TRUE); - return ret; + + ADD_SEP(toolbars, tmenu); + + IMAGE_ITEM(toolbars, customize, gtkCustomize, tmenu, group); + + return tmenu; } /** @@ -271,8 +263,8 @@ static struct nsgtk_toolbars_submenu *nsgtk_menu_toolbars_submenu( * \param group the 'global' in a gtk sense accelerator reference */ -static struct nsgtk_developer_submenu *nsgtk_menu_developer_submenu( - GtkAccelGroup *group) +static struct nsgtk_developer_submenu * +nsgtk_menu_developer_submenu(GtkAccelGroup *group) { struct nsgtk_developer_submenu *dmenu = malloc(sizeof(struct nsgtk_developer_submenu)); @@ -323,7 +315,6 @@ static struct nsgtk_file_menu *nsgtk_menu_file_submenu(GtkAccelGroup *group) IMAGE_ITEM(file, openfile, gtkOpenFile, fmenu, group); IMAGE_ITEM(file, closewindow, gtkCloseWindow, fmenu, group); ADD_SEP(file, fmenu); - IMAGE_ITEM(file, savepage, gtkSavePage, fmenu, group); IMAGE_ITEM(file, export, gtkExport, fmenu, group); ADD_SEP(file, fmenu); IMAGE_ITEM(file, printpreview, gtkPrintPreview, fmenu, group); @@ -385,22 +376,16 @@ static struct nsgtk_view_menu *nsgtk_menu_view_submenu(GtkAccelGroup *group) free(ret); return NULL; } - IMAGE_ITEM(view, stop, gtkStop, ret, group); - IMAGE_ITEM(view, reload, gtkReload, ret, group); - ADD_SEP(view, ret); IMAGE_ITEM(view, scaleview, gtkScaleView, ret, group); + SET_SUBMENU(scaleview, ret); IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group); ADD_SEP(view, ret); - IMAGE_ITEM(view, images, gtkImages, ret, group); IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group); + SET_SUBMENU(toolbars, ret); IMAGE_ITEM(view, tabs, gtkTabs, ret, group); + SET_SUBMENU(tabs, ret); ADD_SEP(view, ret); IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group); - SET_SUBMENU(scaleview, ret); - SET_SUBMENU(images, ret); - SET_SUBMENU(toolbars, ret); - SET_SUBMENU(tabs, ret); - return ret; } @@ -426,6 +411,8 @@ static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group) IMAGE_ITEM(nav, back, gtkBack, ret, group); IMAGE_ITEM(nav, forward, gtkForward, ret, group); + IMAGE_ITEM(nav, stop, gtkStop, ret, group); + IMAGE_ITEM(nav, reload, gtkReload, ret, group); IMAGE_ITEM(nav, home, gtkHome, ret, group); ADD_SEP(nav, ret); IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group); @@ -436,7 +423,6 @@ static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group) ADD_SEP(nav, ret); IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group); - return ret; } @@ -531,44 +517,61 @@ nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkAccelGroup *group) return nmenu; } + /* exported function documented in gtk/menu.h */ -struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group) +struct nsgtk_burger_menu *nsgtk_burger_menu_create(GtkAccelGroup *group) { - struct nsgtk_popup_menu *nmenu; + struct nsgtk_burger_menu *nmenu; - NEW_MENU(nmenu, popup); + NEW_MENU(nmenu, burger); - IMAGE_ITEM(popup, file, gtkFile, nmenu, group); + IMAGE_ITEM(burger, file, gtkFile, nmenu, group); SET_SUBMENU(file, nmenu); - IMAGE_ITEM(popup, edit, gtkEdit, nmenu, group); + IMAGE_ITEM(burger, edit, gtkEdit, nmenu, group); SET_SUBMENU(edit, nmenu); - IMAGE_ITEM(popup, view, gtkView, nmenu, group); + IMAGE_ITEM(burger, view, gtkView, nmenu, group); SET_SUBMENU(view, nmenu); - IMAGE_ITEM(popup, nav, gtkNavigate, nmenu, group); + IMAGE_ITEM(burger, nav, gtkNavigate, nmenu, group); SET_SUBMENU(nav, nmenu); - IMAGE_ITEM(popup, tools, gtkTools, nmenu, group); + IMAGE_ITEM(burger, tools, gtkTools, nmenu, group); SET_SUBMENU(tools, nmenu); - IMAGE_ITEM(popup, help, gtkHelp, nmenu, group); + IMAGE_ITEM(burger, help, gtkHelp, nmenu, group); SET_SUBMENU(help, nmenu); - ADD_NAMED_SEP(popup, first, nmenu); + return nmenu; +} - IMAGE_ITEM(popup, back, gtkBack, nmenu, group); - IMAGE_ITEM(popup, forward, gtkForward, nmenu, group); - ADD_NAMED_SEP(popup, third, nmenu); +/* exported function documented in gtk/menu.h */ +struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group) +{ + struct nsgtk_popup_menu *nmenu; + + NEW_MENU(nmenu, popup); + IMAGE_ITEM(popup, back, gtkBack, nmenu, group); + IMAGE_ITEM(popup, forward, gtkForward, nmenu, group); IMAGE_ITEM(popup, stop, gtkStop, nmenu, group); IMAGE_ITEM(popup, reload, gtkReload, nmenu, group); + + ADD_NAMED_SEP(popup, first, nmenu); + IMAGE_ITEM(popup, cut, gtkCut, nmenu, group); IMAGE_ITEM(popup, copy, gtkCopy, nmenu, group); IMAGE_ITEM(popup, paste, gtkPaste, nmenu, group); - IMAGE_ITEM(popup, customize, gtkCustomize, nmenu, group); + + ADD_NAMED_SEP(popup, second, nmenu); + + IMAGE_ITEM(popup, toolbars, gtkToolbars, nmenu, group); + SET_SUBMENU(toolbars, nmenu); + + IMAGE_ITEM(popup, tools, gtkTools, nmenu, group); + SET_SUBMENU(tools, nmenu); return nmenu; } @@ -593,3 +596,71 @@ nsgtk_link_menu_create(GtkAccelGroup *group) return nmenu; } + + +/* exported function documented in gtk/menu.h */ +nserror nsgtk_menu_bar_destroy(struct nsgtk_bar_submenu *menu) +{ + gtk_widget_destroy(GTK_WIDGET(menu->bar_menu)); + + free(menu->file_submenu->export_submenu); + free(menu->file_submenu); + free(menu->edit_submenu); + free(menu->view_submenu->tabs_submenu); + free(menu->view_submenu->toolbars_submenu); + free(menu->view_submenu->scaleview_submenu); + free(menu->view_submenu); + free(menu->nav_submenu); + free(menu->tools_submenu->developer_submenu); + free(menu->tools_submenu); + free(menu->help_submenu); + free(menu); + + return NSERROR_OK; +} + +/* exported function documented in gtk/menu.h */ +nserror nsgtk_burger_menu_destroy(struct nsgtk_burger_menu *menu) +{ + gtk_widget_destroy(GTK_WIDGET(menu->burger_menu)); + + free(menu->file_submenu->export_submenu); + free(menu->file_submenu); + free(menu->edit_submenu); + free(menu->view_submenu->tabs_submenu); + free(menu->view_submenu->toolbars_submenu); + free(menu->view_submenu->scaleview_submenu); + free(menu->view_submenu); + free(menu->nav_submenu); + free(menu->tools_submenu->developer_submenu); + free(menu->tools_submenu); + free(menu->help_submenu); + free(menu); + + return NSERROR_OK; +} + + +/* exported function documented in gtk/menu.h */ +nserror nsgtk_popup_menu_destroy(struct nsgtk_popup_menu *menu) +{ + gtk_widget_destroy(GTK_WIDGET(menu->popup_menu)); + + free(menu->toolbars_submenu); + free(menu->tools_submenu->developer_submenu); + free(menu->tools_submenu); + free(menu); + + return NSERROR_OK; +} + + +/* exported function documented in gtk/menu.h */ +nserror nsgtk_link_menu_destroy(struct nsgtk_link_menu *menu) +{ + gtk_widget_destroy(GTK_WIDGET(menu->link_menu)); + + free(menu); + + return NSERROR_OK; +} diff --git a/frontends/gtk/menu.h b/frontends/gtk/menu.h index 5da5cb1b2..cf63b334a 100644 --- a/frontends/gtk/menu.h +++ b/frontends/gtk/menu.h @@ -15,66 +15,68 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_GTK_MENU_H_ -#define _NETSURF_GTK_MENU_H_ +#ifndef NETSURF_GTK_MENU_H_ +#define NETSURF_GTK_MENU_H_ #include <gtk/gtk.h> +/** + * File menu item on menubar + */ struct nsgtk_file_menu { - GtkMenuItem *file; /* File menu item on menubar */ - GtkMenu *file_menu; - GtkWidget *newwindow_menuitem; - GtkWidget *newtab_menuitem; - GtkWidget *openfile_menuitem; - GtkWidget *closewindow_menuitem; - GtkWidget *savepage_menuitem; - GtkWidget *export_menuitem; - struct nsgtk_export_submenu *export_submenu; - GtkWidget *printpreview_menuitem; - GtkWidget *print_menuitem; - GtkWidget *quit_menuitem; + GtkMenuItem *file; + GtkMenu *file_menu; + GtkWidget *newwindow_menuitem; + GtkWidget *newtab_menuitem; + GtkWidget *openfile_menuitem; + GtkWidget *closewindow_menuitem; + GtkWidget *export_menuitem; + struct nsgtk_export_submenu *export_submenu; + GtkWidget *printpreview_menuitem; + GtkWidget *print_menuitem; + GtkWidget *quit_menuitem; }; struct nsgtk_edit_menu { - GtkMenuItem *edit; /* Edit menu item on menubar */ - GtkMenu *edit_menu; - GtkWidget *cut_menuitem; - GtkWidget *copy_menuitem; - GtkWidget *paste_menuitem; - GtkWidget *delete_menuitem; - GtkWidget *selectall_menuitem; - GtkWidget *find_menuitem; - GtkWidget *preferences_menuitem; + GtkMenuItem *edit; /* Edit menu item on menubar */ + GtkMenu *edit_menu; + GtkWidget *cut_menuitem; + GtkWidget *copy_menuitem; + GtkWidget *paste_menuitem; + GtkWidget *delete_menuitem; + GtkWidget *selectall_menuitem; + GtkWidget *find_menuitem; + GtkWidget *preferences_menuitem; }; struct nsgtk_view_menu { - GtkMenuItem *view; /* View menu item on menubar */ - GtkMenu *view_menu; /* gtk menu attached to menu item */ - GtkWidget *stop_menuitem; - GtkWidget *reload_menuitem; - GtkWidget *scaleview_menuitem; + GtkMenuItem *view; /* View menu item on menubar */ + GtkMenu *view_menu; /* gtk menu attached to menu item */ + + GtkWidget *scaleview_menuitem; struct nsgtk_scaleview_submenu *scaleview_submenu; - GtkWidget *fullscreen_menuitem; - GtkWidget *images_menuitem; - struct nsgtk_images_submenu *images_submenu; - GtkWidget *toolbars_menuitem; - struct nsgtk_toolbars_submenu *toolbars_submenu; - GtkWidget *tabs_menuitem; - struct nsgtk_tabs_submenu *tabs_submenu; - GtkWidget *savewindowsize_menuitem; + GtkWidget *fullscreen_menuitem; + GtkWidget *toolbars_menuitem; + struct nsgtk_toolbars_submenu *toolbars_submenu; + GtkWidget *tabs_menuitem; + struct nsgtk_tabs_submenu *tabs_submenu; + GtkWidget *savewindowsize_menuitem; }; struct nsgtk_nav_menu { - GtkMenuItem *nav; /* Nav menu item on menubar */ - GtkMenu *nav_menu; - GtkWidget *back_menuitem; - GtkWidget *forward_menuitem; - GtkWidget *home_menuitem; - GtkWidget *localhistory_menuitem; - GtkWidget *globalhistory_menuitem; - GtkWidget *addbookmarks_menuitem; - GtkWidget *showbookmarks_menuitem; - GtkWidget *openlocation_menuitem; + GtkMenuItem *nav; /* Nav menu item on menubar */ + GtkMenu *nav_menu; + + GtkWidget *back_menuitem; + GtkWidget *forward_menuitem; + GtkWidget *stop_menuitem; + GtkWidget *reload_menuitem; + GtkWidget *home_menuitem; + GtkWidget *localhistory_menuitem; + GtkWidget *globalhistory_menuitem; + GtkWidget *addbookmarks_menuitem; + GtkWidget *showbookmarks_menuitem; + GtkWidget *openlocation_menuitem; }; struct nsgtk_tools_menu { @@ -88,47 +90,41 @@ struct nsgtk_tools_menu { }; struct nsgtk_help_menu { - GtkMenuItem *help; /* Help menu item on menubar */ - GtkMenu *help_menu; - GtkWidget *contents_menuitem; - GtkWidget *guide_menuitem; - GtkWidget *info_menuitem; - GtkWidget *about_menuitem; + GtkMenuItem *help; /* Help menu item on menubar */ + GtkMenu *help_menu; + GtkWidget *contents_menuitem; + GtkWidget *guide_menuitem; + GtkWidget *info_menuitem; + GtkWidget *about_menuitem; }; struct nsgtk_export_submenu { - GtkMenu *export_menu; - GtkWidget *plaintext_menuitem; - GtkWidget *drawfile_menuitem; - GtkWidget *postscript_menuitem; - GtkWidget *pdf_menuitem; + GtkMenu *export_menu; + GtkWidget *savepage_menuitem; + GtkWidget *plaintext_menuitem; + GtkWidget *pdf_menuitem; }; struct nsgtk_scaleview_submenu { - GtkMenu *scaleview_menu; - GtkWidget *zoomplus_menuitem; - GtkWidget *zoomminus_menuitem; - GtkWidget *zoomnormal_menuitem; + GtkMenu *scaleview_menu; + GtkWidget *zoomplus_menuitem; + GtkWidget *zoomminus_menuitem; + GtkWidget *zoomnormal_menuitem; }; struct nsgtk_tabs_submenu { - GtkMenu *tabs_menu; - GtkWidget *nexttab_menuitem; - GtkWidget *prevtab_menuitem; - GtkWidget *closetab_menuitem; -}; - -struct nsgtk_images_submenu { - GtkMenu *images_menu; - GtkCheckMenuItem *foregroundimages_menuitem; - GtkCheckMenuItem *backgroundimages_menuitem; + GtkMenu *tabs_menu; + GtkWidget *nexttab_menuitem; + GtkWidget *prevtab_menuitem; + GtkWidget *closetab_menuitem; }; struct nsgtk_toolbars_submenu { - GtkMenu *toolbars_menu; - GtkCheckMenuItem *menubar_menuitem; - GtkCheckMenuItem *toolbar_menuitem; + GtkMenu *toolbars_menu; + GtkCheckMenuItem *menubar_menuitem; + GtkCheckMenuItem *toolbar_menuitem; + GtkWidget *customize_menuitem; }; struct nsgtk_developer_submenu { @@ -140,20 +136,21 @@ struct nsgtk_developer_submenu { GtkWidget *debugdomtree_menuitem; }; - +/** + * main menubar + */ struct nsgtk_bar_submenu { GtkMenuBar *bar_menu; struct nsgtk_file_menu *file_submenu; struct nsgtk_edit_menu *edit_submenu; struct nsgtk_view_menu *view_submenu; struct nsgtk_nav_menu *nav_submenu; - struct nsgtk_tabs_submenu *tabs_submenu; struct nsgtk_tools_menu *tools_submenu; struct nsgtk_help_menu *help_submenu; }; -struct nsgtk_popup_menu { - GtkMenu *popup_menu; +struct nsgtk_burger_menu { + GtkMenu *burger_menu; GtkWidget *file_menuitem; struct nsgtk_file_menu *file_submenu; @@ -167,32 +164,35 @@ struct nsgtk_popup_menu { GtkWidget *nav_menuitem; struct nsgtk_nav_menu *nav_submenu; - GtkWidget *tabs_menuitem; - struct nsgtk_tabs_submenu *tabs_submenu; - GtkWidget *tools_menuitem; struct nsgtk_tools_menu *tools_submenu; GtkWidget *help_menuitem; struct nsgtk_help_menu *help_submenu; +}; - GtkWidget *first_separator; +struct nsgtk_popup_menu { + GtkMenu *popup_menu; /* navigation entries */ GtkWidget *back_menuitem; GtkWidget *forward_menuitem; - - GtkWidget *third_separator; - - /* view entries */ GtkWidget *stop_menuitem; GtkWidget *reload_menuitem; + GtkWidget *first_separator; + + /* edit entries */ GtkWidget *cut_menuitem; GtkWidget *copy_menuitem; GtkWidget *paste_menuitem; - GtkWidget *customize_menuitem; + GtkWidget *second_separator; + + GtkWidget *toolbars_menuitem; + struct nsgtk_toolbars_submenu *toolbars_submenu; + GtkWidget *tools_menuitem; + struct nsgtk_tools_menu *tools_submenu; }; struct nsgtk_link_menu { @@ -206,22 +206,82 @@ struct nsgtk_link_menu { GtkWidget *copy_menuitem; }; + /** - * Create main menu bar. + * Create main menubar menu. */ struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkAccelGroup *group); + +/** + * Generate burger menu. + * + * \param accelerator group to use with menu + * \return new menu structure or NULL on error + */ +struct nsgtk_burger_menu *nsgtk_burger_menu_create(GtkAccelGroup *group); + + /** - * Generate right click menu menu. + * Generate right click popup menu. * + * \param accelerator group to use with menu + * \return new menu structure or NULL on error */ struct nsgtk_popup_menu *nsgtk_popup_menu_create(GtkAccelGroup *group); + /** - * Generate context sensitive popup menu for link. + * Generate context sensitive link popup menu. * + * \param accelerator group to use with menu + * \return new menu structure or NULL on error */ struct nsgtk_link_menu *nsgtk_link_menu_create(GtkAccelGroup *group); +/** + * destroy bar menu + * + * destroys the gtk widgets associated with menu and frees all storage. + * + * \param menu menu to destroy + * \return NSERROR_OK and menu destroyed on success else error code + */ +nserror nsgtk_menu_bar_destroy(struct nsgtk_bar_submenu *menu); + + +/** + * destroy burger menu + * + * destroys the gtk widgets associated with menu and frees all storage. + * + * \param menu menu to destroy + * \return NSERROR_OK and menu destroyed on success else error code + */ +nserror nsgtk_burger_menu_destroy(struct nsgtk_burger_menu *menu); + + +/** + * destroy popup menu + * + * destroys the gtk widgets associated with menu and frees all storage. + * + * \param menu menu to destroy + * \return NSERROR_OK and menu destroyed on success else error code + */ +nserror nsgtk_popup_menu_destroy(struct nsgtk_popup_menu *menu); + + +/** + * destroy link menu + * + * destroys the gtk widgets associated with menu and frees all storage. + * + * \param menu menu to destroy + * \return NSERROR_OK and menu destroyed on success else error code + */ +nserror nsgtk_link_menu_destroy(struct nsgtk_link_menu *menu); + + #endif diff --git a/frontends/gtk/misc.c b/frontends/gtk/misc.c new file mode 100644 index 000000000..8ab1d914c --- /dev/null +++ b/frontends/gtk/misc.c @@ -0,0 +1,192 @@ +/* + * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Implementation of netsurf miscellaneous operations table + */ + +#include <string.h> +#include <stdbool.h> +#include <gtk/gtk.h> + +#include "utils/config.h" +#include "utils/errors.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/nsurl.h" +#include "netsurf/misc.h" +#include "desktop/save_pdf.h" + +#include "gtk/compat.h" +#include "gtk/warn.h" +#include "gtk/schedule.h" +#include "gtk/resources.h" +#include "gtk/cookies.h" +#include "gtk/misc.h" + + +static nserror gui_launch_url(struct nsurl *url) +{ + gboolean ok; + GError *error = NULL; + + ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error); + if (ok == TRUE) { + return NSERROR_OK; + } + + if (error) { + nsgtk_warning(messages_get("URIOpenError"), error->message); + g_error_free(error); + } + return NSERROR_NO_FETCH_HANDLER; +} + +static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) +{ + char **owner_pass = ((void **)data)[0]; + char **user_pass = ((void **)data)[1]; + GtkWindow *wnd = ((void **)data)[2]; + GtkBuilder *password_builder = ((void **)data)[3]; + char *path = ((void **)data)[4]; + + char *op, *op1; + char *up, *up1; + + op = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(password_builder, + "entryPDFOwnerPassword")))); + op1 = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(password_builder, + "entryPDFOwnerPassword1")))); + up = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(password_builder, + "entryPDFUserPassword")))); + up1 = strdup(gtk_entry_get_text( + GTK_ENTRY(gtk_builder_get_object(password_builder, + "entryPDFUserPassword1")))); + + + if (op[0] == '\0') { + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, + "labelInfo")), + "Owner password must be at least 1 character long:"); + free(op); + free(up); + } else if (!strcmp(op, up)) { + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, + "labelInfo")), + "User and owner passwords must be different:"); + free(op); + free(up); + } else if (!strcmp(op, op1) && !strcmp(up, up1)) { + + *owner_pass = op; + if (up[0] == '\0') + free(up); + else + *user_pass = up; + + free(data); + gtk_widget_destroy(GTK_WIDGET(wnd)); + g_object_unref(G_OBJECT(password_builder)); + + save_pdf(path); + + free(path); + } else { + gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, + "labelInfo")), "Passwords not confirmed:"); + free(op); + free(up); + } + + free(op1); + free(up1); +} + +static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data) +{ + GtkWindow *wnd = ((void **)data)[2]; + GtkBuilder *password_builder = ((void **)data)[3]; + char *path = ((void **)data)[4]; + + free(data); + + gtk_widget_destroy(GTK_WIDGET(wnd)); + g_object_unref(G_OBJECT(password_builder)); + + save_pdf(path); + + free(path); +} + +static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path) +{ + GtkButton *ok, *no; + GtkWindow *wnd; + void **data; + GtkBuilder *password_builder; + nserror res; + + res = nsgtk_builder_new_from_resname("password", &password_builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Password UI builder init failed"); + return; + } + + gtk_builder_connect_signals(password_builder, NULL); + + wnd = GTK_WINDOW(gtk_builder_get_object(password_builder, + "wndPDFPassword")); + + data = malloc(5 * sizeof(void *)); + + *owner_pass = NULL; + *user_pass = NULL; + + data[0] = owner_pass; + data[1] = user_pass; + data[2] = wnd; + data[3] = password_builder; + data[4] = path; + + ok = GTK_BUTTON(gtk_builder_get_object(password_builder, + "buttonPDFSetPassword")); + no = GTK_BUTTON(gtk_builder_get_object(password_builder, + "buttonPDFNoPassword")); + + g_signal_connect(G_OBJECT(ok), "clicked", + G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data); + g_signal_connect(G_OBJECT(no), "clicked", + G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data); + + gtk_widget_show(GTK_WIDGET(wnd)); +} + + +static struct gui_misc_table misc_table = { + .schedule = nsgtk_schedule, + + .launch_url = gui_launch_url, + .pdf_password = nsgtk_pdf_password, + .present_cookies = nsgtk_cookies_present, +}; + +struct gui_misc_table *nsgtk_misc_table = &misc_table; diff --git a/frontends/gtk/login.h b/frontends/gtk/misc.h index 00c29000c..3a02c2254 100644 --- a/frontends/gtk/login.h +++ b/frontends/gtk/misc.h @@ -1,5 +1,5 @@ /* - * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> + * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,16 +16,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Login interfaces. - */ - -#ifndef __NSGTK_LOGIN_H__ -#define __NSGTK_LOGIN_H__ +#ifndef NETSURF_GTK_MISC_H +#define NETSURF_GTK_MISC_H 1 -/** - * login window request. - */ -extern void gui_401login_open(struct nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw); +extern struct gui_misc_table *nsgtk_misc_table; #endif diff --git a/frontends/gtk/options.h b/frontends/gtk/options.h index 018a448be..7fd79d7c5 100644 --- a/frontends/gtk/options.h +++ b/frontends/gtk/options.h @@ -16,16 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_GTK_OPTIONS_H_ -#define _NETSURF_GTK_OPTIONS_H_ +#ifndef NETSURF_GTK_OPTIONS_H_ +#define NETSURF_GTK_OPTIONS_H_ /* currently nothing here */ #endif -/* High quality image scaling */ -NSOPTION_BOOL(render_resample, true) - /* clear downloads */ NSOPTION_BOOL(downloads_clear, false) @@ -47,9 +44,6 @@ NSOPTION_INTEGER(button_type, 0) /* disallow popup windows */ NSOPTION_BOOL(disable_popups, false) -/* disable content plugins */ -NSOPTION_BOOL(disable_plugins, false) - /* number of days to keep history data */ NSOPTION_INTEGER(history_age, 0) @@ -72,4 +66,7 @@ NSOPTION_INTEGER(developer_view, 0) NSOPTION_INTEGER(position_tab, 0) /* Toolbar customisation */ -NSOPTION_STRING(toolbar_order, NULL) +NSOPTION_STRING(toolbar_items, NULL) + +/* The menu and tool bars that are shown */ +NSOPTION_STRING(bar_show, NULL) diff --git a/frontends/gtk/page_info.c b/frontends/gtk/page_info.c new file mode 100644 index 000000000..0d76a2f71 --- /dev/null +++ b/frontends/gtk/page_info.c @@ -0,0 +1,258 @@ +/* + * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Implementation of gtk certificate viewing using gtk core windows. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <gtk/gtk.h> + +#include "utils/log.h" +#include "utils/messages.h" +#include "netsurf/keypress.h" +#include "netsurf/plotters.h" +#include "netsurf/misc.h" +#include "netsurf/browser_window.h" +#include "desktop/page-info.h" +#include "desktop/gui_internal.h" + +#include "gtk/plotters.h" +#include "gtk/scaffolding.h" +#include "gtk/resources.h" +#include "gtk/page_info.h" +#include "gtk/corewindow.h" + + +/** + * GTK certificate viewing window context + */ +struct nsgtk_pi_window { + /** GTK core window context */ + struct nsgtk_corewindow core; + /** GTK builder for window */ + GtkBuilder *builder; + /** GTK window being shown */ + GtkWindow *dlg; + /** Core page-info window */ + struct page_info *pi; +}; + + +/** + * destroy a previously created page information window + */ +static gboolean +nsgtk_pi_delete_event(GtkWidget *w, GdkEvent *event, gpointer data) +{ + struct nsgtk_pi_window *pi_win; + pi_win = (struct nsgtk_pi_window *)data; + + page_info_destroy(pi_win->pi); + + nsgtk_corewindow_fini(&pi_win->core); + gtk_widget_destroy(GTK_WIDGET(pi_win->dlg)); + g_object_unref(G_OBJECT(pi_win->builder)); + free(pi_win); + + return FALSE; +} + +/** + * Called to cause the page-info window to close cleanly + */ +static void +nsgtk_pi_close_callback(void *pw) +{ + nsgtk_pi_delete_event(NULL, NULL, pw); +} + +/** + * callback for mouse action for certificate verify on core window + * + * \param nsgtk_cw The nsgtk core window structure. + * \param mouse_state netsurf mouse state on event + * \param x location of event + * \param y location of event + * \return NSERROR_OK on success otherwise appropriate error code + */ +static nserror +nsgtk_pi_mouse(struct nsgtk_corewindow *nsgtk_cw, + browser_mouse_state mouse_state, + int x, int y) +{ + struct nsgtk_pi_window *pi_win; + bool did_something = false; + /* technically degenerate container of */ + pi_win = (struct nsgtk_pi_window *)nsgtk_cw; + + if (page_info_mouse_action(pi_win->pi, mouse_state, x, y, &did_something) == NSERROR_OK) { + if (did_something == true) { + /* Something happened so we need to close ourselves */ + guit->misc->schedule(0, nsgtk_pi_close_callback, pi_win); + } + } + + return NSERROR_OK; +} + +/** + * callback for keypress for certificate verify on core window + * + * \param nsgtk_cw The nsgtk core window structure. + * \param nskey The netsurf key code + * \return NSERROR_OK on success otherwise appropriate error code + */ +static nserror +nsgtk_pi_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey) +{ + struct nsgtk_pi_window *pi_win; + + /* technically degenerate container of */ + pi_win = (struct nsgtk_pi_window *)nsgtk_cw; + + if (page_info_keypress(pi_win->pi, nskey)) { + return NSERROR_OK; + } + return NSERROR_NOT_IMPLEMENTED; +} + +/** + * callback on draw event for certificate verify on core window + * + * \param nsgtk_cw The nsgtk core window structure. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise appropriate error code + */ +static nserror +nsgtk_pi_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r) +{ + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &nsgtk_plotters + }; + struct nsgtk_pi_window *pi_win; + + /* technically degenerate container of */ + pi_win = (struct nsgtk_pi_window *)nsgtk_cw; + + page_info_redraw(pi_win->pi, 0, 0, r, &ctx); + + return NSERROR_OK; +} + +/* exported interface documented in gtk/page_info.h */ +nserror nsgtk_page_info(struct browser_window *bw) +{ + struct nsgtk_pi_window *ncwin; + nserror res; + GtkWindow *scaffwin = nsgtk_scaffolding_window(nsgtk_current_scaffolding()); + + ncwin = calloc(1, sizeof(struct nsgtk_pi_window)); + if (ncwin == NULL) { + return NSERROR_NOMEM; + } + + res = nsgtk_builder_new_from_resname("pageinfo", &ncwin->builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, CRITICAL, "Page Info UI builder init failed %s", messages_get_errorcode(res)); + free(ncwin); + return res; + } + + gtk_builder_connect_signals(ncwin->builder, NULL); + + ncwin->dlg = GTK_WINDOW(gtk_builder_get_object(ncwin->builder, + "PGIWindow")); + + /* Configure for transient behaviour */ + gtk_window_set_type_hint(GTK_WINDOW(ncwin->dlg), + GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU); + + gtk_window_set_modal(GTK_WINDOW(ncwin->dlg), TRUE); + + gtk_window_group_add_window(gtk_window_get_group(scaffwin), + GTK_WINDOW(ncwin->dlg)); + + gtk_window_set_transient_for(GTK_WINDOW(ncwin->dlg), scaffwin); + + gtk_window_set_screen(GTK_WINDOW(ncwin->dlg), + gtk_widget_get_screen(GTK_WIDGET(scaffwin))); + + /* Attempt to place the window in the right place */ + nsgtk_scaffolding_position_page_info(nsgtk_current_scaffolding(), + ncwin); + + ncwin->core.drawing_area = GTK_DRAWING_AREA( + gtk_builder_get_object(ncwin->builder, "PGIDrawingArea")); + + /* make the delete event call our destructor */ + g_signal_connect(G_OBJECT(ncwin->dlg), + "delete_event", + G_CALLBACK(nsgtk_pi_delete_event), + ncwin); + /* Ditto if we lose the grab */ + g_signal_connect(G_OBJECT(ncwin->dlg), + "grab-broken-event", + G_CALLBACK(nsgtk_pi_delete_event), + ncwin); + /* Handle button press events */ + g_signal_connect(G_OBJECT(ncwin->dlg), + "button-press-event", + G_CALLBACK(nsgtk_pi_delete_event), + ncwin); + + /* initialise GTK core window */ + ncwin->core.draw = nsgtk_pi_draw; + ncwin->core.key = nsgtk_pi_key; + ncwin->core.mouse = nsgtk_pi_mouse; + + res = nsgtk_corewindow_init(&ncwin->core); + if (res != NSERROR_OK) { + g_object_unref(G_OBJECT(ncwin->dlg)); + free(ncwin); + return res; + } + + res = page_info_create(ncwin->core.cb_table, + (struct core_window *)ncwin, + bw, &ncwin->pi); + if (res != NSERROR_OK) { + g_object_unref(G_OBJECT(ncwin->dlg)); + free(ncwin); + return res; + } + + gtk_widget_show(GTK_WIDGET(ncwin->dlg)); + + gtk_widget_grab_focus(GTK_WIDGET(ncwin->dlg)); + + return NSERROR_OK; +} + +/* exported interface documented in gtk/page_info.h */ +void +nsgtk_page_info_set_position(struct nsgtk_pi_window *win, int x, int y) +{ + NSLOG(netsurf, INFO, "win=%p x=%d y=%d", win, x, y); + + gtk_window_move(GTK_WINDOW(win->dlg), x, y); +} diff --git a/frontends/gtk/ssl_cert.h b/frontends/gtk/page_info.h index 1712756e9..23e1e348c 100644 --- a/frontends/gtk/ssl_cert.h +++ b/frontends/gtk/page_info.h @@ -1,5 +1,5 @@ /* - * Copyright 2005 James Bursa <bursa@users.sourceforge.net> + * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,22 +16,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NETSURF_GTK_SSL_CERT_H -#define NETSURF_GTK_SSL_CERT_H 1 - -struct nsurl; -struct ssl_cert_info; +#ifndef NETSURF_GTK_PAGE_INFO_H +#define NETSURF_GTK_PAGE_INFO_H 1 /** - * Prompt the user to verify a certificate with issuse. + * Page information window * - * \param url The URL being verified. - * \param certs The certificate to be verified - * \param num The number of certificates to be verified. - * \param cb Callback upon user decision. - * \param cbpw Context pointer passed to cb + * \param bw the browser window to get page information for * \return NSERROR_OK or error code if prompt creation failed. */ -nserror gtk_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw); +nserror nsgtk_page_info(struct browser_window *bw); + +/** + * Position the given page information window at the given + * coordinates. + * + * \param pi the page info window to position + * \param x the X coordinate for the top left of the window + * \param y the Y coordinate for the top left of the window + */ +void nsgtk_page_info_set_position(struct nsgtk_pi_window *pi, int x, int y); #endif diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c index 88e7760c6..110dcffc5 100644 --- a/frontends/gtk/plotters.c +++ b/frontends/gtk/plotters.c @@ -89,6 +89,20 @@ static inline void nsgtk_set_dashed(void) /** + * Set cairo context line width. + */ +static inline void nsgtk_set_line_width(plot_style_fixed width) +{ + if (width == 0) { + cairo_set_line_width(current_cr, 1); + } else { + cairo_set_line_width(current_cr, + plot_style_fixed_to_double(width)); + } +} + + +/** * \brief Sets a clip rectangle for subsequent plot operations. * * \param ctx The current redraw context. @@ -191,10 +205,7 @@ nsgtk_plot_disc(const struct redraw_context *ctx, break; } - if (style->stroke_width == 0) - cairo_set_line_width(current_cr, 1); - else - cairo_set_line_width(current_cr, style->stroke_width); + nsgtk_set_line_width(style->stroke_width); cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); @@ -242,10 +253,7 @@ nsgtk_plot_line(const struct redraw_context *ctx, nsgtk_set_colour(style->stroke_colour); } - if (style->stroke_width == 0) - cairo_set_line_width(current_cr, 1); - else - cairo_set_line_width(current_cr, style->stroke_width); + nsgtk_set_line_width(style->stroke_width); /* core expects horizontal and vertical lines to be on pixels, not * between pixels @@ -331,10 +339,7 @@ nsgtk_plot_rectangle(const struct redraw_context *ctx, break; } - if (style->stroke_width == 0) - cairo_set_line_width(current_cr, 1); - else - cairo_set_line_width(current_cr, style->stroke_width); + nsgtk_set_line_width(style->stroke_width); cairo_rectangle(current_cr, rect->x0 + 0.5, @@ -394,7 +399,6 @@ nsgtk_plot_polygon(const struct redraw_context *ctx, * \param pstyle Style controlling the path plot. * \param p elements of path * \param n nunber of elements on path - * \param width The width of the path * \param transform A transform to apply to the path. * \return NSERROR_OK on success else error code. */ @@ -403,7 +407,6 @@ nsgtk_plot_path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, - float width, const float transform[6]) { unsigned int i; @@ -421,7 +424,7 @@ nsgtk_plot_path(const struct redraw_context *ctx, cairo_get_matrix(current_cr, &old_ctm); /* Set up line style and width */ - cairo_set_line_width(current_cr, 1); + nsgtk_set_line_width(pstyle->stroke_width); nsgtk_set_solid(); /* Load new CTM */ @@ -429,8 +432,8 @@ nsgtk_plot_path(const struct redraw_context *ctx, n_ctm.yx = transform[1]; n_ctm.xy = transform[2]; n_ctm.yy = transform[3]; - n_ctm.x0 = transform[4]; - n_ctm.y0 = transform[5]; + n_ctm.x0 = transform[4] + old_ctm.x0; + n_ctm.y0 = transform[5] + old_ctm.y0; cairo_set_matrix(current_cr, &n_ctm); diff --git a/frontends/gtk/preferences.c b/frontends/gtk/preferences.c index 65f41ed27..a44e7241e 100644 --- a/frontends/gtk/preferences.c +++ b/frontends/gtk/preferences.c @@ -30,6 +30,7 @@ #include "desktop/searchweb.h" #include "gtk/compat.h" +#include "gtk/toolbar_items.h" #include "gtk/window.h" #include "gtk/gui.h" #include "gtk/scaffolding.h" @@ -411,12 +412,6 @@ TOGGLEBUTTON_SIGNALS(checkHideAdverts, block_advertisements) /* enable javascript */ TOGGLEBUTTON_SIGNALS(checkEnableJavascript, enable_javascript) -/* disable plugins */ -TOGGLEBUTTON_SIGNALS(checkDisablePlugins, disable_plugins) - -/* high quality image scaling */ -TOGGLEBUTTON_SIGNALS(checkResampleImages, render_resample) - /* load and display of images */ G_MODULE_EXPORT void nsgtk_preferences_comboboxLoadImages_changed(GtkComboBox *combo, @@ -480,9 +475,6 @@ nsgtk_preferences_comboboxLoadImages_realize(GtkWidget *widget, /* enable animation */ TOGGLEBUTTON_SIGNALS(checkEnableAnimations, animate_images) -/* frame time */ -SPINBUTTON_SIGNALS(spinAnimationSpeed, minimum_gif_delay, 100.0) - /* Fonts */ /* default font */ @@ -511,7 +503,7 @@ SPINBUTTON_SIGNALS(spinDefaultSize, font_size, 10.0) G_MODULE_EXPORT void nsgtk_preferences_fontPreview_clicked(GtkButton *button, struct ppref *priv) { - nsgtk_reflow_all_windows(); + nsgtk_window_update_all(); } @@ -713,7 +705,7 @@ nsgtk_preferences_checkShowSingleTab_toggled(GtkToggleButton *togglebutton, { nsoption_set_bool(show_single_tab, gtk_toggle_button_get_active(togglebutton)); - nsgtk_reflow_all_windows(); + nsgtk_window_update_all(); } G_MODULE_EXPORT void @@ -735,20 +727,11 @@ G_MODULE_EXPORT void nsgtk_preferences_comboTabPosition_changed(GtkComboBox *widget, struct ppref *priv) { - struct nsgtk_scaffolding *current; - /* set the option */ nsoption_set_int(position_tab, gtk_combo_box_get_active(widget)); - /* update all notebooks in all scaffolds */ - current = nsgtk_scaffolding_iterate(NULL); - while (current) { - nsgtk_scaffolding_reset_offset(current); - - nsgtk_reflow_all_windows(); - - current = nsgtk_scaffolding_iterate(current); - } + /* update all windows */ + nsgtk_window_update_all(); } G_MODULE_EXPORT void @@ -791,18 +774,10 @@ G_MODULE_EXPORT void nsgtk_preferences_comboButtonType_changed(GtkComboBox *widget, struct ppref *priv) { - struct nsgtk_scaffolding *current; - nsoption_set_int(button_type, gtk_combo_box_get_active(widget) + 1); - current = nsgtk_scaffolding_iterate(NULL); - while (current != NULL) { - nsgtk_scaffolding_reset_offset(current); - - nsgtk_scaffolding_toolbars(current, nsoption_int(button_type)); - - current = nsgtk_scaffolding_iterate(current); - } + /* update all windows to adopt change */ + nsgtk_window_update_all(); } G_MODULE_EXPORT void @@ -826,7 +801,7 @@ ENTRY_SIGNALS(entryHomePageURL, homepage_url) G_MODULE_EXPORT void nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv) { - const gchar *url = nsurl_access(browser_window_get_url(priv->bw)); + const gchar *url = nsurl_access(browser_window_access_url(priv->bw)); if (priv->entryHomePageURL != NULL) { gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url); diff --git a/frontends/gtk/print.c b/frontends/gtk/print.c index 8f71230a6..c4f1b0f7a 100644 --- a/frontends/gtk/print.c +++ b/frontends/gtk/print.c @@ -133,6 +133,17 @@ static inline void nsgtk_print_set_dashed(void) cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); } +/** Set cairo context line width. */ +static inline void nsgtk_set_line_width(plot_style_fixed width) +{ + if (width == 0) { + cairo_set_line_width(gtk_print_current_cr, 1); + } else { + cairo_set_line_width(gtk_print_current_cr, + plot_style_fixed_to_double(width)); + } +} + /** * \brief Sets a clip rectangle for subsequent plot operations. @@ -248,10 +259,7 @@ nsgtk_print_plot_disc(const struct redraw_context *ctx, break; } - if (style->stroke_width == 0) - cairo_set_line_width(gtk_print_current_cr, 1); - else - cairo_set_line_width(gtk_print_current_cr, style->stroke_width); + nsgtk_set_line_width(style->stroke_width); cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2); @@ -294,10 +302,7 @@ nsgtk_print_plot_line(const struct redraw_context *ctx, break; } - if (style->stroke_width == 0) - cairo_set_line_width(gtk_print_current_cr, 1); - else - cairo_set_line_width(gtk_print_current_cr, style->stroke_width); + nsgtk_set_line_width(style->stroke_width); cairo_move_to(gtk_print_current_cr, line->x0 + 0.5, line->y0 + 0.5); cairo_line_to(gtk_print_current_cr, line->x1 + 0.5, line->y1 + 0.5); @@ -350,13 +355,6 @@ nsgtk_print_plot_rectangle(const struct redraw_context *ctx, } if (style->stroke_type != PLOT_OP_TYPE_NONE) { - int stroke_width; - - /* ensure minimum stroke width */ - stroke_width = style->stroke_width; - if (stroke_width == 0) { - stroke_width = 1; - } nsgtk_print_set_colour(style->stroke_colour); @@ -375,7 +373,7 @@ nsgtk_print_plot_rectangle(const struct redraw_context *ctx, break; } - cairo_set_line_width(gtk_print_current_cr, stroke_width); + nsgtk_set_line_width(style->stroke_width); cairo_rectangle(gtk_print_current_cr, rect->x0, rect->y0, @@ -429,7 +427,6 @@ nsgtk_print_plot_polygon(const struct redraw_context *ctx, * \param pstyle Style controlling the path plot. * \param p elements of path * \param n nunber of elements on path - * \param width The width of the path * \param transform A transform to apply to the path. * \return NSERROR_OK on success else error code. */ @@ -438,7 +435,6 @@ nsgtk_print_plot_path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, - float width, const float transform[6]) { /* Only the internal SVG renderer uses this plot call currently, diff --git a/frontends/gtk/res/arrow_down_8x32.png b/frontends/gtk/res/arrow_down_8x32.png Binary files differdeleted file mode 100644 index 475b4ff61..000000000 --- a/frontends/gtk/res/arrow_down_8x32.png +++ /dev/null diff --git a/frontends/gtk/res/en/maps.html b/frontends/gtk/res/en/maps.html deleted file mode 120000 index 507a4b248..000000000 --- a/frontends/gtk/res/en/maps.html +++ /dev/null @@ -1 +0,0 @@ -../../../../resources/en/maps.html
\ No newline at end of file diff --git a/frontends/gtk/res/fr/credits.html b/frontends/gtk/res/fr/credits.html new file mode 120000 index 000000000..47da488e8 --- /dev/null +++ b/frontends/gtk/res/fr/credits.html @@ -0,0 +1 @@ +../../../../resources/fr/credits.html
\ No newline at end of file diff --git a/frontends/gtk/res/fr/licence.html b/frontends/gtk/res/fr/licence.html new file mode 120000 index 000000000..2fd247ba8 --- /dev/null +++ b/frontends/gtk/res/fr/licence.html @@ -0,0 +1 @@ +../../../../resources/fr/licence.html
\ No newline at end of file diff --git a/frontends/gtk/res/fr/welcome.html b/frontends/gtk/res/fr/welcome.html new file mode 120000 index 000000000..a7a2023ea --- /dev/null +++ b/frontends/gtk/res/fr/welcome.html @@ -0,0 +1 @@ +../../../../resources/fr/welcome.html
\ No newline at end of file diff --git a/frontends/gtk/res/cookies.gtk2.ui b/frontends/gtk/res/gtk2/cookies.ui index 86f15c765..86f15c765 100644 --- a/frontends/gtk/res/cookies.gtk2.ui +++ b/frontends/gtk/res/gtk2/cookies.ui diff --git a/frontends/gtk/res/downloads.gtk2.ui b/frontends/gtk/res/gtk2/downloads.ui index 1e71328a4..1e71328a4 100644 --- a/frontends/gtk/res/downloads.gtk2.ui +++ b/frontends/gtk/res/gtk2/downloads.ui diff --git a/frontends/gtk/res/globalhistory.gtk2.ui b/frontends/gtk/res/gtk2/globalhistory.ui index 2b89ecb4b..2b89ecb4b 100644 --- a/frontends/gtk/res/globalhistory.gtk2.ui +++ b/frontends/gtk/res/gtk2/globalhistory.ui diff --git a/frontends/gtk/res/hotlist.gtk2.ui b/frontends/gtk/res/gtk2/hotlist.ui index af0fd5696..af0fd5696 100644 --- a/frontends/gtk/res/hotlist.gtk2.ui +++ b/frontends/gtk/res/gtk2/hotlist.ui diff --git a/frontends/gtk/res/localhistory.gtk2.ui b/frontends/gtk/res/gtk2/localhistory.ui index 9512b6289..2003ed69a 100644 --- a/frontends/gtk/res/localhistory.gtk2.ui +++ b/frontends/gtk/res/gtk2/localhistory.ui @@ -2,6 +2,7 @@ <interface> <!-- interface-requires gtk+ 3.0 --> <object class="GtkWindow" id="wndHistory"> + <property name="type">GTK_WINDOW_POPUP</property> <property name="can_focus">False</property> <property name="title" translatable="yes">NetSurf Local History</property> <property name="window_position">center</property> diff --git a/frontends/gtk/res/gtk2/netsurf.ui b/frontends/gtk/res/gtk2/netsurf.ui new file mode 100644 index 000000000..adca54001 --- /dev/null +++ b/frontends/gtk/res/gtk2/netsurf.ui @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 2.12 --> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkAdjustment" id="adjustment1"> + <property name="upper">100</property> + <property name="value">0.5357142857142857</property> + <property name="step_increment">26</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkAdjustment" id="adjustment2"> + <property name="upper">100</property> + <property name="step_increment">26</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkWindow" id="wndBrowser"> + <property name="can_focus">False</property> + <property name="title" translatable="yes">NetSurf</property> + <property name="window_position">center</property> + <child> + <object class="GtkVBox" id="vbox14"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuBar" id="menubar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkNotebook" id="notebook"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="show_tabs">False</property> + <property name="show_border">False</property> + <property name="scrollable">True</property> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/options.gtk2.ui b/frontends/gtk/res/gtk2/options.ui index a1162585d..907d0b511 100644 --- a/frontends/gtk/res/options.gtk2.ui +++ b/frontends/gtk/res/gtk2/options.ui @@ -1143,38 +1143,6 @@ </packing> </child> <child> - <object class="GtkCheckButton" id="checkDisablePlugins"> - <property name="label" translatable="yes">preferencesControlDisable</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="nsgtk_preferences_checkDisablePlugins_toggled" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_checkDisablePlugins_realize" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="checkResampleImages"> - <property name="label" translatable="yes">preferencesControlHigh</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="nsgtk_preferences_checkResampleImages_toggled" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_checkResampleImages_realize" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - <child> <object class="GtkHBox" id="hbox8"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -1215,7 +1183,7 @@ <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">5</property> + <property name="position">3</property> </packing> </child> </object> @@ -1272,55 +1240,6 @@ <property name="position">0</property> </packing> </child> - <child> - <object class="GtkHBox" id="hbox9"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel" id="label19"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">preferencesAnimationMinimum</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSpinButton" id="spinAnimationSpeed"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="has_tooltip">True</property> - <property name="tooltip_text" translatable="yes">preferencesAnimationMinimumTooltip</property> - <property name="invisible_char">●</property> - <property name="primary_icon_activatable">False</property> - <property name="secondary_icon_activatable">False</property> - <property name="primary_icon_sensitive">True</property> - <property name="secondary_icon_sensitive">True</property> - <property name="adjustment">adjustment_animation_time</property> - <property name="climb_rate">1</property> - <property name="digits">1</property> - <property name="numeric">True</property> - <property name="update_policy">if-valid</property> - <signal name="value-changed" handler="nsgtk_preferences_spinAnimationSpeed_valuechanged" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_spinAnimationSpeed_realize" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> </object> </child> </object> diff --git a/frontends/gtk/res/gtk2/pageinfo.ui b/frontends/gtk/res/gtk2/pageinfo.ui new file mode 100644 index 000000000..3d541d653 --- /dev/null +++ b/frontends/gtk/res/gtk2/pageinfo.ui @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <requires lib="gtk+" version="2.24"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkWindow" id="PGIWindow"> + <property name="type">GTK_WINDOW_POPUP</property> + <property name="can_focus">False</property> + <child> + <object class="GtkDrawingArea" id="PGIDrawingArea"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property> + </object> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/password.gtk2.ui b/frontends/gtk/res/gtk2/password.ui index eb51e4f8f..eb51e4f8f 100644 --- a/frontends/gtk/res/password.gtk2.ui +++ b/frontends/gtk/res/gtk2/password.ui diff --git a/frontends/gtk/res/gtk2/tabcontents.ui b/frontends/gtk/res/gtk2/tabcontents.ui new file mode 100644 index 000000000..c47e6a2ef --- /dev/null +++ b/frontends/gtk/res/gtk2/tabcontents.ui @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 2.12 --> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkAdjustment" id="layouthadjustment"> + <property name="upper">100</property> + <property name="step_increment">30</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkAdjustment" id="layoutvadjustment"> + <property name="upper">100</property> + <property name="step_increment">30</property> + <property name="page_increment">10</property> + <property name="page_size">10</property> + </object> + <object class="GtkVBox" id="tabBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="toolbar_style">both-horiz</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="findbar"> + <property name="can_focus">False</property> + <property name="toolbar_style">both</property> + <child> + <object class="GtkToolItem" id="toolitemFind"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkEntry" id="Find"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="primary_icon_activatable">False</property> + <property name="secondary_icon_activatable">False</property> + <property name="primary_icon_sensitive">True</property> + <property name="secondary_icon_sensitive">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindBack"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">gtkFindBack</property> + <property name="use_underline">True</property> + <property name="icon_name">go-up</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindForward"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">gtkFindForward</property> + <property name="use_underline">True</property> + <property name="icon_name">go-down</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolItem" id="toolitemFindHighlightAll"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkCheckButton" id="FindHighlightAll"> + <property name="label" translatable="yes">gtkFindHighlightAll</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">show all matches</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkToolItem" id="toolitemFindMatchCase"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkCheckButton" id="FindMatchCase"> + <property name="label" translatable="yes">gtkFindMatchCase</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Match case when searching</property> + <property name="relief">none</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindClose"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">gtkFindClose</property> + <property name="icon_name">window-close</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkTable" id="tabContents"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <child> + <object class="GtkLayout" id="layout"> + <property name="visible">True</property> + <property name="app_paintable">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property> + <property name="hadjustment">layouthadjustment</property> + <property name="vadjustment">layoutvadjustment</property> + </object> + </child> + <child> + <object class="GtkStatusbar" id="resizer"> + <property name="height_request">1</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">2</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkHPaned" id="hpaned1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkLabel" id="status_bar"> + <property name="width_request">1</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="xpad">4</property> + <property name="label" translatable="yes">Status</property> + </object> + <packing> + <property name="resize">False</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkHScrollbar" id="hscrollbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="adjustment">layouthadjustment</property> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <object class="GtkVScrollbar" id="vscrollbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="adjustment">layoutvadjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="x_options"/> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/gtk2/toolbar.ui b/frontends/gtk/res/gtk2/toolbar.ui new file mode 100644 index 000000000..61723065b --- /dev/null +++ b/frontends/gtk/res/gtk2/toolbar.ui @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 2.12 --> + <!-- interface-naming-policy toplevel-contextual --> + <object class="GtkVBox" id="customisation"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xalign">0</property> + <property name="xpad">6</property> + <property name="label" translatable="yes">gtkCustomizeToolbarInstructions</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkVBox" id="toolbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="reset"> + <property name="label" translatable="yes">Reset to defaults</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="discard"> + <property name="label">gtk-discard</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="apply"> + <property name="label">gtk-apply</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">3</property> + </packing> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/viewdata.gtk2.ui b/frontends/gtk/res/gtk2/viewdata.ui index 7589022ca..7589022ca 100644 --- a/frontends/gtk/res/viewdata.gtk2.ui +++ b/frontends/gtk/res/gtk2/viewdata.ui diff --git a/frontends/gtk/res/warning.gtk2.ui b/frontends/gtk/res/gtk2/warning.ui index e4fb4e662..e4fb4e662 100644 --- a/frontends/gtk/res/warning.gtk2.ui +++ b/frontends/gtk/res/gtk2/warning.ui diff --git a/frontends/gtk/res/cookies.gtk3.ui b/frontends/gtk/res/gtk3/cookies.ui index 44dcb80b8..85f9aae76 100644 --- a/frontends/gtk/res/cookies.gtk3.ui +++ b/frontends/gtk/res/gtk3/cookies.ui @@ -187,7 +187,7 @@ <object class="GtkDrawingArea" id="cookiesDrawingArea"> <property name="visible">True</property> <property name="app_paintable">True</property> - <property name="can_focus">False</property> + <property name="can_focus">True</property> <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> </object> </child> diff --git a/frontends/gtk/res/downloads.gtk3.ui b/frontends/gtk/res/gtk3/downloads.ui index 1e71328a4..1e71328a4 100644 --- a/frontends/gtk/res/downloads.gtk3.ui +++ b/frontends/gtk/res/gtk3/downloads.ui diff --git a/frontends/gtk/res/globalhistory.gtk3.ui b/frontends/gtk/res/gtk3/globalhistory.ui index 7fa598f1e..c0496964f 100644 --- a/frontends/gtk/res/globalhistory.gtk3.ui +++ b/frontends/gtk/res/gtk3/globalhistory.ui @@ -219,7 +219,7 @@ <child> <object class="GtkDrawingArea" id="globalHistoryDrawingArea"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can_focus">True</property> <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> </object> </child> diff --git a/frontends/gtk/res/hotlist.gtk3.ui b/frontends/gtk/res/gtk3/hotlist.ui index b0e075c4b..ccd193637 100644 --- a/frontends/gtk/res/hotlist.gtk3.ui +++ b/frontends/gtk/res/gtk3/hotlist.ui @@ -236,7 +236,7 @@ <child> <object class="GtkDrawingArea" id="hotlistDrawingArea"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can_focus">True</property> <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> </object> </child> diff --git a/frontends/gtk/res/localhistory.gtk3.ui b/frontends/gtk/res/gtk3/localhistory.ui index 1a4b9004d..9a36a91a7 100644 --- a/frontends/gtk/res/localhistory.gtk3.ui +++ b/frontends/gtk/res/gtk3/localhistory.ui @@ -2,6 +2,7 @@ <interface> <!-- interface-requires gtk+ 3.0 --> <object class="GtkWindow" id="wndHistory"> + <property name="type">GTK_WINDOW_POPUP</property> <property name="can_focus">False</property> <property name="title" translatable="yes">NetSurf Local History</property> <property name="window_position">center</property> @@ -26,7 +27,7 @@ <child> <object class="GtkDrawingArea" id="HistoryDrawingArea"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can_focus">True</property> <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> </object> </child> diff --git a/frontends/gtk/res/gtk3/netsurf.ui b/frontends/gtk/res/gtk3/netsurf.ui new file mode 100644 index 000000000..6ea8f07a7 --- /dev/null +++ b/frontends/gtk/res/gtk3/netsurf.ui @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.0"/> + <object class="GtkWindow" id="wndBrowser"> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkMenuBar" id="menubar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkNotebook" id="notebook"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="show_tabs">False</property> + <property name="show_border">False</property> + <property name="scrollable">True</property> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child type="tab"> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/options.gtk3.ui b/frontends/gtk/res/gtk3/options.ui index 2a3516f09..82a3e175a 100644 --- a/frontends/gtk/res/options.gtk3.ui +++ b/frontends/gtk/res/gtk3/options.ui @@ -143,9 +143,10 @@ <property name="visible">True</property> <property name="can_focus">True</property> <child> - <object class="GtkVBox" id="vbox_main"> + <object class="GtkBox" id="vbox_main"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="valign">start</property> <property name="spacing">6</property> <child> @@ -162,14 +163,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox2"> + <object class="GtkBox" id="vbox2"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="hbox1"> + <object class="GtkBox" id="hbox1"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label_startup_page"> @@ -207,9 +210,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox2"> + <object class="GtkBox" id="hbox2"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <placeholder/> @@ -289,9 +293,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox3"> + <object class="GtkBox" id="vbox3"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkUrlSearch"> @@ -314,9 +319,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox3"> + <object class="GtkBox" id="hbox3"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label5"> @@ -393,9 +399,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox4"> + <object class="GtkBox" id="vbox4"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkClearDownloads"> @@ -438,9 +445,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox4"> + <object class="GtkBox" id="hbox4"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label8"> @@ -510,9 +518,10 @@ </packing> </child> <child> - <object class="GtkVBox" id="vbox_appearance"> + <object class="GtkBox" id="vbox_appearance"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="valign">start</property> <property name="spacing">6</property> <child> @@ -529,9 +538,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox5"> + <object class="GtkBox" id="vbox5"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkShowSingleTab"> @@ -594,9 +604,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox5"> + <object class="GtkBox" id="hbox5"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label9"> @@ -672,14 +683,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox1"> + <object class="GtkBox" id="vbox1"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="hbox6"> + <object class="GtkBox" id="hbox6"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label13"> @@ -755,9 +768,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox7"> + <object class="GtkBox" id="vbox7"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkDisplayRecentURLs"> @@ -813,14 +827,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox8"> + <object class="GtkBox" id="vbox8"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="hbox7"> + <object class="GtkBox" id="hbox7"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label16"> @@ -899,10 +915,11 @@ </packing> </child> <child> - <object class="GtkVBox" id="vbox_content"> + <object class="GtkBox" id="vbox_content"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="valign">start</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkFrame" id="frame_content_control"> @@ -918,9 +935,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox6"> + <object class="GtkBox" id="vbox6"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkDisablePopups"> @@ -983,49 +1001,10 @@ </packing> </child> <child> - <object class="GtkCheckButton" id="checkDisablePlugins"> - <property name="label" translatable="yes">preferencesControlDisable</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="halign">start</property> - <property name="use_action_appearance">False</property> - <property name="xalign">0.5</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="nsgtk_preferences_checkDisablePlugins_toggled" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_checkDisablePlugins_realize" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="checkResampleImages"> - <property name="label" translatable="yes">preferencesControlHigh</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="halign">start</property> - <property name="use_action_appearance">False</property> - <property name="xalign">0.5</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="nsgtk_preferences_checkResampleImages_toggled" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_checkResampleImages_realize" swapped="no"/> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - <child> - <object class="GtkHBox" id="hbox8"> + <object class="GtkBox" id="hbox8"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label17"> @@ -1064,7 +1043,7 @@ <packing> <property name="expand">True</property> <property name="fill">True</property> - <property name="position">5</property> + <property name="position">3</property> </packing> </child> </object> @@ -1101,9 +1080,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox9"> + <object class="GtkBox" id="vbox9"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkEnableAnimations"> @@ -1125,51 +1105,6 @@ <property name="position">0</property> </packing> </child> - <child> - <object class="GtkHBox" id="hbox9"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel" id="label19"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">preferencesAnimationMinimum</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSpinButton" id="spinAnimationSpeed"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="has_tooltip">True</property> - <property name="tooltip_text" translatable="yes">preferencesAnimationMinimumTooltip</property> - <property name="invisible_char">●</property> - <property name="adjustment">adjustment_animation_time</property> - <property name="climb_rate">1</property> - <property name="digits">1</property> - <property name="numeric">True</property> - <property name="update_policy">if-valid</property> - <signal name="value-changed" handler="nsgtk_preferences_spinAnimationSpeed_valuechanged" swapped="no"/> - <signal name="realize" handler="nsgtk_preferences_spinAnimationSpeed_realize" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> </object> </child> </object> @@ -1204,14 +1139,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkHBox" id="hbox11"> + <object class="GtkBox" id="hbox11"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> - <object class="GtkHBox" id="hbox12"> + <object class="GtkBox" id="hbox12"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label26"> @@ -1253,9 +1190,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox13"> + <object class="GtkBox" id="hbox13"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label27"> @@ -1349,14 +1287,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox10"> + <object class="GtkBox" id="vbox10"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="hbox10"> + <object class="GtkBox" id="hbox10"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">12</property> <child> <object class="GtkLabel" id="label21"> @@ -1446,10 +1386,11 @@ </packing> </child> <child> - <object class="GtkVBox" id="vbox_privacy"> + <object class="GtkBox" id="vbox_privacy"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="valign">start</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkFrame" id="frame_privacy_general"> @@ -1465,9 +1406,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox15"> + <object class="GtkBox" id="vbox15"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkSendReferer"> @@ -1543,9 +1485,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox11"> + <object class="GtkBox" id="vbox11"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkHoverURLs"> @@ -1568,9 +1511,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox14"> + <object class="GtkBox" id="hbox14"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label28"> @@ -1657,9 +1601,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox12"> + <object class="GtkBox" id="vbox12"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkTable" id="table3"> @@ -1815,9 +1760,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox17"> + <object class="GtkBox" id="hbox17"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <child> <placeholder/> </child> @@ -1881,10 +1827,11 @@ </packing> </child> <child> - <object class="GtkVBox" id="vbox_network"> + <object class="GtkBox" id="vbox_network"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="valign">start</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkFrame" id="frame_network_proxy"> @@ -1979,9 +1926,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox19"> + <object class="GtkBox" id="hbox19"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkEntry" id="entryProxyHost"> @@ -2285,10 +2233,11 @@ </packing> </child> <child> - <object class="GtkVBox" id="vbox_pdfexport"> + <object class="GtkBox" id="vbox_pdfexport"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="valign">start</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkFrame" id="frame_pdfexport_appearance"> @@ -2304,9 +2253,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox13"> + <object class="GtkBox" id="vbox13"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> <object class="GtkCheckButton" id="checkSuppressImages"> @@ -2369,9 +2319,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox15"> + <object class="GtkBox" id="hbox15"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label59"> @@ -2458,14 +2409,16 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox16"> + <object class="GtkBox" id="vbox16"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">6</property> <child> - <object class="GtkHBox" id="hbox22"> + <object class="GtkBox" id="hbox22"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <child> <object class="GtkLabel" id="label62"> <property name="visible">True</property> @@ -2504,9 +2457,10 @@ <placeholder/> </child> <child> - <object class="GtkHBox" id="hbox16"> + <object class="GtkBox" id="hbox16"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label51"> @@ -2548,9 +2502,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox18"> + <object class="GtkBox" id="hbox18"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label52"> @@ -2593,9 +2548,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox20"> + <object class="GtkBox" id="hbox20"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label53"> @@ -2639,9 +2595,10 @@ </packing> </child> <child> - <object class="GtkHBox" id="hbox21"> + <object class="GtkBox" id="hbox21"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">horizontal</property> <property name="spacing">6</property> <child> <object class="GtkLabel" id="label54"> @@ -2746,9 +2703,10 @@ <property name="left_padding">12</property> <property name="right_padding">12</property> <child> - <object class="GtkVBox" id="vbox14"> + <object class="GtkBox" id="vbox14"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="orientation">vertical</property> <property name="spacing">7</property> <child> <object class="GtkCheckButton" id="checkCompressPDF"> diff --git a/frontends/gtk/res/gtk3/pageinfo.ui b/frontends/gtk/res/gtk3/pageinfo.ui new file mode 100644 index 000000000..fdee5ac8d --- /dev/null +++ b/frontends/gtk/res/gtk3/pageinfo.ui @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <object class="GtkWindow" id="PGIWindow"> + <property name="type">GTK_WINDOW_POPUP</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_STRUCTURE_MASK</property> + <property name="resizable">False</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkDrawingArea" id="PGIDrawingArea"> + <property name="name">PGIDrawingArea</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property> + </object> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/password.gtk3.ui b/frontends/gtk/res/gtk3/password.ui index eb51e4f8f..eb51e4f8f 100644 --- a/frontends/gtk/res/password.gtk3.ui +++ b/frontends/gtk/res/gtk3/password.ui diff --git a/frontends/gtk/res/gtk3/tabcontents.ui b/frontends/gtk/res/gtk3/tabcontents.ui new file mode 100644 index 000000000..b07cf92e0 --- /dev/null +++ b/frontends/gtk/res/gtk3/tabcontents.ui @@ -0,0 +1,229 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.0"/> + <object class="GtkAdjustment" id="layouthadjustment"> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkAdjustment" id="layoutvadjustment"> + <property name="upper">100</property> + <property name="step_increment">1</property> + <property name="page_increment">10</property> + </object> + <object class="GtkBox" id="tabBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="toolbar_style">both</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="findbar"> + <property name="can_focus">False</property> + <property name="toolbar_style">both</property> + <child> + <object class="GtkToolItem"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkEntry" id="Find"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">●</property> + <property name="placeholder_text" translatable="yes">gtkFindPlaceholder</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindBack"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">gtkFindBack</property> + <property name="label" translatable="yes">gtkFindBack</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-go-up</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindForward"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">gtkFindForward</property> + <property name="label" translatable="yes">gtkFindForward</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-go-down</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolItem"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkCheckButton" id="FindHighlightAll"> + <property name="label" translatable="yes">gtkFindHighlightAll</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkToolItem"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkCheckButton" id="FindMatchCase"> + <property name="label" translatable="yes">gtkFindMatchCase</property> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="FindClose"> + <property name="use_action_appearance">False</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="tooltip_text" translatable="yes">gtkFindClose</property> + <property name="label" translatable="yes">gtkFindClose</property> + <property name="stock_id">gtk-close</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkGrid" id="tabContents"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">2</property> + <property name="column_spacing">2</property> + <child> + <object class="GtkLayout" id="layout"> + <property name="visible">True</property> + <property name="app_paintable">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property> + <property name="hadjustment">layouthadjustment</property> + <property name="vadjustment">layoutvadjustment</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrollbar" id="vscrollbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <property name="adjustment">layoutvadjustment</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkPaned" id="hpaned1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <child> + <object class="GtkLabel" id="status_bar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xpad">4</property> + <property name="label" translatable="yes">Status</property> + <property name="single_line_mode">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="resize">False</property> + <property name="shrink">True</property> + </packing> + </child> + <child> + <object class="GtkScrollbar" id="hscrollbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="adjustment">layouthadjustment</property> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/gtk3/toolbar.ui b/frontends/gtk/res/gtk3/toolbar.ui new file mode 100644 index 000000000..60452f472 --- /dev/null +++ b/frontends/gtk/res/gtk3/toolbar.ui @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<!--*- mode: xml -*--> +<interface> + <requires lib="gtk+" version="3.0"/> + <object class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-refresh</property> + </object> + <object class="GtkBox" id="customisation"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="xpad">6</property> + <property name="label" translatable="yes">gtkCustomizeToolbarInstructions</property> + <property name="wrap">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkBox" id="toolbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButtonBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="reset"> + <property name="label" translatable="yes">Reset</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">image2</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="discard"> + <property name="label">gtk-discard</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="apply"> + <property name="label">gtk-apply</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">6</property> + <property name="position">3</property> + </packing> + </child> + </object> +</interface> diff --git a/frontends/gtk/res/viewdata.gtk3.ui b/frontends/gtk/res/gtk3/viewdata.ui index b742d5f6b..b742d5f6b 100644 --- a/frontends/gtk/res/viewdata.gtk3.ui +++ b/frontends/gtk/res/gtk3/viewdata.ui diff --git a/frontends/gtk/res/warning.gtk3.ui b/frontends/gtk/res/gtk3/warning.ui index e4fb4e662..e4fb4e662 100644 --- a/frontends/gtk/res/warning.gtk3.ui +++ b/frontends/gtk/res/gtk3/warning.ui diff --git a/frontends/gtk/res/login.gtk2.ui b/frontends/gtk/res/login.gtk2.ui deleted file mode 100644 index 552b173ed..000000000 --- a/frontends/gtk/res/login.gtk2.ui +++ /dev/null @@ -1,223 +0,0 @@ -<?xml version="1.0"?> -<!--*- mode: xml -*--> -<interface> - <object class="GtkDialog" id="wndLogin"> - <property name="title" translatable="yes">Site Authentication</property> - <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox2"> - <property name="visible">True</property> - <child> - <object class="GtkHBox" id="hbox12"> - <property name="visible">True</property> - <property name="border_width">3</property> - <child> - <object class="GtkImage" id="image3"> - <property name="visible">True</property> - <property name="yalign">0.10000000149011612</property> - <property name="xpad">12</property> - <property name="icon_size">6</property> - <property name="icon_name">gtk-dialog-authentication</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkTable" id="table5"> - <property name="visible">True</property> - <property name="border_width">1</property> - <property name="n_rows">4</property> - <property name="n_columns">2</property> - <property name="column_spacing">11</property> - <property name="row_spacing">10</property> - <child> - <object class="GtkLabel" id="labelLoginHost"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">moo.yoo.com</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label57"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password</property> - </object> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label56"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Username</property> - </object> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label54"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host</property> - </object> - <packing> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label55"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Realm</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="labelLoginRealm"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">my sekr3t area</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkEntry" id="entryLoginPass"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="visibility">False</property> - <property name="activates_default">True</property> - <property name="text" translatable="yes">opensesame</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"/> - </packing> - </child> - <child> - <object class="GtkEntry" id="entryLoginUser"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="has_focus">True</property> - <property name="text" translatable="yes">sesame</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"/> - </packing> - </child> - </object> - <packing> - <property name="padding">1</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area2"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <object class="GtkButton" id="buttonLoginCan"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label">gtk-cancel</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkButton" id="buttonLoginOK"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <child> - <object class="GtkAlignment" id="alignment14"> - <property name="visible">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox11"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image2"> - <property name="visible">True</property> - <property name="stock">gtk-ok</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label49"> - <property name="visible">True</property> - <property name="label" translatable="yes">Login</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">buttonLoginCan</action-widget> - <action-widget response="-5">buttonLoginOK</action-widget> - </action-widgets> - </object> -</interface> diff --git a/frontends/gtk/res/login.gtk3.ui b/frontends/gtk/res/login.gtk3.ui deleted file mode 100644 index 552b173ed..000000000 --- a/frontends/gtk/res/login.gtk3.ui +++ /dev/null @@ -1,223 +0,0 @@ -<?xml version="1.0"?> -<!--*- mode: xml -*--> -<interface> - <object class="GtkDialog" id="wndLogin"> - <property name="title" translatable="yes">Site Authentication</property> - <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox2"> - <property name="visible">True</property> - <child> - <object class="GtkHBox" id="hbox12"> - <property name="visible">True</property> - <property name="border_width">3</property> - <child> - <object class="GtkImage" id="image3"> - <property name="visible">True</property> - <property name="yalign">0.10000000149011612</property> - <property name="xpad">12</property> - <property name="icon_size">6</property> - <property name="icon_name">gtk-dialog-authentication</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkTable" id="table5"> - <property name="visible">True</property> - <property name="border_width">1</property> - <property name="n_rows">4</property> - <property name="n_columns">2</property> - <property name="column_spacing">11</property> - <property name="row_spacing">10</property> - <child> - <object class="GtkLabel" id="labelLoginHost"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">moo.yoo.com</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label57"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password</property> - </object> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label56"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Username</property> - </object> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label54"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host</property> - </object> - <packing> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="label55"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Realm</property> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkLabel" id="labelLoginRealm"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">my sekr3t area</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"/> - </packing> - </child> - <child> - <object class="GtkEntry" id="entryLoginPass"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="visibility">False</property> - <property name="activates_default">True</property> - <property name="text" translatable="yes">opensesame</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"/> - </packing> - </child> - <child> - <object class="GtkEntry" id="entryLoginUser"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="has_focus">True</property> - <property name="text" translatable="yes">sesame</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"/> - </packing> - </child> - </object> - <packing> - <property name="padding">1</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area2"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <object class="GtkButton" id="buttonLoginCan"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label">gtk-cancel</property> - <property name="use_stock">True</property> - </object> - </child> - <child> - <object class="GtkButton" id="buttonLoginOK"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <child> - <object class="GtkAlignment" id="alignment14"> - <property name="visible">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox11"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image2"> - <property name="visible">True</property> - <property name="stock">gtk-ok</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label49"> - <property name="visible">True</property> - <property name="label" translatable="yes">Login</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">buttonLoginCan</action-widget> - <action-widget response="-5">buttonLoginOK</action-widget> - </action-widgets> - </object> -</interface> diff --git a/frontends/gtk/res/maps.html b/frontends/gtk/res/maps.html deleted file mode 120000 index a32f725fb..000000000 --- a/frontends/gtk/res/maps.html +++ /dev/null @@ -1 +0,0 @@ -en/maps.html
\ No newline at end of file diff --git a/frontends/gtk/res/messages.gresource.xml b/frontends/gtk/res/messages.gresource.xml index 684a10862..6da406245 100644 --- a/frontends/gtk/res/messages.gresource.xml +++ b/frontends/gtk/res/messages.gresource.xml @@ -6,5 +6,6 @@ <file>de/Messages</file> <file>fr/Messages</file> <file>it/Messages</file> + <file>zh_CN/Messages</file> </gresource> </gresources> diff --git a/frontends/gtk/res/netsurf.gresource.xml b/frontends/gtk/res/netsurf.gresource.xml index e8243254a..21a2e7723 100644 --- a/frontends/gtk/res/netsurf.gresource.xml +++ b/frontends/gtk/res/netsurf.gresource.xml @@ -1,34 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <gresources> <gresource prefix="/org/netsurf"> - <file>cookies.gtk2.ui</file> - <file>globalhistory.gtk3.ui</file> - <file>localhistory.gtk3.ui</file> - <file>netsurf.gtk2.ui</file> - <file>password.gtk3.ui</file> - <file>toolbar.gtk2.ui</file> - <file>warning.gtk3.ui</file> - <file>cookies.gtk3.ui</file> - <file>hotlist.gtk2.ui</file> - <file>netsurf.gtk3.ui</file> - <file>ssl.gtk2.ui</file> - <file>toolbar.gtk3.ui</file> - <file>downloads.gtk2.ui</file> - <file>hotlist.gtk3.ui</file> - <file>options.gtk2.ui</file> - <file>ssl.gtk3.ui</file> - <file>viewdata.gtk2.ui</file> - <file>downloads.gtk3.ui</file> - <file>login.gtk2.ui</file> - <file>options.gtk3.ui</file> - <file>tabcontents.gtk2.ui</file> - <file>viewdata.gtk3.ui</file> - <file>localhistory.gtk2.ui</file> - <file>globalhistory.gtk2.ui</file> - <file>login.gtk3.ui</file> - <file>password.gtk2.ui</file> - <file>tabcontents.gtk3.ui</file> - <file>warning.gtk2.ui</file> <file preprocess="to-pixdata">favicon.png</file> <file preprocess="to-pixdata">netsurf.xpm</file> <file preprocess="to-pixdata">menu_cursor.png</file> @@ -42,24 +14,30 @@ <file preprocess="to-pixdata">throbber/throbber7.png</file> <file preprocess="to-pixdata">throbber/throbber8.png</file> <file>credits.html</file> + <file>fr/credits.html</file> <file>it/credits.html</file> <file>nl/credits.html</file> + <file>zh_CN/credits.html</file> <file>licence.html</file> + <file>fr/licence.html</file> <file>it/licence.html</file> <file>nl/licence.html</file> + <file>zh_CN/licence.html</file> <file>welcome.html</file> <file>de/welcome.html</file> + <file>fr/welcome.html</file> <file>it/welcome.html</file> <file>ja/welcome.html</file> <file>nl/welcome.html</file> - <file>maps.html</file> + <file>zh_CN/welcome.html</file> <file>adblock.css</file> <file>default.css</file> <file>internal.css</file> <file>quirks.css</file> <file>netsurf.png</file> <file>default.ico</file> - <file>arrow_down_8x32.png</file> + <file>icons/show-cookie.png</file> + <file>icons/local-history.png</file> <file>icons/arrow-l.png</file> <file>icons/content.png</file> <file>icons/directory2.png</file> @@ -67,6 +45,16 @@ <file>icons/hotlist-add.png</file> <file>icons/hotlist-rmv.png</file> <file>icons/search.png</file> + <file>icons/24x24/actions/page-info-insecure.png</file> + <file>icons/24x24/actions/page-info-internal.png</file> + <file>icons/24x24/actions/page-info-local.png</file> + <file>icons/24x24/actions/page-info-secure.png</file> + <file>icons/24x24/actions/page-info-warning.png</file> + <file>icons/48x48/actions/page-info-insecure.png</file> + <file>icons/48x48/actions/page-info-internal.png</file> + <file>icons/48x48/actions/page-info-local.png</file> + <file>icons/48x48/actions/page-info-secure.png</file> + <file>icons/48x48/actions/page-info-warning.png</file> <file>languages</file> <file>accelerators</file> </gresource> diff --git a/frontends/gtk/res/netsurf.gtk2.ui b/frontends/gtk/res/netsurf.gtk2.ui deleted file mode 100644 index 68812b364..000000000 --- a/frontends/gtk/res/netsurf.gtk2.ui +++ /dev/null @@ -1,212 +0,0 @@ -<?xml version="1.0"?> -<!--Generated with glade3 3.4.5 on Wed Apr 7 17:10:28 2010 --> -<interface> - <object class="GtkAdjustment" id="adjustment1"> - <property name="upper">100</property> - <property name="lower">0</property> - <property name="page_increment">10</property> - <property name="step_increment">26</property> - <property name="page_size">10</property> - <property name="value">0.5357142857142857</property> - </object> - <object class="GtkAdjustment" id="adjustment2"> - <property name="upper">100</property> - <property name="lower">0</property> - <property name="page_increment">10</property> - <property name="step_increment">26</property> - <property name="page_size">10</property> - <property name="value">0</property> - </object> - <object class="GtkUIManager" id="uimanager1"> - <ui> - <menubar name="menubar"/> - </ui> - </object> - <object class="GtkWindow" id="wndBrowser"> - <property name="title" translatable="yes">NetSurf</property> - <property name="window_position">GTK_WIN_POS_CENTER</property> - <child> - <object class="GtkVBox" id="vbox14"> - <property name="visible">True</property> - <child> - <object class="GtkMenuBar" constructor="uimanager1" id="menubar"> - <property name="visible">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="toolbar"> - <property name="visible">True</property> - <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="searchbar"> - <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> - <child> - <object class="GtkToolButton" id="closeSearchButton"> - <property name="visible">True</property> - <property name="stock_id">gtk-close</property> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="searchLabelItem"> - <property name="visible">True</property> - <child> - <object class="GtkLabel" id="searchlabel"> - <property name="visible">True</property> - <property name="xpad">4</property> - <property name="label" translatable="yes">Match</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="toolSearch"> - <property name="visible">True</property> - <child> - <object class="GtkEntry" id="searchEntry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="searchBackButton"> - <property name="visible">True</property> - <property name="label" translatable="yes">Search _Back</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-back</property> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="searchForwardButton"> - <property name="visible">True</property> - <property name="label" translatable="yes">Search _Forward</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-forward</property> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="checkAllSearchItem"> - <property name="visible">True</property> - <child> - <object class="GtkCheckButton" id="checkAllSearch"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="tooltip-text" translatable="yes">show all matches</property> - <property name="label" translatable="yes">All </property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="caseSensItem"> - <property name="visible">True</property> - <child> - <object class="GtkCheckButton" id="caseSensButton"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="tooltip-text" translatable="yes">Match case when searching</property> - <property name="label" translatable="yes">Case</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkNotebook" id="notebook"> - <property name="visible">True</property> - <property name="show_tabs">False</property> - <property name="show_border">False</property> - <property name="scrollable">True</property> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - </object> - <packing> - <property name="position">3</property> - </packing> - </child> - </object> - </child> - </object> -</interface> diff --git a/frontends/gtk/res/netsurf.gtk3.ui b/frontends/gtk/res/netsurf.gtk3.ui deleted file mode 100644 index ce47c6370..000000000 --- a/frontends/gtk/res/netsurf.gtk3.ui +++ /dev/null @@ -1,207 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 3.0 --> - <object class="GtkWindow" id="wndBrowser"> - <property name="can_focus">False</property> - <child> - <object class="GtkBox" id="box1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkMenuBar" id="menubar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="toolbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="toolbar_style">both</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkToolbar" id="searchbar"> - <property name="can_focus">False</property> - <property name="toolbar_style">both</property> - <child> - <object class="GtkToolButton" id="closeSearchButton"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <property name="label" translatable="yes">gtk-close</property> - <property name="stock_id">gtk-close</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="searchLabelItem"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <child> - <object class="GtkLabel" id="searchlabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xpad">4</property> - <property name="label" translatable="yes">Match</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="toolSearch"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <child> - <object class="GtkEntry" id="searchEntry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="searchBackButton"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <property name="label" translatable="yes">Search _Back</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-back</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="searchForwardButton"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <property name="label" translatable="yes">Search _Forward</property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-go-forward</property> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">True</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="checkAllSearchItem"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <child> - <object class="GtkCheckButton" id="checkAllSearch"> - <property name="label" translatable="yes">All</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_action_appearance">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - <child> - <object class="GtkToolItem" id="caseSensItem"> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="use_action_appearance">False</property> - <child> - <object class="GtkCheckButton" id="caseSensButton"> - <property name="label" translatable="yes">Case</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_action_appearance">False</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkNotebook" id="notebook"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="show_tabs">False</property> - <property name="show_border">False</property> - <property name="scrollable">True</property> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child type="tab"> - <placeholder/> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">3</property> - </packing> - </child> - </object> - </child> - </object> -</interface> diff --git a/frontends/gtk/res/ssl.gtk2.ui b/frontends/gtk/res/ssl.gtk2.ui deleted file mode 100644 index 90f449ddd..000000000 --- a/frontends/gtk/res/ssl.gtk2.ui +++ /dev/null @@ -1,202 +0,0 @@ -<?xml version="1.0"?> -<!--*- mode: xml -*--> -<interface> - <object class="GtkDialog" id="wndSSLProblem"> - <property name="border_width">1</property> - <property name="title" translatable="yes">SSL certificate problem</property> - <property name="modal">True</property> - <property name="default_width">500</property> - <property name="default_height">250</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox3"> - <property name="visible">True</property> - <child> - <object class="GtkHBox" id="hbox15"> - <property name="visible">True</property> - <child> - <object class="GtkImage" id="image6"> - <property name="visible">True</property> - <property name="yalign">0</property> - <property name="icon_size">6</property> - <property name="icon_name">gtk-dialog-warning</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkVBox" id="vbox13"> - <property name="visible">True</property> - <child> - <object class="GtkLabel" id="label62"> - <property name="visible">True</property> - <property name="label" translatable="yes">NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.</property> - <property name="justify">GTK_JUSTIFY_CENTER</property> - <property name="wrap">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame13"> - <property name="visible">True</property> - <property name="border_width">5</property> - <property name="label_xalign">0</property> - <child> - <object class="GtkAlignment" id="alignment17"> - <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <object class="GtkScrolledWindow" id="SSLScrolled"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">GTK_SHADOW_IN</property> - <child> - <object class="GtkViewport" id="SSLViewport"> - <property name="visible">True</property> - <property name="resize_mode">GTK_RESIZE_QUEUE</property> - <child> - <object class="GtkDrawingArea" id="SSLDrawingArea"> - <property name="visible">True</property> - <property name="app_paintable">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label63"> - <property name="visible">True</property> - <property name="label" translatable="yes"><b>Certificate chain</b></property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="position">2</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area3"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <object class="GtkButton" id="sslreject"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <child> - <object class="GtkAlignment" id="alignment16"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox14"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image5"> - <property name="visible">True</property> - <property name="stock">gtk-cancel</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label61"> - <property name="visible">True</property> - <property name="label" translatable="yes">Reject</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkButton" id="sslaccept"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <child> - <object class="GtkAlignment" id="alignment15"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <object class="GtkHBox" id="hbox13"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <object class="GtkImage" id="image4"> - <property name="visible">True</property> - <property name="stock">gtk-apply</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label60"> - <property name="visible">True</property> - <property name="label" translatable="yes">Accept</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">sslreject</action-widget> - <action-widget response="-5">sslaccept</action-widget> - </action-widgets> - </object> -</interface> diff --git a/frontends/gtk/res/ssl.gtk3.ui b/frontends/gtk/res/ssl.gtk3.ui deleted file mode 100644 index dace2a49e..000000000 --- a/frontends/gtk/res/ssl.gtk3.ui +++ /dev/null @@ -1,181 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 3.0 --> - <object class="GtkImage" id="image2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-apply</property> - </object> - <object class="GtkImage" id="image3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-cancel</property> - </object> - <object class="GtkDialog" id="wndSSLProblem"> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="default_width">440</property> - <property name="default_height">260</property> - <property name="destroy_with_parent">True</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox1"> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area1"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="sslreject"> - <property name="label" translatable="yes">_Reject</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_action_appearance">False</property> - <property name="image">image3</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="sslaccept"> - <property name="label" translatable="yes">_Accept</property> - <property name="use_action_appearance">False</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_action_appearance">False</property> - <property name="image">image2</property> - <property name="use_underline">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox" id="box1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkBox" id="box2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkImage" id="image1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="margin_right">8</property> - <property name="stock">gtk-dialog-warning</property> - <property name="icon-size">6</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.</property> - <property name="wrap">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="frame1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkAlignment" id="alignment1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="left_padding">12</property> - <child> - <object class="GtkScrolledWindow" id="SSLScrolled"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkViewport" id="SSLViewport"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkDrawingArea" id="SSLDrawingArea"> - <property name="visible">True</property> - <property name="app_paintable">True</property> - <property name="can_focus">True</property> - <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property> - <property name="valign">start</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes"><b>Certificate Chain</b></property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="-6">sslreject</action-widget> - <action-widget response="-5">sslaccept</action-widget> - </action-widgets> - </object> -</interface> diff --git a/frontends/gtk/res/tabcontents.gtk2.ui b/frontends/gtk/res/tabcontents.gtk2.ui deleted file mode 100644 index 63e290e8b..000000000 --- a/frontends/gtk/res/tabcontents.gtk2.ui +++ /dev/null @@ -1,92 +0,0 @@ -<?xml version="1.0"?> -<interface> - <!-- interface-requires gtk+ 2.12 --> - <!-- interface-naming-policy toplevel-contextual --> - <object class="GtkTable" id="tabContents"> - <property name="visible">True</property> - <property name="n_rows">2</property> - <property name="n_columns">2</property> - <child> - <object class="GtkLayout" id="layout"> - <property name="visible">True</property> - <property name="app_paintable">True</property> - <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property> - <property name="hadjustment">layouthadjustment</property> - <property name="vadjustment">layoutvadjustment</property> - </object> - </child> - <child> - <object class="GtkStatusbar" id="resizer"> - <property name="height_request">1</property> - <property name="visible">True</property> - <property name="spacing">2</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkHPaned" id="hpaned1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkLabel" id="status_bar"> - <property name="width_request">1</property> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes">Status</property> - </object> - <packing> - <property name="resize">False</property> - <property name="shrink">False</property> - </packing> - </child> - <child> - <object class="GtkHScrollbar" id="hscrollbar"> - <property name="visible">True</property> - <property name="adjustment">layouthadjustment</property> - </object> - <packing> - <property name="resize">True</property> - <property name="shrink">True</property> - </packing> - </child> - </object> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <object class="GtkVScrollbar" id="vscrollbar"> - <property name="visible">True</property> - <property name="orientation">vertical</property> - <property name="adjustment">layoutvadjustment</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options"></property> - </packing> - </child> - </object> - <object class="GtkAdjustment" id="layouthadjustment"> - <property name="upper">100</property> - <property name="step_increment">30</property> - <property name="page_increment">10</property> - <property name="page_size">10</property> - </object> - <object class="GtkAdjustment" id="layoutvadjustment"> - <property name="upper">100</property> - <property name="step_increment">30</property> - <property name="page_increment">10</property> - <property name="page_size">10</property> - </object> -</interface> diff --git a/frontends/gtk/res/tabcontents.gtk3.ui b/frontends/gtk/res/tabcontents.gtk3.ui deleted file mode 100644 index 23328b3b7..000000000 --- a/frontends/gtk/res/tabcontents.gtk3.ui +++ /dev/null @@ -1,92 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 3.0 --> - <object class="GtkAdjustment" id="layouthadjustment"> - <property name="upper">100</property> - <property name="step_increment">1</property> - <property name="page_increment">10</property> - </object> - <object class="GtkAdjustment" id="layoutvadjustment"> - <property name="upper">100</property> - <property name="step_increment">1</property> - <property name="page_increment">10</property> - </object> - <object class="GtkGrid" id="tabContents"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="row_spacing">2</property> - <property name="column_spacing">2</property> - <child> - <object class="GtkLayout" id="layout"> - <property name="visible">True</property> - <property name="app_paintable">True</property> - <property name="can_focus">False</property> - <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property> - <property name="hadjustment">layouthadjustment</property> - <property name="vadjustment">layoutvadjustment</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkScrollbar" id="vscrollbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="vexpand">True</property> - <property name="orientation">vertical</property> - <property name="adjustment">layoutvadjustment</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkPaned" id="hpaned1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hexpand">True</property> - <child> - <object class="GtkLabel" id="status_bar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes">Status</property> - <property name="single_line_mode">True</property> - </object> - <packing> - <property name="resize">False</property> - <property name="shrink">True</property> - </packing> - </child> - <child> - <object class="GtkScrollbar" id="hscrollbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="adjustment">layouthadjustment</property> - </object> - <packing> - <property name="resize">True</property> - <property name="shrink">True</property> - </packing> - </child> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <placeholder/> - </child> - </object> -</interface> diff --git a/frontends/gtk/res/toolbar.gtk2.ui b/frontends/gtk/res/toolbar.gtk2.ui deleted file mode 100644 index 4e8805a6f..000000000 --- a/frontends/gtk/res/toolbar.gtk2.ui +++ /dev/null @@ -1,172 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 2.12 --> - <!-- interface-naming-policy toplevel-contextual --> - <object class="GtkDialog" id="dialogToolbar"> - <property name="width_request">700</property> - <property name="height_request">450</property> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">gtkToolBarTitle</property> - <property name="window_position">center-on-parent</property> - <property name="destroy_with_parent">True</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkVBox" id="dialog-vbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">2</property> - <child> - <object class="GtkHBox" id="hbox1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="homogeneous">True</property> - <child> - <object class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Move items from store to toolbar</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Rearrange items in toolbar</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Move items from toolbar to store</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="padding">2</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> - <child> - <object class="GtkViewport" id="viewport1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkVBox" id="widgetvbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <placeholder/> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child internal-child="action_area"> - <object class="GtkHButtonBox" id="dialog-action_area1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="reset"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <child> - <object class="GtkHBox" id="button1hbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkImage" id="image1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-refresh</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="refreshbuttonlabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Reset to defaults</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="padding">10</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="close"> - <property name="label">gtk-close</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="0">reset</action-widget> - <action-widget response="0">close</action-widget> - </action-widgets> - </object> -</interface> diff --git a/frontends/gtk/res/toolbar.gtk3.ui b/frontends/gtk/res/toolbar.gtk3.ui deleted file mode 100644 index 1f1148703..000000000 --- a/frontends/gtk/res/toolbar.gtk3.ui +++ /dev/null @@ -1,137 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.18.3 --> -<!--*- mode: xml -*--> -<interface> - <requires lib="gtk+" version="3.0"/> - <object class="GtkImage" id="image2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-refresh</property> - </object> - <object class="GtkDialog" id="dialogToolbar"> - <property name="width_request">700</property> - <property name="height_request">450</property> - <property name="can_focus">False</property> - <property name="title" translatable="yes">gtkToolBarTitle</property> - <property name="type_hint">dialog</property> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox1"> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">2</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="dialog-action_area1"> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="reset"> - <property name="label" translatable="yes">Reset To Defaults</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="image">image2</property> - <property name="yalign">0.52999997138977051</property> - <property name="always_show_image">True</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="close"> - <property name="label">gtk-close</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_stock">True</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkGrid" id="grid1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="column_homogeneous">True</property> - <child> - <object class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Move items from store to toolbar</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Rearrange items in toolbar</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Move items from toolbar to store</property> - </object> - <packing> - <property name="left_attach">2</property> - <property name="top_attach">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkViewport" id="viewport1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkVBox" id="widgetvbox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <placeholder/> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> - </child> - </object> -</interface> diff --git a/frontends/gtk/res/ui.gresource.xml b/frontends/gtk/res/ui.gresource.xml new file mode 100644 index 000000000..dd43ddf59 --- /dev/null +++ b/frontends/gtk/res/ui.gresource.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/netsurf"> + <file>cookies.ui</file> + <file>downloads.ui</file> + <file>globalhistory.ui</file> + <file>hotlist.ui</file> + <file>localhistory.ui</file> + <file>netsurf.ui</file> + <file>options.ui</file> + <file>pageinfo.ui</file> + <file>password.ui</file> + <file>tabcontents.ui</file> + <file>toolbar.ui</file> + <file>viewdata.ui</file> + <file>warning.ui</file> + </gresource> +</gresources> diff --git a/frontends/gtk/res/zh_CN/credits.html b/frontends/gtk/res/zh_CN/credits.html new file mode 120000 index 000000000..6fd96ea63 --- /dev/null +++ b/frontends/gtk/res/zh_CN/credits.html @@ -0,0 +1 @@ +../../../../resources/zh_CN/credits.html
\ No newline at end of file diff --git a/frontends/gtk/res/zh_CN/licence.html b/frontends/gtk/res/zh_CN/licence.html new file mode 120000 index 000000000..d757031d5 --- /dev/null +++ b/frontends/gtk/res/zh_CN/licence.html @@ -0,0 +1 @@ +../../../../resources/zh_CN/licence.html
\ No newline at end of file diff --git a/frontends/gtk/res/zh_CN/welcome.html b/frontends/gtk/res/zh_CN/welcome.html new file mode 120000 index 000000000..fa10c2a20 --- /dev/null +++ b/frontends/gtk/res/zh_CN/welcome.html @@ -0,0 +1 @@ +../../../../resources/zh_CN/welcome.html
\ No newline at end of file diff --git a/frontends/gtk/resources.c b/frontends/gtk/resources.c index fc3ac6ff3..fc17f7418 100644 --- a/frontends/gtk/resources.c +++ b/frontends/gtk/resources.c @@ -77,8 +77,6 @@ static struct nsgtk_resource_s ui_resource[] = { RES_ENTRY("netsurf"), RES_ENTRY("tabcontents"), RES_ENTRY("password"), - RES_ENTRY("login"), - RES_ENTRY("ssl"), RES_ENTRY("toolbar"), RES_ENTRY("downloads"), RES_ENTRY("globalhistory"), @@ -88,6 +86,7 @@ static struct nsgtk_resource_s ui_resource[] = { RES_ENTRY("cookies"), RES_ENTRY("viewdata"), RES_ENTRY("warning"), + RES_ENTRY("pageinfo"), { NULL, 0, NSGTK_RESOURCE_FILE, NULL }, }; @@ -96,7 +95,18 @@ static struct nsgtk_resource_s pixbuf_resource[] = { RES_ENTRY("favicon.png"), RES_ENTRY("netsurf.xpm"), RES_ENTRY("menu_cursor.png"), - RES_ENTRY("arrow_down_8x32.png"), + RES_ENTRY("icons/local-history.png"), + RES_ENTRY("icons/show-cookie.png"), + RES_ENTRY("icons/24x24/actions/page-info-insecure.png"), + RES_ENTRY("icons/24x24/actions/page-info-internal.png"), + RES_ENTRY("icons/24x24/actions/page-info-local.png"), + RES_ENTRY("icons/24x24/actions/page-info-secure.png"), + RES_ENTRY("icons/24x24/actions/page-info-warning.png"), + RES_ENTRY("icons/48x48/actions/page-info-insecure.png"), + RES_ENTRY("icons/48x48/actions/page-info-internal.png"), + RES_ENTRY("icons/48x48/actions/page-info-local.png"), + RES_ENTRY("icons/48x48/actions/page-info-secure.png"), + RES_ENTRY("icons/48x48/actions/page-info-warning.png"), RES_ENTRY("throbber/throbber0.png"), RES_ENTRY("throbber/throbber1.png"), RES_ENTRY("throbber/throbber2.png"), @@ -114,7 +124,6 @@ static struct nsgtk_resource_s direct_resource[] = { RES_ENTRY("welcome.html"), RES_ENTRY("credits.html"), RES_ENTRY("licence.html"), - RES_ENTRY("maps.html"), RES_ENTRY("default.css"), RES_ENTRY("adblock.css"), RES_ENTRY("internal.css"), @@ -336,11 +345,6 @@ init_pixbuf_resource(char **respath, struct nsgtk_resource_s *resource) */ static nserror init_ui_resource(char **respath, struct nsgtk_resource_s *ui_res) { -#if GTK_CHECK_VERSION(3,0,0) - int gtkv = 3; -#else - int gtkv = 2; -#endif int resnamelen; char *resname; struct nsgtk_resource_s resource; @@ -352,7 +356,7 @@ static nserror init_ui_resource(char **respath, struct nsgtk_resource_s *ui_res) if (resname == NULL) { return NSERROR_NOMEM; } - snprintf(resname, resnamelen, "%s.gtk%d.ui", ui_res->name, gtkv); + snprintf(resname, resnamelen, "%s.ui", ui_res->name); resource.name = resname; resource.len = ui_res->len; resource.path = NULL; diff --git a/frontends/gtk/scaffolding.c b/frontends/gtk/scaffolding.c index 6f81e91db..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,80 +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); - - gtk_menu_popup(g->menu_popup->popup_menu, NULL, NULL, NULL, NULL, 0, - gtk_get_current_event_time()); - + nsgtk_scaffolding_enable_edit_actions_sensitivity(g); return TRUE; } @@ -544,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 @@ -557,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); } @@ -570,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 @@ -581,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. @@ -595,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_get_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_get_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_get_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; @@ -1084,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; @@ -1106,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; @@ -1119,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, @@ -1129,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; @@ -1147,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; @@ -1165,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_get_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; @@ -1791,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. * @@ -1821,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; @@ -1831,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; } @@ -2321,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) @@ -2541,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 */ @@ -2587,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) @@ -2642,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) { @@ -2657,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) @@ -2707,86 +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); } - gtk_menu_popup(gtkmenu, NULL, NULL, NULL, NULL, 0, - gtk_get_current_event_time()); + 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); } diff --git a/frontends/gtk/scaffolding.h b/frontends/gtk/scaffolding.h index e1fd9bf2a..87d4f3bd6 100644 --- a/frontends/gtk/scaffolding.h +++ b/frontends/gtk/scaffolding.h @@ -27,91 +27,8 @@ struct hlcache_handle; struct gui_window; struct gui_search_web_table; struct nsurl; +struct nsgtk_pi_window; -extern struct gui_search_web_table *nsgtk_search_web_table; - -typedef enum { - BACK_BUTTON = 0, - HISTORY_BUTTON, - FORWARD_BUTTON, - STOP_BUTTON, - RELOAD_BUTTON, - HOME_BUTTON, - URL_BAR_ITEM, - WEBSEARCH_ITEM, - THROBBER_ITEM, - NEWWINDOW_BUTTON, - NEWTAB_BUTTON, - OPENFILE_BUTTON, - CLOSETAB_BUTTON, - CLOSEWINDOW_BUTTON, - SAVEPAGE_BUTTON, - PDF_BUTTON, - PLAINTEXT_BUTTON, - DRAWFILE_BUTTON, - POSTSCRIPT_BUTTON, - PRINTPREVIEW_BUTTON, - PRINT_BUTTON, - QUIT_BUTTON, - CUT_BUTTON, - COPY_BUTTON, - PASTE_BUTTON, - DELETE_BUTTON, - SELECTALL_BUTTON, - FIND_BUTTON, - PREFERENCES_BUTTON, - ZOOMPLUS_BUTTON, - ZOOMMINUS_BUTTON, - ZOOMNORMAL_BUTTON, - FULLSCREEN_BUTTON, - VIEWSOURCE_BUTTON, - DOWNLOADS_BUTTON, - SAVEWINDOWSIZE_BUTTON, - TOGGLEDEBUGGING_BUTTON, - SAVEBOXTREE_BUTTON, - SAVEDOMTREE_BUTTON, - LOCALHISTORY_BUTTON, - GLOBALHISTORY_BUTTON, - ADDBOOKMARKS_BUTTON, - SHOWBOOKMARKS_BUTTON, - SHOWCOOKIES_BUTTON, - OPENLOCATION_BUTTON, - NEXTTAB_BUTTON, - PREVTAB_BUTTON, - CONTENTS_BUTTON, - GUIDE_BUTTON, - INFO_BUTTON, - ABOUT_BUTTON, - PLACEHOLDER_BUTTON /* size indicator; array maximum indices */ -} nsgtk_toolbar_button; /* PLACEHOLDER_BUTTON - 1 */ - -struct gtk_history_window { - struct nsgtk_scaffolding *g; - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; -}; - -struct gtk_search { - GtkToolbar *bar; - GtkEntry *entry; - GtkToolButton *buttons[3]; /* back, forward, */ - GtkCheckButton *checkAll; /* close */ - GtkCheckButton *caseSens; -}; - -struct nsgtk_button_connect { - GtkToolItem *button; - int location; /* in toolbar */ - bool sensitivity; - GtkWidget *main; /* left click menu entry */ - GtkWidget *rclick; /* right click menu */ - GtkWidget *popup; /* popup menu entry */ - void *mhandler; /* menu item clicked */ - void *bhandler; /* button clicked */ - void *dataplus; /* customization -> toolbar */ - void *dataminus; /* customization -> store */ -}; /** * create a new scaffolding for a window. @@ -122,69 +39,75 @@ struct nsgtk_button_connect { struct nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *gw); /** - * Obtain the most recently used scaffolding element. + * causes all scaffolding windows to be destroyed. * - * This allows tabs to be opened in the most recently used window + * \return NSERROR_OK and all scaffolding windows destroyed else + * NSERROR_INVALID if download in progress and user continued. */ -struct nsgtk_scaffolding *nsgtk_current_scaffolding(void); +nserror nsgtk_scaffolding_destroy_all(void); -/* acessors for gtk elements within a scaffold */ +/** + * Update scaffolding window when throbber state changes + */ +nserror nsgtk_scaffolding_throbber(struct gui_window* gw, bool active); /** - * Get the gtk window for a scaffolding. + * open the toolbar context menu */ -GtkWindow *nsgtk_scaffolding_window(struct nsgtk_scaffolding *g); +nserror nsgtk_scaffolding_toolbar_context_menu(struct nsgtk_scaffolding *gs); /** - * Get the gtk notebook from a scaffold. + * Position the page-info popup in the right place + * + * \param gs The scaffolding to position relative to + * \param win The page-info window to position */ -GtkNotebook *nsgtk_scaffolding_notebook(struct nsgtk_scaffolding *g); +nserror nsgtk_scaffolding_position_page_info(struct nsgtk_scaffolding *gs, + struct nsgtk_pi_window *win); /** - * Get the gtk url bar from a scaffold. + * Position the local-history popup in the right place + * + * \param gs The scaffolding to position relative to */ -GtkWidget *nsgtk_scaffolding_urlbar(struct nsgtk_scaffolding *g); +nserror nsgtk_scaffolding_position_local_history(struct nsgtk_scaffolding *gs); /** - * Get the gtk web search entry from a scaffold. + * open the burger menu */ -GtkWidget *nsgtk_scaffolding_websearch(struct nsgtk_scaffolding *g); +nserror nsgtk_scaffolding_burger_menu(struct nsgtk_scaffolding *gs); /** - * Get the gtk toolbar from a scaffold. + * Obtain the most recently used scaffolding element. + * + * This allows tabs to be opened in the most recently used window */ -GtkToolbar *nsgtk_scaffolding_toolbar(struct nsgtk_scaffolding *g); +struct nsgtk_scaffolding *nsgtk_current_scaffolding(void); +/* acessors for gtk elements within a scaffold */ -struct nsgtk_button_connect *nsgtk_scaffolding_button(struct nsgtk_scaffolding *g, int i); +/** + * Get the gtk window for a scaffolding. + */ +GtkWindow *nsgtk_scaffolding_window(struct nsgtk_scaffolding *g); + +/** + * Get the gtk notebook from a scaffold. + */ +GtkNotebook *nsgtk_scaffolding_notebook(struct nsgtk_scaffolding *g); struct gtk_search *nsgtk_scaffolding_search(struct nsgtk_scaffolding *g); GtkMenuBar *nsgtk_scaffolding_menu_bar(struct nsgtk_scaffolding *g); -struct gtk_history_window *nsgtk_scaffolding_history_window(struct nsgtk_scaffolding *g); - struct gui_window *nsgtk_scaffolding_top_level(struct nsgtk_scaffolding *g); -/** - * reset the scaffold offset value to 0. - * - * \todo The value is only ever altered in - * nsgtk_scaffolding_toolbar_size_allocate and is something to do with - * the history button either clarify or remove! - */ -void nsgtk_scaffolding_reset_offset(struct nsgtk_scaffolding *g); /** * Iterate through available scaffolding. */ struct nsgtk_scaffolding *nsgtk_scaffolding_iterate(struct nsgtk_scaffolding *g); -void nsgtk_scaffolding_update_url_bar_ref(struct nsgtk_scaffolding *g); - -void nsgtk_scaffolding_update_throbber_ref(struct nsgtk_scaffolding *g); - -void nsgtk_scaffolding_update_websearch_ref(struct nsgtk_scaffolding *g); void nsgtk_scaffolding_toggle_search_bar_visibility(struct nsgtk_scaffolding *g); @@ -224,29 +147,20 @@ void nsgtk_scaffolding_set_sensitivity(struct nsgtk_scaffolding *g); */ void nsgtk_scaffolding_context_menu(struct nsgtk_scaffolding *g, gdouble x, gdouble y); -void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget, GtkAllocation *alloc, gpointer data); - -void nsgtk_scaffolding_set_icon(struct gui_window *gw); - -gboolean nsgtk_window_url_activate_event(GtkWidget *, gpointer); - -gboolean nsgtk_window_url_changed(GtkWidget *, GdkEventKey *, gpointer); - -nserror nsgtk_scaffolding_new_tab(struct gui_window *gw); - -/* core acessors */ /** * set the title in the window * * \param gw The gui window to set title on * \param title The title to set which may be NULL */ -void nsgtk_window_set_title(struct gui_window *gw, const char *title); - -nserror gui_window_set_url(struct gui_window *g, struct nsurl *url); -void gui_window_start_throbber(struct gui_window *g); -void gui_window_stop_throbber(struct gui_window *g); +void nsgtk_scaffolding_set_title(struct gui_window *gw, const char *title); -void nsgtk_scaffolding_toolbars(struct nsgtk_scaffolding *g, int tbi); +/** + * find which scaffolding contains a gtk notebook + * + * \param notebook The notebook to search for. + * \return The scaffolding containing the notebook or NULL if not found + */ +struct nsgtk_scaffolding *nsgtk_scaffolding_from_notebook(GtkNotebook *notebook); #endif /* NETSURF_GTK_SCAFFOLDING_H */ diff --git a/frontends/gtk/schedule.c b/frontends/gtk/schedule.c index d5b45674b..69678924d 100644 --- a/frontends/gtk/schedule.c +++ b/frontends/gtk/schedule.c @@ -28,9 +28,9 @@ /** Killable callback closure embodiment. */ typedef struct { - void (*callback)(void *); /**< The callback function. */ - void *context; /**< The context for the callback. */ - bool callback_killed; /**< Whether or not this was killed. */ + void (*callback)(void *); /**< The callback function. */ + void *context; /**< The context for the callback. */ + bool callback_killed; /**< Whether or not this was killed. */ } _nsgtk_callback_t; /** List of callbacks which have occurred and are pending running. */ @@ -61,20 +61,29 @@ nsgtk_schedule_kill_callback(void *_target, void *_match) if ((target->callback == match->callback) && (target->context == match->context)) { NSLOG(schedule, DEBUG, - "Found match for %p(%p), killing.", + "Found match for %p(%p), killing.", target->callback, target->context); target->callback = NULL; target->context = NULL; target->callback_killed = true; + match->callback_killed = true; } } -static void -schedule_remove(void (*callback)(void *p), void *p) +/** + * remove a matching callback and context tuple from all lists + * + * \param callback The callback to match + * \param cbctx The callback context to match + * \return NSERROR_OK if the tuple was removed from at least one list else NSERROR_NOT_FOUND + */ +static nserror +schedule_remove(void (*callback)(void *p), void *cbctx) { _nsgtk_callback_t cb_match = { .callback = callback, - .context = p, + .context = cbctx, + .callback_killed = false, }; g_list_foreach(queued_callbacks, @@ -83,29 +92,36 @@ schedule_remove(void (*callback)(void *p), void *p) nsgtk_schedule_kill_callback, &cb_match); g_list_foreach(this_run, nsgtk_schedule_kill_callback, &cb_match); + + if (cb_match.callback_killed == false) { + return NSERROR_NOT_FOUND; + } + return NSERROR_OK; } /* exported interface documented in gtk/schedule.h */ -nserror nsgtk_schedule(int t, void (*callback)(void *p), void *p) +nserror nsgtk_schedule(int t, void (*callback)(void *p), void *cbctx) { - _nsgtk_callback_t *cb; + _nsgtk_callback_t *cb; + nserror res; /* Kill any pending schedule of this kind. */ - schedule_remove(callback, p); + res = schedule_remove(callback, cbctx); - if (t < 0) { - return NSERROR_OK; - } + /* only removal */ + if (t < 0) { + return res; + } - cb = malloc(sizeof(_nsgtk_callback_t)); + cb = malloc(sizeof(_nsgtk_callback_t)); cb->callback = callback; - cb->context = p; + cb->context = cbctx; cb->callback_killed = false; /* Prepend is faster right now. */ queued_callbacks = g_list_prepend(queued_callbacks, cb); g_timeout_add(t, nsgtk_schedule_generic_callback, cb); - return NSERROR_OK; + return NSERROR_OK; } bool @@ -121,7 +137,7 @@ schedule_run(void) pending_callbacks = NULL; NSLOG(schedule, DEBUG, - "Captured a run of %d callbacks to fire.", + "Captured a run of %d callbacks to fire.", g_list_length(this_run)); /* Run all the callbacks which made it this far. */ @@ -132,5 +148,5 @@ schedule_run(void) cb->callback(cb->context); free(cb); } - return true; + return true; } diff --git a/frontends/gtk/search.c b/frontends/gtk/search.c index 298309679..f9a509f6e 100644 --- a/frontends/gtk/search.c +++ b/frontends/gtk/search.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -17,228 +17,340 @@ */ - /** \file - * Free text search (front component) +/** + * \file + * find in page gtk frontend implementation + * + * \todo this whole thing should be named find rather than search as + * that generally means web search and is confusing. */ -#include <stdint.h> -#include <ctype.h> -#include <string.h> -#include <gdk/gdkkeysyms.h> - -#include "utils/config.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/nsurl.h" + +#include <stdlib.h> +#include <stdbool.h> +#include <gtk/gtk.h> + +#include "utils/nsoption.h" #include "netsurf/search.h" -#include "netsurf/browser_window.h" #include "desktop/search.h" -#include "desktop/searchweb.h" -#include "gtk/warn.h" #include "gtk/compat.h" -#include "gtk/search.h" -#include "gtk/scaffolding.h" +#include "gtk/toolbar_items.h" #include "gtk/window.h" +#include "gtk/search.h" + + +struct gtk_search { + GtkToolbar *bar; + GtkEntry *entry; + GtkToolButton *back; + GtkToolButton *forward; + GtkToolButton *close; + GtkCheckButton *checkAll; + GtkCheckButton *caseSens; + + struct browser_window *bw; +}; /** * activate search forwards button in gui. * * \param active activate/inactivate - * \param gw The gui window in which to activite the search button in. + * \param search the gtk search context */ -static void nsgtk_search_set_forward_state(bool active, struct gui_window *gw) +static void nsgtk_search_set_forward_state(bool active, struct gtk_search *search) { - if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) { - struct nsgtk_scaffolding *g = nsgtk_get_scaffold(gw); - gtk_widget_set_sensitive( - GTK_WIDGET(nsgtk_scaffolding_search(g)->buttons[1]), - active); - } + gtk_widget_set_sensitive(GTK_WIDGET(search->forward), active); } + /** * activate search back button in gui. * * \param active activate/inactivate - * \param gw The gui window in which to activite the search button in. + * \param search the gtk search context */ -static void nsgtk_search_set_back_state(bool active, struct gui_window *gw) +static void nsgtk_search_set_back_state(bool active, struct gtk_search *search) { - if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) { - struct nsgtk_scaffolding *g = nsgtk_get_scaffold(gw); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search( - g)->buttons[0]), active); - } + gtk_widget_set_sensitive(GTK_WIDGET(search->back), active); } -/** connected to the search forward button */ -gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data) +/** + * connected to the search forward button + */ +static gboolean +nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - struct gui_window *gw = nsgtk_scaffolding_top_level(g); - struct browser_window *bw = nsgtk_get_browser_window(gw); - - assert(bw); - - search_flags_t flags = SEARCH_FLAG_FORWARDS | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->caseSens)) ? - SEARCH_FLAG_CASE_SENSITIVE : 0) | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->checkAll)) ? - SEARCH_FLAG_SHOWALL : 0); - - browser_window_search(bw, gw, flags, - gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry)); + struct gtk_search *search; + search_flags_t flags; + + search = (struct gtk_search *)data; + + flags = SEARCH_FLAG_FORWARDS; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) { + flags |= SEARCH_FLAG_CASE_SENSITIVE; + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) { + flags |= SEARCH_FLAG_SHOWALL; + } + + browser_window_search(search->bw, search, flags, + gtk_entry_get_text(search->entry)); + return TRUE; } -/** connected to the search back button */ - -gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data) +/** + * connected to the search back button + */ +static gboolean +nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - struct gui_window *gw = nsgtk_scaffolding_top_level(g); - struct browser_window *bw = nsgtk_get_browser_window(gw); - - assert(bw); - - search_flags_t flags = 0 |(gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->caseSens)) ? - SEARCH_FLAG_CASE_SENSITIVE : 0) | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->checkAll)) ? - SEARCH_FLAG_SHOWALL : 0); - - browser_window_search(bw, gw, flags, - gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry)); + struct gtk_search *search; + search_flags_t flags; + + search = (struct gtk_search *)data; + + flags = 0; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) { + flags |= SEARCH_FLAG_CASE_SENSITIVE; + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) { + flags |= SEARCH_FLAG_SHOWALL; + } + + browser_window_search(search->bw, search, flags, + gtk_entry_get_text(search->entry)); + return TRUE; } -/** connected to the search close button */ - -gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data) +/** + * connected to the search close button + */ +static gboolean +nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - nsgtk_scaffolding_toggle_search_bar_visibility(g); - return TRUE; + struct gtk_search *search; + + search = (struct gtk_search *)data; + + nsgtk_search_toggle_visibility(search); + + return TRUE; } -/** connected to the search entry [typing] */ -gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data) +/** + * connected to the search entry [typing] + */ +static gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - struct gui_window *gw = nsgtk_scaffolding_top_level(g); - struct browser_window *bw = nsgtk_get_browser_window(gw); + struct gtk_search *search; search_flags_t flags; - assert(bw != NULL); + search = (struct gtk_search *)data; + + flags = 0; - nsgtk_search_set_forward_state(true, gw); - nsgtk_search_set_back_state(true, gw); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) { + flags |= SEARCH_FLAG_CASE_SENSITIVE; + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) { + flags |= SEARCH_FLAG_SHOWALL; + } - flags = SEARCH_FLAG_FORWARDS | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->caseSens)) ? - SEARCH_FLAG_CASE_SENSITIVE : 0) | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->checkAll)) ? - SEARCH_FLAG_SHOWALL : 0); + browser_window_search(search->bw, search, flags, + gtk_entry_get_text(search->entry)); - browser_window_search(bw, gw, flags, - gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry)); return TRUE; } -/** connected to the search entry [return key] */ - -gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data) +/** + * connected to the search entry [return key] + */ +static gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - struct gui_window *gw = nsgtk_scaffolding_top_level(g); - struct browser_window *bw = nsgtk_get_browser_window(gw); + struct gtk_search *search; search_flags_t flags; - assert(bw); + search = (struct gtk_search *)data; - flags = SEARCH_FLAG_FORWARDS | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->caseSens)) ? - SEARCH_FLAG_CASE_SENSITIVE : 0) | - (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( - nsgtk_scaffolding_search(g)->checkAll)) ? - SEARCH_FLAG_SHOWALL : 0); + flags = SEARCH_FLAG_FORWARDS; + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->caseSens))) { + flags |= SEARCH_FLAG_CASE_SENSITIVE; + } + + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(search->checkAll))) { + flags |= SEARCH_FLAG_SHOWALL; + } + + browser_window_search(search->bw, search, flags, + gtk_entry_get_text(search->entry)); - browser_window_search(bw, gw, flags, - gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry)); return FALSE; } -/** allows escape key to close search bar too */ - -gboolean +/** + * allows escape key to close search bar too + */ +static gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event->keyval == GDK_KEY(Escape)) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - nsgtk_scaffolding_toggle_search_bar_visibility(g); + struct gtk_search *search; + search = (struct gtk_search *)data; + + nsgtk_search_toggle_visibility(search); } return FALSE; } -/** connected to the websearch entry [return key] */ -gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data) +static struct gui_search_table search_table = { + .forward_state = (void *)nsgtk_search_set_forward_state, + .back_state = (void *)nsgtk_search_set_back_state, +}; + +struct gui_search_table *nsgtk_search_table = &search_table; + + +/* exported interface documented in gtk/scaffolding.h */ +nserror nsgtk_search_toggle_visibility(struct gtk_search *search) { - struct nsgtk_scaffolding *g = data; - nserror ret; - nsurl *url; - - ret = search_web_omni( - gtk_entry_get_text(GTK_ENTRY(nsgtk_scaffolding_websearch(g))), - SEARCH_WEB_OMNI_SEARCHONLY, - &url); - if (ret == NSERROR_OK) { - temp_open_background = 0; - ret = browser_window_create( - BW_CREATE_HISTORY | BW_CREATE_TAB, - url, - NULL, - nsgtk_get_browser_window(nsgtk_scaffolding_top_level(g)), - NULL); - temp_open_background = -1; - nsurl_unref(url); - } - if (ret != NSERROR_OK) { - nsgtk_warning(messages_get_errorcode(ret), 0); + gboolean vis; + + browser_window_search_clear(search->bw); + + g_object_get(G_OBJECT(search->bar), "visible", &vis, NULL); + if (vis) { + gtk_widget_hide(GTK_WIDGET(search->bar)); + } else { + gtk_widget_show(GTK_WIDGET(search->bar)); + gtk_widget_grab_focus(GTK_WIDGET(search->entry)); + nsgtk_search_entry_changed(GTK_WIDGET(search->entry), search); } - return TRUE; + return NSERROR_OK; } -/** - * allows a click in the websearch entry field to clear the name of the - * provider - */ -gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f, - gpointer data) +/* exported interface documented in gtk/search.h */ +nserror nsgtk_search_restyle(struct gtk_search *search) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - gtk_editable_select_region(GTK_EDITABLE( - nsgtk_scaffolding_websearch(g)), 0, -1); - gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_websearch(g))); - return TRUE; + switch (nsoption_int(button_type)) { + + case 1: /* Small icons */ + gtk_toolbar_set_style(GTK_TOOLBAR(search->bar), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar), + GTK_ICON_SIZE_SMALL_TOOLBAR); + break; + + case 2: /* Large icons */ + gtk_toolbar_set_style(GTK_TOOLBAR(search->bar), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar), + GTK_ICON_SIZE_LARGE_TOOLBAR); + break; + + case 3: /* Large icons with text */ + gtk_toolbar_set_style(GTK_TOOLBAR(search->bar), + GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(search->bar), + GTK_ICON_SIZE_LARGE_TOOLBAR); + break; + + case 4: /* Text icons only */ + gtk_toolbar_set_style(GTK_TOOLBAR(search->bar), + GTK_TOOLBAR_TEXT); + break; + + default: + break; + } + return NSERROR_OK; } +/* exported interface documented in gtk/search.h */ +nserror +nsgtk_search_create(GtkBuilder *builder, + struct browser_window *bw, + struct gtk_search **search_out) +{ + struct gtk_search *search; -static struct gui_search_table search_table = { - .forward_state = (void *)nsgtk_search_set_forward_state, - .back_state = (void *)nsgtk_search_set_back_state, -}; + search = malloc(sizeof(struct gtk_search)); + if (search == NULL) { + return NSERROR_NOMEM; + } -struct gui_search_table *nsgtk_search_table = &search_table; + search->bw = bw; + + search->bar = GTK_TOOLBAR(gtk_builder_get_object(builder, "findbar")); + search->entry = GTK_ENTRY(gtk_builder_get_object(builder, "Find")); + search->back = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, + "FindBack")); + search->forward = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, + "FindForward")); + search->close = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, + "FindClose")); + search->checkAll = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, + "FindHighlightAll")); + search->caseSens = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, + "FindMatchCase")); + + g_signal_connect(search->forward, + "clicked", + G_CALLBACK(nsgtk_search_forward_button_clicked), + search); + + g_signal_connect(search->back, + "clicked", + G_CALLBACK(nsgtk_search_back_button_clicked), + search); + + g_signal_connect(search->entry, + "changed", + G_CALLBACK(nsgtk_search_entry_changed), + search); + + g_signal_connect(search->entry, + "activate", + G_CALLBACK(nsgtk_search_entry_activate), + search); + + g_signal_connect(search->entry, + "key-press-event", + G_CALLBACK(nsgtk_search_entry_key), + search); + + g_signal_connect(search->close, + "clicked", + G_CALLBACK(nsgtk_search_close_button_clicked), + search); + + g_signal_connect(search->caseSens, + "toggled", + G_CALLBACK(nsgtk_search_entry_changed), + search); + + g_signal_connect(search->checkAll, + "toggled", + G_CALLBACK(nsgtk_search_entry_changed), + search); + + nsgtk_search_restyle(search); + + + *search_out = search; + + return NSERROR_OK; +} diff --git a/frontends/gtk/search.h b/frontends/gtk/search.h index dd8c60d0f..5eb0b35cc 100644 --- a/frontends/gtk/search.h +++ b/frontends/gtk/search.h @@ -16,21 +16,36 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_GTK_SEARCH_H_ -#define _NETSURF_GTK_SEARCH_H_ - -struct gui_search_table *nsgtk_search_table; - -struct nsgtk_scaffolding; - -void nsgtk_search_bar_toggle_visibility(struct nsgtk_scaffolding * g); -gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data); -gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data); -gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, gpointer data); -gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data); -gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data); -gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data); -gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data); -gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f, gpointer data); - +/** + * \file + * free text page search for gtk interface + */ + +#ifndef NETSURF_GTK_SEARCH_H_ +#define NETSURF_GTK_SEARCH_H_ + +extern struct gui_search_table *nsgtk_search_table; + +struct gtk_search; + +/** + * create text search context + * + * \param builder the gtk builder containing the search toolbar + * \param bw The browsing context to run the find operations against + * \param search search context result + * \return NSERROR_OK and search_out updated + */ +nserror nsgtk_search_create(GtkBuilder *builder, struct browser_window *bw, struct gtk_search **search); + +/** + * update search toolbar size and style + */ +nserror nsgtk_search_restyle(struct gtk_search *search); + +/** + * toggle search bar visibility + */ +nserror nsgtk_search_toggle_visibility(struct gtk_search *search); + #endif diff --git a/frontends/gtk/selection.c b/frontends/gtk/selection.c index 228d65dbe..871526047 100644 --- a/frontends/gtk/selection.c +++ b/frontends/gtk/selection.c @@ -24,6 +24,7 @@ #include "netsurf/browser_window.h" #include "netsurf/clipboard.h" +#include "gtk/toolbar_items.h" #include "gtk/window.h" static GString *current_selection = NULL; diff --git a/frontends/gtk/selection.h b/frontends/gtk/selection.h index 6463692cf..07716a0d9 100644 --- a/frontends/gtk/selection.h +++ b/frontends/gtk/selection.h @@ -19,6 +19,6 @@ #ifndef GTK_SELECTION_H #define GTK_SELECTION_H -struct gui_clipboard_table *nsgtk_clipboard_table; +extern struct gui_clipboard_table *nsgtk_clipboard_table; #endif diff --git a/frontends/gtk/ssl_cert.c b/frontends/gtk/ssl_cert.c deleted file mode 100644 index 9d98db1f6..000000000 --- a/frontends/gtk/ssl_cert.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * \file - * Implementation of gtk certificate viewing using gtk core windows. - */ - -#include <stdint.h> -#include <stdlib.h> -#include <gtk/gtk.h> - -#include "utils/log.h" -#include "netsurf/keypress.h" -#include "netsurf/plotters.h" -#include "desktop/sslcert_viewer.h" - -#include "gtk/plotters.h" -#include "gtk/scaffolding.h" -#include "gtk/resources.h" -#include "gtk/ssl_cert.h" -#include "gtk/corewindow.h" - - -/** - * GTK certificate viewing window context - */ -struct nsgtk_crtvrfy_window { - /** GTK core window context */ - struct nsgtk_corewindow core; - /** GTK builder for window */ - GtkBuilder *builder; - /** GTK dialog window being shown */ - GtkDialog *dlg; - /** SSL certificate viewer context data */ - struct sslcert_session_data *ssl_data; -}; - -/** - * destroy a previously created certificate view - */ -static nserror nsgtk_crtvrfy_destroy(struct nsgtk_crtvrfy_window *crtvrfy_win) -{ - nserror res; - - res = sslcert_viewer_fini(crtvrfy_win->ssl_data); - if (res == NSERROR_OK) { - res = nsgtk_corewindow_fini(&crtvrfy_win->core); - gtk_widget_destroy(GTK_WIDGET(crtvrfy_win->dlg)); - g_object_unref(G_OBJECT(crtvrfy_win->builder)); - free(crtvrfy_win); - } - return res; -} - -static void -nsgtk_crtvrfy_accept(GtkButton *w, gpointer data) -{ - struct nsgtk_crtvrfy_window *crtvrfy_win; - crtvrfy_win = (struct nsgtk_crtvrfy_window *)data; - - sslcert_viewer_accept(crtvrfy_win->ssl_data); - - nsgtk_crtvrfy_destroy(crtvrfy_win); -} - -static void -nsgtk_crtvrfy_reject(GtkWidget *w, gpointer data) -{ - struct nsgtk_crtvrfy_window *crtvrfy_win; - crtvrfy_win = (struct nsgtk_crtvrfy_window *)data; - - sslcert_viewer_reject(crtvrfy_win->ssl_data); - - nsgtk_crtvrfy_destroy(crtvrfy_win); -} - -static gboolean -nsgtk_crtvrfy_delete_event(GtkWidget *w, GdkEvent *event, gpointer data) -{ - nsgtk_crtvrfy_reject(w, data); - return FALSE; -} - -/** - * callback for mouse action for certificate verify on core window - * - * \param nsgtk_cw The nsgtk core window structure. - * \param mouse_state netsurf mouse state on event - * \param x location of event - * \param y location of event - * \return NSERROR_OK on success otherwise appropriate error code - */ -static nserror -nsgtk_crtvrfy_mouse(struct nsgtk_corewindow *nsgtk_cw, - browser_mouse_state mouse_state, - int x, int y) -{ - struct nsgtk_crtvrfy_window *crtvrfy_win; - /* technically degenerate container of */ - crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw; - - sslcert_viewer_mouse_action(crtvrfy_win->ssl_data, mouse_state, x, y); - - return NSERROR_OK; -} - -/** - * callback for keypress for certificate verify on core window - * - * \param nsgtk_cw The nsgtk core window structure. - * \param nskey The netsurf key code - * \return NSERROR_OK on success otherwise appropriate error code - */ -static nserror -nsgtk_crtvrfy_key(struct nsgtk_corewindow *nsgtk_cw, uint32_t nskey) -{ - struct nsgtk_crtvrfy_window *crtvrfy_win; - - /* technically degenerate container of */ - crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw; - - if (sslcert_viewer_keypress(crtvrfy_win->ssl_data, nskey)) { - return NSERROR_OK; - } - return NSERROR_NOT_IMPLEMENTED; -} - -/** - * callback on draw event for certificate verify on core window - * - * \param nsgtk_cw The nsgtk core window structure. - * \param r The rectangle of the window that needs updating. - * \return NSERROR_OK on success otherwise appropriate error code - */ -static nserror -nsgtk_crtvrfy_draw(struct nsgtk_corewindow *nsgtk_cw, struct rect *r) -{ - struct redraw_context ctx = { - .interactive = true, - .background_images = true, - .plot = &nsgtk_plotters - }; - struct nsgtk_crtvrfy_window *crtvrfy_win; - - /* technically degenerate container of */ - crtvrfy_win = (struct nsgtk_crtvrfy_window *)nsgtk_cw; - - sslcert_viewer_redraw(crtvrfy_win->ssl_data, 0, 0, r, &ctx); - - return NSERROR_OK; -} - -/* exported interface documented in gtk/ssl_cert.h */ -nserror gtk_cert_verify(struct nsurl *url, - const struct ssl_cert_info *certs, - unsigned long num, - nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - struct nsgtk_crtvrfy_window *ncwin; - nserror res; - - ncwin = malloc(sizeof(struct nsgtk_crtvrfy_window)); - if (ncwin == NULL) { - return NSERROR_NOMEM; - } - - res = nsgtk_builder_new_from_resname("ssl", &ncwin->builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "SSL UI builder init failed"); - free(ncwin); - return res; - } - - gtk_builder_connect_signals(ncwin->builder, NULL); - - ncwin->dlg = GTK_DIALOG(gtk_builder_get_object(ncwin->builder, - "wndSSLProblem")); - - /* set parent for transient dialog */ - gtk_window_set_transient_for(GTK_WINDOW(ncwin->dlg), - nsgtk_scaffolding_window(nsgtk_current_scaffolding())); - - ncwin->core.scrolled = GTK_SCROLLED_WINDOW( - gtk_builder_get_object(ncwin->builder, "SSLScrolled")); - - ncwin->core.drawing_area = GTK_DRAWING_AREA( - gtk_builder_get_object(ncwin->builder, "SSLDrawingArea")); - - /* make the delete event call our destructor */ - g_signal_connect(G_OBJECT(ncwin->dlg), - "delete_event", - G_CALLBACK(nsgtk_crtvrfy_delete_event), - ncwin); - - /* accept button */ - g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder, - "sslaccept")), - "clicked", - G_CALLBACK(nsgtk_crtvrfy_accept), - ncwin); - - /* reject button */ - g_signal_connect(G_OBJECT(gtk_builder_get_object(ncwin->builder, - "sslreject")), - "clicked", - G_CALLBACK(nsgtk_crtvrfy_reject), - ncwin); - - /* initialise GTK core window */ - ncwin->core.draw = nsgtk_crtvrfy_draw; - ncwin->core.key = nsgtk_crtvrfy_key; - ncwin->core.mouse = nsgtk_crtvrfy_mouse; - - res = nsgtk_corewindow_init(&ncwin->core); - if (res != NSERROR_OK) { - g_object_unref(G_OBJECT(ncwin->dlg)); - free(ncwin); - return res; - } - - /* initialise certificate viewing interface */ - res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, - &ncwin->ssl_data); - if (res != NSERROR_OK) { - g_object_unref(G_OBJECT(ncwin->dlg)); - free(ncwin); - return res; - } - - res = sslcert_viewer_init(ncwin->core.cb_table, - (struct core_window *)ncwin, - ncwin->ssl_data); - if (res != NSERROR_OK) { - g_object_unref(G_OBJECT(ncwin->dlg)); - free(ncwin); - return res; - } - - gtk_widget_show(GTK_WIDGET(ncwin->dlg)); - - return NSERROR_OK; -} diff --git a/frontends/gtk/tabs.c b/frontends/gtk/tabs.c index dbe9d405b..4fa109b70 100644 --- a/frontends/gtk/tabs.c +++ b/frontends/gtk/tabs.c @@ -20,11 +20,12 @@ #include <string.h> #include "utils/nsoption.h" -#include "utils/messages.h" +#include "utils/log.h" #include "netsurf/browser_window.h" #include "desktop/search.h" #include "gtk/compat.h" +#include "gtk/toolbar_items.h" #include "gtk/scaffolding.h" #include "gtk/window.h" #include "gtk/search.h" @@ -32,9 +33,15 @@ #define TAB_WIDTH_N_CHARS 15 -/** callback to update sizes when style-set gtk signal */ -static void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, - GtkWidget *close_button) +static gint srcpagenum; + +/** + * callback to update sizes when style-set gtk signal + */ +static void +nsgtk_tab_update_size(GtkWidget *hbox, + GtkStyle *previous_style, + GtkWidget *close_button) { PangoFontMetrics *metrics; PangoContext *context; @@ -63,63 +70,114 @@ static void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, gtk_widget_set_size_request(close_button, w + 4, h + 4); } -/** Create a notebook tab label */ -static GtkWidget *nsgtk_tab_label_setup(struct gui_window *window) + +/** + * gtk event handler for button release on tab hbox + */ +static gboolean +nsgtk_tab_button_release(GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + GtkWidget *page; + + if ((event->type == GDK_BUTTON_RELEASE) && (event->button == 2)) { + page = (GtkWidget *)user_data; + gtk_widget_destroy(page); + return TRUE; + } + return FALSE; +} + + +/** + * Create a notebook tab label + * + * \param page The page content widget + * \param title The title of the page + * \param icon_pixbuf The icon of the page + */ +static GtkWidget * +nsgtk_tab_label_setup(GtkWidget *page, + const char *title, + GdkPixbuf *icon_pixbuf) { - GtkWidget *hbox, *label, *button, *close; + GtkWidget *ebox, *hbox, *favicon, *label, *button, *close; + + /* horizontal box */ + hbox = nsgtk_hbox_new(FALSE, 3); - hbox = nsgtk_hbox_new(FALSE, 2); + /* event box */ + ebox = gtk_event_box_new(); + gtk_widget_set_events(ebox, GDK_BUTTON_PRESS_MASK); + gtk_container_add(GTK_CONTAINER(ebox), hbox); - label = gtk_label_new(messages_get("NewTab")); + /* construct a favicon */ + favicon = gtk_image_new(); + if (icon_pixbuf != NULL) { + gtk_image_set_from_pixbuf(GTK_IMAGE(favicon), icon_pixbuf); + } + + /* construct a label */ + label = gtk_label_new(title); gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); gtk_label_set_single_line_mode(GTK_LABEL(label), TRUE); nsgtk_widget_set_alignment(label, GTK_ALIGN_START, GTK_ALIGN_CENTER); nsgtk_widget_set_margins(label, 0, 0); gtk_widget_show(label); + /* construct a close button */ button = gtk_button_new(); close = nsgtk_image_new_from_stock(NSGTK_STOCK_CLOSE, - GTK_ICON_SIZE_MENU); + GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_container_add(GTK_CONTAINER(button), close); - gtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE); + nsgtk_button_set_focus_on_click(GTK_BUTTON(button), FALSE); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); gtk_widget_set_tooltip_text(button, "Close this tab."); -#ifdef FIXME - GtkRcStyle *rcstyle; - rcstyle = gtk_rc_style_new(); - rcstyle->xthickness = rcstyle->ythickness = 0; - gtk_widget_modify_style(button, rcstyle); - g_object_unref(rcstyle); -#endif - - g_signal_connect_swapped(button, "clicked", - G_CALLBACK(nsgtk_window_destroy_browser), window); - g_signal_connect(hbox, "style-set", - G_CALLBACK(nsgtk_tab_update_size), button); - + /* pack the widgets into the label box */ + gtk_box_pack_start(GTK_BOX(hbox), favicon, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); - g_object_set_data(G_OBJECT(hbox), "label", label); - g_object_set_data(G_OBJECT(hbox), "close-button", button); + /* make the icon and label widgets findable by name */ + g_object_set_data(G_OBJECT(ebox), "favicon", favicon); + g_object_set_data(G_OBJECT(ebox), "label", label); + /* attach signal handlers */ + g_signal_connect_swapped(button, + "clicked", + G_CALLBACK(gtk_widget_destroy), page); - gtk_widget_show_all(hbox); - return hbox; -} -#include "utils/log.h" + g_signal_connect(hbox, + "style-set", + G_CALLBACK(nsgtk_tab_update_size), + button); -/** callback when page is switched */ + g_signal_connect(ebox, + "button-release-event", + G_CALLBACK(nsgtk_tab_button_release), + page); -static gint srcpagenum; -/** The switch-page signal handler + gtk_widget_show_all(ebox); + + return ebox; +} + + +/** + * The before switch-page gtk signal handler * * This signal is handled both before and after delivery to work round * issue that setting the selected tab during the switch-page signal * fails + * + * \param notebook The notebook being changed + * \param page The notebook page being switched to + * \param selpagenum The currently selected page number + * \param user_data Unused */ static void nsgtk_tab_switch_page(GtkNotebook *notebook, @@ -130,6 +188,15 @@ nsgtk_tab_switch_page(GtkNotebook *notebook, srcpagenum = gtk_notebook_get_current_page(notebook); } + +/** + * The after switch-page gtk signal handler + * + * \param notebook The notebook being changed + * \param selpage The notebook page selected + * \param selpagenum The currently selected page number + * \param user_data Unused + */ static void nsgtk_tab_switch_page_after(GtkNotebook *notebook, GtkWidget *selpage, @@ -138,41 +205,62 @@ nsgtk_tab_switch_page_after(GtkNotebook *notebook, { GtkWidget *srcpage; GtkWidget *addpage; - struct gui_window *gw; - nserror error; + GtkMenuBar *menubar; + struct gui_window *gw = NULL; + nserror res = NSERROR_INVALID; addpage = g_object_get_data(G_OBJECT(notebook), "addtab"); - if (selpage == addpage) { - if ((srcpagenum != -1) && - (srcpagenum != (gint)selpagenum)) { - /* ensure the add tab is not actually selected */ - NSLOG(netsurf, INFO, "src %d sel %d", srcpagenum, - selpagenum); - srcpage = gtk_notebook_get_nth_page(notebook, srcpagenum); - gw = g_object_get_data(G_OBJECT(srcpage), "gui_window"); - if ((gw != NULL) && (nsgtk_get_scaffold(gw) != NULL)) { - error = nsgtk_scaffolding_new_tab(gw); - if (error != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Failed to open new tab."); - } - } - } - } else { + /* check if trying to select the "add page" tab */ + if (selpage != addpage) { NSLOG(netsurf, INFO, "sel %d", selpagenum); - /* tab with page in it */ + menubar = nsgtk_scaffolding_menu_bar(nsgtk_scaffolding_from_notebook(notebook)); gw = g_object_get_data(G_OBJECT(selpage), "gui_window"); if (gw != NULL) { + /* tab with web page in it */ nsgtk_scaffolding_set_top_level(gw); + gtk_widget_show(GTK_WIDGET(addpage)); + gtk_widget_set_sensitive(GTK_WIDGET(menubar), true); + } else { + /* tab with non browser content (e.g. tb customize) */ + gtk_widget_hide(GTK_WIDGET(addpage)); + gtk_widget_set_sensitive(GTK_WIDGET(menubar), false); } + return; + } + + NSLOG(netsurf, INFO, "src %d sel %d", srcpagenum, selpagenum); + + /* ensure the add tab is not already selected */ + if ((srcpagenum == -1) || (srcpagenum == (gint)selpagenum)) { + return; + } + + srcpage = gtk_notebook_get_nth_page(notebook, srcpagenum); + + gw = g_object_get_data(G_OBJECT(srcpage), "gui_window"); + + if (gw != NULL) { + res = nsgtk_window_item_activate(gw, NEWTAB_BUTTON); + } + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Failed to open new tab."); } } -static void nsgtk_tab_page_reordered(GtkNotebook *notebook, - GtkWidget *child, - guint page_num, - gpointer user_data) + +/** + * The tab reordered gtk signal handler + * + * \param notebook The notebook being changed + * \param page_num The currently selected page number + * \param user_data Unused + */ +static void +nsgtk_tab_page_reordered(GtkNotebook *notebook, + GtkWidget *child, + guint page_num, + gpointer user_data) { gint pages; GtkWidget *addpage; @@ -187,6 +275,13 @@ static void nsgtk_tab_page_reordered(GtkNotebook *notebook, } } +/** + * The tab orientation signal handler + * + * \param notebook The notebook being changed + * \param page_num The currently selected page number + * \param user_data Unused + */ static void nsgtk_tab_orientation(GtkNotebook *notebook) { @@ -210,7 +305,9 @@ nsgtk_tab_orientation(GtkNotebook *notebook) } } -/** adds a "new tab" tab */ +/** + * adds a "new tab" tab + */ static GtkWidget * nsgtk_tab_add_newtab(GtkNotebook *notebook) { @@ -221,7 +318,9 @@ nsgtk_tab_add_newtab(GtkNotebook *notebook) tablabel = nsgtk_hbox_new(FALSE, 1); tabcontents = nsgtk_hbox_new(FALSE, 1); - add = nsgtk_image_new_from_stock(NSGTK_STOCK_ADD, GTK_ICON_SIZE_MENU); + add = gtk_image_new_from_icon_name(NSGTK_STOCK_ADD, + GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_widget_set_tooltip_text(add, "New Tab"); gtk_box_pack_start(GTK_BOX(tablabel), add, FALSE, FALSE, 0); @@ -238,18 +337,26 @@ nsgtk_tab_add_newtab(GtkNotebook *notebook) return tablabel; } -/** callback to alter tab visibility when pages are added or removed */ + +/** + * callback to alter tab visibility when pages are added or removed + */ static void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, guint page) { - gint pagec = gtk_notebook_get_n_pages(notebook); - GtkWidget *addpage = g_object_get_data(G_OBJECT(notebook), "addtab"); - - if (addpage != NULL) { - pagec--; /* skip the add tab */ - if ((gint)page == pagec) { - /* ensure the add new tab cannot be current */ - gtk_notebook_set_current_page(notebook, page - 1); + gint pagec; + GtkWidget *addpage; + + pagec = gtk_notebook_get_n_pages(notebook); + if (pagec > 1) { + addpage = g_object_get_data(G_OBJECT(notebook), "addtab"); + if (addpage != NULL) { + pagec--; /* skip the add tab */ + if ((gint)page == pagec) { + /* ensure the add new tab cannot be current */ + gtk_notebook_set_current_page(notebook, + page - 1); + } } } @@ -260,6 +367,7 @@ nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, guint page) } } + /* exported interface documented in gtk/tabs.h */ void nsgtk_tab_options_changed(GtkNotebook *notebook) { @@ -269,48 +377,56 @@ void nsgtk_tab_options_changed(GtkNotebook *notebook) /* exported interface documented in gtk/tabs.h */ -void nsgtk_tab_init(struct nsgtk_scaffolding *gs) +nserror nsgtk_notebook_create(GtkBuilder *builder, GtkNotebook **notebook_out) { GtkNotebook *notebook; - notebook = nsgtk_scaffolding_notebook(gs); + notebook = GTK_NOTEBOOK(gtk_builder_get_object(builder, "notebook")); nsgtk_tab_add_newtab(notebook); - g_signal_connect(notebook, "switch-page", - G_CALLBACK(nsgtk_tab_switch_page), NULL); - g_signal_connect_after(notebook, "switch-page", - G_CALLBACK(nsgtk_tab_switch_page_after), NULL); + g_signal_connect(notebook, + "switch-page", + G_CALLBACK(nsgtk_tab_switch_page), + NULL); + g_signal_connect_after(notebook, + "switch-page", + G_CALLBACK(nsgtk_tab_switch_page_after), + NULL); + g_signal_connect(notebook, + "page-removed", + G_CALLBACK(nsgtk_tab_visibility_update), + NULL); + g_signal_connect(notebook, + "page-added", + G_CALLBACK(nsgtk_tab_visibility_update), + NULL); + g_signal_connect(notebook, + "page-reordered", + G_CALLBACK(nsgtk_tab_page_reordered), + NULL); - g_signal_connect(notebook, "page-removed", - G_CALLBACK(nsgtk_tab_visibility_update), NULL); - g_signal_connect(notebook, "page-added", - G_CALLBACK(nsgtk_tab_visibility_update), NULL); - g_signal_connect(notebook, "page-reordered", - G_CALLBACK(nsgtk_tab_page_reordered), NULL); + nsgtk_tab_options_changed(notebook); + *notebook_out = notebook; - nsgtk_tab_options_changed(notebook); + return NSERROR_OK; } /* exported interface documented in gtk/tabs.h */ -void nsgtk_tab_add(struct gui_window *gw, +nserror +nsgtk_tab_add_page(GtkNotebook *notebook, GtkWidget *tab_contents, - bool background) + bool background, + const char *title, + GdkPixbuf *icon_pixbuf) { - GtkNotebook *notebook; GtkWidget *tabBox; gint remember; gint pages; gint newpage; - g_object_set_data(G_OBJECT(tab_contents), "gui_window", gw); - - notebook = nsgtk_scaffolding_notebook(nsgtk_get_scaffold(gw)); - - tabBox = nsgtk_tab_label_setup(gw); - - nsgtk_window_set_tab(gw, tabBox); + tabBox = nsgtk_tab_label_setup(tab_contents, title, icon_pixbuf); remember = gtk_notebook_get_current_page(notebook); @@ -328,24 +444,83 @@ void nsgtk_tab_add(struct gui_window *gw, gtk_notebook_set_current_page(notebook, newpage); } - gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_urlbar( - nsgtk_get_scaffold(gw)))); + return NSERROR_OK; } + /* exported interface documented in gtk/tabs.h */ -void nsgtk_tab_set_title(struct gui_window *g, const char *title) +void nsgtk_tab_add(struct gui_window *gw, + GtkWidget *tab_contents, + bool background, + const char *title, + GdkPixbuf *icon_pixbuf) { - GtkWidget *label; - GtkWidget *tab; + GtkNotebook *notebook; - tab = nsgtk_window_get_tab(g); - if (tab == NULL) { - return; + g_object_set_data(G_OBJECT(tab_contents), "gui_window", gw); + + notebook = nsgtk_scaffolding_notebook(nsgtk_get_scaffold(gw)); + + nsgtk_tab_add_page(notebook, tab_contents, background, title, icon_pixbuf); + +} + + +/* exported interface documented in gtk/tabs.h */ +nserror nsgtk_tab_set_icon(GtkWidget *page, GdkPixbuf *pixbuf) +{ + GtkImage *favicon; + GtkWidget *tab_label; + GtkNotebook *notebook; + + if (pixbuf == NULL) { + return NSERROR_INVALID; + } + notebook = GTK_NOTEBOOK(gtk_widget_get_ancestor(page, GTK_TYPE_NOTEBOOK)); + if (notebook == NULL) { + return NSERROR_BAD_PARAMETER; + } + + tab_label = gtk_notebook_get_tab_label(notebook, page); + if (tab_label == NULL) { + return NSERROR_INVALID; } - label = g_object_get_data(G_OBJECT(tab), "label"); - gtk_label_set_text(GTK_LABEL(label), title); - gtk_widget_set_tooltip_text(tab, title); + favicon = GTK_IMAGE(g_object_get_data(G_OBJECT(tab_label), "favicon")); + + gtk_image_set_from_pixbuf(favicon, pixbuf); + + return NSERROR_OK; +} + + +/* exported interface documented in gtk/tabs.h */ +nserror nsgtk_tab_set_title(GtkWidget *page, const char *title) +{ + GtkLabel *label; + GtkWidget *tab_label; + GtkNotebook *notebook; + + if (title == NULL) { + return NSERROR_INVALID; + } + + notebook = GTK_NOTEBOOK(gtk_widget_get_ancestor(page, GTK_TYPE_NOTEBOOK)); + if (notebook == NULL) { + return NSERROR_BAD_PARAMETER; + } + + tab_label = gtk_notebook_get_tab_label(notebook, page); + if (tab_label == NULL) { + return NSERROR_INVALID; + } + + label = GTK_LABEL(g_object_get_data(G_OBJECT(tab_label), "label")); + + gtk_label_set_text(label, title); + gtk_widget_set_tooltip_text(tab_label, title); + + return NSERROR_OK; } /* exported interface documented in gtk/tabs.h */ diff --git a/frontends/gtk/tabs.h b/frontends/gtk/tabs.h index 440d61336..63edae3cc 100644 --- a/frontends/gtk/tabs.h +++ b/frontends/gtk/tabs.h @@ -16,24 +16,58 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_GTK_TABS_H_ -#define _NETSURF_GTK_TABS_H_ +#ifndef NETSURF_GTK_TABS_H_ +#define NETSURF_GTK_TABS_H_ struct gui_window; -void nsgtk_tab_init(struct nsgtk_scaffolding *gs); -void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background); +/** + * create notebook + * + * creates a notebook for use inside a window, creates the special add + * page(tab) and attaches all signals. + * + * \param builder the gtk builder object to create notbook from + * \param notebook_out reciveds the created notebook + * \return NSERROR_OK and notebook_out updated else error code + */ +nserror nsgtk_notebook_create(GtkBuilder *builder, GtkNotebook **notebook_out); + +/** + * Add new gui window page to notebook. + */ +void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background, const char *title, GdkPixbuf *icon_pixbuf); + +/** + * Add new page to a notebook + */ +nserror nsgtk_tab_add_page(GtkNotebook *notebook, GtkWidget *tab_contents, bool background, const char *title, GdkPixbuf *icon_pixbuf); -/** set the tab title + +/** + * set the tab title * * The tab title will be set to the parameter * * \note currently only called from nsgtk_window_set_title() * - * \param g the gui window to set tab title for. + * \param page The page widget that was added to the notebook * \param title The title text which may not be NULL. + * \return NSERROR_OK on sucess else appropriate code. + */ +nserror nsgtk_tab_set_title(GtkWidget *page, const char *title); + +/** + * set the tab icon + * + * The tab icon will be set to the \a pixbuf parameter + * + * \param page The page widget that was added to the notebook + * \param pixbuf The pixbuf to set the icon to. + * \return NSERROR_OK on sucess else appropriate code. */ -void nsgtk_tab_set_title(struct gui_window *g, const char *title); +nserror nsgtk_tab_set_icon(GtkWidget *page, GdkPixbuf *pixbuf); + void nsgtk_tab_options_changed(GtkNotebook *notebook); nserror nsgtk_tab_close_current(GtkNotebook *notebook); nserror nsgtk_tab_prev(GtkNotebook *notebook); diff --git a/frontends/gtk/throbber.c b/frontends/gtk/throbber.c index b8efceca1..f94893bef 100644 --- a/frontends/gtk/throbber.c +++ b/frontends/gtk/throbber.c @@ -28,7 +28,16 @@ #include "gtk/resources.h" #include "gtk/throbber.h" -struct nsgtk_throbber *nsgtk_throbber = NULL; +/** + * Throbber images context + */ +struct nsgtk_throbber +{ + int nframes; /**< Number of frames in the throbber */ + GdkPixbuf **framedata; /* pixbuf data for the frames */ +}; + +static struct nsgtk_throbber *nsgtk_throbber = NULL; #define THROBBER_FRAMES 9 #define THROBBER_FMT "throbber/throbber%d.png" @@ -36,10 +45,10 @@ struct nsgtk_throbber *nsgtk_throbber = NULL; /* exported interface documented in gtk/throbber.h */ nserror nsgtk_throbber_init(void) { - struct nsgtk_throbber *throb; /**< structure we generate */ + nserror res = NSERROR_OK; + struct nsgtk_throbber *throb; int frame; char resname[] = THROBBER_FMT; - nserror res = NSERROR_OK; throb = malloc(sizeof(*throb)); if (throb == NULL) { @@ -49,7 +58,7 @@ nserror nsgtk_throbber_init(void) throb->framedata = malloc(sizeof(GdkPixbuf *) * THROBBER_FRAMES); if (throb->framedata == NULL) { free(throb); - return false; + return NSERROR_NOMEM; } for (frame = 0; frame < THROBBER_FRAMES; frame++) { @@ -73,11 +82,9 @@ nserror nsgtk_throbber_init(void) throb->nframes = frame; nsgtk_throbber = throb; return res; - - } - +/* exported interface documented in gtk/throbber.h */ void nsgtk_throbber_finalise(void) { int i; @@ -91,3 +98,30 @@ void nsgtk_throbber_finalise(void) nsgtk_throbber = NULL; } + +/* exported interface documented in gtk/throbber.h */ +nserror nsgtk_throbber_get_frame(int frame, GdkPixbuf **pixbuf) +{ + nserror res = NSERROR_OK; + + /* ensure initialisation */ + if (nsgtk_throbber == NULL) { + res = nsgtk_throbber_init(); + } + if (res != NSERROR_OK) { + return res; + } + + /* ensure frame in range */ + if ((frame < 0) || (frame >= nsgtk_throbber->nframes)) { + return NSERROR_BAD_SIZE; + } + + /* ensure there is frame data */ + if (nsgtk_throbber->framedata[frame] == NULL) { + return NSERROR_INVALID; + } + + *pixbuf = nsgtk_throbber->framedata[frame]; + return NSERROR_OK; +} diff --git a/frontends/gtk/throbber.h b/frontends/gtk/throbber.h index e0b47e15c..c8529d2e2 100644 --- a/frontends/gtk/throbber.h +++ b/frontends/gtk/throbber.h @@ -16,20 +16,27 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef __GTK_THROBBER_H__ -#define __GTK_THROBBER_H__ - -#include <gtk/gtk.h> - -struct nsgtk_throbber -{ - int nframes; /**< Number of frames in the throbber */ - GdkPixbuf **framedata; -}; - -extern struct nsgtk_throbber *nsgtk_throbber; +#ifndef NETSURF_GTK_THROBBER_H +#define NETSURF_GTK_THROBBER_H +/** + * Initialise global throbber context + */ nserror nsgtk_throbber_init(void); + +/** + * release global throbber context + */ void nsgtk_throbber_finalise(void); -#endif /* __GTK_THROBBER_H__ */ +/** + * get the pixbuf of a given frame of the throbber + * + * \param frame The frame number starting at 0 for stopped frame + * \param pixbuf updated on success + * \return NSERROR_OK and pixbuf updated on success, NSERROR_BAD_SIZE if frame + * is out of range else error code. + */ +nserror nsgtk_throbber_get_frame(int frame, GdkPixbuf **pixbuf); + +#endif /* NETSURF_GTK_THROBBER_H */ diff --git a/frontends/gtk/toolbar.c b/frontends/gtk/toolbar.c index e93bd49f9..6ec41cc1d 100644 --- a/frontends/gtk/toolbar.c +++ b/frontends/gtk/toolbar.c @@ -1,5 +1,5 @@ /* - * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net> + * Copyright 2019 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -16,18 +16,36 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +/** + * \file + * implementation of toolbar to control browsing context + */ + #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <errno.h> #include <gtk/gtk.h> -#include "netsurf/browser_window.h" -#include "desktop/searchweb.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/nsoption.h" #include "utils/file.h" +#include "utils/nsurl.h" +#include "utils/corestrings.h" +#include "desktop/browser_history.h" +#include "desktop/searchweb.h" +#include "desktop/search.h" +#include "desktop/save_complete.h" +#include "desktop/save_text.h" +#include "desktop/print.h" +#include "desktop/hotlist.h" +#include "netsurf/content.h" +#include "netsurf/browser_window.h" +#include "netsurf/keypress.h" +#include "gtk/toolbar_items.h" +#include "gtk/completion.h" #include "gtk/gui.h" #include "gtk/warn.h" #include "gtk/search.h" @@ -36,63 +54,203 @@ #include "gtk/window.h" #include "gtk/compat.h" #include "gtk/resources.h" +#include "gtk/schedule.h" +#include "gtk/local_history.h" +#include "gtk/global_history.h" +#include "gtk/viewsource.h" +#include "gtk/download.h" +#include "gtk/viewdata.h" +#include "gtk/tabs.h" +#include "gtk/print.h" +#include "gtk/layout_pango.h" +#include "gtk/preferences.h" +#include "gtk/hotlist.h" +#include "gtk/cookies.h" +#include "gtk/about.h" +#include "gtk/gdk.h" +#include "gtk/bitmap.h" +#include "gtk/page_info.h" #include "gtk/toolbar.h" -static GtkTargetEntry entry = {(char *)"nsgtk_button_data", - GTK_TARGET_SAME_APP, 0}; - -static bool edit_mode = false; - -struct nsgtk_toolbar_custom_store { - GtkWidget *window; - GtkWidget *store_buttons[PLACEHOLDER_BUTTON]; - GtkWidget *widgetvbox; - GtkWidget *currentbar; - char numberh; /* current horizontal location while adding */ - GtkBuilder *builder; /* button widgets to store */ - int buttonlocations[PLACEHOLDER_BUTTON]; - int currentbutton; - bool fromstore; -}; -/* the number of buttons that fit in the width of the store window */ -#define NSGTK_STORE_WIDTH 6 +/** + * button location indicating button is not to be shown + */ +#define INACTIVE_LOCATION (-1) -/* the 'standard' width of a button that makes sufficient of its label -visible */ -#define NSGTK_BUTTON_WIDTH 111 +/** + * time (in ms) between throbber animation frame updates + */ +#define THROBBER_FRAME_TIME (100) -/* the 'standard' height of a button that fits as many toolbars as -possible into the store */ +/** + * the minimum number of columns in the tool store + */ +#define NSGTK_MIN_STORE_COLUMNS 4 + +/** + * the 'standard' width of a button that makes sufficient of its label visible + */ +#define NSGTK_BUTTON_WIDTH 120 + +/** + * the 'standard' height of a button that fits as many toolbars as + * possible into the store + */ #define NSGTK_BUTTON_HEIGHT 70 -/* the 'normal' width of the websearch bar */ +/** + * the 'normal' width of the websearch bar + */ #define NSGTK_WEBSEARCH_WIDTH 150 -static struct nsgtk_toolbar_custom_store store; -static struct nsgtk_toolbar_custom_store *window = &store; +/** + * toolbar item context + */ +struct nsgtk_toolbar_item { + + /** + * GTK widget in the toolbar + */ + GtkToolItem *button; + + /** + * location index in toolbar + */ + int location; + + /** + * if the item is currently sensitive in the toolbar + */ + bool sensitivity; + + /** + * textural name used in serialising items + */ + const char *name; + + /** + * button clicked on toolbar handler + */ + gboolean (*clicked)(GtkWidget *widget, gpointer data); + + /** + * handler when dragging from customisation toolbox to toolbar + */ + void *dataplus; + + /** + * handler when dragging from toolbar to customisation toolbox + */ + void *dataminus; +}; +/** + * Location focus state machine + * + * 1. If we don't care, we're in LFS_IDLE + * 2. When we create a new toolbar, we can put it into + * LFS_WANT which means that we want the url bar to focus + * 3. When we start throbbing if we're in LFS_WANT we move to LFS_THROB + * 4. When we stop throbbing, if we're in LFS_THROB we move to LFS_LAST + * + * While not in LFS_IDLE, if the url bar is updated and we previously had it + * fully selected then we reselect it all. If we're in LFS_LAST we move to + * LFS_IDLE at that point. + */ +typedef enum { + LFS_IDLE, /**< Nothing to do */ + LFS_WANT, /**< Want focus, will apply */ + LFS_THROB, /**< Want focus, we have started throbbing */ + LFS_LAST, /**< Last chance for a focus update */ +} nsgtk_toolbar_location_focus_state; -enum image_sets { - IMAGE_SET_MAIN_MENU = 0, - IMAGE_SET_RCLICK_MENU, - IMAGE_SET_POPUP_MENU, - IMAGE_SET_BUTTONS, - IMAGE_SET_COUNT +/** + * control toolbar context + */ +struct nsgtk_toolbar { + /** gtk toolbar widget */ + GtkToolbar *widget; + + /* toolbar size allocation context */ + int offset; + int toolbarmem; + int toolbarbase; + int historybase; + + /** + * Toolbar item contexts + */ + struct nsgtk_toolbar_item items[PLACEHOLDER_BUTTON]; + + /** + * Current frame of throbber animation + */ + int throb_frame; + + /** + * Web search widget + */ + GtkWidget *webSearchEntry; + + /** + * callback to obtain a browser window for navigation + */ + struct browser_window *(*get_bw)(void *ctx); + + /** + * context passed to get_bw function + */ + void *get_ctx; + + /** + * Location focus state machine, current state + */ + nsgtk_toolbar_location_focus_state loc_focus; }; -typedef enum search_buttons { - SEARCH_BACK_BUTTON = 0, - SEARCH_FORWARD_BUTTON, - SEARCH_CLOSE_BUTTON, - SEARCH_BUTTONS_COUNT -} nsgtk_search_buttons; - -struct nsgtk_theme { - GtkImage *image[PLACEHOLDER_BUTTON]; - GtkImage *searchimage[SEARCH_BUTTONS_COUNT]; - /* apng throbber element */ + +/** + * toolbar cusomisation context + */ +struct nsgtk_toolbar_customisation { + /** + * first entry is a toolbar widget so a customisation widget + * can be cast to toolbar and back. + */ + struct nsgtk_toolbar toolbar; + + /** + * The top level container (tabBox) + */ + GtkWidget *container; + + /** + * The vertical box into which the available tools are shown + */ + GtkBox *toolbox; + + /** + * widget handles for items in the customisation toolbox area + */ + GtkToolItem *items[PLACEHOLDER_BUTTON]; + + /** + * which item is being dragged + */ + int dragitem; /* currentbutton */ + /** + * true if item being dragged onto toolbar, false if from toolbar + */ + bool dragfrom; /*fromstore */ + }; + +/* forward declaration */ +static nserror toolbar_item_create(nsgtk_toolbar_button id, + struct nsgtk_toolbar_item *item_out); + + /** * returns a string without its underscores * @@ -122,1372 +280,3608 @@ static char *remove_underscores(const char *s, bool replacespace) /** - * get default image for buttons / menu items from gtk stock items. - * - * \param tbbutton button reference - * \param iconsize The size of icons to select. - * \param usedef Use the default image if not found. - * \return default images. - */ -static GtkImage * -nsgtk_theme_image_default(nsgtk_toolbar_button tbbutton, - GtkIconSize iconsize, - bool usedef) -{ - GtkImage *image; /* The GTK image to return */ - - switch(tbbutton) { - -#define BUTTON_IMAGE(p, q) \ - case p##_BUTTON: \ - image = GTK_IMAGE(nsgtk_image_new_from_stock(q, iconsize)); \ - break - - BUTTON_IMAGE(BACK, NSGTK_STOCK_GO_BACK); - BUTTON_IMAGE(FORWARD, NSGTK_STOCK_GO_FORWARD); - BUTTON_IMAGE(STOP, NSGTK_STOCK_STOP); - BUTTON_IMAGE(RELOAD, NSGTK_STOCK_REFRESH); - BUTTON_IMAGE(HOME, NSGTK_STOCK_HOME); - BUTTON_IMAGE(NEWWINDOW, "gtk-new"); - BUTTON_IMAGE(NEWTAB, "gtk-new"); - BUTTON_IMAGE(OPENFILE, NSGTK_STOCK_OPEN); - BUTTON_IMAGE(CLOSETAB, NSGTK_STOCK_CLOSE); - BUTTON_IMAGE(CLOSEWINDOW, NSGTK_STOCK_CLOSE); - BUTTON_IMAGE(SAVEPAGE, NSGTK_STOCK_SAVE_AS); - BUTTON_IMAGE(PRINTPREVIEW, "gtk-print-preview"); - BUTTON_IMAGE(PRINT, "gtk-print"); - BUTTON_IMAGE(QUIT, "gtk-quit"); - BUTTON_IMAGE(CUT, "gtk-cut"); - BUTTON_IMAGE(COPY, "gtk-copy"); - BUTTON_IMAGE(PASTE, "gtk-paste"); - BUTTON_IMAGE(DELETE, "gtk-delete"); - BUTTON_IMAGE(SELECTALL, "gtk-select-all"); - BUTTON_IMAGE(FIND, NSGTK_STOCK_FIND); - BUTTON_IMAGE(PREFERENCES, "gtk-preferences"); - BUTTON_IMAGE(ZOOMPLUS, "gtk-zoom-in"); - BUTTON_IMAGE(ZOOMMINUS, "gtk-zoom-out"); - BUTTON_IMAGE(ZOOMNORMAL, "gtk-zoom-100"); - BUTTON_IMAGE(FULLSCREEN, "gtk-fullscreen"); - BUTTON_IMAGE(VIEWSOURCE, "gtk-index"); - BUTTON_IMAGE(CONTENTS, "gtk-help"); - BUTTON_IMAGE(ABOUT, "gtk-about"); -#undef BUTTON_IMAGE + * create throbber toolbar item widget + * + * create a gtk entry widget with a completion attached + */ +static GtkToolItem * +make_toolbar_item_throbber(bool sensitivity, bool edit) +{ + nserror res; + GtkToolItem *item; + GdkPixbuf *pixbuf; + GtkWidget *image; - case HISTORY_BUTTON: - image = GTK_IMAGE(gtk_image_new_from_pixbuf(arrow_down_pixbuf)); - break; + res = nsgtk_throbber_get_frame(0, &pixbuf); + if (res != NSERROR_OK) { + return NULL; + } - default: - image = NULL; - break; + if (edit) { + const char *msg; + msg = messages_get("ToolThrob"); + item = gtk_tool_button_new( + GTK_WIDGET(gtk_image_new_from_pixbuf(pixbuf)), + msg); + } else { + item = gtk_tool_item_new(); + + image = gtk_image_new_from_pixbuf(pixbuf); + if (image != NULL) { + nsgtk_widget_set_alignment(image, + GTK_ALIGN_CENTER, + GTK_ALIGN_CENTER); + nsgtk_widget_set_margins(image, 3, 0); + + gtk_container_add(GTK_CONTAINER(item), image); + } + } + gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity); + + return item; +} + + +/** + * create url bar toolbar item widget + * + * create a gtk entry widget with a completion attached + * + * \param sensitivity if the entry should be created sensitive to input + * \param edit if the entry should be editable + */ +static GtkToolItem * +make_toolbar_item_url_bar(bool sensitivity, bool edit) +{ + GtkToolItem *item; + GtkWidget *entry; + GtkEntryCompletion *completion; + + entry = nsgtk_entry_new(); + if (entry == NULL) { + return NULL; } + nsgtk_entry_set_icon_from_icon_name(entry, + GTK_ENTRY_ICON_PRIMARY, + "page-info-internal"); + + if (edit) { + gtk_entry_set_width_chars(GTK_ENTRY(entry), 9); + + item = gtk_tool_button_new(NULL, "URL"); + gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), entry); + } else { + completion = gtk_entry_completion_new(); + if (completion != NULL) { + gtk_entry_set_completion(GTK_ENTRY(entry), completion); + } + + item = gtk_tool_item_new(); + if (item == NULL) { + return NULL; + } + + gtk_container_add(GTK_CONTAINER(item), entry); + gtk_tool_item_set_expand(item, TRUE); - if (usedef && (image == NULL)) { - image = GTK_IMAGE(nsgtk_image_new_from_stock("gtk-missing-image", iconsize)); } + gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(entry), sensitivity); - return image; + return item; } + /** - * Get default image for search buttons / menu items from gtk stock items + * create web search toolbar item widget + */ +static GtkToolItem * +make_toolbar_item_websearch(bool sensitivity, bool edit) +{ + GtkToolItem *item; + nserror res; + GtkWidget *entry; + struct bitmap *bitmap; + GdkPixbuf *pixbuf = NULL; + + res = search_web_get_provider_bitmap(&bitmap); + if ((res == NSERROR_OK) && (bitmap != NULL)) { + pixbuf = nsgdk_pixbuf_get_from_surface(bitmap->surface, 32, 32); + } + + entry = nsgtk_entry_new(); + + if (entry == NULL) { + return NULL; + } + + if (pixbuf != NULL) { + nsgtk_entry_set_icon_from_pixbuf(entry, + GTK_ENTRY_ICON_PRIMARY, + pixbuf); + g_object_unref(pixbuf); + } else { + nsgtk_entry_set_icon_from_icon_name(entry, + GTK_ENTRY_ICON_PRIMARY, + NSGTK_STOCK_INFO); + } + + if (edit) { + gtk_entry_set_width_chars(GTK_ENTRY(entry), 9); + + item = gtk_tool_button_new(NULL, "Web Search"); + gtk_tool_button_set_icon_widget(GTK_TOOL_BUTTON(item), + entry); + } else { + gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, -1); + + item = gtk_tool_item_new(); + if (item == NULL) { + return NULL; + } + + gtk_container_add(GTK_CONTAINER(item), entry); + } + gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(entry), sensitivity); + + return item; +} + + +/** + * create local history toolbar item widget + */ +static GtkToolItem * +make_toolbar_item_history(bool sensitivity, bool edit) +{ + GtkToolItem *item; + const char *msg = "H"; + char *label = NULL; + + if (edit) { + msg = messages_get("gtkLocalHistory"); + } + label = remove_underscores(msg, false); + item = gtk_tool_button_new(NULL, label); + if (label != NULL) { + free(label); + } + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), "local-history"); + + /* set history widget minimum width */ + gtk_widget_set_size_request(GTK_WIDGET(item), 20, -1); + gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity); + + return item; +} + + +/** + * create generic button toolbar item widget + */ +static GtkToolItem * +make_toolbar_item_button(const char *labelmsg, + const char *iconname, + bool sensitivity, + bool edit) +{ + GtkToolItem *item; + char *label = NULL; + + label = remove_underscores(messages_get(labelmsg), false); + + item = gtk_tool_button_new(NULL, label); + if (label != NULL) { + free(label); + } + + if (item != NULL) { + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), iconname); + + gtk_widget_set_sensitive(GTK_WIDGET(item), sensitivity); + if (edit) { + nsgtk_widget_set_margins(GTK_WIDGET(item), 0, 0); + } + } + + return item; +} + + +/** + * widget factory for creation of toolbar item widgets * - * \param tbbutton search button reference - * \param iconsize The size of icons to select. - * \param usedef Use the default image if not found. - * \return default search image. + * \param i the id of the widget + * \param theme the theme to make the widgets from + * \return gtk widget */ +static GtkToolItem * +make_toolbar_item(nsgtk_toolbar_button itemid, bool sensitivity) +{ + GtkToolItem *toolitem = NULL; + + switch(itemid) { +#define TOOLBAR_ITEM_y(identifier, label, iconame) +#define TOOLBAR_ITEM_n(identifier, label, iconame) +#define TOOLBAR_ITEM_t(identifier, label, iconame) \ + case identifier: \ + toolitem = make_toolbar_item_button(#label, iconame, sensitivity, false); \ + break; +#define TOOLBAR_ITEM_b(identifier, label, iconame) \ + case identifier: \ + toolitem = make_toolbar_item_button(#label, iconame, sensitivity, false); \ + break; +#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \ + TOOLBAR_ITEM_ ## clicked(identifier, label, iconame) + +#include "gtk/toolbar_items.h" + +#undef TOOLBAR_ITEM_t +#undef TOOLBAR_ITEM_b +#undef TOOLBAR_ITEM_n +#undef TOOLBAR_ITEM_y +#undef TOOLBAR_ITEM + + case HISTORY_BUTTON: + toolitem = make_toolbar_item_history(sensitivity, false); + break; + + case URL_BAR_ITEM: + toolitem = make_toolbar_item_url_bar(sensitivity, false); + break; -static GtkImage * -nsgtk_theme_searchimage_default(nsgtk_search_buttons tbbutton, - GtkIconSize iconsize, - bool usedef) + case THROBBER_ITEM: + toolitem = make_toolbar_item_throbber(sensitivity, false); + break; + + case WEBSEARCH_ITEM: + toolitem = make_toolbar_item_websearch(sensitivity, false); + break; + + default: + break; + + } + return toolitem; +} + + +/** + * widget factory for creation of toolbar item widgets for the toolbox + * + * \param itemid the id of the widget + * \return gtk tool item widget + */ +static GtkToolItem * +make_toolbox_item(nsgtk_toolbar_button itemid, bool bar) { - GtkImage *image; + GtkToolItem *toolitem = NULL; + + switch(itemid) { +#define TOOLBAR_ITEM_y(identifier, label, iconame) +#define TOOLBAR_ITEM_n(identifier, label, iconame) +#define TOOLBAR_ITEM_t(identifier, label, iconame) \ + case identifier: \ + if (bar) { \ + toolitem = make_toolbar_item_button(#label, iconame, true, true); \ + } \ + break; +#define TOOLBAR_ITEM_b(identifier, label, iconame) \ + case identifier: \ + toolitem = make_toolbar_item_button(#label, iconame, true, true); \ + break; +#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \ + TOOLBAR_ITEM_ ## clicked(identifier, label, iconame) + +#include "gtk/toolbar_items.h" - switch (tbbutton) { +#undef TOOLBAR_ITEM_t +#undef TOOLBAR_ITEM_b +#undef TOOLBAR_ITEM_n +#undef TOOLBAR_ITEM_y +#undef TOOLBAR_ITEM + + case HISTORY_BUTTON: + toolitem = make_toolbar_item_history(true, true); + break; - case (SEARCH_BACK_BUTTON): - image = GTK_IMAGE(nsgtk_image_new_from_stock( - NSGTK_STOCK_GO_BACK, iconsize)); + case URL_BAR_ITEM: + toolitem = make_toolbar_item_url_bar(false, true); break; - case (SEARCH_FORWARD_BUTTON): - image = GTK_IMAGE(nsgtk_image_new_from_stock( - NSGTK_STOCK_GO_FORWARD, iconsize)); + case THROBBER_ITEM: + toolitem = make_toolbar_item_throbber(true, true); break; - case (SEARCH_CLOSE_BUTTON): - image = GTK_IMAGE(nsgtk_image_new_from_stock( - NSGTK_STOCK_CLOSE, iconsize)); + case WEBSEARCH_ITEM: + toolitem = make_toolbar_item_websearch(false, true); break; default: - image = NULL; + break; + } + return toolitem; +} + + +/** + * target entry for drag source + */ +static GtkTargetEntry target_entry = { + (char *)"nsgtk_button_data", + GTK_TARGET_SAME_APP, + 0 +}; + - if (usedef && (image == NULL)) { - image = GTK_IMAGE(nsgtk_image_new_from_stock( - "gtk-missing-image", iconsize)); +/** + * find the toolbar item with a given location. + * + * \param tb the toolbar instance + * \param locaction the location to search for + * \return the item id for a location + */ +static nsgtk_toolbar_button +itemid_from_location(struct nsgtk_toolbar *tb, int location) +{ + int iidx; + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + if (tb->items[iidx].location == location) { + break; + } } + return iidx; +} + - return image; +/** + * save toolbar settings to file + */ +static nserror +nsgtk_toolbar_customisation_save(struct nsgtk_toolbar *tb) +{ + int iidx; /* item index */ + char *order; /* item ordering */ + char *start; /* start of next item name to be output */ + int orderlen = 0; /* length of item ordering */ + nsgtk_toolbar_button itemid; + int location; + char *choices = NULL; + + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + if (tb->items[iidx].location != INACTIVE_LOCATION) { + orderlen += strlen(tb->items[iidx].name); + orderlen++; /* allow for separator */ + } + } + + /* ensure there are some items to store */ + if (orderlen == 0) { + return NSERROR_INVALID; + } + + order = malloc(orderlen); + if (order == NULL) { + return NSERROR_NOMEM; + } + + start = order; + + for (location = BACK_BUTTON; + location < PLACEHOLDER_BUTTON; + location++) { + int written; + itemid = itemid_from_location(tb, location); + if (itemid == PLACEHOLDER_BUTTON) { + /* no more filled locations */ + break; + } + written = snprintf(start, + orderlen - (start - order), + "%s/", + tb->items[itemid].name); + if ((written < 0) || + (written >= orderlen - (start - order))) { + free(order); + return NSERROR_UNKNOWN; + } + start += written; + + if ((start - order) >= orderlen) { + break; + } + } + + order[orderlen - 1] = 0; + + nsoption_set_charp(toolbar_items, order); + + /* ensure choices are saved */ + netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); + if (choices != NULL) { + nsoption_write(choices, NULL, NULL); + free(choices); + } + + return NSERROR_OK; } + /** - * initialise a theme structure with gtk images + * connect signals to a toolbar item in a customisation toolbar * - * \param iconsize The size of icon to load - * \param usedef use the default gtk icon if unset + * \param tb The toolbar + * \param itemid The item id within to toolbar to connect + * \param NSERROR_OK on success */ -static struct nsgtk_theme *nsgtk_theme_load(GtkIconSize iconsize, bool usedef) +static nserror +toolbar_item_connect_signals(struct nsgtk_toolbar *tb, int itemid) { - struct nsgtk_theme *theme; - int btnloop; + /* set toolbar items to be a drag source */ + gtk_tool_item_set_use_drag_window(tb->items[itemid].button, TRUE); + gtk_drag_source_set(GTK_WIDGET(tb->items[itemid].button), + GDK_BUTTON1_MASK, + &target_entry, + 1, + GDK_ACTION_COPY); + g_signal_connect(tb->items[itemid].button, + "drag-data-get", + G_CALLBACK(tb->items[itemid].dataminus), + tb); + return NSERROR_OK; +} - theme = malloc(sizeof(struct nsgtk_theme)); - if (theme == NULL) { - return NULL; + +/** + * customisation container handler for drag drop signal + * + * called when a widget is dropped onto the store window + */ +static gboolean +customisation_container_drag_drop_cb(GtkWidget *widget, + GdkDragContext *gdc, + gint x, gint y, + guint time, + gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + tbc = (struct nsgtk_toolbar_customisation *)data; + int location; + int itemid; + + if ((tbc->dragfrom) || (tbc->dragitem == -1)) { + tbc->dragitem = -1; + return FALSE; } - for (btnloop = BACK_BUTTON; - btnloop < PLACEHOLDER_BUTTON ; - btnloop++) { - theme->image[btnloop] = nsgtk_theme_image_default(btnloop, - iconsize, - usedef); + if (tbc->toolbar.items[tbc->dragitem].location == INACTIVE_LOCATION) { + tbc->dragitem = -1; + gtk_drag_finish(gdc, TRUE, TRUE, time); + return FALSE; + } - for (btnloop = SEARCH_BACK_BUTTON; - btnloop < SEARCH_BUTTONS_COUNT; - btnloop++) { - theme->searchimage[btnloop] = - nsgtk_theme_searchimage_default(btnloop, - iconsize, - usedef); + /* update the locations for all the subsequent toolbar items */ + for (location = tbc->toolbar.items[tbc->dragitem].location; + location < PLACEHOLDER_BUTTON; + location++) { + itemid = itemid_from_location(&tbc->toolbar, location); + if (itemid == PLACEHOLDER_BUTTON) { + break; + } + tbc->toolbar.items[itemid].location--; } - return theme; -} + /* remove existing item */ + tbc->toolbar.items[tbc->dragitem].location = -1; + gtk_container_remove(GTK_CONTAINER(tbc->toolbar.widget), + GTK_WIDGET(tbc->toolbar.items[tbc->dragitem].button)); + + tbc->dragitem = -1; + gtk_drag_finish(gdc, TRUE, TRUE, time); + return FALSE; +} -/* exported function documented in gtk/toolbar.h */ -void nsgtk_theme_implement(struct nsgtk_scaffolding *g) +/** + * customisation container handler for drag motion signal + * + * called when hovering above the store + */ +static gboolean +customisation_container_drag_motion_cb(GtkWidget *widget, + GdkDragContext *gdc, + gint x, gint y, + guint time, + gpointer data) { - struct nsgtk_theme *theme[IMAGE_SET_COUNT]; - int i; - struct nsgtk_button_connect *button; - struct gtk_search *search; + return FALSE; +} - theme[IMAGE_SET_MAIN_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false); - theme[IMAGE_SET_RCLICK_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false); - theme[IMAGE_SET_POPUP_MENU] = nsgtk_theme_load(GTK_ICON_SIZE_MENU, false); - theme[IMAGE_SET_BUTTONS] = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false); - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) || - (i == WEBSEARCH_ITEM)) - continue; +/** + * customisation toolbar handler for drag drop signal + * + * called when a widget is dropped onto the toolbar + */ +static gboolean +customisation_toolbar_drag_drop_cb(GtkWidget *widget, + GdkDragContext *gdc, + gint x, + gint y, + guint time, + gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + tbc = (struct nsgtk_toolbar_customisation *)data; + gint position; /* drop position in toolbar */ + int location; + int itemid; + struct nsgtk_toolbar_item *dragitem; /* toolbar item being dragged */ + + position = gtk_toolbar_get_drop_index(tbc->toolbar.widget, x, y); + if (tbc->dragitem == -1) { + return TRUE; + } - button = nsgtk_scaffolding_button(g, i); - if (button == NULL) - continue; + /* pure conveiance variable */ + dragitem = &tbc->toolbar.items[tbc->dragitem]; - /* gtk_image_menu_item_set_image accepts NULL image */ - if ((button->main != NULL) && - (theme[IMAGE_SET_MAIN_MENU] != NULL)) { - nsgtk_image_menu_item_set_image( - GTK_WIDGET(button->main), - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->image[i])); - gtk_widget_show_all(GTK_WIDGET(button->main)); + /* deal with replacing existing item in toolbar */ + if (dragitem->location != INACTIVE_LOCATION) { + if (dragitem->location < position) { + position--; } - if ((button->rclick != NULL) && - (theme[IMAGE_SET_RCLICK_MENU] != NULL)) { - nsgtk_image_menu_item_set_image(GTK_WIDGET(button->rclick), - GTK_WIDGET( - theme[IMAGE_SET_RCLICK_MENU]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->rclick)); + + /* update the locations for all the subsequent toolbar items */ + for (location = dragitem->location; + location < PLACEHOLDER_BUTTON; + location++) { + itemid = itemid_from_location(&tbc->toolbar, location); + if (itemid == PLACEHOLDER_BUTTON) { + break; + } + tbc->toolbar.items[itemid].location--; } - if ((button->popup != NULL) && - (theme[IMAGE_SET_POPUP_MENU] != NULL)) { - nsgtk_image_menu_item_set_image(GTK_WIDGET(button->popup), - GTK_WIDGET( - theme[IMAGE_SET_POPUP_MENU]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->popup)); + + /* remove existing item */ + dragitem->location = INACTIVE_LOCATION; + gtk_container_remove(GTK_CONTAINER(tbc->toolbar.widget), + GTK_WIDGET(dragitem->button)); + } + + + dragitem->button = make_toolbox_item(tbc->dragitem, true); + + if (dragitem->button == NULL) { + nsgtk_warning("NoMemory", 0); + return TRUE; + } + + /* update locations */ + for (location = PLACEHOLDER_BUTTON; location >= position; location--) { + itemid = itemid_from_location(&tbc->toolbar, location); + if (itemid != PLACEHOLDER_BUTTON) { + tbc->toolbar.items[itemid].location++; } - if ((button->location != -1) && (button->button != NULL) && - (theme[IMAGE_SET_BUTTONS] != NULL)) { - gtk_tool_button_set_icon_widget( - GTK_TOOL_BUTTON(button->button), - GTK_WIDGET( - theme[IMAGE_SET_BUTTONS]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->button)); + } + dragitem->location = position; + + gtk_toolbar_insert(tbc->toolbar.widget, + dragitem->button, + dragitem->location); + + toolbar_item_connect_signals(&tbc->toolbar, tbc->dragitem); + gtk_widget_show_all(GTK_WIDGET(dragitem->button)); + tbc->dragitem = -1; + return TRUE; +} + + +/** + * customisation toolbar handler for drag data received signal + * + * connected to toolbutton drop; perhaps one day it'll work properly + * so it may replace the global current_button + */ +static gboolean +customisation_toolbar_drag_data_received_cb(GtkWidget *widget, + GdkDragContext *gdc, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time, + gpointer data) +{ + return FALSE; +} + + +/** + * customisation toolbar handler for drag motion signal + * + * called when hovering an item above the toolbar + */ +static gboolean +customisation_toolbar_drag_motion_cb(GtkWidget *widget, + GdkDragContext *gdc, + gint x, + gint y, + guint time, + gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + GtkToolItem *item; + gint position; /* position in toolbar */ + + item = gtk_tool_button_new(NULL, NULL); + position = gtk_toolbar_get_drop_index(tb->widget, x, y); + + gtk_toolbar_set_drop_highlight_item(tb->widget, item, position); + + return FALSE; /* drag not in drop zone */ +} + + +/** + * customisation toolbar handler for drag leave signal + * + * called when hovering stops + */ +static void +customisation_toolbar_drag_leave_cb(GtkWidget *widget, + GdkDragContext *gdc, + guint time, + gpointer data) +{ + gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0); +} + + +/** + * create a new browser window + * + * creates a browser window with default url depending on user choices. + * + * \param bw The browser window to pass for existing window/ + * \param intab true if the new window should be in a tab else false + * for new window. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_browser_window_create(struct browser_window *bw, bool intab) +{ + nserror res = NSERROR_OK; + nsurl *url = NULL; + int flags = BW_CREATE_HISTORY | BW_CREATE_FOREGROUND | BW_CREATE_FOCUS_LOCATION; + + if (intab) { + flags |= BW_CREATE_TAB; + } + + if (!nsoption_bool(new_blank)) { + const char *addr; + if (nsoption_charp(homepage_url) != NULL) { + addr = nsoption_charp(homepage_url); + } else { + addr = NETSURF_HOMEPAGE; } + res = nsurl_create(addr, &url); + } + + if (res == NSERROR_OK) { + res = browser_window_create(flags, url, NULL, bw, NULL); + } + + if (url != NULL) { + nsurl_unref(url); + } + + return res; +} + + +/** + * Apply the user toolbar button settings from configuration + * + * GTK specific user option string is a set of fields arranged as + * [itemreference];[itemlocation]|[itemreference];[itemlocation]| etc + * + * \param tb The toolbar to apply customisation to + * \param NSERROR_OK on success else error code. + */ +static nserror +apply_user_button_customisation(struct nsgtk_toolbar *tb) +{ + const char *tbitems; /* item order user config */ + const char *start; + const char *end; + int iidx; /* item index */ + int location = 0; /* location index */ + + /* set all button locations to inactive */ + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + tb->items[iidx].location = INACTIVE_LOCATION; } - /* set search bar images */ - search = nsgtk_scaffolding_search(g); - if ((search != NULL) && (theme[IMAGE_SET_MAIN_MENU] != NULL)) { - /* gtk_tool_button_set_icon_widget accepts NULL image */ - if (search->buttons[SEARCH_BACK_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_BACK_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_BACK_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[SEARCH_BACK_BUTTON])); + tbitems = nsoption_charp(toolbar_items); + if (tbitems == NULL) { + tbitems = ""; + } + + end = tbitems; + while (*end != 0) { + start = end; + while ((*end != 0) && (*end !='/')) { + end++; } - if (search->buttons[SEARCH_FORWARD_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_FORWARD_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_FORWARD_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[ - SEARCH_FORWARD_BUTTON])); + + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + if (((ssize_t)strlen(tb->items[iidx].name) == (end - start)) && + (strncmp(tb->items[iidx].name, start, end - start) == 0)) { + tb->items[iidx].location = location++; + break; + } } - if (search->buttons[SEARCH_CLOSE_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_CLOSE_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_CLOSE_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[SEARCH_CLOSE_BUTTON])); + + if (*end == '/') { + end++; } } - for (i = 0; i < IMAGE_SET_COUNT; i++) { - if (theme[i] != NULL) { - free(theme[i]); - } + if (location == 0) { + /* completely failed to create any buttons so use defaults */ + tb->items[BACK_BUTTON].location = location++; + tb->items[HISTORY_BUTTON].location = location++; + tb->items[FORWARD_BUTTON].location = location++; + tb->items[RELOADSTOP_BUTTON].location = location++; + tb->items[URL_BAR_ITEM].location = location++; + tb->items[WEBSEARCH_ITEM].location = location++; + tb->items[OPENMENU_BUTTON].location = location++; + tb->items[THROBBER_ITEM].location = location++; } + + + return NSERROR_OK; } /** - * callback function to iterate toolbar's widgets + * callback function to remove a widget from a container */ -static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data) +static void container_remove_widget(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), - widget); + GtkContainer *container = GTK_CONTAINER(data); + gtk_container_remove(container, widget); } + /** - * connect temporary handler for toolbar edit events + * populates a toolbar with widgets in correct order * - * \param g The scaffolding - * \param bi The button index + * \param tb toolbar + * \return NSERROR_OK on success else error code. */ -static void nsgtk_toolbar_temp_connect(struct nsgtk_scaffolding *g, - nsgtk_toolbar_button bi) +static nserror populate_gtk_toolbar_widget(struct nsgtk_toolbar *tb) { - struct nsgtk_button_connect *bc; + int location; /* location index */ + int itemid; + + /* clear the toolbar container of all widgets */ + gtk_container_foreach(GTK_CONTAINER(tb->widget), + container_remove_widget, + tb->widget); + + /* add widgets to toolbar */ + for (location = 0; location < PLACEHOLDER_BUTTON; location++) { + itemid = itemid_from_location(tb, location); + if (itemid == PLACEHOLDER_BUTTON) { + break; + } + tb->items[itemid].button = + make_toolbar_item(itemid, + tb->items[itemid].sensitivity); + + gtk_toolbar_insert(tb->widget, + tb->items[itemid].button, + location); + } - if (bi != URL_BAR_ITEM) { - bc = nsgtk_scaffolding_button(g, bi); - if ((bc->button != NULL) && (bc->dataminus != NULL)) { - g_signal_connect(bc->button, - "drag-data-get", - G_CALLBACK(bc->dataminus), - g); + gtk_widget_show_all(GTK_WIDGET(tb->widget)); + + return NSERROR_OK; +} + + +/** + * populates the customization toolbar with widgets in correct order + * + * \param tb toolbar + * \return NSERROR_OK on success else error code. + */ +static nserror customisation_toolbar_populate(struct nsgtk_toolbar *tb) +{ + int location; /* location index */ + int itemid; + + /* clear the toolbar container of all widgets */ + gtk_container_foreach(GTK_CONTAINER(tb->widget), + container_remove_widget, + tb->widget); + + /* add widgets to toolbar */ + for (location = 0; location < PLACEHOLDER_BUTTON; location++) { + itemid = itemid_from_location(tb, location); + if (itemid == PLACEHOLDER_BUTTON) { + break; } + tb->items[itemid].button = make_toolbox_item(itemid, true); + + gtk_toolbar_insert(tb->widget, + tb->items[itemid].button, + location); } + + gtk_widget_show_all(GTK_WIDGET(tb->widget)); + + return NSERROR_OK; } + /** - * get scaffolding button index of button at location + * find the toolbar item with a given gtk widget. * - * \return toolbar item id from location when there is an item at that logical - * location; else -1 + * \param tb the toolbar instance + * \param toolitem the tool item widget to search for + * \return the item id matching the widget */ static nsgtk_toolbar_button -nsgtk_toolbar_get_id_at_location(struct nsgtk_scaffolding *g, int i) +itemid_from_gtktoolitem(struct nsgtk_toolbar *tb, GtkToolItem *toolitem) { - int q; - for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) { - if (nsgtk_scaffolding_button(g, q)->location == i) { - return q; + int iidx; + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + if ((tb->items[iidx].location != INACTIVE_LOCATION) && + (tb->items[iidx].button == toolitem)) { + break; } } - return -1; + return iidx; } + /** - * widget factory for creation of toolbar item widgets - * \param g the reference scaffolding - * \param i the id of the widget - * \param theme the theme to make the widgets from + * set a toolbar items sensitivity + * + * note this does not set menu items sensitivity */ -static GtkWidget * -nsgtk_toolbar_make_widget(struct nsgtk_scaffolding *g, - nsgtk_toolbar_button i, - struct nsgtk_theme *theme) -{ - GtkWidget *w = NULL; - - switch(i) { - -/* gtk_tool_button_new() accepts NULL args */ -#define MAKE_STOCKBUTTON(p, q) \ - case p##_BUTTON: { \ - GtkStockItem item; \ - char *label = NULL; \ - if (nsgtk_stock_lookup(q, &item) && \ - (item.label != NULL) && \ - ((label = remove_underscores(item.label, false)) != NULL)) { \ - w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \ - theme->image[p##_BUTTON]), label)); \ - free(label); \ - } else { \ - w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \ - theme->image[p##_BUTTON]), q)); \ - } \ - break; \ +static nserror +set_item_sensitivity(struct nsgtk_toolbar_item *item, bool sensitivity) +{ + if (item->sensitivity != sensitivity) { + /* item requires sensitivity changing */ + item->sensitivity = sensitivity; + + if ((item->location != -1) && (item->button != NULL)) { + gtk_widget_set_sensitive(GTK_WIDGET(item->button), + item->sensitivity); + } } - MAKE_STOCKBUTTON(HOME, NSGTK_STOCK_HOME) - MAKE_STOCKBUTTON(BACK, NSGTK_STOCK_GO_BACK) - MAKE_STOCKBUTTON(FORWARD, NSGTK_STOCK_GO_FORWARD) - MAKE_STOCKBUTTON(STOP, NSGTK_STOCK_STOP) - MAKE_STOCKBUTTON(RELOAD, NSGTK_STOCK_REFRESH) -#undef MAKE_STOCKBUTTON + return NSERROR_OK; +} - case HISTORY_BUTTON: - w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - theme->image[HISTORY_BUTTON]), "H")); - break; - case URL_BAR_ITEM: { - GtkWidget *entry = nsgtk_entry_new(); - w = GTK_WIDGET(gtk_tool_item_new()); +/** + * set an item to its alternative action + * + * this is currently only used for the stop/reload button where we + * also reuse the item sensitivity for the state indicator. + * + * \param tb the toolbar instance + */ +static nserror set_item_action(struct nsgtk_toolbar *tb, int itemid, bool alt) +{ + const char *iconname; + char *label = NULL; + + if (itemid != RELOADSTOP_BUTTON) { + return NSERROR_INVALID; + } + if (tb->items[itemid].location == -1) { + return NSERROR_OK; + } + tb->items[itemid].sensitivity = alt; - if ((entry == NULL) || (w == NULL)) { - nsgtk_warning(messages_get("NoMemory"), 0); - return NULL; - } + if (tb->items[itemid].button == NULL) { + return NSERROR_INVALID; + } - nsgtk_entry_set_icon_from_pixbuf(entry, - GTK_ENTRY_ICON_PRIMARY, - favicon_pixbuf); + if (tb->items[itemid].sensitivity) { + iconname = NSGTK_STOCK_REFRESH; + label = remove_underscores(messages_get("Reload"), false); + + } else { + iconname = NSGTK_STOCK_STOP; + label = remove_underscores(messages_get("gtkStop"), false); - gtk_container_add(GTK_CONTAINER(w), entry); - gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE); - break; } + gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb->items[itemid].button), + label); - case THROBBER_ITEM: { - if ((nsgtk_throbber == NULL) || - (nsgtk_throbber->framedata == NULL) || - (nsgtk_throbber->framedata[0] == NULL)) { - return NULL; + gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb->items[itemid].button), + iconname); + + gtk_widget_set_sensitive(GTK_WIDGET(tb->items[itemid].button), TRUE); + + if (label != NULL) { + free(label); + } + + return NSERROR_OK; +} + + +/** + * cause the toolbar browsing context to navigate to a new url. + * + * \param tb the toolbar context. + * \param urltxt The url string. + * \return NSERROR_OK on success else appropriate error code. + */ +static nserror +toolbar_navigate_to_url(struct nsgtk_toolbar *tb, const char *urltxt) +{ + struct browser_window *bw; + nsurl *url; + nserror res; + + res = nsurl_create(urltxt, &url); + if (res != NSERROR_OK) { + return res; + } + + bw = tb->get_bw(tb->get_ctx); + + res = browser_window_navigate(bw, + url, + NULL, + BW_NAVIGATE_HISTORY, + NULL, + NULL, + NULL); + nsurl_unref(url); + + return res; +} + + +/** + * run a gtk file chooser as a save dialog to obtain a path + */ +static nserror +nsgtk_saveas_dialog(struct browser_window *bw, + const char *title, + GtkWindow *parent, + bool folder, + gchar **path_out) +{ + nserror res; + GtkWidget *fc; /* file chooser widget */ + GtkFileChooserAction action; + char *path; /* proposed path */ + + if (!browser_window_has_content(bw)) { + /* cannot save a page with no content */ + return NSERROR_INVALID; + } + + if (folder) { + action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; + } else { + action = GTK_FILE_CHOOSER_ACTION_SAVE; + } + + fc = gtk_file_chooser_dialog_new(title, + parent, + action, + NSGTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + NSGTK_STOCK_SAVE, + GTK_RESPONSE_ACCEPT, + NULL); + + /* set a default file name */ + res = nsurl_nice(browser_window_access_url(bw), &path, false); + if (res != NSERROR_OK) { + path = strdup(messages_get("SaveText")); + if (path == NULL) { + gtk_widget_destroy(fc); + return NSERROR_NOMEM; } + } - if (edit_mode) { - w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - gtk_image_new_from_pixbuf( - nsgtk_throbber->framedata[0])), - "[throbber]")); - } else { - GtkWidget *image; + if ((!folder) || (access(path, F_OK) != 0)) { + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), path); + } + free(path); - w = GTK_WIDGET(gtk_tool_item_new()); + /* confirm overwriting */ + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc), TRUE); - image = gtk_image_new_from_pixbuf(nsgtk_throbber->framedata[0]); - if (image != NULL) { - nsgtk_widget_set_alignment(image, - GTK_ALIGN_CENTER, - GTK_ALIGN_CENTER); - nsgtk_widget_set_margins(image, 3, 0); + /* run the dialog to let user select path */ + if (gtk_dialog_run(GTK_DIALOG(fc)) != GTK_RESPONSE_ACCEPT) { + gtk_widget_destroy(fc); + return NSERROR_NOT_FOUND; + } - gtk_container_add(GTK_CONTAINER(w), image); - } + *path_out = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); + + gtk_widget_destroy(fc); + + return NSERROR_OK; +} + + +/** + * connect all signals to widgets in a customisation + */ +static nserror +toolbar_customisation_connect_signals(struct nsgtk_toolbar *tb) +{ + int iidx; + + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + /* skip inactive items in toolbar */ + if (tb->items[iidx].location != INACTIVE_LOCATION) { + toolbar_item_connect_signals(tb, iidx); } - break; } - case WEBSEARCH_ITEM: { - if (edit_mode) - return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - nsgtk_image_new_from_stock(NSGTK_STOCK_FIND, - GTK_ICON_SIZE_LARGE_TOOLBAR)), - "[websearch]")); + /* add move button listeners */ + g_signal_connect(tb->widget, + "drag-drop", + G_CALLBACK(customisation_toolbar_drag_drop_cb), + tb); + g_signal_connect(tb->widget, + "drag-data-received", + G_CALLBACK(customisation_toolbar_drag_data_received_cb), + tb); + g_signal_connect(tb->widget, + "drag-motion", + G_CALLBACK(customisation_toolbar_drag_motion_cb), + tb); + g_signal_connect(tb->widget, + "drag-leave", + G_CALLBACK(customisation_toolbar_drag_leave_cb), + tb); + + /* set data types */ + gtk_drag_dest_set(GTK_WIDGET(tb->widget), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &target_entry, + 1, + GDK_ACTION_COPY); + + return NSERROR_OK; +} + + +static void +item_size_allocate_cb(GtkWidget *widget, + GdkRectangle *alloc, + gpointer user_data) +{ + if (alloc->width > NSGTK_BUTTON_WIDTH) { + alloc->width = NSGTK_BUTTON_WIDTH; + } + if (alloc->height > NSGTK_BUTTON_HEIGHT) { + alloc->height = NSGTK_BUTTON_HEIGHT; + } + gtk_widget_set_allocation(widget, alloc); +} + - GtkWidget *entry = nsgtk_entry_new(); +/** + * add a row to a toolbar customisation toolbox + * + * \param tbc The toolbar customisation context + * \param startitem The item index of the beginning of the row + * \param enditem The item index of the beginning of the next row + * \return NSERROR_OK on successs else error + */ +static nserror +add_toolbox_row(struct nsgtk_toolbar_customisation *tbc, + int startitem, + int enditem) +{ + GtkToolbar *rowbar; + int iidx; - w = GTK_WIDGET(gtk_tool_item_new()); + rowbar = GTK_TOOLBAR(gtk_toolbar_new()); + if (rowbar == NULL) { + return NSERROR_NOMEM; + } - if ((entry == NULL) || (w == NULL)) { - nsgtk_warning(messages_get("NoMemory"), 0); - return NULL; + gtk_toolbar_set_style(rowbar, GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size(rowbar, GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start(tbc->toolbox, GTK_WIDGET(rowbar), FALSE, FALSE, 0); + + for (iidx = startitem; iidx < enditem; iidx++) { + if (tbc->items[iidx] == NULL) { + /* skip any widgets that failed to initialise */ + continue; } + gtk_widget_set_size_request(GTK_WIDGET(tbc->items[iidx]), + NSGTK_BUTTON_WIDTH, + NSGTK_BUTTON_HEIGHT); + gtk_tool_item_set_use_drag_window(tbc->items[iidx], TRUE); + gtk_drag_source_set(GTK_WIDGET(tbc->items[iidx]), + GDK_BUTTON1_MASK, + &target_entry, + 1, + GDK_ACTION_COPY); + g_signal_connect(tbc->items[iidx], + "drag-data-get", + G_CALLBACK(tbc->toolbar.items[iidx].dataplus), + &tbc->toolbar); + g_signal_connect(tbc->items[iidx], + "size-allocate", + G_CALLBACK(item_size_allocate_cb), + NULL); + gtk_toolbar_insert(rowbar, tbc->items[iidx], -1); + } + return NSERROR_OK; +} - gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, -1); - nsgtk_entry_set_icon_from_stock(entry, GTK_ENTRY_ICON_PRIMARY, - NSGTK_STOCK_INFO); +/** + * creates widgets in customisation toolbox + * + * \param tbc The toolbar customisation context + * \param width The width to layout the toolbox to + * \return NSERROR_OK on success else error code. + */ +static nserror +toolbar_customisation_create_toolbox(struct nsgtk_toolbar_customisation *tbc, + int width) +{ + int columns; /* number of items in a single row */ + int curcol; /* current column in creation */ + int iidx; /* item index */ + int startidx; /* index of item at start of row */ + + /* ensure there are a minimum number of items per row */ + columns = width / NSGTK_BUTTON_WIDTH; + if (columns < NSGTK_MIN_STORE_COLUMNS) { + columns = NSGTK_MIN_STORE_COLUMNS; + } - gtk_container_add(GTK_CONTAINER(w), entry); - break; + curcol = 0; + for (iidx = startidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + if (curcol >= columns) { + add_toolbox_row(tbc, startidx, iidx); + curcol = 0; + startidx = iidx; + } + tbc->items[iidx] = make_toolbox_item(iidx, false); + if (tbc->items[iidx] != NULL) { + curcol++; + } + } + if (curcol > 0) { + add_toolbox_row(tbc, startidx, iidx); } -/* gtk_tool_button_new accepts NULL args */ -#define MAKE_MENUBUTTON(p, q) \ - case p##_BUTTON: { \ - char *label = NULL; \ - label = remove_underscores(messages_get(#q), false); \ - w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( \ - theme->image[p##_BUTTON]), label)); \ - if (label != NULL) \ - free(label); \ - break; \ - } - - MAKE_MENUBUTTON(NEWWINDOW, gtkNewWindow) - MAKE_MENUBUTTON(NEWTAB, gtkNewTab) - MAKE_MENUBUTTON(OPENFILE, gtkOpenFile) - MAKE_MENUBUTTON(CLOSETAB, gtkCloseTab) - MAKE_MENUBUTTON(CLOSEWINDOW, gtkCloseWindow) - MAKE_MENUBUTTON(SAVEPAGE, gtkSavePage) - MAKE_MENUBUTTON(PRINTPREVIEW, gtkPrintPreview) - MAKE_MENUBUTTON(PRINT, gtkPrint) - MAKE_MENUBUTTON(QUIT, gtkQuitMenu) - MAKE_MENUBUTTON(CUT, gtkCut) - MAKE_MENUBUTTON(COPY, gtkCopy) - MAKE_MENUBUTTON(PASTE, gtkPaste) - MAKE_MENUBUTTON(DELETE, gtkDelete) - MAKE_MENUBUTTON(SELECTALL, gtkSelectAll) - MAKE_MENUBUTTON(PREFERENCES, gtkPreferences) - MAKE_MENUBUTTON(ZOOMPLUS, gtkZoomPlus) - MAKE_MENUBUTTON(ZOOMMINUS, gtkZoomMinus) - MAKE_MENUBUTTON(ZOOMNORMAL, gtkZoomNormal) - MAKE_MENUBUTTON(FULLSCREEN, gtkFullScreen) - MAKE_MENUBUTTON(VIEWSOURCE, gtkViewSource) - MAKE_MENUBUTTON(CONTENTS, gtkContents) - MAKE_MENUBUTTON(ABOUT, gtkAbout) - MAKE_MENUBUTTON(PDF, gtkPDF) - MAKE_MENUBUTTON(PLAINTEXT, gtkPlainText) - MAKE_MENUBUTTON(DRAWFILE, gtkDrawFile) - MAKE_MENUBUTTON(POSTSCRIPT, gtkPostScript) - MAKE_MENUBUTTON(FIND, gtkFind) - MAKE_MENUBUTTON(DOWNLOADS, gtkDownloads) - MAKE_MENUBUTTON(SAVEWINDOWSIZE, gtkSaveWindowSize) - MAKE_MENUBUTTON(TOGGLEDEBUGGING, gtkToggleDebugging) - MAKE_MENUBUTTON(SAVEBOXTREE, gtkDebugBoxTree) - MAKE_MENUBUTTON(SAVEDOMTREE, gtkDebugDomTree) - MAKE_MENUBUTTON(LOCALHISTORY, gtkLocalHistory) - MAKE_MENUBUTTON(GLOBALHISTORY, gtkGlobalHistory) - MAKE_MENUBUTTON(ADDBOOKMARKS, gtkAddBookMarks) - MAKE_MENUBUTTON(SHOWBOOKMARKS, gtkShowBookMarks) - MAKE_MENUBUTTON(SHOWCOOKIES, gtkShowCookies) - MAKE_MENUBUTTON(OPENLOCATION, gtkOpenLocation) - MAKE_MENUBUTTON(NEXTTAB, gtkNextTab) - MAKE_MENUBUTTON(PREVTAB, gtkPrevTab) - MAKE_MENUBUTTON(GUIDE, gtkGuide) - MAKE_MENUBUTTON(INFO, gtkUserInformation) -#undef MAKE_MENUBUTTON + return NSERROR_OK; +} - default: - break; +/** + * update toolbar in customisation to user settings + */ +static nserror +customisation_toolbar_update(struct nsgtk_toolbar_customisation *tbc) +{ + nserror res; + + res = apply_user_button_customisation(&tbc->toolbar); + if (res != NSERROR_OK) { + return res; + } + + /* populate toolbar widget */ + res = customisation_toolbar_populate(&tbc->toolbar); + if (res != NSERROR_OK) { + return res; + } + + /* ensure icon sizes and text labels on toolbar are set */ + res = nsgtk_toolbar_restyle(&tbc->toolbar); + if (res != NSERROR_OK) { + return res; } - return w; + + /* attach handlers to toolbar widgets */ + res = toolbar_customisation_connect_signals(&tbc->toolbar); + if (res != NSERROR_OK) { + return res; + } + + return NSERROR_OK; } + /** - * called when a widget is dropped onto the toolbar + * customisation apply handler for clicked signal + * + * when 'save settings' button is clicked + */ +static gboolean +customisation_apply_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + tbc = (struct nsgtk_toolbar_customisation *)data; + + /* save state to file, update toolbars for all windows */ + nsgtk_toolbar_customisation_save(&tbc->toolbar); + nsgtk_window_toolbar_update(); + gtk_widget_destroy(tbc->container); + + return TRUE; +} + + +/** + * customisation reset handler for clicked signal + * + * when 'reload defaults' button is clicked */ static gboolean -nsgtk_toolbar_data(GtkWidget *widget, - GdkDragContext *gdc, - gint x, - gint y, - guint time, - gpointer data) -{ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g), - x, y); - int q, i; - if (window->currentbutton == -1) +customisation_reset_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + tbc = (struct nsgtk_toolbar_customisation *)data; + + customisation_toolbar_update(tbc); + + return TRUE; +} + + +/** + * customisation container destroy handler + */ +static void customisation_container_destroy_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + tbc = (struct nsgtk_toolbar_customisation *)data; + + free(tbc); +} + +/* + * Toolbar button clicked handlers + */ + +/** + * create a toolbar customisation tab + * + * this is completely different approach to previous implementation. it + * is not modal and the toolbar configuration is performed completely + * within the tab. once the user is happy they can apply the change or + * cancel as they see fit while continuing to use the browser as usual. + */ +static gboolean cutomize_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar_customisation *tbc; + nserror res; + GtkBuilder *builder; + GtkNotebook *notebook; /* notebook containing widget */ + GtkAllocation notebook_alloc; /* notebook size allocation */ + int iidx; /* item index */ + + /* obtain the notebook being added to */ + notebook = GTK_NOTEBOOK(gtk_widget_get_ancestor(widget, + GTK_TYPE_NOTEBOOK)); + if (notebook == NULL) { return TRUE; - struct nsgtk_theme *theme = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false); - if (theme == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); + } + + /* create builder */ + res = nsgtk_builder_new_from_resname("toolbar", &builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Toolbar UI builder init failed"); return TRUE; } - if (nsgtk_scaffolding_button(g, window->currentbutton)->location - != -1) { - /* widget was already in the toolbar; so replace */ - if (nsgtk_scaffolding_button(g, window->currentbutton)-> - location < ind) - ind--; - gtk_container_remove(GTK_CONTAINER( - nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button)); - /* 'move' all widgets further right than the original location, - * one place to the left in logical schema */ - for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> - location + 1; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location--; - } - nsgtk_scaffolding_button(g, window->currentbutton)-> - location = -1; - } - nsgtk_scaffolding_button(g, window->currentbutton)->button = - GTK_TOOL_ITEM(nsgtk_toolbar_make_widget(g, - window->currentbutton, theme)); - free(theme); - if (nsgtk_scaffolding_button(g, window->currentbutton)->button - == NULL) { - nsgtk_warning("NoMemory", 0); + gtk_builder_connect_signals(builder, NULL); + + /* create nsgtk_toolbar_customisation which has nsgtk_toolbar + * at the front so we can reuse functions that take + * nsgtk_toolbar + */ + tbc = calloc(1, sizeof(struct nsgtk_toolbar_customisation)); + if (tbc == NULL) { + g_object_unref(builder); return TRUE; } - /* update logical schema */ - nsgtk_scaffolding_reset_offset(g); - /* 'move' all widgets further right than the new location, one place to - * the right in logical schema */ - for (i = PLACEHOLDER_BUTTON - 1; i >= ind; i--) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location++; + + /* get container box widget which forms a page of the tabs */ + tbc->container = GTK_WIDGET(gtk_builder_get_object(builder, "customisation")); + if (tbc->container == NULL) { + goto cutomize_button_clicked_cb_error; } - nsgtk_scaffolding_button(g, window->currentbutton)->location = ind; - /* complete action */ - GtkToolItem *current_button; + /* vertical box for the toolbox to drag items into and out of */ + tbc->toolbox = GTK_BOX(gtk_builder_get_object(builder, "toolbox")); + if (tbc->toolbox == NULL) { + goto cutomize_button_clicked_cb_error; + } - current_button = GTK_TOOL_ITEM(nsgtk_scaffolding_button(g, window->currentbutton)->button); + /* customisation toolbar container */ + tbc->toolbar.widget = GTK_TOOLBAR(gtk_builder_get_object(builder, "toolbar")); + if (tbc->toolbar.widget == NULL) { + goto cutomize_button_clicked_cb_error; + } - gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), current_button, ind); + /* build customisation toolbar */ + gtk_toolbar_set_show_arrow(tbc->toolbar.widget, TRUE); - gtk_tool_item_set_use_drag_window(current_button, TRUE); - gtk_drag_source_set(GTK_WIDGET(current_button), - GDK_BUTTON1_MASK, &entry, 1, - GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, window->currentbutton); - gtk_widget_show_all(GTK_WIDGET(current_button)); + for (iidx = BACK_BUTTON; iidx < PLACEHOLDER_BUTTON; iidx++) { + res = toolbar_item_create(iidx, &tbc->toolbar.items[iidx]); + if (res != NSERROR_OK) { + goto cutomize_button_clicked_cb_error; + } + } + + res = customisation_toolbar_update(tbc); + if (res != NSERROR_OK) { + goto cutomize_button_clicked_cb_error; + } + + /* use toolbox for widgets to drag to/from */ + gtk_widget_get_allocation(GTK_WIDGET(notebook), ¬ebook_alloc); + + res = toolbar_customisation_create_toolbox(tbc, notebook_alloc.width); + if (res != NSERROR_OK) { + goto cutomize_button_clicked_cb_error; + } + + /* configure the container */ + gtk_drag_dest_set(GTK_WIDGET(tbc->container), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &target_entry, + 1, + GDK_ACTION_COPY); + + /* discard button calls destroy */ + g_signal_connect_swapped(GTK_WIDGET(gtk_builder_get_object(builder, + "discard")), + "clicked", + G_CALLBACK(gtk_widget_destroy), + tbc->container); + + /* save and update on apply button */ + g_signal_connect(GTK_WIDGET(gtk_builder_get_object(builder, "apply")), + "clicked", + G_CALLBACK(customisation_apply_clicked_cb), + tbc); + + g_signal_connect(GTK_WIDGET(gtk_builder_get_object(builder, "reset")), + "clicked", + G_CALLBACK(customisation_reset_clicked_cb), + tbc); + + /* close and cleanup on delete signal */ + g_signal_connect(tbc->container, + "destroy", + G_CALLBACK(customisation_container_destroy_cb), + tbc); + + + g_signal_connect(tbc->container, + "drag-drop", + G_CALLBACK(customisation_container_drag_drop_cb), + tbc); + + g_signal_connect(tbc->container, + "drag-motion", + G_CALLBACK(customisation_container_drag_motion_cb), + tbc); - window->currentbutton = -1; + nsgtk_tab_add_page(notebook, + tbc->container, + false, + messages_get("gtkCustomizeToolbarTitle"), + favicon_pixbuf); + + /* safe to drop the reference to the builder as the container is + * referenced by the notebook now. + */ + g_object_unref(builder); + + return TRUE; + + cutomize_button_clicked_cb_error: + free(tbc); + g_object_unref(builder); return TRUE; + +} + + +/** + * callback for all toolbar items widget size allocation + * + * handler connected to all toolbar items for the size-allocate signal + * + * \param widget The widget the signal is being delivered to. + * \param alloc The size allocation being set. + * \param data The toolbar context passed when the signal was connected + */ +static void +toolbar_item_size_allocate_cb(GtkWidget *widget, + GtkAllocation *alloc, + gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + nsgtk_toolbar_button itemid; + + itemid = itemid_from_gtktoolitem(tb, GTK_TOOL_ITEM(widget)); + + if ((tb->toolbarmem == alloc->x) || + (tb->items[itemid].location < tb->items[HISTORY_BUTTON].location)) { + /* + * no reallocation after first adjustment, + * no reallocation for buttons left of history button + */ + return; + } + + if (itemid == HISTORY_BUTTON) { + if (alloc->width == 20) { + return; + } + + tb->toolbarbase = alloc->y + alloc->height; + tb->historybase = alloc->x + 20; + if (tb->offset == 0) { + tb->offset = alloc->width - 20; + } + alloc->width = 20; + } else if (tb->items[itemid].location <= tb->items[URL_BAR_ITEM].location) { + alloc->x -= tb->offset; + if (itemid == URL_BAR_ITEM) { + alloc->width += tb->offset; + } + } + tb->toolbarmem = alloc->x; + + gtk_widget_size_allocate(widget, alloc); } + /** - * connected to toolbutton drop; perhaps one day it'll work properly so it may - * replace the global current_button + * handler for back tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ static gboolean -nsgtk_toolbar_move_complete(GtkWidget *widget, - GdkDragContext *gdc, - gint x, - gint y, - GtkSelectionData *selection, - guint info, - guint time, - gpointer data) +back_button_clicked_cb(GtkWidget *widget, gpointer data) { - return FALSE; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + if ((bw != NULL) && browser_window_history_back_available(bw)) { + /* clear potential search effects */ + browser_window_search_clear(bw); + + browser_window_history_back(bw, false); + + set_item_sensitivity(&tb->items[BACK_BUTTON], + browser_window_history_back_available(bw)); + set_item_sensitivity(&tb->items[FORWARD_BUTTON], + browser_window_history_forward_available(bw)); + + nsgtk_local_history_hide(); + } + return TRUE; } + /** - * called when hovering an item above the toolbar + * handler for forward tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ static gboolean -nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x, - gint y, guint time, gpointer data) -{ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - GtkToolItem *item = gtk_tool_button_new(NULL, NULL); - if (item != NULL) - gtk_toolbar_set_drop_highlight_item( - nsgtk_scaffolding_toolbar(g), - GTK_TOOL_ITEM(item), - gtk_toolbar_get_drop_index( - nsgtk_scaffolding_toolbar(g), x, y)); - return FALSE; +forward_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + if ((bw != NULL) && browser_window_history_forward_available(bw)) { + /* clear potential search effects */ + browser_window_search_clear(bw); + + browser_window_history_forward(bw, false); + + set_item_sensitivity(&tb->items[BACK_BUTTON], + browser_window_history_back_available(bw)); + set_item_sensitivity(&tb->items[FORWARD_BUTTON], + browser_window_history_forward_available(bw)); + nsgtk_local_history_hide(); + } + return TRUE; } + /** - * called when hovering stops + * handler for stop tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static void -nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time, - gpointer data) +static gboolean +stop_button_clicked_cb(GtkWidget *widget, gpointer data) { - gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0); + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + + browser_window_stop(tb->get_bw(tb->get_ctx)); + + return TRUE; +} + + +/** + * handler for reload tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +reload_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + /* clear potential search effects */ + browser_window_search_clear(bw); + + browser_window_reload(bw, true); + + return TRUE; +} + + +/** + * handler for reload/stop tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +reloadstop_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + /* clear potential search effects */ + browser_window_search_clear(bw); + + if (tb->items[RELOADSTOP_BUTTON].sensitivity) { + browser_window_reload(bw, true); + } else { + browser_window_stop(tb->get_bw(tb->get_ctx)); + } + + return TRUE; +} + + +/** + * handler for home tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +home_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + nserror res; + const char *addr; + + if (nsoption_charp(homepage_url) != NULL) { + addr = nsoption_charp(homepage_url); + } else { + addr = NETSURF_HOMEPAGE; + } + + res = toolbar_navigate_to_url(tb, addr); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; +} + + +/** + * callback for url entry widget activation + * + * handler connected to url entry widget for the activate signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE to allow activation. + */ +static gboolean url_entry_activate_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + nsurl *url; + + res = search_web_omni(gtk_entry_get_text(GTK_ENTRY(widget)), + SEARCH_WEB_OMNI_NONE, + &url); + if (res == NSERROR_OK) { + bw = tb->get_bw(tb->get_ctx); + res = browser_window_navigate( + bw, url, NULL, BW_NAVIGATE_HISTORY, NULL, NULL, NULL); + nsurl_unref(url); + } + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; +} + + +/** + * callback for url entry widget changing + * + * handler connected to url entry widget for the change signal + * + * \param widget The widget the signal is being delivered to. + * \param event The key change event that changed the entry. + * \param data The toolbar context passed when the signal was connected + * \return TRUE to allow activation. + */ +static gboolean +url_entry_changed_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + return nsgtk_completion_update(GTK_ENTRY(widget)); } + /** - * add item to toolbar. + * callback for url entry widget icon button release * - * the function should be called, when multiple items are being added, - * in ascending order. + * handler connected to url entry widget for the icon release signal * - * \param g the scaffolding whose toolbar an item is added to. - * \param i the location in the toolbar. - * \param theme The theme in use. + * \param widget The widget the signal is being delivered to. + * \param event The key change event that changed the entry. + * \param data The toolbar context passed when the signal was connected + * \return TRUE to allow activation. */ static void -nsgtk_toolbar_add_item_to_toolbar(struct nsgtk_scaffolding *g, int i, - struct nsgtk_theme *theme) -{ - int q; - for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) - if (nsgtk_scaffolding_button(g, q)->location == i) { - nsgtk_scaffolding_button(g, q)->button = GTK_TOOL_ITEM( - nsgtk_toolbar_make_widget(g, q, - theme)); - gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), - nsgtk_scaffolding_button(g, q)->button, - i); - break; - } +url_entry_icon_release_cb(GtkEntry *entry, + GtkEntryIconPosition icon_pos, + GdkEvent *event, + gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + nsgtk_page_info(bw); +} + + +/** + * handler for web search tool bar entry item activate signal + * + * handler connected to web search entry widget for the activate signal + * + * \todo make this user selectable to switch between opening in new + * and navigating current window. Possibly improve core search_web interfaces + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean websearch_entry_activate_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + nsurl *url; + + res = search_web_omni(gtk_entry_get_text(GTK_ENTRY(widget)), + SEARCH_WEB_OMNI_SEARCHONLY, + &url); + if (res == NSERROR_OK) { + bw = tb->get_bw(tb->get_ctx); + + res = browser_window_create( + BW_CREATE_HISTORY | BW_CREATE_TAB | BW_CREATE_FOREGROUND, + url, + NULL, + bw, + NULL); + nsurl_unref(url); + } + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; } /** - * cleanup code physical update of all toolbars; resensitize - * \param g the 'front' scaffolding that called customize + * handler for web search tool bar item button press signal + * + * allows a click in the websearch entry field to clear the name of the + * provider. + * + * \todo this does not work well, different behaviour wanted perhaps? + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static void nsgtk_toolbar_close(struct nsgtk_scaffolding *g) +static gboolean +websearch_entry_button_press_cb(GtkWidget *widget, + GdkEventFocus *f, + gpointer data) { - int i; + gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1); + gtk_widget_grab_focus(GTK_WIDGET(widget)); - struct nsgtk_scaffolding *list; - struct nsgtk_theme *theme; + return TRUE; +} - list = nsgtk_scaffolding_iterate(NULL); - while (list) { - theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false); - if (theme == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - continue; - } - /* clear toolbar */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar( - list)), nsgtk_toolbar_clear_toolbar, list); - /* then add items */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_toolbar_add_item_to_toolbar(list, i, theme); + +/** + * handler for new window tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +newwindow_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + + res = nsgtk_browser_window_create(tb->get_bw(tb->get_ctx), false); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; +} + + +/** + * handler for new tab tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +newtab_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + + res = nsgtk_browser_window_create(tb->get_bw(tb->get_ctx), true); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + return TRUE; +} + + +/** + * handler for open file tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +openfile_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWidget *dlgOpen; + gint response; + GtkWidget *toplevel; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + dlgOpen = gtk_file_chooser_dialog_new("Open File", + GTK_WINDOW(toplevel), + GTK_FILE_CHOOSER_ACTION_OPEN, + NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NSGTK_STOCK_OPEN, GTK_RESPONSE_OK, + NULL, NULL); + + response = gtk_dialog_run(GTK_DIALOG(dlgOpen)); + if (response == GTK_RESPONSE_OK) { + char *urltxt; + gchar *filename; + nserror res; + nsurl *url; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlgOpen)); + + urltxt = malloc(strlen(filename) + FILE_SCHEME_PREFIX_LEN + 1); + if (urltxt != NULL) { + sprintf(urltxt, FILE_SCHEME_PREFIX"%s", filename); + + res = nsurl_create(urltxt, &url); + if (res == NSERROR_OK) { + bw = tb->get_bw(tb->get_ctx); + res = browser_window_navigate(bw, + url, + NULL, + BW_NAVIGATE_HISTORY, + NULL, + NULL, + NULL); + nsurl_unref(url); + } + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + free(urltxt); } - nsgtk_toolbar_connect_all(list); - gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar( - list))); - nsgtk_scaffolding_set_sensitivity(list); - nsgtk_widget_override_background_color(GTK_WIDGET(nsgtk_window_get_layout(nsgtk_scaffolding_top_level(list))), GTK_STATE_NORMAL, 0, 0xFFFF, 0xFFFF, 0xFFFF); - g_signal_handler_unblock(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_CLICK)); - g_signal_handler_unblock(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_REDRAW)); - browser_window_refresh_url_bar( - nsgtk_get_browser_window( - nsgtk_scaffolding_top_level(list))); - - if (list != g) - gtk_widget_set_sensitive(GTK_WIDGET( - nsgtk_scaffolding_window(list)), TRUE); - free(theme); - list = nsgtk_scaffolding_iterate(list); - } - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), - TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), - TRUE); - /* update favicon etc */ - nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g)); - - search_web_select_provider(-1); -} - -/** - * when cancel button is clicked - */ -static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data) -{ - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - - edit_mode = false; - /* reset g->buttons->location */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_scaffolding_button(g, i)->location = - window->buttonlocations[i]; - } - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_connect_all(g); - nsgtk_toolbar_close(g); - nsgtk_scaffolding_set_sensitivity(g); - gtk_widget_destroy(window->window); + + + g_free(filename); + } + + gtk_widget_destroy(dlgOpen); + + return TRUE; +} + + +/** + * handler for close window tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +closewindow_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWidget *toplevel; + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + gtk_widget_destroy(toplevel); return TRUE; } + /** - * physically add widgets to store window + * handler for full save export tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget) +static gboolean +savepage_button_clicked_cb(GtkWidget *widget, gpointer data) { - if (window->numberh >= NSGTK_STORE_WIDTH) { - window->currentbar = gtk_toolbar_new(); - if (window->currentbar == NULL) { - nsgtk_warning("NoMemory", 0); - return false; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + DIR *d; + gchar *path; + nserror res; + GtkWidget *toplevel; + + bw = tb->get_bw(tb->get_ctx); + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + res = nsgtk_saveas_dialog(bw, + messages_get("gtkcompleteSave"), + GTK_WINDOW(toplevel), + true, + &path); + if (res != NSERROR_OK) { + return FALSE; + } + + d = opendir(path); + if (d == NULL) { + NSLOG(netsurf, INFO, + "Unable to open directory %s for complete save: %s", + path, + strerror(errno)); + if (errno == ENOTDIR) { + nsgtk_warning("NoDirError", path); + } else { + nsgtk_warning("gtkFileError", path); } - gtk_toolbar_set_style(GTK_TOOLBAR(window->currentbar), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(window->currentbar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_box_pack_start(GTK_BOX(window->widgetvbox), - window->currentbar, FALSE, FALSE, 0); - window->numberh = 0; + g_free(path); + return TRUE; } - gtk_widget_set_size_request(widget, NSGTK_BUTTON_WIDTH, - NSGTK_BUTTON_HEIGHT); - gtk_toolbar_insert(GTK_TOOLBAR(window->currentbar), GTK_TOOL_ITEM( - widget), window->numberh++); - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(widget), TRUE); - gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &entry, 1, - GDK_ACTION_COPY); - gtk_widget_show_all(window->window); - return true; + closedir(d); + + save_complete(browser_window_get_content(bw), path, NULL); + g_free(path); + + return TRUE; } /** - * cast toolbar settings to all scaffoldings referenced from the global linked - * list of gui_windows + * handler for pdf export tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static void nsgtk_toolbar_cast(struct nsgtk_scaffolding *g) +static gboolean +pdf_button_clicked_cb(GtkWidget *widget, gpointer data) { - int i; - struct nsgtk_scaffolding *list; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *toplevel; + gchar *filename; + nserror res; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - window->buttonlocations[i] = - ((nsgtk_scaffolding_button(g, i)->location - >= -1) && - (nsgtk_scaffolding_button(g, i)->location - < PLACEHOLDER_BUTTON)) ? - nsgtk_scaffolding_button(g, i)->location : -1; + bw = tb->get_bw(tb->get_ctx); + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + res = nsgtk_saveas_dialog(bw, + "Export to PDF", + GTK_WINDOW(toplevel), + false, + &filename); + if (res != NSERROR_OK) { + return FALSE; } - list = nsgtk_scaffolding_iterate(NULL); - while (list) { - if (list != g) - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_scaffolding_button(list, i)->location = - window->buttonlocations[i]; - list = nsgtk_scaffolding_iterate(list); +#ifdef WITH_PDF_EXPORT + struct print_settings *settings; + + /* this way the scale used by PDF functions is synchronised with that + * used by the all-purpose print interface + */ + haru_nsfont_set_scale((float)option_export_scale / 100); + + settings = print_make_settings(PRINT_OPTIONS, + (const char *) filename, + &haru_nsfont); + g_free(filename); + if (settings == NULL) { + return TRUE; } + /* This will clean up the print_settings object for us */ + print_basic_run(browser_window_get_content(bw), &pdf_printer, settings); +#endif + return TRUE; + } /** - * load toolbar settings from file; file is a set of fields arranged as - * [itemreference];[itemlocation]|[itemreference];[itemlocation]| etc + * handler for plain text export tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -void nsgtk_toolbar_customization_load(struct nsgtk_scaffolding *g) +static gboolean +plaintext_button_clicked_cb(GtkWidget *widget, gpointer data) { - int i, ii; - char *buffer; - char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *toplevel; + gchar *filename; + nserror res; + + bw = tb->get_bw(tb->get_ctx); - /* default toolbar button order */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_scaffolding_button(g, i)->location = - (i <= THROBBER_ITEM) ? i : -1; + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + res = nsgtk_saveas_dialog(bw, + messages_get("gtkplainSave"), + GTK_WINDOW(toplevel), + false, + &filename); + if (res != NSERROR_OK) { + return FALSE; } - /* ensure the option is actually set */ - if (nsoption_charp(toolbar_order) == NULL) { - return; + + save_as_text(browser_window_get_content(bw), filename); + g_free(filename); + + return TRUE; +} + + +/** + * handler for print tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +print_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkPrintOperation *print_op; + GtkPageSetup *page_setup; + GtkPrintSettings *print_settings; + GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR; + struct print_settings *nssettings; + char *settings_fname = NULL; + GtkWidget *toplevel; + + bw = tb->get_bw(tb->get_ctx); + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + print_op = gtk_print_operation_new(); + if (print_op == NULL) { + nsgtk_warning(messages_get("NoMemory"), 0); + return TRUE; } - buffer = strdup(nsoption_charp(toolbar_order)); - - i = BACK_BUTTON; - ii = BACK_BUTTON; - buffer1 = strtok_r(buffer, "|", &ptr); - while (buffer1 != NULL) { - subbuffer = strtok_r(buffer1, ";", &pter); - if (subbuffer != NULL) { - i = atoi(subbuffer); - subbuffer = strtok_r(NULL, ";", &pter); - if (subbuffer != NULL) { - ii = atoi(subbuffer); - if ((i >= BACK_BUTTON) && - (i < PLACEHOLDER_BUTTON) && - (ii >= -1) && - (ii < PLACEHOLDER_BUTTON)) { - nsgtk_scaffolding_button(g, i)->location = ii; - } - } + + /* use previously saved settings if any */ + netsurf_mkpath(&settings_fname, NULL, 2, nsgtk_config_home, "Print"); + if (settings_fname != NULL) { + print_settings = gtk_print_settings_new_from_file(settings_fname, NULL); + if (print_settings != NULL) { + gtk_print_operation_set_print_settings(print_op, + print_settings); + + /* We're not interested in the settings any more */ + g_object_unref(print_settings); + } + } + + content_to_print = browser_window_get_content(bw); + + page_setup = gtk_print_run_page_setup_dialog(GTK_WINDOW(toplevel), + NULL, + NULL); + if (page_setup == NULL) { + nsgtk_warning(messages_get("NoMemory"), 0); + free(settings_fname); + g_object_unref(print_op); + return TRUE; + } + gtk_print_operation_set_default_page_setup(print_op, page_setup); + + nssettings = print_make_settings(PRINT_DEFAULT, + NULL, + nsgtk_layout_table); + + g_signal_connect(print_op, + "begin_print", + G_CALLBACK(gtk_print_signal_begin_print), + nssettings); + g_signal_connect(print_op, + "draw_page", + G_CALLBACK(gtk_print_signal_draw_page), + NULL); + g_signal_connect(print_op, + "end_print", + G_CALLBACK(gtk_print_signal_end_print), + nssettings); + + if (content_get_type(browser_window_get_content(bw)) != CONTENT_TEXTPLAIN) { + res = gtk_print_operation_run(print_op, + GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, + GTK_WINDOW(toplevel), + NULL); + } + + /* if the settings were used save them for future use */ + if (settings_fname != NULL) { + if (res == GTK_PRINT_OPERATION_RESULT_APPLY) { + /* Do not increment the settings reference */ + print_settings = gtk_print_operation_get_print_settings(print_op); + + gtk_print_settings_to_file(print_settings, + settings_fname, + NULL); } - buffer1 = strtok_r(NULL, "|", &ptr); + free(settings_fname); + } + + /* Our print_settings object is destroyed by the end print handler */ + g_object_unref(page_setup); + g_object_unref(print_op); + + return TRUE; +} + +/** + * handler for quit tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +quit_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nsgtk_scaffolding_destroy_all(); + return TRUE; +} + + +/** + * handler for cut tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +cut_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *focused; + GtkWidget *toplevel; + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + focused = gtk_window_get_focus(GTK_WINDOW(toplevel)); + + /* let gtk handle it if focused widget is an editable */ + if (GTK_IS_EDITABLE(focused)) { + gtk_editable_cut_clipboard(GTK_EDITABLE(focused)); + } else { + bw = tb->get_bw(tb->get_ctx); + browser_window_key_press(bw, NS_KEY_CUT_SELECTION); } - free(buffer); + return TRUE; } /** - * save toolbar settings to file + * handler for copy tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static nserror nsgtk_toolbar_customization_save(struct nsgtk_scaffolding *g) +static gboolean +copy_button_clicked_cb(GtkWidget *widget, gpointer data) { - char *choices = NULL; - char *order; - int order_len = PLACEHOLDER_BUTTON * 12; /* length of order buffer */ - int tbidx; - char *cur; - int plen; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *focused; + GtkWidget *toplevel; - order = malloc(order_len); + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); - if (order == NULL) { - return NSERROR_NOMEM; + focused = gtk_window_get_focus(GTK_WINDOW(toplevel)); + + /* let gtk handle it if focused widget is an editable */ + if (GTK_IS_EDITABLE(focused)) { + gtk_editable_copy_clipboard(GTK_EDITABLE(focused)); + } else { + bw = tb->get_bw(tb->get_ctx); + browser_window_key_press(bw, NS_KEY_COPY_SELECTION); } - cur = order; - for (tbidx = BACK_BUTTON; tbidx < PLACEHOLDER_BUTTON; tbidx++) { - plen = snprintf(cur, - order_len, - "%d;%d|", - tbidx, - nsgtk_scaffolding_button(g, tbidx)->location); - if (plen == order_len) { - /* ran out of space, bail early */ - NSLOG(netsurf, INFO, - "toolbar ordering exceeded available space"); - break; - } - cur += plen; - order_len -= plen; + return TRUE; +} + + +/** + * handler for paste tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +paste_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *focused; + GtkWidget *toplevel; + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + focused = gtk_window_get_focus(GTK_WINDOW(toplevel)); + + /* let gtk handle it if focused widget is an editable */ + if (GTK_IS_EDITABLE(focused)) { + gtk_editable_paste_clipboard(GTK_EDITABLE(focused)); + } else { + bw = tb->get_bw(tb->get_ctx); + browser_window_key_press(bw, NS_KEY_PASTE); } - nsoption_set_charp(toolbar_order, order); + return TRUE; +} + + +/** + * handler for delete tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +delete_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *focused; + GtkWidget *toplevel; + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + focused = gtk_window_get_focus(GTK_WINDOW(toplevel)); + + /* let gtk handle it if focused widget is an editable */ + if (GTK_IS_EDITABLE(focused)) { + gtk_editable_delete_selection(GTK_EDITABLE(focused)); + } else { + bw = tb->get_bw(tb->get_ctx); + browser_window_key_press(bw, NS_KEY_CLEAR_SELECTION); + } + + return TRUE; +} + + +/** + * handler for select all tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +selectall_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *focused; + GtkWidget *toplevel; + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + focused = gtk_window_get_focus(GTK_WINDOW(toplevel)); + + /* let gtk handle it if focused widget is an editable */ + if (GTK_IS_EDITABLE(focused)) { + gtk_editable_select_region(GTK_EDITABLE(focused), 0, -1); + } else { + bw = tb->get_bw(tb->get_ctx); + browser_window_key_press(bw, NS_KEY_SELECT_ALL); + } + + return TRUE; +} + + +/** + * handler for preferences tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +preferences_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *toplevel; + GtkWidget *wndpreferences; + + bw = tb->get_bw(tb->get_ctx); + + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + + wndpreferences = nsgtk_preferences(bw, GTK_WINDOW(toplevel)); + if (wndpreferences != NULL) { + gtk_widget_show(wndpreferences); + } + + return TRUE; +} + + +/** + * handler for zoom plus tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +zoomplus_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + browser_window_set_scale(bw, 0.05, false); + + return TRUE; +} + + +/** + * handler for zoom minus tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +zoomminus_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + browser_window_set_scale(bw, -0.05, false); + + return TRUE; + +} + + +/** + * handler for zoom normal tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +zoomnormal_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + browser_window_set_scale(bw, 1.0, true); + + return TRUE; +} + + +/** + * handler for full screen tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +fullscreen_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWindow *gtkwindow; /* gtk window widget is in */ + GdkWindow *gdkwindow; + GdkWindowState state; + + gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW)); + gdkwindow = gtk_widget_get_window(GTK_WIDGET(gtkwindow)); + state = gdk_window_get_state(gdkwindow); + + if (state & GDK_WINDOW_STATE_FULLSCREEN) { + gtk_window_unfullscreen(gtkwindow); + } else { + gtk_window_fullscreen(gtkwindow); + } + return TRUE; +} + + +/** + * handler for view source tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +viewsource_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWindow *gtkwindow; /* gtk window widget is in */ + + bw = tb->get_bw(tb->get_ctx); + + gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW)); + + res = nsgtk_viewsource(gtkwindow, bw); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; +} + + +/** + * handler for show downloads tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +downloads_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWindow *gtkwindow; /* gtk window widget is in */ + gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW)); + nsgtk_download_show(gtkwindow); + return TRUE; +} + + +/** + * handler for show downloads tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +savewindowsize_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWindow *gtkwindow; /* gtk window widget is in */ + int x,y,w,h; + char *choices = NULL; + + gtkwindow = GTK_WINDOW(gtk_widget_get_ancestor(widget,GTK_TYPE_WINDOW)); + + gtk_window_get_position(gtkwindow, &x, &y); + gtk_window_get_size(gtkwindow, &w, &h); + + nsoption_set_int(window_width, w); + nsoption_set_int(window_height, h); + nsoption_set_int(window_x, x); + nsoption_set_int(window_y, y); - /* ensure choices are saved */ netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); if (choices != NULL) { nsoption_write(choices, NULL, NULL); free(choices); } - return NSERROR_OK; + return TRUE; } /** - * when 'save settings' button is clicked + * handler for show downloads tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data) +static gboolean +toggledebugging_button_clicked_cb(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + + browser_window_debug(bw, CONTENT_DEBUG_REDRAW); + + nsgtk_window_update_all(); - edit_mode = false; - /* save state to file, update toolbars for all windows */ - nsgtk_toolbar_customization_save(g); - nsgtk_toolbar_cast(g); - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_close(g); - gtk_widget_destroy(window->window); return TRUE; } + /** - * when 'reload defaults' button is clicked + * handler for debug box tree tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data) +static gboolean +debugboxtree_button_clicked_cb(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - int i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_scaffolding_button(g, i)->location = - (i <= THROBBER_ITEM) ? i : -1; - nsgtk_toolbar_set_physical(g); - for (i = BACK_BUTTON; i <= THROBBER_ITEM; i++) { - if (i == URL_BAR_ITEM) - continue; - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( - nsgtk_scaffolding_button(g, i)->button), TRUE); - gtk_drag_source_set(GTK_WIDGET( - nsgtk_scaffolding_button(g, i)->button), - GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, i); + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + gchar *fname; + gint handle; + FILE *f; + + handle = g_file_open_tmp("nsgtkboxtreeXXXXXX", &fname, NULL); + if ((handle == -1) || (fname == NULL)) { + return TRUE; } + close(handle); /* in case it was binary mode */ + + /* save data to temporary file */ + f = fopen(fname, "w"); + if (f == NULL) { + nsgtk_warning("Error saving box tree dump.", + "Unable to open file for writing."); + unlink(fname); + return TRUE; + } + + bw = tb->get_bw(tb->get_ctx); + + browser_window_debug_dump(bw, f, CONTENT_DEBUG_RENDER); + + fclose(f); + + nsgtk_viewfile("Box Tree Debug", "boxtree", fname); + + g_free(fname); + return TRUE; } + /** - * when titlebar / alt-F4 window close event happens + * handler for debug dom tree tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, - gpointer data) +static gboolean +debugdomtree_button_clicked_cb(GtkWidget *widget, gpointer data) { - edit_mode = false; - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - /* reset g->buttons->location */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_scaffolding_button(g, i)->location = - window->buttonlocations[i]; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + gchar *fname; + gint handle; + FILE *f; + + handle = g_file_open_tmp("nsgtkdomtreeXXXXXX", &fname, NULL); + if ((handle == -1) || (fname == NULL)) { + return TRUE; } - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_connect_all(g); - nsgtk_toolbar_close(g); - nsgtk_scaffolding_set_sensitivity(g); - gtk_widget_destroy(window->window); + close(handle); /* in case it was binary mode */ + + /* save data to temporary file */ + f = fopen(fname, "w"); + if (f == NULL) { + nsgtk_warning("Error saving box tree dump.", + "Unable to open file for writing."); + unlink(fname); + return TRUE; + } + + bw = tb->get_bw(tb->get_ctx); + + browser_window_debug_dump(bw, f, CONTENT_DEBUG_DOM); + + fclose(f); + + nsgtk_viewfile("DOM Tree Debug", "domtree", fname); + + g_free(fname); + return TRUE; + } + /** - * called when a widget is dropped onto the store window + * handler for local history tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ static gboolean -nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, guint time, gpointer data) +localhistory_button_clicked_cb(GtkWidget *widget, gpointer data) { - struct nsgtk_scaffolding *g = (struct nsgtk_scaffolding *)data; - int q, i; + nserror res; + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + GtkWidget *toplevel; - if ((window->fromstore) || (window->currentbutton == -1)) { - window->currentbutton = -1; - return FALSE; - } - if (nsgtk_scaffolding_button(g, window->currentbutton)->location - != -1) { - /* 'move' all widgets further right, one place to the left - * in logical schema */ - for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> - location + 1; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location--; + toplevel = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); + if (toplevel != NULL) { + bw = tb->get_bw(tb->get_ctx); + + res = nsgtk_local_history_present(GTK_WINDOW(toplevel), bw); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Unable to present local history window."); } - gtk_container_remove(GTK_CONTAINER( - nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button)); - nsgtk_scaffolding_button(g, window->currentbutton)->location - = -1; - } - window->currentbutton = -1; - gtk_drag_finish(gdc, TRUE, TRUE, time); - return FALSE; + } + return TRUE; } /** - * called when hovering above the store + * handler for history tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ static gboolean -nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, guint time, gpointer data) +history_button_clicked_cb(GtkWidget *widget, gpointer data) { - return FALSE; + return localhistory_button_clicked_cb(widget, data); } + /** - * create store window + * handler for global history tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE */ -static void nsgtk_toolbar_window_open(struct nsgtk_scaffolding *g) +static gboolean +globalhistory_button_clicked_cb(GtkWidget *widget, gpointer data) { - struct nsgtk_theme *theme; nserror res; + res = nsgtk_global_history_present(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Unable to initialise global history window."); + } + return TRUE; +} - theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, true); - if (theme == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - return; + +/** + * handler for add bookmark tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +addbookmarks_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct browser_window *bw; + + bw = tb->get_bw(tb->get_ctx); + if (browser_window_has_content(bw)) { + hotlist_add_url(browser_window_access_url(bw)); } + return TRUE; +} + - res = nsgtk_builder_new_from_resname("toolbar", &window->builder); +/** + * handler for show bookmark tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +showbookmarks_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + res = nsgtk_hotlist_present(); if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Toolbar UI builder init failed"); - nsgtk_warning("Toolbar UI builder init failed", 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - free(theme); - return; + NSLOG(netsurf, INFO, "Unable to initialise bookmark window."); } + return TRUE; +} - gtk_builder_connect_signals(window->builder, NULL); - window->window = GTK_WIDGET(gtk_builder_get_object( - window->builder, "dialogToolbar")); - if (window->window == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - free(theme); - return; +/** + * handler for show cookies tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +showcookies_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + nserror res; + res = nsgtk_cookies_present(NULL); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise cookies window."); } + return TRUE; +} - gtk_window_set_transient_for(GTK_WINDOW(window->window), - nsgtk_scaffolding_window(g)); - window->widgetvbox = GTK_WIDGET(gtk_builder_get_object( - window->builder, "widgetvbox")); - if (window->widgetvbox == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - free(theme); - return; +/** + * handler for open location tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +openlocation_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + GtkToolItem *urltitem; + + urltitem = tb->items[URL_BAR_ITEM].button; + if (urltitem != NULL) { + GtkEntry *entry; + entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(urltitem))); + gtk_widget_grab_focus(GTK_WIDGET(entry)); } + return TRUE; +} - /* preset to width [in buttons] of */ - window->numberh = NSGTK_STORE_WIDTH; - /* store to cause creation of a new toolbar */ - window->currentbutton = -1; +/** + * handler for contents tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +contents_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + nserror res; - /* load toolbuttons */ - /* add toolbuttons to window */ - /* set event handlers */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if (i == URL_BAR_ITEM) - continue; - window->store_buttons[i] = - nsgtk_toolbar_make_widget(g, i, theme); - if (window->store_buttons[i] == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - continue; - } - nsgtk_toolbar_add_store_widget(window->store_buttons[i]); - g_signal_connect(window->store_buttons[i], "drag-data-get", - G_CALLBACK( - nsgtk_scaffolding_button(g, i)->dataplus), g); + res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/"); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } + + return TRUE; +} + +/** + * handler for contents tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +guide_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + nserror res; + + res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/guide"); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); } - free(theme); + return TRUE; +} + + +/** + * handler for contents tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean +info_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + nserror res; - gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE); + res = toolbar_navigate_to_url(tb, "https://www.netsurf-browser.org/documentation/info"); + if (res != NSERROR_OK) { + nsgtk_warning(messages_get_errorcode(res), 0); + } - gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY); + return TRUE; +} - g_signal_connect(GTK_WIDGET(gtk_builder_get_object( - window->builder, "close")), - "clicked", - G_CALLBACK(nsgtk_toolbar_persist), - g); - g_signal_connect(GTK_WIDGET(gtk_builder_get_object( - window->builder, "reset")), - "clicked", - G_CALLBACK(nsgtk_toolbar_reset), - g); +/** + * handler for contents tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE + */ +static gboolean about_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + GtkWindow *parent; /* gtk window widget is in */ + + parent = GTK_WINDOW(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)); + + nsgtk_about_dialog_init(parent); + return TRUE; +} + +/** + * handler for openmenu tool bar item clicked signal + * + * \param widget The widget the signal is being delivered to. + * \param data The toolbar context passed when the signal was connected + * \return TRUE to indicate signal handled. + */ +static gboolean openmenu_button_clicked_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct gui_window *gw; + struct nsgtk_scaffolding *gs; + + gw = tb->get_ctx; /** \todo stop assuming the context is a gui window */ - g_signal_connect(window->window, "delete-event", - G_CALLBACK(nsgtk_toolbar_delete), g); + gs = nsgtk_get_scaffold(gw); - g_signal_connect(window->window, "drag-drop", - G_CALLBACK(nsgtk_toolbar_store_return), g); + nsgtk_scaffolding_burger_menu(gs); + + return TRUE; +} - g_signal_connect(window->window, "drag-motion", - G_CALLBACK(nsgtk_toolbar_store_action), g); - gtk_widget_show_all(window->window); +/* define data plus and data minus handlers */ +#define TOOLBAR_ITEM(identifier, name, snstvty, clicked, activate, label, iconame) \ +static gboolean \ +nsgtk_toolbar_##name##_data_plus(GtkWidget *widget, \ + GdkDragContext *cont, \ + GtkSelectionData *selection, \ + guint info, \ + guint time, \ + gpointer data) \ +{ \ + struct nsgtk_toolbar_customisation *tbc; \ + tbc = (struct nsgtk_toolbar_customisation *)data; \ + tbc->dragitem = identifier; \ + tbc->dragfrom = true; \ + return TRUE; \ +} \ +static gboolean \ +nsgtk_toolbar_##name##_data_minus(GtkWidget *widget, \ + GdkDragContext *cont, \ + GtkSelectionData *selection, \ + guint info, \ + guint time, \ + gpointer data) \ +{ \ + struct nsgtk_toolbar_customisation *tbc; \ + tbc = (struct nsgtk_toolbar_customisation *)data; \ + tbc->dragitem = identifier; \ + tbc->dragfrom = false; \ + return TRUE; \ } +#include "gtk/toolbar_items.h" + +#undef TOOLBAR_ITEM + + /** - * change behaviour of scaffoldings while editing toolbar + * create a toolbar item * - * All buttons as well as window clicks are desensitized; then buttons - * in the front window are changed to movable buttons + * create a toolbar item and set up its default handlers */ -void nsgtk_toolbar_customization_init(struct nsgtk_scaffolding *g) +static nserror +toolbar_item_create(nsgtk_toolbar_button id, struct nsgtk_toolbar_item *item) { - int i; - struct nsgtk_scaffolding *list; - edit_mode = true; + item->location = INACTIVE_LOCATION; + + /* set item defaults from macro */ + switch (id) { +#define TOOLBAR_ITEM_t(name) \ + item->clicked = name##_button_clicked_cb; +#define TOOLBAR_ITEM_b(name) \ + item->clicked = name##_button_clicked_cb; +#define TOOLBAR_ITEM_y(name) \ + item->clicked = name##_button_clicked_cb; +#define TOOLBAR_ITEM_n(name) \ + item->clicked = NULL; +#define TOOLBAR_ITEM(identifier, iname, snstvty, clicked, activate, label, iconame) \ + case identifier: \ + item->name = #iname; \ + item->sensitivity = snstvty; \ + item->dataplus = nsgtk_toolbar_##iname##_data_plus; \ + item->dataminus = nsgtk_toolbar_##iname##_data_minus; \ + TOOLBAR_ITEM_ ## clicked(iname) \ + break; - list = nsgtk_scaffolding_iterate(NULL); - while (list) { - g_signal_handler_block(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_CLICK)); - g_signal_handler_block(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_REDRAW)); - nsgtk_widget_override_background_color( - GTK_WIDGET(nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - GTK_STATE_NORMAL, 0, 0xEEEE, 0xEEEE, 0xEEEE); +#include "gtk/toolbar_items.h" - if (list == g) { - list = nsgtk_scaffolding_iterate(list); - continue; - } - /* set sensitive for all gui_windows save g */ - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_window( - list)), FALSE); - list = nsgtk_scaffolding_iterate(list); - } - /* set sensitive for all of g save toolbar */ - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), - FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), - FALSE); - - /* set editable aspect for toolbar */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), - nsgtk_toolbar_clear_toolbar, g); - nsgtk_toolbar_set_physical(g); - /* memorize button locations, set editable */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - window->buttonlocations[i] = nsgtk_scaffolding_button(g, i) - ->location; - if ((window->buttonlocations[i] == -1) || (i == URL_BAR_ITEM)) - continue; - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( - nsgtk_scaffolding_button(g, i)->button), TRUE); - gtk_drag_source_set(GTK_WIDGET(nsgtk_scaffolding_button( - g, i)->button), GDK_BUTTON1_MASK, &entry, 1, - GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, i); +#undef TOOLBAR_ITEM_t +#undef TOOLBAR_ITEM_y +#undef TOOLBAR_ITEM_n +#undef TOOLBAR_ITEM + + case PLACEHOLDER_BUTTON: + return NSERROR_INVALID; } - /* add move button listeners */ - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-drop", G_CALLBACK(nsgtk_toolbar_data), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-data-received", G_CALLBACK( - nsgtk_toolbar_move_complete), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-motion", G_CALLBACK(nsgtk_toolbar_action), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-leave", G_CALLBACK( - nsgtk_toolbar_clear), g); + return NSERROR_OK; +} - /* set data types */ - gtk_drag_dest_set(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, - &entry, 1, GDK_ACTION_COPY); - /* open toolbar window */ - nsgtk_toolbar_window_open(g); +/** + * set a toolbar item to a throbber frame number + * + * \param toolbar_item The toolbar item to update + * \param frame The animation frame number to update to + * \return NSERROR_OK on success, + * NSERROR_INVALID if the toolbar item does not contain an image, + * NSERROR_BAD_SIZE if the frame is out of range. + */ +static nserror set_throbber_frame(GtkToolItem *toolbar_item, int frame) +{ + nserror res; + GdkPixbuf *pixbuf; + GtkImage *throbber; + + if (toolbar_item == NULL) { + /* no toolbar item */ + return NSERROR_INVALID; + } + + res = nsgtk_throbber_get_frame(frame, &pixbuf); + if (res != NSERROR_OK) { + return res; + } + + throbber = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(toolbar_item))); + + gtk_image_set_from_pixbuf(throbber, pixbuf); + + return NSERROR_OK; +} + + +/** + * Make the throbber run. + * + * scheduled callback to update the throbber + * + * \param p The context passed when scheduled. + */ +static void next_throbber_frame(void *p) +{ + struct nsgtk_toolbar *tb = p; + nserror res; + + tb->throb_frame++; /* advance to next frame */ + + res = set_throbber_frame(tb->items[THROBBER_ITEM].button, + tb->throb_frame); + if (res == NSERROR_BAD_SIZE) { + tb->throb_frame = 1; + res = set_throbber_frame(tb->items[THROBBER_ITEM].button, + tb->throb_frame); + } + + /* only schedule next frame if there are no errors */ + if (res == NSERROR_OK) { + nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, p); + } } + /** - * set toolbar logical -> physical; physically visible toolbar buttons are made - * to correspond to the logically stored schema in terms of location - * visibility etc + * connect signal handlers to a gtk toolbar item */ -void nsgtk_toolbar_set_physical(struct nsgtk_scaffolding *g) +static nserror +toolbar_connect_signal(struct nsgtk_toolbar *tb, nsgtk_toolbar_button itemid) { - int i; - struct nsgtk_theme *theme; + struct nsgtk_toolbar_item *item; + GtkEntry *entry; - theme = nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR, false); - if (theme == NULL) { - nsgtk_warning(messages_get("NoMemory"), 0); - return; + item = &tb->items[itemid]; + + if (item->button != NULL) { + g_signal_connect(item->button, + "size-allocate", + G_CALLBACK(toolbar_item_size_allocate_cb), + tb); } - /* simplest is to clear the toolbar then reload it from memory */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), - nsgtk_toolbar_clear_toolbar, g); - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_toolbar_add_item_to_toolbar(g, i, theme); + + switch (itemid) { + case URL_BAR_ITEM: + entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->button))); + + g_signal_connect(GTK_WIDGET(entry), + "activate", + G_CALLBACK(url_entry_activate_cb), + tb); + g_signal_connect(GTK_WIDGET(entry), + "changed", + G_CALLBACK(url_entry_changed_cb), + tb); + g_signal_connect(GTK_WIDGET(entry), + "icon-release", + G_CALLBACK(url_entry_icon_release_cb), + tb); + + nsgtk_completion_connect_signals(entry, + tb->get_bw, + tb->get_ctx); + break; + + + case WEBSEARCH_ITEM: + entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->button))); + + g_signal_connect(GTK_WIDGET(entry), + "activate", + G_CALLBACK(websearch_entry_activate_cb), + tb); + g_signal_connect(GTK_WIDGET(entry), + "button-press-event", + G_CALLBACK(websearch_entry_button_press_cb), + tb); + break; + + default: + if ((item->clicked != NULL) && (item->button != NULL)) { + g_signal_connect(item->button, + "clicked", + G_CALLBACK(item->clicked), + tb); + } + break; + } - gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g))); - free(theme); + + return NSERROR_OK; } /** - * \return toolbar item id when a widget is an element of the scaffolding - * else -1 + * connect all signals to widgets in a toolbar */ -int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, - struct nsgtk_scaffolding *g) +static nserror toolbar_connect_signals(struct nsgtk_toolbar *tb) { - int i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if ((nsgtk_scaffolding_button(g, i)->location != -1) - && (widget == GTK_WIDGET( - nsgtk_scaffolding_button(g, i)->button))) { - return i; + int location; /* location index */ + nsgtk_toolbar_button itemid; /* item id */ + + for (location = BACK_BUTTON; location < PLACEHOLDER_BUTTON; location++) { + itemid = itemid_from_location(tb, location); + if (itemid == PLACEHOLDER_BUTTON) { + /* no more filled locations */ + break; } + toolbar_connect_signal(tb, itemid); } - return -1; + + return NSERROR_OK; } /** - * add handlers to factory widgets - * \param g the scaffolding to attach handlers to - * \param i the toolbar item id + * signal handler for toolbar context menu + * + * \param toolbar The toolbar event is being delivered to + * \param x The x coordinate where the click happened + * \param y The x coordinate where the click happened + * \param button the buttons being pressed + * \param data The context pointer passed when the connection was made. + * \return TRUE to indicate signal handled. */ -static void -nsgtk_toolbar_set_handler(struct nsgtk_scaffolding *g, nsgtk_toolbar_button i) +static gboolean +toolbar_popup_context_menu_cb(GtkToolbar *toolbar, + gint x, + gint y, + gint button, + gpointer data) { - switch(i){ - case URL_BAR_ITEM: - nsgtk_scaffolding_update_url_bar_ref(g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), - "activate", G_CALLBACK( - nsgtk_window_url_activate_event), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), - "changed", G_CALLBACK( - nsgtk_window_url_changed), g); + struct nsgtk_toolbar *tb = (struct nsgtk_toolbar *)data; + struct gui_window *gw; + struct nsgtk_scaffolding *gs; + + gw = tb->get_ctx; /** \todo stop assuming the context is a gui window */ + + gs = nsgtk_get_scaffold(gw); + + nsgtk_scaffolding_toolbar_context_menu(gs); + + return TRUE; +} + + +/** + * toolbar delete signal handler + */ +static void toolbar_destroy_cb(GtkWidget *widget, gpointer data) +{ + struct nsgtk_toolbar *tb; + tb = (struct nsgtk_toolbar *)data; + + /* ensure any throbber scheduled is stopped */ + nsgtk_schedule(-1, next_throbber_frame, tb); + + free(tb); +} + + +/* exported interface documented in toolbar.h */ +nserror +nsgtk_toolbar_create(GtkBuilder *builder, + struct browser_window *(*get_bw)(void *ctx), + void *get_ctx, + bool want_location_focus, + struct nsgtk_toolbar **tb_out) +{ + nserror res; + struct nsgtk_toolbar *tb; + int bidx; /* button index */ + + tb = calloc(1, sizeof(struct nsgtk_toolbar)); + if (tb == NULL) { + return NSERROR_NOMEM; + } + + tb->get_bw = get_bw; + tb->get_ctx = get_ctx; + /* set the throbber start frame. */ + tb->throb_frame = 0; + if (want_location_focus) { + tb->loc_focus = LFS_WANT; + } else { + tb->loc_focus = LFS_IDLE; + } + + tb->widget = GTK_TOOLBAR(gtk_builder_get_object(builder, "toolbar")); + gtk_toolbar_set_show_arrow(tb->widget, TRUE); + + g_signal_connect(tb->widget, + "popup-context-menu", + G_CALLBACK(toolbar_popup_context_menu_cb), + tb); + + /* close and cleanup on delete signal */ + g_signal_connect(tb->widget, + "destroy", + G_CALLBACK(toolbar_destroy_cb), + tb); + + /* allocate button contexts */ + for (bidx = BACK_BUTTON; bidx < PLACEHOLDER_BUTTON; bidx++) { + res = toolbar_item_create(bidx, &tb->items[bidx]); + if (res != NSERROR_OK) { + return res; + } + } + + res = nsgtk_toolbar_update(tb); + if (res != NSERROR_OK) { + return res; + } + + *tb_out = tb; + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_restyle(struct nsgtk_toolbar *tb) +{ + /* + * reset toolbar size allocation so icon size change affects + * allocated widths. + */ + tb->offset = 0; + + switch (nsoption_int(button_type)) { + + case 1: /* Small icons */ + gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget), + GTK_ICON_SIZE_SMALL_TOOLBAR); break; - case THROBBER_ITEM: - nsgtk_scaffolding_update_throbber_ref(g); + case 2: /* Large icons */ + gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget), + GTK_ICON_SIZE_LARGE_TOOLBAR); break; - case WEBSEARCH_ITEM: - nsgtk_scaffolding_update_websearch_ref(g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), - "activate", G_CALLBACK( - nsgtk_websearch_activate), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), - "button-press-event", G_CALLBACK( - nsgtk_websearch_clear), g); + case 3: /* Large icons with text */ + gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget), + GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(tb->widget), + GTK_ICON_SIZE_LARGE_TOOLBAR); + break; + + case 4: /* Text icons only */ + gtk_toolbar_set_style(GTK_TOOLBAR(tb->widget), + GTK_TOOLBAR_TEXT); break; default: - if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) && - (nsgtk_scaffolding_button(g, i)->button != NULL)) { - g_signal_connect( - nsgtk_scaffolding_button(g, i)->button, - "clicked", - G_CALLBACK(nsgtk_scaffolding_button( - g, i)->bhandler), g); + break; + } + + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_throbber(struct nsgtk_toolbar *tb, bool active) +{ + nserror res; + struct browser_window *bw; + + /* Manage the location focus state */ + switch (tb->loc_focus) { + case LFS_IDLE: + break; + case LFS_WANT: + if (active) { + tb->loc_focus = LFS_THROB; + } + break; + case LFS_THROB: + if (!active) { + tb->loc_focus = LFS_LAST; } break; + case LFS_LAST: + break; + } + + /* when activating the throbber simply schedule the next frame update */ + if (active) { + nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, tb); + + set_item_sensitivity(&tb->items[STOP_BUTTON], true); + set_item_sensitivity(&tb->items[RELOAD_BUTTON], false); + set_item_action(tb, RELOADSTOP_BUTTON, false); + + return NSERROR_OK; + } + + /* stopping the throbber */ + nsgtk_schedule(-1, next_throbber_frame, tb); + tb->throb_frame = 0; + res = set_throbber_frame(tb->items[THROBBER_ITEM].button, + tb->throb_frame); + + bw = tb->get_bw(tb->get_ctx); + + /* adjust sensitivity of other items */ + set_item_sensitivity(&tb->items[STOP_BUTTON], false); + set_item_sensitivity(&tb->items[RELOAD_BUTTON], true); + set_item_action(tb, RELOADSTOP_BUTTON, true); + set_item_sensitivity(&tb->items[BACK_BUTTON], + browser_window_history_back_available(bw)); + set_item_sensitivity(&tb->items[FORWARD_BUTTON], + browser_window_history_forward_available(bw)); + nsgtk_local_history_hide(); + + return res; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_page_info_change(struct nsgtk_toolbar *tb) +{ + GtkEntry *url_entry; + browser_window_page_info_state pistate; + struct browser_window *bw; + const char *icon_name; + + if (tb->items[URL_BAR_ITEM].button == NULL) { + /* no toolbar item */ + return NSERROR_INVALID; + } + url_entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tb->items[URL_BAR_ITEM].button))); + + bw = tb->get_bw(tb->get_ctx); + + pistate = browser_window_get_page_info_state(bw); + + switch (pistate) { + case PAGE_STATE_INTERNAL: + icon_name = "page-info-internal"; + break; + + case PAGE_STATE_LOCAL: + icon_name = "page-info-local"; + break; + + case PAGE_STATE_INSECURE: + icon_name = "page-info-insecure"; + break; + + case PAGE_STATE_SECURE_OVERRIDE: + icon_name = "page-info-warning"; + break; + + case PAGE_STATE_SECURE_ISSUES: + icon_name = "page-info-warning"; + break; + + case PAGE_STATE_SECURE: + icon_name = "page-info-secure"; + break; + + default: + icon_name = "page-info-internal"; + break; + } + + nsgtk_entry_set_icon_from_icon_name(GTK_WIDGET(url_entry), + GTK_ENTRY_ICON_PRIMARY, + icon_name); + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_set_url(struct nsgtk_toolbar *tb, nsurl *url) +{ + size_t idn_url_l; + char *idn_url_s = NULL; + const char *url_text = NULL; + GtkEntry *url_entry; + + if (tb->items[URL_BAR_ITEM].button == NULL) { + /* no toolbar item */ + return NSERROR_INVALID; + } + url_entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(tb->items[URL_BAR_ITEM].button))); + + if (nsoption_bool(display_decoded_idn) == true) { + if (nsurl_get_utf8(url, &idn_url_s, &idn_url_l) != NSERROR_OK) { + idn_url_s = NULL; + } + url_text = idn_url_s; + } + if (url_text == NULL) { + url_text = nsurl_access(url); + } + + if (strcmp(url_text, gtk_entry_get_text(url_entry)) != 0) { + /* The URL bar content has changed, we need to update it */ + gint startpos, endpos; + bool was_selected; + gtk_editable_get_selection_bounds(GTK_EDITABLE(url_entry), + &startpos, &endpos); + was_selected = gtk_widget_is_focus(GTK_WIDGET(url_entry)) && + startpos == 0 && + endpos == gtk_entry_get_text_length(url_entry); + gtk_entry_set_text(url_entry, url_text); + if (was_selected && tb->loc_focus != LFS_IDLE) { + gtk_widget_grab_focus(GTK_WIDGET(url_entry)); + if (tb->loc_focus == LFS_LAST) { + tb->loc_focus = LFS_IDLE; + } + } } + + if (idn_url_s != NULL) { + free(idn_url_s); + } + + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror +nsgtk_toolbar_set_websearch_image(struct nsgtk_toolbar *tb, GdkPixbuf *pixbuf) +{ + GtkWidget *entry; + + if (tb->items[WEBSEARCH_ITEM].button == NULL) { + /* no toolbar item */ + return NSERROR_INVALID; + } + + entry = gtk_bin_get_child(GTK_BIN(tb->items[WEBSEARCH_ITEM].button)); + + if (pixbuf != NULL) { + nsgtk_entry_set_icon_from_pixbuf(entry, + GTK_ENTRY_ICON_PRIMARY, + pixbuf); + } else { + nsgtk_entry_set_icon_from_icon_name(entry, + GTK_ENTRY_ICON_PRIMARY, + NSGTK_STOCK_INFO); + } + + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror +nsgtk_toolbar_item_activate(struct nsgtk_toolbar *tb, + nsgtk_toolbar_button itemid) +{ + GtkWidget *widget; + + /* ensure item id in range */ + if ((itemid < BACK_BUTTON) || (itemid >= PLACEHOLDER_BUTTON)) { + return NSERROR_BAD_PARAMETER; + } + + if (tb->items[itemid].clicked == NULL) { + return NSERROR_INVALID; + } + + /* + * if item has a widget in the current toolbar use that as the + * signal source otherwise use the toolbar widget itself. + */ + if (tb->items[itemid].button != NULL) { + widget = GTK_WIDGET(tb->items[itemid].button); + } else { + widget = GTK_WIDGET(tb->widget); + } + + tb->items[itemid].clicked(widget, tb); + + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_show(struct nsgtk_toolbar *tb, bool show) +{ + if (show) { + gtk_widget_show(GTK_WIDGET(tb->widget)); + } else { + gtk_widget_hide(GTK_WIDGET(tb->widget)); + } + return NSERROR_OK; +} + + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_update(struct nsgtk_toolbar *tb) +{ + nserror res; + + /* setup item locations based on user config */ + res = apply_user_button_customisation(tb); + if (res != NSERROR_OK) { + return res; + } + + /* populate toolbar widget */ + res = populate_gtk_toolbar_widget(tb); + if (res != NSERROR_OK) { + return res; + } + + /* ensure icon sizes and text labels on toolbar are set */ + res = nsgtk_toolbar_restyle(tb); + if (res != NSERROR_OK) { + return res; + } + + res = toolbar_connect_signals(tb); + + return res; } /** - * connect 'normal' handlers to toolbar buttons + * Find the correct location for popping up a window for the chosen item. + * + * \param tb The toolbar to select from + * \param item_idx The toolbar item to select from + * \param out_x Filled with an appropriate X coordinate + * \param out_y Filled with an appropriate Y coordinate */ -void nsgtk_toolbar_connect_all(struct nsgtk_scaffolding *g) +static nserror +nsgtk_toolbar_get_icon_window_position(struct nsgtk_toolbar *tb, + int item_idx, + int *out_x, + int *out_y) { - int q, i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - if (nsgtk_scaffolding_button(g, q)->button != NULL) - g_signal_connect( - nsgtk_scaffolding_button(g, q)->button, - "size-allocate", G_CALLBACK( - nsgtk_scaffolding_toolbar_size_allocate - ), g); - nsgtk_toolbar_set_handler(g, q); - } -} - - -#define DATAHANDLER(p, q, r)\ -gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ - *cont, GtkSelectionData *selection, guint info, guint time,\ - gpointer data)\ -{\ - r->currentbutton = q##_BUTTON;\ - r->fromstore = true;\ - return TRUE;\ -}\ -gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ - GdkDragContext *cont, GtkSelectionData *selection, guint info,\ - guint time, gpointer data)\ -{\ - r->currentbutton = q##_BUTTON;\ - r->fromstore = false;\ - return TRUE;\ -} - -DATAHANDLER(home, HOME, window) -DATAHANDLER(forward, FORWARD, window) -DATAHANDLER(back, BACK, window) -DATAHANDLER(stop, STOP, window) -DATAHANDLER(reload, RELOAD, window) -DATAHANDLER(history, HISTORY, window) -DATAHANDLER(newwindow, NEWWINDOW, window) -DATAHANDLER(newtab, NEWTAB, window) -DATAHANDLER(openfile, OPENFILE, window) -DATAHANDLER(closetab, CLOSETAB, window) -DATAHANDLER(closewindow, CLOSEWINDOW, window) -DATAHANDLER(savepage, SAVEPAGE, window) -DATAHANDLER(printpreview, PRINTPREVIEW, window) -DATAHANDLER(print, PRINT, window) -DATAHANDLER(quit, QUIT, window) -DATAHANDLER(cut, CUT, window) -DATAHANDLER(copy, COPY, window) -DATAHANDLER(paste, PASTE, window) -DATAHANDLER(delete, DELETE, window) -DATAHANDLER(selectall, SELECTALL, window) -DATAHANDLER(preferences, PREFERENCES, window) -DATAHANDLER(zoomplus, ZOOMPLUS, window) -DATAHANDLER(zoomminus, ZOOMMINUS, window) -DATAHANDLER(zoomnormal, ZOOMNORMAL, window) -DATAHANDLER(fullscreen, FULLSCREEN, window) -DATAHANDLER(viewsource, VIEWSOURCE, window) -DATAHANDLER(contents, CONTENTS, window) -DATAHANDLER(about, ABOUT, window) -DATAHANDLER(pdf, PDF, window) -DATAHANDLER(plaintext, PLAINTEXT, window) -DATAHANDLER(drawfile, DRAWFILE, window) -DATAHANDLER(postscript, POSTSCRIPT, window) -DATAHANDLER(find, FIND, window) -DATAHANDLER(downloads, DOWNLOADS, window) -DATAHANDLER(savewindowsize, SAVEWINDOWSIZE, window) -DATAHANDLER(toggledebugging, TOGGLEDEBUGGING, window) -DATAHANDLER(debugboxtree, SAVEBOXTREE, window) -DATAHANDLER(debugdomtree, SAVEDOMTREE, window) -DATAHANDLER(localhistory, LOCALHISTORY, window) -DATAHANDLER(globalhistory, GLOBALHISTORY, window) -DATAHANDLER(addbookmarks, ADDBOOKMARKS, window) -DATAHANDLER(showbookmarks, SHOWBOOKMARKS, window) -DATAHANDLER(showcookies, SHOWCOOKIES, window) -DATAHANDLER(openlocation, OPENLOCATION, window) -DATAHANDLER(nexttab, NEXTTAB, window) -DATAHANDLER(prevtab, PREVTAB, window) -DATAHANDLER(guide, GUIDE, window) -DATAHANDLER(info, INFO, window) -#undef DATAHANDLER - -#define DATAHANDLER(p, q, r) \ -gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ - *cont, GtkSelectionData *selection, guint info, guint time,\ - gpointer data)\ -{\ - r->currentbutton = q##_ITEM;\ - r->fromstore = true;\ - return TRUE;\ -}\ -gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ - GdkDragContext *cont, GtkSelectionData *selection, guint info,\ - guint time, gpointer data)\ -{\ - r->currentbutton = q##_ITEM;\ - r->fromstore = false;\ - return TRUE;\ -} - -DATAHANDLER(throbber, THROBBER, window) -DATAHANDLER(websearch, WEBSEARCH, window) -#undef DATAHANDLER + struct nsgtk_toolbar_item *item = &tb->items[item_idx]; + GtkWidget *widget = GTK_WIDGET(item->button); + GtkAllocation alloc; + gint rootx, rooty, x, y; + + switch (item_idx) { + case URL_BAR_ITEM: + widget = GTK_WIDGET(gtk_bin_get_child(GTK_BIN(item->button))); + break; + default: + /* Nothing to do here */ + break; + } + + nsgtk_widget_get_allocation(widget, &alloc); + + if (gtk_widget_translate_coordinates(widget, + gtk_widget_get_toplevel(widget), + 0, + alloc.height - 1, + &x, &y) != TRUE) { + return NSERROR_UNKNOWN; + } + + gtk_window_get_position(GTK_WINDOW(gtk_widget_get_toplevel(widget)), + &rootx, &rooty); + + *out_x = rootx + x + 4; + *out_y = rooty + y + 4; + + return NSERROR_OK; +} + +nserror nsgtk_toolbar_position_page_info(struct nsgtk_toolbar *tb, + struct nsgtk_pi_window *win) +{ + nserror res; + int x, y; + + res = nsgtk_toolbar_get_icon_window_position(tb, URL_BAR_ITEM, &x, &y); + if (res != NSERROR_OK) { + return res; + } + + nsgtk_page_info_set_position(win, x, y); + + return NSERROR_OK; +} + +/* exported interface documented in toolbar.h */ +nserror nsgtk_toolbar_position_local_history(struct nsgtk_toolbar *tb) +{ + nserror res; + int x, y; + + res = nsgtk_toolbar_get_icon_window_position(tb, HISTORY_BUTTON, &x, &y); + if (res != NSERROR_OK) { + return res; + } + + nsgtk_local_history_set_position(x, y); + + return NSERROR_OK; +} diff --git a/frontends/gtk/toolbar.h b/frontends/gtk/toolbar.h index 4286fe3f0..4ecca9f02 100644 --- a/frontends/gtk/toolbar.h +++ b/frontends/gtk/toolbar.h @@ -16,77 +16,127 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_GTK_TOOLBAR_H_ -#define _NETSURF_GTK_TOOLBAR_H_ +#ifndef NETSURF_GTK_TOOLBAR_H_ +#define NETSURF_GTK_TOOLBAR_H_ /** - * sets up the images for scaffolding. + * control toolbar context */ -void nsgtk_theme_implement(struct nsgtk_scaffolding *g); +struct nsgtk_toolbar; +struct nsgtk_scaffolding; +/** + * create a control toolbar + * + * \param[in] builder The gtk builder object the toolbar is being created from + * \param[out] toolbar a pointer to receive the result. + * \return NSERROR_OK and toolbar updated on success else error code + */ +nserror nsgtk_toolbar_create(GtkBuilder *builder, + struct browser_window *(*get_bw)(void *ctx), + void *get_bw_ctx, + bool want_location_focus, + struct nsgtk_toolbar **toolbar); + + +/** + * Update the toolbar items being shown based on current settings + * + * \param toolbar A toolbar returned from a creation + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_update(struct nsgtk_toolbar *tb); + + +/** + * Update toolbar style and size based on current settings + * + * \param toolbar A toolbar returned from a creation + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_restyle(struct nsgtk_toolbar *tb); + + +/** + * Start or stop a throbber in a toolbar + * + * \param toolbar A toolbar returned from a creation + * \param active True if the throbber animation should play. + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_throbber(struct nsgtk_toolbar *tb, bool active); + + +/** + * Page info has changed state + * + * \param toolbar A toolbar returned from a creation + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_page_info_change(struct nsgtk_toolbar *tb); + + +/** + * Update the toolbar url entry + * + * \param toolbar A toolbar returned from a creation + * \param url The URL to set + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_set_url(struct nsgtk_toolbar *tb, nsurl *url); + + +/** + * set the websearch image + * + * \param toolbar A toolbar returned from a creation + * \param pixbuf The pixel buffer data to use to set the web search icon + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_set_websearch_image(struct nsgtk_toolbar *tb, GdkPixbuf *pixbuf); + + +/** + * activate the handler for a toolbar item + * + * This allows the same action to be performed for menu enties as if + * the user had clicked the toolbar widget. + * + * \param toolbar A toolbar returned from a creation + * \param itemid the id of the item to activate + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_item_activate(struct nsgtk_toolbar *tb, nsgtk_toolbar_button itemid); + +/** + * set the toolbar to be shown or hidden + * + * \param toolbar A toolbar returned from a creation + * \param show true to show the toolbar and false to hide it. + * \return NSERROR_OK on success + */ +nserror nsgtk_toolbar_show(struct nsgtk_toolbar *tb, bool show); + +/** + * position the page info window appropriately + * + * \param tb The toolbar to position relative to + * \param win The page-info window to position + */ +nserror nsgtk_toolbar_position_page_info(struct nsgtk_toolbar *tb, + struct nsgtk_pi_window *win); + +/** + * position the local history window appropriately + * + * \param tb The toolbar to position relative to + */ +nserror nsgtk_toolbar_position_local_history(struct nsgtk_toolbar *tb); + +/** + * Initialise customization of toolbar entries + */ void nsgtk_toolbar_customization_init(struct nsgtk_scaffolding *g); -void nsgtk_toolbar_init(struct nsgtk_scaffolding *g); -void nsgtk_toolbar_customization_load(struct nsgtk_scaffolding *g); -void nsgtk_toolbar_set_physical(struct nsgtk_scaffolding *g); -void nsgtk_toolbar_connect_all(struct nsgtk_scaffolding *g); -int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, struct nsgtk_scaffolding *g); - -#define TOOLPROTO(q) gboolean nsgtk_toolbar_##q##_button_data(\ - GtkWidget *widget, GdkDragContext *cont, GtkSelectionData\ - *selection, guint info, guint time, gpointer data);\ -gboolean nsgtk_toolbar_##q##_toolbar_button_data(GtkWidget *widget,\ - GdkDragContext *cont, GtkSelectionData *selection, guint info,\ - guint time, gpointer data) -TOOLPROTO(home); -TOOLPROTO(back); -TOOLPROTO(forward); -TOOLPROTO(reload); -TOOLPROTO(stop); -TOOLPROTO(throbber); -TOOLPROTO(websearch); -TOOLPROTO(history); -TOOLPROTO(newwindow); -TOOLPROTO(newtab); -TOOLPROTO(openfile); -TOOLPROTO(closetab); -TOOLPROTO(closewindow); -TOOLPROTO(savepage); -TOOLPROTO(pdf); -TOOLPROTO(plaintext); -TOOLPROTO(drawfile); -TOOLPROTO(postscript); -TOOLPROTO(printpreview); -TOOLPROTO(print); -TOOLPROTO(quit); -TOOLPROTO(cut); -TOOLPROTO(copy); -TOOLPROTO(paste); -TOOLPROTO(delete); -TOOLPROTO(selectall); -TOOLPROTO(find); -TOOLPROTO(preferences); -TOOLPROTO(zoomplus); -TOOLPROTO(zoomminus); -TOOLPROTO(zoomnormal); -TOOLPROTO(fullscreen); -TOOLPROTO(viewsource); -TOOLPROTO(downloads); -TOOLPROTO(localhistory); -TOOLPROTO(globalhistory); -TOOLPROTO(addbookmarks); -TOOLPROTO(showbookmarks); -TOOLPROTO(showcookies); -TOOLPROTO(openlocation); -TOOLPROTO(nexttab); -TOOLPROTO(prevtab); -TOOLPROTO(savewindowsize); -TOOLPROTO(toggledebugging); -TOOLPROTO(debugboxtree); -TOOLPROTO(debugdomtree); -TOOLPROTO(contents); -TOOLPROTO(guide); -TOOLPROTO(info); -TOOLPROTO(about); -#undef TOOLPROTO + #endif diff --git a/frontends/gtk/toolbar_items.h b/frontends/gtk/toolbar_items.h new file mode 100644 index 000000000..b4bed371f --- /dev/null +++ b/frontends/gtk/toolbar_items.h @@ -0,0 +1,159 @@ +/* + * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NETSURF_GTK_TOOLBAR_ITEMS_H +#define NETSURF_GTK_TOOLBAR_ITEMS_H + +typedef enum { + BACK_BUTTON = 0, + HISTORY_BUTTON, + FORWARD_BUTTON, + RELOADSTOP_BUTTON, + URL_BAR_ITEM, + WEBSEARCH_ITEM, + OPENMENU_BUTTON, + STOP_BUTTON, + RELOAD_BUTTON, + HOME_BUTTON, + THROBBER_ITEM, + NEWWINDOW_BUTTON, + NEWTAB_BUTTON, + OPENFILE_BUTTON, + CLOSETAB_BUTTON, + CLOSEWINDOW_BUTTON, + SAVEPAGE_BUTTON, + PDF_BUTTON, + PLAINTEXT_BUTTON, + DRAWFILE_BUTTON, + POSTSCRIPT_BUTTON, + PRINTPREVIEW_BUTTON, + PRINT_BUTTON, + QUIT_BUTTON, + CUT_BUTTON, + COPY_BUTTON, + PASTE_BUTTON, + DELETE_BUTTON, + SELECTALL_BUTTON, + FIND_BUTTON, + PREFERENCES_BUTTON, + ZOOMPLUS_BUTTON, + ZOOMMINUS_BUTTON, + ZOOMNORMAL_BUTTON, + FULLSCREEN_BUTTON, + VIEWSOURCE_BUTTON, + DOWNLOADS_BUTTON, + SAVEWINDOWSIZE_BUTTON, + TOGGLEDEBUGGING_BUTTON, + SAVEBOXTREE_BUTTON, + SAVEDOMTREE_BUTTON, + LOCALHISTORY_BUTTON, + GLOBALHISTORY_BUTTON, + ADDBOOKMARKS_BUTTON, + SHOWBOOKMARKS_BUTTON, + SHOWCOOKIES_BUTTON, + OPENLOCATION_BUTTON, + NEXTTAB_BUTTON, + PREVTAB_BUTTON, + CONTENTS_BUTTON, + GUIDE_BUTTON, + INFO_BUTTON, + ABOUT_BUTTON, + CUSTOMIZE_BUTTON, + PLACEHOLDER_BUTTON /* size indicator; array maximum indices */ +} nsgtk_toolbar_button; /* PLACEHOLDER_BUTTON - 1 */ + +#endif + +/* + * Item fields are: + * - item identifier (enum value) + * - name (identifier) + * - initial sensitivity (true/false) + * - if there is a toolbar click signal handler (y/n) and it is available in + * the toolbar and toolbox as a button (b, implies y) if the item is + * available as a button but not placed in the toolbox (t, implies y) + * - if there is a menu activate signal handler (y/n) and it calls the + * toolbar click handler directly. (p, implies y) + * - item label as a netsurf message (identifier) + * - icon image name ("string") + */ + +#ifndef TOOLBAR_ITEM +#define TOOLBAR_ITEM(a, b, c, d, e, f, g) +#define TOOLBAR_ITEM_SET +#endif + +TOOLBAR_ITEM(BACK_BUTTON, back, false, b, p, gtkBack, "go-previous") +TOOLBAR_ITEM(HISTORY_BUTTON, history, true, y, n, , "local-history") +TOOLBAR_ITEM(FORWARD_BUTTON, forward, false, b, p, gtkForward, "go-next") +TOOLBAR_ITEM(STOP_BUTTON, stop, false, t, p, gtkStop, NSGTK_STOCK_STOP) +TOOLBAR_ITEM(RELOAD_BUTTON, reload, true, t, p, Reload, NSGTK_STOCK_REFRESH) +TOOLBAR_ITEM(HOME_BUTTON, home, true, b, p, gtkHome, NSGTK_STOCK_HOME) +TOOLBAR_ITEM(URL_BAR_ITEM, url_bar, true, n, n, , NULL) +TOOLBAR_ITEM(WEBSEARCH_ITEM, websearch, true, n, n, , NULL) +TOOLBAR_ITEM(THROBBER_ITEM, throbber, true, n, n, , NULL) +TOOLBAR_ITEM(NEWWINDOW_BUTTON, newwindow, true, b, p, gtkNewWindow, "document-new") +TOOLBAR_ITEM(NEWTAB_BUTTON, newtab, true, b, p, gtkNewTab, NSGTK_STOCK_ADD) +TOOLBAR_ITEM(OPENFILE_BUTTON, openfile, true, b, p, gtkOpenFile, "document-open") +TOOLBAR_ITEM(CLOSETAB_BUTTON, closetab, false, n, y, , "window-close") +TOOLBAR_ITEM(CLOSEWINDOW_BUTTON, closewindow, true, y, p, , "window-close") +TOOLBAR_ITEM(SAVEPAGE_BUTTON, savepage, true, b, p, gtkSavePage, "text-html") +TOOLBAR_ITEM(PDF_BUTTON, pdf, false, y, p, , "x-office-document") +TOOLBAR_ITEM(PLAINTEXT_BUTTON, plaintext, true, b, p, gtkPlainText, "text-x-generic") +TOOLBAR_ITEM(DRAWFILE_BUTTON, drawfile, false, n, n, , NULL) +TOOLBAR_ITEM(POSTSCRIPT_BUTTON, postscript, false, n, n, , NULL) +TOOLBAR_ITEM(PRINTPREVIEW_BUTTON, printpreview, false, n, p, gtkPrintPreview, "gtk-print-preview") +TOOLBAR_ITEM(PRINT_BUTTON, print, true, b, p, gtkPrint, "document-print") +TOOLBAR_ITEM(QUIT_BUTTON, quit, true, b, p, gtkQuitMenu, "application-exit") +TOOLBAR_ITEM(CUT_BUTTON, cut, true, b, p, gtkCut, "edit-cut") +TOOLBAR_ITEM(COPY_BUTTON, copy, true, b, p, gtkCopy, "edit-copy") +TOOLBAR_ITEM(PASTE_BUTTON, paste, true, b, p, gtkPaste, "edit-paste") +TOOLBAR_ITEM(DELETE_BUTTON, delete, false, b, p, gtkDelete, "edit-delete") +TOOLBAR_ITEM(SELECTALL_BUTTON, selectall, true, b, p, gtkSelectAll, "edit-select-all") +TOOLBAR_ITEM(FIND_BUTTON, find, true, n, y, gtkFind, "edit-find") +TOOLBAR_ITEM(PREFERENCES_BUTTON, preferences, true, b, p, gtkPreferences, "preferences-system") +TOOLBAR_ITEM(ZOOMPLUS_BUTTON, zoomplus, true, b, p, gtkZoomPlus, "gtk-zoom-in") +TOOLBAR_ITEM(ZOOMMINUS_BUTTON, zoomminus, true, b, p, gtkZoomMinus, "gtk-zoom-out") +TOOLBAR_ITEM(ZOOMNORMAL_BUTTON, zoomnormal, true, b, p, gtkZoomNormal, "gtk-zoom-100") +TOOLBAR_ITEM(FULLSCREEN_BUTTON, fullscreen, true, b, p, gtkFullScreen, "gtk-fullscreen") +TOOLBAR_ITEM(VIEWSOURCE_BUTTON, viewsource, true, b, p, gtkPageSource, "gtk-index") +TOOLBAR_ITEM(DOWNLOADS_BUTTON, downloads, true, b, p, gtkDownloads, NSGTK_STOCK_SAVE_AS) +TOOLBAR_ITEM(SAVEWINDOWSIZE_BUTTON, savewindowsize, true, y, p, gtkSaveWindowSize, NULL) +TOOLBAR_ITEM(TOGGLEDEBUGGING_BUTTON, toggledebugging, true, y, p, gtkToggleDebugging, NULL) +TOOLBAR_ITEM(SAVEBOXTREE_BUTTON, debugboxtree, true, y, p, gtkDebugBoxTree, NULL) +TOOLBAR_ITEM(SAVEDOMTREE_BUTTON, debugdomtree, true, y, p, gtkDebugDomTree, NULL) +TOOLBAR_ITEM(LOCALHISTORY_BUTTON, localhistory, true, y, p, , NULL) +TOOLBAR_ITEM(GLOBALHISTORY_BUTTON, globalhistory, true, y, p, gtkGlobalHistory, NULL) +TOOLBAR_ITEM(ADDBOOKMARKS_BUTTON, addbookmarks, true, y, p, gtkAddBookMarks, NULL) +TOOLBAR_ITEM(SHOWBOOKMARKS_BUTTON, showbookmarks, true, b, p, gtkShowBookMarks, "user-bookmarks") +TOOLBAR_ITEM(SHOWCOOKIES_BUTTON, showcookies, true, b, p, gtkShowCookies, "show-cookie") +TOOLBAR_ITEM(OPENLOCATION_BUTTON, openlocation, true, y, p, gtkOpenLocation, NULL) +TOOLBAR_ITEM(NEXTTAB_BUTTON, nexttab, false, n, y, gtkNextTab, "media-skip-forward") +TOOLBAR_ITEM(PREVTAB_BUTTON, prevtab, false, n, y, gtkPrevTab, "media-skip-backward") +TOOLBAR_ITEM(CONTENTS_BUTTON, contents, true, y, p, gtkContents, "gtk-help") +TOOLBAR_ITEM(GUIDE_BUTTON, guide, true, y, p, gtkGuide, "gtk-help") +TOOLBAR_ITEM(INFO_BUTTON, info, true, y, p, gtkUserInformation, "dialog-information") +TOOLBAR_ITEM(ABOUT_BUTTON, about, true, b, p, gtkAbout, "help-about") +TOOLBAR_ITEM(OPENMENU_BUTTON, openmenu, true, b, n, gtkOpenMenu, NSGTK_STOCK_OPEN_MENU) +TOOLBAR_ITEM(CUSTOMIZE_BUTTON, cutomize, true, y, p, , NULL) +TOOLBAR_ITEM(RELOADSTOP_BUTTON, reloadstop, true, b, n, Reload, NSGTK_STOCK_REFRESH) + +#ifdef TOOLBAR_ITEM_SET +#undef TOOLBAR_ITEM +#undef TOOLBAR_ITEM_SET +#endif diff --git a/frontends/gtk/viewsource.c b/frontends/gtk/viewsource.c index acf81018d..7c11862c6 100644 --- a/frontends/gtk/viewsource.c +++ b/frontends/gtk/viewsource.c @@ -34,8 +34,8 @@ nserror nsgtk_viewsource(GtkWindow *parent, struct browser_window *bw) { nserror ret; struct hlcache_handle *hlcontent; - const char *source_data; - unsigned long source_size; + const uint8_t *source_data; + size_t source_size; char *ndata = NULL; size_t ndata_len; char *filename; @@ -52,7 +52,7 @@ nserror nsgtk_viewsource(GtkWindow *parent, struct browser_window *bw) source_data = content_get_source_data(hlcontent, &source_size); - ret = nsurl_nice(browser_window_get_url(bw), &filename, false); + ret = nsurl_nice(browser_window_access_url(bw), &filename, false); if (ret != NSERROR_OK) { filename = strdup(messages_get("SaveSource")); if (filename == NULL) { @@ -60,15 +60,16 @@ nserror nsgtk_viewsource(GtkWindow *parent, struct browser_window *bw) } } - title = malloc(strlen(nsurl_access(browser_window_get_url(bw))) + SLEN("Source of - NetSurf") + 1); + title = malloc(strlen(nsurl_access(browser_window_access_url(bw))) + SLEN("Source of - NetSurf") + 1); if (title == NULL) { free(filename); return NSERROR_NOMEM; } - sprintf(title, "Source of %s - NetSurf", nsurl_access(browser_window_get_url(bw))); + sprintf(title, "Source of %s - NetSurf", nsurl_access(browser_window_access_url(bw))); - ret = utf8_from_enc(source_data, - content_get_encoding(hlcontent, CONTENT_ENCODING_NORMAL), + ret = utf8_from_enc((const char *)source_data, + content_get_encoding(hlcontent, + CONTENT_ENCODING_NORMAL), source_size, &ndata, &ndata_len); diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c index 7f24d40ac..f5c87ef87 100644 --- a/frontends/gtk/window.c +++ b/frontends/gtk/window.c @@ -31,10 +31,13 @@ #include <gdk/gdkkeysyms.h> #include <gdk-pixbuf/gdk-pixdata.h> -#include "netsurf/inttypes.h" +#include "utils/utils.h" #include "utils/log.h" #include "utils/utf8.h" #include "utils/nsoption.h" +#include "utils/messages.h" +#include "utils/nsurl.h" +#include "netsurf/inttypes.h" #include "netsurf/content.h" #include "netsurf/browser_window.h" #include "netsurf/mouse.h" @@ -45,12 +48,13 @@ #include "desktop/searchweb.h" #include "desktop/textinput.h" -#include "gtk/window.h" #include "gtk/selection.h" #include "gtk/warn.h" #include "gtk/compat.h" #include "gtk/gui.h" #include "gtk/scaffolding.h" +#include "gtk/toolbar_items.h" +#include "gtk/toolbar.h" #include "gtk/local_history.h" #include "gtk/plotters.h" #include "gtk/schedule.h" @@ -58,13 +62,18 @@ #include "gtk/bitmap.h" #include "gtk/gdk.h" #include "gtk/resources.h" +#include "gtk/search.h" +#include "gtk/throbber.h" +#include "gtk/window.h" + +/** + * time (in ms) between throbber animation frame updates + */ +#define THROBBER_FRAME_TIME (100) static GtkWidget *select_menu; static struct form_control *select_menu_control; -static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, - gpointer user_data); - struct gui_window { /** * The gtk scaffold object containing menu, buttons, url bar, [tabs], @@ -94,12 +103,21 @@ struct gui_window { /** previous event location */ int last_x, last_y; - /** The top level container (tabContents) */ + /** controls toolbar context */ + struct nsgtk_toolbar *toolbar; + + /** search toolbar context */ + struct gtk_search *search; + + /** The top level container (tabBox) */ GtkWidget *container; /** display widget for this page or frame */ GtkLayout *layout; + /** The container for the layout etc */ + GtkWidget *grid; + /** handle to the the visible tab */ GtkWidget *tab; @@ -112,15 +130,15 @@ struct gui_window { /** has the status pane had its first size operation yet? */ bool paned_sized; - /** to allow disactivation / resume of normal window behaviour */ - gulong signalhandler[NSGTK_WINDOW_SIGNAL_COUNT]; - /** The icon this window should have */ GdkPixbuf *icon; /** The input method to use with this window */ GtkIMContext *input_method; + /** current frame of throbber */ + int throb_frame; + /** list for cleanup */ struct gui_window *next, *prev; }; @@ -128,60 +146,12 @@ struct gui_window { /**< first entry in window list */ struct gui_window *window_list = NULL; -/** flag controlling opening of tabs in teh background */ -int temp_open_background = -1; - -struct nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g) -{ - return g->scaffold; -} - -GdkPixbuf *nsgtk_get_icon(struct gui_window *gw) -{ - return gw->icon; -} - -struct browser_window *nsgtk_get_browser_window(struct gui_window *g) -{ - return g->bw; -} - -unsigned long nsgtk_window_get_signalhandler(struct gui_window *g, int i) -{ - return g->signalhandler[i]; -} - -GtkLayout *nsgtk_window_get_layout(struct gui_window *g) -{ - return g->layout; -} - -GtkWidget *nsgtk_window_get_tab(struct gui_window *g) -{ - return g->tab; -} - -void nsgtk_window_set_tab(struct gui_window *g, GtkWidget *w) -{ - g->tab = w; -} - - -struct gui_window *nsgtk_window_iterate(struct gui_window *g) -{ - return g->next; -} - -float nsgtk_get_scale_for_gui(struct gui_window *g) -{ - return browser_window_get_scale(g->bw); -} - -static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, - gpointer user_data) +static void +nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) { form_select_process_selection(select_menu_control, - (intptr_t)user_data); + (intptr_t)user_data); } #if GTK_CHECK_VERSION(3,0,0) @@ -278,8 +248,10 @@ nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) #endif -static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, - GdkEventMotion *event, gpointer data) +static gboolean +nsgtk_window_motion_notify_event(GtkWidget *widget, + GdkEventMotion *event, + gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; @@ -325,15 +297,34 @@ static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; - browser_window_mouse_track(g->bw, g->mouse.state, - event->x / browser_window_get_scale(g->bw), - event->y / browser_window_get_scale(g->bw)); + browser_window_mouse_track(g->bw, g->mouse.state, event->x, event->y); return TRUE; } -static gboolean nsgtk_window_button_press_event(GtkWidget *widget, - GdkEventButton *event, gpointer data) +/** + * GTK signal handler for focus-out-event on layout + * + * when focus leaves the layout widget ensure the caret is cleared + */ +static gboolean +nsgtk_window_focus_out_event(GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + struct gui_window *g = data; + + browser_window_remove_caret(g->bw, true); + return FALSE; +} + +/** + * GTK signal handler for button-press-event on layout + */ +static gboolean +nsgtk_window_button_press_event(GtkWidget *widget, + GdkEventButton *event, + gpointer data) { struct gui_window *g = data; @@ -341,8 +332,8 @@ static gboolean nsgtk_window_button_press_event(GtkWidget *widget, gtk_widget_grab_focus(GTK_WIDGET(g->layout)); nsgtk_local_history_hide(); - g->mouse.pressed_x = event->x / browser_window_get_scale(g->bw); - g->mouse.pressed_y = event->y / browser_window_get_scale(g->bw); + g->mouse.pressed_x = event->x; + g->mouse.pressed_y = event->y; switch (event->button) { case 1: /* Left button, usually. Pass to core as BUTTON 1. */ @@ -382,25 +373,43 @@ static gboolean nsgtk_window_button_press_event(GtkWidget *widget, g->last_x = event->x; g->last_y = event->y; - browser_window_mouse_click(g->bw, g->mouse.state, g->mouse.pressed_x, - g->mouse.pressed_y); + browser_window_mouse_click(g->bw, + g->mouse.state, + g->mouse.pressed_x, + g->mouse.pressed_y); return TRUE; } -static gboolean nsgtk_window_button_release_event(GtkWidget *widget, - GdkEventButton *event, gpointer data) + +static gboolean +nsgtk_window_button_release_event(GtkWidget *widget, + GdkEventButton *event, + gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; + switch (event->button) { + case 8: + nsgtk_toolbar_item_activate(g->toolbar, BACK_BUTTON); + break; + case 9: + nsgtk_toolbar_item_activate(g->toolbar, FORWARD_BUTTON); + break; + default: + NSLOG(netsurf, DEBUG, "event button %d", event->button); + break; + } + /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing */ - if (g->mouse.state & BROWSER_MOUSE_PRESS_1) + if (g->mouse.state & BROWSER_MOUSE_PRESS_1) { g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); - else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) + } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) { g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); + } /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) @@ -409,19 +418,16 @@ static gboolean nsgtk_window_button_release_event(GtkWidget *widget, g->mouse.state ^= BROWSER_MOUSE_MOD_2; if (g->mouse.state & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) { - browser_window_mouse_click(g->bw, g->mouse.state, - event->x / browser_window_get_scale(g->bw), - event->y / browser_window_get_scale(g->bw)); + browser_window_mouse_click(g->bw, g->mouse.state, event->x, event->y); } else { - browser_window_mouse_track(g->bw, 0, - event->x / browser_window_get_scale(g->bw), - event->y / browser_window_get_scale(g->bw)); + browser_window_mouse_track(g->bw, 0, event->x, event->y); } g->mouse.state = 0; return TRUE; } + static gboolean nsgtk_window_scroll_event(GtkWidget *widget, GdkEventScroll *event, @@ -466,9 +472,8 @@ nsgtk_window_scroll_event(GtkWidget *widget, deltay *= nsgtk_adjustment_get_step_increment(vscroll); if (browser_window_scroll_at_point(g->bw, - event->x / browser_window_get_scale(g->bw), - event->y / browser_window_get_scale(g->bw), - deltax, deltay) != true) { + event->x, event->y, + deltax, deltay) != true) { /* core did not handle event so change adjustments */ @@ -510,12 +515,15 @@ nsgtk_window_scroll_event(GtkWidget *widget, return TRUE; } -static gboolean nsgtk_window_keypress_event(GtkWidget *widget, - GdkEventKey *event, gpointer data) + +static gboolean +nsgtk_window_keypress_event(GtkWidget *widget, + GdkEventKey *event, + gpointer data) { struct gui_window *g = data; uint32_t nskey; - + if (gtk_im_context_filter_keypress(g->input_method, event)) return TRUE; @@ -627,17 +635,22 @@ static gboolean nsgtk_window_keypress_event(GtkWidget *widget, return TRUE; } -static gboolean nsgtk_window_keyrelease_event(GtkWidget *widget, - GdkEventKey *event, gpointer data) + +static gboolean +nsgtk_window_keyrelease_event(GtkWidget *widget, + GdkEventKey *event, + gpointer data) { struct gui_window *g = data; - + return gtk_im_context_filter_keypress(g->input_method, event); } -static void nsgtk_window_input_method_commit(GtkIMContext *ctx, - const gchar *str, gpointer data) +static void +nsgtk_window_input_method_commit(GtkIMContext *ctx, + const gchar *str, + gpointer data) { struct gui_window *g = data; size_t len = strlen(str), offset = 0; @@ -652,8 +665,10 @@ static void nsgtk_window_input_method_commit(GtkIMContext *ctx, } -static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, - GtkAllocation *allocation, gpointer data) +static gboolean +nsgtk_window_size_allocate_event(GtkWidget *widget, + GtkAllocation *allocation, + gpointer data) { struct gui_window *g = data; @@ -663,7 +678,8 @@ static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, } -/** when the pane position is changed update the user option +/** + * when the pane position is changed update the user option * * The slightly awkward implementation with the first allocation flag * is necessary because the initial window creation does not cause an @@ -692,11 +708,15 @@ nsgtk_paned_notify__position(GObject *gobject, GParamSpec *pspec, gpointer data) ((gtk_paned_get_position(g->paned) * 10000) / (pane_alloc.width - 1))); } -/** Set status bar / scroll bar proportion according to user option - * when pane is resized. + +/** + * Set status bar / scroll bar proportion according to user option + * when pane is resized. */ -static gboolean nsgtk_paned_size_allocate_event(GtkWidget *widget, - GtkAllocation *allocation, gpointer data) +static gboolean +nsgtk_paned_size_allocate_event(GtkWidget *widget, + GtkAllocation *allocation, + gpointer data) { gtk_paned_set_position(GTK_PANED(widget), (nsoption_int(toolbar_status_size) * allocation->width) / 10000); @@ -704,7 +724,12 @@ static gboolean nsgtk_paned_size_allocate_event(GtkWidget *widget, return TRUE; } -/* destroy the browsing context as there is nothing to display it now */ + +/** + * handler for gtk destroy signal on window container + * + * destroy the browsing context as there is will be nothing to display it now + */ static void window_destroy(GtkWidget *widget, gpointer data) { struct gui_window *gw = data; @@ -712,6 +737,66 @@ static void window_destroy(GtkWidget *widget, gpointer data) browser_window_destroy(gw->bw); g_object_unref(gw->input_method); + + /* free any existing icon */ + if (gw->icon != NULL) { + g_object_unref(gw->icon); + gw->icon = NULL; + } + + free(gw); +} + + +static struct browser_window *bw_from_gw(void *data) +{ + struct gui_window *gw = data; + return gw->bw; +} + + +static bool get_tool_bar_show(void) +{ + const char *cur_bar_show; + + cur_bar_show = nsoption_charp(bar_show); + if (cur_bar_show != NULL) { + if (strcmp(cur_bar_show, "menu/tool") == 0) { + return true; + } else if (strcmp(cur_bar_show, "tool") == 0) { + return true; + } + } + return false; +} + + +/** + * Make the throbber advance to next frame. + * + * scheduled callback to update the throbber + * + * \param p The context passed when scheduled. + */ +static void next_throbber_frame(void *p) +{ + struct gui_window *gw = p; + nserror res; + GdkPixbuf *pixbuf; + + gw->throb_frame++; /* advance to next frame */ + + res = nsgtk_throbber_get_frame(gw->throb_frame, &pixbuf); + if (res == NSERROR_BAD_SIZE) { + gw->throb_frame = 1; + res = nsgtk_throbber_get_frame(gw->throb_frame, &pixbuf); + } + + if (res == NSERROR_OK) { + nsgtk_tab_set_icon(gw->container, pixbuf); + /* only schedule next frame if there are no errors */ + nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, p); + } } @@ -730,13 +815,17 @@ static void window_destroy(GtkWidget *widget, gpointer data) */ static struct gui_window * gui_window_create(struct browser_window *bw, - struct gui_window *existing, - gui_window_create_flags flags) + struct gui_window *existing, + gui_window_create_flags flags) { struct gui_window *g; /* what is being created to return */ - bool tempback; + bool open_in_background = !(nsoption_bool(focus_new)); GtkBuilder* tab_builder; + /* If there is a foreground request, override user preference */ + if (flags & GW_CREATE_FOREGROUND) + open_in_background = false; + nserror res; res = nsgtk_builder_new_from_resname("tabcontents", &tab_builder); @@ -781,12 +870,32 @@ gui_window_create(struct browser_window *bw, } /* Construct our primary elements */ - g->container = GTK_WIDGET(gtk_builder_get_object(tab_builder, "tabContents")); + g->container = GTK_WIDGET(gtk_builder_get_object(tab_builder, "tabBox")); g->layout = GTK_LAYOUT(gtk_builder_get_object(tab_builder, "layout")); + g->grid = GTK_WIDGET(gtk_builder_get_object(tab_builder, "tabContents")); g->status_bar = GTK_LABEL(gtk_builder_get_object(tab_builder, "status_bar")); g->paned = GTK_PANED(gtk_builder_get_object(tab_builder, "hpaned1")); g->input_method = gtk_im_multicontext_new(); + + /* create toolbar */ + res = nsgtk_toolbar_create(tab_builder, bw_from_gw, g, + !!(flags & GW_CREATE_FOCUS_LOCATION), + &g->toolbar); + if (res != NSERROR_OK) { + free(g); + g_object_unref(tab_builder); + return NULL; + } + + /* local page text search toolbar */ + res = nsgtk_search_create(tab_builder, g->bw, &g->search); + if (res != NSERROR_OK) { + free(g); + g_object_unref(tab_builder); + return NULL; + } + /* set a default favicon */ g_object_ref(favicon_pixbuf); g->icon = favicon_pixbuf; @@ -816,11 +925,10 @@ gui_window_create(struct browser_window *bw, /* set the default background colour of the drawing area to white. */ nsgtk_widget_override_background_color(GTK_WIDGET(g->layout), - GTK_STATE_NORMAL, + GTK_STATE_FLAG_NORMAL, 0, 0xffff, 0xffff, 0xffff); - g->signalhandler[NSGTK_WINDOW_SIGNAL_REDRAW] = - nsgtk_connect_draw_event(GTK_WIDGET(g->layout), + nsgtk_connect_draw_event(GTK_WIDGET(g->layout), G_CALLBACK(nsgtk_window_draw_event), g); /* helper macro to conect signals to callbacks */ @@ -830,8 +938,7 @@ gui_window_create(struct browser_window *bw, /* layout signals */ CONNECT(g->layout, "motion-notify-event", nsgtk_window_motion_notify_event, g); - g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = - CONNECT(g->layout, "button-press-event", + CONNECT(g->layout, "button-press-event", nsgtk_window_button_press_event, g); CONNECT(g->layout, "button-release-event", nsgtk_window_button_release_event, g); @@ -843,6 +950,8 @@ gui_window_create(struct browser_window *bw, nsgtk_window_size_allocate_event, g); CONNECT(g->layout, "scroll-event", nsgtk_window_scroll_event, g); + CONNECT(g->layout, "focus-out-event", + nsgtk_window_focus_out_event, g); /* status pane signals */ CONNECT(g->paned, "size-allocate", @@ -864,71 +973,65 @@ gui_window_create(struct browser_window *bw, nsgtk_window_input_method_commit, g); /* add the tab container to the scaffold notebook */ - switch (temp_open_background) { - case -1: - tempback = !(nsoption_bool(focus_new)); - break; - case 0: - tempback = false; - break; - default: - tempback = true; - break; - } - nsgtk_tab_add(g, g->container, tempback); + nsgtk_tab_add(g, g->container, + open_in_background, + messages_get("NewTab"), g->icon); + + /* initialy should not be visible */ + nsgtk_search_toggle_visibility(g->search); + + /* set toolbar visibility from user option */ + nsgtk_toolbar_show(g->toolbar, get_tool_bar_show()); /* safe to drop the reference to the tab_builder as the container is * referenced by the notebook now. */ g_object_unref(tab_builder); - return g; -} - - - -void nsgtk_reflow_all_windows(void) -{ - for (struct gui_window *g = window_list; g; g = g->next) { - nsgtk_tab_options_changed(nsgtk_scaffolding_notebook(g->scaffold)); - browser_window_schedule_reformat(g->bw); + /* Finally we need to focus the location bar if requested */ + if (flags & GW_CREATE_FOCUS_LOCATION) { + if (nsgtk_window_item_activate(g, OPENLOCATION_BUTTON) != NSERROR_OK) { + NSLOG(netsurf, WARNING, "Unable to focus location input"); + } } + + return g; } -void nsgtk_window_destroy_browser(struct gui_window *gw) +static void gui_window_destroy(struct gui_window *gw) { - /* remove tab */ - gtk_widget_destroy(gw->container); -} + NSLOG(netsurf, INFO, "gui_window: %p", gw); + assert(gw != NULL); + assert(gw->bw != NULL); + NSLOG(netsurf, INFO, "scaffolding: %p", gw->scaffold); -static void gui_window_destroy(struct gui_window *g) -{ - NSLOG(netsurf, INFO, "gui_window: %p", g); - assert(g != NULL); - assert(g->bw != NULL); - NSLOG(netsurf, INFO, "scaffolding: %p", g->scaffold); + /* kill off any throbber that might be running */ + nsgtk_schedule(-1, next_throbber_frame, gw); - if (g->prev) { - g->prev->next = g->next; + /* remove from window list */ + if (gw->prev) { + gw->prev->next = gw->next; } else { - window_list = g->next; + window_list = gw->next; } - if (g->next) { - g->next->prev = g->prev; + if (gw->next) { + gw->next->prev = gw->prev; } NSLOG(netsurf, INFO, "window list head: %p", window_list); } + /** * favicon setting for gtk gui window. * * \param gw gtk gui window to set favicon on. * \param icon A handle to the new favicon content. */ -static void gui_window_set_icon(struct gui_window *gw, struct hlcache_handle *icon) +static void +gui_window_set_icon(struct gui_window *gw, struct hlcache_handle *icon) { struct bitmap *icon_bitmap = NULL; @@ -952,9 +1055,13 @@ static void gui_window_set_icon(struct gui_window *gw, struct hlcache_handle *ic gw->icon = favicon_pixbuf; } - nsgtk_scaffolding_set_icon(gw); + /* only set icon if throbber not running */ + if (gw->throb_frame == 0) { + nsgtk_tab_set_icon(gw->container, gw->icon); + } } + static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) { GtkAdjustment *vadj = nsgtk_layout_get_vadjustment(g->layout); @@ -969,6 +1076,7 @@ static bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) return true; } + static void nsgtk_redraw_caret(struct gui_window *g) { int sx, sy; @@ -983,6 +1091,7 @@ static void nsgtk_redraw_caret(struct gui_window *g) } + static void gui_window_remove_caret(struct gui_window *g) { int sx, sy; @@ -1000,6 +1109,7 @@ static void gui_window_remove_caret(struct gui_window *g) } + /** * Invalidates an area of a GTK browser window * @@ -1011,7 +1121,6 @@ static nserror nsgtk_window_invalidate_area(struct gui_window *g, const struct rect *rect) { int sx, sy; - float scale; if (rect == NULL) { gtk_widget_queue_draw(GTK_WIDGET(g->layout)); @@ -1023,17 +1132,17 @@ nsgtk_window_invalidate_area(struct gui_window *g, const struct rect *rect) } gui_window_get_scroll(g, &sx, &sy); - scale = browser_window_get_scale(g->bw); gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), - rect->x0 * scale - sx, - rect->y0 * scale - sy, - (rect->x1 - rect->x0) * scale, - (rect->y1 - rect->y0) * scale); + rect->x0 - sx, + rect->y0 - sy, + rect->x1 - rect->x0, + rect->y1 - rect->y0); return NSERROR_OK; } + static void gui_window_set_status(struct gui_window *g, const char *text) { assert(g); @@ -1087,17 +1196,20 @@ gui_window_set_scroll(struct gui_window *g, const struct rect *rect) return NSERROR_OK; } + static void gui_window_update_extent(struct gui_window *g) { int w, h; if (browser_window_get_extents(g->bw, true, &w, &h) == NSERROR_OK) { gtk_layout_set_size(g->layout, w, h); + gtk_widget_queue_resize(g->grid); } } -static void gui_window_set_pointer(struct gui_window *g, - gui_pointer_shape shape) + +static void +gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) { GdkCursor *cursor = NULL; GdkCursorType cursortype; @@ -1182,8 +1294,10 @@ static void gui_window_set_pointer(struct gui_window *g, } -static void gui_window_place_caret(struct gui_window *g, int x, int y, int height, - const struct rect *clip) +static void +gui_window_place_caret(struct gui_window *g, + int x, int y, int height, + const struct rect *clip) { nsgtk_redraw_caret(g); @@ -1215,14 +1329,11 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh * \param gw The gui window to measure content area of. * \param width receives width of window * \param height receives height of window - * \param scaled whether to return scaled values * \return NSERROR_OK on sucess and width and height updated * else error code. */ static nserror -gui_window_get_dimensions(struct gui_window *gw, - int *width, int *height, - bool scaled) +gui_window_get_dimensions(struct gui_window *gw, int *width, int *height) { GtkAllocation alloc; @@ -1232,23 +1343,19 @@ gui_window_get_dimensions(struct gui_window *gw, *width = alloc.width; *height = alloc.height; - if (scaled) { - float scale = browser_window_get_scale(gw->bw); - *width /= scale; - *height /= scale; - } - NSLOG(netsurf, INFO, "gw:%p width:%i height:%i", gw, *width, *height); - return NSERROR_OK; } + static void gui_window_start_selection(struct gui_window *g) { gtk_widget_grab_focus(GTK_WIDGET(g->layout)); } -static void gui_window_create_form_select_menu(struct gui_window *g, - struct form_control *control) + +static void +gui_window_create_form_select_menu(struct gui_window *g, + struct form_control *control) { intptr_t item; struct form_option *option; @@ -1295,11 +1402,15 @@ static void gui_window_create_form_select_menu(struct gui_window *g, gtk_widget_show_all(select_menu); - gtk_menu_popup(GTK_MENU(select_menu), NULL, NULL, NULL, - NULL /* data */, 0, gtk_get_current_event_time()); - + nsgtk_menu_popup_at_pointer(GTK_MENU(select_menu), NULL); } + +/** + * GTK window UI callback when core needs a file selection gadget + * + * \param g The gui window on which the gadget has been requested + */ static void gui_window_file_gadget_open(struct gui_window *g, struct hlcache_handle *hl, @@ -1315,7 +1426,7 @@ gui_window_file_gadget_open(struct gui_window *g, NULL); NSLOG(netsurf, INFO, "*** open dialog: %p", dialog); - + int ret = gtk_dialog_run(GTK_DIALOG(dialog)); NSLOG(netsurf, INFO, "*** return value: %d", ret); if (ret == GTK_RESPONSE_ACCEPT) { @@ -1323,7 +1434,7 @@ gui_window_file_gadget_open(struct gui_window *g, filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog)); - + browser_window_set_gadget_filename(g->bw, gadget, filename); g_free(filename); @@ -1332,6 +1443,147 @@ gui_window_file_gadget_open(struct gui_window *g, gtk_widget_destroy(dialog); } + +/** + * handle throbber changing state + */ +static nserror throbber(struct gui_window *gw, bool active) +{ + nsgtk_toolbar_throbber(gw->toolbar, active); + nsgtk_scaffolding_throbber(gw, active); + if (active) { + nsgtk_schedule(THROBBER_FRAME_TIME, next_throbber_frame, gw); + } else { + nsgtk_schedule(-1, next_throbber_frame, gw); + gw->throb_frame = 0; + /* set tab back to favicon */ + nsgtk_tab_set_icon(gw->container, gw->icon); + } + return NSERROR_OK; +} + + +/** + * handle page info changing + */ +static nserror page_info_change(struct gui_window *gw) +{ + nsgtk_toolbar_page_info_change(gw->toolbar); + return NSERROR_OK; +} + +/** + * GTK window UI callback to process miscellaneous events + * + * \param gw The window receiving the event. + * \param event The event code. + * \return NSERROR_OK when processed ok + */ +static nserror +gui_window_event(struct gui_window *gw, enum gui_window_event event) +{ + switch (event) { + case GW_EVENT_UPDATE_EXTENT: + gui_window_update_extent(gw); + break; + + case GW_EVENT_REMOVE_CARET: + gui_window_remove_caret(gw); + break; + + case GW_EVENT_START_SELECTION: + gui_window_start_selection(gw); + break; + + case GW_EVENT_START_THROBBER: + throbber(gw, true); + break; + + case GW_EVENT_STOP_THROBBER: + throbber(gw, false); + break; + + case GW_EVENT_PAGE_INFO_CHANGE: + page_info_change(gw); + break; + + default: + break; + } + return NSERROR_OK; +} + + +/** + * GTK window UI callback when core changes the current url + * + * \param gw The gui window on which the url has been set. + * \param url The new url. + */ +static nserror gui_window_set_url(struct gui_window *gw, nsurl *url) +{ + return nsgtk_toolbar_set_url(gw->toolbar, url); +} + + +/** + * GTK window UI callback when core changes the current title + * + * \param gw The gui window on which the url has been set. + * \param url The new url. + */ +static void gui_window_set_title(struct gui_window *gw, const char *title) +{ + + if ((title != NULL) && (title[0] != '\0')) { + nsgtk_tab_set_title(gw->container, title); + } + nsgtk_scaffolding_set_title(gw, title); +} + + +/** + * GTK UI callback when search provider details are updated. + * + * \param name The providers name. + * \param bitmap The bitmap representing the provider. + * \return NSERROR_OK on success else error code. + */ +static nserror +gui_search_web_provider_update(const char *name, struct bitmap *bitmap) +{ + struct gui_window *gw; + GdkPixbuf *pixbuf = NULL; + + if (bitmap != NULL) { + pixbuf = nsgdk_pixbuf_get_from_surface(bitmap->surface, 32, 32); + } + + for (gw = window_list; gw != NULL; gw = gw->next) { + nsgtk_toolbar_set_websearch_image(gw->toolbar, pixbuf); + } + + if (pixbuf != NULL) { + g_object_unref(pixbuf); + } + + return NSERROR_OK; +} + + +/** + * GTK frontend web search operation table + */ +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; + + +/** + * GTK frontend browser window operation table + */ static struct gui_window_table window_table = { .create = gui_window_create, .destroy = gui_window_destroy, @@ -1339,22 +1591,115 @@ static struct gui_window_table window_table = { .get_scroll = gui_window_get_scroll, .set_scroll = gui_window_set_scroll, .get_dimensions = gui_window_get_dimensions, - .update_extent = gui_window_update_extent, + .event = gui_window_event, .set_icon = gui_window_set_icon, + .set_title = gui_window_set_title, .set_status = gui_window_set_status, .set_pointer = gui_window_set_pointer, .place_caret = gui_window_place_caret, - .remove_caret = gui_window_remove_caret, .create_form_select_menu = gui_window_create_form_select_menu, .file_gadget_open = gui_window_file_gadget_open, - .start_selection = gui_window_start_selection, - - /* from scaffold */ - .set_title = nsgtk_window_set_title, .set_url = gui_window_set_url, - .start_throbber = gui_window_start_throbber, - .stop_throbber = gui_window_stop_throbber, + + }; struct gui_window_table *nsgtk_window_table = &window_table; + + +/* exported interface documented in window.h */ +struct nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g) +{ + return g->scaffold; +} + + +/* exported interface documented in window.h */ +struct browser_window *nsgtk_get_browser_window(struct gui_window *g) +{ + return g->bw; +} + + +/* exported interface documented in window.h */ +GtkLayout *nsgtk_window_get_layout(struct gui_window *g) +{ + return g->layout; +} + + +/* exported interface documented in window.h */ +nserror +nsgtk_window_search_toggle(struct gui_window *gw) +{ + return nsgtk_search_toggle_visibility(gw->search); +} + + +/* exported interface documented in window.h */ +nserror +nsgtk_window_item_activate(struct gui_window *gw, nsgtk_toolbar_button itemid) +{ + return nsgtk_toolbar_item_activate(gw->toolbar, itemid); +} + + +/* exported interface documented in window.h */ +void nsgtk_window_destroy_browser(struct gui_window *gw) +{ + /* remove tab */ + gtk_widget_destroy(gw->container); +} + + +/* exported interface documented in window.h */ +nserror nsgtk_window_update_all(void) +{ + struct gui_window *gw; + for (gw = window_list; gw != NULL; gw = gw->next) { + nsgtk_tab_options_changed(nsgtk_scaffolding_notebook(gw->scaffold)); + nsgtk_toolbar_restyle(gw->toolbar); + nsgtk_search_restyle(gw->search); + browser_window_schedule_reformat(gw->bw); + } + return NSERROR_OK; +} + + +/* exported interface documented in window.h */ +nserror nsgtk_window_toolbar_show(struct nsgtk_scaffolding *gs, bool show) +{ + struct gui_window *gw; + for (gw = window_list; gw != NULL; gw = gw->next) { + if (gw->scaffold == gs) { + nsgtk_toolbar_show(gw->toolbar, show); + } + } + return NSERROR_OK; +} + + +/* exported interface documented in window.h */ +nserror nsgtk_window_toolbar_update(void) +{ + struct gui_window *gw; + for (gw = window_list; gw != NULL; gw = gw->next) { + nsgtk_toolbar_update(gw->toolbar); + + } + return NSERROR_OK; +} + +/* exported interface documented in window.h */ +nserror nsgtk_window_position_page_info(struct gui_window *gw, + struct nsgtk_pi_window *win) +{ + return nsgtk_toolbar_position_page_info(gw->toolbar, win); +} + +/* exported interface documented in window.h */ +nserror nsgtk_window_position_local_history(struct gui_window *gw) +{ + return nsgtk_toolbar_position_local_history(gw->toolbar); +} diff --git a/frontends/gtk/window.h b/frontends/gtk/window.h index 7e46a7c60..a43e0b197 100644 --- a/frontends/gtk/window.h +++ b/frontends/gtk/window.h @@ -19,28 +19,98 @@ #ifndef NETSURF_GTK_WINDOW_H #define NETSURF_GTK_WINDOW_H 1 -extern struct gui_window_table *nsgtk_window_table; +struct nsgtk_pi_window; -typedef enum nsgtk_window_signals { - NSGTK_WINDOW_SIGNAL_CLICK, - NSGTK_WINDOW_SIGNAL_REDRAW, - NSGTK_WINDOW_SIGNAL_COUNT -} nsgtk_window_signal; +extern struct gui_window_table *nsgtk_window_table; +extern struct gui_search_web_table *nsgtk_search_web_table; extern struct gui_window *window_list; -extern int temp_open_background; - -struct browser_window *nsgtk_get_browser_window(struct gui_window *g); -struct nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g); -GdkPixbuf *nsgtk_get_icon(struct gui_window *gw); -void nsgtk_reflow_all_windows(void); -float nsgtk_get_scale_for_gui(struct gui_window *g); -int nsgtk_gui_window_update_targets(struct gui_window *g); -void nsgtk_window_destroy_browser(struct gui_window *g); -unsigned long nsgtk_window_get_signalhandler(struct gui_window *g, int i); -GtkLayout *nsgtk_window_get_layout(struct gui_window *g); -struct gui_window *nsgtk_window_iterate(struct gui_window *g); -GtkWidget *nsgtk_window_get_tab(struct gui_window *g); -void nsgtk_window_set_tab(struct gui_window *g, GtkWidget *w); + +/** + * get core browsing context from gui window handle + * + * \param gw gui window handle + */ +struct browser_window *nsgtk_get_browser_window(struct gui_window *gw); + +/** + * get containing nsgtk scaffolding handle from gui window handle + * + * \param gw gui window handle + */ +struct nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *gw); + +/** + * Every window will have its tab, toolbar and drawing area updated + * + * The update will ensure the correct tab options are used, the + * toolbar size and style is changed and the browser window contents + * redrawn. + */ +nserror nsgtk_window_update_all(void); + +/** + * every window will have its toolbar updated to reflect user settings + */ +nserror nsgtk_window_toolbar_update(void); + +/** + * Windows associated with a scaffold will have their toolbar show state set + */ +nserror nsgtk_window_toolbar_show(struct nsgtk_scaffolding *gs, bool show); + +/** + * update targets + * + * \param gw gui window handle + */ +int nsgtk_gui_window_update_targets(struct gui_window *gw); + +/** + * destroy browsing context + * + * \param gw gui window handle + */ +void nsgtk_window_destroy_browser(struct gui_window *gw); + + +/** + * toggle search visibility + * + * \param gw gui window handle + */ +nserror nsgtk_window_search_toggle(struct gui_window *gw); + +/** + * get gtk layout from gui handle + * + * \param gw gui window handle + */ +GtkLayout *nsgtk_window_get_layout(struct gui_window *gw); + + +/** + * activate the handler for a item in a toolbar of a gui window + * + * \param gw The gui window handle + * \param itemid The id of the item to activate + */ +nserror nsgtk_window_item_activate(struct gui_window *gw, nsgtk_toolbar_button itemid); + +/** + * position page_info appropriately + * + * \param gw The gui window handle to position relative to + * \param win The page-info window to position + */ +nserror nsgtk_window_position_page_info(struct gui_window *gw, + struct nsgtk_pi_window *win); + +/** + * position local_history appropriately + * + * \param gw The gui window handle to position relative to + */ +nserror nsgtk_window_position_local_history(struct gui_window *gw); #endif /* NETSURF_GTK_WINDOW_H */ |