From 42f89d4e0b35bbe768918305b624e20ef654d619 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 29 Jan 2011 23:40:22 +0000 Subject: fixup gtk source file names svn path=/trunk/netsurf/; revision=11529 --- gtk/Makefile.target | 14 +- gtk/bitmap.c | 348 +++++++ gtk/bitmap.h | 33 + gtk/compat.c | 90 ++ gtk/compat.h | 36 + gtk/completion.c | 75 ++ gtk/completion.h | 32 + gtk/cookies.c | 218 ++++ gtk/cookies.h | 34 + gtk/dialogs/about.c | 85 ++ gtk/dialogs/about.h | 26 + gtk/dialogs/gtk_about.c | 85 -- gtk/dialogs/gtk_about.h | 26 - gtk/dialogs/gtk_options.c | 939 ----------------- gtk/dialogs/gtk_options.h | 34 - gtk/dialogs/gtk_source.c | 528 ---------- gtk/dialogs/gtk_source.h | 28 - gtk/dialogs/options.c | 940 +++++++++++++++++ gtk/dialogs/options.h | 34 + gtk/dialogs/source.c | 529 ++++++++++ gtk/dialogs/source.h | 28 + gtk/download.c | 827 +++++++++++++++ gtk/download.h | 81 ++ gtk/filetype.c | 221 ++++ gtk/filetype.h | 21 + gtk/font_pango.c | 3 +- gtk/gtk_bitmap.c | 347 ------- gtk/gtk_bitmap.h | 33 - gtk/gtk_compat.c | 90 -- gtk/gtk_compat.h | 36 - gtk/gtk_completion.c | 74 -- gtk/gtk_completion.h | 32 - gtk/gtk_cookies.c | 218 ---- gtk/gtk_cookies.h | 34 - gtk/gtk_download.c | 827 --------------- gtk/gtk_download.h | 81 -- gtk/gtk_filetype.c | 221 ---- gtk/gtk_filetype.h | 21 - gtk/gtk_gui.c | 1150 -------------------- gtk/gtk_gui.h | 51 - gtk/gtk_history.c | 263 ----- gtk/gtk_history.h | 40 - gtk/gtk_hotlist.c | 279 ----- gtk/gtk_hotlist.h | 38 - gtk/gtk_login.c | 182 ---- gtk/gtk_menu.c | 543 ---------- gtk/gtk_menu.h | 195 ---- gtk/gtk_plotters.c | 569 ---------- gtk/gtk_plotters.h | 46 - gtk/gtk_print.c | 543 ---------- gtk/gtk_print.h | 50 - gtk/gtk_save.c | 81 -- gtk/gtk_scaffolding.c | 2540 -------------------------------------------- gtk/gtk_scaffolding.h | 156 --- gtk/gtk_schedule.c | 128 --- gtk/gtk_schedule.h | 25 - gtk/gtk_search.c | 265 ----- gtk/gtk_search.h | 39 - gtk/gtk_selection.c | 119 --- gtk/gtk_selection.h | 25 - gtk/gtk_tabs.c | 217 ---- gtk/gtk_tabs.h | 30 - gtk/gtk_theme.c | 785 -------------- gtk/gtk_theme.h | 46 - gtk/gtk_throbber.c | 106 -- gtk/gtk_throbber.h | 35 - gtk/gtk_thumbnail.c | 138 --- gtk/gtk_toolbar.c | 1113 -------------------- gtk/gtk_toolbar.h | 91 -- gtk/gtk_treeview.c | 556 ---------- gtk/gtk_treeview.h | 54 - gtk/gtk_window.c | 1121 -------------------- gtk/gtk_window.h | 51 - gtk/gui.c | 1150 ++++++++++++++++++++ gtk/gui.h | 51 + gtk/history.c | 263 +++++ gtk/history.h | 40 + gtk/hotlist.c | 279 +++++ gtk/hotlist.h | 38 + gtk/login.c | 183 ++++ gtk/menu.c | 543 ++++++++++ gtk/menu.h | 195 ++++ gtk/plotters.c | 570 ++++++++++ gtk/plotters.h | 46 + gtk/print.c | 543 ++++++++++ gtk/print.h | 50 + gtk/save.c | 82 ++ gtk/scaffolding.c | 2541 +++++++++++++++++++++++++++++++++++++++++++++ gtk/scaffolding.h | 157 +++ gtk/schedule.c | 128 +++ gtk/schedule.h | 25 + gtk/search.c | 266 +++++ gtk/search.h | 39 + gtk/selection.c | 119 +++ gtk/selection.h | 25 + gtk/sexy_icon_entry.c | 6 +- gtk/tabs.c | 217 ++++ gtk/tabs.h | 30 + gtk/theme.c | 786 ++++++++++++++ gtk/theme.h | 46 + gtk/throbber.c | 106 ++ gtk/throbber.h | 35 + gtk/thumbnail.c | 138 +++ gtk/toolbar.c | 1113 ++++++++++++++++++++ gtk/toolbar.h | 92 ++ gtk/treeview.c | 556 ++++++++++ gtk/treeview.h | 54 + gtk/window.c | 1123 ++++++++++++++++++++ gtk/window.h | 51 + 109 files changed, 15349 insertions(+), 15336 deletions(-) create mode 100644 gtk/bitmap.c create mode 100644 gtk/bitmap.h create mode 100644 gtk/compat.c create mode 100644 gtk/compat.h create mode 100644 gtk/completion.c create mode 100644 gtk/completion.h create mode 100644 gtk/cookies.c create mode 100644 gtk/cookies.h create mode 100644 gtk/dialogs/about.c create mode 100644 gtk/dialogs/about.h delete mode 100644 gtk/dialogs/gtk_about.c delete mode 100644 gtk/dialogs/gtk_about.h delete mode 100644 gtk/dialogs/gtk_options.c delete mode 100644 gtk/dialogs/gtk_options.h delete mode 100644 gtk/dialogs/gtk_source.c delete mode 100644 gtk/dialogs/gtk_source.h create mode 100644 gtk/dialogs/options.c create mode 100644 gtk/dialogs/options.h create mode 100644 gtk/dialogs/source.c create mode 100644 gtk/dialogs/source.h create mode 100644 gtk/download.c create mode 100644 gtk/download.h create mode 100644 gtk/filetype.c create mode 100644 gtk/filetype.h delete mode 100644 gtk/gtk_bitmap.c delete mode 100644 gtk/gtk_bitmap.h delete mode 100644 gtk/gtk_compat.c delete mode 100644 gtk/gtk_compat.h delete mode 100644 gtk/gtk_completion.c delete mode 100644 gtk/gtk_completion.h delete mode 100644 gtk/gtk_cookies.c delete mode 100644 gtk/gtk_cookies.h delete mode 100644 gtk/gtk_download.c delete mode 100644 gtk/gtk_download.h delete mode 100644 gtk/gtk_filetype.c delete mode 100644 gtk/gtk_filetype.h delete mode 100644 gtk/gtk_gui.c delete mode 100644 gtk/gtk_gui.h delete mode 100644 gtk/gtk_history.c delete mode 100644 gtk/gtk_history.h delete mode 100644 gtk/gtk_hotlist.c delete mode 100644 gtk/gtk_hotlist.h delete mode 100644 gtk/gtk_login.c delete mode 100644 gtk/gtk_menu.c delete mode 100644 gtk/gtk_menu.h delete mode 100644 gtk/gtk_plotters.c delete mode 100644 gtk/gtk_plotters.h delete mode 100644 gtk/gtk_print.c delete mode 100644 gtk/gtk_print.h delete mode 100644 gtk/gtk_save.c delete mode 100644 gtk/gtk_scaffolding.c delete mode 100644 gtk/gtk_scaffolding.h delete mode 100644 gtk/gtk_schedule.c delete mode 100644 gtk/gtk_schedule.h delete mode 100644 gtk/gtk_search.c delete mode 100644 gtk/gtk_search.h delete mode 100644 gtk/gtk_selection.c delete mode 100644 gtk/gtk_selection.h delete mode 100644 gtk/gtk_tabs.c delete mode 100644 gtk/gtk_tabs.h delete mode 100644 gtk/gtk_theme.c delete mode 100644 gtk/gtk_theme.h delete mode 100644 gtk/gtk_throbber.c delete mode 100644 gtk/gtk_throbber.h delete mode 100644 gtk/gtk_thumbnail.c delete mode 100644 gtk/gtk_toolbar.c delete mode 100644 gtk/gtk_toolbar.h delete mode 100644 gtk/gtk_treeview.c delete mode 100644 gtk/gtk_treeview.h delete mode 100644 gtk/gtk_window.c delete mode 100644 gtk/gtk_window.h create mode 100644 gtk/gui.c create mode 100644 gtk/gui.h create mode 100644 gtk/history.c create mode 100644 gtk/history.h create mode 100644 gtk/hotlist.c create mode 100644 gtk/hotlist.h create mode 100644 gtk/login.c create mode 100644 gtk/menu.c create mode 100644 gtk/menu.h create mode 100644 gtk/plotters.c create mode 100644 gtk/plotters.h create mode 100644 gtk/print.c create mode 100644 gtk/print.h create mode 100644 gtk/save.c create mode 100644 gtk/scaffolding.c create mode 100644 gtk/scaffolding.h create mode 100644 gtk/schedule.c create mode 100644 gtk/schedule.h create mode 100644 gtk/search.c create mode 100644 gtk/search.h create mode 100644 gtk/selection.c create mode 100644 gtk/selection.h create mode 100644 gtk/tabs.c create mode 100644 gtk/tabs.h create mode 100644 gtk/theme.c create mode 100644 gtk/theme.h create mode 100644 gtk/throbber.c create mode 100644 gtk/throbber.h create mode 100644 gtk/thumbnail.c create mode 100644 gtk/toolbar.c create mode 100644 gtk/toolbar.h create mode 100644 gtk/treeview.c create mode 100644 gtk/treeview.h create mode 100644 gtk/window.c create mode 100644 gtk/window.h diff --git a/gtk/Makefile.target b/gtk/Makefile.target index ef9c97978..9fd780a7c 100644 --- a/gtk/Makefile.target +++ b/gtk/Makefile.target @@ -57,14 +57,12 @@ # ---------------------------------------------------------------------------- # S_GTK are sources purely for the GTK build -S_GTK := font_pango.c gtk_bitmap.c gtk_gui.c gtk_schedule.c \ - gtk_thumbnail.c gtk_plotters.c gtk_treeview.c gtk_scaffolding.c \ - gtk_completion.c gtk_login.c gtk_throbber.c gtk_selection.c \ - gtk_history.c gtk_window.c gtk_filetype.c gtk_download.c \ - gtk_menu.c gtk_print.c gtk_save.c gtk_search.c gtk_tabs.c \ - gtk_theme.c gtk_toolbar.c sexy_icon_entry.c gtk_compat.c \ - gtk_cookies.c gtk_hotlist.c \ - $(addprefix dialogs/,gtk_options.c gtk_about.c gtk_source.c) +S_GTK := font_pango.c bitmap.c gui.c schedule.c thumbnail.c plotters.c \ + treeview.c scaffolding.c completion.c login.c throbber.c \ + selection.c history.c window.c filetype.c download.c menu.c \ + print.c save.c search.c tabs.c theme.c toolbar.c \ + sexy_icon_entry.c compat.c cookies.c hotlist.c \ + $(addprefix dialogs/,options.c about.c source.c) S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c) # code in utils/container.ch is non-universal it seems diff --git a/gtk/bitmap.c b/gtk/bitmap.c new file mode 100644 index 000000000..5dafb129e --- /dev/null +++ b/gtk/bitmap.c @@ -0,0 +1,348 @@ +/* + * Copyright 2004 James Bursa + * + * 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 . + */ + +/** \file + * Generic bitmap handling (GDK / GTK+ implementation). + * + * This implements the interface given by desktop/bitmap.h using GdkPixbufs. + */ + +#include +#include +#include +#include +#include + +#include "content/content.h" +#include "gtk/bitmap.h" +#include "gtk/scaffolding.h" +#include "image/bitmap.h" +#include "utils/log.h" + + +struct bitmap { + GdkPixbuf *primary; + GdkPixbuf *pretile_x; + GdkPixbuf *pretile_y; + GdkPixbuf *pretile_xy; + bool opaque; +}; + +#define MIN_PRETILE_WIDTH 256 +#define MIN_PRETILE_HEIGHT 256 + + +/** + * 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 + * \return an opaque struct bitmap, or NULL on memory exhaustion + */ + +void *bitmap_create(int width, int height, unsigned int state) +{ + struct bitmap *bmp = malloc(sizeof(struct bitmap)); + + bmp->primary = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, + 8, width, height); + + /* fill the pixbuf in with 100% transparent black, as the memory + * won't have been cleared. + */ + gdk_pixbuf_fill(bmp->primary, 0); + bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL; + bmp->opaque = (state & BITMAP_OPAQUE) != 0; + return bmp; +} + + +/** + * Sets whether a bitmap should be plotted opaque + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \param opaque whether the bitmap should be plotted opaque + */ +void bitmap_set_opaque(void *vbitmap, bool opaque) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + bitmap->opaque = opaque; +} + + +/** + * Tests whether a bitmap has an opaque alpha channel + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return whether the bitmap is opaque + */ +bool bitmap_test_opaque(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); +/* todo: test if bitmap is opaque */ + return false; +} + + +/** + * Gets whether a bitmap should be plotted opaque + * + * \param vbitmap a bitmap, as returned by bitmap_create() + */ +bool bitmap_get_opaque(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + return bitmap->opaque; +} + + +/** + * Return a pointer to the pixel data in a bitmap. + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return pointer to the pixel buffer + * + * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end + * of rows. The width of a row in bytes is given by bitmap_get_rowstride(). + */ + +unsigned char *bitmap_get_buffer(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + return (unsigned char *)gdk_pixbuf_get_pixels(bitmap->primary); +} + + +/** + * Find the width of a pixel row in bytes. + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return width of a pixel row in the bitmap + */ + +size_t bitmap_get_rowstride(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + return gdk_pixbuf_get_rowstride(bitmap->primary); +} + + +/** + * Find the bytes per pixel of a bitmap + * + * \param vbitmap a bitmap, as returned by bitmap_create() + * \return bytes per pixel + */ + +size_t bitmap_get_bpp(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + return 4; +} + + +static void +gtk_bitmap_free_pretiles(struct bitmap *bitmap) +{ +#define FREE_TILE(XY) if (bitmap->pretile_##XY) g_object_unref(bitmap->pretile_##XY); bitmap->pretile_##XY = NULL + FREE_TILE(x); + FREE_TILE(y); + FREE_TILE(xy); +#undef FREE_TILE +} + +/** + * Free a bitmap. + * + * \param vbitmap a bitmap, as returned by bitmap_create() + */ + +void bitmap_destroy(void *vbitmap) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + assert(bitmap); + gtk_bitmap_free_pretiles(bitmap); + g_object_unref(bitmap->primary); + free(bitmap); +} + + +/** + * 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 + */ + +bool bitmap_save(void *vbitmap, const char *path, unsigned flags) +{ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + GError *err = NULL; + + gdk_pixbuf_save(bitmap->primary, path, "png", &err, NULL); + + if (err == NULL) + /* TODO: report an error here */ + return false; + + return true; +} + + +/** + * The bitmap image has changed, so flush any persistant cache. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +void bitmap_modified(void *vbitmap) { + struct bitmap *bitmap = (struct bitmap *)vbitmap; + gtk_bitmap_free_pretiles(bitmap); +} + + +/** + * The bitmap image can be suspended. + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param private_word a private word to be returned later + * \param invalidate the function to be called upon suspension + */ +void bitmap_set_suspendable(void *vbitmap, void *private_word, + void (*invalidate)(void *vbitmap, void *private_word)) { +} + +int bitmap_get_width(void *vbitmap){ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + return gdk_pixbuf_get_width(bitmap->primary); +} + +int bitmap_get_height(void *vbitmap){ + struct bitmap *bitmap = (struct bitmap *)vbitmap; + return gdk_pixbuf_get_height(bitmap->primary); +} + +static GdkPixbuf * +gtk_bitmap_generate_pretile(GdkPixbuf *primary, int repeat_x, int repeat_y) +{ + int width = gdk_pixbuf_get_width(primary); + int height = gdk_pixbuf_get_height(primary); + size_t primary_stride = gdk_pixbuf_get_rowstride(primary); + GdkPixbuf *result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, + width * repeat_x, height * repeat_y); + char *target_buffer = (char *)gdk_pixbuf_get_pixels(result); + int x,y,row; + /* This algorithm won't work if the strides are not multiples */ + assert((size_t)gdk_pixbuf_get_rowstride(result) == + (primary_stride * repeat_x)); + + if (repeat_x == 1 && repeat_y == 1) { + g_object_ref(primary); + g_object_unref(result); + return primary; + } + + for (y = 0; y < repeat_y; ++y) { + char *primary_buffer = (char *)gdk_pixbuf_get_pixels(primary); + for (row = 0; row < height; ++row) { + for (x = 0; x < repeat_x; ++x) { + memcpy(target_buffer, + primary_buffer, primary_stride); + target_buffer += primary_stride; + } + primary_buffer += primary_stride; + } + } + return result; +} + +/** + * The primary image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +GdkPixbuf * +gtk_bitmap_get_primary(struct bitmap *bitmap) +{ + if (bitmap != NULL) + return bitmap->primary; + else + return NULL; +} + +/** + * The X-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +GdkPixbuf * +gtk_bitmap_get_pretile_x(struct bitmap* bitmap) +{ + if (!bitmap->pretile_x) { + int width = gdk_pixbuf_get_width(bitmap->primary); + int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; + LOG(("Pretiling %p for X*%d", bitmap, xmult)); + bitmap->pretile_x = gtk_bitmap_generate_pretile(bitmap->primary, xmult, 1); + } + return bitmap->pretile_x; + +} + +/** + * The Y-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +GdkPixbuf * +gtk_bitmap_get_pretile_y(struct bitmap* bitmap) +{ + if (!bitmap->pretile_y) { + int height = gdk_pixbuf_get_height(bitmap->primary); + int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; + LOG(("Pretiling %p for Y*%d", bitmap, ymult)); + bitmap->pretile_y = gtk_bitmap_generate_pretile(bitmap->primary, 1, ymult); + } + return bitmap->pretile_y; +} + +/** + * The XY-pretiled image associated with this bitmap object. + * + * \param bitmap a bitmap, as returned by bitmap_create() + */ +GdkPixbuf * +gtk_bitmap_get_pretile_xy(struct bitmap* bitmap) +{ + if (!bitmap->pretile_xy) { + int width = gdk_pixbuf_get_width(bitmap->primary); + int height = gdk_pixbuf_get_height(bitmap->primary); + int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; + int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; + LOG(("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult)); + bitmap->pretile_xy = gtk_bitmap_generate_pretile(bitmap->primary, xmult, ymult); + } + return bitmap->pretile_xy; +} diff --git a/gtk/bitmap.h b/gtk/bitmap.h new file mode 100644 index 000000000..d936f7d76 --- /dev/null +++ b/gtk/bitmap.h @@ -0,0 +1,33 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NS_GTK_BITMAP_H +#define NS_GTK_BITMAP_H + +#include +#include +#include "image/bitmap.h" + +GdkPixbuf *gtk_bitmap_get_primary(struct bitmap*); +GdkPixbuf *gtk_bitmap_get_pretile_x(struct bitmap*); +GdkPixbuf *gtk_bitmap_get_pretile_y(struct bitmap*); +GdkPixbuf *gtk_bitmap_get_pretile_xy(struct bitmap*); + + + +#endif /* NS_GTK_BITMAP_H */ diff --git a/gtk/compat.c b/gtk/compat.c new file mode 100644 index 000000000..822459474 --- /dev/null +++ b/gtk/compat.c @@ -0,0 +1,90 @@ +/* + * Copyright 2010 Rob Kendrick + * + * 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 . + */ + +/** \file + * Compatibility functions for older GTK versions (implementation) + */ + +#include "gtk/compat.h" + +void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus) +{ + #if GTK_CHECK_VERSION(2,22,0) + gtk_widget_set_can_focus(widget, can_focus); + #else + if (can_focus == TRUE) + GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); + else + GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_FOCUS); + #endif +} + +gboolean nsgtk_widget_has_focus(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,20,0) + return gtk_widget_has_focus(widget); + #else + return GTK_WIDGET_HAS_FOCUS(widget); + #endif +} + +gboolean nsgtk_widget_get_visible(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,20,0) + return gtk_widget_get_visible(widget); + #else + return GTK_WIDGET_VISIBLE(widget); + #endif +} + +gboolean nsgtk_widget_get_realized(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,20,0) + return gtk_widget_get_realized(widget); + #else + return GTK_WIDGET_REALIZED(widget); + #endif +} + +gboolean nsgtk_widget_get_mapped(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,20,0) + return gtk_widget_get_mapped(widget); + #else + return GTK_WIDGET_MAPPED(widget); + #endif +} + +gboolean nsgtk_widget_is_drawable(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,18,0) + return gtk_widget_is_drawable(widget); + #else + return GTK_WIDGET_DRAWABLE(widget); + #endif +} + +GtkStateType nsgtk_widget_get_state(GtkWidget *widget) +{ + #if GTK_CHECK_VERSION(2,18,0) + return gtk_widget_get_state(widget); + #else + return GTK_WIDGET_STATE(widget); + #endif +} + diff --git a/gtk/compat.h b/gtk/compat.h new file mode 100644 index 000000000..489fa7ea1 --- /dev/null +++ b/gtk/compat.h @@ -0,0 +1,36 @@ +/* + * Copyright 2010 Rob Kendrick + * + * 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 . + */ + +/** \file + * Compatibility functions for older GTK versions (interface) + */ + +#ifndef NETSURF_GTK_COMPAT_H_ +#define NETSURF_GTK_COMPAT_H_ + +#include + +void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus); +gboolean nsgtk_widget_has_focus(GtkWidget *widget); +gboolean nsgtk_widget_get_visible(GtkWidget *widget); +gboolean nsgtk_widget_get_realized(GtkWidget *widget); +gboolean nsgtk_widget_get_mapped(GtkWidget *widget); +gboolean nsgtk_widget_is_drawable(GtkWidget *widget); +GtkStateType nsgtk_widget_get_state(GtkWidget *widget); + +#endif /* NETSURF_GTK_COMPAT_H */ diff --git a/gtk/completion.c b/gtk/completion.c new file mode 100644 index 000000000..80a4693e4 --- /dev/null +++ b/gtk/completion.c @@ -0,0 +1,75 @@ +/* + * Copyright 2006 Rob Kendrick + * + * 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 . + */ + +#include +#include "gtk/completion.h" + +#include "content/urldb.h" +#include "utils/log.h" +#include "desktop/options.h" + +GtkListStore *nsgtk_completion_list; + +static void nsgtk_completion_empty(void); +static bool nsgtk_completion_udb_callback(const char *url, + const struct url_data *data); + +void nsgtk_completion_init(void) +{ + nsgtk_completion_list = gtk_list_store_new(1, G_TYPE_STRING); + +} + +gboolean nsgtk_completion_match(GtkEntryCompletion *completion, + const gchar *key, + GtkTreeIter *iter, + gpointer user_data) +{ + char *b[4096]; /* no way of finding out its length :( */ + gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_completion_list), iter, + 0, b, -1); + + /* TODO: work out why this works, when there's no code to implement + * it. I boggle. */ + + return TRUE; + +} + +void nsgtk_completion_empty(void) +{ + gtk_list_store_clear(nsgtk_completion_list); +} + +bool nsgtk_completion_udb_callback(const char *url, const struct url_data *data) +{ + GtkTreeIter iter; + + if (data->visits != 0) { + gtk_list_store_append(nsgtk_completion_list, &iter); + gtk_list_store_set(nsgtk_completion_list, &iter, 0, url, -1); + } + return true; +} + +void nsgtk_completion_update(const char *prefix) +{ + nsgtk_completion_empty(); + if (option_url_suggestion == true) + urldb_iterate_partial(prefix, nsgtk_completion_udb_callback); +} diff --git a/gtk/completion.h b/gtk/completion.h new file mode 100644 index 000000000..67de43d8e --- /dev/null +++ b/gtk/completion.h @@ -0,0 +1,32 @@ +/* + * Copyright 2006 Rob Kendrick + * + * 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 . + */ + +#ifndef _NETSURF_GTK_COMPLETION_H_ +#define _NETSURF_GTK_COMPLETION_H_ + +#include + +extern GtkListStore *nsgtk_completion_list; + +void nsgtk_completion_init(void); +void nsgtk_completion_update(const char *prefix); +gboolean nsgtk_completion_match(GtkEntryCompletion *completion, + const gchar *key, + GtkTreeIter *iter, + gpointer user_data); +#endif diff --git a/gtk/cookies.c b/gtk/cookies.c new file mode 100644 index 000000000..6427a1b06 --- /dev/null +++ b/gtk/cookies.c @@ -0,0 +1,218 @@ +/* + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +/** \file + * Cookies (implementation). + */ + + +#include "desktop/cookies.h" +#include "desktop/plotters.h" +#include "desktop/tree.h" +#include "gtk/gui.h" +#include "gtk/cookies.h" +#include "gtk/plotters.h" +#include "gtk/scaffolding.h" +#include "gtk/treeview.h" + +#define GLADE_NAME "cookies.glade" + +#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ + GtkMenuItem *widget, gpointer g) +#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } +#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ + gpointer g) + +struct menu_events { + const char *widget; + GCallback handler; +}; + +static void nsgtk_cookies_init_menu(void); + +/* edit menu */ +MENUPROTO(delete_selected); +MENUPROTO(delete_all); +MENUPROTO(select_all); +MENUPROTO(clear_selection); + +/* view menu*/ +MENUPROTO(expand_all); +MENUPROTO(expand_domains); +MENUPROTO(expand_cookies); +MENUPROTO(collapse_all); +MENUPROTO(collapse_domains); +MENUPROTO(collapse_cookies); + + +static struct menu_events menu_events[] = { + + /* edit menu */ + MENUEVENT(delete_selected), + MENUEVENT(delete_all), + MENUEVENT(select_all), + MENUEVENT(clear_selection), + + /* view menu*/ + MENUEVENT(expand_all), + MENUEVENT(expand_domains), + MENUEVENT(expand_cookies), + MENUEVENT(collapse_all), + MENUEVENT(collapse_domains), + MENUEVENT(collapse_cookies), + + {NULL, NULL} +}; + +static struct nsgtk_treeview *cookies_window; +static GladeXML *gladeFile; +GtkWindow *wndCookies; + +/** + * Creates the window for the cookies tree. + */ +bool nsgtk_cookies_init(const char *glade_file_location) +{ + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; + + gladeFile = glade_xml_new(glade_file_location, NULL, NULL); + if (gladeFile == NULL) + return false; + + glade_xml_signal_autoconnect(gladeFile); + + wndCookies = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndCookies")); + window = wndCookies; + + scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, + "cookiesScrolled")); + + drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, + "cookiesDrawingArea")); + + cookies_window = nsgtk_treeview_create(cookies_get_tree_flags(), window, + scrolled, drawing_area); + + if (cookies_window == NULL) + return false; + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); + CONNECT(window, "hide", nsgtk_tree_window_hide, cookies_window); + + cookies_initialise(nsgtk_treeview_get_tree(cookies_window), + tree_directory_icon_name, + tree_content_icon_name); + + nsgtk_cookies_init_menu(); + + return true; +} + +/** + * Connects menu events in the cookies window. + */ +void nsgtk_cookies_init_menu() +{ + struct menu_events *event = menu_events; + + while (event->widget != NULL) + { + GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); + g_signal_connect(G_OBJECT(w), "activate", event->handler, + cookies_window); + event++; + } +} + +/** + * Destroys the cookies window and performs any other necessary cleanup actions. + */ +void nsgtk_cookies_destroy(void) +{ + /* TODO: what about gladeFile? */ + cookies_cleanup(); + nsgtk_treeview_destroy(cookies_window); +} + + +/* edit menu */ +MENUHANDLER(delete_selected) +{ + cookies_delete_selected(); + return TRUE; +} + +MENUHANDLER(delete_all) +{ + cookies_delete_all(); + return TRUE; +} + +MENUHANDLER(select_all) +{ + cookies_select_all(); + return TRUE; +} + +MENUHANDLER(clear_selection) +{ + cookies_clear_selection(); + return TRUE; +} + +/* view menu*/ +MENUHANDLER(expand_all) +{ + cookies_expand_all(); + return TRUE; +} + +MENUHANDLER(expand_domains) +{ + cookies_expand_domains(); + return TRUE; +} + +MENUHANDLER(expand_cookies) +{ + cookies_expand_cookies(); + return TRUE; +} + +MENUHANDLER(collapse_all) +{ + cookies_collapse_all(); + return TRUE; +} + +MENUHANDLER(collapse_domains) +{ + cookies_collapse_domains(); + return TRUE; +} + +MENUHANDLER(collapse_cookies) +{ + cookies_collapse_cookies(); + return TRUE; +} diff --git a/gtk/cookies.h b/gtk/cookies.h new file mode 100644 index 000000000..db12dfe31 --- /dev/null +++ b/gtk/cookies.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +/** \file + * Cookies (interface). + */ + +#ifndef __NSGTK_COOKIES_H__ +#define __NSGTK_COOKIES_H__ + +#include + +extern GtkWindow *wndCookies; + +bool nsgtk_cookies_init(const char *glade_file_location); + +void nsgtk_cookies_destroy(void); + +#endif /* __NSGTK_COOKIES_H__ */ diff --git a/gtk/dialogs/about.c b/gtk/dialogs/about.c new file mode 100644 index 000000000..14ddf624c --- /dev/null +++ b/gtk/dialogs/about.c @@ -0,0 +1,85 @@ +/* + * Copyright 2008 Mike Lester + * + * 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 . + */ + +#include "gtk/gui.h" +#include "gtk/dialogs/about.h" +#include "desktop/browser.h" + +GtkAboutDialog* about_dialog; + +static const gchar *authors[] = { + "John-Mark Bell", "James Bursa", "Michael Drake", + "Rob Kendrick", "Adrian Lees", "Vincent Sanders", + "Daniel Silverstone", "Richard Wilson", + "\nContributors:", "Kevin Bagust", "Stefaan Claes", + "Matthew Hambley", "Rob Jackson", "Jeffrey Lee", "Phil Mellor", + "Philip Pemberton", "Darren Salt", "Andrew Timmins", + "John Tytgat", "Chris Williams", + "\nGoogle Summer of Code Contributors:", "Mark Benjamin", + "Adam Blokus", "Paul Blokus", "Sean Fox", + "Michael Lester", "Andrew Sidwell", "Bo Yang", NULL +}; + +static const gchar *translators = "Sebastian Barthel\nBruno D'Arcangeli\n" + "Gerard van Katwijk\nJérôme Mathevet\nSimon Voortman."; +static const gchar *artists[] = { + "Michael Drake", "\nContributors:", "Andrew Duffell", + "John Duffell", "Richard Hallas", "Phil Mellor", NULL +}; + +static const gchar *documenters[] = { + "John-Mark Bell", "James Bursa", "Michael Drake", + "Richard Wilson", "\nContributors:", "James Shaw", NULL +}; + +static const gchar *name = "NetSurf"; +static const gchar *description = + "Small as a mouse, fast as a cheetah, and available for free.\n" + "NetSurf is a portable web browser for RISC OS, AmigaOS, BeOS " + "and UNIX-like platforms."; +static const gchar *url = "http://www.netsurf-browser.org/"; +static const gchar *url_label = "NetSurf Website"; +static const gchar *copyright = + "Copyright © 2003 - 2010 The NetSurf Developers"; + +static void launch_url (GtkAboutDialog *about_dialog, const gchar *url, + gpointer data) +{ + struct browser_window *bw = data; + browser_window_go(bw, url, 0, true); +} + +void nsgtk_about_dialog_init(GtkWindow *parent, struct browser_window *bw, + const char *version) +{ + gchar *licence_text; + gchar *licence_location = g_strconcat(res_dir_location, "licence", NULL); + + g_file_get_contents(licence_location, &licence_text, NULL, NULL); + free(licence_location); + gtk_about_dialog_set_url_hook (launch_url, (gpointer) bw, NULL); + + gtk_show_about_dialog(parent, "artists", artists, "authors", authors, + "comments", description,"copyright", copyright, + "documenters", documenters, "license", licence_text, + "program-name", name, "translator-credits", translators, + "version", version, "website", url, + "website-label", url_label, + "wrap-license", FALSE, NULL); +} + diff --git a/gtk/dialogs/about.h b/gtk/dialogs/about.h new file mode 100644 index 000000000..e34a7bff7 --- /dev/null +++ b/gtk/dialogs/about.h @@ -0,0 +1,26 @@ +/* + * Copyright 2008 Rob Kendrick + * + * 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 . + */ + +#ifndef NETSURF_GTK_ABOUT_H +#define NETSURF_GTK_ABOUT_H + +#include "desktop/browser.h" + +void nsgtk_about_dialog_init(GtkWindow *parent, struct browser_window *bw, const char *version); + +#endif diff --git a/gtk/dialogs/gtk_about.c b/gtk/dialogs/gtk_about.c deleted file mode 100644 index eb7417127..000000000 --- a/gtk/dialogs/gtk_about.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2008 Mike Lester - * - * 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 . - */ - -#include "gtk/gtk_gui.h" -#include "gtk/dialogs/gtk_about.h" -#include "desktop/browser.h" - -GtkAboutDialog* about_dialog; - -static const gchar *authors[] = { - "John-Mark Bell", "James Bursa", "Michael Drake", - "Rob Kendrick", "Adrian Lees", "Vincent Sanders", - "Daniel Silverstone", "Richard Wilson", - "\nContributors:", "Kevin Bagust", "Stefaan Claes", - "Matthew Hambley", "Rob Jackson", "Jeffrey Lee", "Phil Mellor", - "Philip Pemberton", "Darren Salt", "Andrew Timmins", - "John Tytgat", "Chris Williams", - "\nGoogle Summer of Code Contributors:", "Mark Benjamin", - "Adam Blokus", "Paul Blokus", "Sean Fox", - "Michael Lester", "Andrew Sidwell", "Bo Yang", NULL -}; - -static const gchar *translators = "Sebastian Barthel\nBruno D'Arcangeli\n" - "Gerard van Katwijk\nJérôme Mathevet\nSimon Voortman."; -static const gchar *artists[] = { - "Michael Drake", "\nContributors:", "Andrew Duffell", - "John Duffell", "Richard Hallas", "Phil Mellor", NULL -}; - -static const gchar *documenters[] = { - "John-Mark Bell", "James Bursa", "Michael Drake", - "Richard Wilson", "\nContributors:", "James Shaw", NULL -}; - -static const gchar *name = "NetSurf"; -static const gchar *description = - "Small as a mouse, fast as a cheetah, and available for free.\n" - "NetSurf is a portable web browser for RISC OS, AmigaOS, BeOS " - "and UNIX-like platforms."; -static const gchar *url = "http://www.netsurf-browser.org/"; -static const gchar *url_label = "NetSurf Website"; -static const gchar *copyright = - "Copyright © 2003 - 2010 The NetSurf Developers"; - -static void launch_url (GtkAboutDialog *about_dialog, const gchar *url, - gpointer data) -{ - struct browser_window *bw = data; - browser_window_go(bw, url, 0, true); -} - -void nsgtk_about_dialog_init(GtkWindow *parent, struct browser_window *bw, - const char *version) -{ - gchar *licence_text; - gchar *licence_location = g_strconcat(res_dir_location, "licence", NULL); - - g_file_get_contents(licence_location, &licence_text, NULL, NULL); - free(licence_location); - gtk_about_dialog_set_url_hook (launch_url, (gpointer) bw, NULL); - - gtk_show_about_dialog(parent, "artists", artists, "authors", authors, - "comments", description,"copyright", copyright, - "documenters", documenters, "license", licence_text, - "program-name", name, "translator-credits", translators, - "version", version, "website", url, - "website-label", url_label, - "wrap-license", FALSE, NULL); -} - diff --git a/gtk/dialogs/gtk_about.h b/gtk/dialogs/gtk_about.h deleted file mode 100644 index e34a7bff7..000000000 --- a/gtk/dialogs/gtk_about.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2008 Rob Kendrick - * - * 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 . - */ - -#ifndef NETSURF_GTK_ABOUT_H -#define NETSURF_GTK_ABOUT_H - -#include "desktop/browser.h" - -void nsgtk_about_dialog_init(GtkWindow *parent, struct browser_window *bw, const char *version); - -#endif diff --git a/gtk/dialogs/gtk_options.c b/gtk/dialogs/gtk_options.c deleted file mode 100644 index dae0c8581..000000000 --- a/gtk/dialogs/gtk_options.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2008 Mike Lester - * Copyright 2009 Daniel Silverstone - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "desktop/options.h" -#include "desktop/print.h" -#include "desktop/searchweb.h" -#include "gtk/options.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_theme.h" -#include "gtk/dialogs/gtk_options.h" -#include "gtk/gtk_window.h" -#include "utils/log.h" -#include "utils/utils.h" -#include "utils/messages.h" - -GtkDialog *wndPreferences = NULL; -static GladeXML *gladeFile; - -static struct browser_window *current_browser; - -static int proxy_type; -static float animation_delay; - -static void dialog_response_handler (GtkDialog *dlg, gint res_id); -static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive); -static void nsgtk_options_theme_combo(void); - -/* Declares both widget and callback */ -#define DECLARE(x) \ - static GtkWidget *x; \ - static gboolean on_##x##_changed(GtkWidget *widget, gpointer data) - -DECLARE(entryHomePageURL); -DECLARE(setCurrentPage); -DECLARE(setDefaultPage); -DECLARE(checkHideAdverts); -DECLARE(checkDisablePopups); -DECLARE(checkDisablePlugins); -DECLARE(spinHistoryAge); -DECLARE(checkHoverURLs); -DECLARE(checkDisplayRecentURLs); -DECLARE(comboLanguage); -DECLARE(checkSendReferer); -DECLARE(checkShowSingleTab); - -DECLARE(comboProxyType); -DECLARE(entryProxyHost); -DECLARE(entryProxyPort); -DECLARE(entryProxyUser); -DECLARE(entryProxyPassword); -DECLARE(spinMaxFetchers); -DECLARE(spinFetchesPerHost); -DECLARE(spinCachedConnections); - -DECLARE(checkResampleImages); -DECLARE(spinAnimationSpeed); -DECLARE(checkDisableAnimations); - -DECLARE(fontSansSerif); -DECLARE(fontSerif); -DECLARE(fontMonospace); -DECLARE(fontCursive); -DECLARE(fontFantasy); -DECLARE(comboDefault); -DECLARE(spinDefaultSize); -DECLARE(spinMinimumSize); -DECLARE(fontPreview); - -DECLARE(comboButtonType); - -DECLARE(spinMemoryCacheSize); -DECLARE(spinDiscCacheAge); - -DECLARE(checkClearDownloads); -DECLARE(checkRequestOverwrite); -DECLARE(fileChooserDownloads); -DECLARE(checkFocusNew); -DECLARE(checkNewBlank); -DECLARE(checkUrlSearch); -DECLARE(comboSearch); -DECLARE(combotheme); -DECLARE(buttonaddtheme); -DECLARE(sourceButtonTab); -static GtkWidget *sourceButtonWindow; - -DECLARE(spinMarginTop); -DECLARE(spinMarginBottom); -DECLARE(spinMarginLeft); -DECLARE(spinMarginRight); -DECLARE(spinExportScale); -DECLARE(checkSuppressImages); -DECLARE(checkRemoveBackgrounds); -DECLARE(checkFitPage); -DECLARE(checkCompressPDF); -DECLARE(checkPasswordPDF); -DECLARE(setDefaultExportOptions); - -/* Used when the feature is not implemented yet */ -#define FIND_WIDGET(wname) \ - do { \ - (wname) = glade_xml_get_widget(gladeFile, #wname); \ - if ((wname) == NULL) \ - LOG(("Unable to find widget '%s'!", #wname)); \ - } while (0) - -/* Assigns widget and connects it to its callback function */ -#define CONNECT(wname, event) \ - g_signal_connect(G_OBJECT(wname), event, \ - G_CALLBACK(on_##wname##_changed), NULL) - -GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent) -{ - gladeFile = glade_xml_new(glade_options_file_location, NULL, NULL); - if (gladeFile == NULL) - return NULL; - - current_browser = bw; - wndPreferences = GTK_DIALOG(glade_xml_get_widget(gladeFile, - "dlgPreferences")); - gtk_window_set_transient_for (GTK_WINDOW(wndPreferences), parent); - - FIND_WIDGET(sourceButtonTab); - FIND_WIDGET(sourceButtonWindow); - GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON( - sourceButtonWindow)); - gtk_radio_button_set_group(GTK_RADIO_BUTTON(sourceButtonTab), group); - - /* set the widgets to reflect the current options */ - nsgtk_options_load(); - - /* Connect all widgets to their appropriate callbacks */ - CONNECT(entryHomePageURL, "focus-out-event"); - CONNECT(setCurrentPage, "clicked"); - CONNECT(setDefaultPage, "clicked"); - CONNECT(checkHideAdverts, "toggled"); - - CONNECT(checkDisablePopups, "toggled"); - CONNECT(checkDisablePlugins, "toggled"); - CONNECT(spinHistoryAge, "focus-out-event"); - CONNECT(checkHoverURLs, "toggled"); - - CONNECT(comboLanguage, "changed"); - - CONNECT(checkDisplayRecentURLs, "toggled"); - CONNECT(checkSendReferer, "toggled"); - CONNECT(checkShowSingleTab, "toggled"); - - CONNECT(comboProxyType, "changed"); - CONNECT(entryProxyHost, "focus-out-event"); - CONNECT(entryProxyPort, "focus-out-event"); - CONNECT(entryProxyUser, "focus-out-event"); - CONNECT(entryProxyPassword, "focus-out-event"); - CONNECT(spinMaxFetchers, "value-changed"); - CONNECT(spinFetchesPerHost, "value-changed"); - CONNECT(spinCachedConnections, "value-changed"); - - CONNECT(checkResampleImages, "toggled"); - CONNECT(spinAnimationSpeed, "value-changed"); - CONNECT(checkDisableAnimations, "toggled"); - - CONNECT(fontSansSerif, "font-set"); - CONNECT(fontSerif, "font-set"); - CONNECT(fontMonospace, "font-set"); - CONNECT(fontCursive, "font-set"); - CONNECT(fontFantasy, "font-set"); - CONNECT(comboDefault, "changed"); - CONNECT(spinDefaultSize, "value-changed"); - CONNECT(spinMinimumSize, "value-changed"); - CONNECT(fontPreview, "clicked"); - - CONNECT(comboButtonType, "changed"); - - CONNECT(spinMemoryCacheSize, "value-changed"); - CONNECT(spinDiscCacheAge, "value-changed"); - - CONNECT(checkClearDownloads, "toggled"); - CONNECT(checkRequestOverwrite, "toggled"); - CONNECT(fileChooserDownloads, "current-folder-changed"); - - CONNECT(checkFocusNew, "toggled"); - CONNECT(checkNewBlank, "toggled"); - CONNECT(checkUrlSearch, "toggled"); - CONNECT(comboSearch, "changed"); - - CONNECT(combotheme, "changed"); - CONNECT(buttonaddtheme, "clicked"); - CONNECT(sourceButtonTab, "toggled"); - - CONNECT(spinMarginTop, "value-changed"); - CONNECT(spinMarginBottom, "value-changed"); - CONNECT(spinMarginLeft, "value-changed"); - CONNECT(spinMarginRight, "value-changed"); - CONNECT(spinExportScale, "value-changed"); - CONNECT(checkSuppressImages, "toggled"); - CONNECT(checkRemoveBackgrounds, "toggled"); - CONNECT(checkFitPage, "toggled"); - CONNECT(checkCompressPDF, "toggled"); - CONNECT(checkPasswordPDF, "toggled"); - CONNECT(setDefaultExportOptions, "clicked"); - - g_signal_connect(G_OBJECT(wndPreferences), "response", - G_CALLBACK (dialog_response_handler), NULL); - - g_signal_connect(G_OBJECT(wndPreferences), "delete-event", - G_CALLBACK (on_dialog_close), (gpointer)TRUE); - - g_signal_connect(G_OBJECT(wndPreferences), "destroy", - G_CALLBACK (on_dialog_close), (gpointer)FALSE); - - gtk_widget_show(GTK_WIDGET(wndPreferences)); - - return wndPreferences; -} - -#define SET_ENTRY(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_entry_set_text(GTK_ENTRY((widget)), (value)); \ - } while (0) - -#define SET_SPIN(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_spin_button_set_value(GTK_SPIN_BUTTON((widget)), (value)); \ - } while (0) - -#define SET_CHECK(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON((widget)), \ - (value)); \ - } while (0) - -#define SET_COMBO(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_combo_box_set_active(GTK_COMBO_BOX((widget)), (value)); \ - } while (0) - -#define SET_FONT(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_font_button_set_font_name(GTK_FONT_BUTTON((widget)), \ - (value)); \ - } while (0) - -#define SET_FILE_CHOOSER(widget, value) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(\ - (widget)), (value)); \ - } while (0) - -#define SET_BUTTON(widget) \ - do { \ - (widget) = glade_xml_get_widget(gladeFile, #widget); \ - } while (0) - - -void nsgtk_options_load(void) -{ - GtkBox *box; - const char *default_accept_language = - option_accept_language ? option_accept_language : "en"; - int combo_row_count = 0; - int active_language = 0; - int proxytype = 0; - FILE *fp; - char buf[50]; - - /* Create combobox */ - box = GTK_BOX(glade_xml_get_widget(gladeFile, "combolanguagevbox")); - comboLanguage = gtk_combo_box_new_text(); - - /* Populate combobox from languages file */ - if ((languages_file_location != NULL) && - ((fp = fopen(languages_file_location, "r")) != NULL)) { - LOG(("Used %s for languages", languages_file_location)); - while (fgets(buf, sizeof(buf), fp)) { - /* Ignore blank lines */ - if (buf[0] == '\0') - continue; - - /* Remove trailing \n */ - buf[strlen(buf) - 1] = '\0'; - - gtk_combo_box_append_text(GTK_COMBO_BOX(comboLanguage), buf); - - if (strcmp(buf, default_accept_language) == 0) - active_language = combo_row_count; - - combo_row_count++; - } - - fclose(fp); - } else { - LOG(("Failed opening languages file")); - warn_user("FileError", languages_file_location); - gtk_combo_box_append_text(GTK_COMBO_BOX(comboLanguage), "en"); - } - - - gtk_combo_box_set_active(GTK_COMBO_BOX(comboLanguage), active_language); - /** \todo localisation */ - gtk_widget_set_tooltip_text(GTK_WIDGET(comboLanguage), - "set preferred language for web pages"); - gtk_box_pack_start(box, comboLanguage, FALSE, FALSE, 0); - gtk_widget_show(comboLanguage); - - nsgtk_options_theme_combo(); - - SET_ENTRY(entryHomePageURL, - option_homepage_url ? option_homepage_url : ""); - SET_BUTTON(setCurrentPage); - SET_BUTTON(setDefaultPage); - SET_CHECK(checkHideAdverts, option_block_ads); - - SET_CHECK(checkDisablePopups, option_disable_popups); - SET_CHECK(checkDisablePlugins, option_disable_plugins); - SET_SPIN(spinHistoryAge, option_history_age); - SET_CHECK(checkHoverURLs, option_hover_urls); - - SET_CHECK(checkDisplayRecentURLs, option_url_suggestion); - SET_CHECK(checkSendReferer, option_send_referer); - SET_CHECK(checkShowSingleTab, option_show_single_tab); - - if (option_http_proxy == false) - proxytype = 0; - else - proxytype = option_http_proxy_auth + 1; - - SET_COMBO(comboProxyType, proxytype); - SET_ENTRY(entryProxyHost, - option_http_proxy_host ? option_http_proxy_host : ""); - gtk_widget_set_sensitive(entryProxyHost, proxytype != 0); - - snprintf(buf, sizeof(buf), "%d", option_http_proxy_port); - - SET_ENTRY(entryProxyPort, buf); - gtk_widget_set_sensitive(entryProxyPort, proxytype != 0); - - SET_ENTRY(entryProxyUser, option_http_proxy_auth_user ? - option_http_proxy_auth_user : ""); - gtk_widget_set_sensitive(entryProxyUser, proxytype != 0); - - SET_ENTRY(entryProxyPassword, option_http_proxy_auth_pass ? - option_http_proxy_auth_pass : ""); - gtk_widget_set_sensitive(entryProxyPassword, proxytype != 0); - - SET_SPIN(spinMaxFetchers, option_max_fetchers); - SET_SPIN(spinFetchesPerHost, option_max_fetchers_per_host); - SET_SPIN(spinCachedConnections, option_max_cached_fetch_handles); - - SET_CHECK(checkResampleImages, option_render_resample); - SET_SPIN(spinAnimationSpeed, option_minimum_gif_delay / 100.0); - SET_CHECK(checkDisableAnimations, !option_animate_images); - - SET_FONT(fontSansSerif, option_font_sans); - SET_FONT(fontSerif, option_font_serif); - SET_FONT(fontMonospace, option_font_mono); - SET_FONT(fontCursive, option_font_cursive); - SET_FONT(fontFantasy, option_font_fantasy); - SET_COMBO(comboDefault, option_font_default); - SET_SPIN(spinDefaultSize, option_font_size / 10); - SET_SPIN(spinMinimumSize, option_font_min_size / 10); - SET_BUTTON(fontPreview); - - SET_COMBO(comboButtonType, option_button_type -1); - - SET_SPIN(spinMemoryCacheSize, option_memory_cache_size >> 20); - SET_SPIN(spinDiscCacheAge, option_disc_cache_age); - - SET_CHECK(checkClearDownloads, option_downloads_clear); - SET_CHECK(checkRequestOverwrite, option_request_overwrite); - SET_FILE_CHOOSER(fileChooserDownloads, option_downloads_directory); - - SET_CHECK(checkFocusNew, option_focus_new); - SET_CHECK(checkNewBlank, option_new_blank); - SET_CHECK(checkUrlSearch, option_search_url_bar); - SET_COMBO(comboSearch, option_search_provider); - - SET_BUTTON(buttonaddtheme); - SET_CHECK(sourceButtonTab, option_source_tab); - - SET_SPIN(spinMarginTop, option_margin_top); - SET_SPIN(spinMarginBottom, option_margin_bottom); - SET_SPIN(spinMarginLeft, option_margin_left); - SET_SPIN(spinMarginRight, option_margin_right); - SET_SPIN(spinExportScale, option_export_scale); - SET_CHECK(checkSuppressImages, option_suppress_images); - SET_CHECK(checkRemoveBackgrounds, option_remove_backgrounds); - SET_CHECK(checkFitPage, option_enable_loosening); - SET_CHECK(checkCompressPDF, option_enable_PDF_compression); - SET_CHECK(checkPasswordPDF, option_enable_PDF_password); - SET_BUTTON(setDefaultExportOptions); -} - -static void dialog_response_handler (GtkDialog *dlg, gint res_id) -{ - switch (res_id) { - case GTK_RESPONSE_HELP: - /* Ready to implement Help */ - break; - - case GTK_RESPONSE_CLOSE: - on_dialog_close(dlg, TRUE); - } -} - -static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive) -{ - LOG(("Writing options to file")); - options_write(options_file_location); - if ((stay_alive) && GTK_IS_WIDGET(dlg)) - gtk_widget_hide(GTK_WIDGET(dlg)); - else { - stay_alive = FALSE; - } - return stay_alive; -} - -static void nsgtk_options_theme_combo(void) { -/* populate theme combo from themelist file */ - GtkBox *box = GTK_BOX(glade_xml_get_widget(gladeFile, "themehbox")); - char buf[50]; - combotheme = gtk_combo_box_new_text(); - size_t len = SLEN("themelist") + strlen(res_dir_location) + 1; - char themefile[len]; - if ((combotheme == NULL) || (box == NULL)) { - warn_user(messages_get("NoMemory"), 0); - return; - } - snprintf(themefile, len, "%sthemelist", res_dir_location); - FILE *fp = fopen((const char *)themefile, "r"); - if (fp == NULL) { - LOG(("Failed opening themes file")); - warn_user("FileError", (const char *) themefile); - return; - } - while (fgets(buf, sizeof(buf), fp) != NULL) { - /* Ignore blank lines */ - if (buf[0] == '\0') - continue; - - /* Remove trailing \n */ - buf[strlen(buf) - 1] = '\0'; - - gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), buf); - } - fclose(fp); - gtk_combo_box_set_active(GTK_COMBO_BOX(combotheme), - option_current_theme); - gtk_box_pack_start(box, combotheme, FALSE, TRUE, 0); - gtk_widget_show(combotheme); -} - -bool nsgtk_options_combo_theme_add(const char *themename) -{ - if (wndPreferences == NULL) - return false; - gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), themename); - return true; -} - - -/* Defines the callback functions for all widgets and specifies - * nsgtk_reflow_all_windows only where necessary */ - -#define ENTRY_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - if (!g_str_equal(gtk_entry_get_text(GTK_ENTRY((widget))), (option) ? (option) : "")) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - if ((option)) \ - free((option)); \ - (option) = strdup(gtk_entry_get_text(GTK_ENTRY((widget)))); \ - } \ - do { \ - -#define CHECK_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - (option) = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((widget))); \ - do { \ - -#define SPIN_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - (option) = gtk_spin_button_get_value(GTK_SPIN_BUTTON((widget))); \ - do { \ - -#define COMBO_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - (option) = gtk_combo_box_get_active(GTK_COMBO_BOX((widget))); \ - do { - -#define FONT_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - if ((option)) \ - free((option)); \ - (option) = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON((widget)))); \ - do { - -#define FILE_CHOOSER_CHANGED(widget, option) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - (option) = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER((widget))); \ - do { - -#define BUTTON_CLICKED(widget) \ - static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ - LOG(("Signal emitted on '%s'", #widget)); \ - do { - -#define END_HANDLER \ - } while (0); \ - return FALSE; \ - } - -static gboolean on_comboLanguage_changed(GtkWidget *widget, gpointer data) -{ - char *old_lang = option_accept_language; - gchar *lang = - gtk_combo_box_get_active_text(GTK_COMBO_BOX(comboLanguage)); - if (lang == NULL) - return FALSE; - - option_accept_language = strdup((const char *) lang); - if (option_accept_language == NULL) - option_accept_language = old_lang; - else - free(old_lang); - - g_free(lang); - - return FALSE; -} - -ENTRY_CHANGED(entryHomePageURL, option_homepage_url) -END_HANDLER - -BUTTON_CLICKED(setCurrentPage) - const gchar *url = content_get_url(current_browser->current_content); - gtk_entry_set_text(GTK_ENTRY(entryHomePageURL), url); - option_homepage_url = - strdup(gtk_entry_get_text(GTK_ENTRY(entryHomePageURL))); -END_HANDLER - -BUTTON_CLICKED(setDefaultPage) - gtk_entry_set_text(GTK_ENTRY(entryHomePageURL), - "http://www.netsurf-browser.org/welcome/"); - option_homepage_url = - strdup(gtk_entry_get_text(GTK_ENTRY(entryHomePageURL))); -END_HANDLER - -CHECK_CHANGED(checkHideAdverts, option_block_ads) -END_HANDLER - -CHECK_CHANGED(checkDisplayRecentURLs, option_url_suggestion) -END_HANDLER - -CHECK_CHANGED(checkSendReferer, option_send_referer) -END_HANDLER - -CHECK_CHANGED(checkShowSingleTab, option_show_single_tab) - nsgtk_reflow_all_windows(); -END_HANDLER - -COMBO_CHANGED(comboProxyType, proxy_type) - LOG(("proxy type: %d", proxy_type)); - switch (proxy_type) - { - case 0: - option_http_proxy = false; - option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; - break; - case 1: - option_http_proxy = true; - option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; - break; - case 2: - option_http_proxy = true; - option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_BASIC; - break; - case 3: - option_http_proxy = true; - option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NTLM; - break; - } - gboolean sensitive = (!proxy_type == 0); - gtk_widget_set_sensitive (entryProxyHost, sensitive); - gtk_widget_set_sensitive (entryProxyPort, sensitive); - gtk_widget_set_sensitive (entryProxyUser, sensitive); - gtk_widget_set_sensitive (entryProxyPassword, sensitive); - -END_HANDLER - -ENTRY_CHANGED(entryProxyHost, option_http_proxy_host) -END_HANDLER - -gboolean on_entryProxyPort_changed(GtkWidget *widget, gpointer data) -{ - long port; - - errno = 0; - port = strtol((char *)gtk_entry_get_text(GTK_ENTRY(entryProxyPort)), - NULL, 10) & 0xffff; - if (port != 0 && errno == 0) { - option_http_proxy_port = port; - } else { - char buf[32]; - snprintf(buf, sizeof(buf), "%d", option_http_proxy_port); - SET_ENTRY(entryProxyPort, buf); - } - - return FALSE; -} - -ENTRY_CHANGED(entryProxyUser, option_http_proxy_auth_user) -END_HANDLER - -ENTRY_CHANGED(entryProxyPassword, option_http_proxy_auth_pass) -END_HANDLER - -SPIN_CHANGED(spinMaxFetchers, option_max_fetchers) -END_HANDLER - -SPIN_CHANGED(spinFetchesPerHost, option_max_fetchers_per_host) -END_HANDLER - -SPIN_CHANGED(spinCachedConnections, option_max_cached_fetch_handles) -END_HANDLER - -CHECK_CHANGED(checkResampleImages, option_render_resample) -END_HANDLER - -SPIN_CHANGED(spinAnimationSpeed, animation_delay) - option_minimum_gif_delay = round(animation_delay * 100.0); -END_HANDLER - -CHECK_CHANGED(checkDisableAnimations, option_animate_images); - option_animate_images = !option_animate_images; -END_HANDLER - -CHECK_CHANGED(checkDisablePopups, option_disable_popups) -END_HANDLER - -CHECK_CHANGED(checkDisablePlugins, option_disable_plugins) -END_HANDLER - -SPIN_CHANGED(spinHistoryAge, option_history_age) -END_HANDLER - -CHECK_CHANGED(checkHoverURLs, option_hover_urls) -END_HANDLER - -FONT_CHANGED(fontSansSerif, option_font_sans) -END_HANDLER - -FONT_CHANGED(fontSerif, option_font_serif) -END_HANDLER - -FONT_CHANGED(fontMonospace, option_font_mono) -END_HANDLER - -FONT_CHANGED(fontCursive, option_font_cursive) -END_HANDLER - -FONT_CHANGED(fontFantasy, option_font_fantasy) -END_HANDLER - -COMBO_CHANGED(comboDefault, option_font_default) -END_HANDLER - -SPIN_CHANGED(spinDefaultSize, option_font_size) - option_font_size *= 10; -END_HANDLER - -SPIN_CHANGED(spinMinimumSize, option_font_min_size) - option_font_min_size *= 10; -END_HANDLER - -BUTTON_CLICKED(fontPreview) - nsgtk_reflow_all_windows(); -END_HANDLER - -COMBO_CHANGED(comboButtonType, option_button_type) - nsgtk_scaffolding *current = scaf_list; - option_button_type++; - /* value of 0 is reserved for 'unset' */ - while (current) { - nsgtk_scaffolding_reset_offset(current); - switch(option_button_type) { - case 1: - gtk_toolbar_set_style( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_ICON_SIZE_SMALL_TOOLBAR); - break; - case 2: - gtk_toolbar_set_style( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_TOOLBAR_ICONS); - gtk_toolbar_set_icon_size( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_ICON_SIZE_LARGE_TOOLBAR); - break; - case 3: - gtk_toolbar_set_style( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_ICON_SIZE_LARGE_TOOLBAR); - break; - case 4: - gtk_toolbar_set_style( - GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), - GTK_TOOLBAR_TEXT); - default: - break; - } - current = nsgtk_scaffolding_iterate(current); - } -END_HANDLER - -SPIN_CHANGED(spinMemoryCacheSize, option_memory_cache_size) - option_memory_cache_size <<= 20; -END_HANDLER - -SPIN_CHANGED(spinDiscCacheAge, option_disc_cache_age) -END_HANDLER - -CHECK_CHANGED(checkClearDownloads, option_downloads_clear) -END_HANDLER - -CHECK_CHANGED(checkRequestOverwrite, option_request_overwrite) -END_HANDLER - -FILE_CHOOSER_CHANGED(fileChooserDownloads, option_downloads_directory) -END_HANDLER - -CHECK_CHANGED(checkFocusNew, option_focus_new) -END_HANDLER - -CHECK_CHANGED(checkNewBlank, option_new_blank) -END_HANDLER - -CHECK_CHANGED(checkUrlSearch, option_search_url_bar) -END_HANDLER - -COMBO_CHANGED(comboSearch, option_search_provider) - nsgtk_scaffolding *current = scaf_list; - char *name; - /* refresh web search prefs from file */ - search_web_provider_details(option_search_provider); - /* retrieve ico */ - search_web_retrieve_ico(false); - /* callback may handle changing gui */ - if (search_web_ico() != NULL) - gui_window_set_search_ico(search_web_ico()); - /* set entry */ - name = search_web_provider_name(); - if (name == NULL) { - warn_user(messages_get("NoMemory"), 0); - continue; - } - char content[strlen(name) + SLEN("Search ") + 1]; - sprintf(content, "Search %s", name); - free(name); - while (current) { - nsgtk_scaffolding_set_websearch(current, content); - current = nsgtk_scaffolding_iterate(current); - } -END_HANDLER - -COMBO_CHANGED(combotheme, option_current_theme) - nsgtk_scaffolding *current = scaf_list; - char *name; - if (option_current_theme != 0) { - if (nsgtk_theme_name() != NULL) - free(nsgtk_theme_name()); - name = strdup(gtk_combo_box_get_active_text( - GTK_COMBO_BOX(combotheme))); - if (name == NULL) { - warn_user(messages_get("NoMemory"), 0); - continue; - } - nsgtk_theme_set_name(name); - nsgtk_theme_prepare(); - } else if (nsgtk_theme_name() != NULL) { - free(nsgtk_theme_name()); - nsgtk_theme_set_name(NULL); - } - while (current) { - nsgtk_theme_implement(current); - current = nsgtk_scaffolding_iterate(current); - } -END_HANDLER - -BUTTON_CLICKED(buttonaddtheme) - char *filename, *directory; - size_t len; - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkAddThemeTitle"), - GTK_WINDOW(wndPreferences), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); - len = SLEN("themes") + strlen(res_dir_location) + 1; - char themesfolder[len]; - snprintf(themesfolder, len, "%sthemes", res_dir_location); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), - themesfolder); - gint res = gtk_dialog_run(GTK_DIALOG(fc)); - if (res == GTK_RESPONSE_ACCEPT) { - filename = gtk_file_chooser_get_current_folder( - GTK_FILE_CHOOSER(fc)); - if (strcmp(filename, themesfolder) != 0) { - directory = strrchr(filename, '/'); - *directory = '\0'; - if (strcmp(filename, themesfolder) != 0) { - warn_user(messages_get( - "gtkThemeFolderInstructions"), - 0); - gtk_widget_destroy(GTK_WIDGET(fc)); - if (filename != NULL) - free(filename); - return FALSE; - } else { - directory++; - } - } else { - if (filename != NULL) - free(filename); - filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(fc)); - if (strcmp(filename, themesfolder) == 0) { - warn_user(messages_get("gtkThemeFolderSub"), - 0); - gtk_widget_destroy(GTK_WIDGET(fc)); - free(filename); - return FALSE; - } - directory = strrchr(filename, '/') + 1; - } - gtk_widget_destroy(GTK_WIDGET(fc)); - nsgtk_theme_add(directory); - if (filename != NULL) - free(filename); - } - -END_HANDLER - -CHECK_CHANGED(sourceButtonTab, option_source_tab) -END_HANDLER - -SPIN_CHANGED(spinMarginTop, option_margin_top) -END_HANDLER - -SPIN_CHANGED(spinMarginBottom, option_margin_bottom) -END_HANDLER - -SPIN_CHANGED(spinMarginLeft, option_margin_left) -END_HANDLER - -SPIN_CHANGED(spinMarginRight, option_margin_right) -END_HANDLER - -SPIN_CHANGED(spinExportScale, option_export_scale) -END_HANDLER - -CHECK_CHANGED(checkSuppressImages, option_suppress_images) -END_HANDLER - -CHECK_CHANGED(checkRemoveBackgrounds, option_remove_backgrounds) -END_HANDLER - -CHECK_CHANGED(checkFitPage, option_enable_loosening) -END_HANDLER - -CHECK_CHANGED(checkCompressPDF, option_enable_PDF_compression) -END_HANDLER - -CHECK_CHANGED(checkPasswordPDF, option_enable_PDF_password) -END_HANDLER - -BUTTON_CLICKED(setDefaultExportOptions) - option_margin_top = DEFAULT_MARGIN_TOP_MM; - option_margin_bottom = DEFAULT_MARGIN_BOTTOM_MM; - option_margin_left = DEFAULT_MARGIN_LEFT_MM; - option_margin_right = DEFAULT_MARGIN_RIGHT_MM; - option_export_scale = DEFAULT_EXPORT_SCALE * 100; - option_suppress_images = false; - option_remove_backgrounds = false; - option_enable_loosening = true; - option_enable_PDF_compression = true; - option_enable_PDF_password = false; - - SET_SPIN(spinMarginTop, option_margin_top); - SET_SPIN(spinMarginBottom, option_margin_bottom); - SET_SPIN(spinMarginLeft, option_margin_left); - SET_SPIN(spinMarginRight, option_margin_right); - SET_SPIN(spinExportScale, option_export_scale); - SET_CHECK(checkSuppressImages, option_suppress_images); - SET_CHECK(checkRemoveBackgrounds, option_remove_backgrounds); - SET_CHECK(checkCompressPDF, option_enable_PDF_compression); - SET_CHECK(checkPasswordPDF, option_enable_PDF_password); - SET_CHECK(checkFitPage, option_enable_loosening); -END_HANDLER diff --git a/gtk/dialogs/gtk_options.h b/gtk/dialogs/gtk_options.h deleted file mode 100644 index 9f6602593..000000000 --- a/gtk/dialogs/gtk_options.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#ifndef NETSURF_GTK_OPTIONS_H -#define NETSURF_GTK_OPTIONS_H - -#include - -extern GtkDialog *wndPreferences; - -GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent); - /** Init options and load window */ -void nsgtk_options_load(void); /** Load current options into window */ -void nsgtk_options_save(void); /** Save options from window */ -bool nsgtk_options_combo_theme_add(const char *themename); - /** add new theme name to combo */ - -#endif diff --git a/gtk/dialogs/gtk_source.c b/gtk/dialogs/gtk_source.c deleted file mode 100644 index b7dec945b..000000000 --- a/gtk/dialogs/gtk_source.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include "gtk/dialogs/gtk_source.h" -#include "gtk/dialogs/gtk_about.h" -#include "gtk/gtk_window.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_print.h" -#include "gtk/gtk_selection.h" -#include "gtk/options.h" -#include "desktop/netsurf.h" -#include "desktop/print.h" -#include "desktop/options.h" -#include "utils/messages.h" -#include "utils/url.h" -#include "utils/utils.h" -#include "utils/utf8.h" -#include "render/font.h" -#include "content/content.h" -#include "content/content_type.h" -#include "render/textplain.h" - -#include "utils/log.h" - -struct nsgtk_source_window { - gchar *url; - char *data; - GtkWindow *sourcewindow; - GtkTextView *gv; - struct browser_window *bw; - struct nsgtk_source_window *next; - struct nsgtk_source_window *prev; -}; - -struct menu_events { - const char *widget; - GCallback handler; -}; - -static GladeXML *glade_File; -static struct nsgtk_source_window *nsgtk_source_list = 0; -static char source_zoomlevel = 10; - -void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw); -static void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g); -static gboolean nsgtk_source_delete_event(GtkWindow *window, gpointer g); -static gboolean nsgtk_source_destroy_event(GtkWindow *window, gpointer g); -static void nsgtk_source_update_zoomlevel(gpointer g); -static void nsgtk_source_file_save(GtkWindow *parent, const char *filename, - const char *data); - -#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } -#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ - GtkMenuItem *widget, gpointer g) - -MENUPROTO(source_save_as); -MENUPROTO(source_print); -MENUPROTO(source_close); -MENUPROTO(source_select_all); -MENUPROTO(source_cut); -MENUPROTO(source_copy); -MENUPROTO(source_paste); -MENUPROTO(source_delete); -MENUPROTO(source_zoom_in); -MENUPROTO(source_zoom_out); -MENUPROTO(source_zoom_normal); -MENUPROTO(source_about); - -struct menu_events source_menu_events[] = { -MENUEVENT(source_save_as), -MENUEVENT(source_print), -MENUEVENT(source_close), -MENUEVENT(source_select_all), -MENUEVENT(source_cut), -MENUEVENT(source_copy), -MENUEVENT(source_paste), -MENUEVENT(source_delete), -MENUEVENT(source_zoom_in), -MENUEVENT(source_zoom_out), -MENUEVENT(source_zoom_normal), -MENUEVENT(source_about), -{NULL, NULL} -}; - -void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw) -{ - char glade_Location[strlen(res_dir_location) + SLEN("source.glade") - + 1]; - if (content_get_type(bw->current_content) != CONTENT_HTML) - return; - - if (option_source_tab) { - nsgtk_source_tab_init(parent, bw); - return; - } - - sprintf(glade_Location, "%ssource.glade", res_dir_location); - glade_File = glade_xml_new(glade_Location, NULL, NULL); - if (glade_File == NULL) { - LOG(("error loading glade tree")); - } - - const char *source_data; - unsigned long source_size; - char *data = NULL; - - source_data = content_get_source_data(bw->current_content, - &source_size); - - utf8_convert_ret r = utf8_from_enc( - source_data, - html_get_encoding(bw->current_content), - source_size, - &data); - if (r == UTF8_CONVERT_NOMEM) { - warn_user("NoMemory",0); - return; - } else if (r == UTF8_CONVERT_BADENC) { - warn_user("EncNotRec",0); - return; - } - - GtkWindow *wndSource = GTK_WINDOW(glade_xml_get_widget( - glade_File, "wndSource")); - GtkWidget *cutbutton = glade_xml_get_widget( - glade_File, "source_cut"); - GtkWidget *pastebutton = glade_xml_get_widget( - glade_File, "source_paste"); - GtkWidget *deletebutton = glade_xml_get_widget( - glade_File, "source_delete"); - GtkWidget *printbutton = glade_xml_get_widget( - glade_File, "source_print"); - gtk_widget_set_sensitive(cutbutton, FALSE); - gtk_widget_set_sensitive(pastebutton, FALSE); - gtk_widget_set_sensitive(deletebutton, FALSE); - /* for now */ - gtk_widget_set_sensitive(printbutton, FALSE); - - struct nsgtk_source_window *thiswindow = - malloc(sizeof(struct nsgtk_source_window)); - if (thiswindow == NULL) { - free(data); - warn_user("NoMemory", 0); - return; - } - - thiswindow->url = strdup(content_get_url(bw->current_content)); - if (thiswindow->url == NULL) { - free(thiswindow); - free(data); - warn_user("NoMemory", 0); - return; - } - - thiswindow->data = data; - - thiswindow->sourcewindow = wndSource; - thiswindow->bw = bw; - - char title[strlen(thiswindow->url) + SLEN("Source of - NetSurf") + 1]; - sprintf(title, "Source of %s - NetSurf", thiswindow->url); - - thiswindow->next = nsgtk_source_list; - thiswindow->prev = NULL; - if (nsgtk_source_list != NULL) - nsgtk_source_list->prev = thiswindow; - nsgtk_source_list = thiswindow; - - nsgtk_attach_source_menu_handlers(glade_File, thiswindow); - - gtk_window_set_title(wndSource, title); - - g_signal_connect(G_OBJECT(wndSource), "destroy", - G_CALLBACK(nsgtk_source_destroy_event), - thiswindow); - g_signal_connect(G_OBJECT(wndSource), "delete-event", - G_CALLBACK(nsgtk_source_delete_event), - thiswindow); - - GtkTextView *sourceview = GTK_TEXT_VIEW( - glade_xml_get_widget(glade_File, - "source_view")); - PangoFontDescription *fontdesc = - pango_font_description_from_string("Monospace 8"); - - thiswindow->gv = sourceview; - gtk_widget_modify_font(GTK_WIDGET(sourceview), fontdesc); - GtkTextBuffer *tb = gtk_text_view_get_buffer(sourceview); - gtk_text_buffer_set_text(tb, thiswindow->data, -1); - - gtk_widget_show(GTK_WIDGET(wndSource)); - -} -void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw) -{ - const char *source_data; - unsigned long source_size; - char *ndata = 0; - - source_data = content_get_source_data(bw->current_content, - &source_size); - - utf8_convert_ret r = utf8_from_enc( - source_data, - html_get_encoding(bw->current_content), - source_size, - &ndata); - if (r == UTF8_CONVERT_NOMEM) { - warn_user("NoMemory",0); - return; - } else if (r == UTF8_CONVERT_BADENC) { - warn_user("EncNotRec",0); - return; - } - gchar *filename; - char *fileurl; - gint handle = g_file_open_tmp("nsgtksourceXXXXXX", &filename, NULL); - if ((handle == -1) || (filename == NULL)) { - warn_user(messages_get("gtkSourceTabError"), 0); - return; - } - close (handle); /* in case it was binary mode */ - FILE *f = fopen(filename, "w"); - if (f == NULL) { - warn_user(messages_get("gtkSourceTabError"), 0); - g_free(filename); - return; - } - fprintf(f, "%s", ndata); - fclose(f); - free(ndata); - fileurl = path_to_url(filename); - g_free(filename); - if (fileurl == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; - } - /* Open tab */ - browser_window_create(fileurl, bw, NULL, false, true); - free(fileurl); -} - - -void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g) -{ - struct menu_events *event = source_menu_events; - - while (event->widget != NULL) - { - GtkWidget *w = glade_xml_get_widget(xml, event->widget); - g_signal_connect(G_OBJECT(w), "activate", event->handler, g); - event++; - } -} - -gboolean nsgtk_on_source_save_as_activate(GtkMenuItem *widget, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkSourceSave"), - nsg->sourcewindow, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, - GTK_RESPONSE_ACCEPT, - NULL); - char *filename; - url_func_result res; - - res = url_nice(nsg->url, &filename, false); - if (res != URL_FUNC_OK) { - filename = strdup(messages_get("SaveSource")); - if (filename == NULL) { - warn_user("NoMemory", 0); - return FALSE; - } - } - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), filename); - - free(filename); - - if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) { - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); - nsgtk_source_file_save(nsg->sourcewindow, filename, nsg->data); - g_free(filename); - } - - gtk_widget_destroy(fc); - - return TRUE; -} - -void nsgtk_source_file_save(GtkWindow *parent, const char *filename, - const char *data) -{ - FILE *f; - bool auth = true; - char temp[255]; - GtkWidget *notif, *label; - - if (!(access(filename, F_OK))) { - GtkWidget *confd = gtk_dialog_new_with_buttons( - messages_get("gtkOverwriteTitle"), - parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, - GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, - GTK_RESPONSE_REJECT, - NULL); - const char *format = messages_get("gtkOverwrite"); - int len = strlen(filename) + strlen(format) + SLEN("\n\n") + 1; - char warn[len]; - auth = false; - - warn[0] = '\n'; - snprintf(warn + 1, len - 2, format, filename); - len = strlen(warn); - warn[len - 1] = '\n'; - warn[len] = '\0'; - - label = gtk_label_new(warn); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(confd)->vbox), - label); - gtk_widget_show(label); - if (gtk_dialog_run(GTK_DIALOG(confd)) == GTK_RESPONSE_ACCEPT) { - auth = true; - } - gtk_widget_destroy(confd); - } - - if (auth) { - f = fopen(filename, "w+"); - fprintf(f, "%s", data); - fclose(f); - snprintf(temp, sizeof(temp), "\n %s" - " \n", - messages_get("gtkSaveConfirm")); - } else { - snprintf(temp, sizeof(temp), "\n %s" - " \n", - messages_get("gtkSaveCancelled")); - } - - notif = gtk_dialog_new_with_buttons(temp, - parent, GTK_DIALOG_MODAL, GTK_STOCK_OK, - GTK_RESPONSE_NONE, NULL); - g_signal_connect_swapped(notif, "response", - G_CALLBACK(gtk_widget_destroy), notif); - label = gtk_label_new(temp); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notif)->vbox), label); - gtk_widget_show_all(notif); -} - -gboolean nsgtk_on_source_print_activate( GtkMenuItem *widget, gpointer g) -{ - /* correct printing */ - - return TRUE; -} - -gboolean nsgtk_on_source_close_activate( GtkMenuItem *widget, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - - gtk_widget_destroy(GTK_WIDGET(nsg->sourcewindow)); - - return TRUE; -} - -gboolean nsgtk_source_delete_event(GtkWindow * window, gpointer g) -{ - return FALSE; -} - -gboolean nsgtk_source_destroy_event(GtkWindow * window, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - - if (nsg->next != NULL) - nsg->next->prev = nsg->prev; - - if (nsg->prev != NULL) - nsg->prev->next = nsg->next; - else - nsgtk_source_list = nsg->next; - - free(nsg->data); - free(nsg->url); - free(g); - - return FALSE; -} - -gboolean nsgtk_on_source_select_all_activate (GtkMenuItem *widget, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - GtkTextBuffer *buf = gtk_text_view_get_buffer(nsg->gv); - GtkTextIter start, end; - - gtk_text_buffer_get_bounds(buf, &start, &end); - - gtk_text_buffer_select_range(buf, &start, &end); - - return TRUE; -} - -gboolean nsgtk_on_source_cut_activate(GtkMenuItem *widget, gpointer g) -{ - return TRUE; -} - -gboolean nsgtk_on_source_copy_activate(GtkMenuItem *widget, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(nsg->gv)); - - gtk_text_buffer_copy_clipboard(buf, - gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); - - return TRUE; -} - -gboolean nsgtk_on_source_paste_activate(GtkMenuItem *widget, gpointer g) -{ - return TRUE; -} - -gboolean nsgtk_on_source_delete_activate(GtkMenuItem *widget, gpointer g) -{ - return TRUE; -} - -gboolean nsgtk_on_source_zoom_in_activate(GtkMenuItem *widget, gpointer g) -{ - source_zoomlevel++; - nsgtk_source_update_zoomlevel(g); - - return TRUE; -} - -gboolean nsgtk_on_source_zoom_out_activate(GtkMenuItem *widget, gpointer g) -{ - if (source_zoomlevel > 1) { - source_zoomlevel--; - nsgtk_source_update_zoomlevel(g); - } - - return TRUE; -} - -gboolean nsgtk_on_source_zoom_normal_activate(GtkMenuItem *widget, gpointer g) -{ - source_zoomlevel = 10; - nsgtk_source_update_zoomlevel(g); - - return TRUE; -} - -gboolean nsgtk_on_source_about_activate(GtkMenuItem *widget, gpointer g) -{ - struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; - - nsgtk_about_dialog_init(nsg->sourcewindow, nsg->bw, netsurf_version); - - return TRUE; -} - -void nsgtk_source_update_zoomlevel(gpointer g) -{ - struct nsgtk_source_window *nsg; - GtkTextBuffer *buf; - GtkTextTagTable *tab; - GtkTextTag *tag; - - nsg = nsgtk_source_list; - while (nsg) { - if (nsg->gv) { - buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(nsg->gv)); - - tab = gtk_text_buffer_get_tag_table( - GTK_TEXT_BUFFER(buf)); - - tag = gtk_text_tag_table_lookup(tab, "zoomlevel"); - if (!tag) { - tag = gtk_text_tag_new("zoomlevel"); - gtk_text_tag_table_add(tab, GTK_TEXT_TAG(tag)); - } - - gdouble fscale = ((gdouble) source_zoomlevel) / 10; - - g_object_set(GTK_TEXT_TAG(tag), "scale", fscale, NULL); - - GtkTextIter start, end; - - gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buf), - &start, &end); - gtk_text_buffer_remove_all_tags(GTK_TEXT_BUFFER(buf), - &start, &end); - gtk_text_buffer_apply_tag(GTK_TEXT_BUFFER(buf), - GTK_TEXT_TAG(tag), &start, &end); - } - nsg = nsg->next; - } -} diff --git a/gtk/dialogs/gtk_source.h b/gtk/dialogs/gtk_source.h deleted file mode 100644 index fcba6b664..000000000 --- a/gtk/dialogs/gtk_source.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#ifndef netsurf_gtk_dialogs_source_h_ -#define netsurf_gtk_dialogs_source_h_ - -#include -#include "desktop/browser.h" - -void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw); - -#endif - diff --git a/gtk/dialogs/options.c b/gtk/dialogs/options.c new file mode 100644 index 000000000..0587c3cae --- /dev/null +++ b/gtk/dialogs/options.c @@ -0,0 +1,940 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2008 Mike Lester + * Copyright 2009 Daniel Silverstone + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "desktop/options.h" +#include "desktop/print.h" +#include "desktop/searchweb.h" +#include "gtk/options.h" +#include "gtk/gui.h" +#include "gtk/scaffolding.h" +#include "gtk/theme.h" +#include "gtk/dialogs/options.h" +#include "gtk/window.h" +#include "utils/log.h" +#include "utils/utils.h" +#include "utils/messages.h" + +GtkDialog *wndPreferences = NULL; +static GladeXML *gladeFile; + +static struct browser_window *current_browser; + +static int proxy_type; +static float animation_delay; + +static void dialog_response_handler (GtkDialog *dlg, gint res_id); +static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive); +static void nsgtk_options_theme_combo(void); + +/* Declares both widget and callback */ +#define DECLARE(x) \ + static GtkWidget *x; \ + static gboolean on_##x##_changed(GtkWidget *widget, gpointer data) + +DECLARE(entryHomePageURL); +DECLARE(setCurrentPage); +DECLARE(setDefaultPage); +DECLARE(checkHideAdverts); +DECLARE(checkDisablePopups); +DECLARE(checkDisablePlugins); +DECLARE(spinHistoryAge); +DECLARE(checkHoverURLs); +DECLARE(checkDisplayRecentURLs); +DECLARE(comboLanguage); +DECLARE(checkSendReferer); +DECLARE(checkShowSingleTab); + +DECLARE(comboProxyType); +DECLARE(entryProxyHost); +DECLARE(entryProxyPort); +DECLARE(entryProxyUser); +DECLARE(entryProxyPassword); +DECLARE(spinMaxFetchers); +DECLARE(spinFetchesPerHost); +DECLARE(spinCachedConnections); + +DECLARE(checkResampleImages); +DECLARE(spinAnimationSpeed); +DECLARE(checkDisableAnimations); + +DECLARE(fontSansSerif); +DECLARE(fontSerif); +DECLARE(fontMonospace); +DECLARE(fontCursive); +DECLARE(fontFantasy); +DECLARE(comboDefault); +DECLARE(spinDefaultSize); +DECLARE(spinMinimumSize); +DECLARE(fontPreview); + +DECLARE(comboButtonType); + +DECLARE(spinMemoryCacheSize); +DECLARE(spinDiscCacheAge); + +DECLARE(checkClearDownloads); +DECLARE(checkRequestOverwrite); +DECLARE(fileChooserDownloads); +DECLARE(checkFocusNew); +DECLARE(checkNewBlank); +DECLARE(checkUrlSearch); +DECLARE(comboSearch); +DECLARE(combotheme); +DECLARE(buttonaddtheme); +DECLARE(sourceButtonTab); +static GtkWidget *sourceButtonWindow; + +DECLARE(spinMarginTop); +DECLARE(spinMarginBottom); +DECLARE(spinMarginLeft); +DECLARE(spinMarginRight); +DECLARE(spinExportScale); +DECLARE(checkSuppressImages); +DECLARE(checkRemoveBackgrounds); +DECLARE(checkFitPage); +DECLARE(checkCompressPDF); +DECLARE(checkPasswordPDF); +DECLARE(setDefaultExportOptions); + +/* Used when the feature is not implemented yet */ +#define FIND_WIDGET(wname) \ + do { \ + (wname) = glade_xml_get_widget(gladeFile, #wname); \ + if ((wname) == NULL) \ + LOG(("Unable to find widget '%s'!", #wname)); \ + } while (0) + +/* Assigns widget and connects it to its callback function */ +#define CONNECT(wname, event) \ + g_signal_connect(G_OBJECT(wname), event, \ + G_CALLBACK(on_##wname##_changed), NULL) + +GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent) +{ + gladeFile = glade_xml_new(glade_options_file_location, NULL, NULL); + if (gladeFile == NULL) + return NULL; + + current_browser = bw; + wndPreferences = GTK_DIALOG(glade_xml_get_widget(gladeFile, + "dlgPreferences")); + gtk_window_set_transient_for (GTK_WINDOW(wndPreferences), parent); + + FIND_WIDGET(sourceButtonTab); + FIND_WIDGET(sourceButtonWindow); + GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON( + sourceButtonWindow)); + gtk_radio_button_set_group(GTK_RADIO_BUTTON(sourceButtonTab), group); + + /* set the widgets to reflect the current options */ + nsgtk_options_load(); + + /* Connect all widgets to their appropriate callbacks */ + CONNECT(entryHomePageURL, "focus-out-event"); + CONNECT(setCurrentPage, "clicked"); + CONNECT(setDefaultPage, "clicked"); + CONNECT(checkHideAdverts, "toggled"); + + CONNECT(checkDisablePopups, "toggled"); + CONNECT(checkDisablePlugins, "toggled"); + CONNECT(spinHistoryAge, "focus-out-event"); + CONNECT(checkHoverURLs, "toggled"); + + CONNECT(comboLanguage, "changed"); + + CONNECT(checkDisplayRecentURLs, "toggled"); + CONNECT(checkSendReferer, "toggled"); + CONNECT(checkShowSingleTab, "toggled"); + + CONNECT(comboProxyType, "changed"); + CONNECT(entryProxyHost, "focus-out-event"); + CONNECT(entryProxyPort, "focus-out-event"); + CONNECT(entryProxyUser, "focus-out-event"); + CONNECT(entryProxyPassword, "focus-out-event"); + CONNECT(spinMaxFetchers, "value-changed"); + CONNECT(spinFetchesPerHost, "value-changed"); + CONNECT(spinCachedConnections, "value-changed"); + + CONNECT(checkResampleImages, "toggled"); + CONNECT(spinAnimationSpeed, "value-changed"); + CONNECT(checkDisableAnimations, "toggled"); + + CONNECT(fontSansSerif, "font-set"); + CONNECT(fontSerif, "font-set"); + CONNECT(fontMonospace, "font-set"); + CONNECT(fontCursive, "font-set"); + CONNECT(fontFantasy, "font-set"); + CONNECT(comboDefault, "changed"); + CONNECT(spinDefaultSize, "value-changed"); + CONNECT(spinMinimumSize, "value-changed"); + CONNECT(fontPreview, "clicked"); + + CONNECT(comboButtonType, "changed"); + + CONNECT(spinMemoryCacheSize, "value-changed"); + CONNECT(spinDiscCacheAge, "value-changed"); + + CONNECT(checkClearDownloads, "toggled"); + CONNECT(checkRequestOverwrite, "toggled"); + CONNECT(fileChooserDownloads, "current-folder-changed"); + + CONNECT(checkFocusNew, "toggled"); + CONNECT(checkNewBlank, "toggled"); + CONNECT(checkUrlSearch, "toggled"); + CONNECT(comboSearch, "changed"); + + CONNECT(combotheme, "changed"); + CONNECT(buttonaddtheme, "clicked"); + CONNECT(sourceButtonTab, "toggled"); + + CONNECT(spinMarginTop, "value-changed"); + CONNECT(spinMarginBottom, "value-changed"); + CONNECT(spinMarginLeft, "value-changed"); + CONNECT(spinMarginRight, "value-changed"); + CONNECT(spinExportScale, "value-changed"); + CONNECT(checkSuppressImages, "toggled"); + CONNECT(checkRemoveBackgrounds, "toggled"); + CONNECT(checkFitPage, "toggled"); + CONNECT(checkCompressPDF, "toggled"); + CONNECT(checkPasswordPDF, "toggled"); + CONNECT(setDefaultExportOptions, "clicked"); + + g_signal_connect(G_OBJECT(wndPreferences), "response", + G_CALLBACK (dialog_response_handler), NULL); + + g_signal_connect(G_OBJECT(wndPreferences), "delete-event", + G_CALLBACK (on_dialog_close), (gpointer)TRUE); + + g_signal_connect(G_OBJECT(wndPreferences), "destroy", + G_CALLBACK (on_dialog_close), (gpointer)FALSE); + + gtk_widget_show(GTK_WIDGET(wndPreferences)); + + return wndPreferences; +} + +#define SET_ENTRY(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_entry_set_text(GTK_ENTRY((widget)), (value)); \ + } while (0) + +#define SET_SPIN(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_spin_button_set_value(GTK_SPIN_BUTTON((widget)), (value)); \ + } while (0) + +#define SET_CHECK(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON((widget)), \ + (value)); \ + } while (0) + +#define SET_COMBO(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_combo_box_set_active(GTK_COMBO_BOX((widget)), (value)); \ + } while (0) + +#define SET_FONT(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_font_button_set_font_name(GTK_FONT_BUTTON((widget)), \ + (value)); \ + } while (0) + +#define SET_FILE_CHOOSER(widget, value) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(\ + (widget)), (value)); \ + } while (0) + +#define SET_BUTTON(widget) \ + do { \ + (widget) = glade_xml_get_widget(gladeFile, #widget); \ + } while (0) + + +void nsgtk_options_load(void) +{ + GtkBox *box; + const char *default_accept_language = + option_accept_language ? option_accept_language : "en"; + int combo_row_count = 0; + int active_language = 0; + int proxytype = 0; + FILE *fp; + char buf[50]; + + /* Create combobox */ + box = GTK_BOX(glade_xml_get_widget(gladeFile, "combolanguagevbox")); + comboLanguage = gtk_combo_box_new_text(); + + /* Populate combobox from languages file */ + if ((languages_file_location != NULL) && + ((fp = fopen(languages_file_location, "r")) != NULL)) { + LOG(("Used %s for languages", languages_file_location)); + while (fgets(buf, sizeof(buf), fp)) { + /* Ignore blank lines */ + if (buf[0] == '\0') + continue; + + /* Remove trailing \n */ + buf[strlen(buf) - 1] = '\0'; + + gtk_combo_box_append_text(GTK_COMBO_BOX(comboLanguage), buf); + + if (strcmp(buf, default_accept_language) == 0) + active_language = combo_row_count; + + combo_row_count++; + } + + fclose(fp); + } else { + LOG(("Failed opening languages file")); + warn_user("FileError", languages_file_location); + gtk_combo_box_append_text(GTK_COMBO_BOX(comboLanguage), "en"); + } + + + gtk_combo_box_set_active(GTK_COMBO_BOX(comboLanguage), active_language); + /** \todo localisation */ + gtk_widget_set_tooltip_text(GTK_WIDGET(comboLanguage), + "set preferred language for web pages"); + gtk_box_pack_start(box, comboLanguage, FALSE, FALSE, 0); + gtk_widget_show(comboLanguage); + + nsgtk_options_theme_combo(); + + SET_ENTRY(entryHomePageURL, + option_homepage_url ? option_homepage_url : ""); + SET_BUTTON(setCurrentPage); + SET_BUTTON(setDefaultPage); + SET_CHECK(checkHideAdverts, option_block_ads); + + SET_CHECK(checkDisablePopups, option_disable_popups); + SET_CHECK(checkDisablePlugins, option_disable_plugins); + SET_SPIN(spinHistoryAge, option_history_age); + SET_CHECK(checkHoverURLs, option_hover_urls); + + SET_CHECK(checkDisplayRecentURLs, option_url_suggestion); + SET_CHECK(checkSendReferer, option_send_referer); + SET_CHECK(checkShowSingleTab, option_show_single_tab); + + if (option_http_proxy == false) + proxytype = 0; + else + proxytype = option_http_proxy_auth + 1; + + SET_COMBO(comboProxyType, proxytype); + SET_ENTRY(entryProxyHost, + option_http_proxy_host ? option_http_proxy_host : ""); + gtk_widget_set_sensitive(entryProxyHost, proxytype != 0); + + snprintf(buf, sizeof(buf), "%d", option_http_proxy_port); + + SET_ENTRY(entryProxyPort, buf); + gtk_widget_set_sensitive(entryProxyPort, proxytype != 0); + + SET_ENTRY(entryProxyUser, option_http_proxy_auth_user ? + option_http_proxy_auth_user : ""); + gtk_widget_set_sensitive(entryProxyUser, proxytype != 0); + + SET_ENTRY(entryProxyPassword, option_http_proxy_auth_pass ? + option_http_proxy_auth_pass : ""); + gtk_widget_set_sensitive(entryProxyPassword, proxytype != 0); + + SET_SPIN(spinMaxFetchers, option_max_fetchers); + SET_SPIN(spinFetchesPerHost, option_max_fetchers_per_host); + SET_SPIN(spinCachedConnections, option_max_cached_fetch_handles); + + SET_CHECK(checkResampleImages, option_render_resample); + SET_SPIN(spinAnimationSpeed, option_minimum_gif_delay / 100.0); + SET_CHECK(checkDisableAnimations, !option_animate_images); + + SET_FONT(fontSansSerif, option_font_sans); + SET_FONT(fontSerif, option_font_serif); + SET_FONT(fontMonospace, option_font_mono); + SET_FONT(fontCursive, option_font_cursive); + SET_FONT(fontFantasy, option_font_fantasy); + SET_COMBO(comboDefault, option_font_default); + SET_SPIN(spinDefaultSize, option_font_size / 10); + SET_SPIN(spinMinimumSize, option_font_min_size / 10); + SET_BUTTON(fontPreview); + + SET_COMBO(comboButtonType, option_button_type -1); + + SET_SPIN(spinMemoryCacheSize, option_memory_cache_size >> 20); + SET_SPIN(spinDiscCacheAge, option_disc_cache_age); + + SET_CHECK(checkClearDownloads, option_downloads_clear); + SET_CHECK(checkRequestOverwrite, option_request_overwrite); + SET_FILE_CHOOSER(fileChooserDownloads, option_downloads_directory); + + SET_CHECK(checkFocusNew, option_focus_new); + SET_CHECK(checkNewBlank, option_new_blank); + SET_CHECK(checkUrlSearch, option_search_url_bar); + SET_COMBO(comboSearch, option_search_provider); + + SET_BUTTON(buttonaddtheme); + SET_CHECK(sourceButtonTab, option_source_tab); + + SET_SPIN(spinMarginTop, option_margin_top); + SET_SPIN(spinMarginBottom, option_margin_bottom); + SET_SPIN(spinMarginLeft, option_margin_left); + SET_SPIN(spinMarginRight, option_margin_right); + SET_SPIN(spinExportScale, option_export_scale); + SET_CHECK(checkSuppressImages, option_suppress_images); + SET_CHECK(checkRemoveBackgrounds, option_remove_backgrounds); + SET_CHECK(checkFitPage, option_enable_loosening); + SET_CHECK(checkCompressPDF, option_enable_PDF_compression); + SET_CHECK(checkPasswordPDF, option_enable_PDF_password); + SET_BUTTON(setDefaultExportOptions); +} + +static void dialog_response_handler (GtkDialog *dlg, gint res_id) +{ + switch (res_id) { + case GTK_RESPONSE_HELP: + /* Ready to implement Help */ + break; + + case GTK_RESPONSE_CLOSE: + on_dialog_close(dlg, TRUE); + } +} + +static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive) +{ + LOG(("Writing options to file")); + options_write(options_file_location); + if ((stay_alive) && GTK_IS_WIDGET(dlg)) + gtk_widget_hide(GTK_WIDGET(dlg)); + else { + stay_alive = FALSE; + } + return stay_alive; +} + +static void nsgtk_options_theme_combo(void) { +/* populate theme combo from themelist file */ + GtkBox *box = GTK_BOX(glade_xml_get_widget(gladeFile, "themehbox")); + char buf[50]; + combotheme = gtk_combo_box_new_text(); + size_t len = SLEN("themelist") + strlen(res_dir_location) + 1; + char themefile[len]; + if ((combotheme == NULL) || (box == NULL)) { + warn_user(messages_get("NoMemory"), 0); + return; + } + snprintf(themefile, len, "%sthemelist", res_dir_location); + FILE *fp = fopen((const char *)themefile, "r"); + if (fp == NULL) { + LOG(("Failed opening themes file")); + warn_user("FileError", (const char *) themefile); + return; + } + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* Ignore blank lines */ + if (buf[0] == '\0') + continue; + + /* Remove trailing \n */ + buf[strlen(buf) - 1] = '\0'; + + gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), buf); + } + fclose(fp); + gtk_combo_box_set_active(GTK_COMBO_BOX(combotheme), + option_current_theme); + gtk_box_pack_start(box, combotheme, FALSE, TRUE, 0); + gtk_widget_show(combotheme); +} + +bool nsgtk_options_combo_theme_add(const char *themename) +{ + if (wndPreferences == NULL) + return false; + gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), themename); + return true; +} + + +/* Defines the callback functions for all widgets and specifies + * nsgtk_reflow_all_windows only where necessary */ + +#define ENTRY_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + if (!g_str_equal(gtk_entry_get_text(GTK_ENTRY((widget))), (option) ? (option) : "")) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + if ((option)) \ + free((option)); \ + (option) = strdup(gtk_entry_get_text(GTK_ENTRY((widget)))); \ + } \ + do { \ + +#define CHECK_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + (option) = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON((widget))); \ + do { \ + +#define SPIN_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + (option) = gtk_spin_button_get_value(GTK_SPIN_BUTTON((widget))); \ + do { \ + +#define COMBO_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + (option) = gtk_combo_box_get_active(GTK_COMBO_BOX((widget))); \ + do { + +#define FONT_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + if ((option)) \ + free((option)); \ + (option) = strdup(gtk_font_button_get_font_name(GTK_FONT_BUTTON((widget)))); \ + do { + +#define FILE_CHOOSER_CHANGED(widget, option) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + (option) = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER((widget))); \ + do { + +#define BUTTON_CLICKED(widget) \ + static gboolean on_##widget##_changed(GtkWidget *widget, gpointer data) { \ + LOG(("Signal emitted on '%s'", #widget)); \ + do { + +#define END_HANDLER \ + } while (0); \ + return FALSE; \ + } + +static gboolean on_comboLanguage_changed(GtkWidget *widget, gpointer data) +{ + char *old_lang = option_accept_language; + gchar *lang = + gtk_combo_box_get_active_text(GTK_COMBO_BOX(comboLanguage)); + if (lang == NULL) + return FALSE; + + option_accept_language = strdup((const char *) lang); + if (option_accept_language == NULL) + option_accept_language = old_lang; + else + free(old_lang); + + g_free(lang); + + return FALSE; +} + +ENTRY_CHANGED(entryHomePageURL, option_homepage_url) +END_HANDLER + +BUTTON_CLICKED(setCurrentPage) + const gchar *url = content_get_url(current_browser->current_content); + gtk_entry_set_text(GTK_ENTRY(entryHomePageURL), url); + option_homepage_url = + strdup(gtk_entry_get_text(GTK_ENTRY(entryHomePageURL))); +END_HANDLER + +BUTTON_CLICKED(setDefaultPage) + gtk_entry_set_text(GTK_ENTRY(entryHomePageURL), + "http://www.netsurf-browser.org/welcome/"); + option_homepage_url = + strdup(gtk_entry_get_text(GTK_ENTRY(entryHomePageURL))); +END_HANDLER + +CHECK_CHANGED(checkHideAdverts, option_block_ads) +END_HANDLER + +CHECK_CHANGED(checkDisplayRecentURLs, option_url_suggestion) +END_HANDLER + +CHECK_CHANGED(checkSendReferer, option_send_referer) +END_HANDLER + +CHECK_CHANGED(checkShowSingleTab, option_show_single_tab) + nsgtk_reflow_all_windows(); +END_HANDLER + +COMBO_CHANGED(comboProxyType, proxy_type) + LOG(("proxy type: %d", proxy_type)); + switch (proxy_type) + { + case 0: + option_http_proxy = false; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; + break; + case 1: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NONE; + break; + case 2: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_BASIC; + break; + case 3: + option_http_proxy = true; + option_http_proxy_auth = OPTION_HTTP_PROXY_AUTH_NTLM; + break; + } + gboolean sensitive = (!proxy_type == 0); + gtk_widget_set_sensitive (entryProxyHost, sensitive); + gtk_widget_set_sensitive (entryProxyPort, sensitive); + gtk_widget_set_sensitive (entryProxyUser, sensitive); + gtk_widget_set_sensitive (entryProxyPassword, sensitive); + +END_HANDLER + +ENTRY_CHANGED(entryProxyHost, option_http_proxy_host) +END_HANDLER + +gboolean on_entryProxyPort_changed(GtkWidget *widget, gpointer data) +{ + long port; + + errno = 0; + port = strtol((char *)gtk_entry_get_text(GTK_ENTRY(entryProxyPort)), + NULL, 10) & 0xffff; + if (port != 0 && errno == 0) { + option_http_proxy_port = port; + } else { + char buf[32]; + snprintf(buf, sizeof(buf), "%d", option_http_proxy_port); + SET_ENTRY(entryProxyPort, buf); + } + + return FALSE; +} + +ENTRY_CHANGED(entryProxyUser, option_http_proxy_auth_user) +END_HANDLER + +ENTRY_CHANGED(entryProxyPassword, option_http_proxy_auth_pass) +END_HANDLER + +SPIN_CHANGED(spinMaxFetchers, option_max_fetchers) +END_HANDLER + +SPIN_CHANGED(spinFetchesPerHost, option_max_fetchers_per_host) +END_HANDLER + +SPIN_CHANGED(spinCachedConnections, option_max_cached_fetch_handles) +END_HANDLER + +CHECK_CHANGED(checkResampleImages, option_render_resample) +END_HANDLER + +SPIN_CHANGED(spinAnimationSpeed, animation_delay) + option_minimum_gif_delay = round(animation_delay * 100.0); +END_HANDLER + +CHECK_CHANGED(checkDisableAnimations, option_animate_images); + option_animate_images = !option_animate_images; +END_HANDLER + +CHECK_CHANGED(checkDisablePopups, option_disable_popups) +END_HANDLER + +CHECK_CHANGED(checkDisablePlugins, option_disable_plugins) +END_HANDLER + +SPIN_CHANGED(spinHistoryAge, option_history_age) +END_HANDLER + +CHECK_CHANGED(checkHoverURLs, option_hover_urls) +END_HANDLER + +FONT_CHANGED(fontSansSerif, option_font_sans) +END_HANDLER + +FONT_CHANGED(fontSerif, option_font_serif) +END_HANDLER + +FONT_CHANGED(fontMonospace, option_font_mono) +END_HANDLER + +FONT_CHANGED(fontCursive, option_font_cursive) +END_HANDLER + +FONT_CHANGED(fontFantasy, option_font_fantasy) +END_HANDLER + +COMBO_CHANGED(comboDefault, option_font_default) +END_HANDLER + +SPIN_CHANGED(spinDefaultSize, option_font_size) + option_font_size *= 10; +END_HANDLER + +SPIN_CHANGED(spinMinimumSize, option_font_min_size) + option_font_min_size *= 10; +END_HANDLER + +BUTTON_CLICKED(fontPreview) + nsgtk_reflow_all_windows(); +END_HANDLER + +COMBO_CHANGED(comboButtonType, option_button_type) + nsgtk_scaffolding *current = scaf_list; + option_button_type++; + /* value of 0 is reserved for 'unset' */ + while (current) { + nsgtk_scaffolding_reset_offset(current); + switch(option_button_type) { + case 1: + gtk_toolbar_set_style( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_ICON_SIZE_SMALL_TOOLBAR); + break; + case 2: + gtk_toolbar_set_style( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_TOOLBAR_ICONS); + gtk_toolbar_set_icon_size( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_ICON_SIZE_LARGE_TOOLBAR); + break; + case 3: + gtk_toolbar_set_style( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_ICON_SIZE_LARGE_TOOLBAR); + break; + case 4: + gtk_toolbar_set_style( + GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)), + GTK_TOOLBAR_TEXT); + default: + break; + } + current = nsgtk_scaffolding_iterate(current); + } +END_HANDLER + +SPIN_CHANGED(spinMemoryCacheSize, option_memory_cache_size) + option_memory_cache_size <<= 20; +END_HANDLER + +SPIN_CHANGED(spinDiscCacheAge, option_disc_cache_age) +END_HANDLER + +CHECK_CHANGED(checkClearDownloads, option_downloads_clear) +END_HANDLER + +CHECK_CHANGED(checkRequestOverwrite, option_request_overwrite) +END_HANDLER + +FILE_CHOOSER_CHANGED(fileChooserDownloads, option_downloads_directory) +END_HANDLER + +CHECK_CHANGED(checkFocusNew, option_focus_new) +END_HANDLER + +CHECK_CHANGED(checkNewBlank, option_new_blank) +END_HANDLER + +CHECK_CHANGED(checkUrlSearch, option_search_url_bar) +END_HANDLER + +COMBO_CHANGED(comboSearch, option_search_provider) + nsgtk_scaffolding *current = scaf_list; + char *name; + /* refresh web search prefs from file */ + search_web_provider_details(option_search_provider); + /* retrieve ico */ + search_web_retrieve_ico(false); + /* callback may handle changing gui */ + if (search_web_ico() != NULL) + gui_window_set_search_ico(search_web_ico()); + /* set entry */ + name = search_web_provider_name(); + if (name == NULL) { + warn_user(messages_get("NoMemory"), 0); + continue; + } + char content[strlen(name) + SLEN("Search ") + 1]; + sprintf(content, "Search %s", name); + free(name); + while (current) { + nsgtk_scaffolding_set_websearch(current, content); + current = nsgtk_scaffolding_iterate(current); + } +END_HANDLER + +COMBO_CHANGED(combotheme, option_current_theme) + nsgtk_scaffolding *current = scaf_list; + char *name; + if (option_current_theme != 0) { + if (nsgtk_theme_name() != NULL) + free(nsgtk_theme_name()); + name = strdup(gtk_combo_box_get_active_text( + GTK_COMBO_BOX(combotheme))); + if (name == NULL) { + warn_user(messages_get("NoMemory"), 0); + continue; + } + nsgtk_theme_set_name(name); + nsgtk_theme_prepare(); + } else if (nsgtk_theme_name() != NULL) { + free(nsgtk_theme_name()); + nsgtk_theme_set_name(NULL); + } + while (current) { + nsgtk_theme_implement(current); + current = nsgtk_scaffolding_iterate(current); + } +END_HANDLER + +BUTTON_CLICKED(buttonaddtheme) + char *filename, *directory; + size_t len; + GtkWidget *fc = gtk_file_chooser_dialog_new( + messages_get("gtkAddThemeTitle"), + GTK_WINDOW(wndPreferences), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); + len = SLEN("themes") + strlen(res_dir_location) + 1; + char themesfolder[len]; + snprintf(themesfolder, len, "%sthemes", res_dir_location); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), + themesfolder); + gint res = gtk_dialog_run(GTK_DIALOG(fc)); + if (res == GTK_RESPONSE_ACCEPT) { + filename = gtk_file_chooser_get_current_folder( + GTK_FILE_CHOOSER(fc)); + if (strcmp(filename, themesfolder) != 0) { + directory = strrchr(filename, '/'); + *directory = '\0'; + if (strcmp(filename, themesfolder) != 0) { + warn_user(messages_get( + "gtkThemeFolderInstructions"), + 0); + gtk_widget_destroy(GTK_WIDGET(fc)); + if (filename != NULL) + free(filename); + return FALSE; + } else { + directory++; + } + } else { + if (filename != NULL) + free(filename); + filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(fc)); + if (strcmp(filename, themesfolder) == 0) { + warn_user(messages_get("gtkThemeFolderSub"), + 0); + gtk_widget_destroy(GTK_WIDGET(fc)); + free(filename); + return FALSE; + } + directory = strrchr(filename, '/') + 1; + } + gtk_widget_destroy(GTK_WIDGET(fc)); + nsgtk_theme_add(directory); + if (filename != NULL) + free(filename); + } + +END_HANDLER + +CHECK_CHANGED(sourceButtonTab, option_source_tab) +END_HANDLER + +SPIN_CHANGED(spinMarginTop, option_margin_top) +END_HANDLER + +SPIN_CHANGED(spinMarginBottom, option_margin_bottom) +END_HANDLER + +SPIN_CHANGED(spinMarginLeft, option_margin_left) +END_HANDLER + +SPIN_CHANGED(spinMarginRight, option_margin_right) +END_HANDLER + +SPIN_CHANGED(spinExportScale, option_export_scale) +END_HANDLER + +CHECK_CHANGED(checkSuppressImages, option_suppress_images) +END_HANDLER + +CHECK_CHANGED(checkRemoveBackgrounds, option_remove_backgrounds) +END_HANDLER + +CHECK_CHANGED(checkFitPage, option_enable_loosening) +END_HANDLER + +CHECK_CHANGED(checkCompressPDF, option_enable_PDF_compression) +END_HANDLER + +CHECK_CHANGED(checkPasswordPDF, option_enable_PDF_password) +END_HANDLER + +BUTTON_CLICKED(setDefaultExportOptions) + option_margin_top = DEFAULT_MARGIN_TOP_MM; + option_margin_bottom = DEFAULT_MARGIN_BOTTOM_MM; + option_margin_left = DEFAULT_MARGIN_LEFT_MM; + option_margin_right = DEFAULT_MARGIN_RIGHT_MM; + option_export_scale = DEFAULT_EXPORT_SCALE * 100; + option_suppress_images = false; + option_remove_backgrounds = false; + option_enable_loosening = true; + option_enable_PDF_compression = true; + option_enable_PDF_password = false; + + SET_SPIN(spinMarginTop, option_margin_top); + SET_SPIN(spinMarginBottom, option_margin_bottom); + SET_SPIN(spinMarginLeft, option_margin_left); + SET_SPIN(spinMarginRight, option_margin_right); + SET_SPIN(spinExportScale, option_export_scale); + SET_CHECK(checkSuppressImages, option_suppress_images); + SET_CHECK(checkRemoveBackgrounds, option_remove_backgrounds); + SET_CHECK(checkCompressPDF, option_enable_PDF_compression); + SET_CHECK(checkPasswordPDF, option_enable_PDF_password); + SET_CHECK(checkFitPage, option_enable_loosening); +END_HANDLER diff --git a/gtk/dialogs/options.h b/gtk/dialogs/options.h new file mode 100644 index 000000000..9f6602593 --- /dev/null +++ b/gtk/dialogs/options.h @@ -0,0 +1,34 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#ifndef NETSURF_GTK_OPTIONS_H +#define NETSURF_GTK_OPTIONS_H + +#include + +extern GtkDialog *wndPreferences; + +GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent); + /** Init options and load window */ +void nsgtk_options_load(void); /** Load current options into window */ +void nsgtk_options_save(void); /** Save options from window */ +bool nsgtk_options_combo_theme_add(const char *themename); + /** add new theme name to combo */ + +#endif diff --git a/gtk/dialogs/source.c b/gtk/dialogs/source.c new file mode 100644 index 000000000..7c58a014e --- /dev/null +++ b/gtk/dialogs/source.c @@ -0,0 +1,529 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include "gtk/dialogs/source.h" +#include "gtk/dialogs/about.h" +#include "gtk/window.h" +#include "gtk/gui.h" +#include "gtk/print.h" +#include "gtk/selection.h" +#include "gtk/options.h" +#include "desktop/netsurf.h" +#include "desktop/print.h" +#include "desktop/options.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utils.h" +#include "utils/utf8.h" +#include "render/font.h" +#include "content/content.h" +#include "content/content_type.h" +#include "render/textplain.h" + +#include "utils/log.h" + +struct nsgtk_source_window { + gchar *url; + char *data; + GtkWindow *sourcewindow; + GtkTextView *gv; + struct browser_window *bw; + struct nsgtk_source_window *next; + struct nsgtk_source_window *prev; +}; + +struct menu_events { + const char *widget; + GCallback handler; +}; + +static GladeXML *glade_File; +static struct nsgtk_source_window *nsgtk_source_list = 0; +static char source_zoomlevel = 10; + +void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw); +static void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g); +static gboolean nsgtk_source_delete_event(GtkWindow *window, gpointer g); +static gboolean nsgtk_source_destroy_event(GtkWindow *window, gpointer g); +static void nsgtk_source_update_zoomlevel(gpointer g); +static void nsgtk_source_file_save(GtkWindow *parent, const char *filename, + const char *data); + +#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } +#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ + GtkMenuItem *widget, gpointer g) + +MENUPROTO(source_save_as); +MENUPROTO(source_print); +MENUPROTO(source_close); +MENUPROTO(source_select_all); +MENUPROTO(source_cut); +MENUPROTO(source_copy); +MENUPROTO(source_paste); +MENUPROTO(source_delete); +MENUPROTO(source_zoom_in); +MENUPROTO(source_zoom_out); +MENUPROTO(source_zoom_normal); +MENUPROTO(source_about); + +struct menu_events source_menu_events[] = { +MENUEVENT(source_save_as), +MENUEVENT(source_print), +MENUEVENT(source_close), +MENUEVENT(source_select_all), +MENUEVENT(source_cut), +MENUEVENT(source_copy), +MENUEVENT(source_paste), +MENUEVENT(source_delete), +MENUEVENT(source_zoom_in), +MENUEVENT(source_zoom_out), +MENUEVENT(source_zoom_normal), +MENUEVENT(source_about), +{NULL, NULL} +}; + +void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw) +{ + char glade_Location[strlen(res_dir_location) + SLEN("source.glade") + + 1]; + if (content_get_type(bw->current_content) != CONTENT_HTML) + return; + + if (option_source_tab) { + nsgtk_source_tab_init(parent, bw); + return; + } + + sprintf(glade_Location, "%ssource.glade", res_dir_location); + glade_File = glade_xml_new(glade_Location, NULL, NULL); + if (glade_File == NULL) { + LOG(("error loading glade tree")); + } + + const char *source_data; + unsigned long source_size; + char *data = NULL; + + source_data = content_get_source_data(bw->current_content, + &source_size); + + utf8_convert_ret r = utf8_from_enc( + source_data, + html_get_encoding(bw->current_content), + source_size, + &data); + if (r == UTF8_CONVERT_NOMEM) { + warn_user("NoMemory",0); + return; + } else if (r == UTF8_CONVERT_BADENC) { + warn_user("EncNotRec",0); + return; + } + + GtkWindow *wndSource = GTK_WINDOW(glade_xml_get_widget( + glade_File, "wndSource")); + GtkWidget *cutbutton = glade_xml_get_widget( + glade_File, "source_cut"); + GtkWidget *pastebutton = glade_xml_get_widget( + glade_File, "source_paste"); + GtkWidget *deletebutton = glade_xml_get_widget( + glade_File, "source_delete"); + GtkWidget *printbutton = glade_xml_get_widget( + glade_File, "source_print"); + gtk_widget_set_sensitive(cutbutton, FALSE); + gtk_widget_set_sensitive(pastebutton, FALSE); + gtk_widget_set_sensitive(deletebutton, FALSE); + /* for now */ + gtk_widget_set_sensitive(printbutton, FALSE); + + struct nsgtk_source_window *thiswindow = + malloc(sizeof(struct nsgtk_source_window)); + if (thiswindow == NULL) { + free(data); + warn_user("NoMemory", 0); + return; + } + + thiswindow->url = strdup(content_get_url(bw->current_content)); + if (thiswindow->url == NULL) { + free(thiswindow); + free(data); + warn_user("NoMemory", 0); + return; + } + + thiswindow->data = data; + + thiswindow->sourcewindow = wndSource; + thiswindow->bw = bw; + + char title[strlen(thiswindow->url) + SLEN("Source of - NetSurf") + 1]; + sprintf(title, "Source of %s - NetSurf", thiswindow->url); + + thiswindow->next = nsgtk_source_list; + thiswindow->prev = NULL; + if (nsgtk_source_list != NULL) + nsgtk_source_list->prev = thiswindow; + nsgtk_source_list = thiswindow; + + nsgtk_attach_source_menu_handlers(glade_File, thiswindow); + + gtk_window_set_title(wndSource, title); + + g_signal_connect(G_OBJECT(wndSource), "destroy", + G_CALLBACK(nsgtk_source_destroy_event), + thiswindow); + g_signal_connect(G_OBJECT(wndSource), "delete-event", + G_CALLBACK(nsgtk_source_delete_event), + thiswindow); + + GtkTextView *sourceview = GTK_TEXT_VIEW( + glade_xml_get_widget(glade_File, + "source_view")); + PangoFontDescription *fontdesc = + pango_font_description_from_string("Monospace 8"); + + thiswindow->gv = sourceview; + gtk_widget_modify_font(GTK_WIDGET(sourceview), fontdesc); + GtkTextBuffer *tb = gtk_text_view_get_buffer(sourceview); + gtk_text_buffer_set_text(tb, thiswindow->data, -1); + + gtk_widget_show(GTK_WIDGET(wndSource)); + +} +void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw) +{ + const char *source_data; + unsigned long source_size; + char *ndata = 0; + + source_data = content_get_source_data(bw->current_content, + &source_size); + + utf8_convert_ret r = utf8_from_enc( + source_data, + html_get_encoding(bw->current_content), + source_size, + &ndata); + if (r == UTF8_CONVERT_NOMEM) { + warn_user("NoMemory",0); + return; + } else if (r == UTF8_CONVERT_BADENC) { + warn_user("EncNotRec",0); + return; + } + gchar *filename; + char *fileurl; + gint handle = g_file_open_tmp("nsgtksourceXXXXXX", &filename, NULL); + if ((handle == -1) || (filename == NULL)) { + warn_user(messages_get("gtkSourceTabError"), 0); + return; + } + close (handle); /* in case it was binary mode */ + FILE *f = fopen(filename, "w"); + if (f == NULL) { + warn_user(messages_get("gtkSourceTabError"), 0); + g_free(filename); + return; + } + fprintf(f, "%s", ndata); + fclose(f); + free(ndata); + fileurl = path_to_url(filename); + g_free(filename); + if (fileurl == NULL) { + warn_user(messages_get("NoMemory"), 0); + return; + } + /* Open tab */ + browser_window_create(fileurl, bw, NULL, false, true); + free(fileurl); +} + + +void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g) +{ + struct menu_events *event = source_menu_events; + + while (event->widget != NULL) + { + GtkWidget *w = glade_xml_get_widget(xml, event->widget); + g_signal_connect(G_OBJECT(w), "activate", event->handler, g); + event++; + } +} + +gboolean nsgtk_on_source_save_as_activate(GtkMenuItem *widget, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + GtkWidget *fc = gtk_file_chooser_dialog_new( + messages_get("gtkSourceSave"), + nsg->sourcewindow, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, + GTK_RESPONSE_ACCEPT, + NULL); + char *filename; + url_func_result res; + + res = url_nice(nsg->url, &filename, false); + if (res != URL_FUNC_OK) { + filename = strdup(messages_get("SaveSource")); + if (filename == NULL) { + warn_user("NoMemory", 0); + return FALSE; + } + } + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), filename); + + free(filename); + + if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc)); + nsgtk_source_file_save(nsg->sourcewindow, filename, nsg->data); + g_free(filename); + } + + gtk_widget_destroy(fc); + + return TRUE; +} + +void nsgtk_source_file_save(GtkWindow *parent, const char *filename, + const char *data) +{ + FILE *f; + bool auth = true; + char temp[255]; + GtkWidget *notif, *label; + + if (!(access(filename, F_OK))) { + GtkWidget *confd = gtk_dialog_new_with_buttons( + messages_get("gtkOverwriteTitle"), + parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK, + GTK_RESPONSE_ACCEPT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_REJECT, + NULL); + const char *format = messages_get("gtkOverwrite"); + int len = strlen(filename) + strlen(format) + SLEN("\n\n") + 1; + char warn[len]; + auth = false; + + warn[0] = '\n'; + snprintf(warn + 1, len - 2, format, filename); + len = strlen(warn); + warn[len - 1] = '\n'; + warn[len] = '\0'; + + label = gtk_label_new(warn); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(confd)->vbox), + label); + gtk_widget_show(label); + if (gtk_dialog_run(GTK_DIALOG(confd)) == GTK_RESPONSE_ACCEPT) { + auth = true; + } + gtk_widget_destroy(confd); + } + + if (auth) { + f = fopen(filename, "w+"); + fprintf(f, "%s", data); + fclose(f); + snprintf(temp, sizeof(temp), "\n %s" + " \n", + messages_get("gtkSaveConfirm")); + } else { + snprintf(temp, sizeof(temp), "\n %s" + " \n", + messages_get("gtkSaveCancelled")); + } + + notif = gtk_dialog_new_with_buttons(temp, + parent, GTK_DIALOG_MODAL, GTK_STOCK_OK, + GTK_RESPONSE_NONE, NULL); + g_signal_connect_swapped(notif, "response", + G_CALLBACK(gtk_widget_destroy), notif); + label = gtk_label_new(temp); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notif)->vbox), label); + gtk_widget_show_all(notif); +} + +gboolean nsgtk_on_source_print_activate( GtkMenuItem *widget, gpointer g) +{ + /* correct printing */ + + return TRUE; +} + +gboolean nsgtk_on_source_close_activate( GtkMenuItem *widget, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + + gtk_widget_destroy(GTK_WIDGET(nsg->sourcewindow)); + + return TRUE; +} + +gboolean nsgtk_source_delete_event(GtkWindow * window, gpointer g) +{ + return FALSE; +} + +gboolean nsgtk_source_destroy_event(GtkWindow * window, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + + if (nsg->next != NULL) + nsg->next->prev = nsg->prev; + + if (nsg->prev != NULL) + nsg->prev->next = nsg->next; + else + nsgtk_source_list = nsg->next; + + free(nsg->data); + free(nsg->url); + free(g); + + return FALSE; +} + +gboolean nsgtk_on_source_select_all_activate (GtkMenuItem *widget, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + GtkTextBuffer *buf = gtk_text_view_get_buffer(nsg->gv); + GtkTextIter start, end; + + gtk_text_buffer_get_bounds(buf, &start, &end); + + gtk_text_buffer_select_range(buf, &start, &end); + + return TRUE; +} + +gboolean nsgtk_on_source_cut_activate(GtkMenuItem *widget, gpointer g) +{ + return TRUE; +} + +gboolean nsgtk_on_source_copy_activate(GtkMenuItem *widget, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(nsg->gv)); + + gtk_text_buffer_copy_clipboard(buf, + gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); + + return TRUE; +} + +gboolean nsgtk_on_source_paste_activate(GtkMenuItem *widget, gpointer g) +{ + return TRUE; +} + +gboolean nsgtk_on_source_delete_activate(GtkMenuItem *widget, gpointer g) +{ + return TRUE; +} + +gboolean nsgtk_on_source_zoom_in_activate(GtkMenuItem *widget, gpointer g) +{ + source_zoomlevel++; + nsgtk_source_update_zoomlevel(g); + + return TRUE; +} + +gboolean nsgtk_on_source_zoom_out_activate(GtkMenuItem *widget, gpointer g) +{ + if (source_zoomlevel > 1) { + source_zoomlevel--; + nsgtk_source_update_zoomlevel(g); + } + + return TRUE; +} + +gboolean nsgtk_on_source_zoom_normal_activate(GtkMenuItem *widget, gpointer g) +{ + source_zoomlevel = 10; + nsgtk_source_update_zoomlevel(g); + + return TRUE; +} + +gboolean nsgtk_on_source_about_activate(GtkMenuItem *widget, gpointer g) +{ + struct nsgtk_source_window *nsg = (struct nsgtk_source_window *) g; + + nsgtk_about_dialog_init(nsg->sourcewindow, nsg->bw, netsurf_version); + + return TRUE; +} + +void nsgtk_source_update_zoomlevel(gpointer g) +{ + struct nsgtk_source_window *nsg; + GtkTextBuffer *buf; + GtkTextTagTable *tab; + GtkTextTag *tag; + + nsg = nsgtk_source_list; + while (nsg) { + if (nsg->gv) { + buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(nsg->gv)); + + tab = gtk_text_buffer_get_tag_table( + GTK_TEXT_BUFFER(buf)); + + tag = gtk_text_tag_table_lookup(tab, "zoomlevel"); + if (!tag) { + tag = gtk_text_tag_new("zoomlevel"); + gtk_text_tag_table_add(tab, GTK_TEXT_TAG(tag)); + } + + gdouble fscale = ((gdouble) source_zoomlevel) / 10; + + g_object_set(GTK_TEXT_TAG(tag), "scale", fscale, NULL); + + GtkTextIter start, end; + + gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(buf), + &start, &end); + gtk_text_buffer_remove_all_tags(GTK_TEXT_BUFFER(buf), + &start, &end); + gtk_text_buffer_apply_tag(GTK_TEXT_BUFFER(buf), + GTK_TEXT_TAG(tag), &start, &end); + } + nsg = nsg->next; + } +} diff --git a/gtk/dialogs/source.h b/gtk/dialogs/source.h new file mode 100644 index 000000000..fcba6b664 --- /dev/null +++ b/gtk/dialogs/source.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#ifndef netsurf_gtk_dialogs_source_h_ +#define netsurf_gtk_dialogs_source_h_ + +#include +#include "desktop/browser.h" + +void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw); + +#endif + diff --git a/gtk/download.c b/gtk/download.c new file mode 100644 index 000000000..990176a24 --- /dev/null +++ b/gtk/download.c @@ -0,0 +1,827 @@ +/* + * Copyright 2008 Michael Lester + * + * 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 . + */ + +#include +#include +#include + +#include +#include + +#include "utils/log.h" +#include "utils/utils.h" +#include "utils/url.h" +#include "utils/messages.h" +#include "desktop/gui.h" +#include "gtk/gui.h" +#include "gtk/scaffolding.h" +#include "gtk/options.h" +#include "gtk/download.h" +#include "gtk/window.h" +#include "gtk/compat.h" + +#define UPDATE_RATE 500 /* In milliseconds */ + +static GtkWindow *nsgtk_download_window, *nsgtk_download_parent; +static GtkProgressBar *nsgtk_download_progress_bar; + +static GtkTreeView *nsgtk_download_tree; +static GtkListStore *nsgtk_download_store; +static GtkTreeSelection *nsgtk_download_selection; +static GtkTreeIter nsgtk_download_iter; + +static GTimer *nsgtk_downloads_timer; +static GList *nsgtk_downloads_list, *nsgtk_download_buttons; +static gint nsgtk_downloads_num_active; +static const gchar* status_messages[] = { NULL, "gtkWorking", "gtkError", + "gtkComplete", "gtkCanceled" }; + +static gboolean nsgtk_download_hide(GtkWidget *window); + +static GtkTreeView *nsgtk_download_tree_view_new(GladeXML *gladeFile); +static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, + GtkTreePath *path, GtkTreeViewColumn *column, gpointer data); + +static gint nsgtk_download_sort(GtkTreeModel *model, GtkTreeIter *a, + GtkTreeIter *b, gpointer userdata); +static gboolean nsgtk_download_update(gboolean force_update); +static void nsgtk_download_do(nsgtk_download_selection_action action); + +static void nsgtk_download_store_update_item(struct gui_download_window *dl); +static void nsgtk_download_store_create_item (struct gui_download_window *dl); +static void nsgtk_download_store_clear_item (struct gui_download_window *dl); +static void nsgtk_download_store_cancel_item (struct gui_download_window *dl); + +static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection); +static void nsgtk_download_sensitivity_update_buttons( + nsgtk_download_actions sensitivity); + +static void nsgtk_download_change_sensitivity( + struct gui_download_window *dl, nsgtk_download_actions sens); +static void nsgtk_download_change_status ( + struct gui_download_window *dl, nsgtk_download_status status); + +static gchar* nsgtk_download_dialog_show (gchar *filename, gchar *domain, + const gchar *size); +static gchar* nsgtk_download_info_to_string (struct gui_download_window *dl); +static gchar* nsgtk_download_time_to_string (gint seconds); +static gboolean nsgtk_download_handle_error (GError *error); + + + +bool nsgtk_download_init(const char *glade_file_location) +{ + GladeXML *gladeFile; + + gladeFile = glade_xml_new(glade_file_location, NULL, NULL); + if (gladeFile == NULL) + return false; + + nsgtk_download_buttons = + glade_xml_get_widget_prefix(gladeFile, "button"); + nsgtk_download_progress_bar = GTK_PROGRESS_BAR(glade_xml_get_widget( + gladeFile, "progressBar")); + nsgtk_download_window = GTK_WINDOW(glade_xml_get_widget(gladeFile, + "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(gladeFile); + + 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(glade_xml_get_widget(gladeFile, "buttonClear"), + "clicked", G_CALLBACK(nsgtk_download_do), + nsgtk_download_store_clear_item); + g_signal_connect_swapped(glade_xml_get_widget(gladeFile, + "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 true; +} + +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, + "%s\n\n" + "%s", 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); +} + +gboolean nsgtk_download_hide (GtkWidget *window) +{ + gtk_widget_hide(window); + return TRUE; +} + +struct gui_download_window *gui_download_window_create(download_context *ctx, + struct gui_window *gui) +{ + const char *url = download_context_get_url(ctx); + unsigned long total_size = download_context_get_total_length(ctx); + gchar *domain; + gchar *filename; + gchar *destination; + gboolean unknown_size = total_size == 0; + const char *size = (total_size == 0 ? + messages_get("gtkUnknownSize") : + human_friendly_bytesize(total_size)); + + nsgtk_download_parent = + nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); + + struct gui_download_window *download = malloc(sizeof *download); + if (download == NULL) + return NULL; + + if (url_nice(url, &filename, false) != URL_FUNC_OK) { + filename = g_strdup(messages_get("gtkUnknownFile")); + if (filename == NULL) { + free(download); + return NULL; + } + } + + if (url_host(url, &domain) != URL_FUNC_OK) { + domain = g_strdup(messages_get("gtkUnknownHost")); + if (domain == NULL) { + g_free(filename); + free(download); + return NULL; + } + } + + destination = nsgtk_download_dialog_show(filename, domain, size); + if (destination == NULL) { + g_free(domain); + g_free(filename); + free(download); + return NULL; + } + + /* 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); + 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)); + + download->ctx = ctx; + download->name = g_string_new(filename); + download->time_left = g_string_new(""); + download->size_total = total_size; + download->size_downloaded = 0; + download->speed = 0; + download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL); + download->time_remaining = -1; + download->status = NSGTK_DOWNLOAD_NONE; + download->filename = destination; + download->progress = 0; + download->error = NULL; + download->write = + g_io_channel_new_file(destination, "w", &download->error); + + if (nsgtk_download_handle_error(download->error)) { + g_string_free(download->name, TRUE); + g_string_free(download->time_left, TRUE); + g_free(download->filename); + free(download); + return NULL; + } + g_io_channel_set_encoding(download->write, NULL, &download->error); + + nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); + + nsgtk_download_store_create_item(download); + nsgtk_download_show(nsgtk_download_parent); + + 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); + } + + nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download); + + return download; +} + + +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) { + dw->speed = 0; + dw->time_remaining = -1; + + nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); + nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_ERROR); + + nsgtk_download_update(TRUE); + + gtk_window_present(nsgtk_download_window); + + return NSERROR_SAVE_FAILED; + } + dw->size_downloaded += size; + + return NSERROR_OK; +} + + +void gui_download_window_error(struct gui_download_window *dw, + const char *error_msg) +{ +} + + +void gui_download_window_done(struct gui_download_window *dw) +{ + g_io_channel_shutdown(dw->write, TRUE, &dw->error); + g_io_channel_unref(dw->write); + + dw->speed = 0; + dw->time_remaining = -1; + dw->progress = 100; + dw->size_total = dw->size_downloaded; + nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); + nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE); + + if (option_downloads_clear) + nsgtk_download_store_clear_item(dw); + else + nsgtk_download_update(TRUE); +} + + +GtkTreeView* nsgtk_download_tree_view_new(GladeXML *gladeFile) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(glade_xml_get_widget(gladeFile, + "treeDownloads")); + GtkCellRenderer *renderer; + + /* 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); + + /* 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); + + /* 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); + + /* 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); + + return treeview; +} + +void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, + GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model(tree); + + if (gtk_tree_model_get_iter(model, &iter, path)) { + /* TODO: This will be a context action (pause, start, clear) */ + nsgtk_download_do(nsgtk_download_store_clear_item); + } +} + +gint nsgtk_download_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, + gpointer userdata) +{ + struct gui_download_window *dl1, *dl2; + + gtk_tree_model_get(model, a, NSGTK_DOWNLOAD, &dl1, -1); + gtk_tree_model_get(model, b, NSGTK_DOWNLOAD, &dl2, -1); + + return dl1->status - dl2->status; +} + +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); + + if (selection_exists) { + rows = gtk_tree_selection_get_selected_rows( + nsgtk_download_selection, &model); + while (rows != NULL) { + struct gui_download_window *dl; + gtk_tree_model_get_iter(GTK_TREE_MODEL( + nsgtk_download_store), + &nsgtk_download_iter, + (GtkTreePath*)rows->data); + gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_download_store), + &nsgtk_download_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_free(rows); + } else + dls = g_list_copy(nsgtk_downloads_list); + + g_list_foreach(dls, (GFunc)action, NULL); + g_list_free(dls); +} + +gboolean nsgtk_download_update(gboolean force_update) +{ + /* Be sure we need to update */ + if (!nsgtk_widget_get_visible(GTK_WIDGET(nsgtk_download_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; + + for (list = nsgtk_downloads_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; + + case NSGTK_DOWNLOAD_NONE: + dl->speed = dl->size_downloaded / + (elapsed - dl->start_time); + if (dl->status == NSGTK_DOWNLOAD_NONE) { + dl->time_remaining = (dl->size_total - + dl->size_downloaded)/ + dl->speed; + dl->progress = (gfloat) + dl->size_downloaded / + dl->size_total * 100; + } else + dl->progress++; + + nsgtk_downloads_num_active++; + update = TRUE; + + case NSGTK_DOWNLOAD_COMPLETE: + downloaded += dl->size_downloaded; + total += dl->size_total; + dls++; + + default: + ;//Do nothing + + } + if (update) + nsgtk_download_store_update_item(dl); + } + + if (pulse_mode) { + text = g_strdup_printf( + messages_get(nsgtk_downloads_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); + } else { + percent = total != 0 ? (gfloat)downloaded / total : 0; + text = g_strdup_printf(messages_get("gtkProgressBar"), + floor(percent*100), dls); + gtk_progress_bar_set_fraction(nsgtk_download_progress_bar, + percent); + gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); + } + + g_free(text); + + if (nsgtk_downloads_num_active == 0) + return FALSE; /* Returning FALSE here cancels the g_timeout */ + else + return TRUE; +} + +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); + char speed[strlen(human) + SLEN("/s") + 1]; + sprintf(speed, "%s/s", human); + gchar *time = nsgtk_download_time_to_string(dl->time_remaining); + 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_row_reference_get_path(dl->row)); + + gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1, + NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress, + NSGTK_DOWNLOAD_INFO, info, + NSGTK_DOWNLOAD_SPEED, dl->speed == 0 ? "-" : speed, + NSGTK_DOWNLOAD_REMAINING, time, + NSGTK_DOWNLOAD, dl, + -1); + + g_free(info); + g_free(time); +} + +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); +} + +void nsgtk_download_store_clear_item (struct gui_download_window *dl) +{ + if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) { + nsgtk_downloads_list = g_list_remove(nsgtk_downloads_list, dl); + + gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), + &nsgtk_download_iter, + gtk_tree_row_reference_get_path(dl->row)); + gtk_list_store_remove(nsgtk_download_store, + &nsgtk_download_iter); + + download_context_destroy(dl->ctx); + g_string_free(dl->name, TRUE); + g_string_free(dl->time_left, TRUE); + g_free(dl->filename); + g_free(dl); + + nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); + nsgtk_download_update(FALSE); + } +} + +void nsgtk_download_store_cancel_item (struct gui_download_window *dl) +{ + if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) { + dl->speed = 0; + dl->size_downloaded = 0; + dl->progress = 0; + dl->time_remaining = -1; + nsgtk_download_change_sensitivity(dl, NSGTK_DOWNLOAD_CLEAR); + nsgtk_download_change_status(dl, NSGTK_DOWNLOAD_CANCELED); + + download_context_abort(dl->ctx); + + g_unlink(dl->filename); + + nsgtk_download_update(TRUE); + } +} + +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); + nsgtk_download_actions sensitivity = 0; + struct gui_download_window *dl; + + if (selected) { + rows = gtk_tree_selection_get_selected_rows(selection, &model); + while (rows != NULL) { + gtk_tree_model_get_iter(model, &iter, + (GtkTreePath*)rows->data); + gtk_tree_model_get(model, &iter, NSGTK_DOWNLOAD, + &dl, -1); + sensitivity |= dl->sensitivity; + rows = rows->next; + } + } else { + rows = nsgtk_downloads_list; + while (rows != NULL) { + dl = rows->data; + sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR); + rows = rows->next; + } + } + + + nsgtk_download_sensitivity_update_buttons(sensitivity); +} + +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(g_list_nth_data(nsgtk_download_buttons, + PAUSE_BUTTON), sensitivity & NSGTK_DOWNLOAD_PAUSE); + gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, + CLEAR_BUTTON), sensitivity & NSGTK_DOWNLOAD_CLEAR); + gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, + CANCEL_BUTTON), sensitivity & NSGTK_DOWNLOAD_CANCEL); + gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, + RESUME_BUTTON), sensitivity & NSGTK_DOWNLOAD_RESUME); +} + +void nsgtk_download_change_sensitivity(struct gui_download_window *dl, + nsgtk_download_actions sensitivity) +{ + dl->sensitivity = sensitivity; + nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); +} + +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_row_reference_get_path(dl->row)); + + gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + NSGTK_DOWNLOAD_STATUS, + messages_get(status_messages[status]), -1); + } +} + +gchar* nsgtk_download_dialog_show (gchar *filename, 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, + "%s" + "\n\n%s", + message, info); + + gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_SAVE, + GTK_RESPONSE_DOWNLOAD, GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE_AS, + GTK_RESPONSE_SAVE_AS, NULL); + + gint result = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + g_free(message); + g_free(info); + + switch (result) { + case GTK_RESPONSE_SAVE_AS: { + dialog = gtk_file_chooser_dialog_new + (messages_get("gtkSave"), + nsgtk_download_parent, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_current_name + (GTK_FILE_CHOOSER(dialog), filename); + gtk_file_chooser_set_current_folder + (GTK_FILE_CHOOSER(dialog), + option_downloads_directory); + gtk_file_chooser_set_do_overwrite_confirmation + (GTK_FILE_CHOOSER(dialog), + option_request_overwrite); + + gint result = gtk_dialog_run(GTK_DIALOG(dialog)); + if (result == GTK_RESPONSE_ACCEPT) + destination = gtk_file_chooser_get_filename + (GTK_FILE_CHOOSER(dialog)); + gtk_widget_destroy(dialog); + break; + } + case GTK_RESPONSE_DOWNLOAD: { + destination = malloc(strlen(option_downloads_directory) + + strlen(filename) + SLEN("/") + 1); + if (destination == NULL) { + warn_user(messages_get("NoMemory"), 0); + break; + } + sprintf(destination, "%s/%s", + option_downloads_directory, filename); + /* Test if file already exists and display overwrite + * confirmation if needed */ + if (g_file_test(destination, G_FILE_TEST_EXISTS) + && option_request_overwrite) { + message = g_strdup_printf(messages_get( + "gtkOverwrite"), filename); + info = g_strdup_printf(messages_get( + "gtkOverwriteInfo"), + option_downloads_directory); + + dialog = gtk_message_dialog_new_with_markup( + nsgtk_download_parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + "%s",message); + gtk_message_dialog_format_secondary_markup( + GTK_MESSAGE_DIALOG(dialog), + "%s", info); + + GtkWidget *button = gtk_dialog_add_button( + GTK_DIALOG(dialog), + "_Replace", + GTK_RESPONSE_DOWNLOAD); + gtk_button_set_image(GTK_BUTTON(button), + gtk_image_new_from_stock( + "gtk-save", + GTK_ICON_SIZE_BUTTON)); + + gint result = gtk_dialog_run(GTK_DIALOG( + dialog)); + if (result == GTK_RESPONSE_CANCEL) + destination = NULL; + + gtk_widget_destroy(dialog); + g_free(message); + g_free(info); + } + break; + } + } + return destination; +} + +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 *r; + + 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); + + g_free(size_info); + + return r; +} + +gchar* nsgtk_download_time_to_string (gint seconds) +{ + gint hours, minutes; + + 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, + seconds); + else + return g_strdup_printf("%u:%02u", minutes, seconds); +} + +gboolean nsgtk_download_handle_error (GError *error) +{ + 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, + "%s\n\n" + "%s", messages_get("gtkFailed"), + message); + + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return TRUE; + } + return FALSE; +} + + diff --git a/gtk/download.h b/gtk/download.h new file mode 100644 index 000000000..7e8226ce9 --- /dev/null +++ b/gtk/download.h @@ -0,0 +1,81 @@ +/* + * Copyright 2008 Michael Lester + * + * 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 . + */ + +#ifndef GTK_DOWNLOAD_H +#define GTK_DOWNLOAD_H + +#include + +struct download_context; + +enum { + NSGTK_DOWNLOAD_PROGRESS, + NSGTK_DOWNLOAD_INFO, + NSGTK_DOWNLOAD_REMAINING, + NSGTK_DOWNLOAD_SPEED, + NSGTK_DOWNLOAD_PULSE, + NSGTK_DOWNLOAD_STATUS, + NSGTK_DOWNLOAD, + + NSGTK_DOWNLOAD_N_COLUMNS +}; + +typedef enum { + NSGTK_DOWNLOAD_NONE, + NSGTK_DOWNLOAD_WORKING, + NSGTK_DOWNLOAD_ERROR, + NSGTK_DOWNLOAD_COMPLETE, + NSGTK_DOWNLOAD_CANCELED +} nsgtk_download_status; + +typedef enum { + NSGTK_DOWNLOAD_PAUSE = 1 << 0, + NSGTK_DOWNLOAD_RESUME = 1 << 1, + NSGTK_DOWNLOAD_CANCEL = 1 << 2, + NSGTK_DOWNLOAD_CLEAR = 1 << 3 +} nsgtk_download_actions; + +struct gui_download_window { + struct download_context *ctx; + nsgtk_download_actions sensitivity; + nsgtk_download_status status; + + GString *name; + GString *time_left; + gint size_total; + gint size_downloaded; + gint progress; + gfloat time_remaining; + gfloat start_time; + gfloat speed; + gchar *filename; + + GtkTreeRowReference *row; + GIOChannel *write; + GError *error; +}; + +typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl); + +bool nsgtk_download_init(const char *glade_file_location); +void nsgtk_download_destroy (void); +bool nsgtk_check_for_downloads(GtkWindow *parent); +void nsgtk_download_show(GtkWindow *parent); +void nsgtk_download_add(gchar *url, gchar *destination); + +#endif diff --git a/gtk/filetype.c b/gtk/filetype.c new file mode 100644 index 000000000..b172f5191 --- /dev/null +++ b/gtk/filetype.c @@ -0,0 +1,221 @@ +/* + * Copyright 2007 Rob Kendrick + * Copyright 2007 Vincent Sanders + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtk/filetype.h" +#include "content/fetch.h" +#include "utils/log.h" +#include "utils/hashtable.h" + +static struct hash_table *mime_hash = NULL; + +void gtk_fetch_filetype_init(const char *mimefile) +{ + struct stat statbuf; + FILE *fh = NULL; + + mime_hash = hash_create(117); + + /* first, check to see if /etc/mime.types in preference */ + + if ((stat("/etc/mime.types", &statbuf) == 0) && + S_ISREG(statbuf.st_mode)) { + mimefile = "/etc/mime.types"; + + } + + fh = fopen(mimefile, "r"); + + /* Some OSes (mentioning no Solarises) have a worthlessly tiny + * /etc/mime.types that don't include essential things, so we + * pre-seed our hash with the essentials. These will get + * over-ridden if they are mentioned in the mime.types file. + */ + + hash_add(mime_hash, "css", "text/css"); + hash_add(mime_hash, "htm", "text/html"); + 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, "gif", "image/gif"); + hash_add(mime_hash, "png", "image/png"); + hash_add(mime_hash, "jng", "image/jng"); + hash_add(mime_hash, "mng", "image/mng"); + hash_add(mime_hash, "webp", "image/webp"); + hash_add(mime_hash, "spr", "image/x-riscos-sprite"); + + if (fh == NULL) { + LOG(("Unable to open a mime.types file, so using a minimal one for you.")); + return; + } + + while (!feof(fh)) { + char line[256], *ptr, *type, *ext; + if (fgets(line, 256, fh) == NULL) + break; + if (!feof(fh) && line[0] != '#') { + ptr = line; + + /* search for the first non-whitespace character */ + while (isspace(*ptr)) + ptr++; + + /* is this line empty other than leading whitespace? */ + if (*ptr == '\n' || *ptr == '\0') + continue; + + type = ptr; + + /* search for the first non-whitespace char or NUL or + * NL */ + while (*ptr && (!isspace(*ptr)) && *ptr != '\n') + ptr++; + + if (*ptr == '\0' || *ptr == '\n') { + /* this mimetype has no extensions - read next + * line. + */ + continue; + } + + *ptr++ = '\0'; + + /* search for the first non-whitespace character which + * will be the first filename extenion */ + while (isspace(*ptr)) + ptr++; + + while(true) { + ext = ptr; + + /* search for the first whitespace char or + * NUL or NL which is the end of the ext. + */ + while (*ptr && (!isspace(*ptr)) && + *ptr != '\n') + ptr++; + + if (*ptr == '\0' || *ptr == '\n') { + /* special case for last extension on + * the line + */ + *ptr = '\0'; + hash_add(mime_hash, ext, type); + break; + } + + *ptr++ = '\0'; + hash_add(mime_hash, ext, type); + + /* search for the first non-whitespace char or + * NUL or NL, to find start of next ext. + */ + while (*ptr && (isspace(*ptr)) && *ptr != '\n') + ptr++; + } + } + } + + fclose(fh); +} + +void gtk_fetch_filetype_fin(void) +{ + hash_destroy(mime_hash); +} + +const char *fetch_filetype(const char *unix_path) +{ + struct stat statbuf; + char *ext; + const char *ptr; + char *lowerchar; + const char *type; + + stat(unix_path, &statbuf); + if (S_ISDIR(statbuf.st_mode)) + return "application/x-netsurf-directory"; + + if (strchr(unix_path, '.') == NULL) { + /* no extension anywhere! */ + return "text/plain"; + } + + ptr = unix_path + strlen(unix_path); + while (*ptr != '.' && *ptr != '/') + ptr--; + + if (*ptr != '.') + return "text/plain"; + + ext = strdup(ptr + 1); /* skip the . */ + + /* the hash table only contains lower-case versions - make sure this + * copy is lower case too. + */ + lowerchar = ext; + while(*lowerchar) { + *lowerchar = tolower(*lowerchar); + lowerchar++; + } + + type = hash_get(mime_hash, ext); + free(ext); + + return type != NULL ? type : "text/plain"; +} + +char *fetch_mimetype(const char *unix_path) +{ + return strdup(fetch_filetype(unix_path)); +} + +#ifdef TEST_RIG + +int main(int argc, char *argv[]) +{ + unsigned int c1, *c2; + const char *key; + + gtk_fetch_filetype_init("./mime.types"); + + c1 = 0; c2 = 0; + + while ( (key = hash_iterate(mime_hash, &c1, &c2)) != NULL) { + printf("%s ", key); + } + + printf("\n"); + + if (argc > 1) { + printf("%s maps to %s\n", argv[1], fetch_filetype(argv[1])); + } + + gtk_fetch_filetype_fin(); +} + +#endif diff --git a/gtk/filetype.h b/gtk/filetype.h new file mode 100644 index 000000000..8bf98db7c --- /dev/null +++ b/gtk/filetype.h @@ -0,0 +1,21 @@ +/* + * Copyright 2007 Rob Kendrick + * Copyright 2007 Vincent Sanders + * + * 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 . + */ + +void gtk_fetch_filetype_init(const char *mimefile); +void gtk_fetch_filetype_fin(void); diff --git a/gtk/font_pango.c b/gtk/font_pango.c index 0671d12fb..d512ae69f 100644 --- a/gtk/font_pango.c +++ b/gtk/font_pango.c @@ -26,10 +26,11 @@ #include #include #include + #include "css/css.h" #include "css/utils.h" #include "gtk/font_pango.h" -#include "gtk/gtk_plotters.h" +#include "gtk/plotters.h" #include "render/font.h" #include "utils/utils.h" #include "utils/log.h" diff --git a/gtk/gtk_bitmap.c b/gtk/gtk_bitmap.c deleted file mode 100644 index 1e9f6b40e..000000000 --- a/gtk/gtk_bitmap.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright 2004 James Bursa - * - * 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 . - */ - -/** \file - * Generic bitmap handling (GDK / GTK+ implementation). - * - * This implements the interface given by desktop/bitmap.h using GdkPixbufs. - */ - -#include -#include -#include -#include -#include -#include "content/content.h" -#include "gtk/gtk_bitmap.h" -#include "gtk/gtk_scaffolding.h" -#include "image/bitmap.h" -#include "utils/log.h" - - -struct bitmap { - GdkPixbuf *primary; - GdkPixbuf *pretile_x; - GdkPixbuf *pretile_y; - GdkPixbuf *pretile_xy; - bool opaque; -}; - -#define MIN_PRETILE_WIDTH 256 -#define MIN_PRETILE_HEIGHT 256 - - -/** - * 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 - * \return an opaque struct bitmap, or NULL on memory exhaustion - */ - -void *bitmap_create(int width, int height, unsigned int state) -{ - struct bitmap *bmp = malloc(sizeof(struct bitmap)); - - bmp->primary = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, - 8, width, height); - - /* fill the pixbuf in with 100% transparent black, as the memory - * won't have been cleared. - */ - gdk_pixbuf_fill(bmp->primary, 0); - bmp->pretile_x = bmp->pretile_y = bmp->pretile_xy = NULL; - bmp->opaque = (state & BITMAP_OPAQUE) != 0; - return bmp; -} - - -/** - * Sets whether a bitmap should be plotted opaque - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \param opaque whether the bitmap should be plotted opaque - */ -void bitmap_set_opaque(void *vbitmap, bool opaque) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - bitmap->opaque = opaque; -} - - -/** - * Tests whether a bitmap has an opaque alpha channel - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return whether the bitmap is opaque - */ -bool bitmap_test_opaque(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); -/* todo: test if bitmap is opaque */ - return false; -} - - -/** - * Gets whether a bitmap should be plotted opaque - * - * \param vbitmap a bitmap, as returned by bitmap_create() - */ -bool bitmap_get_opaque(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - return bitmap->opaque; -} - - -/** - * Return a pointer to the pixel data in a bitmap. - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return pointer to the pixel buffer - * - * The pixel data is packed as BITMAP_FORMAT, possibly with padding at the end - * of rows. The width of a row in bytes is given by bitmap_get_rowstride(). - */ - -unsigned char *bitmap_get_buffer(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - return (unsigned char *)gdk_pixbuf_get_pixels(bitmap->primary); -} - - -/** - * Find the width of a pixel row in bytes. - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return width of a pixel row in the bitmap - */ - -size_t bitmap_get_rowstride(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - return gdk_pixbuf_get_rowstride(bitmap->primary); -} - - -/** - * Find the bytes per pixel of a bitmap - * - * \param vbitmap a bitmap, as returned by bitmap_create() - * \return bytes per pixel - */ - -size_t bitmap_get_bpp(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - return 4; -} - - -static void -gtk_bitmap_free_pretiles(struct bitmap *bitmap) -{ -#define FREE_TILE(XY) if (bitmap->pretile_##XY) g_object_unref(bitmap->pretile_##XY); bitmap->pretile_##XY = NULL - FREE_TILE(x); - FREE_TILE(y); - FREE_TILE(xy); -#undef FREE_TILE -} - -/** - * Free a bitmap. - * - * \param vbitmap a bitmap, as returned by bitmap_create() - */ - -void bitmap_destroy(void *vbitmap) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - assert(bitmap); - gtk_bitmap_free_pretiles(bitmap); - g_object_unref(bitmap->primary); - free(bitmap); -} - - -/** - * 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 - */ - -bool bitmap_save(void *vbitmap, const char *path, unsigned flags) -{ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - GError *err = NULL; - - gdk_pixbuf_save(bitmap->primary, path, "png", &err, NULL); - - if (err == NULL) - /* TODO: report an error here */ - return false; - - return true; -} - - -/** - * The bitmap image has changed, so flush any persistant cache. - * - * \param bitmap a bitmap, as returned by bitmap_create() - */ -void bitmap_modified(void *vbitmap) { - struct bitmap *bitmap = (struct bitmap *)vbitmap; - gtk_bitmap_free_pretiles(bitmap); -} - - -/** - * The bitmap image can be suspended. - * - * \param bitmap a bitmap, as returned by bitmap_create() - * \param private_word a private word to be returned later - * \param invalidate the function to be called upon suspension - */ -void bitmap_set_suspendable(void *vbitmap, void *private_word, - void (*invalidate)(void *vbitmap, void *private_word)) { -} - -int bitmap_get_width(void *vbitmap){ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - return gdk_pixbuf_get_width(bitmap->primary); -} - -int bitmap_get_height(void *vbitmap){ - struct bitmap *bitmap = (struct bitmap *)vbitmap; - return gdk_pixbuf_get_height(bitmap->primary); -} - -static GdkPixbuf * -gtk_bitmap_generate_pretile(GdkPixbuf *primary, int repeat_x, int repeat_y) -{ - int width = gdk_pixbuf_get_width(primary); - int height = gdk_pixbuf_get_height(primary); - size_t primary_stride = gdk_pixbuf_get_rowstride(primary); - GdkPixbuf *result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, - width * repeat_x, height * repeat_y); - char *target_buffer = (char *)gdk_pixbuf_get_pixels(result); - int x,y,row; - /* This algorithm won't work if the strides are not multiples */ - assert((size_t)gdk_pixbuf_get_rowstride(result) == - (primary_stride * repeat_x)); - - if (repeat_x == 1 && repeat_y == 1) { - g_object_ref(primary); - g_object_unref(result); - return primary; - } - - for (y = 0; y < repeat_y; ++y) { - char *primary_buffer = (char *)gdk_pixbuf_get_pixels(primary); - for (row = 0; row < height; ++row) { - for (x = 0; x < repeat_x; ++x) { - memcpy(target_buffer, - primary_buffer, primary_stride); - target_buffer += primary_stride; - } - primary_buffer += primary_stride; - } - } - return result; -} - -/** - * The primary image associated with this bitmap object. - * - * \param bitmap a bitmap, as returned by bitmap_create() - */ -GdkPixbuf * -gtk_bitmap_get_primary(struct bitmap *bitmap) -{ - if (bitmap != NULL) - return bitmap->primary; - else - return NULL; -} - -/** - * The X-pretiled image associated with this bitmap object. - * - * \param bitmap a bitmap, as returned by bitmap_create() - */ -GdkPixbuf * -gtk_bitmap_get_pretile_x(struct bitmap* bitmap) -{ - if (!bitmap->pretile_x) { - int width = gdk_pixbuf_get_width(bitmap->primary); - int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; - LOG(("Pretiling %p for X*%d", bitmap, xmult)); - bitmap->pretile_x = gtk_bitmap_generate_pretile(bitmap->primary, xmult, 1); - } - return bitmap->pretile_x; - -} - -/** - * The Y-pretiled image associated with this bitmap object. - * - * \param bitmap a bitmap, as returned by bitmap_create() - */ -GdkPixbuf * -gtk_bitmap_get_pretile_y(struct bitmap* bitmap) -{ - if (!bitmap->pretile_y) { - int height = gdk_pixbuf_get_height(bitmap->primary); - int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; - LOG(("Pretiling %p for Y*%d", bitmap, ymult)); - bitmap->pretile_y = gtk_bitmap_generate_pretile(bitmap->primary, 1, ymult); - } - return bitmap->pretile_y; -} - -/** - * The XY-pretiled image associated with this bitmap object. - * - * \param bitmap a bitmap, as returned by bitmap_create() - */ -GdkPixbuf * -gtk_bitmap_get_pretile_xy(struct bitmap* bitmap) -{ - if (!bitmap->pretile_xy) { - int width = gdk_pixbuf_get_width(bitmap->primary); - int height = gdk_pixbuf_get_height(bitmap->primary); - int xmult = (MIN_PRETILE_WIDTH + width - 1)/width; - int ymult = (MIN_PRETILE_HEIGHT + height - 1)/height; - LOG(("Pretiling %p for X*%d Y*%d", bitmap, xmult, ymult)); - bitmap->pretile_xy = gtk_bitmap_generate_pretile(bitmap->primary, xmult, ymult); - } - return bitmap->pretile_xy; -} diff --git a/gtk/gtk_bitmap.h b/gtk/gtk_bitmap.h deleted file mode 100644 index d936f7d76..000000000 --- a/gtk/gtk_bitmap.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006 Daniel Silverstone - * - * 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 . - */ - -#ifndef NS_GTK_BITMAP_H -#define NS_GTK_BITMAP_H - -#include -#include -#include "image/bitmap.h" - -GdkPixbuf *gtk_bitmap_get_primary(struct bitmap*); -GdkPixbuf *gtk_bitmap_get_pretile_x(struct bitmap*); -GdkPixbuf *gtk_bitmap_get_pretile_y(struct bitmap*); -GdkPixbuf *gtk_bitmap_get_pretile_xy(struct bitmap*); - - - -#endif /* NS_GTK_BITMAP_H */ diff --git a/gtk/gtk_compat.c b/gtk/gtk_compat.c deleted file mode 100644 index f6ca5c3c4..000000000 --- a/gtk/gtk_compat.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2010 Rob Kendrick - * - * 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 . - */ - -/** \file - * Compatibility functions for older GTK versions (implementation) - */ - -#include "gtk/gtk_compat.h" - -void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus) -{ - #if GTK_CHECK_VERSION(2,22,0) - gtk_widget_set_can_focus(widget, can_focus); - #else - if (can_focus == TRUE) - GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); - else - GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_FOCUS); - #endif -} - -gboolean nsgtk_widget_has_focus(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,20,0) - return gtk_widget_has_focus(widget); - #else - return GTK_WIDGET_HAS_FOCUS(widget); - #endif -} - -gboolean nsgtk_widget_get_visible(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,20,0) - return gtk_widget_get_visible(widget); - #else - return GTK_WIDGET_VISIBLE(widget); - #endif -} - -gboolean nsgtk_widget_get_realized(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,20,0) - return gtk_widget_get_realized(widget); - #else - return GTK_WIDGET_REALIZED(widget); - #endif -} - -gboolean nsgtk_widget_get_mapped(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,20,0) - return gtk_widget_get_mapped(widget); - #else - return GTK_WIDGET_MAPPED(widget); - #endif -} - -gboolean nsgtk_widget_is_drawable(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,18,0) - return gtk_widget_is_drawable(widget); - #else - return GTK_WIDGET_DRAWABLE(widget); - #endif -} - -GtkStateType nsgtk_widget_get_state(GtkWidget *widget) -{ - #if GTK_CHECK_VERSION(2,18,0) - return gtk_widget_get_state(widget); - #else - return GTK_WIDGET_STATE(widget); - #endif -} - diff --git a/gtk/gtk_compat.h b/gtk/gtk_compat.h deleted file mode 100644 index 489fa7ea1..000000000 --- a/gtk/gtk_compat.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2010 Rob Kendrick - * - * 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 . - */ - -/** \file - * Compatibility functions for older GTK versions (interface) - */ - -#ifndef NETSURF_GTK_COMPAT_H_ -#define NETSURF_GTK_COMPAT_H_ - -#include - -void nsgtk_widget_set_can_focus(GtkWidget *widget, gboolean can_focus); -gboolean nsgtk_widget_has_focus(GtkWidget *widget); -gboolean nsgtk_widget_get_visible(GtkWidget *widget); -gboolean nsgtk_widget_get_realized(GtkWidget *widget); -gboolean nsgtk_widget_get_mapped(GtkWidget *widget); -gboolean nsgtk_widget_is_drawable(GtkWidget *widget); -GtkStateType nsgtk_widget_get_state(GtkWidget *widget); - -#endif /* NETSURF_GTK_COMPAT_H */ diff --git a/gtk/gtk_completion.c b/gtk/gtk_completion.c deleted file mode 100644 index 8566f1c6d..000000000 --- a/gtk/gtk_completion.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * - * 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 . - */ - -#include -#include "gtk/gtk_completion.h" -#include "content/urldb.h" -#include "utils/log.h" -#include "desktop/options.h" - -GtkListStore *nsgtk_completion_list; - -static void nsgtk_completion_empty(void); -static bool nsgtk_completion_udb_callback(const char *url, - const struct url_data *data); - -void nsgtk_completion_init(void) -{ - nsgtk_completion_list = gtk_list_store_new(1, G_TYPE_STRING); - -} - -gboolean nsgtk_completion_match(GtkEntryCompletion *completion, - const gchar *key, - GtkTreeIter *iter, - gpointer user_data) -{ - char *b[4096]; /* no way of finding out its length :( */ - gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_completion_list), iter, - 0, b, -1); - - /* TODO: work out why this works, when there's no code to implement - * it. I boggle. */ - - return TRUE; - -} - -void nsgtk_completion_empty(void) -{ - gtk_list_store_clear(nsgtk_completion_list); -} - -bool nsgtk_completion_udb_callback(const char *url, const struct url_data *data) -{ - GtkTreeIter iter; - - if (data->visits != 0) { - gtk_list_store_append(nsgtk_completion_list, &iter); - gtk_list_store_set(nsgtk_completion_list, &iter, 0, url, -1); - } - return true; -} - -void nsgtk_completion_update(const char *prefix) -{ - nsgtk_completion_empty(); - if (option_url_suggestion == true) - urldb_iterate_partial(prefix, nsgtk_completion_udb_callback); -} diff --git a/gtk/gtk_completion.h b/gtk/gtk_completion.h deleted file mode 100644 index 67de43d8e..000000000 --- a/gtk/gtk_completion.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * - * 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 . - */ - -#ifndef _NETSURF_GTK_COMPLETION_H_ -#define _NETSURF_GTK_COMPLETION_H_ - -#include - -extern GtkListStore *nsgtk_completion_list; - -void nsgtk_completion_init(void); -void nsgtk_completion_update(const char *prefix); -gboolean nsgtk_completion_match(GtkEntryCompletion *completion, - const gchar *key, - GtkTreeIter *iter, - gpointer user_data); -#endif diff --git a/gtk/gtk_cookies.c b/gtk/gtk_cookies.c deleted file mode 100644 index 12fa9cc14..000000000 --- a/gtk/gtk_cookies.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -/** \file - * Cookies (implementation). - */ - - -#include "desktop/cookies.h" -#include "desktop/plotters.h" -#include "desktop/tree.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_cookies.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_treeview.h" - -#define GLADE_NAME "cookies.glade" - -#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ - GtkMenuItem *widget, gpointer g) -#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } -#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ - gpointer g) - -struct menu_events { - const char *widget; - GCallback handler; -}; - -static void nsgtk_cookies_init_menu(void); - -/* edit menu */ -MENUPROTO(delete_selected); -MENUPROTO(delete_all); -MENUPROTO(select_all); -MENUPROTO(clear_selection); - -/* view menu*/ -MENUPROTO(expand_all); -MENUPROTO(expand_domains); -MENUPROTO(expand_cookies); -MENUPROTO(collapse_all); -MENUPROTO(collapse_domains); -MENUPROTO(collapse_cookies); - - -static struct menu_events menu_events[] = { - - /* edit menu */ - MENUEVENT(delete_selected), - MENUEVENT(delete_all), - MENUEVENT(select_all), - MENUEVENT(clear_selection), - - /* view menu*/ - MENUEVENT(expand_all), - MENUEVENT(expand_domains), - MENUEVENT(expand_cookies), - MENUEVENT(collapse_all), - MENUEVENT(collapse_domains), - MENUEVENT(collapse_cookies), - - {NULL, NULL} -}; - -static struct nsgtk_treeview *cookies_window; -static GladeXML *gladeFile; -GtkWindow *wndCookies; - -/** - * Creates the window for the cookies tree. - */ -bool nsgtk_cookies_init(const char *glade_file_location) -{ - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; - - gladeFile = glade_xml_new(glade_file_location, NULL, NULL); - if (gladeFile == NULL) - return false; - - glade_xml_signal_autoconnect(gladeFile); - - wndCookies = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndCookies")); - window = wndCookies; - - scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, - "cookiesScrolled")); - - drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, - "cookiesDrawingArea")); - - cookies_window = nsgtk_treeview_create(cookies_get_tree_flags(), window, - scrolled, drawing_area); - - if (cookies_window == NULL) - return false; - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); - CONNECT(window, "hide", nsgtk_tree_window_hide, cookies_window); - - cookies_initialise(nsgtk_treeview_get_tree(cookies_window), - tree_directory_icon_name, - tree_content_icon_name); - - nsgtk_cookies_init_menu(); - - return true; -} - -/** - * Connects menu events in the cookies window. - */ -void nsgtk_cookies_init_menu() -{ - struct menu_events *event = menu_events; - - while (event->widget != NULL) - { - GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); - g_signal_connect(G_OBJECT(w), "activate", event->handler, - cookies_window); - event++; - } -} - -/** - * Destroys the cookies window and performs any other necessary cleanup actions. - */ -void nsgtk_cookies_destroy(void) -{ - /* TODO: what about gladeFile? */ - cookies_cleanup(); - nsgtk_treeview_destroy(cookies_window); -} - - -/* edit menu */ -MENUHANDLER(delete_selected) -{ - cookies_delete_selected(); - return TRUE; -} - -MENUHANDLER(delete_all) -{ - cookies_delete_all(); - return TRUE; -} - -MENUHANDLER(select_all) -{ - cookies_select_all(); - return TRUE; -} - -MENUHANDLER(clear_selection) -{ - cookies_clear_selection(); - return TRUE; -} - -/* view menu*/ -MENUHANDLER(expand_all) -{ - cookies_expand_all(); - return TRUE; -} - -MENUHANDLER(expand_domains) -{ - cookies_expand_domains(); - return TRUE; -} - -MENUHANDLER(expand_cookies) -{ - cookies_expand_cookies(); - return TRUE; -} - -MENUHANDLER(collapse_all) -{ - cookies_collapse_all(); - return TRUE; -} - -MENUHANDLER(collapse_domains) -{ - cookies_collapse_domains(); - return TRUE; -} - -MENUHANDLER(collapse_cookies) -{ - cookies_collapse_cookies(); - return TRUE; -} diff --git a/gtk/gtk_cookies.h b/gtk/gtk_cookies.h deleted file mode 100644 index db12dfe31..000000000 --- a/gtk/gtk_cookies.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -/** \file - * Cookies (interface). - */ - -#ifndef __NSGTK_COOKIES_H__ -#define __NSGTK_COOKIES_H__ - -#include - -extern GtkWindow *wndCookies; - -bool nsgtk_cookies_init(const char *glade_file_location); - -void nsgtk_cookies_destroy(void); - -#endif /* __NSGTK_COOKIES_H__ */ diff --git a/gtk/gtk_download.c b/gtk/gtk_download.c deleted file mode 100644 index a91f25188..000000000 --- a/gtk/gtk_download.c +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Copyright 2008 Michael Lester - * - * 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 . - */ - -#include -#include -#include - -#include -#include - -#include "utils/log.h" -#include "utils/utils.h" -#include "utils/url.h" -#include "utils/messages.h" -#include "desktop/gui.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/options.h" -#include "gtk/gtk_download.h" -#include "gtk/gtk_window.h" -#include "gtk/gtk_compat.h" - -#define UPDATE_RATE 500 /* In milliseconds */ - -static GtkWindow *nsgtk_download_window, *nsgtk_download_parent; -static GtkProgressBar *nsgtk_download_progress_bar; - -static GtkTreeView *nsgtk_download_tree; -static GtkListStore *nsgtk_download_store; -static GtkTreeSelection *nsgtk_download_selection; -static GtkTreeIter nsgtk_download_iter; - -static GTimer *nsgtk_downloads_timer; -static GList *nsgtk_downloads_list, *nsgtk_download_buttons; -static gint nsgtk_downloads_num_active; -static const gchar* status_messages[] = { NULL, "gtkWorking", "gtkError", - "gtkComplete", "gtkCanceled" }; - -static gboolean nsgtk_download_hide(GtkWidget *window); - -static GtkTreeView *nsgtk_download_tree_view_new(GladeXML *gladeFile); -static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, - GtkTreePath *path, GtkTreeViewColumn *column, gpointer data); - -static gint nsgtk_download_sort(GtkTreeModel *model, GtkTreeIter *a, - GtkTreeIter *b, gpointer userdata); -static gboolean nsgtk_download_update(gboolean force_update); -static void nsgtk_download_do(nsgtk_download_selection_action action); - -static void nsgtk_download_store_update_item(struct gui_download_window *dl); -static void nsgtk_download_store_create_item (struct gui_download_window *dl); -static void nsgtk_download_store_clear_item (struct gui_download_window *dl); -static void nsgtk_download_store_cancel_item (struct gui_download_window *dl); - -static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection); -static void nsgtk_download_sensitivity_update_buttons( - nsgtk_download_actions sensitivity); - -static void nsgtk_download_change_sensitivity( - struct gui_download_window *dl, nsgtk_download_actions sens); -static void nsgtk_download_change_status ( - struct gui_download_window *dl, nsgtk_download_status status); - -static gchar* nsgtk_download_dialog_show (gchar *filename, gchar *domain, - const gchar *size); -static gchar* nsgtk_download_info_to_string (struct gui_download_window *dl); -static gchar* nsgtk_download_time_to_string (gint seconds); -static gboolean nsgtk_download_handle_error (GError *error); - - - -bool nsgtk_download_init(const char *glade_file_location) -{ - GladeXML *gladeFile; - - gladeFile = glade_xml_new(glade_file_location, NULL, NULL); - if (gladeFile == NULL) - return false; - - nsgtk_download_buttons = - glade_xml_get_widget_prefix(gladeFile, "button"); - nsgtk_download_progress_bar = GTK_PROGRESS_BAR(glade_xml_get_widget( - gladeFile, "progressBar")); - nsgtk_download_window = GTK_WINDOW(glade_xml_get_widget(gladeFile, - "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(gladeFile); - - 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(glade_xml_get_widget(gladeFile, "buttonClear"), - "clicked", G_CALLBACK(nsgtk_download_do), - nsgtk_download_store_clear_item); - g_signal_connect_swapped(glade_xml_get_widget(gladeFile, - "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 true; -} - -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, - "%s\n\n" - "%s", 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); -} - -gboolean nsgtk_download_hide (GtkWidget *window) -{ - gtk_widget_hide(window); - return TRUE; -} - -struct gui_download_window *gui_download_window_create(download_context *ctx, - struct gui_window *gui) -{ - const char *url = download_context_get_url(ctx); - unsigned long total_size = download_context_get_total_length(ctx); - gchar *domain; - gchar *filename; - gchar *destination; - gboolean unknown_size = total_size == 0; - const char *size = (total_size == 0 ? - messages_get("gtkUnknownSize") : - human_friendly_bytesize(total_size)); - - nsgtk_download_parent = - nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); - - struct gui_download_window *download = malloc(sizeof *download); - if (download == NULL) - return NULL; - - if (url_nice(url, &filename, false) != URL_FUNC_OK) { - filename = g_strdup(messages_get("gtkUnknownFile")); - if (filename == NULL) { - free(download); - return NULL; - } - } - - if (url_host(url, &domain) != URL_FUNC_OK) { - domain = g_strdup(messages_get("gtkUnknownHost")); - if (domain == NULL) { - g_free(filename); - free(download); - return NULL; - } - } - - destination = nsgtk_download_dialog_show(filename, domain, size); - if (destination == NULL) { - g_free(domain); - g_free(filename); - free(download); - return NULL; - } - - /* 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); - 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)); - - download->ctx = ctx; - download->name = g_string_new(filename); - download->time_left = g_string_new(""); - download->size_total = total_size; - download->size_downloaded = 0; - download->speed = 0; - download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL); - download->time_remaining = -1; - download->status = NSGTK_DOWNLOAD_NONE; - download->filename = destination; - download->progress = 0; - download->error = NULL; - download->write = - g_io_channel_new_file(destination, "w", &download->error); - - if (nsgtk_download_handle_error(download->error)) { - g_string_free(download->name, TRUE); - g_string_free(download->time_left, TRUE); - g_free(download->filename); - free(download); - return NULL; - } - g_io_channel_set_encoding(download->write, NULL, &download->error); - - nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); - - nsgtk_download_store_create_item(download); - nsgtk_download_show(nsgtk_download_parent); - - 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); - } - - nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download); - - return download; -} - - -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) { - dw->speed = 0; - dw->time_remaining = -1; - - nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); - nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_ERROR); - - nsgtk_download_update(TRUE); - - gtk_window_present(nsgtk_download_window); - - return NSERROR_SAVE_FAILED; - } - dw->size_downloaded += size; - - return NSERROR_OK; -} - - -void gui_download_window_error(struct gui_download_window *dw, - const char *error_msg) -{ -} - - -void gui_download_window_done(struct gui_download_window *dw) -{ - g_io_channel_shutdown(dw->write, TRUE, &dw->error); - g_io_channel_unref(dw->write); - - dw->speed = 0; - dw->time_remaining = -1; - dw->progress = 100; - dw->size_total = dw->size_downloaded; - nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); - nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE); - - if (option_downloads_clear) - nsgtk_download_store_clear_item(dw); - else - nsgtk_download_update(TRUE); -} - - -GtkTreeView* nsgtk_download_tree_view_new(GladeXML *gladeFile) -{ - GtkTreeView *treeview = GTK_TREE_VIEW(glade_xml_get_widget(gladeFile, - "treeDownloads")); - GtkCellRenderer *renderer; - - /* 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); - - /* 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); - - /* 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); - - /* 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); - - return treeview; -} - -void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, - GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model(tree); - - if (gtk_tree_model_get_iter(model, &iter, path)) { - /* TODO: This will be a context action (pause, start, clear) */ - nsgtk_download_do(nsgtk_download_store_clear_item); - } -} - -gint nsgtk_download_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, - gpointer userdata) -{ - struct gui_download_window *dl1, *dl2; - - gtk_tree_model_get(model, a, NSGTK_DOWNLOAD, &dl1, -1); - gtk_tree_model_get(model, b, NSGTK_DOWNLOAD, &dl2, -1); - - return dl1->status - dl2->status; -} - -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); - - if (selection_exists) { - rows = gtk_tree_selection_get_selected_rows( - nsgtk_download_selection, &model); - while (rows != NULL) { - struct gui_download_window *dl; - gtk_tree_model_get_iter(GTK_TREE_MODEL( - nsgtk_download_store), - &nsgtk_download_iter, - (GtkTreePath*)rows->data); - gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_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_free(rows); - } else - dls = g_list_copy(nsgtk_downloads_list); - - g_list_foreach(dls, (GFunc)action, NULL); - g_list_free(dls); -} - -gboolean nsgtk_download_update(gboolean force_update) -{ - /* Be sure we need to update */ - if (!nsgtk_widget_get_visible(GTK_WIDGET(nsgtk_download_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; - - for (list = nsgtk_downloads_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; - - case NSGTK_DOWNLOAD_NONE: - dl->speed = dl->size_downloaded / - (elapsed - dl->start_time); - if (dl->status == NSGTK_DOWNLOAD_NONE) { - dl->time_remaining = (dl->size_total - - dl->size_downloaded)/ - dl->speed; - dl->progress = (gfloat) - dl->size_downloaded / - dl->size_total * 100; - } else - dl->progress++; - - nsgtk_downloads_num_active++; - update = TRUE; - - case NSGTK_DOWNLOAD_COMPLETE: - downloaded += dl->size_downloaded; - total += dl->size_total; - dls++; - - default: - ;//Do nothing - - } - if (update) - nsgtk_download_store_update_item(dl); - } - - if (pulse_mode) { - text = g_strdup_printf( - messages_get(nsgtk_downloads_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); - } else { - percent = total != 0 ? (gfloat)downloaded / total : 0; - text = g_strdup_printf(messages_get("gtkProgressBar"), - floor(percent*100), dls); - gtk_progress_bar_set_fraction(nsgtk_download_progress_bar, - percent); - gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); - } - - g_free(text); - - if (nsgtk_downloads_num_active == 0) - return FALSE; /* Returning FALSE here cancels the g_timeout */ - else - return TRUE; -} - -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); - char speed[strlen(human) + SLEN("/s") + 1]; - sprintf(speed, "%s/s", human); - gchar *time = nsgtk_download_time_to_string(dl->time_remaining); - 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_row_reference_get_path(dl->row)); - - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, - NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1, - NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress, - NSGTK_DOWNLOAD_INFO, info, - NSGTK_DOWNLOAD_SPEED, dl->speed == 0 ? "-" : speed, - NSGTK_DOWNLOAD_REMAINING, time, - NSGTK_DOWNLOAD, dl, - -1); - - g_free(info); - g_free(time); -} - -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); -} - -void nsgtk_download_store_clear_item (struct gui_download_window *dl) -{ - if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) { - nsgtk_downloads_list = g_list_remove(nsgtk_downloads_list, dl); - - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, - gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_remove(nsgtk_download_store, - &nsgtk_download_iter); - - download_context_destroy(dl->ctx); - g_string_free(dl->name, TRUE); - g_string_free(dl->time_left, TRUE); - g_free(dl->filename); - g_free(dl); - - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); - nsgtk_download_update(FALSE); - } -} - -void nsgtk_download_store_cancel_item (struct gui_download_window *dl) -{ - if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) { - dl->speed = 0; - dl->size_downloaded = 0; - dl->progress = 0; - dl->time_remaining = -1; - nsgtk_download_change_sensitivity(dl, NSGTK_DOWNLOAD_CLEAR); - nsgtk_download_change_status(dl, NSGTK_DOWNLOAD_CANCELED); - - download_context_abort(dl->ctx); - - g_unlink(dl->filename); - - nsgtk_download_update(TRUE); - } -} - -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); - nsgtk_download_actions sensitivity = 0; - struct gui_download_window *dl; - - if (selected) { - rows = gtk_tree_selection_get_selected_rows(selection, &model); - while (rows != NULL) { - gtk_tree_model_get_iter(model, &iter, - (GtkTreePath*)rows->data); - gtk_tree_model_get(model, &iter, NSGTK_DOWNLOAD, - &dl, -1); - sensitivity |= dl->sensitivity; - rows = rows->next; - } - } else { - rows = nsgtk_downloads_list; - while (rows != NULL) { - dl = rows->data; - sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR); - rows = rows->next; - } - } - - - nsgtk_download_sensitivity_update_buttons(sensitivity); -} - -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(g_list_nth_data(nsgtk_download_buttons, - PAUSE_BUTTON), sensitivity & NSGTK_DOWNLOAD_PAUSE); - gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, - CLEAR_BUTTON), sensitivity & NSGTK_DOWNLOAD_CLEAR); - gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, - CANCEL_BUTTON), sensitivity & NSGTK_DOWNLOAD_CANCEL); - gtk_widget_set_sensitive(g_list_nth_data(nsgtk_download_buttons, - RESUME_BUTTON), sensitivity & NSGTK_DOWNLOAD_RESUME); -} - -void nsgtk_download_change_sensitivity(struct gui_download_window *dl, - nsgtk_download_actions sensitivity) -{ - dl->sensitivity = sensitivity; - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); -} - -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_row_reference_get_path(dl->row)); - - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, - NSGTK_DOWNLOAD_STATUS, - messages_get(status_messages[status]), -1); - } -} - -gchar* nsgtk_download_dialog_show (gchar *filename, 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, - "%s" - "\n\n%s", - message, info); - - gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_SAVE, - GTK_RESPONSE_DOWNLOAD, GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE_AS, - GTK_RESPONSE_SAVE_AS, NULL); - - gint result = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - g_free(message); - g_free(info); - - switch (result) { - case GTK_RESPONSE_SAVE_AS: { - dialog = gtk_file_chooser_dialog_new - (messages_get("gtkSave"), - nsgtk_download_parent, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_current_name - (GTK_FILE_CHOOSER(dialog), filename); - gtk_file_chooser_set_current_folder - (GTK_FILE_CHOOSER(dialog), - option_downloads_directory); - gtk_file_chooser_set_do_overwrite_confirmation - (GTK_FILE_CHOOSER(dialog), - option_request_overwrite); - - gint result = gtk_dialog_run(GTK_DIALOG(dialog)); - if (result == GTK_RESPONSE_ACCEPT) - destination = gtk_file_chooser_get_filename - (GTK_FILE_CHOOSER(dialog)); - gtk_widget_destroy(dialog); - break; - } - case GTK_RESPONSE_DOWNLOAD: { - destination = malloc(strlen(option_downloads_directory) - + strlen(filename) + SLEN("/") + 1); - if (destination == NULL) { - warn_user(messages_get("NoMemory"), 0); - break; - } - sprintf(destination, "%s/%s", - option_downloads_directory, filename); - /* Test if file already exists and display overwrite - * confirmation if needed */ - if (g_file_test(destination, G_FILE_TEST_EXISTS) - && option_request_overwrite) { - message = g_strdup_printf(messages_get( - "gtkOverwrite"), filename); - info = g_strdup_printf(messages_get( - "gtkOverwriteInfo"), - option_downloads_directory); - - dialog = gtk_message_dialog_new_with_markup( - nsgtk_download_parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_CANCEL, - "%s",message); - gtk_message_dialog_format_secondary_markup( - GTK_MESSAGE_DIALOG(dialog), - "%s", info); - - GtkWidget *button = gtk_dialog_add_button( - GTK_DIALOG(dialog), - "_Replace", - GTK_RESPONSE_DOWNLOAD); - gtk_button_set_image(GTK_BUTTON(button), - gtk_image_new_from_stock( - "gtk-save", - GTK_ICON_SIZE_BUTTON)); - - gint result = gtk_dialog_run(GTK_DIALOG( - dialog)); - if (result == GTK_RESPONSE_CANCEL) - destination = NULL; - - gtk_widget_destroy(dialog); - g_free(message); - g_free(info); - } - break; - } - } - return destination; -} - -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 *r; - - 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); - - g_free(size_info); - - return r; -} - -gchar* nsgtk_download_time_to_string (gint seconds) -{ - gint hours, minutes; - - 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, - seconds); - else - return g_strdup_printf("%u:%02u", minutes, seconds); -} - -gboolean nsgtk_download_handle_error (GError *error) -{ - 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, - "%s\n\n" - "%s", messages_get("gtkFailed"), - message); - - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - return TRUE; - } - return FALSE; -} - - diff --git a/gtk/gtk_download.h b/gtk/gtk_download.h deleted file mode 100644 index 7e8226ce9..000000000 --- a/gtk/gtk_download.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2008 Michael Lester - * - * 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 . - */ - -#ifndef GTK_DOWNLOAD_H -#define GTK_DOWNLOAD_H - -#include - -struct download_context; - -enum { - NSGTK_DOWNLOAD_PROGRESS, - NSGTK_DOWNLOAD_INFO, - NSGTK_DOWNLOAD_REMAINING, - NSGTK_DOWNLOAD_SPEED, - NSGTK_DOWNLOAD_PULSE, - NSGTK_DOWNLOAD_STATUS, - NSGTK_DOWNLOAD, - - NSGTK_DOWNLOAD_N_COLUMNS -}; - -typedef enum { - NSGTK_DOWNLOAD_NONE, - NSGTK_DOWNLOAD_WORKING, - NSGTK_DOWNLOAD_ERROR, - NSGTK_DOWNLOAD_COMPLETE, - NSGTK_DOWNLOAD_CANCELED -} nsgtk_download_status; - -typedef enum { - NSGTK_DOWNLOAD_PAUSE = 1 << 0, - NSGTK_DOWNLOAD_RESUME = 1 << 1, - NSGTK_DOWNLOAD_CANCEL = 1 << 2, - NSGTK_DOWNLOAD_CLEAR = 1 << 3 -} nsgtk_download_actions; - -struct gui_download_window { - struct download_context *ctx; - nsgtk_download_actions sensitivity; - nsgtk_download_status status; - - GString *name; - GString *time_left; - gint size_total; - gint size_downloaded; - gint progress; - gfloat time_remaining; - gfloat start_time; - gfloat speed; - gchar *filename; - - GtkTreeRowReference *row; - GIOChannel *write; - GError *error; -}; - -typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl); - -bool nsgtk_download_init(const char *glade_file_location); -void nsgtk_download_destroy (void); -bool nsgtk_check_for_downloads(GtkWindow *parent); -void nsgtk_download_show(GtkWindow *parent); -void nsgtk_download_add(gchar *url, gchar *destination); - -#endif diff --git a/gtk/gtk_filetype.c b/gtk/gtk_filetype.c deleted file mode 100644 index 51b632db8..000000000 --- a/gtk/gtk_filetype.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2007 Rob Kendrick - * Copyright 2007 Vincent Sanders - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gtk/gtk_filetype.h" -#include "content/fetch.h" -#include "utils/log.h" -#include "utils/hashtable.h" - -static struct hash_table *mime_hash = NULL; - -void gtk_fetch_filetype_init(const char *mimefile) -{ - struct stat statbuf; - FILE *fh = NULL; - - mime_hash = hash_create(117); - - /* first, check to see if /etc/mime.types in preference */ - - if ((stat("/etc/mime.types", &statbuf) == 0) && - S_ISREG(statbuf.st_mode)) { - mimefile = "/etc/mime.types"; - - } - - fh = fopen(mimefile, "r"); - - /* Some OSes (mentioning no Solarises) have a worthlessly tiny - * /etc/mime.types that don't include essential things, so we - * pre-seed our hash with the essentials. These will get - * over-ridden if they are mentioned in the mime.types file. - */ - - hash_add(mime_hash, "css", "text/css"); - hash_add(mime_hash, "htm", "text/html"); - 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, "gif", "image/gif"); - hash_add(mime_hash, "png", "image/png"); - hash_add(mime_hash, "jng", "image/jng"); - hash_add(mime_hash, "mng", "image/mng"); - hash_add(mime_hash, "webp", "image/webp"); - hash_add(mime_hash, "spr", "image/x-riscos-sprite"); - - if (fh == NULL) { - LOG(("Unable to open a mime.types file, so using a minimal one for you.")); - return; - } - - while (!feof(fh)) { - char line[256], *ptr, *type, *ext; - if (fgets(line, 256, fh) == NULL) - break; - if (!feof(fh) && line[0] != '#') { - ptr = line; - - /* search for the first non-whitespace character */ - while (isspace(*ptr)) - ptr++; - - /* is this line empty other than leading whitespace? */ - if (*ptr == '\n' || *ptr == '\0') - continue; - - type = ptr; - - /* search for the first non-whitespace char or NUL or - * NL */ - while (*ptr && (!isspace(*ptr)) && *ptr != '\n') - ptr++; - - if (*ptr == '\0' || *ptr == '\n') { - /* this mimetype has no extensions - read next - * line. - */ - continue; - } - - *ptr++ = '\0'; - - /* search for the first non-whitespace character which - * will be the first filename extenion */ - while (isspace(*ptr)) - ptr++; - - while(true) { - ext = ptr; - - /* search for the first whitespace char or - * NUL or NL which is the end of the ext. - */ - while (*ptr && (!isspace(*ptr)) && - *ptr != '\n') - ptr++; - - if (*ptr == '\0' || *ptr == '\n') { - /* special case for last extension on - * the line - */ - *ptr = '\0'; - hash_add(mime_hash, ext, type); - break; - } - - *ptr++ = '\0'; - hash_add(mime_hash, ext, type); - - /* search for the first non-whitespace char or - * NUL or NL, to find start of next ext. - */ - while (*ptr && (isspace(*ptr)) && *ptr != '\n') - ptr++; - } - } - } - - fclose(fh); -} - -void gtk_fetch_filetype_fin(void) -{ - hash_destroy(mime_hash); -} - -const char *fetch_filetype(const char *unix_path) -{ - struct stat statbuf; - char *ext; - const char *ptr; - char *lowerchar; - const char *type; - - stat(unix_path, &statbuf); - if (S_ISDIR(statbuf.st_mode)) - return "application/x-netsurf-directory"; - - if (strchr(unix_path, '.') == NULL) { - /* no extension anywhere! */ - return "text/plain"; - } - - ptr = unix_path + strlen(unix_path); - while (*ptr != '.' && *ptr != '/') - ptr--; - - if (*ptr != '.') - return "text/plain"; - - ext = strdup(ptr + 1); /* skip the . */ - - /* the hash table only contains lower-case versions - make sure this - * copy is lower case too. - */ - lowerchar = ext; - while(*lowerchar) { - *lowerchar = tolower(*lowerchar); - lowerchar++; - } - - type = hash_get(mime_hash, ext); - free(ext); - - return type != NULL ? type : "text/plain"; -} - -char *fetch_mimetype(const char *unix_path) -{ - return strdup(fetch_filetype(unix_path)); -} - -#ifdef TEST_RIG - -int main(int argc, char *argv[]) -{ - unsigned int c1, *c2; - const char *key; - - gtk_fetch_filetype_init("./mime.types"); - - c1 = 0; c2 = 0; - - while ( (key = hash_iterate(mime_hash, &c1, &c2)) != NULL) { - printf("%s ", key); - } - - printf("\n"); - - if (argc > 1) { - printf("%s maps to %s\n", argv[1], fetch_filetype(argv[1])); - } - - gtk_fetch_filetype_fin(); -} - -#endif diff --git a/gtk/gtk_filetype.h b/gtk/gtk_filetype.h deleted file mode 100644 index 8bf98db7c..000000000 --- a/gtk/gtk_filetype.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2007 Rob Kendrick - * Copyright 2007 Vincent Sanders - * - * 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 . - */ - -void gtk_fetch_filetype_init(const char *mimefile); -void gtk_fetch_filetype_fin(void); diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c deleted file mode 100644 index 399cf138f..000000000 --- a/gtk/gtk_gui.c +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * Copyright 2004-2010 James Bursa - * Copyright 2010 Vincent Sanders - * Copyright 2004-2009 John-Mark Bell - * Copyright 2009 Paul Blokus - * Copyright 2006-2009 Daniel Silverstone - * Copyright 2006-2008 Rob Kendrick - * Copyright 2008 John Tytgat - * Copyright 2008 Adam Blokus - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "content/content.h" -#include "content/fetch.h" -#include "content/fetchers/fetch_curl.h" -#include "content/hlcache.h" -#include "content/urldb.h" -#include "desktop/browser.h" -#include "desktop/cookies.h" -#include "desktop/gui.h" -#include "desktop/history_global_core.h" -#include "desktop/netsurf.h" -#include "desktop/options.h" -#include "desktop/save_pdf/pdf_plotters.h" -#include "desktop/searchweb.h" -#include "desktop/sslcert.h" -#include "desktop/textinput.h" -#include "desktop/tree.h" -#include "css/utils.h" -#include "gtk/dialogs/gtk_options.h" -#include "gtk/gtk_completion.h" -#include "gtk/gtk_cookies.h" -#include "gtk/gtk_download.h" -#include "gtk/gtk_filetype.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_history.h" -#include "gtk/gtk_hotlist.h" -#include "gtk/gtk_throbber.h" -#include "gtk/gtk_treeview.h" -#include "gtk/gtk_window.h" -#include "gtk/options.h" -#include "gtk/gtk_schedule.h" - -#include "render/box.h" -#include "render/form.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/url.h" -#include "utils/utf8.h" -#include "utils/utils.h" -#include "utils/findresource.h" - -char *default_stylesheet_url; -char *quirks_stylesheet_url; -char *adblock_stylesheet_url; -char *options_file_location; -char *toolbar_indices_file_location; -char *res_dir_location; -char *print_options_file_location; -char *languages_file_location; - -char *glade_netsurf_file_location; -char *glade_password_file_location; -char *glade_warning_file_location; -char *glade_login_file_location; -char *glade_ssl_file_location; -char *glade_toolbar_file_location; -char *glade_options_file_location; - -static char *glade_downloads_file_location; -static char *glade_history_file_location; -static char *glade_hotlist_file_location; -static char *glade_cookies_file_location; - -static GtkWindow *nsgtk_warning_window; -GtkWidget *widWarning; - -static GtkWidget *select_menu; -static struct browser_window *select_menu_bw; -static struct form_control *select_menu_control; - -static void nsgtk_ssl_accept(GtkButton *w, gpointer data); -static void nsgtk_ssl_reject(GtkWidget *w, gpointer data); -static gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event, - gpointer data); -static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, - gpointer user_data); -#ifdef WITH_PDF_EXPORT -static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data); -static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data); -#endif - -#define THROBBER_FRAMES 9 - -#define MAX_RESPATH 128 /* maximum number of elements in the resource vector */ - -/* expand ${} in a string into environment variables */ -static char * -expand_path(const char *path) -{ - char *exp = strdup(path); - int explen; - int cstart = -1; - int cloop = 0; - char *envv; - int envlen; - int replen; /* length of replacement */ - - if (exp == NULL) - return NULL; - - explen = strlen(exp) + 1; - - while (exp[cloop] != 0) { - if ((exp[cloop] == '$') && - (exp[cloop + 1] == '{')) { - cstart = cloop; - cloop++; - } - - if ((cstart != -1) && - (exp[cloop] == '}')) { - replen = cloop - cstart; - exp[cloop] = 0; - envv = getenv(exp + cstart + 2); - if (envv == NULL) { - memmove(exp + cstart, - exp + cloop + 1, - explen - cloop - 1); - explen -= replen; - } else { - envlen = strlen(envv); - exp = realloc(exp, explen + envlen - replen); - memmove(exp + cstart + envlen, - exp + cloop + 1, - explen - cloop - 1); - memmove(exp + cstart, envv, envlen); - explen += envlen - replen; - } - cloop -= replen; - cstart = -1; - } - - cloop++; - } - - return exp; -} - -/* convert a colon separated list of path elements into a string vector */ -static char ** -path_to_strvec(const char *path) -{ - char **strvec; - int strc = 0; - - strvec = calloc(MAX_RESPATH, sizeof(char *)); - if (strvec == NULL) - return NULL; - - strvec[strc] = expand_path(path); - if (strvec[strc] == NULL) { - free(strvec); - return NULL; - } - strc++; - - strvec[strc] = strchr(strvec[0], ':'); - while ((strc < (MAX_RESPATH - 2)) && - (strvec[strc] != NULL)) { - /* null terminate previous entry */ - *strvec[strc] = 0; - strvec[strc]++; - - /* skip colons */ - while (*strvec[strc] == ':') - strvec[strc]++; - - if (*strvec[strc] == 0) - break; /* string is terminated */ - - strc++; - - strvec[strc] = strchr(strvec[strc - 1], ':'); - } - - return strvec; -} - - -/** 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(const char *resource_path) -{ - const gchar * const *langv; - char **pathv; /* resource path string vector */ - char **respath; /* resource paths vector */ - - pathv = path_to_strvec(resource_path); - - langv = g_get_language_names(); - - respath = findresource_generate(pathv, langv); - - free(pathv[0]); - free(pathv); - - return respath; -} - -/* This is an ugly hack to just get the new-style throbber going. - * It, along with the PNG throbber loader, need making more generic. - */ -static bool nsgtk_throbber_init(char **respath, int framec) -{ - char **filenames; - char targetname[PATH_MAX]; - int frame_num; - bool ret; - - filenames = calloc(framec, sizeof(char *)); - if (filenames == NULL) - return false; - - for (frame_num = 0; frame_num < framec; frame_num++) { - snprintf(targetname, PATH_MAX, "throbber/throbber%d.png", frame_num); - filenames[frame_num] = findresource(respath, targetname); - } - - ret = nsgtk_throbber_initialise_from_png(frame_num, filenames); - - for (frame_num = 0; frame_num < framec; frame_num++) { - free(filenames[frame_num]); - } - free(filenames); - - return ret; - -} - -#define NEW_GLADE_ERROR_SIZE 128 - -static char * -nsgtk_new_glade(char **respath, const char *name, GladeXML **pglade) -{ - GladeXML *newglade; - char *filepath; - char errorstr[NEW_GLADE_ERROR_SIZE]; - char resname[PATH_MAX]; - - snprintf(resname, PATH_MAX, "%s.glade", name); - - filepath = findresource(respath, resname); - if (filepath == NULL) { - snprintf(errorstr, NEW_GLADE_ERROR_SIZE, - "Unable to locate %s glade template file.\n", name); - die(errorstr); - } - - newglade = glade_xml_new(filepath, NULL, NULL); - if (newglade == NULL) { - snprintf(errorstr, NEW_GLADE_ERROR_SIZE, - "Unable to load glade %s window definitions.\n", name); - - die(errorstr); - } - glade_xml_signal_autoconnect(newglade); - - LOG(("Using '%s' as %s glade template file", filepath, name)); - - if (pglade != NULL) { - *pglade = newglade; - } - - return filepath; -} - -/** - * Load definitions from glade files. - */ -static void -nsgtk_init_glade(char **respath) -{ - GladeXML *gladeWarning; - - glade_init(); - - glade_netsurf_file_location = nsgtk_new_glade(respath, "netsurf", NULL); - glade_password_file_location = nsgtk_new_glade(respath, "password", NULL); - glade_login_file_location = nsgtk_new_glade(respath, "login", NULL); - glade_ssl_file_location = nsgtk_new_glade(respath, "ssl", NULL); - glade_toolbar_file_location = nsgtk_new_glade(respath, "toolbar", NULL); - glade_downloads_file_location = nsgtk_new_glade(respath, "downloads", NULL); - glade_history_file_location = nsgtk_new_glade(respath, "history", NULL); - glade_options_file_location = nsgtk_new_glade(respath, "options", NULL); - glade_hotlist_file_location = nsgtk_new_glade(respath, "hotlist", NULL); - glade_cookies_file_location = nsgtk_new_glade(respath, "cookies", NULL); - - glade_warning_file_location = nsgtk_new_glade(respath, "warning", &gladeWarning); - nsgtk_warning_window = GTK_WINDOW(glade_xml_get_widget(gladeWarning, "wndWarning")); - widWarning = glade_xml_get_widget(gladeWarning, "labelWarning"); -} - -static void check_options(char **respath) -{ - char *hdir = getenv("HOME"); - char buf[PATH_MAX]; - - option_core_select_menu = true; - - /* 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 (option_toolbar_status_width < 1500) { - option_toolbar_status_width = 6667; - } - - /* user options should be stored in the users home directory */ - snprintf(buf, PATH_MAX, "%s/.netsurf/Choices", hdir); - options_file_location = strdup(buf); - - /* VRS - I do not beleive these setting should search the - * resource path, they should just be set to the default - * values! - */ - if (!option_cookie_file) { - sfindresourcedef(respath, buf, "Cookies", "~/.netsurf/"); - LOG(("Using '%s' as Cookies file", buf)); - option_cookie_file = strdup(buf); - } - if (!option_cookie_jar) { - sfindresourcedef(respath, buf, "Cookies", "~/.netsurf/"); - LOG(("Using '%s' as Cookie Jar file", buf)); - option_cookie_jar = strdup(buf); - } - if (!option_cookie_file || !option_cookie_jar) - die("Failed initialising cookie options"); - - if (!option_url_file) { - sfindresourcedef(respath, buf, "URLs", "~/.netsurf/"); - LOG(("Using '%s' as URL file", buf)); - option_url_file = strdup(buf); - } - - if (!option_ca_path) { - sfindresourcedef(respath, buf, "certs", "/etc/ssl/"); - LOG(("Using '%s' as certificate path", buf)); - option_ca_path = strdup(buf); - } - - if (!option_downloads_directory) { - LOG(("Using '%s' as download directory", hdir)); - option_downloads_directory = hdir; - } - - sfindresourcedef(respath, buf, "icons/", "~/.netsurf/"); - LOG(("Using '%s' as Tree icons dir", buf)); - tree_set_icon_dir(strdup(buf)); - - if (!option_hotlist_path) { - sfindresourcedef(respath, buf, "Hotlist", "~/.netsurf/"); - LOG(("Using '%s' as Hotlist file", buf)); - option_hotlist_path = strdup(buf); - } - if (!option_hotlist_path) - die("Failed initialising hotlist option"); - - - sfindresourcedef(respath, buf, "Print", "~/.netsurf/"); - LOG(("Using '%s' as Print Settings file", buf)); - print_options_file_location = strdup(buf); - - /* check what the font settings are, setting them to a default font - * if they're not set - stops Pango whinging - */ -#define SETFONTDEFAULT(x,y) (x) = ((x) != NULL) ? (x) : strdup((y)) - SETFONTDEFAULT(option_font_sans, "Sans"); - SETFONTDEFAULT(option_font_serif, "Serif"); - SETFONTDEFAULT(option_font_mono, "Monospace"); - SETFONTDEFAULT(option_font_cursive, "Serif"); - SETFONTDEFAULT(option_font_fantasy, "Serif"); - -} - -/** - * Initialize GTK interface. - */ -static void gui_init(int argc, char** argv, char **respath) -{ - char buf[PATH_MAX]; - struct browser_window *bw; - const char *addr = NETSURF_HOMEPAGE; - char *resource_filename; - - /* check user options */ - check_options(respath); - - /* Obtain resources path location. - * - * Uses the directory the languages file was found in, - * previously the location of the glade files was used, - * however these may be translated which breaks things - * relying on res_dir_location. - */ - resource_filename = findresource(respath, "languages"); - resource_filename[strlen(resource_filename) - 9] = 0; - res_dir_location = resource_filename; - - /* languages file */ - languages_file_location = findresource(respath, "languages"); - - /* initialise the glade templates */ - nsgtk_init_glade(respath); - - /* set default icon if its available */ - resource_filename = findresource(respath, "netsurf.xpm"); - if (resource_filename != NULL) { - gtk_window_set_default_icon_from_file(resource_filename, NULL); - free(resource_filename); - } - - /* Search engine sources */ - search_engines_file_location = findresource(respath, "SearchEngines"); - LOG(("Using '%s' as Search Engines file", search_engines_file_location)); - - /* Default Icon */ - search_default_ico_location = findresource(respath, "default.ico"); - LOG(("Using '%s' as default search ico", search_default_ico_location)); - - /* Toolbar inicies file */ - toolbar_indices_file_location = findresource(respath, "toolbarIndices"); - LOG(("Using '%s' as custom toolbar settings file", toolbar_indices_file_location)); - - /* load throbber images */ - if (nsgtk_throbber_init(respath, THROBBER_FRAMES) == false) - die("Unable to load throbber image.\n"); - - /* Initialise completions - cannot fail */ - nsgtk_completion_init(); - - sfindresourcedef(respath, buf, "mime.types", "/etc/"); - gtk_fetch_filetype_init(buf); - - /* set up stylesheet urls */ - sfindresourcedef(respath, buf, "gtkdefault.css", "./gtk/res/"); - default_stylesheet_url = path_to_url(buf); - LOG(("Using '%s' as Default CSS URL", default_stylesheet_url)); - - sfindresourcedef(respath, buf, "quirks.css", "./gtk/res/"); - quirks_stylesheet_url = path_to_url(buf); - - sfindresourcedef(respath, buf, "adblock.css", "./gtk/res/"); - adblock_stylesheet_url = path_to_url(buf); - LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url)); - - urldb_load(option_url_file); - urldb_load_cookies(option_cookie_file); - - /* 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. - */ - - nscss_screen_dpi = FLTTOFIX(gdk_screen_get_resolution( - gdk_screen_get_default())); - LOG(("Set CSS DPI to %f", FIXTOFLT(nscss_screen_dpi))); - - if (nsgtk_history_init(glade_history_file_location) == false) - die("Unable to initialise history window.\n"); - - if (nsgtk_download_init(glade_downloads_file_location) == false) - die("Unable to initialise download window.\n"); - - if (nsgtk_cookies_init(glade_cookies_file_location) == false) - die("Unable to initialise cookies window.\n"); - - if (nsgtk_hotlist_init(glade_hotlist_file_location) == false) - die("Unable to initialise hotlist window.\n"); - - sslcert_init(tree_content_icon_name); - - if (option_homepage_url != NULL && option_homepage_url[0] != '\0') - addr = option_homepage_url; - - if (2 <= argc) - addr = argv[1]; - - /* Last step of initialization. Opens the main browser window. */ - bw = browser_window_create(addr, 0, 0, true, false); -} - - -/** - * Check that ~/.netsurf/ exists, and if it doesn't, create it. - */ -static void nsgtk_check_homedir(void) -{ - char *hdir = getenv("HOME"); - char buf[PATH_MAX]; - - if (hdir == NULL) { - /* we really can't continue without a home directory. */ - LOG(("HOME is not set - nowhere to store state!")); - die("NetSurf requires HOME to be set in order to run.\n"); - - } - - snprintf(buf, PATH_MAX, "%s/.netsurf", hdir); - if (access(buf, F_OK) != 0) { - LOG(("You don't have a ~/.netsurf - creating one for you.")); - if (mkdir(buf, 0777) == -1) { - LOG(("Unable to create %s", buf)); - die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n"); - } - } -} - -/** - * Main entry point from OS. - */ -int main(int argc, char** argv) -{ - char *messages; - char *options; - char **respaths; - - /* check home directory is available */ - nsgtk_check_homedir(); - - respaths = nsgtk_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"GTK_RESPATH":./gtk/res"); - - /* Some modern distributions can set ALL_PROXY/all_proxy if configured - * to by the user. Due to a bug in many versions of libcurl - * (including the one shipped in Ubuntu 10.04 LTS), this also takes - * effect on file:// URLs, meaning that NetSurf cannot load its - * default CSS file. Given all examples of distributions I've checked - * also set http_proxy and friends, we can safely unset these. - */ - - unsetenv("ALL_PROXY"); - unsetenv("all_proxy"); - - gtk_init(&argc, &argv); - - /* set standard error to be non-buffering */ - setbuf(stderr, NULL); - - options = findresource(respaths, "Choices"); - - messages = findresource(respaths, "Messages"); - - netsurf_init(&argc, &argv, options, messages); - - free(messages); - free(options); - - gui_init(argc, argv, respaths); - - netsurf_main_loop(); - - netsurf_exit(); - - - return 0; -} - - -void gui_poll(bool active) -{ - CURLMcode code; - fd_set read_fd_set, write_fd_set, exc_fd_set; - int max_fd; - GPollFD *fd_list[1000]; - unsigned int fd_count = 0; - bool block = true; - - if (browser_reformat_pending) - block = false; - - if (active) { - FD_ZERO(&read_fd_set); - FD_ZERO(&write_fd_set); - FD_ZERO(&exc_fd_set); - code = curl_multi_fdset(fetch_curl_multi, - &read_fd_set, - &write_fd_set, - &exc_fd_set, - &max_fd); - assert(code == CURLM_OK); - 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_do(block); - - for (unsigned int i = 0; i != fd_count; i++) { - g_main_context_remove_poll(0, fd_list[i]); - free(fd_list[i]); - } - - schedule_run(); - - if (browser_reformat_pending) - nsgtk_window_process_reformats(); -} - - -void gui_multitask(void) -{ - while (gtk_events_pending()) - gtk_main_iteration(); -} - - -void gui_quit(void) -{ - nsgtk_download_destroy(); - urldb_save_cookies(option_cookie_jar); - urldb_save(option_url_file); - nsgtk_cookies_destroy(); - nsgtk_history_destroy(); - nsgtk_hotlist_destroy(); - sslcert_cleanup(); - free(default_stylesheet_url); - free(quirks_stylesheet_url); - free(adblock_stylesheet_url); - free(option_cookie_file); - free(option_cookie_jar); - free(print_options_file_location); - free(search_engines_file_location); - free(search_default_ico_location); - free(toolbar_indices_file_location); - gtk_fetch_filetype_fin(); -} - - - - - - - - - -static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, - gpointer user_data) -{ - form_select_process_selection(select_menu_bw->current_content, - select_menu_control, (intptr_t)user_data); -} - -void gui_create_form_select_menu(struct browser_window *bw, - struct form_control *control) -{ - - intptr_t i; - struct form_option *option; - - GtkWidget *menu_item; - - /* control->data.select.multiple is true if multiple selections - * are allowable. We ignore this, as the core handles it for us. - * Yay. \o/ - */ - - if (select_menu != NULL) - gtk_widget_destroy(select_menu); - - select_menu = gtk_menu_new(); - select_menu_bw = bw; - select_menu_control = control; - - for (i = 0, option = control->data.select.items; option; - i++, option = option->next) { - menu_item = gtk_check_menu_item_new_with_label(option->text); - if (option->selected) - gtk_check_menu_item_set_active( - GTK_CHECK_MENU_ITEM(menu_item), TRUE); - - g_signal_connect(menu_item, "toggled", - G_CALLBACK(nsgtk_select_menu_clicked), (gpointer)i); - - gtk_menu_shell_append(GTK_MENU_SHELL(select_menu), menu_item); - } - - gtk_widget_show_all(select_menu); - - gtk_menu_popup(GTK_MENU(select_menu), NULL, NULL, NULL, - NULL /* data */, 0, gtk_get_current_event_time()); - -} - -void gui_window_save_link(struct gui_window *g, const char *url, - const char *title) -{ -} - -void gui_launch_url(const char *url) -{ -} - -void warn_user(const char *warning, const char *detail) -{ - char buf[300]; /* 300 is the size the RISC OS GUI uses */ - - LOG(("%s %s", warning, detail ? detail : "")); - fflush(stdout); - - snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), - detail ? detail : ""); - buf[sizeof(buf) - 1] = 0; - - gtk_label_set_text(GTK_LABEL(widWarning), buf); - - gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window)); -} - -void die(const char * const error) -{ - fprintf(stderr, "%s", error); - exit(EXIT_FAILURE); -} - - -void gui_cert_verify(const char *url, const struct ssl_cert_info *certs, - unsigned long num, nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - static struct nsgtk_treeview *ssl_window; - struct sslcert_session_data *data; - GladeXML *x = glade_xml_new(glade_ssl_file_location, NULL, NULL); - GtkButton *accept, *reject; - void **session = calloc(sizeof(void *), 3); - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; - - data = sslcert_create_session_data(num, url, cb, cbpw); - - window = GTK_WINDOW( - glade_xml_get_widget(x,"wndSSLProblem")); - scrolled = GTK_SCROLLED_WINDOW( - glade_xml_get_widget(x,"SSLScrolled")); - drawing_area = GTK_DRAWING_AREA( - glade_xml_get_widget(x,"SSLDrawingArea")); - - - ssl_window = nsgtk_treeview_create(sslcert_get_tree_flags(), - window, scrolled, drawing_area); - - if (ssl_window == NULL) - return; - - sslcert_load_tree(nsgtk_treeview_get_tree(ssl_window), certs, data); - - accept = GTK_BUTTON(glade_xml_get_widget(x, "sslaccept")); - reject = GTK_BUTTON(glade_xml_get_widget(x, "sslreject")); - - session[0] = x; - session[1] = ssl_window; - session[2] = data; - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - CONNECT(accept, "clicked", nsgtk_ssl_accept, session); - CONNECT(reject, "clicked", nsgtk_ssl_reject, session); - CONNECT(window, "delete_event", G_CALLBACK(nsgtk_ssl_delete_event), - (gpointer)session); - - gtk_widget_show(GTK_WIDGET(window)); -} - -void nsgtk_ssl_accept(GtkButton *w, gpointer data) -{ - void **session = data; - GladeXML *x = session[0]; - struct nsgtk_treeview *wnd = session[1]; - struct sslcert_session_data *ssl_data = session[2]; - - sslcert_accept(ssl_data); - - nsgtk_treeview_destroy(wnd); - g_object_unref(G_OBJECT(x)); - free(session); -} - -void nsgtk_ssl_reject(GtkWidget *w, gpointer data) -{ - void **session = data; - GladeXML *x = session[0]; - struct nsgtk_treeview *wnd = session[1]; - struct sslcert_session_data *ssl_data = session[2]; - - sslcert_reject(ssl_data); - - nsgtk_treeview_destroy(wnd); - g_object_unref(G_OBJECT(x)); - free(session); -} - -gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event, gpointer data) -{ - nsgtk_ssl_reject(w, data); - return FALSE; -} - -utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len, - char **result) -{ - assert(string && result); - - if (len == 0) - len = strlen(string); - - *result = strndup(string, len); - if (!(*result)) - return UTF8_CONVERT_NOMEM; - - return UTF8_CONVERT_OK; -} - - -utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len, - char **result) -{ - assert(string && result); - - if (len == 0) - len = strlen(string); - - *result = strndup(string, len); - if (!(*result)) - return UTF8_CONVERT_NOMEM; - - return UTF8_CONVERT_OK; -} - - -char *path_to_url(const char *path) -{ - int urllen = strlen(path) + FILE_SCHEME_PREFIX_LEN + 1; - char *url = malloc(urllen); - - if (url == NULL) { - return NULL; - } - - if (*path == '/') { - path++; /* file: paths are already absolute */ - } - - snprintf(url, urllen, "%s%s", FILE_SCHEME_PREFIX, path); - - return url; -} - - -char *url_to_path(const char *url) -{ - char *path; - char *respath; - url_func_result res; /* result from url routines */ - - res = url_path(url, &path); - if (res != URL_FUNC_OK) { - return NULL; - } - - res = url_unescape(path, &respath); - free(path); - if (res != URL_FUNC_OK) { - return NULL; - } - - return respath; -} - -#ifdef WITH_PDF_EXPORT - -void PDF_Password(char **owner_pass, char **user_pass, char *path) -{ - GladeXML *x = glade_xml_new(glade_password_file_location, NULL, NULL); - GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndPDFPassword")); - GtkButton *ok, *no; - void **data = malloc(5 * sizeof(void *)); - - *owner_pass = NULL; - *user_pass = NULL; - - data[0] = owner_pass; - data[1] = user_pass; - data[2] = wnd; - data[3] = x; - data[4] = path; - - ok = GTK_BUTTON(glade_xml_get_widget(x, "buttonPDFSetPassword")); - no = GTK_BUTTON(glade_xml_get_widget(x, "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 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]; - GladeXML *x = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - char *op, *op1; - char *up, *up1; - - op = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFOwnerPassword")))); - op1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFOwnerPassword1")))); - up = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFUserPassword")))); - up1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, - "entryPDFUserPassword1")))); - - - if (op[0] == '\0') { - gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, - "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(glade_xml_get_widget(x, - "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(x)); - - save_pdf(path); - free(path); - } - else { - gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, - "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]; - GladeXML *x = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - free(data); - - gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(x)); - - save_pdf(path); - free(path); -} -#endif - -uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) -{ - /* this function will need to become much more complex to support - * everything that the RISC OS version does. But this will do for - * now. I hope. - */ - switch (key->keyval) - { - case GDK_BackSpace: - if (key->state & GDK_SHIFT_MASK) - return KEY_DELETE_LINE_START; - else - return KEY_DELETE_LEFT; - case GDK_Delete: - if (key->state & GDK_SHIFT_MASK) - return KEY_DELETE_LINE_END; - else - return KEY_DELETE_RIGHT; - case GDK_Linefeed: return 13; - case GDK_Return: return 10; - case GDK_Left: return KEY_LEFT; - case GDK_Right: return KEY_RIGHT; - case GDK_Up: return KEY_UP; - case GDK_Down: return KEY_DOWN; - case GDK_Home: - if (key->state & GDK_CONTROL_MASK) - return KEY_TEXT_START; - else - return KEY_LINE_START; - case GDK_End: - if (key->state & GDK_CONTROL_MASK) - return KEY_TEXT_END; - else - return KEY_LINE_END; - case GDK_Page_Up: - return KEY_PAGE_UP; - case GDK_Page_Down: - return KEY_PAGE_DOWN; - case 'a': - if (key->state & GDK_CONTROL_MASK) - return KEY_SELECT_ALL; - return gdk_keyval_to_unicode(key->keyval); - case 'u': - if (key->state & GDK_CONTROL_MASK) - return KEY_CLEAR_SELECTION; - return gdk_keyval_to_unicode(key->keyval); - case GDK_Escape: - return KEY_ESCAPE; - - /* Modifiers - do nothing for now */ - case GDK_Shift_L: - case GDK_Shift_R: - case GDK_Control_L: - case GDK_Control_R: - case GDK_Caps_Lock: - case GDK_Shift_Lock: - case GDK_Meta_L: - case GDK_Meta_R: - case GDK_Alt_L: - case GDK_Alt_R: - case GDK_Super_L: - case GDK_Super_R: - case GDK_Hyper_L: - case GDK_Hyper_R: return 0; - - default: return gdk_keyval_to_unicode( - key->keyval); - } -} - -/** - * Return the filename part of a full path - * - * \param path full path and filename - * \return filename (will be freed with free()) - */ - -char *filename_from_path(char *path) -{ - char *leafname; - - leafname = strrchr(path, '/'); - if (!leafname) - leafname = path; - else - leafname += 1; - - return strdup(leafname); -} - -/** - * Add a path component/filename to an existing path - * - * \param path buffer containing path + free space - * \param length length of buffer "path" - * \param newpart string containing path component to add to path - * \return true on success - */ - -bool path_add_part(char *path, int length, const char *newpart) -{ - if(path[strlen(path) - 1] != '/') - strncat(path, "/", length); - - strncat(path, newpart, length); - - return true; -} diff --git a/gtk/gtk_gui.h b/gtk/gtk_gui.h deleted file mode 100644 index 9035d8873..000000000 --- a/gtk/gtk_gui.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2004-2010 James Bursa - * Copyright 2010 Vincent Sanders - * Copyright 2004-2009 John-Mark Bell - * Copyright 2009 Paul Blokus - * Copyright 2006-2009 Daniel Silverstone - * Copyright 2006-2008 Rob Kendrick - * Copyright 2008 John Tytgat - * Copyright 2008 Adam Blokus - * - * 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 . - */ - -#ifndef GTK_GUI_H -#define GTK_GUI_H - -#include -#include -#include -#include - -extern char *glade_netsurf_file_location; -extern char *glade_password_file_location; -extern char *glade_warning_file_location; -extern char *glade_login_file_location; -extern char *glade_ssl_file_location; -extern char *glade_toolbar_file_location; -extern char *glade_options_file_location; - -extern char *languages_file_location; -extern char *toolbar_indices_file_location; -extern char *options_file_location; /**< location where user options are written */ -extern char *res_dir_location; -extern char *print_options_file_location; - -uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *); - -#endif /* GTK_GUI_H */ - diff --git a/gtk/gtk_history.c b/gtk/gtk_history.c deleted file mode 100644 index 09f945963..000000000 --- a/gtk/gtk_history.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2009 Paul Blokus - * - * 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 . - */ - - -#include "desktop/history_global_core.h" -#include "desktop/plotters.h" -#include "desktop/tree.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_history.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_treeview.h" -#include "utils/log.h" -#include "utils/utils.h" - -#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ - GtkMenuItem *widget, gpointer g) -#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } -#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ - gpointer g) - -struct menu_events { - const char *widget; - GCallback handler; -}; - -static void nsgtk_history_init_menu(void); - -/* file menu*/ -MENUPROTO(export); - -/* edit menu */ -MENUPROTO(delete_selected); -MENUPROTO(delete_all); -MENUPROTO(select_all); -MENUPROTO(clear_selection); - -/* view menu*/ -MENUPROTO(expand_all); -MENUPROTO(expand_directories); -MENUPROTO(expand_addresses); -MENUPROTO(collapse_all); -MENUPROTO(collapse_directories); -MENUPROTO(collapse_addresses); - -MENUPROTO(launch); - -static struct menu_events menu_events[] = { - - /* file menu*/ - MENUEVENT(export), - - /* edit menu */ - MENUEVENT(delete_selected), - MENUEVENT(delete_all), - MENUEVENT(select_all), - MENUEVENT(clear_selection), - - /* view menu*/ - MENUEVENT(expand_all), - MENUEVENT(expand_directories), - MENUEVENT(expand_addresses), - MENUEVENT(collapse_all), - MENUEVENT(collapse_directories), - MENUEVENT(collapse_addresses), - - MENUEVENT(launch), - {NULL, NULL} -}; - -static struct nsgtk_treeview *global_history_window; -static GladeXML *gladeFile; -GtkWindow *wndHistory; - - -/* exported interface, documented in gtk_history.h */ -bool nsgtk_history_init(const char *glade_file_location) -{ - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; - - gladeFile = glade_xml_new(glade_file_location, NULL, NULL); - if (gladeFile == NULL) - return false; - - glade_xml_signal_autoconnect(gladeFile); - - wndHistory = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndHistory")); - - window = wndHistory; - - scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, - "globalHistoryScrolled")); - - drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, - "globalHistoryDrawingArea")); - - global_history_window = nsgtk_treeview_create( - history_global_get_tree_flags(), window, scrolled, - drawing_area); - - if (global_history_window == NULL) - return false; - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); - CONNECT(window, "hide", nsgtk_tree_window_hide, global_history_window); - - history_global_initialise( - nsgtk_treeview_get_tree(global_history_window), - tree_directory_icon_name); - - nsgtk_history_init_menu(); - - return true; -} - - -/** - * Connects menu events in the global history window. - */ -void nsgtk_history_init_menu(void) -{ - struct menu_events *event = menu_events; - - while (event->widget != NULL) - { - GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); - g_signal_connect(G_OBJECT(w), "activate", event->handler, - global_history_window); - event++; - } -} - - -/** - * Destroys the global history window and performs any other necessary cleanup - * actions. - */ -void nsgtk_history_destroy(void) -{ - /* TODO: what about gladeFile? */ - history_global_cleanup(); - nsgtk_treeview_destroy(global_history_window); -} - - -/* file menu*/ -MENUHANDLER(export) -{ - GtkWidget *save_dialog; - save_dialog = gtk_file_chooser_dialog_new("Save File", - wndHistory, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - getenv("HOME") ? getenv("HOME") : "/"); - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - "history.html"); - - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - - history_global_export(filename); - g_free(filename); - } - - gtk_widget_destroy(save_dialog); - - return TRUE; -} - -/* edit menu */ -MENUHANDLER(delete_selected) -{ - history_global_delete_selected(); - return TRUE; -} - -MENUHANDLER(delete_all) -{ - history_global_delete_all(); - return TRUE; -} - -MENUHANDLER(select_all) -{ - history_global_select_all(); - return TRUE; -} - -MENUHANDLER(clear_selection) -{ - history_global_clear_selection(); - return TRUE; -} - -/* view menu*/ -MENUHANDLER(expand_all) -{ - history_global_expand_all(); - return TRUE; -} - -MENUHANDLER(expand_directories) -{ - history_global_expand_directories(); - return TRUE; -} - -MENUHANDLER(expand_addresses) -{ - history_global_expand_addresses(); - return TRUE; -} - -MENUHANDLER(collapse_all) -{ - history_global_collapse_all(); - return TRUE; -} - -MENUHANDLER(collapse_directories) -{ - history_global_collapse_directories(); - return TRUE; -} - -MENUHANDLER(collapse_addresses) -{ - history_global_collapse_addresses(); - return TRUE; -} - -MENUHANDLER(launch) -{ - history_global_launch_selected(); - return TRUE; -} diff --git a/gtk/gtk_history.h b/gtk/gtk_history.h deleted file mode 100644 index ab3c10ee6..000000000 --- a/gtk/gtk_history.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -#ifndef __NSGTK_HISTORY_H__ -#define __NSGTK_HISTORY_H__ - -#include - -extern GtkWindow *wndHistory; - -/** - * Creates the window for the global history tree. - * - * \param glade_file_location The glade file to use for the window. - * \return true on success false on faliure. - */ -bool nsgtk_history_init(const char *glade_file_location); - -/** - * Free global resources associated with the gtk history window. - */ -void nsgtk_history_destroy(void); - -#endif /* __NSGTK_HISTORY_H__ */ diff --git a/gtk/gtk_hotlist.c b/gtk/gtk_hotlist.c deleted file mode 100644 index 98e0b217e..000000000 --- a/gtk/gtk_hotlist.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2009 Paul Blokus - * - * 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 . - */ - - -#include "desktop/hotlist.h" -#include "desktop/options.h" -#include "desktop/plotters.h" -#include "desktop/tree.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_hotlist.h" -#include "gtk/options.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_treeview.h" -#include "utils/log.h" - -#define GLADE_NAME "hotlist.glade" - -#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ - GtkMenuItem *widget, gpointer g) -#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } -#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ - gpointer g) - -struct menu_events { - const char *widget; - GCallback handler; -}; - -static void nsgtk_hotlist_init_menu(void); - -/* file menu*/ -MENUPROTO(export); -MENUPROTO(new_folder); -MENUPROTO(new_entry); - -/* edit menu */ -MENUPROTO(edit_selected); -MENUPROTO(delete_selected); -MENUPROTO(select_all); -MENUPROTO(clear_selection); - -/* view menu*/ -MENUPROTO(expand_all); -MENUPROTO(expand_directories); -MENUPROTO(expand_addresses); -MENUPROTO(collapse_all); -MENUPROTO(collapse_directories); -MENUPROTO(collapse_addresses); - -MENUPROTO(launch); - -static struct menu_events menu_events[] = { - - /* file menu*/ - MENUEVENT(export), - MENUEVENT(new_folder), - MENUEVENT(new_entry), - - /* edit menu */ - MENUEVENT(edit_selected), - MENUEVENT(delete_selected), - MENUEVENT(select_all), - MENUEVENT(clear_selection), - - /* view menu*/ - MENUEVENT(expand_all), - MENUEVENT(expand_directories), - MENUEVENT(expand_addresses), - MENUEVENT(collapse_all), - MENUEVENT(collapse_directories), - MENUEVENT(collapse_addresses), - - MENUEVENT(launch), - {NULL, NULL} -}; - -static struct nsgtk_treeview *hotlist_window; -static GladeXML *gladeFile; -GtkWindow *wndHotlist; - - -/* exported interface docuemnted in gtk_hotlist.h */ -bool nsgtk_hotlist_init(const char *glade_file_location) -{ - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; - - gladeFile = glade_xml_new(glade_file_location, NULL, NULL); - if (gladeFile == NULL) - return false; - - glade_xml_signal_autoconnect(gladeFile); - - wndHotlist = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndHotlist")); - window = wndHotlist; - - scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, - "hotlistScrolled")); - - drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, - "hotlistDrawingArea")); - - - hotlist_window = nsgtk_treeview_create(hotlist_get_tree_flags(), window, - scrolled, drawing_area); - - if (hotlist_window == NULL) - return false; - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); - CONNECT(window, "hide", nsgtk_tree_window_hide, hotlist_window); - - hotlist_initialise(nsgtk_treeview_get_tree(hotlist_window), - option_hotlist_path, - tree_directory_icon_name); - - nsgtk_hotlist_init_menu(); - - return true; -} - - -/** - * Connects menu events in the hotlist window. - */ -void nsgtk_hotlist_init_menu(void) -{ - struct menu_events *event = menu_events; - - while (event->widget != NULL) - { - GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); - g_signal_connect(G_OBJECT(w), "activate", event->handler, - hotlist_window); - event++; - } -} - - -/** - * Destroys the hotlist window and performs any other necessary cleanup actions. - */ -void nsgtk_hotlist_destroy(void) -{ - /* TODO: what about gladeFile? */ - hotlist_cleanup(option_hotlist_path); - nsgtk_treeview_destroy(hotlist_window); -} - - -/* file menu*/ -MENUHANDLER(export) -{ - GtkWidget *save_dialog; - save_dialog = gtk_file_chooser_dialog_new("Save File", - wndHotlist, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - getenv("HOME") ? getenv("HOME") : "/"); - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - "hotlist.html"); - - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - - hotlist_export(filename); - g_free(filename); - } - - gtk_widget_destroy(save_dialog); - - return TRUE; -} - -MENUHANDLER(new_folder) -{ - hotlist_add_folder(); - return TRUE; -} - -MENUHANDLER(new_entry) -{ - hotlist_add_entry(); - return TRUE; -} - -/* edit menu */ -MENUHANDLER(edit_selected) -{ - hotlist_edit_selected(); - return TRUE; -} - -MENUHANDLER(delete_selected) -{ - hotlist_delete_selected(); - return TRUE; -} - -MENUHANDLER(select_all) -{ - hotlist_select_all(); - return TRUE; -} - -MENUHANDLER(clear_selection) -{ - hotlist_clear_selection(); - return TRUE; -} - -/* view menu*/ -MENUHANDLER(expand_all) -{ - hotlist_expand_all(); - return TRUE; -} - -MENUHANDLER(expand_directories) -{ - hotlist_expand_directories(); - return TRUE; -} - -MENUHANDLER(expand_addresses) -{ - hotlist_expand_addresses(); - return TRUE; -} - -MENUHANDLER(collapse_all) -{ - hotlist_collapse_all(); - return TRUE; -} - -MENUHANDLER(collapse_directories) -{ - hotlist_collapse_directories(); - return TRUE; -} - -MENUHANDLER(collapse_addresses) -{ - hotlist_collapse_addresses(); - return TRUE; -} - -MENUHANDLER(launch) -{ - hotlist_launch_selected(); - return TRUE; -} diff --git a/gtk/gtk_hotlist.h b/gtk/gtk_hotlist.h deleted file mode 100644 index b2477bc9f..000000000 --- a/gtk/gtk_hotlist.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -/** \file - * GTK hotlist (interface). - */ - -#ifndef __NSGTK_HOTLIST_H__ -#define __NSGTK_HOTLIST_H__ - -#include - -extern GtkWindow *wndHotlist; - -/** - * Initialise the gtk specific hotlist (bookmarks) display. - * - * \param glade_hotlist_file_location the path to the glade file for the hotlist - */ -bool nsgtk_hotlist_init(const char *glade_hotlist_file_location); -void nsgtk_hotlist_destroy(void); - -#endif /* __NSGTK_HOTLIST_H__ */ diff --git a/gtk/gtk_login.c b/gtk/gtk_login.c deleted file mode 100644 index 4b9f15333..000000000 --- a/gtk/gtk_login.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include "utils/log.h" -#include "gtk/gtk_gui.h" -#include "content/content.h" -#include "content/hlcache.h" -#include "content/urldb.h" -#include "desktop/browser.h" -#include "desktop/401login.h" -#include "desktop/gui.h" -#include "utils/messages.h" -#include "utils/url.h" -#include "utils/utils.h" - -struct session_401 { - char *url; /**< URL being fetched */ - char *host; /**< Host for user display */ - char *realm; /**< Authentication realm */ - nserror (*cb)(bool proceed, void *pw); /**< Continuation callback */ - void *cbpw; /**< Continuation data */ - GladeXML *x; /**< Our glade windows */ - GtkWindow *wnd; /**< The login window itself */ - GtkEntry *user; /**< Widget with username */ - GtkEntry *pass; /**< Widget with password */ -}; - -static void create_login_window(const char *url, const char *host, - const char *realm, nserror (*cb)(bool proceed, void *pw), - void *cbpw); -static void destroy_login_window(struct session_401 *session); -static void nsgtk_login_next(GtkWidget *w, gpointer data); -static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data); -static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data); - -void gui_401login_open(const char *url, const char *realm, - nserror (*cb)(bool proceed, void *pw), void *cbpw) -{ - char *host; - url_func_result res; - - res = url_host(url, &host); - assert(res == URL_FUNC_OK); - - create_login_window(url, host, realm, cb, cbpw); - - free(host); -} - -void create_login_window(const char *url, const char *host, const char *realm, - nserror (*cb)(bool proceed, void *pw), void *cbpw) -{ - struct session_401 *session; - - /* create a new instance of the login window, and get handles to all - * the widgets we're interested in. - */ - - GladeXML *x = glade_xml_new(glade_login_file_location, NULL, NULL); - GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndLogin")); - GtkLabel *lhost, *lrealm; - GtkEntry *euser, *epass; - GtkButton *bok, *bcan; - - lhost = GTK_LABEL(glade_xml_get_widget(x, "labelLoginHost")); - lrealm = GTK_LABEL(glade_xml_get_widget(x, "labelLoginRealm")); - euser = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginUser")); - epass = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginPass")); - bok = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginOK")); - bcan = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginCan")); - - /* create and fill in our session structure */ - - session = calloc(1, sizeof(struct session_401)); - session->url = strdup(url); - session->host = strdup(host); - session->realm = strdup(realm ? realm : "Secure Area"); - session->cb = cb; - session->cbpw = cbpw; - session->x = x; - session->wnd = wnd; - session->user = euser; - session->pass = epass; - - /* fill in our new login window */ - - gtk_label_set_text(GTK_LABEL(lhost), 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)); -} - -void destroy_login_window(struct session_401 *session) -{ - free(session->url); - free(session->host); - free(session->realm); - gtk_widget_destroy(GTK_WIDGET(session->wnd)); - g_object_unref(G_OBJECT(session->x)); - free(session); -} - -void nsgtk_login_next(GtkWidget *w, gpointer data) -{ - gtk_widget_grab_focus(GTK_WIDGET(data)); -} - -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); -} - -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); -} diff --git a/gtk/gtk_menu.c b/gtk/gtk_menu.c deleted file mode 100644 index d8063e356..000000000 --- a/gtk/gtk_menu.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include - -#include -#include -#include - -#include "gtk/gtk_menu.h" -#include "utils/messages.h" -#include "utils/utils.h" - -/** - * adds image menu item to specified menu - * \param menu the menu to add the item to - * \param item a pointer to the item's location in the menu struct - * \param message the menu item I18n lookup value - * \param messageAccel the menu item accelerator I18n lookup value - * \param group the 'global' in a gtk sense accelerator group - */ - -static bool nsgtk_menu_add_image_item(GtkMenu *menu, - GtkImageMenuItem **item, const char *message, - const char *messageAccel, GtkAccelGroup *group) -{ - unsigned int key; - GdkModifierType mod; - *item = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic( - messages_get(message))); - if (*item == NULL) - return false; - gtk_accelerator_parse(messages_get(messageAccel), &key, &mod); - if (key > 0) - gtk_widget_add_accelerator(GTK_WIDGET(*item), "activate", - group, key, mod, GTK_ACCEL_VISIBLE); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(*item)); - gtk_widget_show(GTK_WIDGET(*item)); - return true; -} - -#define IMAGE_ITEM(p, q, r, s, t)\ - nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\ - #r "Accel", t) - -#define CHECK_ITEM(p, q, r, s)\ - 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));\ - } - -#define SET_SUBMENU(q, r) \ - do { \ - r->q##_submenu = nsgtk_menu_##q##_submenu(group); \ - if ((r->q##_submenu != NULL) && \ - (r->q##_submenu->q##_menu != NULL) && \ - (r->q##_menuitem != NULL)) { \ - gtk_menu_item_set_submenu(GTK_MENU_ITEM(r->q##_menuitem), \ - GTK_WIDGET(r->q##_submenu->q##_menu)); \ - } \ - } while(0) - -#define ADD_NAMED_SEP(q, r, s) \ - do { \ - s->r##_separator = gtk_separator_menu_item_new(); \ - if ((s->r##_separator != NULL) && (s->q##_menu != NULL)) { \ - gtk_menu_shell_append(GTK_MENU_SHELL(s->q##_menu), s->r##_separator); \ - gtk_widget_show(s->r##_separator); \ - } \ - } while(0) - -#define ADD_SEP(q, r) \ - do { \ - GtkWidget *w = gtk_separator_menu_item_new(); \ - if ((w != NULL) && (r->q##_menu != NULL)) { \ - gtk_menu_shell_append(GTK_MENU_SHELL(r->q##_menu), w); \ - gtk_widget_show(w); \ - } \ - } while(0) - -#define ATTACH_PARENT(parent, msgname, menuv, group) \ - do { \ - if (parent != NULL) { \ - /* create top level menu entry and attach to parent */ \ - menuv = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(messages_get(#msgname))); \ - gtk_menu_shell_append(parent, GTK_WIDGET(menuv)); \ - gtk_widget_show(GTK_WIDGET(menuv)); \ - /* attach submenu to parent */ \ - gtk_menu_item_set_submenu(menuv, GTK_WIDGET(menuv##_menu)); \ - gtk_menu_set_accel_group(menuv##_menu, group); \ - } \ - } while(0) - -/** -* creates an export submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *group) -{ - struct nsgtk_export_submenu *ret = malloc(sizeof(struct - nsgtk_export_submenu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->export_menu = GTK_MENU(gtk_menu_new()); - if (ret->export_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - 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; -} - -/** -* creates a scaleview submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu( - GtkAccelGroup *group) -{ - struct nsgtk_scaleview_submenu *ret = - malloc(sizeof(struct nsgtk_scaleview_submenu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->scaleview_menu = GTK_MENU(gtk_menu_new()); - if (ret->scaleview_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - IMAGE_ITEM(scaleview, zoomplus, gtkZoomPlus, ret, group); - IMAGE_ITEM(scaleview, zoomnormal, gtkZoomNormal, ret, group); - IMAGE_ITEM(scaleview, zoomminus, gtkZoomMinus, ret, group); - return ret; -} - -/** -* creates a tab navigation submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group) -{ - struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct nsgtk_tabs_submenu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->tabs_menu = GTK_MENU(gtk_menu_new()); - if (ret->tabs_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - IMAGE_ITEM(tabs, nexttab, gtkNextTab, ret, group); - IMAGE_ITEM(tabs, prevtab, gtkPrevTab, ret, group); - IMAGE_ITEM(tabs, closetab, gtkCloseTab, ret, 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) -{ - struct nsgtk_images_submenu *ret = - malloc(sizeof(struct nsgtk_images_submenu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->images_menu = GTK_MENU(gtk_menu_new()); - if (ret->images_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - 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) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->toolbars_menu = GTK_MENU(gtk_menu_new()); - if (ret->toolbars_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - 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; -} - -/** -* creates a debugging submenu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_debugging_submenu *nsgtk_menu_debugging_submenu( - GtkAccelGroup *group) -{ - struct nsgtk_debugging_submenu *ret = - malloc(sizeof(struct nsgtk_debugging_submenu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->debugging_menu = GTK_MENU(gtk_menu_new()); - if (ret->debugging_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - IMAGE_ITEM(debugging, toggledebugging, gtkToggleDebugging, ret, group); - IMAGE_ITEM(debugging, saveboxtree, gtkSaveBoxTree, ret, group); - IMAGE_ITEM(debugging, savedomtree, gtkSaveDomTree, ret, group); - return ret; -} - -/** - * creates the file menu - * \param group The gtk 'global' accelerator reference - * \param parent The parent menu to attach to or NULL - */ -static struct nsgtk_file_menu *nsgtk_menu_file_submenu(GtkAccelGroup *group) -{ - struct nsgtk_file_menu *fmenu; - - fmenu = malloc(sizeof(struct nsgtk_file_menu)); - if (fmenu == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - - fmenu->file_menu = GTK_MENU(gtk_menu_new()); - if (fmenu->file_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(fmenu); - return NULL; - } - - IMAGE_ITEM(file, newwindow, gtkNewWindow, fmenu, group); - IMAGE_ITEM(file, newtab, gtkNewTab, fmenu, 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); - IMAGE_ITEM(file, print, gtkPrint, fmenu, group); - ADD_SEP(file, fmenu); - IMAGE_ITEM(file, quit, gtkQuitMenu, fmenu, group); - SET_SUBMENU(export, fmenu); - - return fmenu; -} - -/** -* creates an edit menu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_edit_menu *nsgtk_menu_edit_submenu(GtkAccelGroup *group) -{ - struct nsgtk_edit_menu *ret = malloc(sizeof(struct nsgtk_edit_menu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->edit_menu = GTK_MENU(gtk_menu_new()); - if (ret->edit_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - IMAGE_ITEM(edit, cut, gtkCut, ret, group); - IMAGE_ITEM(edit, copy, gtkCopy, ret, group); - IMAGE_ITEM(edit, paste, gtkPaste, ret, group); - IMAGE_ITEM(edit, delete, gtkDelete, ret, group); - ADD_SEP(edit, ret); - IMAGE_ITEM(edit, selectall, gtkSelectAll, ret, group); - ADD_SEP(edit, ret); - IMAGE_ITEM(edit, find, gtkFind, ret, group); - ADD_SEP(edit, ret); - IMAGE_ITEM(edit, preferences, gtkPreferences, ret, group); - - return ret; -} - -/** -* creates a view menu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_view_menu *nsgtk_menu_view_submenu(GtkAccelGroup *group) -{ - struct nsgtk_view_menu *ret = malloc(sizeof(struct nsgtk_view_menu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->view_menu = GTK_MENU(gtk_menu_new()); - if (ret->view_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - 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); - IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group); - IMAGE_ITEM(view, viewsource, gtkViewSource, ret, group); - ADD_SEP(view, ret); - IMAGE_ITEM(view, images, gtkImages, ret, group); - IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group); - IMAGE_ITEM(view, tabs, gtkTabs, ret, group); - ADD_SEP(view, ret); - IMAGE_ITEM(view, downloads, gtkDownloads, ret, group); - IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group); - IMAGE_ITEM(view, debugging, gtkDebugging, ret, group); - SET_SUBMENU(scaleview, ret); - SET_SUBMENU(images, ret); - SET_SUBMENU(toolbars, ret); - SET_SUBMENU(tabs, ret); - SET_SUBMENU(debugging, ret); - - - return ret; -} - -/** -* creates a nav menu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group) -{ - struct nsgtk_nav_menu *ret = malloc(sizeof(struct nsgtk_nav_menu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->nav_menu = GTK_MENU(gtk_menu_new()); - if (ret->nav_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - - IMAGE_ITEM(nav, back, gtkBack, ret, group); - IMAGE_ITEM(nav, forward, gtkForward, ret, group); - IMAGE_ITEM(nav, home, gtkHome, ret, group); - ADD_SEP(nav, ret); - IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group); - IMAGE_ITEM(nav, globalhistory, gtkGlobalHistory, ret, group); - ADD_SEP(nav, ret); - IMAGE_ITEM(nav, addbookmarks, gtkAddBookMarks, ret, group); - IMAGE_ITEM(nav, showbookmarks, gtkShowBookMarks, ret, group); - ADD_SEP(nav, ret); - IMAGE_ITEM(nav, showcookies, gtkShowCookies, ret, group); - ADD_SEP(nav, ret); - IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group); - - - return ret; -} - -/** -* creates a help menu -* \param group the 'global' in a gtk sense accelerator reference -*/ - -static struct nsgtk_help_menu *nsgtk_menu_help_submenu(GtkAccelGroup *group) -{ - struct nsgtk_help_menu *ret = malloc(sizeof(struct nsgtk_help_menu)); - if (ret == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - ret->help_menu = GTK_MENU(gtk_menu_new()); - if (ret->help_menu == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(ret); - return NULL; - } - IMAGE_ITEM(help, contents, gtkContents, ret, group); - IMAGE_ITEM(help, guide, gtkGuide, ret, group); - IMAGE_ITEM(help, info, gtkUserInformation, ret, group); - ADD_SEP(help, ret); - IMAGE_ITEM(help, about, gtkAbout, ret, group); - - return ret; -} - - -/** - * Generate menubar menus. - * - * Generate the main menu structure and attach it to a menubar widget. - */ -struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkWindow *window) -{ - GtkAccelGroup *group; - struct nsgtk_bar_submenu *nmenu; - - nmenu = malloc(sizeof(struct nsgtk_bar_submenu)); - if (nmenu == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - - nmenu->bar_menu = GTK_MENU_BAR(menubar); - - group = gtk_accel_group_new(); - gtk_window_add_accel_group(window, group); - - nmenu->file_submenu = nsgtk_menu_file_submenu(group); - ATTACH_PARENT(menubar, gtkFile, nmenu->file_submenu->file, group); - - nmenu->edit_submenu = nsgtk_menu_edit_submenu(group); - ATTACH_PARENT(menubar, gtkEdit, nmenu->edit_submenu->edit, group); - - nmenu->view_submenu = nsgtk_menu_view_submenu(group); - ATTACH_PARENT(menubar, gtkView, nmenu->view_submenu->view, group); - - nmenu->nav_submenu = nsgtk_menu_nav_submenu(group); - ATTACH_PARENT(menubar, gtkNavigate, nmenu->nav_submenu->nav, group); - - nmenu->help_submenu = nsgtk_menu_help_submenu(group); - ATTACH_PARENT(menubar, gtkHelp, nmenu->help_submenu->help, group); - - return nmenu; -} - -/** - * Generate right click menu menu. - * - */ -struct nsgtk_popup_submenu *nsgtk_menu_popup_create(GtkWindow *window) -{ - GtkAccelGroup *group; - struct nsgtk_popup_submenu *nmenu; - - nmenu = malloc(sizeof(struct nsgtk_popup_submenu)); - if (nmenu == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - - group = gtk_accel_group_new(); - gtk_window_add_accel_group(window, group); - - nmenu->popup_menu = GTK_MENU(gtk_menu_new()); - - IMAGE_ITEM(popup, file, gtkFile, nmenu, group); - SET_SUBMENU(file, nmenu); - - IMAGE_ITEM(popup, edit, gtkEdit, nmenu, group); - SET_SUBMENU(edit, nmenu); - - IMAGE_ITEM(popup, view, gtkView, nmenu, group); - SET_SUBMENU(view, nmenu); - - IMAGE_ITEM(popup, nav, gtkNavigate, nmenu, group); - SET_SUBMENU(nav, nmenu); - - IMAGE_ITEM(popup, help, gtkHelp, nmenu, group); - SET_SUBMENU(help, nmenu); - - ADD_NAMED_SEP(popup, first, nmenu); - - IMAGE_ITEM(popup, opentab, gtkOpentab, nmenu, group); - IMAGE_ITEM(popup, openwin, gtkOpenwin, nmenu, group); - IMAGE_ITEM(popup, savelink, gtkSavelink, nmenu, group); - - ADD_NAMED_SEP(popup, second, nmenu); - - IMAGE_ITEM(popup, back, gtkBack, nmenu, group); - IMAGE_ITEM(popup, forward, gtkForward, nmenu, group); - - ADD_NAMED_SEP(popup, third, nmenu); - - IMAGE_ITEM(popup, stop, gtkStop, nmenu, group); - IMAGE_ITEM(popup, reload, gtkReload, nmenu, group); - 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); - - - return nmenu; -} diff --git a/gtk/gtk_menu.h b/gtk/gtk_menu.h deleted file mode 100644 index 84faa5f71..000000000 --- a/gtk/gtk_menu.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ -#ifndef _NETSURF_GTK_MENU_H_ -#define _NETSURF_GTK_MENU_H_ - -#include - -struct nsgtk_file_menu { - GtkMenuItem *file; /* File menu item on menubar */ - GtkMenu *file_menu; - GtkImageMenuItem *newwindow_menuitem; - GtkImageMenuItem *newtab_menuitem; - GtkImageMenuItem *openfile_menuitem; - GtkImageMenuItem *closewindow_menuitem; - GtkImageMenuItem *savepage_menuitem; - GtkImageMenuItem *export_menuitem; - struct nsgtk_export_submenu *export_submenu; - GtkImageMenuItem *printpreview_menuitem; - GtkImageMenuItem *print_menuitem; - GtkImageMenuItem *quit_menuitem; -}; - -struct nsgtk_edit_menu { - GtkMenuItem *edit; /* Edit menu item on menubar */ - GtkMenu *edit_menu; - GtkImageMenuItem *cut_menuitem; - GtkImageMenuItem *copy_menuitem; - GtkImageMenuItem *paste_menuitem; - GtkImageMenuItem *delete_menuitem; - GtkImageMenuItem *selectall_menuitem; - GtkImageMenuItem *find_menuitem; - GtkImageMenuItem *preferences_menuitem; -}; - -struct nsgtk_view_menu { - GtkMenuItem *view; /* View menu item on menubar */ - GtkMenu *view_menu; /* gtk menu attached to menu item */ - GtkImageMenuItem *stop_menuitem; - GtkImageMenuItem *reload_menuitem; - GtkImageMenuItem *scaleview_menuitem; - struct nsgtk_scaleview_submenu *scaleview_submenu; - GtkImageMenuItem *fullscreen_menuitem; - GtkImageMenuItem *viewsource_menuitem; - GtkImageMenuItem *images_menuitem; - struct nsgtk_images_submenu *images_submenu; - GtkImageMenuItem *toolbars_menuitem; - struct nsgtk_toolbars_submenu *toolbars_submenu; - GtkImageMenuItem *tabs_menuitem; - struct nsgtk_tabs_submenu *tabs_submenu; - GtkImageMenuItem *downloads_menuitem; - GtkImageMenuItem *savewindowsize_menuitem; - GtkImageMenuItem *debugging_menuitem; - struct nsgtk_debugging_submenu *debugging_submenu; -}; - -struct nsgtk_nav_menu { - GtkMenuItem *nav; /* Nav menu item on menubar */ - GtkMenu *nav_menu; - GtkImageMenuItem *back_menuitem; - GtkImageMenuItem *forward_menuitem; - GtkImageMenuItem *home_menuitem; - GtkImageMenuItem *localhistory_menuitem; - GtkImageMenuItem *globalhistory_menuitem; - GtkImageMenuItem *addbookmarks_menuitem; - GtkImageMenuItem *showbookmarks_menuitem; - GtkImageMenuItem *showcookies_menuitem; - GtkImageMenuItem *openlocation_menuitem; -}; - -struct nsgtk_help_menu { - GtkMenuItem *help; /* Help menu item on menubar */ - GtkMenu *help_menu; - GtkImageMenuItem *contents_menuitem; - GtkImageMenuItem *guide_menuitem; - GtkImageMenuItem *info_menuitem; - GtkImageMenuItem *about_menuitem; -}; - -struct nsgtk_export_submenu { - GtkMenu *export_menu; - GtkImageMenuItem *plaintext_menuitem; - GtkImageMenuItem *drawfile_menuitem; - GtkImageMenuItem *postscript_menuitem; - GtkImageMenuItem *pdf_menuitem; -}; - -struct nsgtk_scaleview_submenu { - GtkMenu *scaleview_menu; - GtkImageMenuItem *zoomplus_menuitem; - GtkImageMenuItem *zoomminus_menuitem; - GtkImageMenuItem *zoomnormal_menuitem; -}; - -struct nsgtk_tabs_submenu { - GtkMenu *tabs_menu; - GtkImageMenuItem *nexttab_menuitem; - GtkImageMenuItem *prevtab_menuitem; - GtkImageMenuItem *closetab_menuitem; -}; - -struct nsgtk_images_submenu { - GtkMenu *images_menu; - GtkCheckMenuItem *foregroundimages_menuitem; - GtkCheckMenuItem *backgroundimages_menuitem; -}; - -struct nsgtk_toolbars_submenu { - GtkMenu *toolbars_menu; - GtkCheckMenuItem *menubar_menuitem; - GtkCheckMenuItem *toolbar_menuitem; -}; - -struct nsgtk_debugging_submenu { - GtkMenu *debugging_menu; - GtkImageMenuItem *toggledebugging_menuitem; - GtkImageMenuItem *saveboxtree_menuitem; - GtkImageMenuItem *savedomtree_menuitem; -}; - - -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_menu *tabs_submenu; - struct nsgtk_help_menu *help_submenu; -}; - -struct nsgtk_popup_submenu { - GtkMenu *popup_menu; - - GtkImageMenuItem *file_menuitem; - struct nsgtk_file_menu *file_submenu; - - GtkImageMenuItem *edit_menuitem; - struct nsgtk_edit_menu *edit_submenu; - - GtkImageMenuItem *view_menuitem; - struct nsgtk_view_menu *view_submenu; - - GtkImageMenuItem *nav_menuitem; - struct nsgtk_nav_menu *nav_submenu; - - GtkImageMenuItem *tabs_menuitem; - struct nsgtk_tabs_menu *tabs_submenu; - - GtkImageMenuItem *help_menuitem; - struct nsgtk_help_menu *help_submenu; - - GtkWidget *first_separator; - - GtkImageMenuItem *opentab_menuitem; - GtkImageMenuItem *openwin_menuitem; - GtkImageMenuItem *savelink_menuitem; - - GtkWidget *second_separator; - - /* navigation entries */ - GtkImageMenuItem *back_menuitem; - GtkImageMenuItem *forward_menuitem; - - GtkWidget *third_separator; - - /* view entries */ - GtkImageMenuItem *stop_menuitem; - GtkImageMenuItem *reload_menuitem; - - GtkImageMenuItem *cut_menuitem; - GtkImageMenuItem *copy_menuitem; - GtkImageMenuItem *paste_menuitem; - GtkImageMenuItem *customize_menuitem; - -}; - -struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkWindow *window); -struct nsgtk_popup_submenu *nsgtk_menu_popup_create(GtkWindow *window); - -#endif diff --git a/gtk/gtk_plotters.c b/gtk/gtk_plotters.c deleted file mode 100644 index 1428710ec..000000000 --- a/gtk/gtk_plotters.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2005 James Bursa - * - * 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 . - */ - -/** \file - * Target independent plotting (GDK / GTK+ and Cairo implementation). - * Can use either GDK drawing primitives (which are mostly passed straight - * to X to process, and thus accelerated) or Cairo drawing primitives (much - * higher quality, not accelerated). Cairo's fast enough, so it defaults - * to using it if it is available. It does this by checking for the - * CAIRO_VERSION define that the cairo headers set. - */ - -#include -#include -#include -#include -#include "desktop/plotters.h" -#include "gtk/font_pango.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_scaffolding.h" -#include "render/font.h" -#include "utils/log.h" -#include "desktop/options.h" -#include "gtk/options.h" -#include "gtk/gtk_bitmap.h" - -#ifndef CAIRO_VERSION -#error "nsgtk requires cairo" -#endif - -GtkWidget *current_widget; -GdkDrawable *current_drawable; -GdkGC *current_gc; -cairo_t *current_cr; - -static GdkRectangle cliprect; -static float nsgtk_plot_scale = 1.0; - -struct plotter_table plot; - -/** set plotting scale factor. */ -void nsgtk_plot_set_scale(float s) -{ - nsgtk_plot_scale = s; -} - -/** get plotting scale factor. */ -float nsgtk_plot_get_scale(void) -{ - return nsgtk_plot_scale; -} - -/** Set cairo context colour to nsgtk colour. */ -void nsgtk_set_colour(colour c) -{ - int r, g, b; - GdkColor colour; - - r = c & 0xff; - g = (c & 0xff00) >> 8; - b = (c & 0xff0000) >> 16; - - colour.red = r | (r << 8); - colour.green = g | (g << 8); - colour.blue = b | (b << 8); - colour.pixel = (r << 16) | (g << 8) | b; - - gdk_color_alloc(gdk_colormap_get_system(), - &colour); - gdk_gc_set_foreground(current_gc, &colour); - - cairo_set_source_rgba(current_cr, r / 255.0, - g / 255.0, b / 255.0, 1.0); -} - -/** Plot a caret. - * - * @note It is assumed that the plotters have been set up. - */ -void nsgtk_plot_caret(int x, int y, int h) -{ - GdkColor colour; - - colour.red = 0; - colour.green = 0; - colour.blue = 0; - colour.pixel = 0; - gdk_color_alloc(gdk_colormap_get_system(), - &colour); - gdk_gc_set_foreground(current_gc, &colour); - - gdk_draw_line(current_drawable, current_gc, - x, y, - x, y + h - 1); -} - -/** Set cairo context to solid plot operation. */ -static inline void nsgtk_set_solid(void) -{ - double dashes = 0; - cairo_set_dash(current_cr, &dashes, 0, 0); -} - -/** Set cairo context to dotted plot operation. */ -static inline void nsgtk_set_dotted(void) -{ - double cdashes[] = { 1.0, 2.0 }; - cairo_set_dash(current_cr, cdashes, 2, 0); -} - -/** Set cairo context to dashed plot operation. */ -static inline void nsgtk_set_dashed(void) -{ - double cdashes[] = { 8.0, 2.0 }; - cairo_set_dash(current_cr, cdashes, 2, 0); -} - -/** Set clipping area for subsequent plot operations. */ -static bool nsgtk_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1) -{ - cairo_reset_clip(current_cr); - cairo_rectangle(current_cr, clip_x0, clip_y0, - clip_x1 - clip_x0, clip_y1 - clip_y0); - cairo_clip(current_cr); - - cliprect.x = clip_x0; - cliprect.y = clip_y0; - cliprect.width = clip_x1 - clip_x0; - cliprect.height = clip_y1 - clip_y0; - gdk_gc_set_clip_rectangle(current_gc, &cliprect); - - return true; -} - - -static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) -{ - nsgtk_set_colour(style->fill_colour); - nsgtk_set_solid(); - - cairo_set_line_width(current_cr, 1); - cairo_arc(current_cr, x, y, radius, - (angle1 + 90) * (M_PI / 180), - (angle2 + 90) * (M_PI / 180)); - cairo_stroke(current_cr); - - return true; -} - -static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ - if (style->fill_type != PLOT_OP_TYPE_NONE) { - nsgtk_set_colour(style->fill_colour); - nsgtk_set_solid(); - cairo_set_line_width(current_cr, 0); - cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); - cairo_fill(current_cr); - cairo_stroke(current_cr); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - nsgtk_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_set_dashed(); - break; - } - - if (style->stroke_width == 0) - cairo_set_line_width(current_cr, 1); - else - cairo_set_line_width(current_cr, style->stroke_width); - - cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); - - cairo_stroke(current_cr); - } - - return true; -} - -static bool nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - - nsgtk_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_set_dashed(); - break; - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - 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); - - /* core expects horizontal and vertical lines to be on pixels, not - * between pixels */ - cairo_move_to(current_cr, (x0 == x1) ? x0 + 0.5 : x0, - (y0 == y1) ? y0 + 0.5 : y0); - cairo_line_to(current_cr, (x0 == x1) ? x1 + 0.5 : x1, - (y0 == y1) ? y1 + 0.5 : y1); - cairo_stroke(current_cr); - - return true; -} - - -static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - if (style->fill_type != PLOT_OP_TYPE_NONE) { - nsgtk_set_colour(style->fill_colour); - nsgtk_set_solid(); - - cairo_set_line_width(current_cr, 0); - cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0); - cairo_fill(current_cr); - cairo_stroke(current_cr); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - nsgtk_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_set_dashed(); - break; - } - - if (style->stroke_width == 0) - cairo_set_line_width(current_cr, 1); - else - cairo_set_line_width(current_cr, style->stroke_width); - - cairo_rectangle(current_cr, x0 + 0.5, y0 + 0.5, x1 - x0, y1 - y0); - cairo_stroke(current_cr); - } - return true; -} - -static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - unsigned int i; - - nsgtk_set_colour(style->fill_colour); - nsgtk_set_solid(); - - cairo_set_line_width(current_cr, 0); - cairo_move_to(current_cr, p[0], p[1]); - for (i = 1; i != n; i++) { - cairo_line_to(current_cr, p[i * 2], p[i * 2 + 1]); - } - cairo_fill(current_cr); - cairo_stroke(current_cr); - - return true; -} - - - - -static bool nsgtk_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) -{ - return nsfont_paint(x, y, text, length, fstyle); -} - - - -static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, - GdkPixbuf *pixbuf, colour bg) -{ - /* XXX: This currently ignores the background colour supplied. - * Does this matter? - */ - - int x0, y0, x1, y1; - int dsrcx, dsrcy, dwidth, dheight; - - /* Bail early if we can */ - if (width == 0 || height == 0) - /* Nothing to plot */ - return true; - if ((x > (cliprect.x + cliprect.width)) || - ((x + width) < cliprect.x) || - (y > (cliprect.y + cliprect.height)) || - ((y + height) < cliprect.y)) { - /* Image completely outside clip region */ - return true; - } - - /* Get clip rectangle / image rectangle edge differences */ - x0 = cliprect.x - x; - y0 = cliprect.y - y; - x1 = (x + width) - (cliprect.x + cliprect.width); - y1 = (y + height) - (cliprect.y + cliprect.height); - - /* Set initial draw geometry */ - dsrcx = dsrcy = 0; - dwidth = width; - dheight = height; - - /* Manually clip draw coordinates to area of image to be rendered */ - if (x0 > 0) { - /* Clip left */ - dsrcx = x0; - x += x0; - dwidth -= x0; - } - if (y0 > 0) { - /* Clip top */ - dsrcy = y0; - y += y0; - dheight -= y0; - } - if (x1 > 0) { - /* Clip right */ - dwidth -= x1; - } - if (y1 > 0) { - /* Clip bottom */ - dheight -= y1; - } - - if (dwidth == 0 || dheight == 0) - /* Nothing to plot */ - return true; - - /* Render the bitmap */ - if (gdk_pixbuf_get_width(pixbuf) == width && - gdk_pixbuf_get_height(pixbuf) == height) { - /* Bitmap is not scaled */ - /* Plot the bitmap */ - gdk_draw_pixbuf(current_drawable, current_gc, pixbuf, - dsrcx, dsrcy, x, y, dwidth, dheight, - GDK_RGB_DITHER_MAX, 0, 0); - - } else { - /* Bitmap is scaled */ - /* Get scale factors */ - double sx = (double)width / gdk_pixbuf_get_width(pixbuf); - double sy = (double)height / gdk_pixbuf_get_height(pixbuf); - - /* Create bitmap for scaled image portion */ - GdkPixbuf *scaled = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, - dwidth, dheight); - /* Only scale up the portion of the bitmap that we are - * interested in rendering */ - gdk_pixbuf_scale(pixbuf, scaled, - 0, 0, dwidth, dheight, - -dsrcx, -dsrcy, sx, sy, - option_render_resample ? GDK_INTERP_BILINEAR : - GDK_INTERP_NEAREST); - if (!scaled) - return false; - - /* Plot the scaled bitmap */ - gdk_draw_pixbuf(current_drawable, current_gc, scaled, - 0, 0, x, y, dwidth, dheight, - GDK_RGB_DITHER_MAX, 0, 0); - - g_object_unref(scaled); - } - - return true; -} - -static bool nsgtk_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) -{ - int doneheight = 0, donewidth = 0; - GdkPixbuf *primary; - GdkPixbuf *pretiled = NULL; - - bool repeat_x = (flags & BITMAPF_REPEAT_X); - bool repeat_y = (flags & BITMAPF_REPEAT_Y); - - if (!(repeat_x || repeat_y)) { - /* Not repeating at all, so just pass it on */ - primary = gtk_bitmap_get_primary(bitmap); - return nsgtk_plot_pixbuf(x, y, width, height, primary, bg); - } - - if (repeat_x && !repeat_y) - pretiled = gtk_bitmap_get_pretile_x(bitmap); - if (repeat_x && repeat_y) - pretiled = gtk_bitmap_get_pretile_xy(bitmap); - if (!repeat_x && repeat_y) - pretiled = gtk_bitmap_get_pretile_y(bitmap); - - assert(pretiled != NULL); - - primary = gtk_bitmap_get_primary(bitmap); - /* use the primary and pretiled widths to scale the w/h provided */ - width *= gdk_pixbuf_get_width(pretiled); - width /= gdk_pixbuf_get_width(primary); - height *= gdk_pixbuf_get_height(pretiled); - height /= gdk_pixbuf_get_height(primary); - - if (y > cliprect.y) - doneheight = (cliprect.y - height) + ((y - cliprect.y) % height); - else - doneheight = y; - - while (doneheight < (cliprect.y + cliprect.height)) { - if (x > cliprect.x) - donewidth = (cliprect.x - width) + ((x - cliprect.x) % width); - else - donewidth = x; - while (donewidth < (cliprect.x + cliprect.width)) { - nsgtk_plot_pixbuf(donewidth, doneheight, - width, height, pretiled, bg); - donewidth += width; - if (!repeat_x) break; - } - doneheight += height; - if (!repeat_y) break; - } - - return true; -} - -static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - unsigned int i; - cairo_matrix_t old_ctm, n_ctm; - - if (n == 0) - return true; - - if (p[0] != PLOTTER_PATH_MOVE) { - LOG(("Path does not start with move")); - return false; - } - - - /* Save CTM */ - cairo_get_matrix(current_cr, &old_ctm); - - /* Set up line style and width */ - cairo_set_line_width(current_cr, 1); - nsgtk_set_solid(); - - /* Load new CTM */ - n_ctm.xx = transform[0]; - 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]; - - cairo_set_matrix(current_cr, &n_ctm); - - /* Construct path */ - for (i = 0; i < n; ) { - if (p[i] == PLOTTER_PATH_MOVE) { - cairo_move_to(current_cr, p[i+1], p[i+2]); - i += 3; - } else if (p[i] == PLOTTER_PATH_CLOSE) { - cairo_close_path(current_cr); - i++; - } else if (p[i] == PLOTTER_PATH_LINE) { - cairo_line_to(current_cr, p[i+1], p[i+2]); - i += 3; - } else if (p[i] == PLOTTER_PATH_BEZIER) { - cairo_curve_to(current_cr, p[i+1], p[i+2], - p[i+3], p[i+4], - p[i+5], p[i+6]); - i += 7; - } else { - LOG(("bad path command %f", p[i])); - /* Reset matrix for safety */ - cairo_set_matrix(current_cr, &old_ctm); - return false; - } - } - - /* Restore original CTM */ - cairo_set_matrix(current_cr, &old_ctm); - - /* Now draw path */ - if (fill != NS_TRANSPARENT) { - nsgtk_set_colour(fill); - - if (c != NS_TRANSPARENT) { - /* Fill & Stroke */ - cairo_fill_preserve(current_cr); - nsgtk_set_colour(c); - cairo_stroke(current_cr); - } else { - /* Fill only */ - cairo_fill(current_cr); - } - } else if (c != NS_TRANSPARENT) { - /* Stroke only */ - nsgtk_set_colour(c); - cairo_stroke(current_cr); - } - - return true; -} - -/** GTK plotter table */ -const struct plotter_table nsgtk_plotters = { - .clip = nsgtk_plot_clip, - .arc = nsgtk_plot_arc, - .disc = nsgtk_plot_disc, - .line = nsgtk_plot_line, - .rectangle = nsgtk_plot_rectangle, - .polygon = nsgtk_plot_polygon, - .path = nsgtk_plot_path, - .bitmap = nsgtk_plot_bitmap, - .text = nsgtk_plot_text, - .option_knockout = true -}; - - - diff --git a/gtk/gtk_plotters.h b/gtk/gtk_plotters.h deleted file mode 100644 index a59ae00bb..000000000 --- a/gtk/gtk_plotters.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2005 James Bursa - * - * 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 . - */ - -/** \file - * Target independent plotting (GDK / GTK+ interface). - */ - -#ifndef NETSURF_GTK_PLOTTERS_H -#define NETSURF_GTK_PLOTTERS_H 1 - -#include - -struct plotter_table; - -extern const struct plotter_table nsgtk_plotters; - -/* make sure this is NULL if no redraw is in progress */ -extern GtkWidget *current_widget; -extern GdkDrawable *current_drawable; -extern GdkGC *current_gc; -#ifdef CAIRO_VERSION -extern cairo_t *current_cr; -#endif - -void nsgtk_plot_set_scale(float s); -float nsgtk_plot_get_scale(void); -void nsgtk_set_colour(colour c); -void nsgtk_plot_caret(int x, int y, int h); - -#endif /* NETSURF_GTK_PLOTTERS_H */ - diff --git a/gtk/gtk_print.c b/gtk/gtk_print.c deleted file mode 100644 index f08880157..000000000 --- a/gtk/gtk_print.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2005 James Bursa - * Copyright 2008 Adam Blokus - * - * 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 . - */ - /** \file - * GTK printing (implementation). - * All the functions and structures necessary for printing( signal handlers, - * plotters, printer) are here. - * Most of the plotters have been copied from the gtk_plotters.c file. - */ - -#include "utils/config.h" - -#include -#include -#include -#include - -#include "content/content.h" -#include "content/hlcache.h" -#include "desktop/options.h" -#include "desktop/plotters.h" -#include "desktop/print.h" -#include "desktop/printer.h" -#include "gtk/font_pango.h" -#include "gtk/gtk_bitmap.h" -#include "gtk/gtk_print.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/options.h" -#include "render/font.h" -#include "utils/log.h" -#include "utils/utils.h" - -/* Globals */ -cairo_t *gtk_print_current_cr; -static struct print_settings* settings; -hlcache_handle *content_to_print; -static GdkRectangle cliprect; - -static inline void nsgtk_print_set_colour(colour c) -{ - int r, g, b; - GdkColor colour; - - r = c & 0xff; - g = (c & 0xff00) >> 8; - b = (c & 0xff0000) >> 16; - - colour.red = r | (r << 8); - colour.green = g | (g << 8); - colour.blue = b | (b << 8); - colour.pixel = (r << 16) | (g << 8) | b; - - gdk_color_alloc(gdk_colormap_get_system(), &colour); - - cairo_set_source_rgba(gtk_print_current_cr, r / 255.0, - g / 255.0, b / 255.0, 1.0); -} - -static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height, - GdkPixbuf *pixbuf, colour bg) -{ - /* XXX: This currently ignores the background colour supplied. - * Does this matter? - */ - - if (width == 0 || height == 0) - return true; - - if (gdk_pixbuf_get_width(pixbuf) == width && - gdk_pixbuf_get_height(pixbuf) == height) { - gdk_cairo_set_source_pixbuf(gtk_print_current_cr, pixbuf, x, y); - cairo_paint(gtk_print_current_cr); - } else { - GdkPixbuf *scaled; - scaled = gdk_pixbuf_scale_simple(pixbuf, - width, height, - /* plotting for the printer doesn't have - * to be fast so we can use always the - * interp_style that gives better quality - */ - GDK_INTERP_BILINEAR); - if (!scaled) - return false; - - gdk_cairo_set_source_pixbuf(gtk_print_current_cr, scaled, x, y); - cairo_paint(gtk_print_current_cr); - - g_object_unref(scaled); - } - - return true; -} - - -static bool gtk_print_font_paint(int x, int y, - const char *string, size_t length, - const plot_font_style_t *fstyle) -{ - PangoFontDescription *desc; - PangoLayout *layout; - gint size; - PangoLayoutLine *line; - - if (length == 0) - return true; - - desc = nsfont_style_to_description(fstyle); - size = (gint) ((double) pango_font_description_get_size(desc) * - settings->scale); - - if (pango_font_description_get_size_is_absolute(desc)) - pango_font_description_set_absolute_size(desc, size); - else - pango_font_description_set_size(desc, size); - - layout = pango_cairo_create_layout(gtk_print_current_cr); - - pango_layout_set_font_description(layout, desc); - pango_layout_set_text(layout, string, length); - - line = pango_layout_get_line(layout, 0); - - cairo_move_to(gtk_print_current_cr, x, y); - nsgtk_print_set_colour(fstyle->foreground); - pango_cairo_show_layout_line(gtk_print_current_cr, line); - - g_object_unref(layout); - pango_font_description_free(desc); - - return true; -} - - -/** Set cairo context to solid plot operation. */ -static inline void nsgtk_print_set_solid(void) -{ - double dashes = 0; - cairo_set_dash(gtk_print_current_cr, &dashes, 0, 0); -} - -/** Set cairo context to dotted plot operation. */ -static inline void nsgtk_print_set_dotted(void) -{ - double cdashes[] = { 1.0, 2.0 }; - cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); -} - -/** Set cairo context to dashed plot operation. */ -static inline void nsgtk_print_set_dashed(void) -{ - double cdashes[] = { 8.0, 2.0 }; - cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); -} - -/** Set clipping area for subsequent plot operations. */ -static bool nsgtk_print_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1) -{ - LOG(("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", - clip_x0,clip_y0,clip_x1,clip_y1)); - - /* Normalize cllipping area - to prevent overflows. - * See comment in pdf_plot_fill. */ - clip_x0 = min(max(clip_x0, 0), settings->page_width); - clip_y0 = min(max(clip_y0, 0), settings->page_height); - clip_x1 = min(max(clip_x1, 0), settings->page_width); - clip_y1 = min(max(clip_y1, 0), settings->page_height); - - cairo_reset_clip(gtk_print_current_cr); - cairo_rectangle(gtk_print_current_cr, clip_x0, clip_y0, - clip_x1 - clip_x0, clip_y1 - clip_y0); - cairo_clip(gtk_print_current_cr); - - cliprect.x = clip_x0; - cliprect.y = clip_y0; - cliprect.width = clip_x1 - clip_x0; - cliprect.height = clip_y1 - clip_y0; - - return true; -} - -static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) -{ - nsgtk_print_set_colour(style->fill_colour); - nsgtk_print_set_solid(); - - cairo_set_line_width(gtk_print_current_cr, 1); - cairo_arc(gtk_print_current_cr, x, y, radius, - (angle1 + 90) * (M_PI / 180), - (angle2 + 90) * (M_PI / 180)); - cairo_stroke(gtk_print_current_cr); - - return true; -} - -static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ - if (style->fill_type != PLOT_OP_TYPE_NONE) { - nsgtk_print_set_colour(style->fill_colour); - nsgtk_print_set_solid(); - cairo_set_line_width(gtk_print_current_cr, 0); - cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2); - cairo_fill(gtk_print_current_cr); - cairo_stroke(gtk_print_current_cr); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - nsgtk_print_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_print_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_print_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_print_set_dashed(); - 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); - - cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2); - - cairo_stroke(gtk_print_current_cr); - } - return true; -} - -static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - nsgtk_print_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_print_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_print_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_print_set_dashed(); - 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); - - cairo_move_to(gtk_print_current_cr, x0 + 0.5, y0 + 0.5); - cairo_line_to(gtk_print_current_cr, x1 + 0.5, y1 + 0.5); - cairo_stroke(gtk_print_current_cr); - - return true; -} - -static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - LOG(("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0,y0,x1,y1)); - - if (style->fill_type != PLOT_OP_TYPE_NONE) { - - nsgtk_print_set_colour(style->fill_colour); - nsgtk_print_set_solid(); - - /* Normalize boundaries of the area - to prevent overflows. - * See comment in pdf_plot_fill. */ - x0 = min(max(x0, 0), settings->page_width); - y0 = min(max(y0, 0), settings->page_height); - x1 = min(max(x1, 0), settings->page_width); - y1 = min(max(y1, 0), settings->page_height); - - cairo_set_line_width(gtk_print_current_cr, 0); - cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0); - cairo_fill(gtk_print_current_cr); - cairo_stroke(gtk_print_current_cr); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - nsgtk_print_set_colour(style->stroke_colour); - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - nsgtk_print_set_solid(); - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - nsgtk_print_set_dotted(); - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - nsgtk_print_set_dashed(); - 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); - - cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0); - cairo_stroke(gtk_print_current_cr); - } - - return true; -} - -static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - unsigned int i; - - LOG(("Plotting polygon.")); - - nsgtk_print_set_colour(style->fill_colour); - nsgtk_print_set_solid(); - - cairo_set_line_width(gtk_print_current_cr, 0); - cairo_move_to(gtk_print_current_cr, p[0], p[1]); - - LOG(("Starting line at: %i\t%i",p[0],p[1])); - - for (i = 1; i != n; i++) { - cairo_line_to(gtk_print_current_cr, p[i * 2], p[i * 2 + 1]); - LOG(("Drawing line to: %i\t%i",p[i * 2], p[i * 2 + 1])); - } - - cairo_fill(gtk_print_current_cr); - cairo_stroke(gtk_print_current_cr); - - return true; -} - - -static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]) -{ - /* Only the internal SVG renderer uses this plot call currently, - * and the GTK version uses librsvg. Thus, we ignore this complexity, - * and just return true obliviously. */ - - return true; -} - -static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) -{ - int doneheight = 0, donewidth = 0; - GdkPixbuf *primary; - GdkPixbuf *pretiled = NULL; - - bool repeat_x = (flags & BITMAPF_REPEAT_X); - bool repeat_y = (flags & BITMAPF_REPEAT_Y); - - if (!(repeat_x || repeat_y)) { - /* Not repeating at all, so just pass it on */ - primary = gtk_bitmap_get_primary(bitmap); - return nsgtk_print_plot_pixbuf(x, y, width, height, primary, bg); - } - - if (repeat_x && !repeat_y) - pretiled = gtk_bitmap_get_pretile_x(bitmap); - if (repeat_x && repeat_y) - pretiled = gtk_bitmap_get_pretile_xy(bitmap); - if (!repeat_x && repeat_y) - pretiled = gtk_bitmap_get_pretile_y(bitmap); - - assert(pretiled != NULL); - - primary = gtk_bitmap_get_primary(bitmap); - - /* use the primary and pretiled widths to scale the w/h provided */ - width *= gdk_pixbuf_get_width(pretiled); - width /= gdk_pixbuf_get_width(primary); - height *= gdk_pixbuf_get_height(pretiled); - height /= gdk_pixbuf_get_height(primary); - - if (y > cliprect.y) { - doneheight = (cliprect.y - height) + - ((y - cliprect.y) % height); - } else - doneheight = y; - - while (doneheight < (cliprect.y + cliprect.height)) { - if (x > cliprect.x) { - donewidth = (cliprect.x - width) + - ((x - cliprect.x) % width); - } else - donewidth = x; - - while (donewidth < (cliprect.x + cliprect.width)) { - nsgtk_print_plot_pixbuf(donewidth, doneheight, - width, height, pretiled, bg); - donewidth += width; - if (!repeat_x) break; - } - - doneheight += height; - - if (!repeat_y) break; - } - - return true; -} - -static bool nsgtk_print_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) -{ - return gtk_print_font_paint(x, y, text, length, fstyle); -} - -/** GTK print plotter table */ -static const struct plotter_table nsgtk_print_plotters = { - .clip = nsgtk_print_plot_clip, - .arc = nsgtk_print_plot_arc, - .disc = nsgtk_print_plot_disc, - .line = nsgtk_print_plot_line, - .rectangle = nsgtk_print_plot_rectangle, - .polygon = nsgtk_print_plot_polygon, - .path = nsgtk_print_plot_path, - .bitmap = nsgtk_print_plot_bitmap, - .text = nsgtk_print_plot_text, - .option_knockout = false, -}; - -static bool gtk_print_begin(struct print_settings* settings) -{ - return true; -} - -static bool gtk_print_next_page(void) -{ - return true; -} - -static void gtk_print_end(void) -{ -} - -static const struct printer gtk_printer = { - &nsgtk_print_plotters, - gtk_print_begin, - gtk_print_next_page, - gtk_print_end -}; - -/** - * Handle the begin_print signal from the GtkPrintOperation - * - * \param operation the operation which emited the signal - * \param context the print context used to set up the pages - * \param user_data nothing in here - */ -void gtk_print_signal_begin_print (GtkPrintOperation *operation, - GtkPrintContext *context, gpointer user_data) -{ - int page_number; - double height_on_page, height_to_print; - - LOG(("Begin print")); - - settings = user_data; - - settings->margins[MARGINTOP] = 0; - settings->margins[MARGINLEFT] = 0; - settings->margins[MARGINBOTTOM] = 0; - settings->margins[MARGINRIGHT] = 0; - settings->page_width = gtk_print_context_get_width(context); - settings->page_height = gtk_print_context_get_height(context); - settings->scale = 0.7;/*at 0.7 the pages look the best*/ - settings->font_func = &nsfont; - - print_set_up(content_to_print, >k_printer, - settings, &height_to_print); - - LOG(("page_width: %f ;page_height: %f; content height: %lf", - settings->page_width, settings->page_height, height_to_print)); - - height_on_page = settings->page_height; - height_on_page = height_on_page - - FIXTOFLT(FSUB(settings->margins[MARGINTOP], - settings->margins[MARGINBOTTOM])); - height_to_print *= settings->scale; - - page_number = height_to_print / height_on_page; - - if (height_to_print - page_number * height_on_page > 0) - page_number += 1; - - gtk_print_operation_set_n_pages(operation, page_number); -} - -/** - * Handle the draw_page signal from the GtkPrintOperation. - * This function changes only the cairo context to print on. - */ -void gtk_print_signal_draw_page(GtkPrintOperation *operation, - GtkPrintContext *context, gint page_nr, gpointer user_data) -{ - LOG(("Draw Page")); - gtk_print_current_cr = gtk_print_context_get_cairo_context(context); - print_draw_next_page(>k_printer, settings); -} - -/** - * Handle the end_print signal from the GtkPrintOperation. - * This functions calls only the print_cleanup function from the print interface - */ -void gtk_print_signal_end_print(GtkPrintOperation *operation, - GtkPrintContext *context, gpointer user_data) -{ - LOG(("End print")); - print_cleanup(content_to_print, >k_printer, user_data); -} - - diff --git a/gtk/gtk_print.h b/gtk/gtk_print.h deleted file mode 100644 index d44fad31f..000000000 --- a/gtk/gtk_print.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2008 Adam Blokus - * - * 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 . - */ - - /** \file - * GTK printing (interface). - */ - -#ifndef NETSURF_GTK_PRINT_PLOTTERS_H -#define NETSURF_GTK_PRINT_PLOTTERS_H - - -#include - -struct hlcache_handle; - -extern cairo_t *gtk_print_current_cr; - -extern struct hlcache_handle *content_to_print; - - -/*handlers for signals from the GTK print operation*/ -void gtk_print_signal_begin_print(GtkPrintOperation *operation, - GtkPrintContext *context, - gpointer user_data); - -void gtk_print_signal_draw_page(GtkPrintOperation *operation, - GtkPrintContext *context, - gint page_nr, - gpointer user_data); - -void gtk_print_signal_end_print(GtkPrintOperation *operation, - GtkPrintContext *context, - gpointer user_data); - -#endif diff --git a/gtk/gtk_save.c b/gtk/gtk_save.c deleted file mode 100644 index fc03499ea..000000000 --- a/gtk/gtk_save.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include -#include -#include -#include "content/content.h" -#include "desktop/save_complete.h" -#include "utils/utils.h" - -/** -* conducts the filesystem save appropriate to the gui -* \param path save path -* \param filename name of file to save -* \param len data length -* \param sourcedata pointer to data to save -* \param type content type -* \return true for success -*/ - -bool save_complete_gui_save(const char *path, const char *filename, - size_t len, const char *sourcedata, content_type type) -{ - int res; - int namelen; - namelen = strlen(path) + strlen(filename) + 2; /* '/', '\0' */ - char *fullpath = malloc(namelen); - if (!fullpath) { - warn_user("NoMemory", 0); - return false; - } - snprintf(fullpath, namelen, "%s/%s", path, filename); - FILE *f; - f = fopen(fullpath, "wb"); - free(fullpath); - if (f == NULL) - return false; - res = fwrite(sourcedata, len, 1, f); - fclose(f); - if (res != 1) - return false; - return true; -} - -/** -* wrapper for lib function htmlSaveFileFormat; front sets path from path -* + filename in a filesystem-specific way -*/ - -int save_complete_htmlSaveFileFormat(const char *path, const char *filename, - xmlDocPtr cur, const char *encoding, int format) -{ - int ret; - int len = strlen(path) + strlen(filename) + 2; - char *fullpath = malloc(len); - if (fullpath == NULL) { - warn_user("NoMemory", 0); - return -1; - } - snprintf(fullpath, len, "%s/%s", path, filename); - ret = htmlSaveFileFormat(fullpath, cur, encoding, format); - free(fullpath); - return ret; -} - diff --git a/gtk/gtk_scaffolding.c b/gtk/gtk_scaffolding.c deleted file mode 100644 index a79469a51..000000000 --- a/gtk/gtk_scaffolding.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "gtk/gtk_scaffolding.h" -#include "content/content.h" -#include "content/hlcache.h" -#include "css/utils.h" -#include "desktop/browser.h" -#include "desktop/history_core.h" -#include "desktop/hotlist.h" -#include "desktop/gui.h" -#include "desktop/netsurf.h" -#include "desktop/options.h" -#include "desktop/plotters.h" -#include "desktop/print.h" -#include "desktop/save_complete.h" -#ifdef WITH_PDF_EXPORT -#include "desktop/save_pdf/font_haru.h" -#include "desktop/save_pdf/pdf_plotters.h" -#endif -#include "desktop/save_text.h" -#include "desktop/search.h" -#include "desktop/searchweb.h" -#include "desktop/selection.h" -#include "desktop/textinput.h" -#include "desktop/tree.h" -#include "gtk/gtk_cookies.h" -#include "gtk/gtk_completion.h" -#include "gtk/dialogs/gtk_options.h" -#include "gtk/dialogs/gtk_about.h" -#include "gtk/dialogs/gtk_source.h" -#include "gtk/gtk_bitmap.h" -#include "gtk/gtk_download.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_history.h" -#include "gtk/gtk_hotlist.h" -#include "gtk/gtk_menu.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_print.h" -#include "gtk/gtk_schedule.h" -#include "gtk/gtk_search.h" -#include "gtk/gtk_tabs.h" -#include "gtk/gtk_theme.h" -#include "gtk/gtk_throbber.h" -#include "gtk/gtk_toolbar.h" -#include "gtk/gtk_treeview.h" -#include "gtk/gtk_window.h" -#include "gtk/options.h" -#include "gtk/sexy_icon_entry.h" -#include "gtk/gtk_compat.h" -#include "image/ico.h" -#include "render/box.h" -#include "render/font.h" -#include "render/form.h" -#include "render/html.h" -#include "utils/messages.h" -#include "utils/utils.h" -#include "utils/url.h" - -#include "utils/log.h" - -/** Connect a GTK signal handler to a widget */ -#define SIG_CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - -/** Obtain a GTK widget handle from glade xml object */ -#define GET_WIDGET(x) glade_xml_get_widget(g->xml, (x)) - -/** Macro to define a handler for menu, button and activate events. */ -#define MULTIHANDLER(q)\ -static gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g);\ -static gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *widget, gpointer data)\ -{\ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\ - return nsgtk_on_##q##_activate(g);\ -}\ -static gboolean nsgtk_on_##q##_activate_button(GtkButton *widget, gpointer data)\ -{\ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\ - return nsgtk_on_##q##_activate(g);\ -}\ -static gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g) - -/** Macro to define a handler for menu events. */ -#define MENUHANDLER(q)\ -static gboolean nsgtk_on_##q##_activate(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. */ -struct gtk_scaffolding { - GtkWindow *window; - GtkNotebook *notebook; - GtkWidget *url_bar; - GtkEntryCompletion *url_bar_completion; - - /** menu bar hierarchy */ - struct nsgtk_bar_submenu *menu_bar; - - /** right click popup menu hierarchy */ - struct nsgtk_popup_submenu *menu_popup; - - GtkToolbar *tool_bar; - struct nsgtk_button_connect *buttons[PLACEHOLDER_BUTTON]; - GtkImage *throbber; - GtkImage *icoFav; - struct gtk_search *search; - GtkImage *webSearchIco; - GtkWidget *webSearchEntry; - GtkPaned *status_pane; - - int offset; - int toolbarmem; - int toolbarbase; - int historybase; - - GladeXML *xml; - - struct gtk_history_window *history_window; - GtkDialog *preferences_dialog; - - int throb_frame; - struct gui_window *top_level; - int being_destroyed; - - bool fullscreen; - - /* keep global linked list for gui interface adjustments */ - struct gtk_scaffolding *next, *prev; -}; - -/** current number of open browser windows */ -static int open_windows = 0; - -/** current window for model dialogue use */ -static struct gtk_scaffolding *current_model; - -/** global list for interface changes */ -nsgtk_scaffolding *scaf_list = NULL; - -/** The box containing a link under the mouse, or 0 if none */ -static struct box *current_menu_link_box; - -/** - * Helper to hide popup menu entries by grouping - */ -static void popup_menu_hide(struct nsgtk_popup_submenu *menu, bool submenu, - bool link, bool nav, bool cnp, bool custom) -{ - 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 (link) { - gtk_widget_hide(GTK_WIDGET(menu->opentab_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->openwin_menuitem)); - gtk_widget_hide(GTK_WIDGET(menu->savelink_menuitem)); - - gtk_widget_hide(menu->second_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)); - } - - 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)); - } - -} - -/** - * Helper to show popup menu entries by grouping - */ -static void popup_menu_show(struct nsgtk_popup_submenu *menu, bool submenu, - bool link, bool nav, bool cnp, bool custom) -{ - 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 (link) { - gtk_widget_show(GTK_WIDGET(menu->opentab_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->openwin_menuitem)); - gtk_widget_show(GTK_WIDGET(menu->savelink_menuitem)); - - gtk_widget_show(menu->second_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)); - } - - 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)); - } - -} - - -/* event handlers and support functions for them */ - -/** - * resource cleanup function for window closure. - */ -static void nsgtk_window_close(struct gtk_scaffolding *g) -{ - /* close all tabs first */ - gint numbertabs = gtk_notebook_get_n_pages(g->notebook); - while (numbertabs-- > 1) { - nsgtk_tab_close_current(g->notebook); - } - LOG(("Being Destroyed = %d", g->being_destroyed)); - - if ((g->history_window) && (g->history_window->window)) { - gtk_widget_destroy(GTK_WIDGET(g->history_window->window)); - } - - if (--open_windows == 0) - netsurf_quit = true; - - if (!g->being_destroyed) { - g->being_destroyed = 1; - nsgtk_window_destroy_browser(g->top_level); - } - if (g->prev != NULL) - g->prev->next = g->next; - else - scaf_list = g->next; - - if (g->next != NULL) - g->next->prev = g->prev; - -} - -static gboolean nsgtk_window_delete_event(GtkWidget *widget, - GdkEvent *event, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - if ((open_windows != 1) || - nsgtk_check_for_downloads(GTK_WINDOW(widget)) == false) { - nsgtk_window_close(g); - gtk_widget_destroy(GTK_WIDGET(g->window)); - } - return TRUE; -} - -/* exported interface documented in gtk_scaffold.h */ -void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g) -{ - /* Our top_level has asked us to die */ - LOG(("Being Destroyed = %d", g->being_destroyed)); - if (g->being_destroyed) return; - g->being_destroyed = 1; - nsgtk_window_close(g); -} - -/** - * Update the back and forward button sensitivity. - */ -static void nsgtk_window_update_back_forward(struct gtk_scaffolding *g) -{ - int width, height; - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - - g->buttons[BACK_BUTTON]->sensitivity = - history_back_available(bw->history); - g->buttons[FORWARD_BUTTON]->sensitivity = history_forward_available( - bw->history); - - nsgtk_scaffolding_set_sensitivity(g); - - /* update the url bar, particularly necessary when tabbing */ - if (bw->current_content != NULL && - content_get_url(bw->current_content) != NULL) - browser_window_refresh_url_bar(bw, - content_get_url(bw->current_content), - bw->frag_id); - - /* update the local history window, as well as queuing a redraw - * for it. - */ - history_size(bw->history, &width, &height); - gtk_widget_set_size_request(GTK_WIDGET(g->history_window->drawing_area), - width, height); - gtk_widget_queue_draw(GTK_WIDGET(g->history_window->drawing_area)); -} - -/** - * Make the throbber run. - */ -static void nsgtk_throb(void *p) -{ - struct gtk_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]); - - schedule(10, nsgtk_throb, p); -} - -static guint nsgtk_scaffolding_update_edit_actions_sensitivity( - struct gtk_scaffolding *g) -{ - GtkWidget *widget = gtk_window_get_focus(g->window); - gboolean has_selection; - - if (GTK_IS_EDITABLE(widget)) { - 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; - } else { - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - has_selection = bw->sel->defined; - - g->buttons[COPY_BUTTON]->sensitivity = has_selection; - g->buttons[CUT_BUTTON]->sensitivity = (has_selection && - bw->caret_callback != 0); - g->buttons[PASTE_BUTTON]->sensitivity = - (bw->paste_callback != 0); - } - - nsgtk_scaffolding_set_sensitivity(g); - return ((g->buttons[COPY_BUTTON]->sensitivity) | - (g->buttons[CUT_BUTTON]->sensitivity) | - (g->buttons[PASTE_BUTTON]->sensitivity)); -} - -static void nsgtk_scaffolding_enable_link_operations_sensitivity( - struct gtk_scaffolding *g) -{ - - gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->savelink_menuitem), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->opentab_menuitem), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->openwin_menuitem), TRUE); - - popup_menu_show(g->menu_popup, false, true, false, false, false); - -} - -static void nsgtk_scaffolding_enable_edit_actions_sensitivity( - struct gtk_scaffolding *g) -{ - - g->buttons[PASTE_BUTTON]->sensitivity = true; - g->buttons[COPY_BUTTON]->sensitivity = true; - g->buttons[CUT_BUTTON]->sensitivity = true; - nsgtk_scaffolding_set_sensitivity(g); - - popup_menu_show(g->menu_popup, false, false, false, true, false); -} - -/* signal handling functions for the toolbar, URL bar, and menu bar */ -static gboolean nsgtk_window_edit_menu_clicked(GtkWidget *widget, - struct gtk_scaffolding *g) -{ - nsgtk_scaffolding_update_edit_actions_sensitivity(g); - - return TRUE; -} - -static gboolean nsgtk_window_edit_menu_hidden(GtkWidget *widget, - struct gtk_scaffolding *g) -{ - nsgtk_scaffolding_enable_edit_actions_sensitivity(g); - - return TRUE; -} - -static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget, - struct gtk_scaffolding *g) -{ - nsgtk_scaffolding_enable_link_operations_sensitivity(g); - nsgtk_scaffolding_enable_edit_actions_sensitivity(g); - return TRUE; -} - -gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data) -{ - struct gtk_scaffolding *g = data; - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - char *url; - if (search_is_url(gtk_entry_get_text(GTK_ENTRY(g->url_bar))) - == false) - url = search_web_from_term(gtk_entry_get_text(GTK_ENTRY( - g->url_bar))); - else - url = strdup(gtk_entry_get_text(GTK_ENTRY(g->url_bar))); - browser_window_go(bw, url, 0, true); - if (url != NULL) - free(url); - return TRUE; -} - - -gboolean nsgtk_window_url_changed(GtkWidget *widget, GdkEventKey *event, - gpointer data) -{ - const char *prefix; - - prefix = gtk_entry_get_text(GTK_ENTRY(widget)); - nsgtk_completion_update(prefix); - - return TRUE; -} - -/** - * Event handler for popup menu on toolbar. - */ -static gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, - gint x, gint y, gint button, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - - /* set visibility for right-click popup menu */ - popup_menu_hide(g->menu_popup, true, true, false, true, false); - popup_menu_show(g->menu_popup, false, false, false, false, true); - - gtk_menu_popup(g->menu_popup->popup_menu, NULL, NULL, NULL, NULL, 0, - gtk_get_current_event_time()); - - return TRUE; -} - -/** - * Update the menus when the number of tabs changes. - */ -static void nsgtk_window_tabs_num_changed(GtkNotebook *notebook, - GtkWidget *page, guint page_num, struct gtk_scaffolding *g) -{ - 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; - nsgtk_scaffolding_set_sensitivity(g); -} - -/** - * Handle opening a file path. - */ -static void nsgtk_openfile_open(const char *filename) -{ - struct browser_window *bw = gui_window_get_browser_window( - current_model->top_level); - char url[strlen(filename) + FILE_SCHEME_PREFIX_LEN + 1]; - - sprintf(url, FILE_SCHEME_PREFIX"%s", filename); - - browser_window_go(bw, url, 0, true); - -} - -/* signal handlers for menu entries */ - -MULTIHANDLER(newwindow) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - const char *url = gtk_entry_get_text(GTK_ENTRY(g->url_bar)); - - browser_window_create(url, bw, NULL, false, false); - - return TRUE; -} - -MULTIHANDLER(newtab) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - - if (option_new_blank) { - browser_window_create(NULL, bw, NULL, false, true); - GtkWidget *window = gtk_notebook_get_nth_page(g->notebook, -1); - gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &((GdkColor) - {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF})); - } else { - const char *url = option_homepage_url; - - if ((url != NULL) && (url[0] == '\0')) - url = NULL; - - if (url == NULL) - url = NETSURF_HOMEPAGE; - - browser_window_create(url, bw, NULL, false, true); - } - - return TRUE; -} - -MULTIHANDLER(openfile) -{ - current_model = g; - GtkWidget *dlgOpen = gtk_file_chooser_dialog_new("Open File", - current_model->window, GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, -6, GTK_STOCK_OPEN, -5, NULL); - - gint response = gtk_dialog_run(GTK_DIALOG(dlgOpen)); - if (response == GTK_RESPONSE_OK) { - gchar *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; -} - -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 (gui_window_get_browser_window(g->top_level)->current_content - == NULL) - return FALSE; - - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkcompleteSave"), g->window, - GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - DIR *d; - char *path; - url_func_result 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 = url_nice(content_get_url(gui_window_get_browser_window( - g->top_level)->current_content), &path, false); - if (res != URL_FUNC_OK) { - path = strdup(messages_get("SaveText")); - if (path == NULL) { - warn_user("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) { - LOG(("Unable to open directory %s for complete save: %s", path, - strerror(errno))); - if (errno == ENOTDIR) - warn_user("NoDirError", path); - else - warn_user("gtkFileError", path); - gtk_widget_destroy(fc); - g_free(path); - return TRUE; - } - closedir(d); - save_complete_init(); - save_complete(gui_window_get_browser_window( - g->top_level)->current_content, path); - g_free(path); - - gtk_widget_destroy(fc); - - return TRUE; -} - - -MULTIHANDLER(pdf) -{ -#ifdef WITH_PDF_EXPORT - - GtkWidget *save_dialog; - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - struct print_settings *settings; - char filename[PATH_MAX]; - char dirname[PATH_MAX]; - char *url_name; - url_func_result res; - - LOG(("Print preview (generating PDF) started.")); - - res = url_nice(content_get_url(bw->current_content), &url_name, true); - if (res != URL_FUNC_OK) { - warn_user(messages_get(res == URL_FUNC_NOMEM ? "NoMemory" - : "URIError"), 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 synchronized 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, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_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) { - warn_user(messages_get("NoMemory"), 0); - gtk_widget_destroy(save_dialog); - return TRUE; - } - - /* This will clean up the print_settings object for us */ - print_basic_run(bw->current_content, &pdf_printer, settings); - } - - gtk_widget_destroy(save_dialog); - -#endif /* WITH_PDF_EXPORT */ - - return TRUE; -} - -MULTIHANDLER(plaintext) -{ - if (gui_window_get_browser_window(g->top_level)->current_content - == NULL) - return FALSE; - - GtkWidget *fc = gtk_file_chooser_dialog_new( - messages_get("gtkplainSave"), g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - char *filename; - url_func_result res; - - res = url_nice(content_get_url(gui_window_get_browser_window( - g->top_level)->current_content), &filename, false); - if (res != URL_FUNC_OK) { - filename = strdup(messages_get("SaveText")); - if (filename == NULL) { - warn_user("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); - - 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(gui_window_get_browser_window( - g->top_level)->current_content, 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 = gui_window_get_browser_window(g->top_level); - - GtkPrintOperation *print_op; - GtkPageSetup *page_setup; - GtkPrintSettings *gtk_print_settings; - GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR; - struct print_settings *settings; - - print_op = gtk_print_operation_new(); - if (print_op == NULL) { - warn_user(messages_get("NoMemory"), 0); - return TRUE; - } - - /* use previously saved settings if any */ - gtk_print_settings = gtk_print_settings_new_from_file( - print_options_file_location, NULL); - if (gtk_print_settings != NULL) { - gtk_print_operation_set_print_settings(print_op, - gtk_print_settings); - - /* We're not interested in the settings any more */ - g_object_unref(gtk_print_settings); - } - - content_to_print = bw->current_content; - - page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL); - if (page_setup == NULL) { - warn_user(messages_get("NoMemory"), 0); - g_object_unref(print_op); - return TRUE; - } - gtk_print_operation_set_default_page_setup(print_op, page_setup); - - settings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont); - - g_signal_connect(print_op, "begin_print", - G_CALLBACK(gtk_print_signal_begin_print), settings); - 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), settings); - if (content_get_type(bw->current_content) != 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 (res == GTK_PRINT_OPERATION_RESULT_APPLY) { - /* Don't ref the settings, as we don't want to own them */ - gtk_print_settings = gtk_print_operation_get_print_settings( - print_op); - - gtk_print_settings_to_file(gtk_print_settings, - print_options_file_location, NULL); - } - - /* 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) -{ - /* close all tabs first */ - gint numbertabs = gtk_notebook_get_n_pages(g->notebook); - while (numbertabs-- > 1) { - nsgtk_tab_close_current(g->notebook); - } - nsgtk_window_close(g); - gtk_widget_destroy(GTK_WIDGET(g->window)); - return TRUE; -} - -MULTIHANDLER(quit) -{ - if (nsgtk_check_for_downloads(g->window) == false) - netsurf_quit = true; - return TRUE; -} - -MENUHANDLER(savelink) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; - struct gui_window *gui = g->top_level; - struct browser_window *bw = gui_window_get_browser_window(gui); - - if (!current_menu_link_box) - return FALSE; - - browser_window_download(bw, current_menu_link_box->href, - content_get_url(bw->current_content)); - - return TRUE; -} - -/** - * Handler for opening new window from a link. attached to the popup menu. - */ -MENUHANDLER(link_openwin) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; - struct gui_window *gui = g->top_level; - struct browser_window *bw = gui_window_get_browser_window(gui); - - if (current_menu_link_box == NULL) - return FALSE; - - browser_window_create(current_menu_link_box->href, bw, NULL, true, false); - - return TRUE; -} - -/** - * Handler for opening new tab from a link. attached to the popup menu. - */ -MENUHANDLER(link_opentab) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; - struct gui_window *gui = g->top_level; - struct browser_window *bw = gui_window_get_browser_window(gui); - - temp_open_background = 1; - - if (current_menu_link_box == NULL) - return FALSE; - - browser_window_create(current_menu_link_box->href, bw, NULL, true, - true); - temp_open_background = -1; - - return TRUE; -} - - -MULTIHANDLER(cut) -{ - struct browser_window *bw = gui_window_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, KEY_CUT_SELECTION); - - return TRUE; -} - -MULTIHANDLER(copy) -{ - struct browser_window *bw = gui_window_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 - gui_copy_to_clipboard(bw->sel); - - return TRUE; -} - -MULTIHANDLER(paste) -{ - struct gui_window *gui = 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 - gui_paste_from_clipboard(gui, 0, 0); - - return TRUE; -} - -MULTIHANDLER(delete) -{ - return TRUE; -} - -MENUHANDLER(customize) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - nsgtk_toolbar_customization_init(g); - return TRUE; -} - -MULTIHANDLER(selectall) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - - if (nsgtk_widget_has_focus(GTK_WIDGET(g->url_bar))) { - LOG(("Selecting all URL bar text")); - gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1); - } else { - LOG(("Selecting all document text")); - selection_select_all(bw->sel); - } - - return TRUE; -} - -MULTIHANDLER(find) -{ - nsgtk_scaffolding_toggle_search_bar_visibility(g); - return TRUE; -} - -MULTIHANDLER(preferences) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - if (g->preferences_dialog == NULL) - g->preferences_dialog = nsgtk_options_init(bw, g->window); - else - gtk_widget_show(GTK_WIDGET(g->preferences_dialog)); - - return TRUE; -} - -MULTIHANDLER(zoomplus) -{ - struct browser_window *bw = gui_window_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 = gui_window_get_browser_window(g->top_level); - - browser_window_set_scale(bw, 1.0, true); - - return TRUE; -} - -MULTIHANDLER(zoomminus) -{ - struct browser_window *bw = gui_window_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(fullscreen) -{ - if (g->fullscreen) { - gtk_window_unfullscreen(g->window); - } else { - gtk_window_fullscreen(g->window); - } - - g->fullscreen = !g->fullscreen; - - return TRUE; -} - -MULTIHANDLER(viewsource) -{ - nsgtk_source_dialog_init(g->window, - gui_window_get_browser_window(g->top_level)); - return TRUE; -} - -MENUHANDLER(menubar) -{ - GtkWidget *w; - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - - /* if the menubar is not being shown the popup menu shows the - * menubar entries instead. - */ - 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, true); - popup_menu_hide(g->menu_popup, true, false, 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, true); - - } - return TRUE; -} - -MENUHANDLER(toolbar) -{ - GtkWidget *w; - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - - 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)); - } 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) -{ - if (GTK_IS_PANED(g->status_pane)) - option_toolbar_status_width = - gtk_paned_get_position(g->status_pane); - gtk_window_get_position(g->window, &option_window_x, - &option_window_y); - gtk_window_get_size(g->window, &option_window_width, - &option_window_height); - - - options_write(options_file_location); - - return TRUE; -} - -MULTIHANDLER(toggledebugging) -{ - html_redraw_debug = !html_redraw_debug; - nsgtk_reflow_all_windows(); - return TRUE; -} - -MULTIHANDLER(saveboxtree) -{ - GtkWidget *save_dialog; - - save_dialog = gtk_file_chooser_dialog_new("Save File", g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - getenv("HOME") ? getenv("HOME") : "/"); - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - "boxtree.txt"); - - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - FILE *fh; - - LOG(("Saving box tree dump to %s...\n", filename)); - - fh = fopen((const char *) filename, "w"); - if (fh == NULL) { - warn_user("Error saving box tree dump.", - "Unable to open file for writing."); - } else { - struct browser_window *bw; - bw = gui_window_get_browser_window(g->top_level); - - if (bw->current_content && - content_get_type(bw->current_content) == - CONTENT_HTML) { - box_dump(fh, - html_get_box_tree(bw->current_content), - 0); - } - - fclose(fh); - } - - g_free(filename); - } - - gtk_widget_destroy(save_dialog); - - return TRUE; -} - -MULTIHANDLER(savedomtree) -{ - GtkWidget *save_dialog; - - save_dialog = gtk_file_chooser_dialog_new("Save File", g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - getenv("HOME") ? getenv("HOME") : "/"); - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - "domtree.txt"); - - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - FILE *fh; - LOG(("Saving dom tree to %s...\n", filename)); - - fh = fopen((const char *) filename, "w"); - if (fh == NULL) { - warn_user("Error saving box tree dump.", - "Unable to open file for writing."); - } else { - struct browser_window *bw; - bw = gui_window_get_browser_window(g->top_level); - - if (bw->current_content && - content_get_type(bw->current_content) == - CONTENT_HTML) { - xmlDebugDumpDocument(fh, - html_get_document(bw->current_content)); - } - - fclose(fh); - } - - g_free(filename); - } - - gtk_widget_destroy(save_dialog); - - return TRUE; -} - - -MULTIHANDLER(stop) -{ - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - - browser_window_stop(bw); - - return TRUE; -} - -MULTIHANDLER(reload) -{ - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - if (bw == NULL) - return TRUE; - - /* clear potential search effects */ - if (bw->search_context != NULL) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, bw); - - browser_window_reload(bw, true); - - return TRUE; -} - -MULTIHANDLER(back) -{ - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - - if ((bw == NULL) || (!history_back_available(bw->history))) - return TRUE; - - /* clear potential search effects */ - if (bw->search_context != NULL) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, bw); - - history_back(bw, bw->history); - nsgtk_window_update_back_forward(g); - - return TRUE; -} - -MULTIHANDLER(forward) -{ - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - - if ((bw == NULL) || (!history_forward_available(bw->history))) - return TRUE; - - /* clear potential search effects */ - if (bw->search_context != NULL) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, bw); - - history_forward(bw, bw->history); - nsgtk_window_update_back_forward(g); - - return TRUE; -} - -MULTIHANDLER(home) -{ - static const char *addr = NETSURF_HOMEPAGE; - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - - if (option_homepage_url != NULL && option_homepage_url[0] != '\0') - addr = option_homepage_url; - - browser_window_go(bw, addr, 0, true); - - return TRUE; -} - -MULTIHANDLER(localhistory) -{ - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - - int x,y, width, height, mainwidth, mainheight, margin = 20; - /* if entries of the same url but different frag_ids have been added - * the history needs redrawing (what throbber code normally does) - */ - history_size(bw->history, &width, &height); - nsgtk_window_update_back_forward(g); - gtk_window_get_position(g->window, &x, &y); - gtk_window_get_size(g->window, &mainwidth, &mainheight); - width = (width + g->historybase + margin > mainwidth) ? - mainwidth - g->historybase : width + margin; - height = (height + g->toolbarbase + margin > mainheight) ? - mainheight - g->toolbarbase : height + margin; - gtk_window_set_default_size(g->history_window->window, width, height); - gtk_widget_set_size_request(GTK_WIDGET(g->history_window->window), - -1, -1); - gtk_window_resize(g->history_window->window, width, height); - gtk_window_set_transient_for(g->history_window->window, g->window); - gtk_window_set_opacity(g->history_window->window, 0.9); - gtk_widget_show(GTK_WIDGET(g->history_window->window)); - gtk_window_move(g->history_window->window, x + g->historybase, y + - g->toolbarbase); - gdk_window_raise(GTK_WIDGET(g->history_window->window)->window); - - return TRUE; -} - -MULTIHANDLER(globalhistory) -{ - gtk_widget_show(GTK_WIDGET(wndHistory)); - gdk_window_raise(GTK_WIDGET(wndHistory)->window); - - return TRUE; -} - -MULTIHANDLER(addbookmarks) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - - if (bw == NULL || bw->current_content == NULL || - content_get_url(bw->current_content) == NULL) - return TRUE; - hotlist_add_page(content_get_url(bw->current_content)); - return TRUE; -} - -MULTIHANDLER(showbookmarks) -{ - gtk_widget_show(GTK_WIDGET(wndHotlist)); - gdk_window_raise(GTK_WIDGET(wndHotlist)->window); - gtk_window_set_focus(wndHotlist, NULL); - - return TRUE; -} - -MULTIHANDLER(showcookies) -{ - gtk_widget_show(GTK_WIDGET(wndCookies)); - gdk_window_raise(GTK_WIDGET(wndCookies)->window); - - return TRUE; -} - -MULTIHANDLER(openlocation) -{ - gtk_widget_grab_focus(GTK_WIDGET(g->url_bar)); - return TRUE; -} - -MULTIHANDLER(nexttab) -{ - gtk_notebook_next_page(g->notebook); - - return TRUE; -} - -MULTIHANDLER(prevtab) -{ - gtk_notebook_prev_page(g->notebook); - - return TRUE; -} - -MULTIHANDLER(closetab) -{ - nsgtk_tab_close_current(g->notebook); - - return TRUE; -} - -MULTIHANDLER(contents) -{ - return TRUE; -} - -MULTIHANDLER(guide) -{ - return TRUE; -} - -MULTIHANDLER(info) -{ - return TRUE; -} - -MULTIHANDLER(about) -{ - nsgtk_about_dialog_init(g->window, - gui_window_get_browser_window(g->top_level), - netsurf_version); - return TRUE; -} - -BUTTONHANDLER(history) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - return nsgtk_on_localhistory_activate(g); -} - -#undef MULTIHANDLER -#undef CHECKHANDLER -#undef BUTTONHANDLER - - -/* signal handler functions for the local history window */ -static gboolean nsgtk_history_expose_event(GtkWidget *widget, - GdkEventExpose *event, gpointer g) -{ - struct gtk_history_window *hw = (struct gtk_history_window *)g; - struct browser_window *bw = - gui_window_get_browser_window(hw->g->top_level); - - current_widget = widget; - current_drawable = widget->window; - current_gc = gdk_gc_new(current_drawable); -#ifdef CAIRO_VERSION - current_cr = gdk_cairo_create(current_drawable); -#endif - plot = nsgtk_plotters; - nsgtk_plot_set_scale(1.0); - - plot.clip(event->area.x, - event->area.y, - event->area.x + event->area.width, - event->area.y + event->area.height); - - history_redraw(bw->history); - - current_widget = NULL; - g_object_unref(current_gc); -#ifdef CAIRO_VERSION - cairo_destroy(current_cr); -#endif - return FALSE; -} - - -static gboolean nsgtk_history_button_press_event(GtkWidget *widget, - GdkEventButton *event, gpointer g) -{ - struct gtk_history_window *hw = (struct gtk_history_window *)g; - struct browser_window *bw = - gui_window_get_browser_window(hw->g->top_level); - - LOG(("X=%g, Y=%g", event->x, event->y)); - - history_click(bw, bw->history, - event->x, event->y, false); - - return TRUE; -} - - - -static void nsgtk_attach_menu_handlers(struct gtk_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), g);\ - g_signal_connect(g->menu_popup->view_submenu->toolbars_submenu->q##_menuitem, "toggled", G_CALLBACK(nsgtk_on_##q##_activate), g) - CONNECT_CHECK(menubar); - CONNECT_CHECK(toolbar); -#undef CONNECT_CHECK - -} - -/** - * Create and connect handlers to popup menu. - * - * \param g scaffoliding to attach popup menu to. - * \return true on success or false on error. - */ -static bool nsgtk_new_scaffolding_popup(struct gtk_scaffolding *g) -{ - struct nsgtk_popup_submenu *nmenu; - - nmenu = nsgtk_menu_popup_create(g->window); - - if (nmenu == NULL) - return false; - - SIG_CONNECT(nmenu->popup_menu, "hide", - nsgtk_window_popup_menu_hidden, g); - - SIG_CONNECT(nmenu->savelink_menuitem, "activate", - nsgtk_on_savelink_activate, g); - - SIG_CONNECT(nmenu->opentab_menuitem, "activate", - nsgtk_on_link_opentab_activate, g); - - SIG_CONNECT(nmenu->openwin_menuitem, "activate", - nsgtk_on_link_openwin_activate, g); - - SIG_CONNECT(nmenu->cut_menuitem, "activate", - nsgtk_on_cut_activate, g); - - SIG_CONNECT(nmenu->copy_menuitem, "activate", - nsgtk_on_copy_activate, g); - - SIG_CONNECT(nmenu->paste_menuitem, "activate", - nsgtk_on_paste_activate, g); - - SIG_CONNECT(nmenu->customize_menuitem, "activate", - nsgtk_on_customize_activate, g); - - - /* set initial popup menu visibility */ - popup_menu_hide(nmenu, true, false, false, false, true); - - g->menu_popup = nmenu; - - return true; -} - -nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) -{ - struct gtk_scaffolding *g = malloc(sizeof(*g)); - char *searchname; - int i; - - if (g == NULL) { - warn_user("NoMemory", 0); - return NULL; - } - - LOG(("Constructing a scaffold of %p for gui_window %p", g, toplevel)); - - g->top_level = toplevel; - - open_windows++; - - /* load the window template from the glade xml file, and extract - * widget references from it for later use. - */ - g->xml = glade_xml_new(glade_netsurf_file_location, - "wndBrowser", NULL); - glade_xml_signal_autoconnect(g->xml); - g->window = GTK_WINDOW(GET_WIDGET("wndBrowser")); - g->notebook = GTK_NOTEBOOK(GET_WIDGET("notebook")); - g->tool_bar = GTK_TOOLBAR(GET_WIDGET("toolbar")); - - g->search = malloc(sizeof(struct gtk_search)); - if (g->search == NULL) { - warn_user("NoMemory", 0); - free(g); - return NULL; - } - - g->search->bar = GTK_TOOLBAR(GET_WIDGET("searchbar")); - g->search->entry = GTK_ENTRY(GET_WIDGET("searchEntry")); - - g->search->buttons[0] = GTK_TOOL_BUTTON(GET_WIDGET("searchBackButton")); - g->search->buttons[1] = GTK_TOOL_BUTTON(GET_WIDGET( - "searchForwardButton")); - g->search->buttons[2] = GTK_TOOL_BUTTON(GET_WIDGET( - "closeSearchButton")); - g->search->checkAll = GTK_CHECK_BUTTON(GET_WIDGET("checkAllSearch")); - g->search->caseSens = GTK_CHECK_BUTTON(GET_WIDGET("caseSensButton")); - - - - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - g->buttons[i] = malloc(sizeof(struct nsgtk_button_connect)); - if (g->buttons[i] == NULL) { - warn_user("NoMemory", 0); - return NULL; - } - g->buttons[i]->button = NULL; - g->buttons[i]->location = -1; - g->buttons[i]->sensitivity = true; - g->buttons[i]->main = NULL; - g->buttons[i]->rclick = NULL; - g->buttons[i]->popup = NULL; - g->buttons[i]->mhandler = NULL; - g->buttons[i]->bhandler = NULL; - g->buttons[i]->dataplus = NULL; - g->buttons[i]->dataminus = NULL; - } - /* here custom toolbutton adding code */ - g->offset = 0; - g->toolbarmem = 0; - g->toolbarbase = 0; - g->historybase = 0; - nsgtk_toolbar_customization_load(g); - nsgtk_toolbar_set_physical(g); - - g->menu_bar = nsgtk_menu_bar_create(GTK_MENU_SHELL(glade_xml_get_widget(g->xml, "menubar")), g->window); - - - g->preferences_dialog = NULL; - - /* 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 (option_window_width > 0) { - gtk_window_move(g->window, option_window_x, option_window_y); - gtk_window_resize(g->window, option_window_width, - option_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(g->window, 1000, 700); - } - - /* Default toolbar button type uses system defaults */ - if (option_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: - option_button_type = (tooliconsize == - GTK_ICON_SIZE_SMALL_TOOLBAR) ? - 1 : 2; - break; - case GTK_TOOLBAR_TEXT: - option_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 */ - option_button_type = 2; - break; - } - } - - switch (option_button_type) { - /* case 0 is 'unset' [from fresh install / clearing options] - * see above */ - - case 1: /* Small 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_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); - 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); - break; - case 4: /* Text icons only */ - gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), - GTK_TOOLBAR_TEXT); - default: - break; - } - - gtk_toolbar_set_show_arrow(g->tool_bar, TRUE); - gtk_widget_show_all(GTK_WIDGET(g->tool_bar)); - nsgtk_tab_init(GTK_WIDGET(g->notebook)); - - gtk_widget_set_size_request(GTK_WIDGET( - g->buttons[HISTORY_BUTTON]->button), 20, -1); - - /* create the local history window to be associated with this browser */ - g->history_window = malloc(sizeof(struct gtk_history_window)); - g->history_window->g = g; - g->history_window->window = - GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); - gtk_window_set_transient_for(g->history_window->window, g->window); - gtk_window_set_title(g->history_window->window, "NetSurf History"); - gtk_window_set_type_hint(g->history_window->window, - GDK_WINDOW_TYPE_HINT_UTILITY); - g->history_window->scrolled = - GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(0, 0)); - gtk_container_add(GTK_CONTAINER(g->history_window->window), - GTK_WIDGET(g->history_window->scrolled)); - - gtk_widget_show(GTK_WIDGET(g->history_window->scrolled)); - g->history_window->drawing_area = - GTK_DRAWING_AREA(gtk_drawing_area_new()); - - gtk_widget_set_events(GTK_WIDGET(g->history_window->drawing_area), - GDK_EXPOSURE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_BUTTON_PRESS_MASK); - gtk_widget_modify_bg(GTK_WIDGET(g->history_window->drawing_area), - GTK_STATE_NORMAL, - &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); - gtk_scrolled_window_add_with_viewport(g->history_window->scrolled, - GTK_WIDGET(g->history_window->drawing_area)); - gtk_widget_show(GTK_WIDGET(g->history_window->drawing_area)); - - - /* set up URL bar completion */ - g->url_bar_completion = gtk_entry_completion_new(); - gtk_entry_completion_set_match_func(g->url_bar_completion, - nsgtk_completion_match, NULL, NULL); - gtk_entry_completion_set_model(g->url_bar_completion, - GTK_TREE_MODEL(nsgtk_completion_list)); - gtk_entry_completion_set_text_column(g->url_bar_completion, 0); - gtk_entry_completion_set_minimum_key_length(g->url_bar_completion, 1); - gtk_entry_completion_set_popup_completion(g->url_bar_completion, TRUE); - g_object_set(G_OBJECT(g->url_bar_completion), - "popup-set-width", TRUE, - "popup-single-match", TRUE, - NULL); - - /* set up the throbber. */ - g->throb_frame = 0; - - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - /* connect history window signals to their handlers */ - CONNECT(g->history_window->drawing_area, "expose_event", - nsgtk_history_expose_event, g->history_window); - /*CONNECT(g->history_window->drawing_area, "motion_notify_event", - nsgtk_history_motion_notify_event, g->history_window);*/ - CONNECT(g->history_window->drawing_area, "button_press_event", - nsgtk_history_button_press_event, g->history_window); - CONNECT(g->history_window->window, "delete_event", - gtk_widget_hide_on_delete, NULL); - - g_signal_connect_after(g->notebook, "page-added", - G_CALLBACK(nsgtk_window_tabs_num_changed), g); - g_signal_connect_after(g->notebook, "page-removed", - G_CALLBACK(nsgtk_window_tabs_num_changed), g); - - /* connect signals to handlers. */ - CONNECT(g->window, "delete-event", nsgtk_window_delete_event, g); - - /* toolbar URL bar menu bar search bar signal handlers */ - CONNECT(g->menu_bar->edit_submenu->edit, "show", nsgtk_window_edit_menu_clicked, g); - CONNECT(g->menu_bar->edit_submenu->edit, "hide", nsgtk_window_edit_menu_hidden, g); - CONNECT(g->search->buttons[1], "clicked", - nsgtk_search_forward_button_clicked, g); - CONNECT(g->search->buttons[0], "clicked", - nsgtk_search_back_button_clicked, g); - CONNECT(g->search->entry, "changed", nsgtk_search_entry_changed, g); - CONNECT(g->search->entry, "activate", nsgtk_search_entry_activate, g); - CONNECT(g->search->entry, "key-press-event", nsgtk_search_entry_key, g); - CONNECT(g->search->buttons[2], "clicked", - nsgtk_search_close_button_clicked, g); - CONNECT(g->search->caseSens, "toggled", nsgtk_search_entry_changed, - g); - - - CONNECT(g->tool_bar, "popup-context-menu", - nsgtk_window_tool_bar_clicked, g); - - /* create popup menu */ - nsgtk_new_scaffolding_popup(g); - - /* set up the menu signal handlers */ - nsgtk_scaffolding_toolbar_init(g); - nsgtk_toolbar_connect_all(g); - nsgtk_attach_menu_handlers(g); - - /* prepare to set the web search ico */ - - /* init web search prefs from file */ - search_web_provider_details(option_search_provider); - - /* potentially retrieve ico */ - if (search_web_ico() == NULL) - search_web_retrieve_ico(false); - - /* set entry */ - searchname = search_web_provider_name(); - if (searchname != NULL) { - char searchcontent[strlen(searchname) + SLEN("Search ") + 1]; - sprintf(searchcontent, "Search %s", searchname); - nsgtk_scaffolding_set_websearch(g, searchcontent); - free(searchname); - } - - nsgtk_scaffolding_initial_sensitivity(g); - - g->being_destroyed = 0; - - g->fullscreen = false; - - - /* attach to the list */ - if (scaf_list) - scaf_list->prev = g; - g->next = scaf_list; - g->prev = NULL; - scaf_list = g; - - /* call functions that need access from the list */ - nsgtk_theme_init(); - nsgtk_theme_implement(g); - - /* set web search ico */ - if (search_web_ico() != NULL) - gui_window_set_search_ico(search_web_ico()); - - /* finally, show the window. */ - gtk_widget_show(GTK_WIDGET(g->window)); - - LOG(("creation complete")); - - return g; -} - -void gui_window_set_title(struct gui_window *_g, const char *title) -{ - static char suffix[] = " - NetSurf"; - char nt[strlen(title) + strlen(suffix) + 1]; - struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); - - nsgtk_tab_set_title(_g, title); - - if (g->top_level == _g) { - if (title == NULL || title[0] == '\0') - { - gtk_window_set_title(g->window, "NetSurf"); - - } - else - { - strcpy(nt, title); - strcat(nt, suffix); - gtk_window_set_title(g->window, nt); - } - } -} - -void gui_window_set_url(struct gui_window *_g, const char *url) -{ - struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); - if (g->top_level != _g) return; - gtk_entry_set_text(GTK_ENTRY(g->url_bar), url); - gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1); -} - -void gui_window_start_throbber(struct gui_window* _g) -{ - struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); - g->buttons[STOP_BUTTON]->sensitivity = true; - g->buttons[RELOAD_BUTTON]->sensitivity = false; - nsgtk_scaffolding_set_sensitivity(g); - - nsgtk_window_update_back_forward(g); - - schedule(10, nsgtk_throb, g); -} - -void gui_window_stop_throbber(struct gui_window* _g) -{ - struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); - if (g == NULL) - return; - nsgtk_window_update_back_forward(g); - schedule_remove(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 gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon) -{ - struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); - struct bitmap *icon_bitmap; - GtkImage *iconImage = NULL; - - if (g->top_level != _g) - return; - -#ifdef WITH_BMP - if (icon != NULL && content_get_type(icon) == CONTENT_ICO) - nsico_set_bitmap_from_size(icon, 16, 16); -#endif - - icon_bitmap = (icon != NULL) ? content_get_bitmap(icon) : NULL; - - if (icon_bitmap != NULL) { - GdkPixbuf *pb = gtk_bitmap_get_primary(icon_bitmap); - if (pb != NULL && gdk_pixbuf_get_width(pb) > 0 && - gdk_pixbuf_get_height(pb) > 0) { - pb = gdk_pixbuf_scale_simple(pb, 16, 16, GDK_INTERP_HYPER); - iconImage = GTK_IMAGE(gtk_image_new_from_pixbuf(pb)); - } - } - if (iconImage == NULL) { - /** \todo Does pb need cleaning up? */ - char imagepath[strlen(res_dir_location) + - SLEN("favicon.png") + 1]; - sprintf(imagepath, "%sfavicon.png", res_dir_location); - iconImage = GTK_IMAGE(gtk_image_new_from_file(imagepath)); - } - - if (iconImage == NULL) - return; - - if (g->icoFav != NULL) - g_object_unref(g->icoFav); - g->icoFav = iconImage; - - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar), - SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(g->icoFav)); - gtk_widget_show_all(GTK_WIDGET(g->buttons[URL_BAR_ITEM]->button)); -} - -void gui_window_set_search_ico(hlcache_handle *ico) -{ - GdkPixbuf *pbico; - GtkImage *searchico; - struct bitmap *ico_bitmap; - nsgtk_scaffolding *current; - - if (ico == NULL && (ico = search_web_ico()) == NULL) - return; - -#ifdef WITH_BMP - if (content_get_type(ico) == CONTENT_ICO) - nsico_set_bitmap_from_size(ico, 20, 20); -#endif - - ico_bitmap = content_get_bitmap(ico); - if (ico_bitmap == NULL) - return; - - pbico = gtk_bitmap_get_primary(ico_bitmap); - if (pbico != NULL && gdk_pixbuf_get_width(pbico) > 0 && - gdk_pixbuf_get_height(pbico) > 0) { - pbico = gdk_pixbuf_scale_simple(pbico, 20, 20, - GDK_INTERP_HYPER); - searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico)); - } else { - /** \todo Does pbico need cleaning up? */ - return; - } - - /* add ico to each window's toolbar */ - for (current = scaf_list; current != NULL; current = current->next) { - if (searchico != NULL) { - /** \todo Are we leaking webSearchIco here? */ - current->webSearchIco = searchico; - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY( - current->webSearchEntry), - SEXY_ICON_ENTRY_PRIMARY, - current->webSearchIco); - } - if (pbico != NULL) - searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico)); - else - searchico = NULL; - } -} - -bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g) -{ - /* We are considered "busy" if the stop button is sensitive */ - return g->buttons[STOP_BUTTON]->sensitivity; -} - -GtkWindow* nsgtk_scaffolding_window(nsgtk_scaffolding *g) -{ - return g->window; -} - -GtkNotebook* nsgtk_scaffolding_notebook(nsgtk_scaffolding *g) -{ - return g->notebook; -} - -GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g) -{ - return g->url_bar; -} - -GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g) -{ - return g->webSearchEntry; -} - - -GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g) -{ - return g->tool_bar; -} - -struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g, - int i) -{ - return g->buttons[i]; -} - -struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g) -{ - return g->search; -} - -GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g) -{ - return g->menu_bar->bar_menu; -} - -struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding - *g) -{ - return g->history_window; -} - -nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g) -{ - return g->next; -} - -void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g) -{ - g->offset = 0; -} - -void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g) -{ - g->url_bar = GTK_WIDGET(gtk_bin_get_child(GTK_BIN( - nsgtk_scaffolding_button(g, URL_BAR_ITEM)->button))); - g->icoFav = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY(g->url_bar), - SEXY_ICON_ENTRY_PRIMARY); - - gtk_entry_set_completion(GTK_ENTRY(g->url_bar), - g->url_bar_completion); -} -void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g) -{ - g->throbber = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(gtk_bin_get_child( - GTK_BIN(g->buttons[THROBBER_ITEM]->button))))); -} - -void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g) -{ - g->webSearchEntry = gtk_bin_get_child(GTK_BIN( - g->buttons[WEBSEARCH_ITEM]->button)); - g->webSearchIco = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY( - g->webSearchEntry), SEXY_ICON_ENTRY_PRIMARY); -} - -void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char *content) -{ - /* this code appears technically correct, though currently has no - * effect at all - tinkering encouraged */ - 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("", content, - "", 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); -} - -void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g) -{ - gboolean vis; - struct browser_window *bw = - gui_window_get_browser_window(g->top_level); - g_object_get(G_OBJECT(g->search->bar), "visible", &vis, NULL); - if (vis) { - if ((bw != NULL) && (bw->search_context != NULL)) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, 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)); - } -} - - -struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g) -{ - return g->top_level; -} - -void nsgtk_scaffolding_set_top_level (struct gui_window *gw) -{ - nsgtk_get_scaffold(gw)->top_level = gw; - struct browser_window *bw = gui_window_get_browser_window(gw); - - assert(bw != NULL); - - /* Synchronise the history (will also update the URL bar) */ - nsgtk_window_update_back_forward(nsgtk_get_scaffold(gw)); - - /* clear effects of potential searches */ - if (bw->search_context != NULL) - search_destroy_context(bw->search_context); - - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, bw); - - /* Ensure the window's title bar as well as favicon are updated */ - if (bw->current_content != NULL) { - gui_window_set_title(gw, - content_get_title(bw->current_content)); - - if (content_get_type(bw->current_content) == CONTENT_HTML) - gui_window_set_icon(gw, - html_get_favicon(bw->current_content)); - } -} - -void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g) -{ -#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); - - int i; - SENSITIVITY(STOP) - SENSITIVITY(RELOAD) - SENSITIVITY(CUT) - SENSITIVITY(COPY) - SENSITIVITY(PASTE) - SENSITIVITY(BACK) - SENSITIVITY(FORWARD) - SENSITIVITY(NEXTTAB) - SENSITIVITY(PREVTAB) - SENSITIVITY(CLOSETAB) -#undef SENSITIVITY -} - -void nsgtk_scaffolding_initial_sensitivity(struct gtk_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) - 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); - } - gtk_widget_set_sensitive(GTK_WIDGET(g->menu_bar->view_submenu->images_menuitem), FALSE); -} - -/** - * Checks if a location is over a link. - * - * Side effect of this function is to set the global current_menu_link_box - */ -static bool is_menu_over_link(struct gtk_scaffolding *g, gdouble x, gdouble y) -{ - struct browser_window *bw = gui_window_get_browser_window(g->top_level); - current_menu_link_box = NULL; - - if ((bw->current_content != NULL) && - (content_get_type(bw->current_content) == CONTENT_HTML)) { - current_menu_link_box = box_href_at_point(bw->current_content, x, y); - } - - if (current_menu_link_box == NULL) - return false; - - return true; -} - -void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g, gdouble x, gdouble y) -{ - if (is_menu_over_link(g, x, y)) { - popup_menu_show(g->menu_popup, false, true, false, false, false); - } else { - popup_menu_hide(g->menu_popup, false, true, false, false, false); - } - - nsgtk_scaffolding_update_edit_actions_sensitivity(g); - - if (!(g->buttons[COPY_BUTTON]->sensitivity)) - gtk_widget_hide(GTK_WIDGET(g->menu_popup->copy_menuitem)); - else - gtk_widget_show(GTK_WIDGET(g->menu_popup->copy_menuitem)); - - if (!(g->buttons[CUT_BUTTON]->sensitivity)) - gtk_widget_hide(GTK_WIDGET(g->menu_popup->cut_menuitem)); - else - gtk_widget_show(GTK_WIDGET(g->menu_popup->cut_menuitem)); - - if (!(g->buttons[PASTE_BUTTON]->sensitivity)) - gtk_widget_hide(GTK_WIDGET(g->menu_popup->paste_menuitem)); - else - gtk_widget_show(GTK_WIDGET(g->menu_popup->paste_menuitem)); - - /* hide customize */ - popup_menu_hide(g->menu_popup, false, false, false, false, true); - - gtk_menu_popup(g->menu_popup->popup_menu, NULL, NULL, NULL, NULL, 0, - gtk_get_current_event_time()); -} - -/** - * 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) -{ - struct gtk_scaffolding *g = (struct gtk_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; - } - g->toolbarmem = alloc->x; - gtk_widget_size_allocate(widget, alloc); -} - - - - -/** - * init the array g->buttons[] - */ -void nsgtk_scaffolding_toolbar_init(struct gtk_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 = GTK_IMAGE_MENU_ITEM(\ - 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(VIEWSOURCE, view_submenu, viewsource); - ITEM_MAIN(DOWNLOADS, view_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, nav_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); - ITEM_SUB(TOGGLEDEBUGGING, view_submenu, debugging, toggledebugging); - ITEM_SUB(SAVEBOXTREE, view_submenu, debugging, saveboxtree); - ITEM_SUB(SAVEDOMTREE, view_submenu, debugging, savedomtree); - 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(CONTENTS); - SENSITIVITY(DRAWFILE); - SENSITIVITY(POSTSCRIPT); - SENSITIVITY(NEXTTAB); - SENSITIVITY(PREVTAB); - SENSITIVITY(CLOSETAB); - SENSITIVITY(GUIDE); - SENSITIVITY(INFO); -#ifndef WITH_PDF_EXPORT - SENSITIVITY(PDF); -#endif - -#undef ITEM_MAIN -#undef ITEM_SUB -#undef ITEM_BUTTON -#undef ITEM_POP -#undef SENSITIVITY - -} diff --git a/gtk/gtk_scaffolding.h b/gtk/gtk_scaffolding.h deleted file mode 100644 index 76483e96b..000000000 --- a/gtk/gtk_scaffolding.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2005 James Bursa - * - * 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 . - */ - -#ifndef NETSURF_GTK_SCAFFOLDING_H -#define NETSURF_GTK_SCAFFOLDING_H 1 - -#include -#include -#include -#include "desktop/gui.h" -#include "desktop/plotters.h" -#include "gtk/gtk_menu.h" -#include "gtk/sexy_icon_entry.h" - -typedef struct gtk_scaffolding nsgtk_scaffolding; - -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 gtk_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; - GtkImageMenuItem *main; - GtkImageMenuItem *rclick; - GtkImageMenuItem *popup; - void *mhandler; /* menu item clicked */ - void *bhandler; /* button clicked */ - void *dataplus; /* customization -> toolbar */ - void *dataminus; /* customization -> store */ -}; - -extern nsgtk_scaffolding *scaf_list; - -nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel); - -bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g); - -GtkWindow *nsgtk_scaffolding_window(nsgtk_scaffolding *g); -GtkNotebook *nsgtk_scaffolding_notebook(nsgtk_scaffolding *g); -GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g); -GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g); -GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g); -struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g, - int i); -struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g); -GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g); -struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding - *g); -struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g); -void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g); -nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g); -void nsgtk_scaffolding_toolbar_init(struct gtk_scaffolding *g); -void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g); -void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g); -void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g); -void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char - *content); -void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g); -void nsgtk_scaffolding_set_top_level(struct gui_window *g); - -void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g); - -void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g); -void nsgtk_scaffolding_initial_sensitivity(struct gtk_scaffolding *g); -void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g, gdouble x, - gdouble y); -void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget, - GtkAllocation *alloc, gpointer data); - -gboolean nsgtk_window_url_activate_event(GtkWidget *, gpointer); -gboolean nsgtk_window_url_changed(GtkWidget *, GdkEventKey *, gpointer); - -#endif /* NETSURF_GTK_SCAFFOLDING_H */ diff --git a/gtk/gtk_schedule.c b/gtk/gtk_schedule.c deleted file mode 100644 index a3f866d3d..000000000 --- a/gtk/gtk_schedule.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2006-2007 Daniel Silverstone - * - * 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 . - */ - -#include -#include -#include - -#include "desktop/browser.h" -#include "gtk/gtk_schedule.h" - -#ifdef DEBUG_GTK_SCHEDULE -#include "utils/log.h" -#else -#define LOG(X) -#endif - -/** 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. */ -} _nsgtk_callback_t; - -/** List of callbacks which have occurred and are pending running. */ -static GList *pending_callbacks = NULL; -/** List of callbacks which are queued to occur in the future. */ -static GList *queued_callbacks = NULL; -/** List of callbacks which are about to be run in this ::schedule_run. */ -static GList *this_run = NULL; - -static gboolean -nsgtk_schedule_generic_callback(gpointer data) -{ - _nsgtk_callback_t *cb = (_nsgtk_callback_t *)(data); - if (cb->callback_killed) { - /* This callback instance has been killed. */ - LOG(("CB at %p already dead.", cb)); - } - queued_callbacks = g_list_remove(queued_callbacks, cb); - pending_callbacks = g_list_append(pending_callbacks, cb); - return FALSE; -} - -static void -nsgtk_schedule_kill_callback(void *_target, void *_match) -{ - _nsgtk_callback_t *target = (_nsgtk_callback_t *)_target; - _nsgtk_callback_t *match = (_nsgtk_callback_t *)_match; - if ((target->callback == match->callback) && - (target->context == match->context)) { - LOG(("Found match for %p(%p), killing.", - target->callback, target->context)); - target->callback = NULL; - target->context = NULL; - target->callback_killed = true; - } -} - -void -schedule_remove(void (*callback)(void *p), void *p) -{ - _nsgtk_callback_t cb_match = { - .callback = callback, - .context = p, - }; - - g_list_foreach(queued_callbacks, - nsgtk_schedule_kill_callback, &cb_match); - g_list_foreach(pending_callbacks, - nsgtk_schedule_kill_callback, &cb_match); - g_list_foreach(this_run, - nsgtk_schedule_kill_callback, &cb_match); -} - -void -schedule(int t, void (*callback)(void *p), void *p) -{ - const int msec_timeout = t * 10; - _nsgtk_callback_t *cb = malloc(sizeof(_nsgtk_callback_t)); - /* Kill any pending schedule of this kind. */ - schedule_remove(callback, p); - cb->callback = callback; - cb->context = p; - cb->callback_killed = false; - /* Prepend is faster right now. */ - queued_callbacks = g_list_prepend(queued_callbacks, cb); - g_timeout_add(msec_timeout, nsgtk_schedule_generic_callback, cb); -} - -bool -schedule_run(void) -{ - /* Capture this run of pending callbacks into the list. */ - this_run = pending_callbacks; - - if (this_run == NULL) - return false; /* Nothing to do */ - - /* Clear the pending list. */ - pending_callbacks = NULL; - - LOG(("Captured a run of %d callbacks to fire.", g_list_length(this_run))); - - /* Run all the callbacks which made it this far. */ - while (this_run != NULL) { - _nsgtk_callback_t *cb = (_nsgtk_callback_t *)(this_run->data); - this_run = g_list_remove(this_run, this_run->data); - if (!cb->callback_killed) - cb->callback(cb->context); - free(cb); - } - return true; -} diff --git a/gtk/gtk_schedule.h b/gtk/gtk_schedule.h deleted file mode 100644 index c63215e88..000000000 --- a/gtk/gtk_schedule.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2006 Daniel Silverstone - * - * 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 . - */ - -#ifndef NETSURF_GTK_CALLBACK_H -#define NETSURF_GTK_CALLBACK_H 1 - -typedef void (*gtk_callback)(void *p); -bool schedule_run(void); - -#endif /* NETSURF_GTK_CALLBACK_H */ diff --git a/gtk/gtk_search.c b/gtk/gtk_search.c deleted file mode 100644 index 30075be02..000000000 --- a/gtk/gtk_search.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - - - /** \file - * Free text search (front component) - */ -#include -#include -#include -#include "gtk/gtk_search.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_window.h" -#include "utils/config.h" -#include "content/content.h" -#include "content/hlcache.h" -#include "desktop/browser.h" -#include "desktop/gui.h" -#include "desktop/search.h" -#include "desktop/searchweb.h" -#include "desktop/selection.h" -#include "render/box.h" -#include "render/html.h" -#include "utils/config.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/utils.h" - -static void nsgtk_search_init(struct gtk_scaffolding *g); -static void nsgtk_search_set_status(bool found, void *p); -static void nsgtk_search_set_hourglass(bool active, void *p); -static void nsgtk_search_add_recent(const char *string, void *p); - -static struct search_callbacks nsgtk_search_callbacks = { - nsgtk_search_set_forward_state, - nsgtk_search_set_back_state, - nsgtk_search_set_status, - nsgtk_search_set_hourglass, - nsgtk_search_add_recent -}; - -/** connected to the search forward button */ - -gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - struct browser_window *bw = gui_window_get_browser_window( - nsgtk_scaffolding_top_level(g)); - nsgtk_search_init(g); - 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); - if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) - search_step(bw->search_context, flags, gtk_entry_get_text( - nsgtk_scaffolding_search(g)->entry)); - return TRUE; -} - -/** connected to the search back button */ - -gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - struct browser_window *bw = gui_window_get_browser_window( - nsgtk_scaffolding_top_level(g)); - nsgtk_search_init(g); - 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); - if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) - search_step(bw->search_context, flags, gtk_entry_get_text( - nsgtk_scaffolding_search(g)->entry)); - return TRUE; -} - -/** preparatory code when the search bar is made visible initially */ - -void nsgtk_search_init(struct gtk_scaffolding *g) -{ - hlcache_handle *c; - - assert(gui_window_get_browser_window(nsgtk_scaffolding_top_level(g)) - != NULL); - - c = gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))-> - current_content; - - if ((!c) || (content_get_type(c) != CONTENT_HTML && - content_get_type(c) != CONTENT_TEXTPLAIN)) - return; - -} - -/** connected to the search close button */ - -gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - nsgtk_scaffolding_toggle_search_bar_visibility(g); - return TRUE; -} - -/** connected to the search entry [typing] */ - -gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - struct browser_window *bw = gui_window_get_browser_window( - nsgtk_scaffolding_top_level(g)); - if ((bw != NULL) && (bw->search_context != NULL)) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, (void *)bw); - nsgtk_search_set_back_state(true, (void *)bw); - return TRUE; -} - -/** connected to the search entry [return key] */ - -gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - struct browser_window *bw = gui_window_get_browser_window( - nsgtk_scaffolding_top_level(g)); - nsgtk_search_init(g); - 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); - if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) - search_step(bw->search_context, flags, gtk_entry_get_text( - nsgtk_scaffolding_search(g)->entry)); - return FALSE; -} - -/** allows escape key to close search bar too */ - -gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, - gpointer data) -{ - if (event->keyval == GDK_Escape) { - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - nsgtk_scaffolding_toggle_search_bar_visibility(g); - } - return FALSE; -} - -/** connected to the websearch entry [return key] */ - -gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data) -{ - struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; - temp_open_background = 0; - search_web_new_window(gui_window_get_browser_window( - nsgtk_scaffolding_top_level(g)), - (char *)gtk_entry_get_text(GTK_ENTRY( - nsgtk_scaffolding_websearch(g)))); - temp_open_background = -1; - return TRUE; -} - -/** - * 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) -{ - struct gtk_scaffolding *g = (struct gtk_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; -} - -/** -* Change the displayed search status. -* \param found search pattern matched in text -* \param p the pointer sent to search_verify_new() / search_create_context() -*/ - -void nsgtk_search_set_status(bool found, void *p) -{ -} - -/** -* display hourglass while searching -* \param active start/stop indicator -* \param p the pointer sent to search_verify_new() / search_create_context() -*/ - -void nsgtk_search_set_hourglass(bool active, void *p) -{ -} - -/** -* add search string to recent searches list -* front is at liberty how to implement the bare notification -* should normally store a strdup() of the string; -* core gives no guarantee of the integrity of the const char * -* \param string search pattern -* \param p the pointer sent to search_verify_new() / search_create_context() -*/ - -void nsgtk_search_add_recent(const char *string, void *p) -{ -} - -/** -* activate search forwards button in gui -* \param active activate/inactivate -* \param p the pointer sent to search_verify_new() / search_create_context() -*/ - -void nsgtk_search_set_forward_state(bool active, void *p) -{ - struct browser_window *bw = (struct browser_window *)p; - if ((bw != NULL) && (bw->window != NULL)) { - struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search( - g)->buttons[1]), active); - } -} - -/** -* activate search back button in gui -* \param active activate/inactivate -* \param p the pointer sent to search_verify_new() / search_create_context() -*/ - -void nsgtk_search_set_back_state(bool active, void *p) -{ - struct browser_window *bw = (struct browser_window *)p; - if ((bw != NULL) && (bw->window != NULL)) { - struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search( - g)->buttons[0]), active); - } -} diff --git a/gtk/gtk_search.h b/gtk/gtk_search.h deleted file mode 100644 index 981ea5bfd..000000000 --- a/gtk/gtk_search.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#ifndef _NETSURF_GTK_SEARCH_H_ -#define _NETSURF_GTK_SEARCH_H_ - -#include -#include "gtk/gtk_scaffolding.h" - -void nsgtk_search_bar_toggle_visibility(struct gtk_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); -void nsgtk_search_set_forward_state(bool active, void *p); -void nsgtk_search_set_back_state(bool active, void *p); - -#endif diff --git a/gtk/gtk_selection.c b/gtk/gtk_selection.c deleted file mode 100644 index 334b552e5..000000000 --- a/gtk/gtk_selection.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2008 Mike Lester - * - * 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 . - */ - -#include -#include - -#include "utils/log.h" - -#include "desktop/gui.h" -#include "desktop/textinput.h" -#include "desktop/selection.h" -#include "desktop/browser.h" -#include "gtk/gtk_selection.h" -#include "gtk/gtk_window.h" -#include "utils/utf8.h" - -static GString *current_selection = NULL; -static GtkClipboard *clipboard; - -static bool copy_handler(const char *text, size_t length, struct box *box, - void *handle, const char *whitespace_text, - size_t whitespace_length); - - -bool gui_add_to_clipboard(const char *text, size_t length, bool space) -{ - /* add the text from this box */ - current_selection = g_string_append_len (current_selection, - text, length); - if (space) g_string_append (current_selection, " "); - return true; -} - -bool copy_handler(const char *text, size_t length, struct box *box, - void *handle, const char *whitespace_text, - size_t whitespace_length) -{ - /* add any whitespace which precedes the text from this box */ - if (whitespace_text) { - if (!gui_add_to_clipboard(whitespace_text, - whitespace_length, false)) { - return false; - } - } - /* add the text from this box */ - if (!gui_add_to_clipboard(text, length, box->space)) - return false; - - return true; -} - -bool gui_copy_to_clipboard(struct selection *s) -{ - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - if (s->defined && selection_traverse(s, copy_handler, NULL)) - gui_commit_clipboard(); - return TRUE; -} - -void gui_start_selection(struct gui_window *g) -{ - if (current_selection == NULL) - current_selection = g_string_new(NULL); - else - g_string_set_size(current_selection, 0); - - gtk_widget_grab_focus(GTK_WIDGET(nsgtk_window_get_layout(g))); -} - -void gui_clear_selection(struct gui_window *g) -{ -} - -void gui_paste_from_clipboard(struct gui_window *g, int x, int y) -{ - gchar *text; - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - text = gtk_clipboard_wait_for_text (clipboard); - /* clipboard_wait... converts the string to utf8 for us */ - if (text != NULL) - browser_window_paste_text(gui_window_get_browser_window(g), - text, strlen(text), true); - g_free(text); -} - -bool gui_empty_clipboard(void) -{ - if (!current_selection) - current_selection = g_string_new(NULL); - else - g_string_set_size(current_selection, 0); - - return true; -} - -bool gui_commit_clipboard(void) -{ - clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); - gtk_clipboard_set_text(clipboard, current_selection->str, -1); - gui_empty_clipboard(); - - return true; -} - diff --git a/gtk/gtk_selection.h b/gtk/gtk_selection.h deleted file mode 100644 index c2a0b35f4..000000000 --- a/gtk/gtk_selection.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2008 Mike Lester - * - * 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 . - */ - -#ifndef GTK_SELECTION_H -#define GTK_SELECTION_H - -#include -#include "desktop/gui.h" - -#endif diff --git a/gtk/gtk_tabs.c b/gtk/gtk_tabs.c deleted file mode 100644 index 5c2563c1a..000000000 --- a/gtk/gtk_tabs.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2008 Michael Lester - * - * 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 . - */ - -#include -#include -#include "gtk/gtk_window.h" -#include "gtk/gtk_gui.h" -#include "desktop/browser.h" -#include "content/content.h" -#include "desktop/options.h" -#include "desktop/search.h" -#include "utils/utils.h" -#include "gtk/options.h" -#include "gtk/gtk_search.h" -#include "gtk/gtk_tabs.h" - -#define TAB_WIDTH_N_CHARS 15 - -static GtkWidget *nsgtk_tab_label_setup(struct gui_window *window); -static void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, - guint page); -static void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, - GtkWidget *close_button); - -static void nsgtk_tab_page_changed(GtkNotebook *notebook, gpointer *page, - gint page_num); - -void nsgtk_tab_options_changed(GtkWidget *tabs) -{ - nsgtk_tab_visibility_update(GTK_NOTEBOOK(tabs), NULL, 0); -} - -void nsgtk_tab_init(GtkWidget *tabs) -{ - g_signal_connect(tabs, "switch-page", - G_CALLBACK(nsgtk_tab_page_changed), NULL); - - g_signal_connect(tabs, "page-removed", - G_CALLBACK(nsgtk_tab_visibility_update), NULL); - g_signal_connect(tabs, "page-added", - G_CALLBACK(nsgtk_tab_visibility_update), NULL); - nsgtk_tab_options_changed(tabs); -} - -void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background) -{ - GtkWidget *tabs = GTK_WIDGET(nsgtk_scaffolding_notebook( - nsgtk_get_scaffold(window))); - GtkWidget *tabBox = nsgtk_tab_label_setup(window); - gint remember = gtk_notebook_get_current_page(GTK_NOTEBOOK(tabs)); - gtk_notebook_append_page(GTK_NOTEBOOK(tabs), tab_contents, tabBox); - /*causes gtk errors can't set a parent */ - gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(tabs), - tab_contents, - true); - gtk_widget_show_all(tab_contents); - gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), - gtk_notebook_get_n_pages(GTK_NOTEBOOK(tabs)) - 1); - if (option_new_blank) { - /*char *blankpage = malloc(strlen(res_dir_location) + - SLEN("file:///blankpage") + 1); - blankpage = g_strconcat("file:///", res_dir_location, - "blankpage", NULL); */ - /* segfaults - struct browser_window *bw = - gui_window_get_browser_window(window); - browser_window_go(bw, blankpage, 0, true); */ - /* free(blankpage); */ - } - if (background) - gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), remember); - gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_urlbar( - nsgtk_get_scaffold(window)))); -} - -void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, - guint page) -{ - gint num_pages = gtk_notebook_get_n_pages(notebook); - if (option_show_single_tab == true || num_pages > 1) - gtk_notebook_set_show_tabs(notebook, TRUE); - else - gtk_notebook_set_show_tabs(notebook, FALSE); -} - -void nsgtk_tab_set_title(struct gui_window *g, const char *title) -{ - GtkWidget *label; - GtkWidget *tab; - tab = nsgtk_window_get_tab(g); - gboolean is_top_level = (tab != NULL); - - if (is_top_level) { - label = g_object_get_data(G_OBJECT(tab), "label"); - gtk_label_set_text(GTK_LABEL(label), title); - gtk_widget_set_tooltip_text(tab, title); - } -} - -GtkWidget *nsgtk_tab_label_setup(struct gui_window *window) -{ - GtkWidget *hbox, *label, *button, *close; - GtkRcStyle *rcstyle; - - hbox = gtk_hbox_new(FALSE, 2); - - if (option_new_blank == true) - label = gtk_label_new("New Tab"); - else - label = gtk_label_new("Loading..."); - gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); - gtk_label_set_single_line_mode(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_misc_set_padding(GTK_MISC(label), 0, 0); - gtk_widget_show(label); - - button = gtk_button_new(); - - close = gtk_image_new_from_stock("gtk-close", GTK_ICON_SIZE_MENU); - gtk_container_add(GTK_CONTAINER(button), close); - gtk_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."); - - rcstyle = gtk_rc_style_new(); - rcstyle->xthickness = rcstyle->ythickness = 0; - gtk_widget_modify_style(button, rcstyle); - g_object_unref(rcstyle); - - 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); - - 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); - - nsgtk_window_set_tab(window, hbox); - - gtk_widget_show_all(hbox); - return hbox; -} - -void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, - GtkWidget *close_button) -{ - PangoFontMetrics *metrics; - PangoContext *context; - int char_width, h, w; - - context = gtk_widget_get_pango_context(hbox); - metrics = pango_context_get_metrics(context, hbox->style->font_desc, - pango_context_get_language(context)); - - char_width = pango_font_metrics_get_approximate_digit_width(metrics); - pango_font_metrics_unref(metrics); - - gtk_icon_size_lookup_for_settings(gtk_widget_get_settings (hbox), - GTK_ICON_SIZE_MENU, &w, &h); - - gtk_widget_set_size_request(hbox, - TAB_WIDTH_N_CHARS * PANGO_PIXELS(char_width) + 2 * w, - -1); - - gtk_widget_set_size_request(close_button, w + 4, h + 4); -} - -void nsgtk_tab_page_changed(GtkNotebook *notebook, gpointer *page, - gint page_num) -{ - GtkWidget *window = gtk_notebook_get_nth_page(notebook, page_num); - struct gui_window *gw = g_object_get_data(G_OBJECT(window), - "gui_window"); - if (gw == NULL) - return; - struct browser_window *bw = gui_window_get_browser_window(gw); - if (bw == NULL) - return; - if (bw->search_context != NULL) - search_destroy_context(bw->search_context); - nsgtk_search_set_forward_state(true, bw); - nsgtk_search_set_back_state(true, bw); - nsgtk_scaffolding_set_top_level(gw); -} - -void nsgtk_tab_close_current(GtkNotebook *notebook) -{ - gint curr_page = gtk_notebook_get_current_page(notebook); - GtkWidget *window = gtk_notebook_get_nth_page(notebook, curr_page); - struct gui_window *gw = g_object_get_data(G_OBJECT(window), - "gui_window"); - - if (gtk_notebook_get_n_pages(notebook) < 2) - return; /* wicked things happen if we close the last tab */ - - nsgtk_window_destroy_browser(gw); - /* deletes 2 notebook tabs at a time! - gtk_notebook_remove_page(notebook, curr_page); */ -} diff --git a/gtk/gtk_tabs.h b/gtk/gtk_tabs.h deleted file mode 100644 index 969383001..000000000 --- a/gtk/gtk_tabs.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2008 Michael Lester - * - * 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 . - */ - -#ifndef _NETSURF_GTK_TABS_H_ -#define _NETSURF_GTK_TABS_H_ - -struct gui_window; - -void nsgtk_tab_init(GtkWidget *tabs); -void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background); -void nsgtk_tab_set_title(struct gui_window *g, const char *title); -void nsgtk_tab_options_changed(GtkWidget *tabs); -void nsgtk_tab_close_current(GtkNotebook *notebook); - -#endif diff --git a/gtk/gtk_theme.c b/gtk/gtk_theme.c deleted file mode 100644 index 98fc03410..000000000 --- a/gtk/gtk_theme.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include -#include -#include -#include "content/content.h" -#include "content/content_type.h" -#include "content/hlcache.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_menu.h" -#include "gtk/gtk_theme.h" -#include "gtk/gtk_window.h" -#include "gtk/options.h" -#include "gtk/dialogs/gtk_options.h" -#include "utils/container.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/utils.h" - -enum image_sets { - IMAGE_SET_MAIN_MENU = 0, - IMAGE_SET_RCLICK_MENU, - IMAGE_SET_POPUP_MENU, - IMAGE_SET_BUTTONS, - IMAGE_SET_COUNT -}; - -struct nsgtk_theme_cache { - GdkPixbuf *image[PLACEHOLDER_BUTTON]; - GdkPixbuf *searchimage[SEARCH_BUTTONS_COUNT]; - /* apng throbber image */ -}; - -static char *current_theme_name = NULL; -static struct nsgtk_theme_cache *theme_cache_menu = NULL; -static struct nsgtk_theme_cache *theme_cache_toolbar = NULL; - -static struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s); -static GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, - GtkIconSize s); -static bool nsgtk_theme_verify(const char *themename); -static void nsgtk_theme_cache_image(nsgtk_toolbar_button i, - const char *filename, const char *path); -static void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i, - const char *filename, const char *path); - -#ifdef WITH_THEME_INSTALL -static nserror theme_install_callback(hlcache_handle *c, - const hlcache_event *event, void *pw); -static bool theme_install_read(const char *data, unsigned long len); -#endif - -/** - * called during gui init phase to retrieve theme name from file then - * implement - */ - -void nsgtk_theme_init(void) -{ - size_t len; - if (option_current_theme == 0) - return; - len = SLEN("themelist") + strlen(res_dir_location) + 1; - char themefile[len]; - snprintf(themefile, len, "%s%s", res_dir_location, "themelist"); - nsgtk_scaffolding *list = scaf_list; - nsgtk_theme_verify(NULL); - FILE *fp = fopen(themefile, "r"); - if (fp == NULL) - return; - char buf[50]; - int row_count = 0; - while (fgets(buf, sizeof(buf), fp) != NULL) { - if (buf[0] == '\0') - continue; - - if (row_count++ == option_current_theme) { - if (current_theme_name != NULL) - free(current_theme_name); - /* clear the '\n' ["\n\0"->"\0\0"] */ - buf[strlen(buf) - 1] = '\0'; - current_theme_name = strdup(buf); - break; - } - } - fclose(fp); - - while (list != NULL) { - nsgtk_theme_implement(list); - list = nsgtk_scaffolding_iterate(list); - } -} - -/** - * return reference to static global current_theme_name; caller then has - * responsibility for global reference - */ - -char *nsgtk_theme_name(void) -{ - return current_theme_name; -} - -/** - * set static global current_theme_name from param; caller is responsible - * for the integrity of the global reference - */ - -void nsgtk_theme_set_name(char *name) -{ - current_theme_name = name; -} - -/** - * adds a theme name to the list of themes - */ - -void nsgtk_theme_add(const char *themename) -{ - size_t len; - GtkWidget *notification, *label; - len = SLEN("themelist") + strlen(res_dir_location) + 1; - char themefile[len]; - snprintf(themefile, len, "%s%s", res_dir_location, "themelist"); - /* conduct verification here; no adding duplicates to list */ - if (nsgtk_theme_verify(themename) == false) { - warn_user(messages_get("gtkThemeDup"), 0); - return; - } - FILE *fp = fopen(themefile, "a"); - if (fp == NULL) { - warn_user(messages_get("gtkFileError"), themefile); - return; - } - fprintf(fp, "%s\n", themename); - fclose(fp); - - /* notification that theme was added successfully */ - notification = gtk_dialog_new_with_buttons(messages_get("gtkThemeAdd"), - NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, - GTK_RESPONSE_NONE, NULL); - if (notification == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; - } - len = SLEN("\t\t\t\t\t\t") + strlen(messages_get("gtkThemeAdd")) + 1; - char labelcontent[len]; - snprintf(labelcontent, len, "\t\t\t%s\t\t\t", - messages_get("gtkThemeAdd")); - label = gtk_label_new(labelcontent); - if (label == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; - } - g_signal_connect_swapped(notification, "response", - G_CALLBACK(gtk_widget_destroy), notification); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notification)->vbox), label); - gtk_widget_show_all(notification); - - /* update combo */ - if (wndPreferences == NULL) - return; - nsgtk_options_combo_theme_add(themename); - -} - -/** - * \param themename contains a name of theme to check whether it may - * properly be added to the list; alternatively NULL to check the integrity - * of the list - * \return true for themename may be added / every item in the list is - * a valid directory - */ - -bool nsgtk_theme_verify(const char *themename) -{ - long filelength; - FILE *fp; - size_t val = SLEN("themelist") + strlen(res_dir_location) + 1; - char buf[50]; - char themefile[val]; - snprintf(themefile, val, "%s%s", res_dir_location, "themelist"); - if (themename == NULL) { - char *filecontent, *testfile; - struct stat sta; - fp = fopen(themefile, "r+"); - if (fp == NULL) { - warn_user(messages_get("gtkFileError"), themefile); - return true; - } - fseek(fp, 0L, SEEK_END); - filelength = ftell(fp); - filecontent = malloc(filelength + - SLEN("gtk default theme\n") + SLEN("\n") - + 1); - if (filecontent == NULL) { - warn_user(messages_get("NoMemory"), 0); - fclose(fp); - return true; - } - strcpy(filecontent, "gtk default theme\n"); - fseek(fp, 0L, SEEK_SET); - while (fgets(buf, sizeof(buf), fp) != NULL) { - /* iterate list */ - buf[strlen(buf) - 1] = '\0'; - /* "\n\0" -> "\0\0" */ - testfile = malloc(strlen(res_dir_location) + - SLEN("themes/") + strlen(buf) + 1); - if (testfile == NULL) { - warn_user(messages_get("NoMemory"), 0); - free(filecontent); - fclose(fp); - return false; - } - sprintf(testfile, "%sthemes/%s", res_dir_location, - buf); - /* check every directory */ - if (access(testfile, R_OK) == 0) { - stat(testfile, &sta); - if (S_ISDIR(sta.st_mode)) { - buf[strlen(buf)] = '\n'; - /* "\0\0" -> "\n\0" */ - strcat(filecontent, buf); - } - } - free(testfile); - } - fclose(fp); - fp = fopen(themefile, "w"); - if (fp == NULL) { - warn_user(messages_get("gtkFileError"), themefile); - free(filecontent); - return true; - } - val = fwrite(filecontent, strlen(filecontent), 1, fp); - if (val == 0) - LOG(("empty write themelist")); - fclose(fp); - free(filecontent); - return true; - } else { - fp = fopen(themefile, "r"); - if (fp == NULL) { - warn_user(messages_get("gtkFileError"), themefile); - return false; - } - while (fgets(buf, sizeof(buf), fp) != NULL) { - buf[strlen(buf) - 1] = '\0'; - /* "\n\0" -> "\0\0" */ - if (strcmp(buf, themename) == 0) { - fclose(fp); - return false; - } - } - fclose(fp); - return true; - } - -} - -/** - * sets the images for a particular scaffolding according to the current theme - */ - -void nsgtk_theme_implement(struct gtk_scaffolding *g) -{ - struct nsgtk_theme *theme[IMAGE_SET_COUNT]; - int i; - struct nsgtk_button_connect *button; - struct gtk_search *search; - - for (i = 0; i <= IMAGE_SET_POPUP_MENU; i++) - theme[i] = nsgtk_theme_load(GTK_ICON_SIZE_MENU); - - theme[IMAGE_SET_BUTTONS] = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); - - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) || - (i == WEBSEARCH_ITEM)) - continue; - button = nsgtk_scaffolding_button(g, i); - if (button == NULL) - continue; - /* gtk_image_menu_item_set_image accepts NULL image */ - if ((button->main != NULL) && - (theme[IMAGE_SET_MAIN_MENU] != NULL)) { - gtk_image_menu_item_set_image(button->main, - GTK_WIDGET( - theme[IMAGE_SET_MAIN_MENU]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->main)); - } - if ((button->rclick != NULL) && - (theme[IMAGE_SET_RCLICK_MENU] != NULL)) { - gtk_image_menu_item_set_image(button->rclick, - GTK_WIDGET( - theme[IMAGE_SET_RCLICK_MENU]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->rclick)); - } - if ((button->popup != NULL) && - (theme[IMAGE_SET_POPUP_MENU] != NULL)) { - gtk_image_menu_item_set_image(button->popup, - GTK_WIDGET( - theme[IMAGE_SET_POPUP_MENU]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->popup)); - } - if ((button->location != -1) && (button->button != NULL) && - (theme[IMAGE_SET_BUTTONS] != NULL)) { - gtk_tool_button_set_icon_widget( - GTK_TOOL_BUTTON(button->button), - GTK_WIDGET( - theme[IMAGE_SET_BUTTONS]-> - image[i])); - gtk_widget_show_all(GTK_WIDGET(button->button)); - } - } - - /* set search bar images */ - search = nsgtk_scaffolding_search(g); - if ((search != NULL) && (theme[IMAGE_SET_MAIN_MENU] != NULL)) { - /* gtk_tool_button_set_icon_widget accepts NULL image */ - if (search->buttons[SEARCH_BACK_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_BACK_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_BACK_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[SEARCH_BACK_BUTTON])); - } - if (search->buttons[SEARCH_FORWARD_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_FORWARD_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_FORWARD_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[ - SEARCH_FORWARD_BUTTON])); - } - if (search->buttons[SEARCH_CLOSE_BUTTON] != NULL) { - gtk_tool_button_set_icon_widget( - search->buttons[SEARCH_CLOSE_BUTTON], - GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> - searchimage[SEARCH_CLOSE_BUTTON])); - gtk_widget_show_all(GTK_WIDGET( - search->buttons[SEARCH_CLOSE_BUTTON])); - } - } - for (i = 0; i < IMAGE_SET_COUNT; i++) - if (theme[i] != NULL) - free(theme[i]); -} - -/** - * creates a set of images to add to buttons / menus - * loads images from cache, calling an update to the cache when necessary - * \return a struct nsgtk_theme is an array of images - */ - -struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s) -{ - if (current_theme_name == NULL) - return nsgtk_theme_default(s); - - struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme)); - if (theme == NULL) - return theme; - - if ((theme_cache_menu == NULL) || (theme_cache_toolbar == NULL)) - nsgtk_theme_prepare(); - - /* load theme from cache */ - struct nsgtk_theme_cache *cachetheme = (s == GTK_ICON_SIZE_MENU) ? - theme_cache_menu : theme_cache_toolbar; - if (cachetheme == NULL) { - free(theme); - return NULL; - } - -#define SET_BUTTON_IMAGE(p, q, r)\ - if (p->image[q##_BUTTON] != NULL)\ - r->image[q##_BUTTON] = GTK_IMAGE(gtk_image_new_from_pixbuf(\ - p->image[q##_BUTTON]));\ - else\ - r->image[q##_BUTTON] = nsgtk_theme_image_default(\ - q##_BUTTON, s); - - SET_BUTTON_IMAGE(cachetheme, BACK, theme) - SET_BUTTON_IMAGE(cachetheme, HISTORY, theme) - SET_BUTTON_IMAGE(cachetheme, FORWARD, theme) - SET_BUTTON_IMAGE(cachetheme, STOP, theme) - SET_BUTTON_IMAGE(cachetheme, RELOAD, theme) - SET_BUTTON_IMAGE(cachetheme, HOME, theme) - SET_BUTTON_IMAGE(cachetheme, NEWWINDOW, theme) - SET_BUTTON_IMAGE(cachetheme, NEWTAB, theme) - SET_BUTTON_IMAGE(cachetheme, OPENFILE, theme) - SET_BUTTON_IMAGE(cachetheme, CLOSETAB, theme) - SET_BUTTON_IMAGE(cachetheme, CLOSEWINDOW, theme) - SET_BUTTON_IMAGE(cachetheme, SAVEPAGE, theme) - SET_BUTTON_IMAGE(cachetheme, PRINTPREVIEW, theme) - SET_BUTTON_IMAGE(cachetheme, PRINT, theme) - SET_BUTTON_IMAGE(cachetheme, QUIT, theme) - SET_BUTTON_IMAGE(cachetheme, CUT, theme) - SET_BUTTON_IMAGE(cachetheme, COPY, theme) - SET_BUTTON_IMAGE(cachetheme, PASTE, theme) - SET_BUTTON_IMAGE(cachetheme, DELETE, theme) - SET_BUTTON_IMAGE(cachetheme, SELECTALL, theme) - SET_BUTTON_IMAGE(cachetheme, PREFERENCES, theme) - SET_BUTTON_IMAGE(cachetheme, ZOOMPLUS, theme) - SET_BUTTON_IMAGE(cachetheme, ZOOMMINUS, theme) - SET_BUTTON_IMAGE(cachetheme, ZOOMNORMAL, theme) - SET_BUTTON_IMAGE(cachetheme, FULLSCREEN, theme) - SET_BUTTON_IMAGE(cachetheme, VIEWSOURCE, theme) - SET_BUTTON_IMAGE(cachetheme, CONTENTS, theme) - SET_BUTTON_IMAGE(cachetheme, ABOUT, theme) - SET_BUTTON_IMAGE(cachetheme, PDF, theme) - SET_BUTTON_IMAGE(cachetheme, PLAINTEXT, theme) - SET_BUTTON_IMAGE(cachetheme, DRAWFILE, theme) - SET_BUTTON_IMAGE(cachetheme, POSTSCRIPT, theme) - SET_BUTTON_IMAGE(cachetheme, FIND, theme) - SET_BUTTON_IMAGE(cachetheme, DOWNLOADS, theme) - SET_BUTTON_IMAGE(cachetheme, SAVEWINDOWSIZE, theme) - SET_BUTTON_IMAGE(cachetheme, TOGGLEDEBUGGING, theme) - SET_BUTTON_IMAGE(cachetheme, SAVEBOXTREE, theme) - SET_BUTTON_IMAGE(cachetheme, SAVEDOMTREE, theme) - SET_BUTTON_IMAGE(cachetheme, LOCALHISTORY, theme) - SET_BUTTON_IMAGE(cachetheme, GLOBALHISTORY, theme) - SET_BUTTON_IMAGE(cachetheme, ADDBOOKMARKS, theme) - SET_BUTTON_IMAGE(cachetheme, SHOWBOOKMARKS, theme) - SET_BUTTON_IMAGE(cachetheme, SHOWCOOKIES, theme) - SET_BUTTON_IMAGE(cachetheme, OPENLOCATION, theme) - SET_BUTTON_IMAGE(cachetheme, NEXTTAB, theme) - SET_BUTTON_IMAGE(cachetheme, PREVTAB, theme) - SET_BUTTON_IMAGE(cachetheme, GUIDE, theme) - SET_BUTTON_IMAGE(cachetheme, INFO, theme) -#undef SET_BUTTON_IMAGE -#define SET_BUTTON_IMAGE(p, q, qq, r)\ - if (qq->searchimage[SEARCH_##p##_BUTTON] != NULL)\ - r->searchimage[SEARCH_##p##_BUTTON] =\ - GTK_IMAGE(gtk_image_new_from_pixbuf(\ - qq->searchimage[\ - SEARCH_##p##_BUTTON]));\ - else if (qq->image[q##_BUTTON] != NULL)\ - r->searchimage[SEARCH_##p##_BUTTON] =\ - GTK_IMAGE(gtk_image_new_from_pixbuf(\ - qq->image[q##_BUTTON]));\ - else\ - r->searchimage[SEARCH_##p##_BUTTON] =\ - nsgtk_theme_image_default(\ - PLACEHOLDER_BUTTON + SEARCH_##p##_BUTTON, s); - - SET_BUTTON_IMAGE(BACK, BACK, cachetheme, theme) - SET_BUTTON_IMAGE(FORWARD, FORWARD, cachetheme, theme) - SET_BUTTON_IMAGE(CLOSE, CLOSEWINDOW, cachetheme, theme) -#undef SET_BUTTON_IMAGE - return theme; -} - -/** - * caches individual theme images from file - * \param i the toolbar button reference - * \param filename the image file name - * \param path the path to the theme folder - */ -void nsgtk_theme_cache_image(nsgtk_toolbar_button i, const char *filename, - const char *path) -{ - char fullpath[strlen(filename) + strlen(path) + 1]; - sprintf(fullpath, "%s%s", path, filename); - if (theme_cache_toolbar != NULL) - theme_cache_toolbar->image[i] = - gdk_pixbuf_new_from_file_at_size(fullpath, - 24, 24, NULL); - if (theme_cache_menu != NULL) - theme_cache_menu->image[i] = gdk_pixbuf_new_from_file_at_size( - fullpath, 16, 16, NULL); -} - -void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i, - const char *filename, const char *path) -{ - char fullpath[strlen(filename) + strlen(path) + 1]; - sprintf(fullpath, "%s%s", path, filename); - if (theme_cache_toolbar != NULL) - theme_cache_toolbar->searchimage[i] = - gdk_pixbuf_new_from_file_at_size(fullpath, - 24, 24, NULL); - if (theme_cache_menu != NULL) - theme_cache_menu->searchimage[i] = - gdk_pixbuf_new_from_file_at_size(fullpath, - 16, 16, NULL); -} - -/** - * caches theme images from file as pixbufs - */ -void nsgtk_theme_prepare(void) -{ - if (current_theme_name == NULL) - return; - if (theme_cache_menu == NULL) - theme_cache_menu = malloc(sizeof(struct nsgtk_theme_cache)); - if (theme_cache_toolbar == NULL) - theme_cache_toolbar = malloc(sizeof(struct nsgtk_theme_cache)); - size_t len = strlen(res_dir_location) + SLEN("/themes/") + - strlen(current_theme_name) + 1; - char path[len]; - snprintf(path, len, "%sthemes/%s/", res_dir_location, - current_theme_name); -#define CACHE_IMAGE(p, q, r)\ - nsgtk_theme_cache_image(p##_BUTTON, #q ".png", r) - - CACHE_IMAGE(BACK, back, path); - CACHE_IMAGE(HISTORY, history, path); - CACHE_IMAGE(FORWARD, forward, path); - CACHE_IMAGE(STOP, stop, path); - CACHE_IMAGE(RELOAD, reload, path); - CACHE_IMAGE(HOME, home, path); - CACHE_IMAGE(NEWWINDOW, newwindow, path); - CACHE_IMAGE(NEWTAB, newtab, path); - CACHE_IMAGE(OPENFILE, openfile, path); - CACHE_IMAGE(CLOSETAB, closetab, path); - CACHE_IMAGE(CLOSEWINDOW, closewindow, path); - CACHE_IMAGE(SAVEPAGE, savepage, path); - CACHE_IMAGE(PRINTPREVIEW, printpreview, path); - CACHE_IMAGE(PRINT, print, path); - CACHE_IMAGE(QUIT, quit, path); - CACHE_IMAGE(CUT, cut, path); - CACHE_IMAGE(COPY, copy, path); - CACHE_IMAGE(PASTE, paste, path); - CACHE_IMAGE(DELETE, delete, path); - CACHE_IMAGE(SELECTALL, selectall, path); - CACHE_IMAGE(PREFERENCES, preferences, path); - CACHE_IMAGE(ZOOMPLUS, zoomplus, path); - CACHE_IMAGE(ZOOMMINUS, zoomminus, path); - CACHE_IMAGE(ZOOMNORMAL, zoomnormal, path); - CACHE_IMAGE(FULLSCREEN, fullscreen, path); - CACHE_IMAGE(VIEWSOURCE, viewsource, path); - CACHE_IMAGE(CONTENTS, helpcontents, path); - CACHE_IMAGE(ABOUT, helpabout, path); - CACHE_IMAGE(PDF, pdf, path); - CACHE_IMAGE(PLAINTEXT, plaintext, path); - CACHE_IMAGE(DRAWFILE, drawfile, path); - CACHE_IMAGE(POSTSCRIPT, postscript, path); - CACHE_IMAGE(FIND, find, path); - CACHE_IMAGE(DOWNLOADS, downloads, path); - CACHE_IMAGE(SAVEWINDOWSIZE, savewindowsize, path); - CACHE_IMAGE(TOGGLEDEBUGGING, toggledebugging, path); - CACHE_IMAGE(SAVEBOXTREE, boxtree, path); - CACHE_IMAGE(SAVEDOMTREE, domtree, path); - CACHE_IMAGE(LOCALHISTORY, localhistory, path); - CACHE_IMAGE(GLOBALHISTORY, globalhistory, path); - CACHE_IMAGE(ADDBOOKMARKS, addbookmarks, path); - CACHE_IMAGE(SHOWBOOKMARKS, showbookmarks, path); - CACHE_IMAGE(SHOWCOOKIES, showcookies, path); - CACHE_IMAGE(OPENLOCATION, openlocation, path); - CACHE_IMAGE(NEXTTAB, nexttab, path); - CACHE_IMAGE(PREVTAB, prevtab, path); - CACHE_IMAGE(GUIDE, helpguide, path); - CACHE_IMAGE(INFO, helpinfo, path); -#undef CACHE_IMAGE -#define CACHE_IMAGE(p, q, r)\ - nsgtk_theme_cache_searchimage(p, #q ".png", r); - - CACHE_IMAGE(SEARCH_BACK_BUTTON, searchback, path); - CACHE_IMAGE(SEARCH_FORWARD_BUTTON, searchforward, path); - CACHE_IMAGE(SEARCH_CLOSE_BUTTON, searchclose, path); -#undef CACHE_IMAGE -} - -/** - * returns default image for buttons / menu items from gtk stock items - * \param i button reference - */ - -GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, GtkIconSize s) -{ - char *imagefile; - GtkImage *image; - switch(i) { -#define BUTTON_IMAGE(p, q)\ - case p##_BUTTON:\ - return GTK_IMAGE(gtk_image_new_from_stock(#q, s)) - - BUTTON_IMAGE(BACK, gtk-go-back); - case HISTORY_BUTTON: { - size_t len = SLEN("arrow_down_8x32.png") + - strlen(res_dir_location) + 1; - imagefile = malloc(len); - if (imagefile == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - snprintf(imagefile, len, "%sarrow_down_8x32.png", - res_dir_location); - image = GTK_IMAGE(gtk_image_new_from_file(imagefile)); - free(imagefile); - return image; - } - BUTTON_IMAGE(FORWARD, gtk-go-forward); - BUTTON_IMAGE(STOP, gtk-stop); - BUTTON_IMAGE(RELOAD, gtk-refresh); - BUTTON_IMAGE(HOME, gtk-home); - BUTTON_IMAGE(NEWWINDOW, gtk-new); - BUTTON_IMAGE(NEWTAB, gtk-new); - BUTTON_IMAGE(OPENFILE, gtk-open); - BUTTON_IMAGE(CLOSETAB, gtk-close); - BUTTON_IMAGE(CLOSEWINDOW, gtk-close); - BUTTON_IMAGE(SAVEPAGE, gtk-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, gtk-find); - BUTTON_IMAGE(PREFERENCES, gtk-preferences); - BUTTON_IMAGE(ZOOMPLUS, gtk-zoom-in); - BUTTON_IMAGE(ZOOMMINUS, gtk-zoom-out); - BUTTON_IMAGE(ZOOMNORMAL, gtk-zoom-100); - BUTTON_IMAGE(FULLSCREEN, gtk-fullscreen); - BUTTON_IMAGE(VIEWSOURCE, gtk-index); - BUTTON_IMAGE(CONTENTS, gtk-help); - BUTTON_IMAGE(ABOUT, gtk-about); -#undef BUTTON_IMAGE - case (PLACEHOLDER_BUTTON + SEARCH_BACK_BUTTON): - return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-back", s)); - case (PLACEHOLDER_BUTTON + SEARCH_FORWARD_BUTTON): - return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-forward", - s)); - case (PLACEHOLDER_BUTTON + SEARCH_CLOSE_BUTTON): - return GTK_IMAGE(gtk_image_new_from_stock("gtk-close", s)); - default: { - size_t len = SLEN("themes/Alpha.png") + - strlen(res_dir_location) + 1; - imagefile = malloc(len); - if (imagefile == NULL) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - snprintf(imagefile, len, "%sthemes/Alpha.png", - res_dir_location); - image = GTK_IMAGE( - gtk_image_new_from_file(imagefile)); - free(imagefile); - return image; - } - } -} - - -#ifdef WITH_THEME_INSTALL -/** - * when CONTENT_THEME needs handling call this function - */ -void theme_install_start(hlcache_handle *c) -{ - assert(c); - assert(content_get_type(c) == CONTENT_THEME); - - /* stop theme sitting in memory cache */ - content_invalidate_reuse_data(c); - - hlcache_handle_replace_callback(c, theme_install_callback, NULL); -} - - -/** - * Callback for fetchcache() for theme install fetches. - */ - -nserror theme_install_callback(hlcache_handle *c, - const hlcache_event *event, void *pw) -{ - switch (event->type) { - case CONTENT_MSG_READY: - break; - - case CONTENT_MSG_DONE: - { - const char *source_data; - unsigned long source_size; - - source_data = content_get_source_data(c, &source_size); - - if (!theme_install_read(source_data, source_size)) - warn_user("ThemeInvalid", 0); - - hlcache_handle_release(c); - } - break; - - case CONTENT_MSG_ERROR: - warn_user(event->data.error, 0); - break; - - case CONTENT_MSG_STATUS: - break; - - case CONTENT_MSG_LOADING: - case CONTENT_MSG_REFORMAT: - case CONTENT_MSG_REDRAW: - default: - assert(0); - break; - } - - return NSERROR_OK; -} - -/** - * handler saves theme data content as a local theme - */ - -bool theme_install_read(const char *data, unsigned long len) -{ - char *filename, *newfilename; - size_t namelen; - int handle = g_file_open_tmp("nsgtkthemeXXXXXX", &filename, NULL); - if (handle == -1) { - warn_user(messages_get("gtkFileError"), - "temporary theme file"); - return false; - } - ssize_t written = write(handle, data, len); - close(handle); - if ((unsigned)written != len) - return false; - - /* get name of theme; set as dirname */ - namelen = SLEN("themes/") + strlen(res_dir_location) + 1; - char dirname[namelen]; - snprintf(dirname, namelen, "%sthemes/", res_dir_location); - - /* save individual files in theme */ - newfilename = container_extract_theme(filename, dirname); - g_free(filename); - if (newfilename == NULL) - return false; - nsgtk_theme_add(newfilename); - free(newfilename); - - return true; -} -#endif - -/** - * loads the set of default images for the toolbar / menus - */ - -struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s) -{ - struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme)); - if (theme == NULL) { - warn_user("NoMemory", 0); - return NULL; - } - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON + - SEARCH_BUTTONS_COUNT; i++) - theme->image[i] = nsgtk_theme_image_default(i, s); - return theme; -} - diff --git a/gtk/gtk_theme.h b/gtk/gtk_theme.h deleted file mode 100644 index 833379d36..000000000 --- a/gtk/gtk_theme.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#ifndef _NETSURF_GTK_THEME_H_ -#define _NETSURF_GTK_THEME_H_ - -#include -#include "gtk/gtk_scaffolding.h" - -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 */ -}; - -struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s); -void nsgtk_theme_add(const char *themename); -void nsgtk_theme_init(void); -void nsgtk_theme_prepare(void); -void nsgtk_theme_implement(struct gtk_scaffolding *g); -char *nsgtk_theme_name(void); -void nsgtk_theme_set_name(char *name); - -#endif diff --git a/gtk/gtk_throbber.c b/gtk/gtk_throbber.c deleted file mode 100644 index 5f79a2182..000000000 --- a/gtk/gtk_throbber.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2008 Rob Kendrick - * Copyright 2008 Sean Fox - * - * 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 . - */ - -#include -#include -#include -#ifdef WITH_GIF -#include -#endif -#include "utils/log.h" -#include "gtk/gtk_throbber.h" -#include "gtk/gtk_bitmap.h" - -struct nsgtk_throbber *nsgtk_throbber = NULL; - -/** - * Creates the throbber using a PNG for each frame. The number of frames must - * be at least two. The first frame is the inactive frame, others are the - * active frames. - * - * \param frames The number of frames. Must be at least two. - * \param ... Filenames of PNGs containing frames. - * \return true on success. - */ -bool nsgtk_throbber_initialise_from_png(const int frames, char** frame_files) -{ - GError *err = NULL; - struct nsgtk_throbber *throb; /**< structure we generate */ - bool errors_when_loading = false; /**< true if a frame failed */ - int frame_loop; - - if (frames < 2) { - /* we need at least two frames - one for idle, one for active */ - LOG(("Insufficent number of frames in throbber animation!")); - LOG(("(called with %d frames, where 2 is a minimum.)", - frames)); - return false; - } - - throb = malloc(sizeof(*throb)); - if (throb == NULL) - return false; - - throb->nframes = frames; - throb->framedata = malloc(sizeof(GdkPixbuf *) * throb->nframes); - if (throb->framedata == NULL) { - free(throb); - return false; - } - - for (frame_loop = 0; frame_loop < frames; frame_loop++) { - throb->framedata[frame_loop] = gdk_pixbuf_new_from_file(frame_files[frame_loop], &err); - if (err != NULL) { - LOG(("Error when loading %s: %s (%d)", - frame_files[frame_loop], err->message, err->code)); - throb->framedata[frame_loop] = NULL; - errors_when_loading = true; - } - } - - if (errors_when_loading == true) { - for (frame_loop = 0; frame_loop < frames; frame_loop++) { - if (throb->framedata[frame_loop] != NULL) - gdk_pixbuf_unref(throb->framedata[frame_loop]); - } - - free(throb->framedata); - free(throb); - - return false; - } - - nsgtk_throbber = throb; - - return true; -} - -void nsgtk_throbber_finalise(void) -{ - int i; - - for (i = 0; i < nsgtk_throbber->nframes; i++) - gdk_pixbuf_unref(nsgtk_throbber->framedata[i]); - - free(nsgtk_throbber->framedata); - free(nsgtk_throbber); - - nsgtk_throbber = NULL; -} - diff --git a/gtk/gtk_throbber.h b/gtk/gtk_throbber.h deleted file mode 100644 index 1463c9b26..000000000 --- a/gtk/gtk_throbber.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2008 Rob Kendrick - * - * 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 . - */ - -#ifndef __GTK_THROBBER_H__ -#define __GTK_THROBBER_H__ - -#include - -struct nsgtk_throbber -{ - int nframes; /**< Number of frames in the throbber */ - GdkPixbuf **framedata; -}; - -extern struct nsgtk_throbber *nsgtk_throbber; - -bool nsgtk_throbber_initialise_from_png(const int frames, char** frame_files); -void nsgtk_throbber_finalise(void); - -#endif /* __GTK_THROBBER_H__ */ diff --git a/gtk/gtk_thumbnail.c b/gtk/gtk_thumbnail.c deleted file mode 100644 index 59727727c..000000000 --- a/gtk/gtk_thumbnail.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2006 Rob Kendrick - * - * 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 . - */ - -/** \file - * Page thumbnail creation (implementation). - * - * Thumbnails are created by setting the current drawing contexts to the - * bitmap (a gdk pixbuf) we are passed, and plotting the page at a small - * scale. - */ - -#include -#include -#include "content/content.h" -#include "content/hlcache.h" -#include "content/urldb.h" -#include "desktop/plotters.h" -#include "desktop/browser.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_bitmap.h" -#include "image/bitmap.h" -#include "render/font.h" -#include "utils/log.h" -#include "utils/utils.h" - -/** - * Create a thumbnail of a page. - * - * \param content content structure to thumbnail - * \param bitmap the bitmap to draw to - * \param url the URL the thumnail belongs to, or NULL - */ -bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap, - const char *url) -{ - GdkPixbuf *pixbuf; - int cwidth, cheight; - gint width; - gint height; - gint depth; - GdkPixmap *pixmap; - GdkPixbuf *big; - - assert(content); - assert(bitmap); - - cwidth = min(content_get_width(content), 1024); - cheight = min(content_get_height(content), 768); - - pixbuf = gtk_bitmap_get_primary(bitmap); - width = gdk_pixbuf_get_width(pixbuf); - height = gdk_pixbuf_get_height(pixbuf); - depth = (gdk_screen_get_system_visual(gdk_screen_get_default()))->depth; - - LOG(("Trying to create a thumbnail pixmap for a content of %dx%d@%d", - content_get_width(content), content_get_height(content), - depth)); - - pixmap = gdk_pixmap_new(NULL, cwidth, cwidth, depth); - - if (pixmap == NULL) { - /* the creation failed for some reason: most likely because - * we've been asked to create with with at least one dimention - * as zero. The RISC OS thumbnail generator returns false - * from here when it can't create a bitmap, so we assume it's - * safe to do so here too. - */ - return false; - } - - gdk_drawable_set_colormap(pixmap, gdk_colormap_get_system()); - - /* set the plotting functions up */ - plot = nsgtk_plotters; - - nsgtk_plot_set_scale((double) cwidth / - (double) content_get_width(content)); - - /* set to plot to pixmap */ - current_drawable = pixmap; - current_gc = gdk_gc_new(current_drawable); -#ifdef CAIRO_VERSION - current_cr = gdk_cairo_create(current_drawable); -#endif - plot.rectangle(0, 0, cwidth, cwidth, plot_style_fill_white); - - plot.clip(0, 0, content_get_width(content), content_get_width(content)); - - /* render the content */ - content_redraw(content, 0, 0, content_get_width(content), - content_get_width(content), - 0, 0, content_get_width(content), - content_get_width(content), 1.0, 0xFFFFFF); - - /* resample the large plot down to the size of our thumbnail */ - big = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0, - cwidth, cwidth); - - gdk_pixbuf_scale(big, pixbuf, 0, 0, width, height, 0, 0, - (double)width / (double)cwidth, - (double)height / (double)cwidth, - GDK_INTERP_TILES); - - /* As a debugging aid, try this to dump out a copy of the thumbnail as - * a PNG: gdk_pixbuf_save(pixbuf, "thumbnail.png", "png", NULL, NULL); - */ - - /* register the thumbnail with the URL */ - if (url) - urldb_set_thumbnail(url, bitmap); - - bitmap_modified(bitmap); - - g_object_unref(current_gc); -#ifdef CAIRO_VERSION - cairo_destroy(current_cr); -#endif - g_object_unref(pixmap); - g_object_unref(big); - - return true; -} diff --git a/gtk/gtk_toolbar.c b/gtk/gtk_toolbar.c deleted file mode 100644 index ab463a103..000000000 --- a/gtk/gtk_toolbar.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#include -#include "desktop/searchweb.h" -#include "gtk/gtk_toolbar.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_search.h" -#include "gtk/gtk_theme.h" -#include "gtk/gtk_throbber.h" -#include "gtk/gtk_window.h" -#include "gtk/sexy_icon_entry.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/utils.h" - -static GtkTargetEntry entry = {(char *)"nsgtk_button_data", - GTK_TARGET_SAME_APP, 0}; - -static bool edit_mode = false; - -struct nsgtk_toolbar_custom_store { - GtkWidget *window; - GtkWidget *store_buttons[PLACEHOLDER_BUTTON]; - GtkWidget *widgetvbox; - GtkWidget *currentbar; - char numberh; /* current horizontal location while adding */ - GladeXML *glade; /* button widgets to store */ - int buttonlocations[PLACEHOLDER_BUTTON]; - int currentbutton; - bool fromstore; -}; -/* the number of buttons that fit in the width of the store window */ -#define NSGTK_STORE_WIDTH 6 - -/* the 'standard' width of a button that makes sufficient of its label -visible */ -#define NSGTK_BUTTON_WIDTH 111 - -/* the 'standard' height of a button that fits as many toolbars as -possible into the store */ -#define NSGTK_BUTTON_HEIGHT 70 - -/* the 'normal' width of the websearch bar */ -#define NSGTK_WEBSEARCH_WIDTH 150 - -static struct nsgtk_toolbar_custom_store store; -static struct nsgtk_toolbar_custom_store *window = &store; - -static void nsgtk_toolbar_close(nsgtk_scaffolding *g); -static void nsgtk_toolbar_window_open(nsgtk_scaffolding *g); -static void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g); -static void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i, - struct nsgtk_theme *theme); -static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget); -static gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *context, - gint x, gint y, guint time, gpointer data); -static gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, gint x, gint y, guint time, gpointer data); -static gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext - *drag_context, gint x, gint y, guint time, gpointer data); -gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, guint time, gpointer data); -static gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext - *gdc, gint x, gint y, GtkSelectionData *selection, guint info, - guint time, gpointer data); -static void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint - time, gpointer data); -static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, - gpointer data); -static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data); -static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data); -static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data); -static void nsgtk_toolbar_cast(nsgtk_scaffolding *g); -static GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g, - nsgtk_toolbar_button i, struct nsgtk_theme *theme); -static void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, - nsgtk_toolbar_button i); -static void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, - nsgtk_toolbar_button i); -static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data); -static nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location( - nsgtk_scaffolding *g, int i); - -/** - * change behaviour of scaffoldings while editing toolbar; all buttons as - * well as window clicks are desensitized; then buttons in the front window - * are changed to movable buttons - */ -void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g) -{ - int i; - nsgtk_scaffolding *list = scaf_list; - edit_mode = true; - - while (list) { - g_signal_handler_block(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_CLICK)); - g_signal_handler_block(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_REDRAW)); - gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - GTK_STATE_NORMAL, &((GdkColor) - {0, 0xEEEE, 0xEEEE, 0xEEEE})); - - if (list == g) { - list = nsgtk_scaffolding_iterate(list); - continue; - } - /* set sensitive for all gui_windows save g */ - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_window( - list)), FALSE); - list = nsgtk_scaffolding_iterate(list); - } - /* set sensitive for all of g save toolbar */ - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), - FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), - FALSE); - - /* set editable aspect for toolbar */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), - nsgtk_toolbar_clear_toolbar, g); - nsgtk_toolbar_set_physical(g); - /* memorize button locations, set editable */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - window->buttonlocations[i] = nsgtk_scaffolding_button(g, i) - ->location; - if ((window->buttonlocations[i] == -1) || (i == URL_BAR_ITEM)) - continue; - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( - nsgtk_scaffolding_button(g, i)->button), TRUE); - gtk_drag_source_set(GTK_WIDGET(nsgtk_scaffolding_button( - g, i)->button), GDK_BUTTON1_MASK, &entry, 1, - GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, i); - } - - /* add move button listeners */ - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-drop", G_CALLBACK(nsgtk_toolbar_data), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-data-received", G_CALLBACK( - nsgtk_toolbar_move_complete), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-motion", G_CALLBACK(nsgtk_toolbar_action), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - "drag-leave", G_CALLBACK( - nsgtk_toolbar_clear), g); - - /* set data types */ - gtk_drag_dest_set(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), - GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, - &entry, 1, GDK_ACTION_COPY); - - /* open toolbar window */ - nsgtk_toolbar_window_open(g); -} - -/** - * create store window - */ -void nsgtk_toolbar_window_open(nsgtk_scaffolding *g) -{ - int x = 0, y = 0; - struct nsgtk_theme *theme = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); - if (theme == NULL) { - warn_user(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - return; - } - window->glade = glade_xml_new(glade_toolbar_file_location, - "toolbarwindow", NULL); - if (window->glade == NULL) { - warn_user(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - } - glade_xml_signal_autoconnect(window->glade); - - window->window = glade_xml_get_widget(window->glade, "toolbarwindow"); - if (window->window == NULL) { - warn_user(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - free(theme); - return; - } - window->widgetvbox = glade_xml_get_widget(window->glade, "widgetvbox"); - if (window->widgetvbox == NULL) { - warn_user(messages_get("NoMemory"), 0); - nsgtk_toolbar_cancel_clicked(NULL, g); - free(theme); - return; - } - - window->numberh = NSGTK_STORE_WIDTH; /* preset to width [in buttons] of */ - /* store to cause creation of a new toolbar */ - window->currentbutton = -1; - /* load toolbuttons */ - /* add toolbuttons to window */ - /* set event handlers */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if (i == URL_BAR_ITEM) - continue; - window->store_buttons[i] = - nsgtk_toolbar_make_widget(g, i, theme); - if (window->store_buttons[i] == NULL) { - warn_user(messages_get("NoMemory"), 0); - continue; - } - nsgtk_toolbar_add_store_widget(window->store_buttons[i]); - g_signal_connect(window->store_buttons[i], "drag-data-get", - G_CALLBACK( - nsgtk_scaffolding_button(g, i)->dataplus), g); - } - free(theme); - gtk_window_set_transient_for(GTK_WINDOW(window->window), - nsgtk_scaffolding_window(g)); - gtk_window_set_title(GTK_WINDOW(window->window), messages_get( - "gtkToolBarTitle")); - gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE); - gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY); - gtk_widget_show_all(window->window); - gtk_window_set_position(GTK_WINDOW(window->window), - GTK_WIN_POS_CENTER_ON_PARENT); - gtk_window_get_position(nsgtk_scaffolding_window(g), &x, &y); - gtk_window_move(GTK_WINDOW(window->window), x, y + 100); - g_signal_connect(glade_xml_get_widget(window->glade, "cancelbutton"), - "clicked", G_CALLBACK( - nsgtk_toolbar_cancel_clicked), g); - g_signal_connect(glade_xml_get_widget(window->glade, "okbutton"), - "clicked", G_CALLBACK(nsgtk_toolbar_persist), g); - g_signal_connect(glade_xml_get_widget(window->glade, "resetbutton"), - "clicked", G_CALLBACK(nsgtk_toolbar_reset), g); - g_signal_connect(window->window, "delete-event", - G_CALLBACK(nsgtk_toolbar_delete), g); - g_signal_connect(window->window, "drag-drop", - G_CALLBACK(nsgtk_toolbar_store_return), g); - g_signal_connect(window->window, "drag-motion", - G_CALLBACK(nsgtk_toolbar_store_action), g); -} - -/** - * when titlebar / alt-F4 window close event happens - */ -gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - edit_mode = false; - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - /* reset g->buttons->location */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_scaffolding_button(g, i)->location = - window->buttonlocations[i]; - } - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_connect_all(g); - nsgtk_toolbar_close(g); - nsgtk_scaffolding_set_sensitivity(g); - gtk_widget_destroy(window->window); - return TRUE; -} - -/** - * when cancel button is clicked - */ -gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data) -{ - edit_mode = false; - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - /* reset g->buttons->location */ - for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_scaffolding_button(g, i)->location = - window->buttonlocations[i]; - } - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_connect_all(g); - nsgtk_toolbar_close(g); - nsgtk_scaffolding_set_sensitivity(g); - gtk_widget_destroy(window->window); - return TRUE; -} - -/** - * when 'save settings' button is clicked - */ -gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data) -{ - edit_mode = false; - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - /* save state to file, update toolbars for all windows */ - nsgtk_toolbar_customization_save(g); - nsgtk_toolbar_cast(g); - nsgtk_toolbar_set_physical(g); - nsgtk_toolbar_close(g); - gtk_widget_destroy(window->window); - return TRUE; -} - -/** - * when 'reload defaults' button is clicked - */ -gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - int i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_scaffolding_button(g, i)->location = - (i <= THROBBER_ITEM) ? i : -1; - nsgtk_toolbar_set_physical(g); - for (i = BACK_BUTTON; i <= THROBBER_ITEM; i++) { - if (i == URL_BAR_ITEM) - continue; - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( - nsgtk_scaffolding_button(g, i)->button), TRUE); - gtk_drag_source_set(GTK_WIDGET( - nsgtk_scaffolding_button(g, i)->button), - GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, i); - } - return TRUE; -} - -/** - * set toolbar logical -> physical; physically visible toolbar buttons are made - * to correspond to the logically stored schema in terms of location - * visibility etc - */ -void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g) -{ - int i; - struct nsgtk_theme *theme = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); - if (theme == NULL) { - warn_user(messages_get("NoMemory"), 0); - return; - } - /* simplest is to clear the toolbar then reload it from memory */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), - nsgtk_toolbar_clear_toolbar, g); - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_toolbar_add_item_to_toolbar(g, i, theme); - gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g))); - free(theme); -} - -/** - * cleanup code physical update of all toolbars; resensitize - * \param g the 'front' scaffolding that called customize - */ -void nsgtk_toolbar_close(nsgtk_scaffolding *g) -{ - int i; - nsgtk_scaffolding *list = scaf_list; - while (list) { - struct nsgtk_theme *theme = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); - if (theme == NULL) { - warn_user(messages_get("NoMemory"), 0); - continue; - } - /* clear toolbar */ - gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar( - list)), nsgtk_toolbar_clear_toolbar, list); - /* then add items */ - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - nsgtk_toolbar_add_item_to_toolbar(list, i, theme); - } - nsgtk_toolbar_connect_all(list); - gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar( - list))); - nsgtk_scaffolding_set_sensitivity(list); - gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - GTK_STATE_NORMAL, &((GdkColor) - {0, 0xFFFF, 0xFFFF, 0xFFFF})); - g_signal_handler_unblock(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_CLICK)); - g_signal_handler_unblock(GTK_WIDGET( - nsgtk_window_get_layout( - nsgtk_scaffolding_top_level(list))), - nsgtk_window_get_signalhandler( - nsgtk_scaffolding_top_level(list), - NSGTK_WINDOW_SIGNAL_REDRAW)); - if ((gui_window_get_browser_window(nsgtk_scaffolding_top_level( - list))->current_content != NULL) && - (content_get_url(gui_window_get_browser_window( - nsgtk_scaffolding_top_level(list))-> - current_content) != NULL)) - browser_window_refresh_url_bar( - gui_window_get_browser_window( - nsgtk_scaffolding_top_level(list)), - content_get_url( - gui_window_get_browser_window( - nsgtk_scaffolding_top_level(list))-> - current_content), - gui_window_get_browser_window( - nsgtk_scaffolding_top_level(list))-> - frag_id); - - if (list != g) - gtk_widget_set_sensitive(GTK_WIDGET( - nsgtk_scaffolding_window(list)), TRUE); - free(theme); - list = nsgtk_scaffolding_iterate(list); - } - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), - TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), - TRUE); - /* update favicon etc */ - nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g)); - if (search_web_ico()) - gui_window_set_search_ico(search_web_ico()); -} - -/** - * callback function to iterate toolbar's widgets - */ -void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), widget); -} - -/** - * add item to toolbar - * \param g the scaffolding whose toolbar an item is added to - * \param i the location in the toolbar - * the function should be called, when multiple items are being added, - * in ascending order - */ -void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i, - struct nsgtk_theme *theme) -{ - int q; - for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) - if (nsgtk_scaffolding_button(g, q)->location == i) { - nsgtk_scaffolding_button(g, q)->button = GTK_TOOL_ITEM( - nsgtk_toolbar_make_widget(g, q, - theme)); - gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), - nsgtk_scaffolding_button(g, q)->button, - i); - break; - } -} - -/** - * physically add widgets to store window - */ -bool nsgtk_toolbar_add_store_widget(GtkWidget *widget) -{ - if (window->numberh >= NSGTK_STORE_WIDTH) { - window->currentbar = gtk_toolbar_new(); - if (window->currentbar == NULL) { - warn_user("NoMemory", 0); - return false; - } - gtk_toolbar_set_style(GTK_TOOLBAR(window->currentbar), - GTK_TOOLBAR_BOTH); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(window->currentbar), - GTK_ICON_SIZE_LARGE_TOOLBAR); - gtk_box_pack_start(GTK_BOX(window->widgetvbox), - window->currentbar, FALSE, FALSE, 0); - window->numberh = 0; - } - gtk_widget_set_size_request(widget, NSGTK_BUTTON_WIDTH, - NSGTK_BUTTON_HEIGHT); - gtk_toolbar_insert(GTK_TOOLBAR(window->currentbar), GTK_TOOL_ITEM( - widget), window->numberh++); - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(widget), TRUE); - gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &entry, 1, - GDK_ACTION_COPY); - gtk_widget_show_all(window->window); - return true; -} - -/** - * called when a widget is dropped onto the toolbar - */ -gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *gdc, gint x, - gint y, guint time, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g), - x, y); - int q, i; - if (window->currentbutton == -1) - return TRUE; - struct nsgtk_theme *theme = - nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); - if (theme == NULL) { - warn_user(messages_get("NoMemory"), 0); - return TRUE; - } - if (nsgtk_scaffolding_button(g, window->currentbutton)->location - != -1) { - /* widget was already in the toolbar; so replace */ - if (nsgtk_scaffolding_button(g, window->currentbutton)-> - location < ind) - ind--; - gtk_container_remove(GTK_CONTAINER( - nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button)); - /* 'move' all widgets further right than the original location, - * one place to the left in logical schema */ - for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> - location + 1; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location--; - } - nsgtk_scaffolding_button(g, window->currentbutton)-> - location = -1; - } - nsgtk_scaffolding_button(g, window->currentbutton)->button = - GTK_TOOL_ITEM(nsgtk_toolbar_make_widget(g, - window->currentbutton, theme)); - free(theme); - if (nsgtk_scaffolding_button(g, window->currentbutton)->button - == NULL) { - warn_user("NoMemory", 0); - return TRUE; - } - /* update logical schema */ - nsgtk_scaffolding_reset_offset(g); - /* 'move' all widgets further right than the new location, one place to - * the right in logical schema */ - for (i = PLACEHOLDER_BUTTON - 1; i >= ind; i--) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location++; - } - nsgtk_scaffolding_button(g, window->currentbutton)->location = ind; - - /* complete action */ - gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), - nsgtk_scaffolding_button(g, - window->currentbutton)->button, ind); - gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( - nsgtk_scaffolding_button(g, - window->currentbutton)->button), TRUE); - gtk_drag_source_set(GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button), - GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY); - nsgtk_toolbar_temp_connect(g, window->currentbutton); - gtk_widget_show_all(GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button)); - window->currentbutton = -1; - return TRUE; -} - -/** - * connected to toolbutton drop; perhaps one day it'll work properly so it may - * replace the global current_button - */ - -gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, GtkSelectionData *selection, guint info, - guint time, gpointer data) -{ - return FALSE; -} - -/** - * called when a widget is dropped onto the store window - */ -gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, guint time, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - int q, i; - - if ((window->fromstore) || (window->currentbutton == -1)) { - window->currentbutton = -1; - return FALSE; - } - if (nsgtk_scaffolding_button(g, window->currentbutton)->location - != -1) { - /* 'move' all widgets further right, one place to the left - * in logical schema */ - for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> - location + 1; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - nsgtk_scaffolding_button(g, q)->location--; - } - gtk_container_remove(GTK_CONTAINER( - nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( - nsgtk_scaffolding_button(g, - window->currentbutton)->button)); - nsgtk_scaffolding_button(g, window->currentbutton)->location - = -1; - } - window->currentbutton = -1; - gtk_drag_finish(gdc, TRUE, TRUE, time); - return FALSE; -} -/** - * called when hovering an item above the toolbar - */ -gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x, - gint y, guint time, gpointer data) -{ - nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; - GtkToolItem *item = gtk_tool_button_new(NULL, NULL); - if (item != NULL) - gtk_toolbar_set_drop_highlight_item( - nsgtk_scaffolding_toolbar(g), - GTK_TOOL_ITEM(item), - gtk_toolbar_get_drop_index( - nsgtk_scaffolding_toolbar(g), x, y)); - return FALSE; -} - -/** - * called when hovering above the store - */ -gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, - gint x, gint y, guint time, gpointer data) -{ - return FALSE; -} -/** - * called when hovering stops - */ -void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time, - gpointer data) -{ - gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0); -} - -/** - * widget factory for creation of toolbar item widgets - * \param g the reference scaffolding - * \param i the id of the widget - * \param theme the theme to make the widgets from - */ -GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g, - nsgtk_toolbar_button i, struct nsgtk_theme *theme) -{ - switch(i) { - -/* gtk_tool_button_new() accepts NULL args */ -#define MAKE_STOCKBUTTON(p, q) case p##_BUTTON: {\ - GtkStockItem item;\ - char *label = NULL;\ - gtk_stock_lookup(#q, &item);\ - if (item.label != NULL)\ - label = remove_underscores(item.label, false);\ - GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\ - theme->image[p##_BUTTON]), label));\ - if (label != NULL) {\ - free(label);\ - label = NULL;\ - }\ - return w;\ - } - - MAKE_STOCKBUTTON(HOME, gtk-home) - MAKE_STOCKBUTTON(BACK, gtk-go-back) - MAKE_STOCKBUTTON(FORWARD, gtk-go-forward) - MAKE_STOCKBUTTON(STOP, gtk-stop) - MAKE_STOCKBUTTON(RELOAD, gtk-refresh) -#undef MAKE_STOCKBUTTON - case HISTORY_BUTTON: - return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - theme->image[HISTORY_BUTTON]), "")); - case URL_BAR_ITEM: { - char imagefile[strlen(res_dir_location) + SLEN("favicon.png") - + 1]; - sprintf(imagefile, "%sfavicon.png", res_dir_location); - GtkWidget *image = GTK_WIDGET(gtk_image_new_from_file( - imagefile)); - GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new()); - GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); - - if ((entry == NULL) || (w == NULL)) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - - if (image != NULL) - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry), - SEXY_ICON_ENTRY_PRIMARY, - GTK_IMAGE(image)); - - gtk_container_add(GTK_CONTAINER(w), entry); - gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE); - return w; - } - case THROBBER_ITEM: { - if (edit_mode) - return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - gtk_image_new_from_pixbuf( - nsgtk_throbber->framedata[0])), - "[throbber]")); - if ((nsgtk_throbber == NULL) || (nsgtk_throbber->framedata == - NULL) || (nsgtk_throbber->framedata[0] == - NULL)) - return NULL; - GtkWidget *image = GTK_WIDGET(gtk_image_new_from_pixbuf( - nsgtk_throbber->framedata[0])); - GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); - GtkWidget *al = GTK_WIDGET(gtk_alignment_new(0.5, 0.5, 1, 1)); - if ((w == NULL) || (al == NULL)) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - gtk_alignment_set_padding(GTK_ALIGNMENT(al), 0, 0, 3, 3); - if (image != NULL) - gtk_container_add(GTK_CONTAINER(al), image); - gtk_container_add(GTK_CONTAINER(w), al); - return w; - } - case WEBSEARCH_ITEM: { - if (edit_mode) - return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( - gtk_image_new_from_stock("gtk-find", - GTK_ICON_SIZE_LARGE_TOOLBAR)), - "[websearch]")); - GtkWidget *image = GTK_WIDGET(gtk_image_new_from_stock( - "gtk-info", GTK_ICON_SIZE_LARGE_TOOLBAR)); - GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new()); - GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); - - if ((entry == NULL) || (w == NULL)) { - warn_user(messages_get("NoMemory"), 0); - return NULL; - } - - gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, - -1); - if (image != NULL) - sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry), - SEXY_ICON_ENTRY_PRIMARY, - GTK_IMAGE(image)); - - gtk_container_add(GTK_CONTAINER(w), entry); - return w; - } - -/* gtk_tool_button_new accepts NULL args */ -#define MAKE_MENUBUTTON(p, q) case p##_BUTTON: {\ - char *label = NULL;\ - label = remove_underscores(messages_get(#q), false);\ - GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\ - theme->image[p##_BUTTON]), label));\ - if (label != NULL)\ - free(label);\ - return w;\ - } - - MAKE_MENUBUTTON(NEWWINDOW, gtkNewWindow) - MAKE_MENUBUTTON(NEWTAB, gtkNewTab) - MAKE_MENUBUTTON(OPENFILE, gtkOpenFile) - MAKE_MENUBUTTON(CLOSETAB, gtkCloseTab) - MAKE_MENUBUTTON(CLOSEWINDOW, gtkCloseWindow) - MAKE_MENUBUTTON(SAVEPAGE, gtkSavePage) - MAKE_MENUBUTTON(PRINTPREVIEW, gtkPrintPreview) - MAKE_MENUBUTTON(PRINT, gtkPrint) - MAKE_MENUBUTTON(QUIT, gtkQuitMenu) - MAKE_MENUBUTTON(CUT, gtkCut) - MAKE_MENUBUTTON(COPY, gtkCopy) - MAKE_MENUBUTTON(PASTE, gtkPaste) - MAKE_MENUBUTTON(DELETE, gtkDelete) - MAKE_MENUBUTTON(SELECTALL, gtkSelectAll) - MAKE_MENUBUTTON(PREFERENCES, gtkPreferences) - MAKE_MENUBUTTON(ZOOMPLUS, gtkZoomPlus) - MAKE_MENUBUTTON(ZOOMMINUS, gtkZoomMinus) - MAKE_MENUBUTTON(ZOOMNORMAL, gtkZoomNormal) - MAKE_MENUBUTTON(FULLSCREEN, gtkFullScreen) - MAKE_MENUBUTTON(VIEWSOURCE, gtkViewSource) - MAKE_MENUBUTTON(CONTENTS, gtkContents) - MAKE_MENUBUTTON(ABOUT, gtkAbout) - MAKE_MENUBUTTON(PDF, gtkPDF) - MAKE_MENUBUTTON(PLAINTEXT, gtkPlainText) - MAKE_MENUBUTTON(DRAWFILE, gtkDrawFile) - MAKE_MENUBUTTON(POSTSCRIPT, gtkPostScript) - MAKE_MENUBUTTON(FIND, gtkFind) - MAKE_MENUBUTTON(DOWNLOADS, gtkDownloads) - MAKE_MENUBUTTON(SAVEWINDOWSIZE, gtkSaveWindowSize) - MAKE_MENUBUTTON(TOGGLEDEBUGGING, gtkToggleDebugging) - MAKE_MENUBUTTON(SAVEBOXTREE, gtkSaveBoxTree) - MAKE_MENUBUTTON(SAVEDOMTREE, gtkSaveDomTree) - MAKE_MENUBUTTON(LOCALHISTORY, gtkLocalHistory) - MAKE_MENUBUTTON(GLOBALHISTORY, gtkGlobalHistory) - MAKE_MENUBUTTON(ADDBOOKMARKS, gtkAddBookMarks) - MAKE_MENUBUTTON(SHOWBOOKMARKS, gtkShowBookMarks) - MAKE_MENUBUTTON(SHOWCOOKIES, gtkShowCookies) - MAKE_MENUBUTTON(OPENLOCATION, gtkOpenLocation) - MAKE_MENUBUTTON(NEXTTAB, gtkNextTab) - MAKE_MENUBUTTON(PREVTAB, gtkPrevTab) - MAKE_MENUBUTTON(GUIDE, gtkGuide) - MAKE_MENUBUTTON(INFO, gtkUserInformation) - default: - return NULL; -#undef MAKE_MENUBUTTON - } -} - -/** - * \return toolbar item id when a widget is an element of the scaffolding - * else -1 - */ -int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, nsgtk_scaffolding *g) -{ - int i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - if ((nsgtk_scaffolding_button(g, i)->location != -1) - && (widget == GTK_WIDGET( - nsgtk_scaffolding_button(g, i)->button))) { - return i; - } - } - return -1; -} - -/** - * \return toolbar item id from location when there is an item at that logical - * location; else -1 - */ -nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(nsgtk_scaffolding *g, - int i) -{ - int q; - for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) - if (nsgtk_scaffolding_button(g, q)->location == i) - return q; - return -1; -} - -/** - * connect 'normal' handlers to toolbar buttons - */ - -void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g) -{ - int q, i; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - q = nsgtk_toolbar_get_id_at_location(g, i); - if (q == -1) - continue; - if (nsgtk_scaffolding_button(g, q)->button != NULL) - g_signal_connect( - nsgtk_scaffolding_button(g, q)->button, - "size-allocate", G_CALLBACK( - nsgtk_scaffolding_toolbar_size_allocate - ), g); - nsgtk_toolbar_set_handler(g, q); - } -} - -/** - * add handlers to factory widgets - * \param g the scaffolding to attach handlers to - * \param i the toolbar item id - */ -void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, nsgtk_toolbar_button i) -{ - switch(i){ - case URL_BAR_ITEM: - nsgtk_scaffolding_update_url_bar_ref(g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), - "activate", G_CALLBACK( - nsgtk_window_url_activate_event), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), - "changed", G_CALLBACK( - nsgtk_window_url_changed), g); - break; - case THROBBER_ITEM: - nsgtk_scaffolding_update_throbber_ref(g); - break; - case WEBSEARCH_ITEM: - nsgtk_scaffolding_update_websearch_ref(g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), - "activate", G_CALLBACK( - nsgtk_websearch_activate), g); - g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), - "button-press-event", G_CALLBACK( - nsgtk_websearch_clear), g); - break; - default: - if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) && - (nsgtk_scaffolding_button(g, i)->button - != NULL)) - g_signal_connect(nsgtk_scaffolding_button(g, i)-> - button, "clicked", - G_CALLBACK(nsgtk_scaffolding_button(g, - i)->bhandler), g); - break; - } -} - -#define DATAHANDLER(p, q, r)\ -gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ - *cont, GtkSelectionData *selection, guint info, guint time,\ - gpointer data)\ -{\ - r->currentbutton = q##_BUTTON;\ - r->fromstore = true;\ - return TRUE;\ -}\ -gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ - GdkDragContext *cont, GtkSelectionData *selection, guint info,\ - guint time, gpointer data)\ -{\ - r->currentbutton = q##_BUTTON;\ - r->fromstore = false;\ - return TRUE;\ -} - -DATAHANDLER(home, HOME, window) -DATAHANDLER(forward, FORWARD, window) -DATAHANDLER(back, BACK, window) -DATAHANDLER(stop, STOP, window) -DATAHANDLER(reload, RELOAD, window) -DATAHANDLER(history, HISTORY, window) -DATAHANDLER(newwindow, NEWWINDOW, window) -DATAHANDLER(newtab, NEWTAB, window) -DATAHANDLER(openfile, OPENFILE, window) -DATAHANDLER(closetab, CLOSETAB, window) -DATAHANDLER(closewindow, CLOSEWINDOW, window) -DATAHANDLER(savepage, SAVEPAGE, window) -DATAHANDLER(printpreview, PRINTPREVIEW, window) -DATAHANDLER(print, PRINT, window) -DATAHANDLER(quit, QUIT, window) -DATAHANDLER(cut, CUT, window) -DATAHANDLER(copy, COPY, window) -DATAHANDLER(paste, PASTE, window) -DATAHANDLER(delete, DELETE, window) -DATAHANDLER(selectall, SELECTALL, window) -DATAHANDLER(preferences, PREFERENCES, window) -DATAHANDLER(zoomplus, ZOOMPLUS, window) -DATAHANDLER(zoomminus, ZOOMMINUS, window) -DATAHANDLER(zoomnormal, ZOOMNORMAL, window) -DATAHANDLER(fullscreen, FULLSCREEN, window) -DATAHANDLER(viewsource, VIEWSOURCE, window) -DATAHANDLER(contents, CONTENTS, window) -DATAHANDLER(about, ABOUT, window) -DATAHANDLER(pdf, PDF, window) -DATAHANDLER(plaintext, PLAINTEXT, window) -DATAHANDLER(drawfile, DRAWFILE, window) -DATAHANDLER(postscript, POSTSCRIPT, window) -DATAHANDLER(find, FIND, window) -DATAHANDLER(downloads, DOWNLOADS, window) -DATAHANDLER(savewindowsize, SAVEWINDOWSIZE, window) -DATAHANDLER(toggledebugging, TOGGLEDEBUGGING, window) -DATAHANDLER(saveboxtree, SAVEBOXTREE, window) -DATAHANDLER(savedomtree, SAVEDOMTREE, window) -DATAHANDLER(localhistory, LOCALHISTORY, window) -DATAHANDLER(globalhistory, GLOBALHISTORY, window) -DATAHANDLER(addbookmarks, ADDBOOKMARKS, window) -DATAHANDLER(showbookmarks, SHOWBOOKMARKS, window) -DATAHANDLER(showcookies, SHOWCOOKIES, window) -DATAHANDLER(openlocation, OPENLOCATION, window) -DATAHANDLER(nexttab, NEXTTAB, window) -DATAHANDLER(prevtab, PREVTAB, window) -DATAHANDLER(guide, GUIDE, window) -DATAHANDLER(info, INFO, window) -#undef DATAHANDLER -#define DATAHANDLER(p, q, r)\ -gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ - *cont, GtkSelectionData *selection, guint info, guint time,\ - gpointer data)\ -{\ - r->currentbutton = q##_ITEM;\ - r->fromstore = true;\ - return TRUE;\ -}\ -gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ - GdkDragContext *cont, GtkSelectionData *selection, guint info,\ - guint time, gpointer data)\ -{\ - r->currentbutton = q##_ITEM;\ - r->fromstore = false;\ - return TRUE;\ -} - -DATAHANDLER(throbber, THROBBER, window) -DATAHANDLER(websearch, WEBSEARCH, window) -#undef DATAHANDLER - -/** - * connect temporary handler for toolbar edit events - */ -void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, nsgtk_toolbar_button i) -{ - if ((i == URL_BAR_ITEM) || - (nsgtk_scaffolding_button(g, i)->button == NULL) || - (nsgtk_scaffolding_button(g, i)->dataminus == NULL)) - return; - g_signal_connect(nsgtk_scaffolding_button(g, i)->button, - "drag-data-get", G_CALLBACK(nsgtk_scaffolding_button( - g, i)->dataminus), g); -} - -/** - * load toolbar settings from file; file is a set of fields arranged as - * ;|;| etc - */ -void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g) -{ - int i, ii; - char *val; - char buffer[SLEN("11;|") * 2 * PLACEHOLDER_BUTTON]; /* numbers 0-99 */ - buffer[0] = '\0'; - char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_scaffolding_button(g, i)->location = - (i <= THROBBER_ITEM) ? i : -1; - FILE *f = fopen(toolbar_indices_file_location, "r"); - if (f == NULL) { - warn_user(messages_get("gtkFileError"), - toolbar_indices_file_location); - return; - } - val = fgets(buffer, sizeof buffer, f); - if (val == NULL) - LOG(("empty read toolbar settings")); - fclose(f); - i = BACK_BUTTON; - ii = BACK_BUTTON; - buffer1 = strtok_r(buffer, "|", &ptr); - while (buffer1 != NULL) { - subbuffer = strtok_r(buffer1, ";", &pter); - i = atoi(subbuffer); - subbuffer = strtok_r(NULL, ";", &pter); - ii = atoi(subbuffer); - if ((i >= BACK_BUTTON) && (i < PLACEHOLDER_BUTTON) && - (ii >= -1) && (ii < PLACEHOLDER_BUTTON)) { - nsgtk_scaffolding_button(g, i)->location = ii; - } - buffer1 = strtok_r(NULL, "|", &ptr); - } -} - -/** - * cast toolbar settings to all scaffoldings referenced from the global linked - * list of gui_windows - */ -void nsgtk_toolbar_cast(nsgtk_scaffolding *g) -{ - int i; - nsgtk_scaffolding *list = scaf_list; - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - window->buttonlocations[i] = - ((nsgtk_scaffolding_button(g, i)->location - >= -1) && - (nsgtk_scaffolding_button(g, i)->location - < PLACEHOLDER_BUTTON)) ? - nsgtk_scaffolding_button(g, i)->location : -1; - while (list) { - if (list != g) - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) - nsgtk_scaffolding_button(list, i)->location = - window->buttonlocations[i]; - list = nsgtk_scaffolding_iterate(list); - } -} - -/** - * save toolbar settings to file - */ -void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g) -{ - int i; - FILE *f = fopen(toolbar_indices_file_location, "w"); - if (f == NULL){ - warn_user("gtkFileError", toolbar_indices_file_location); - return; - } - for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { - fprintf(f, "%d;%d|", i, nsgtk_scaffolding_button(g, i)->location); - } - fclose(f); -} - diff --git a/gtk/gtk_toolbar.h b/gtk/gtk_toolbar.h deleted file mode 100644 index 7d483578b..000000000 --- a/gtk/gtk_toolbar.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2009 Mark Benjamin - * - * 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 . - */ - -#ifndef _NETSURF_GTK_TOOLBAR_H_ -#define _NETSURF_GTK_TOOLBAR_H_ - -#include -#include "gtk/gtk_scaffolding.h" - -void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g); -void nsgtk_toolbar_init(nsgtk_scaffolding *g); -void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g); -void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g); -void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g); -int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, 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(saveboxtree); -TOOLPROTO(savedomtree); -TOOLPROTO(contents); -TOOLPROTO(guide); -TOOLPROTO(info); -TOOLPROTO(about); -#undef TOOLPROTO - -#endif diff --git a/gtk/gtk_treeview.c b/gtk/gtk_treeview.c deleted file mode 100644 index c896fc7e6..000000000 --- a/gtk/gtk_treeview.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright 2004 Richard Wilson - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -/** \file - * Generic tree handling (implementation). - */ - -#include -#include -#include -#include -#include - -#include "desktop/tree.h" -#include "desktop/tree_url_node.h" -#include "desktop/plotters.h" -#include "gtk/gtk_gui.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_treeview.h" -#include "utils/log.h" -#include "utils/utils.h" - -struct nsgtk_treeview { - GtkWindow *window; - GtkScrolledWindow *scrolled; - GtkDrawingArea *drawing_area; - int mouse_pressed_x; - int mouse_pressed_y; - int last_x, last_y; - browser_mouse_state mouse_state; - struct tree *tree; -}; - -const char tree_directory_icon_name[] = "directory.png"; -const char tree_content_icon_name[] = "content.png"; - -void nsgtk_treeview_destroy(struct nsgtk_treeview *tv) -{ - tree_delete(tv->tree); - gtk_widget_destroy(GTK_WIDGET(tv->window)); - free(tv); -} - -struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv) -{ - return tv->tree; -} - -static void nsgtk_tree_redraw_request(int x, int y, int width, int height, void *data) -{ - struct nsgtk_treeview *tw = data; - - gtk_widget_queue_draw_area(GTK_WIDGET(tw->drawing_area), - x, y, width, height); -} - - -/** - * Updates the tree owner following a tree resize - * - * \param tree the tree to update the owner of - */ -static void nsgtk_tree_resized(struct tree *tree, int width, int height, void *data) -{ - struct nsgtk_treeview *tw = data; - - gtk_widget_set_size_request(GTK_WIDGET(tw->drawing_area), - width, height); - return; -} - -/** - * Translates a content_type to the name of a respective icon - * - * \param content_type content type - * \param buffer buffer for the icon name - */ -void tree_icon_name_from_content_type(char *buffer, content_type type) -{ - // TODO: design/acquire icons - switch (type) { - case CONTENT_HTML: - case CONTENT_TEXTPLAIN: - case CONTENT_CSS: -#if defined(WITH_MNG) || defined(WITH_PNG) - case CONTENT_PNG: -#endif -#ifdef WITH_MNG - case CONTENT_JNG: - case CONTENT_MNG: -#endif -#ifdef WITH_JPEG - case CONTENT_JPEG: -#endif -#ifdef WITH_GIF - case CONTENT_GIF: -#endif -#ifdef WITH_BMP - case CONTENT_BMP: - case CONTENT_ICO: -#endif -#ifdef WITH_SPRITE - case CONTENT_SPRITE: -#endif -#ifdef WITH_DRAW - case CONTENT_DRAW: -#endif -#ifdef WITH_ARTWORKS - case CONTENT_ARTWORKS: -#endif -#ifdef WITH_NS_SVG - case CONTENT_SVG: -#endif - default: - sprintf(buffer, tree_content_icon_name); - break; - } -} - -/** - * Scrolls the tree to make an element visible - * - * \param y Y coordinate of the element - * \param height height of the element - * \param data user data assigned to the tree on tree creation - */ -static void nsgtk_tree_scroll_visible(int y, int height, void *data) -{ - int y0, y1; - gdouble page; - struct nsgtk_treeview *tw = data; - GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled); - - assert(vadj); - - g_object_get(vadj, "page-size", &page, NULL); - - y0 = (int)(gtk_adjustment_get_value(vadj)); - y1 = y0 + page; - - 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); -} - - -/** - * Retrieves the dimensions of the window with the tree - * - * \param data user data assigned to the tree on tree creation - * \param width will be updated to window width if not NULL - * \param height will be updated to window height if not NULL - */ -static void nsgtk_tree_get_window_dimensions(int *width, int *height, void *data) -{ - struct nsgtk_treeview *tw = data; - GtkAdjustment *vadj; - GtkAdjustment *hadj; - gdouble page; - - if (width != NULL) { - hadj = gtk_scrolled_window_get_hadjustment(tw->scrolled); - g_object_get(hadj, "page-size", &page, NULL); - *width = page; - } - - if (height != NULL) { - vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled); - g_object_get(vadj, "page-size", &page, NULL); - *height = page; - } -} - -/* signal handler functions for a tree window */ -gboolean nsgtk_tree_window_expose_event(GtkWidget *widget, - GdkEventExpose *event, gpointer g) -{ - struct tree *tree = (struct tree *) g; - int x, y, width, height; - - x = event->area.x; - y = event->area.y; - width = event->area.width; - height = event->area.height; - - current_widget = widget; - current_drawable = widget->window; - current_gc = gdk_gc_new(current_drawable); -#ifdef CAIRO_VERSION - current_cr = gdk_cairo_create(current_drawable); -#endif - plot = nsgtk_plotters; - nsgtk_plot_set_scale(1.0);current_widget = widget; - current_drawable = widget->window; - current_gc = gdk_gc_new(current_drawable); -#ifdef CAIRO_VERSION - current_cr = gdk_cairo_create(current_drawable); -#endif - plot = nsgtk_plotters; - nsgtk_plot_set_scale(1.0); - - tree_set_redraw(tree, true); - tree_draw(tree, 0, 0, x, y, width, height); - - current_widget = NULL; - g_object_unref(current_gc); -#ifdef CAIRO_VERSION - cairo_destroy(current_cr); -#endif - - return FALSE; -} - -void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g) -{ - struct nsgtk_treeview *tw = g; - struct tree *tree = tw->tree; - - if (tree != NULL) - tree_set_redraw(tree, false); -} - -gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget, - GdkEventButton *event, gpointer g) -{ - struct nsgtk_treeview *tw = g; - struct tree *tree = tw->tree; - - gtk_widget_grab_focus(GTK_WIDGET(tw->drawing_area)); - - - tw->mouse_pressed_x = event->x; - tw->mouse_pressed_y = event->y; - - if (event->type == GDK_2BUTTON_PRESS) - tw->mouse_state = BROWSER_MOUSE_DOUBLE_CLICK; - - switch (event->button) { - case 1: tw->mouse_state |= BROWSER_MOUSE_PRESS_1; break; - case 3: tw->mouse_state |= BROWSER_MOUSE_PRESS_2; break; - } - /* Handle the modifiers too */ - if (event->state & GDK_SHIFT_MASK) - tw->mouse_state |= BROWSER_MOUSE_MOD_1; - if (event->state & GDK_CONTROL_MASK) - tw->mouse_state |= BROWSER_MOUSE_MOD_2; - if (event->state & GDK_MOD1_MASK) - tw->mouse_state |= BROWSER_MOUSE_MOD_3; - - /* Record where we pressed, for use when determining whether to start - * a drag in motion notify events. */ - tw->last_x = event->x; - tw->last_y = event->y; - - tree_mouse_action(tree, tw->mouse_state, event->x, event->y); - - return TRUE; -} - -gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget, - GdkEventButton *event, gpointer g) -{ - bool shift = event->state & GDK_SHIFT_MASK; - bool ctrl = event->state & GDK_CONTROL_MASK; - bool alt = event->state & GDK_MOD1_MASK; - struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; - struct tree *tree = tw->tree; - - /* We consider only button 1 clicks as double clicks. - * 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 (tw->mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) { - - if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) - tw->mouse_state ^= BROWSER_MOUSE_PRESS_1 | - BROWSER_MOUSE_CLICK_1; - else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) - tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | - BROWSER_MOUSE_CLICK_2 | - BROWSER_MOUSE_DOUBLE_CLICK); - - } else if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) - tw->mouse_state ^= - (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); - else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) - tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | - BROWSER_MOUSE_CLICK_2); - - /* Handle modifiers being removed */ - if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) - tw->mouse_state ^= BROWSER_MOUSE_MOD_1; - if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) - tw->mouse_state ^= BROWSER_MOUSE_MOD_2; - if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) - tw->mouse_state ^= BROWSER_MOUSE_MOD_3; - - - if (tw->mouse_state & - (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 - | BROWSER_MOUSE_DOUBLE_CLICK)) - tree_mouse_action(tree, tw->mouse_state, - event->x, event->y); - else - tree_drag_end(tree, tw->mouse_state, - tw->mouse_pressed_x, - tw->mouse_pressed_y, - event->x, event->y); - - - tw->mouse_state = 0; - - - return TRUE; -} - -gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget, - GdkEventButton *event, gpointer g) -{ - bool shift = event->state & GDK_SHIFT_MASK; - bool ctrl = event->state & GDK_CONTROL_MASK; - bool alt = event->state & GDK_MOD1_MASK; - struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; - struct tree *tree = tw->tree; - - if ((abs(event->x - tw->last_x) < 5) && - (abs(event->y - tw->last_y) < 5)) { - /* Mouse hasn't moved far enough from press coordinate for this - * to be considered a drag. */ - return FALSE; - } else { - /* This is a drag, ensure it's always treated as such, even if - * we drag back over the press location */ - tw->last_x = INT_MIN; - tw->last_y = INT_MIN; - } - - /* Handle modifiers being removed */ - if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) - tw->mouse_state ^= BROWSER_MOUSE_MOD_1; - if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) - tw->mouse_state ^= BROWSER_MOUSE_MOD_2; - if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) - tw->mouse_state ^= BROWSER_MOUSE_MOD_3; - - if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) { - /* Start button 1 drag */ - tree_mouse_action(tree, BROWSER_MOUSE_DRAG_1, - tw->mouse_pressed_x, tw->mouse_pressed_y); - /* Replace PRESS with HOLDING and declare drag in progress */ - tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 | - BROWSER_MOUSE_HOLDING_1); - tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; - return TRUE; - } - else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2){ - /* Start button 2s drag */ - tree_mouse_action(tree, BROWSER_MOUSE_DRAG_2, - tw->mouse_pressed_x, tw->mouse_pressed_y); - /* Replace PRESS with HOLDING and declare drag in progress */ - tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | - BROWSER_MOUSE_HOLDING_2); - tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; - return TRUE; - } - - if (tw->mouse_state & (BROWSER_MOUSE_HOLDING_1 | - BROWSER_MOUSE_HOLDING_2)) - tree_mouse_action(tree, tw->mouse_state, event->x, - event->y); - - return TRUE; -} - - -gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event, - gpointer g) -{ - struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; - struct tree *tree = tw->tree; - uint32_t nskey; - double value; - GtkAdjustment *vscroll; - GtkAdjustment *hscroll; - GtkAdjustment *scroll = NULL; - gdouble hpage, vpage; - bool edited; - - nskey = gtk_gui_gdkkey_to_nskey(event); - - - vscroll = gtk_scrolled_window_get_vadjustment(tw->scrolled); - hscroll = gtk_scrolled_window_get_hadjustment(tw->scrolled); - g_object_get(vscroll, "page-size", &vpage, NULL); - g_object_get(hscroll, "page-size", &hpage, NULL); - - - edited = tree_is_edited(tree); - - switch (event->keyval) { - case GDK_Home: - case GDK_KP_Home: - if (edited) - break; - scroll = vscroll; - value = scroll->lower; - break; - - case GDK_End: - case GDK_KP_End: - if (edited) - break; - scroll = vscroll; - value = scroll->upper - vpage; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Left: - case GDK_KP_Left: - if (edited) - break; - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->step_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Up: - case GDK_KP_Up: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->step_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Right: - case GDK_KP_Right: - if (edited) - break; - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->step_increment; - if (value > scroll->upper - hpage) - value = scroll->upper - hpage; - break; - - case GDK_Down: - case GDK_KP_Down: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->step_increment; - if (value > scroll->upper - vpage) - value = scroll->upper - vpage; - break; - - case GDK_Page_Up: - case GDK_KP_Page_Up: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->page_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Page_Down: - case GDK_KP_Page_Down: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->page_increment; - if (value > scroll->upper - vpage) - value = scroll->upper - vpage; - break; - default: - tree_keypress(tree, nskey); - return TRUE; - } - - if (scroll != NULL) - gtk_adjustment_set_value(scroll, value); - - tree_keypress(tree, nskey); - - return TRUE; -} - -static const struct treeview_table nsgtk_tree_callbacks = { - .redraw_request = nsgtk_tree_redraw_request, - .resized = nsgtk_tree_resized, - .scroll_visible = nsgtk_tree_scroll_visible, - .get_window_dimensions = nsgtk_tree_get_window_dimensions -}; - -struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags, - GtkWindow *window, GtkScrolledWindow *scrolled, - GtkDrawingArea *drawing_area) -{ - struct nsgtk_treeview *tv; - - tv = malloc(sizeof(struct nsgtk_treeview)); - if (tv == NULL) { - LOG(("malloc failed")); - warn_user("NoMemory", 0); - return NULL; - } - - tv->window = window; - tv->scrolled = scrolled; - tv->drawing_area = drawing_area; - tv->tree = tree_create(flags, &nsgtk_tree_callbacks, tv); - tv->mouse_state = 0; - - gtk_widget_modify_bg(GTK_WIDGET(drawing_area), GTK_STATE_NORMAL, - &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - - CONNECT(drawing_area, "expose_event", - nsgtk_tree_window_expose_event, - tv->tree); - CONNECT(drawing_area, "button_press_event", - nsgtk_tree_window_button_press_event, - tv); - CONNECT(drawing_area, "button_release_event", - nsgtk_tree_window_button_release_event, - tv); - CONNECT(drawing_area, "motion_notify_event", - nsgtk_tree_window_motion_notify_event, - tv); - CONNECT(drawing_area, "key_press_event", - nsgtk_tree_window_keypress_event, - tv); - return tv; -} diff --git a/gtk/gtk_treeview.h b/gtk/gtk_treeview.h deleted file mode 100644 index c7520465e..000000000 --- a/gtk/gtk_treeview.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2004 Richard Wilson - * Copyright 2009 Paul Blokus - * - * 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 . - */ - -/** \file - * Generic tree handling. - */ - -#ifndef __NSGTK_TREEVIEW_H__ -#define __NSGTK_TREEVIEW_H__ - -#include "desktop/browser.h" - -/* defined in front end code */ -extern const char tree_directory_icon_name[]; -extern const char tree_content_icon_name[]; - -struct nsgtk_treeview; - -struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags, - GtkWindow *window, GtkScrolledWindow *scrolled, - GtkDrawingArea *drawing_area); -void nsgtk_treeview_destroy(struct nsgtk_treeview *tv); - -struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv); - -gboolean nsgtk_tree_window_expose_event(GtkWidget *, GdkEventExpose *, - gpointer g); -void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g); -gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget, - GdkEventButton *event, gpointer g); -gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget, - GdkEventButton *event, gpointer g); -gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget, - GdkEventButton *event, gpointer g); -gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event, - gpointer g); - -#endif /*__NSGTK_TREEVIEW_H__*/ diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c deleted file mode 100644 index a45faa595..000000000 --- a/gtk/gtk_window.c +++ /dev/null @@ -1,1121 +0,0 @@ -/* - * Copyright 2006 Daniel Silverstone - * Copyright 2006 Rob Kendrick - * - * 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 . - */ - -#include -#include -#include -#include "content/hlcache.h" -#include "gtk/gtk_window.h" -#include "desktop/browser.h" -#include "desktop/mouse.h" -#include "desktop/options.h" -#include "desktop/searchweb.h" -#include "desktop/textinput.h" -#include "desktop/selection.h" -#include "gtk/gtk_compat.h" -#include "gtk/gtk_gui.h" -#include "gtk/options.h" -#include "gtk/gtk_scaffolding.h" -#include "gtk/gtk_plotters.h" -#include "gtk/gtk_schedule.h" -#include "gtk/gtk_tabs.h" -#include "utils/log.h" -#include "utils/utils.h" -#include -#include - -struct gui_window { - /* All gui_window objects have an ultimate scaffold */ - nsgtk_scaffolding *scaffold; - /**< the gtk object containing menu, buttons, url bar, [tabs], - * drawing area, etc that may contain 1 -> several gui_windows */ - struct browser_window *bw; - /**< the 'content' window that is rendered in the gui_window*/ - - struct { - struct gui_window *gui; - struct box *box; - - gdouble pressed_x; - gdouble pressed_y; - gboolean waiting; - browser_mouse_state state; - } mouse; /**< contains mouse state / events */ - - int caretx, carety, careth; - /**< storage caret dimension / location for rendering */ - gui_pointer_shape current_pointer; - /**< storage caret shape for rendering */ - int last_x, last_y; - /**< storage caret location for rendering */ - - GtkLayout *layout; /**< display widget for this page or frame */ - GtkScrolledWindow *scrolledwindow; - /**< frames only; top level of gtk structure of gui_window */ - GtkWidget *tab; /**< the visible tab */ - GtkLabel *status_bar; - GtkPaned *paned; /**< statusbar/scrollbar paned */ - gulong signalhandler[NSGTK_WINDOW_SIGNAL_COUNT]; - /**< to allow disactivation / resume of normal window behaviour */ - struct gui_window *next, *prev; /**< list for eventual cleanup */ -}; - -struct gui_window *window_list = NULL; /**< first entry in win list*/ -int temp_open_background = -1; - - -static void nsgtk_gui_window_attach_child(struct gui_window *parent, - struct gui_window *child); -/* Methods which apply only to a gui_window */ -static gboolean nsgtk_window_expose_event(GtkWidget *, GdkEventExpose *, - gpointer); -static gboolean nsgtk_window_motion_notify_event(GtkWidget *, GdkEventMotion *, - gpointer); -static gboolean nsgtk_window_button_press_event(GtkWidget *, GdkEventButton *, - gpointer); -static gboolean nsgtk_window_button_release_event(GtkWidget *, GdkEventButton *, - gpointer); -static gboolean nsgtk_window_scroll_event(GtkWidget *, GdkEventScroll *, - gpointer); -static gboolean nsgtk_window_keypress_event(GtkWidget *, GdkEventKey *, - gpointer); -static gboolean nsgtk_window_size_allocate_event(GtkWidget *, GtkAllocation *, - gpointer); - -/* Other useful bits */ -static void nsgtk_redraw_caret(struct gui_window *g); - -static GdkCursor *nsgtk_create_menu_cursor(void); - -nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g) -{ - return g->scaffold; -} - -struct browser_window *gui_window_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 g->bw->scale; -} - -/* Create a gui_window */ -struct gui_window *gui_create_browser_window(struct browser_window *bw, - struct browser_window *clone, - bool new_tab) -{ - struct gui_window *g; /**< what we're creating to return */ - GtkPolicyType scrollpolicy; - - g = calloc(1, sizeof(*g)); - if (!g) { - warn_user("NoMemory", 0); - return 0; - } - - LOG(("Creating gui window %p for browser window %p", g, bw)); - - g->bw = bw; - g->paned = NULL; - g->mouse.state = 0; - g->current_pointer = GUI_POINTER_DEFAULT; - if (clone != NULL) - bw->scale = clone->scale; - else - bw->scale = (float) option_scale / 100; - - g->careth = 0; - - if (bw->parent != NULL) - /* Find our parent's scaffolding */ - g->scaffold = bw->parent->window->scaffold; - else if (new_tab) - g->scaffold = clone->window->scaffold; - else - /* Now construct and attach a scaffold */ - g->scaffold = nsgtk_new_scaffolding(g); - if (g->scaffold == NULL) { - warn_user("NoMemory", 0); - free(g); - return NULL; - } - - /* Construct our primary elements */ - if (bw->parent == NULL) { - /* top-level document (not a frame) => create a new tab */ - GladeXML *xml = glade_xml_new(glade_netsurf_file_location, "tabContents", NULL); - if (!xml) { - warn_user("MiscError", "Failed to create tab contents"); - free(g); - return 0; - } - - GtkWidget *tab_contents = glade_xml_get_widget(xml, "tabContents"); - g->layout = GTK_LAYOUT(glade_xml_get_widget(xml, "layout")); - g->status_bar = GTK_LABEL(glade_xml_get_widget(xml, "status_bar")); - g->paned = GTK_PANED(glade_xml_get_widget(xml, "hpaned1")); - - /* connect the scrollbars to the layout widget */ - gtk_layout_set_hadjustment(g->layout, - gtk_range_get_adjustment(GTK_RANGE( - glade_xml_get_widget(xml, "hscrollbar")))); - gtk_layout_set_vadjustment(g->layout, - gtk_range_get_adjustment(GTK_RANGE( - glade_xml_get_widget(xml, "vscrollbar")))); - - /* add the tab to the scaffold */ - bool tempback = true; - switch (temp_open_background) { - case -1: - tempback = !(option_focus_new); - break; - case 0: - tempback = false; - break; - case 1: - tempback = true; - break; - } - g_object_set_data(G_OBJECT(tab_contents), "gui_window", g); - nsgtk_tab_add(g, tab_contents, tempback); - - g_object_unref(xml); - - } else { - /* frame or iframe => create a child layout */ - g->layout = GTK_LAYOUT(gtk_layout_new(NULL, NULL)); - gtk_container_set_border_width(GTK_CONTAINER(g->layout), 0); - - g->scrolledwindow = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); - g_object_set_data(G_OBJECT(g->scrolledwindow), "gui_window", g); - gtk_container_add(GTK_CONTAINER(g->scrolledwindow), GTK_WIDGET(g->layout)); - gtk_scrolled_window_set_shadow_type(g->scrolledwindow, - GTK_SHADOW_NONE); - g->tab = NULL; - - /* Attach ourselves into our parent at the right point */ - nsgtk_gui_window_attach_child(bw->parent->window, g); - - gtk_widget_show(GTK_WIDGET(g->scrolledwindow)); - } - - switch(bw->scrolling) { - case SCROLLING_NO: - scrollpolicy = GTK_POLICY_NEVER; - break; - case SCROLLING_YES: - scrollpolicy = GTK_POLICY_ALWAYS; - break; - case SCROLLING_AUTO: - default: - scrollpolicy = GTK_POLICY_AUTOMATIC; - break; - } - - switch (bw->browser_window_type) { - case BROWSER_WINDOW_FRAMESET: - if (g->scrolledwindow) - gtk_scrolled_window_set_policy(g->scrolledwindow, - GTK_POLICY_NEVER, - GTK_POLICY_NEVER); - break; - case BROWSER_WINDOW_FRAME: - if (g->scrolledwindow) - gtk_scrolled_window_set_policy(g->scrolledwindow, - scrollpolicy, - scrollpolicy); - break; - case BROWSER_WINDOW_NORMAL: - if (g->scrolledwindow) - gtk_scrolled_window_set_policy(g->scrolledwindow, - scrollpolicy, - scrollpolicy); - break; - case BROWSER_WINDOW_IFRAME: - if (g->scrolledwindow) - gtk_scrolled_window_set_policy(g->scrolledwindow, - scrollpolicy, - scrollpolicy); - break; - } - - /* Attach ourselves to the list (push_top) */ - if (window_list) - window_list->prev = g; - g->next = window_list; - g->prev = NULL; - window_list = g; - - /* set the events we're interested in receiving from the browser's - * drawing area. - */ - gtk_widget_add_events(GTK_WIDGET(g->layout), - GDK_EXPOSURE_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_SCROLL_MASK); - nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); - - /* set the default background colour of the drawing area to white. */ - gtk_widget_modify_bg(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, - &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); - -#define CONNECT(obj, sig, callback, ptr) \ - g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) - g->signalhandler[NSGTK_WINDOW_SIGNAL_REDRAW] = - CONNECT(g->layout, "expose_event", - nsgtk_window_expose_event, g); - CONNECT(g->layout, "motion_notify_event", - nsgtk_window_motion_notify_event, g); - g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = - CONNECT(g->layout, "button_press_event", - nsgtk_window_button_press_event, g); - CONNECT(g->layout, "button_release_event", - nsgtk_window_button_release_event, g); - CONNECT(g->layout, "key_press_event", - nsgtk_window_keypress_event, g); - CONNECT(g->layout, "size_allocate", - nsgtk_window_size_allocate_event, g); - CONNECT(g->layout, "scroll_event", - nsgtk_window_scroll_event, g); - return g; -} - -static void nsgtk_gui_window_attach_child(struct gui_window *parent, - struct gui_window *child) -{ - /* Attach the child gui_window (frame) into the parent. - * It will be resized later on. - */ - GtkLayout *parent_layout = parent->layout; - GtkWidget *child_widget = GTK_WIDGET(child->scrolledwindow); - gtk_layout_put(parent_layout, child_widget, 0, 0); -} - -void gui_window_position_frame(struct gui_window *g, int x0, int y0, int x1, int y1) -{ - /* g is a child frame, we need to place it relative to its parent */ - GtkWidget *w = GTK_WIDGET(g->scrolledwindow); - GtkLayout *f = g->bw->parent->window->layout; - int width = x1 - x0 + 2, height = y1 - y0 + 2; - assert(w); - assert(f); - - if (width < 1) - width = 1; - if (height < 1) - height = 1; - - LOG(("%s: %d,%d %dx%d", g->bw->name, x0, y0, width, height)); - - /* if the window has not changed position or size, do not bother - * moving/resising it. - */ - - LOG((" current: %d,%d %dx%d", - w->allocation.x, w->allocation.y, - w->allocation.width, w->allocation.height)); - - if (w->allocation.x != x0 || w->allocation.y != y0 || - w->allocation.width != width || - w->allocation.height != height) { - LOG((" frame has moved/resized.")); - gtk_layout_move(f, w, x0, y0); - gtk_widget_set_size_request(w, width, height); - } -} - -gboolean nsgtk_window_expose_event(GtkWidget *widget, - GdkEventExpose *event, gpointer data) -{ - struct gui_window *g = data; - hlcache_handle *c; - float scale = g->bw->scale; - - assert(g); - assert(g->bw); - - struct gui_window *z; - for (z = window_list; z && z != g; z = z->next) - continue; - assert(z); - assert(GTK_WIDGET(g->layout) == widget); - - c = g->bw->current_content; - if (c == NULL) - return FALSE; - - /* HTML rendering handles scale itself */ - if (content_get_type(c) == CONTENT_HTML) - scale = 1; - - current_widget = (GtkWidget *)g->layout; - current_drawable = g->layout->bin_window; - current_gc = gdk_gc_new(current_drawable); -#ifdef CAIRO_VERSION - current_cr = gdk_cairo_create(current_drawable); -#endif - - plot = nsgtk_plotters; - nsgtk_plot_set_scale(g->bw->scale); - current_redraw_browser = g->bw; - - plot.clip(event->area.x, - event->area.y, - event->area.x + event->area.width, - event->area.y + event->area.height); - - content_redraw(c, 0, 0, - content_get_width(c) * scale, - content_get_height(c) * scale, - event->area.x, - event->area.y, - event->area.x + event->area.width, - event->area.y + event->area.height, - g->bw->scale, 0xFFFFFF); - current_redraw_browser = NULL; - - if (g->careth != 0) - nsgtk_plot_caret(g->caretx, g->carety, g->careth); - - current_widget = NULL; - g_object_unref(current_gc); -#ifdef CAIRO_VERSION - cairo_destroy(current_cr); -#endif - - return FALSE; -} - -gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, - GdkEventMotion *event, gpointer data) -{ - struct gui_window *g = data; - bool shift = event->state & GDK_SHIFT_MASK; - bool ctrl = event->state & GDK_CONTROL_MASK; - - if ((abs(event->x - g->last_x) < 5) && - (abs(event->y - g->last_y) < 5)) { - /* Mouse hasn't moved far enough from press coordinate for this - * to be considered a drag. */ - return FALSE; - } else { - /* This is a drag, ensure it's always treated as such, even if - * we drag back over the press location */ - g->last_x = INT_MIN; - g->last_y = INT_MIN; - } - - if (g->mouse.state & BROWSER_MOUSE_PRESS_1){ - /* Start button 1 drag */ - browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, - g->mouse.pressed_x, g->mouse.pressed_y); - /* Replace PRESS with HOLDING and declare drag in progress */ - g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | - BROWSER_MOUSE_HOLDING_1); - g->mouse.state |= BROWSER_MOUSE_DRAG_ON; - } - else if (g->mouse.state & BROWSER_MOUSE_PRESS_2){ - /* Start button 2 drag */ - browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, - g->mouse.pressed_x, g->mouse.pressed_y); - /* Replace PRESS with HOLDING and declare drag in progress */ - g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | - BROWSER_MOUSE_HOLDING_2); - g->mouse.state |= BROWSER_MOUSE_DRAG_ON; - } - /* Handle modifiers being removed */ - if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) - g->mouse.state ^= BROWSER_MOUSE_MOD_1; - 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 / g->bw->scale, event->y / g->bw->scale); - - return TRUE; -} - -gboolean nsgtk_window_button_press_event(GtkWidget *widget, - GdkEventButton *event, gpointer data) -{ - struct gui_window *g = data; - - gtk_widget_grab_focus(GTK_WIDGET(g->layout)); - gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( - g->scaffold)->window)); - - g->mouse.pressed_x = event->x / g->bw->scale; - g->mouse.pressed_y = event->y / g->bw->scale; - - switch (event->button) { - case 1: - /* Left button, usually. - * Pass to core as BUTTON 1. */ - g->mouse.state = BROWSER_MOUSE_PRESS_1; - break; - case 2: - /* Middle button, usually. - * Pass to core as BUTTON 2 */ - g->mouse.state = BROWSER_MOUSE_PRESS_2; - break; - case 3: - /* Right button, usually. - * Front end action button -- context menu. */ - browser_window_remove_caret(g->bw); - nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, - g->mouse.pressed_y); - return TRUE; - default: - return FALSE; - } - /* Handle the modifiers too */ - if (event->state & GDK_SHIFT_MASK) - g->mouse.state |= BROWSER_MOUSE_MOD_1; - if (event->state & GDK_CONTROL_MASK) - g->mouse.state |= BROWSER_MOUSE_MOD_2; - - /* Record where we pressed, for use when determining whether to start - * a drag in motion notify events. */ - 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); - - return TRUE; -} - -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; - - /* 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) - g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); - 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) - g->mouse.state ^= BROWSER_MOUSE_MOD_1; - if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) - 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 / g->bw->scale, - event->y / g->bw->scale); - else - browser_window_mouse_drag_end(g->bw, 0, event->x / g->bw->scale, - event->y / g->bw->scale); - - g->mouse.state = 0; - return TRUE; -} - -gboolean nsgtk_window_scroll_event(GtkWidget *widget, - GdkEventScroll *event, gpointer data) -{ - struct gui_window *g = data; - double value; - GtkAdjustment *vscroll = gtk_layout_get_vadjustment(g->layout); - GtkAdjustment *hscroll = gtk_layout_get_hadjustment(g->layout); - GtkAdjustment *scroll; - const GtkAllocation *const alloc = - >K_WIDGET(g->layout)->allocation; - - switch (event->direction) { - case GDK_SCROLL_LEFT: - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) - - (scroll->step_increment * 2); - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_SCROLL_UP: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) - - (scroll->step_increment * 2); - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_SCROLL_RIGHT: - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) + - (scroll->step_increment * 2); - if (value > scroll->upper - alloc->width) - value = scroll->upper - alloc->width; - break; - - case GDK_SCROLL_DOWN: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) + - (scroll->step_increment * 2); - if (value > scroll->upper - alloc->height) - value = scroll->upper - alloc->height; - break; - default: - return TRUE; - } - - gtk_adjustment_set_value(scroll, value); - - return TRUE; -} - -gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, - gpointer data) -{ - struct gui_window *g = data; - uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); - if (browser_window_key_press(g->bw, nskey)) - return TRUE; - - if ((event->state & 0x7) == 0) { - double value; - GtkAdjustment *vscroll = gtk_layout_get_vadjustment(g->layout); - - GtkAdjustment *hscroll = gtk_layout_get_hadjustment(g->layout); - - GtkAdjustment *scroll; - - const GtkAllocation *const alloc = - >K_WIDGET(g->layout)->allocation; - - switch (event->keyval) { - default: - return TRUE; - - case GDK_Home: - case GDK_KP_Home: - scroll = vscroll; - value = scroll->lower; - break; - - case GDK_End: - case GDK_KP_End: - scroll = vscroll; - value = scroll->upper - alloc->height; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Left: - case GDK_KP_Left: - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->step_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Up: - case GDK_KP_Up: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->step_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Right: - case GDK_KP_Right: - scroll = hscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->step_increment; - if (value > scroll->upper - alloc->width) - value = scroll->upper - alloc->width; - break; - - case GDK_Down: - case GDK_KP_Down: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->step_increment; - if (value > scroll->upper - alloc->height) - value = scroll->upper - alloc->height; - break; - - case GDK_Page_Up: - case GDK_KP_Page_Up: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) - - scroll->page_increment; - if (value < scroll->lower) - value = scroll->lower; - break; - - case GDK_Page_Down: - case GDK_KP_Page_Down: - scroll = vscroll; - value = gtk_adjustment_get_value(scroll) + - scroll->page_increment; - if (value > scroll->upper - alloc->height) - value = scroll->upper - alloc->height; - break; - } - - gtk_adjustment_set_value(scroll, value); - } - - return TRUE; -} - -gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, - GtkAllocation *allocation, gpointer data) -{ - struct gui_window *g = data; - - g->bw->reformat_pending = true; - browser_reformat_pending = true; - - if (g->paned != NULL) { - /* Set status bar / scroll bar proportion according to - * option_toolbar_status_width */ - /* TODO: Probably want to detect when the user adjusts the - * status bar width, remember that proportion for the - * window, and use that here. */ - gtk_paned_set_position(g->paned, (option_toolbar_status_width * - allocation->width) / 10000); - } - - return TRUE; -} - - -void nsgtk_reflow_all_windows(void) -{ - for (struct gui_window *g = window_list; g; g = g->next) { - nsgtk_tab_options_changed(GTK_WIDGET( - nsgtk_scaffolding_notebook(g->scaffold))); - g->bw->reformat_pending = true; - } - - browser_reformat_pending = true; -} - - -/** - * Process pending reformats - */ - -void nsgtk_window_process_reformats(void) -{ - struct gui_window *g; - - browser_reformat_pending = false; - for (g = window_list; g; g = g->next) { - GtkWidget *widget = GTK_WIDGET(g->layout); - if (!g->bw->reformat_pending) - continue; - g->bw->reformat_pending = false; - browser_window_reformat(g->bw, - widget->allocation.width, - widget->allocation.height); - } -} - - -void nsgtk_window_destroy_browser(struct gui_window *g) -{ - browser_window_destroy(g->bw); -} - -void gui_window_destroy(struct gui_window *g) -{ - if (g->prev) - g->prev->next = g->next; - else - window_list = g->next; - - if (g->next) - g->next->prev = g->prev; - - - LOG(("Destroying gui_window %p", g)); - assert(g != NULL); - assert(g->bw != NULL); - LOG((" Scaffolding: %p", g->scaffold)); - LOG((" Window name: %s", g->bw->name)); - - if (g->scrolledwindow == NULL) { - /* tab => remove tab */ - gtk_widget_destroy(gtk_widget_get_parent(GTK_WIDGET(g->layout))); - /* if it was the last tab, destroy scaffold too */ - gint numbertabs = gtk_notebook_get_n_pages(nsgtk_scaffolding_notebook(g->scaffold)); - if (numbertabs == 0) - nsgtk_scaffolding_destroy(g->scaffold); - } else { - /* frame within a document => destroy frame only */ - gtk_widget_destroy(GTK_WIDGET(g->scrolledwindow)); - } - - free(g); - -} - -void nsgtk_redraw_caret(struct gui_window *g) -{ - if (g->careth == 0) - return; - - gui_window_redraw(g, g->caretx, g->carety, - g->caretx, g->carety + g->careth); -} - -void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1) -{ - int sx, sy; - - gui_window_get_scroll(g, &sx, &sy); - - gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), - x0 - sx, y0 - sy, x1-x0+1, y1-y0+1); -} - -void gui_window_redraw_window(struct gui_window *g) -{ - gtk_widget_queue_draw(GTK_WIDGET(g->layout)); -} - -void gui_window_update_box(struct gui_window *g, - const union content_msg_data *data) -{ - int sx, sy; - hlcache_handle *c = g->bw->current_content; - - if (c == NULL) - return; - - gui_window_get_scroll(g, &sx, &sy); - - gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), - data->redraw.x * g->bw->scale - sx, - data->redraw.y * g->bw->scale - sy, - data->redraw.width * g->bw->scale, - data->redraw.height * g->bw->scale); -} - -void gui_window_set_status(struct gui_window *g, const char *text) -{ - assert(g); - assert(g->status_bar); - gtk_label_set_text(g->status_bar, text); -} - -bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) -{ - GtkAdjustment *vadj = gtk_layout_get_vadjustment(g->layout); - GtkAdjustment *hadj = gtk_layout_get_hadjustment(g->layout); - - assert(vadj); - assert(hadj); - - *sy = (int)(gtk_adjustment_get_value(vadj)); - *sx = (int)(gtk_adjustment_get_value(hadj)); - - return true; -} - -void gui_window_set_scroll(struct gui_window *g, int sx, int sy) -{ - GtkAdjustment *vadj = gtk_layout_get_vadjustment(g->layout); - GtkAdjustment *hadj = gtk_layout_get_hadjustment(g->layout); - gdouble vlower, vpage, vupper, hlower, hpage, hupper, x = (double)sx, y = (double)sy; - - assert(vadj); - assert(hadj); - - g_object_get(vadj, "page-size", &vpage, "lower", &vlower, "upper", &vupper, NULL); - g_object_get(hadj, "page-size", &hpage, "lower", &hlower, "upper", &hupper, NULL); - - if (x < hlower) - x = hlower; - if (x > (hupper - hpage)) - x = hupper - hpage; - if (y < vlower) - y = vlower; - if (y > (vupper - vpage)) - y = vupper - vpage; - - gtk_adjustment_set_value(vadj, y); - gtk_adjustment_set_value(hadj, x); -} - -void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, - int x1, int y1) -{ - gui_window_set_scroll(g,x0,y0); -} - - -/** - * Set the scale setting of a window - * - * \param g gui window - * \param scale scale value (1.0 == normal scale) - */ - -void gui_window_set_scale(struct gui_window *g, float scale) -{ -} - - -void gui_window_update_extent(struct gui_window *g) -{ - if (!g->bw->current_content) - return; - - gtk_layout_set_size(g->layout, - content_get_width(g->bw->current_content) * g->bw->scale, - content_get_height(g->bw->current_content) * g->bw->scale); -} - -static GdkCursor *nsgtk_create_menu_cursor(void) -{ - static char menu_cursor_bits[] = { - 0x00, 0x00, 0x80, 0x7F, 0x88, 0x40, 0x9E, 0x5E, 0x88, 0x40, 0x80, 0x56, - 0x80, 0x40, 0x80, 0x5A, 0x80, 0x40, 0x80, 0x5E, 0x80, 0x40, 0x80, 0x56, - 0x80, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, }; - - static char menu_cursor_mask_bits[] = { - 0xC0, 0xFF, 0xC8, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xC8, 0xFF, - 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, - 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0x00, 0x00, }; - - static GdkCursor *r; - static GdkColor fg = { 0, 0, 0, 0 }; - static GdkColor bg = { 0, 65535, 65535, 65535 }; - - GdkPixmap *source, *mask; - - if (r != NULL) - return r; - - source = gdk_bitmap_create_from_data(NULL, menu_cursor_bits, - 16, 16); - mask = gdk_bitmap_create_from_data (NULL, menu_cursor_mask_bits, - 16, 16); - - r = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 0, 3); - gdk_pixmap_unref(source); - gdk_pixmap_unref(mask); - - return r; -} - -void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) -{ - GdkCursor *cursor = NULL; - GdkCursorType cursortype; - bool nullcursor = false; - - if (g->current_pointer == shape) - return; - - g->current_pointer = shape; - - switch (shape) { - case GUI_POINTER_POINT: - cursortype = GDK_HAND2; - break; - case GUI_POINTER_CARET: - cursortype = GDK_XTERM; - break; - case GUI_POINTER_UP: - cursortype = GDK_TOP_SIDE; - break; - case GUI_POINTER_DOWN: - cursortype = GDK_BOTTOM_SIDE; - break; - case GUI_POINTER_LEFT: - cursortype = GDK_LEFT_SIDE; - break; - case GUI_POINTER_RIGHT: - cursortype = GDK_RIGHT_SIDE; - break; - case GUI_POINTER_LD: - cursortype = GDK_BOTTOM_LEFT_CORNER; - break; - case GUI_POINTER_RD: - cursortype = GDK_BOTTOM_RIGHT_CORNER; - break; - case GUI_POINTER_LU: - cursortype = GDK_TOP_LEFT_CORNER; - break; - case GUI_POINTER_RU: - cursortype = GDK_TOP_RIGHT_CORNER; - break; - case GUI_POINTER_CROSS: - cursortype = GDK_CROSS; - break; - case GUI_POINTER_MOVE: - cursortype = GDK_FLEUR; - break; - case GUI_POINTER_WAIT: - cursortype = GDK_WATCH; - break; - case GUI_POINTER_HELP: - cursortype = GDK_QUESTION_ARROW; - break; - case GUI_POINTER_MENU: - cursor = nsgtk_create_menu_cursor(); - nullcursor = true; - break; - case GUI_POINTER_PROGRESS: - /* In reality, this needs to be the funky left_ptr_watch - * which we can't do easily yet. - */ - cursortype = GDK_WATCH; - break; - /* The following we're not sure about */ - case GUI_POINTER_NO_DROP: - case GUI_POINTER_NOT_ALLOWED: - case GUI_POINTER_DEFAULT: - default: - nullcursor = true; - } - - if (!nullcursor) - cursor = gdk_cursor_new_for_display( - gtk_widget_get_display( - GTK_WIDGET(g->layout)), - cursortype); - gdk_window_set_cursor(GTK_WIDGET(g->layout)->window, cursor); - - if (!nullcursor) - gdk_cursor_unref(cursor); -} - -void gui_window_hide_pointer(struct gui_window *g) -{ - -} - -void gui_window_place_caret(struct gui_window *g, int x, int y, int height) -{ - nsgtk_redraw_caret(g); - - g->caretx = x; - g->carety = y + 1; - g->careth = height - 2; - - nsgtk_redraw_caret(g); - - gtk_widget_grab_focus(GTK_WIDGET(g->layout)); -} - -void gui_window_remove_caret(struct gui_window *g) -{ - int oh = g->careth; - - if (oh == 0) - return; - - g->careth = 0; - - gui_window_redraw(g, g->caretx, g->carety, - g->caretx, g->carety + oh); -} - -void gui_window_new_content(struct gui_window *g) -{ - -} - -bool gui_window_scroll_start(struct gui_window *g) -{ - return true; -} - -bool gui_window_box_scroll_start(struct gui_window *g, - int x0, int y0, int x1, int y1) -{ - return true; -} - -void gui_drag_save_object(gui_save_type type, hlcache_handle *c, - struct gui_window *g) -{ - -} - -void gui_drag_save_selection(struct selection *s, struct gui_window *g) -{ - -} - -void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, - bool scaled) -{ - *width = GTK_WIDGET(g->layout)->allocation.width; - *height = GTK_WIDGET(g->layout)->allocation.height; - - if (scaled) { - *width /= g->bw->scale; - *height /= g->bw->scale; - } - LOG(("\tWINDOW WIDTH: %i\n", *width)); - LOG(("\tWINDOW HEIGHT: %i\n", *height)); -} - -bool gui_window_frame_resize_start(struct gui_window *g) -{ - return true; -} diff --git a/gtk/gtk_window.h b/gtk/gtk_window.h deleted file mode 100644 index 27bbe5945..000000000 --- a/gtk/gtk_window.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2006 Daniel Silverstone - * - * 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 . - */ - -#ifndef NETSURF_GTK_WINDOW_H -#define NETSURF_GTK_WINDOW_H 1 - -#include "desktop/gui.h" -#include "desktop/browser.h" -#include "gtk/gtk_scaffolding.h" - - -typedef enum nsgtk_window_signals { - NSGTK_WINDOW_SIGNAL_CLICK, - NSGTK_WINDOW_SIGNAL_REDRAW, - NSGTK_WINDOW_SIGNAL_COUNT -} nsgtk_window_signal; - -extern struct gui_window *window_list; -extern int temp_open_background; - -void nsgtk_reflow_all_windows(void); -void nsgtk_window_process_reformats(void); - -nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g); - -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); - - -#endif /* NETSURF_GTK_WINDOW_H */ diff --git a/gtk/gui.c b/gtk/gui.c new file mode 100644 index 000000000..98a0c3322 --- /dev/null +++ b/gtk/gui.c @@ -0,0 +1,1150 @@ +/* + * Copyright 2004-2010 James Bursa + * Copyright 2010 Vincent Sanders + * Copyright 2004-2009 John-Mark Bell + * Copyright 2009 Paul Blokus + * Copyright 2006-2009 Daniel Silverstone + * Copyright 2006-2008 Rob Kendrick + * Copyright 2008 John Tytgat + * Copyright 2008 Adam Blokus + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "content/content.h" +#include "content/fetch.h" +#include "content/fetchers/fetch_curl.h" +#include "content/hlcache.h" +#include "content/urldb.h" +#include "desktop/browser.h" +#include "desktop/cookies.h" +#include "desktop/gui.h" +#include "desktop/history_global_core.h" +#include "desktop/netsurf.h" +#include "desktop/options.h" +#include "desktop/save_pdf/pdf_plotters.h" +#include "desktop/searchweb.h" +#include "desktop/sslcert.h" +#include "desktop/textinput.h" +#include "desktop/tree.h" +#include "css/utils.h" +#include "gtk/dialogs/options.h" +#include "gtk/completion.h" +#include "gtk/cookies.h" +#include "gtk/download.h" +#include "gtk/filetype.h" +#include "gtk/gui.h" +#include "gtk/history.h" +#include "gtk/hotlist.h" +#include "gtk/throbber.h" +#include "gtk/treeview.h" +#include "gtk/window.h" +#include "gtk/options.h" +#include "gtk/schedule.h" + +#include "render/box.h" +#include "render/form.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utf8.h" +#include "utils/utils.h" +#include "utils/findresource.h" + +char *default_stylesheet_url; +char *quirks_stylesheet_url; +char *adblock_stylesheet_url; +char *options_file_location; +char *toolbar_indices_file_location; +char *res_dir_location; +char *print_options_file_location; +char *languages_file_location; + +char *glade_netsurf_file_location; +char *glade_password_file_location; +char *glade_warning_file_location; +char *glade_login_file_location; +char *glade_ssl_file_location; +char *glade_toolbar_file_location; +char *glade_options_file_location; + +static char *glade_downloads_file_location; +static char *glade_history_file_location; +static char *glade_hotlist_file_location; +static char *glade_cookies_file_location; + +static GtkWindow *nsgtk_warning_window; +GtkWidget *widWarning; + +static GtkWidget *select_menu; +static struct browser_window *select_menu_bw; +static struct form_control *select_menu_control; + +static void nsgtk_ssl_accept(GtkButton *w, gpointer data); +static void nsgtk_ssl_reject(GtkWidget *w, gpointer data); +static gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event, + gpointer data); +static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, + gpointer user_data); +#ifdef WITH_PDF_EXPORT +static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data); +static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data); +#endif + +#define THROBBER_FRAMES 9 + +#define MAX_RESPATH 128 /* maximum number of elements in the resource vector */ + +/* expand ${} in a string into environment variables */ +static char * +expand_path(const char *path) +{ + char *exp = strdup(path); + int explen; + int cstart = -1; + int cloop = 0; + char *envv; + int envlen; + int replen; /* length of replacement */ + + if (exp == NULL) + return NULL; + + explen = strlen(exp) + 1; + + while (exp[cloop] != 0) { + if ((exp[cloop] == '$') && + (exp[cloop + 1] == '{')) { + cstart = cloop; + cloop++; + } + + if ((cstart != -1) && + (exp[cloop] == '}')) { + replen = cloop - cstart; + exp[cloop] = 0; + envv = getenv(exp + cstart + 2); + if (envv == NULL) { + memmove(exp + cstart, + exp + cloop + 1, + explen - cloop - 1); + explen -= replen; + } else { + envlen = strlen(envv); + exp = realloc(exp, explen + envlen - replen); + memmove(exp + cstart + envlen, + exp + cloop + 1, + explen - cloop - 1); + memmove(exp + cstart, envv, envlen); + explen += envlen - replen; + } + cloop -= replen; + cstart = -1; + } + + cloop++; + } + + return exp; +} + +/* convert a colon separated list of path elements into a string vector */ +static char ** +path_to_strvec(const char *path) +{ + char **strvec; + int strc = 0; + + strvec = calloc(MAX_RESPATH, sizeof(char *)); + if (strvec == NULL) + return NULL; + + strvec[strc] = expand_path(path); + if (strvec[strc] == NULL) { + free(strvec); + return NULL; + } + strc++; + + strvec[strc] = strchr(strvec[0], ':'); + while ((strc < (MAX_RESPATH - 2)) && + (strvec[strc] != NULL)) { + /* null terminate previous entry */ + *strvec[strc] = 0; + strvec[strc]++; + + /* skip colons */ + while (*strvec[strc] == ':') + strvec[strc]++; + + if (*strvec[strc] == 0) + break; /* string is terminated */ + + strc++; + + strvec[strc] = strchr(strvec[strc - 1], ':'); + } + + return strvec; +} + + +/** 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(const char *resource_path) +{ + const gchar * const *langv; + char **pathv; /* resource path string vector */ + char **respath; /* resource paths vector */ + + pathv = path_to_strvec(resource_path); + + langv = g_get_language_names(); + + respath = findresource_generate(pathv, langv); + + free(pathv[0]); + free(pathv); + + return respath; +} + +/* This is an ugly hack to just get the new-style throbber going. + * It, along with the PNG throbber loader, need making more generic. + */ +static bool nsgtk_throbber_init(char **respath, int framec) +{ + char **filenames; + char targetname[PATH_MAX]; + int frame_num; + bool ret; + + filenames = calloc(framec, sizeof(char *)); + if (filenames == NULL) + return false; + + for (frame_num = 0; frame_num < framec; frame_num++) { + snprintf(targetname, PATH_MAX, "throbber/throbber%d.png", frame_num); + filenames[frame_num] = findresource(respath, targetname); + } + + ret = nsgtk_throbber_initialise_from_png(frame_num, filenames); + + for (frame_num = 0; frame_num < framec; frame_num++) { + free(filenames[frame_num]); + } + free(filenames); + + return ret; + +} + +#define NEW_GLADE_ERROR_SIZE 128 + +static char * +nsgtk_new_glade(char **respath, const char *name, GladeXML **pglade) +{ + GladeXML *newglade; + char *filepath; + char errorstr[NEW_GLADE_ERROR_SIZE]; + char resname[PATH_MAX]; + + snprintf(resname, PATH_MAX, "%s.glade", name); + + filepath = findresource(respath, resname); + if (filepath == NULL) { + snprintf(errorstr, NEW_GLADE_ERROR_SIZE, + "Unable to locate %s glade template file.\n", name); + die(errorstr); + } + + newglade = glade_xml_new(filepath, NULL, NULL); + if (newglade == NULL) { + snprintf(errorstr, NEW_GLADE_ERROR_SIZE, + "Unable to load glade %s window definitions.\n", name); + + die(errorstr); + } + glade_xml_signal_autoconnect(newglade); + + LOG(("Using '%s' as %s glade template file", filepath, name)); + + if (pglade != NULL) { + *pglade = newglade; + } + + return filepath; +} + +/** + * Load definitions from glade files. + */ +static void +nsgtk_init_glade(char **respath) +{ + GladeXML *gladeWarning; + + glade_init(); + + glade_netsurf_file_location = nsgtk_new_glade(respath, "netsurf", NULL); + glade_password_file_location = nsgtk_new_glade(respath, "password", NULL); + glade_login_file_location = nsgtk_new_glade(respath, "login", NULL); + glade_ssl_file_location = nsgtk_new_glade(respath, "ssl", NULL); + glade_toolbar_file_location = nsgtk_new_glade(respath, "toolbar", NULL); + glade_downloads_file_location = nsgtk_new_glade(respath, "downloads", NULL); + glade_history_file_location = nsgtk_new_glade(respath, "history", NULL); + glade_options_file_location = nsgtk_new_glade(respath, "options", NULL); + glade_hotlist_file_location = nsgtk_new_glade(respath, "hotlist", NULL); + glade_cookies_file_location = nsgtk_new_glade(respath, "cookies", NULL); + + glade_warning_file_location = nsgtk_new_glade(respath, "warning", &gladeWarning); + nsgtk_warning_window = GTK_WINDOW(glade_xml_get_widget(gladeWarning, "wndWarning")); + widWarning = glade_xml_get_widget(gladeWarning, "labelWarning"); +} + +static void check_options(char **respath) +{ + char *hdir = getenv("HOME"); + char buf[PATH_MAX]; + + option_core_select_menu = true; + + /* 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 (option_toolbar_status_width < 1500) { + option_toolbar_status_width = 6667; + } + + /* user options should be stored in the users home directory */ + snprintf(buf, PATH_MAX, "%s/.netsurf/Choices", hdir); + options_file_location = strdup(buf); + + /* VRS - I do not beleive these setting should search the + * resource path, they should just be set to the default + * values! + */ + if (!option_cookie_file) { + sfindresourcedef(respath, buf, "Cookies", "~/.netsurf/"); + LOG(("Using '%s' as Cookies file", buf)); + option_cookie_file = strdup(buf); + } + if (!option_cookie_jar) { + sfindresourcedef(respath, buf, "Cookies", "~/.netsurf/"); + LOG(("Using '%s' as Cookie Jar file", buf)); + option_cookie_jar = strdup(buf); + } + if (!option_cookie_file || !option_cookie_jar) + die("Failed initialising cookie options"); + + if (!option_url_file) { + sfindresourcedef(respath, buf, "URLs", "~/.netsurf/"); + LOG(("Using '%s' as URL file", buf)); + option_url_file = strdup(buf); + } + + if (!option_ca_path) { + sfindresourcedef(respath, buf, "certs", "/etc/ssl/"); + LOG(("Using '%s' as certificate path", buf)); + option_ca_path = strdup(buf); + } + + if (!option_downloads_directory) { + LOG(("Using '%s' as download directory", hdir)); + option_downloads_directory = hdir; + } + + sfindresourcedef(respath, buf, "icons/", "~/.netsurf/"); + LOG(("Using '%s' as Tree icons dir", buf)); + tree_set_icon_dir(strdup(buf)); + + if (!option_hotlist_path) { + sfindresourcedef(respath, buf, "Hotlist", "~/.netsurf/"); + LOG(("Using '%s' as Hotlist file", buf)); + option_hotlist_path = strdup(buf); + } + if (!option_hotlist_path) + die("Failed initialising hotlist option"); + + + sfindresourcedef(respath, buf, "Print", "~/.netsurf/"); + LOG(("Using '%s' as Print Settings file", buf)); + print_options_file_location = strdup(buf); + + /* check what the font settings are, setting them to a default font + * if they're not set - stops Pango whinging + */ +#define SETFONTDEFAULT(x,y) (x) = ((x) != NULL) ? (x) : strdup((y)) + SETFONTDEFAULT(option_font_sans, "Sans"); + SETFONTDEFAULT(option_font_serif, "Serif"); + SETFONTDEFAULT(option_font_mono, "Monospace"); + SETFONTDEFAULT(option_font_cursive, "Serif"); + SETFONTDEFAULT(option_font_fantasy, "Serif"); + +} + +/** + * Initialize GTK interface. + */ +static void gui_init(int argc, char** argv, char **respath) +{ + char buf[PATH_MAX]; + struct browser_window *bw; + const char *addr = NETSURF_HOMEPAGE; + char *resource_filename; + + /* check user options */ + check_options(respath); + + /* Obtain resources path location. + * + * Uses the directory the languages file was found in, + * previously the location of the glade files was used, + * however these may be translated which breaks things + * relying on res_dir_location. + */ + resource_filename = findresource(respath, "languages"); + resource_filename[strlen(resource_filename) - 9] = 0; + res_dir_location = resource_filename; + + /* languages file */ + languages_file_location = findresource(respath, "languages"); + + /* initialise the glade templates */ + nsgtk_init_glade(respath); + + /* set default icon if its available */ + resource_filename = findresource(respath, "netsurf.xpm"); + if (resource_filename != NULL) { + gtk_window_set_default_icon_from_file(resource_filename, NULL); + free(resource_filename); + } + + /* Search engine sources */ + search_engines_file_location = findresource(respath, "SearchEngines"); + LOG(("Using '%s' as Search Engines file", search_engines_file_location)); + + /* Default Icon */ + search_default_ico_location = findresource(respath, "default.ico"); + LOG(("Using '%s' as default search ico", search_default_ico_location)); + + /* Toolbar inicies file */ + toolbar_indices_file_location = findresource(respath, "toolbarIndices"); + LOG(("Using '%s' as custom toolbar settings file", toolbar_indices_file_location)); + + /* load throbber images */ + if (nsgtk_throbber_init(respath, THROBBER_FRAMES) == false) + die("Unable to load throbber image.\n"); + + /* Initialise completions - cannot fail */ + nsgtk_completion_init(); + + sfindresourcedef(respath, buf, "mime.types", "/etc/"); + gtk_fetch_filetype_init(buf); + + /* set up stylesheet urls */ + sfindresourcedef(respath, buf, "gtkdefault.css", "./gtk/res/"); + default_stylesheet_url = path_to_url(buf); + LOG(("Using '%s' as Default CSS URL", default_stylesheet_url)); + + sfindresourcedef(respath, buf, "quirks.css", "./gtk/res/"); + quirks_stylesheet_url = path_to_url(buf); + + sfindresourcedef(respath, buf, "adblock.css", "./gtk/res/"); + adblock_stylesheet_url = path_to_url(buf); + LOG(("Using '%s' as AdBlock CSS URL", adblock_stylesheet_url)); + + urldb_load(option_url_file); + urldb_load_cookies(option_cookie_file); + + /* 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. + */ + + nscss_screen_dpi = FLTTOFIX(gdk_screen_get_resolution( + gdk_screen_get_default())); + LOG(("Set CSS DPI to %f", FIXTOFLT(nscss_screen_dpi))); + + if (nsgtk_history_init(glade_history_file_location) == false) + die("Unable to initialise history window.\n"); + + if (nsgtk_download_init(glade_downloads_file_location) == false) + die("Unable to initialise download window.\n"); + + if (nsgtk_cookies_init(glade_cookies_file_location) == false) + die("Unable to initialise cookies window.\n"); + + if (nsgtk_hotlist_init(glade_hotlist_file_location) == false) + die("Unable to initialise hotlist window.\n"); + + sslcert_init(tree_content_icon_name); + + if (option_homepage_url != NULL && option_homepage_url[0] != '\0') + addr = option_homepage_url; + + if (2 <= argc) + addr = argv[1]; + + /* Last step of initialization. Opens the main browser window. */ + bw = browser_window_create(addr, 0, 0, true, false); +} + + +/** + * Check that ~/.netsurf/ exists, and if it doesn't, create it. + */ +static void nsgtk_check_homedir(void) +{ + char *hdir = getenv("HOME"); + char buf[PATH_MAX]; + + if (hdir == NULL) { + /* we really can't continue without a home directory. */ + LOG(("HOME is not set - nowhere to store state!")); + die("NetSurf requires HOME to be set in order to run.\n"); + + } + + snprintf(buf, PATH_MAX, "%s/.netsurf", hdir); + if (access(buf, F_OK) != 0) { + LOG(("You don't have a ~/.netsurf - creating one for you.")); + if (mkdir(buf, 0777) == -1) { + LOG(("Unable to create %s", buf)); + die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n"); + } + } +} + +/** + * Main entry point from OS. + */ +int main(int argc, char** argv) +{ + char *messages; + char *options; + char **respaths; + + /* check home directory is available */ + nsgtk_check_homedir(); + + respaths = nsgtk_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"GTK_RESPATH":./gtk/res"); + + /* Some modern distributions can set ALL_PROXY/all_proxy if configured + * to by the user. Due to a bug in many versions of libcurl + * (including the one shipped in Ubuntu 10.04 LTS), this also takes + * effect on file:// URLs, meaning that NetSurf cannot load its + * default CSS file. Given all examples of distributions I've checked + * also set http_proxy and friends, we can safely unset these. + */ + + unsetenv("ALL_PROXY"); + unsetenv("all_proxy"); + + gtk_init(&argc, &argv); + + /* set standard error to be non-buffering */ + setbuf(stderr, NULL); + + options = findresource(respaths, "Choices"); + + messages = findresource(respaths, "Messages"); + + netsurf_init(&argc, &argv, options, messages); + + free(messages); + free(options); + + gui_init(argc, argv, respaths); + + netsurf_main_loop(); + + netsurf_exit(); + + + return 0; +} + + +void gui_poll(bool active) +{ + CURLMcode code; + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd; + GPollFD *fd_list[1000]; + unsigned int fd_count = 0; + bool block = true; + + if (browser_reformat_pending) + block = false; + + if (active) { + FD_ZERO(&read_fd_set); + FD_ZERO(&write_fd_set); + FD_ZERO(&exc_fd_set); + code = curl_multi_fdset(fetch_curl_multi, + &read_fd_set, + &write_fd_set, + &exc_fd_set, + &max_fd); + assert(code == CURLM_OK); + 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_do(block); + + for (unsigned int i = 0; i != fd_count; i++) { + g_main_context_remove_poll(0, fd_list[i]); + free(fd_list[i]); + } + + schedule_run(); + + if (browser_reformat_pending) + nsgtk_window_process_reformats(); +} + + +void gui_multitask(void) +{ + while (gtk_events_pending()) + gtk_main_iteration(); +} + + +void gui_quit(void) +{ + nsgtk_download_destroy(); + urldb_save_cookies(option_cookie_jar); + urldb_save(option_url_file); + nsgtk_cookies_destroy(); + nsgtk_history_destroy(); + nsgtk_hotlist_destroy(); + sslcert_cleanup(); + free(default_stylesheet_url); + free(quirks_stylesheet_url); + free(adblock_stylesheet_url); + free(option_cookie_file); + free(option_cookie_jar); + free(print_options_file_location); + free(search_engines_file_location); + free(search_default_ico_location); + free(toolbar_indices_file_location); + gtk_fetch_filetype_fin(); +} + + + + + + + + + +static void nsgtk_select_menu_clicked(GtkCheckMenuItem *checkmenuitem, + gpointer user_data) +{ + form_select_process_selection(select_menu_bw->current_content, + select_menu_control, (intptr_t)user_data); +} + +void gui_create_form_select_menu(struct browser_window *bw, + struct form_control *control) +{ + + intptr_t i; + struct form_option *option; + + GtkWidget *menu_item; + + /* control->data.select.multiple is true if multiple selections + * are allowable. We ignore this, as the core handles it for us. + * Yay. \o/ + */ + + if (select_menu != NULL) + gtk_widget_destroy(select_menu); + + select_menu = gtk_menu_new(); + select_menu_bw = bw; + select_menu_control = control; + + for (i = 0, option = control->data.select.items; option; + i++, option = option->next) { + menu_item = gtk_check_menu_item_new_with_label(option->text); + if (option->selected) + gtk_check_menu_item_set_active( + GTK_CHECK_MENU_ITEM(menu_item), TRUE); + + g_signal_connect(menu_item, "toggled", + G_CALLBACK(nsgtk_select_menu_clicked), (gpointer)i); + + gtk_menu_shell_append(GTK_MENU_SHELL(select_menu), menu_item); + } + + gtk_widget_show_all(select_menu); + + gtk_menu_popup(GTK_MENU(select_menu), NULL, NULL, NULL, + NULL /* data */, 0, gtk_get_current_event_time()); + +} + +void gui_window_save_link(struct gui_window *g, const char *url, + const char *title) +{ +} + +void gui_launch_url(const char *url) +{ +} + +void warn_user(const char *warning, const char *detail) +{ + char buf[300]; /* 300 is the size the RISC OS GUI uses */ + + LOG(("%s %s", warning, detail ? detail : "")); + fflush(stdout); + + snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), + detail ? detail : ""); + buf[sizeof(buf) - 1] = 0; + + gtk_label_set_text(GTK_LABEL(widWarning), buf); + + gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window)); +} + +void die(const char * const error) +{ + fprintf(stderr, "%s", error); + exit(EXIT_FAILURE); +} + + +void gui_cert_verify(const char *url, const struct ssl_cert_info *certs, + unsigned long num, nserror (*cb)(bool proceed, void *pw), + void *cbpw) +{ + static struct nsgtk_treeview *ssl_window; + struct sslcert_session_data *data; + GladeXML *x = glade_xml_new(glade_ssl_file_location, NULL, NULL); + GtkButton *accept, *reject; + void **session = calloc(sizeof(void *), 3); + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; + + data = sslcert_create_session_data(num, url, cb, cbpw); + + window = GTK_WINDOW( + glade_xml_get_widget(x,"wndSSLProblem")); + scrolled = GTK_SCROLLED_WINDOW( + glade_xml_get_widget(x,"SSLScrolled")); + drawing_area = GTK_DRAWING_AREA( + glade_xml_get_widget(x,"SSLDrawingArea")); + + + ssl_window = nsgtk_treeview_create(sslcert_get_tree_flags(), + window, scrolled, drawing_area); + + if (ssl_window == NULL) + return; + + sslcert_load_tree(nsgtk_treeview_get_tree(ssl_window), certs, data); + + accept = GTK_BUTTON(glade_xml_get_widget(x, "sslaccept")); + reject = GTK_BUTTON(glade_xml_get_widget(x, "sslreject")); + + session[0] = x; + session[1] = ssl_window; + session[2] = data; + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + CONNECT(accept, "clicked", nsgtk_ssl_accept, session); + CONNECT(reject, "clicked", nsgtk_ssl_reject, session); + CONNECT(window, "delete_event", G_CALLBACK(nsgtk_ssl_delete_event), + (gpointer)session); + + gtk_widget_show(GTK_WIDGET(window)); +} + +void nsgtk_ssl_accept(GtkButton *w, gpointer data) +{ + void **session = data; + GladeXML *x = session[0]; + struct nsgtk_treeview *wnd = session[1]; + struct sslcert_session_data *ssl_data = session[2]; + + sslcert_accept(ssl_data); + + nsgtk_treeview_destroy(wnd); + g_object_unref(G_OBJECT(x)); + free(session); +} + +void nsgtk_ssl_reject(GtkWidget *w, gpointer data) +{ + void **session = data; + GladeXML *x = session[0]; + struct nsgtk_treeview *wnd = session[1]; + struct sslcert_session_data *ssl_data = session[2]; + + sslcert_reject(ssl_data); + + nsgtk_treeview_destroy(wnd); + g_object_unref(G_OBJECT(x)); + free(session); +} + +gboolean nsgtk_ssl_delete_event(GtkWidget *w, GdkEvent *event, gpointer data) +{ + nsgtk_ssl_reject(w, data); + return FALSE; +} + +utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len, + char **result) +{ + assert(string && result); + + if (len == 0) + len = strlen(string); + + *result = strndup(string, len); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + + return UTF8_CONVERT_OK; +} + + +utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len, + char **result) +{ + assert(string && result); + + if (len == 0) + len = strlen(string); + + *result = strndup(string, len); + if (!(*result)) + return UTF8_CONVERT_NOMEM; + + return UTF8_CONVERT_OK; +} + + +char *path_to_url(const char *path) +{ + int urllen = strlen(path) + FILE_SCHEME_PREFIX_LEN + 1; + char *url = malloc(urllen); + + if (url == NULL) { + return NULL; + } + + if (*path == '/') { + path++; /* file: paths are already absolute */ + } + + snprintf(url, urllen, "%s%s", FILE_SCHEME_PREFIX, path); + + return url; +} + + +char *url_to_path(const char *url) +{ + char *path; + char *respath; + url_func_result res; /* result from url routines */ + + res = url_path(url, &path); + if (res != URL_FUNC_OK) { + return NULL; + } + + res = url_unescape(path, &respath); + free(path); + if (res != URL_FUNC_OK) { + return NULL; + } + + return respath; +} + +#ifdef WITH_PDF_EXPORT + +void PDF_Password(char **owner_pass, char **user_pass, char *path) +{ + GladeXML *x = glade_xml_new(glade_password_file_location, NULL, NULL); + GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndPDFPassword")); + GtkButton *ok, *no; + void **data = malloc(5 * sizeof(void *)); + + *owner_pass = NULL; + *user_pass = NULL; + + data[0] = owner_pass; + data[1] = user_pass; + data[2] = wnd; + data[3] = x; + data[4] = path; + + ok = GTK_BUTTON(glade_xml_get_widget(x, "buttonPDFSetPassword")); + no = GTK_BUTTON(glade_xml_get_widget(x, "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 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]; + GladeXML *x = ((void **)data)[3]; + char *path = ((void **)data)[4]; + + char *op, *op1; + char *up, *up1; + + op = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, + "entryPDFOwnerPassword")))); + op1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, + "entryPDFOwnerPassword1")))); + up = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, + "entryPDFUserPassword")))); + up1 = strdup(gtk_entry_get_text(GTK_ENTRY(glade_xml_get_widget(x, + "entryPDFUserPassword1")))); + + + if (op[0] == '\0') { + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, + "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(glade_xml_get_widget(x, + "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(x)); + + save_pdf(path); + free(path); + } + else { + gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(x, + "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]; + GladeXML *x = ((void **)data)[3]; + char *path = ((void **)data)[4]; + + free(data); + + gtk_widget_destroy(GTK_WIDGET(wnd)); + g_object_unref(G_OBJECT(x)); + + save_pdf(path); + free(path); +} +#endif + +uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) +{ + /* this function will need to become much more complex to support + * everything that the RISC OS version does. But this will do for + * now. I hope. + */ + switch (key->keyval) + { + case GDK_BackSpace: + if (key->state & GDK_SHIFT_MASK) + return KEY_DELETE_LINE_START; + else + return KEY_DELETE_LEFT; + case GDK_Delete: + if (key->state & GDK_SHIFT_MASK) + return KEY_DELETE_LINE_END; + else + return KEY_DELETE_RIGHT; + case GDK_Linefeed: return 13; + case GDK_Return: return 10; + case GDK_Left: return KEY_LEFT; + case GDK_Right: return KEY_RIGHT; + case GDK_Up: return KEY_UP; + case GDK_Down: return KEY_DOWN; + case GDK_Home: + if (key->state & GDK_CONTROL_MASK) + return KEY_TEXT_START; + else + return KEY_LINE_START; + case GDK_End: + if (key->state & GDK_CONTROL_MASK) + return KEY_TEXT_END; + else + return KEY_LINE_END; + case GDK_Page_Up: + return KEY_PAGE_UP; + case GDK_Page_Down: + return KEY_PAGE_DOWN; + case 'a': + if (key->state & GDK_CONTROL_MASK) + return KEY_SELECT_ALL; + return gdk_keyval_to_unicode(key->keyval); + case 'u': + if (key->state & GDK_CONTROL_MASK) + return KEY_CLEAR_SELECTION; + return gdk_keyval_to_unicode(key->keyval); + case GDK_Escape: + return KEY_ESCAPE; + + /* Modifiers - do nothing for now */ + case GDK_Shift_L: + case GDK_Shift_R: + case GDK_Control_L: + case GDK_Control_R: + case GDK_Caps_Lock: + case GDK_Shift_Lock: + case GDK_Meta_L: + case GDK_Meta_R: + case GDK_Alt_L: + case GDK_Alt_R: + case GDK_Super_L: + case GDK_Super_R: + case GDK_Hyper_L: + case GDK_Hyper_R: return 0; + + default: return gdk_keyval_to_unicode( + key->keyval); + } +} + +/** + * Return the filename part of a full path + * + * \param path full path and filename + * \return filename (will be freed with free()) + */ + +char *filename_from_path(char *path) +{ + char *leafname; + + leafname = strrchr(path, '/'); + if (!leafname) + leafname = path; + else + leafname += 1; + + return strdup(leafname); +} + +/** + * Add a path component/filename to an existing path + * + * \param path buffer containing path + free space + * \param length length of buffer "path" + * \param newpart string containing path component to add to path + * \return true on success + */ + +bool path_add_part(char *path, int length, const char *newpart) +{ + if(path[strlen(path) - 1] != '/') + strncat(path, "/", length); + + strncat(path, newpart, length); + + return true; +} diff --git a/gtk/gui.h b/gtk/gui.h new file mode 100644 index 000000000..9035d8873 --- /dev/null +++ b/gtk/gui.h @@ -0,0 +1,51 @@ +/* + * Copyright 2004-2010 James Bursa + * Copyright 2010 Vincent Sanders + * Copyright 2004-2009 John-Mark Bell + * Copyright 2009 Paul Blokus + * Copyright 2006-2009 Daniel Silverstone + * Copyright 2006-2008 Rob Kendrick + * Copyright 2008 John Tytgat + * Copyright 2008 Adam Blokus + * + * 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 . + */ + +#ifndef GTK_GUI_H +#define GTK_GUI_H + +#include +#include +#include +#include + +extern char *glade_netsurf_file_location; +extern char *glade_password_file_location; +extern char *glade_warning_file_location; +extern char *glade_login_file_location; +extern char *glade_ssl_file_location; +extern char *glade_toolbar_file_location; +extern char *glade_options_file_location; + +extern char *languages_file_location; +extern char *toolbar_indices_file_location; +extern char *options_file_location; /**< location where user options are written */ +extern char *res_dir_location; +extern char *print_options_file_location; + +uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *); + +#endif /* GTK_GUI_H */ + diff --git a/gtk/history.c b/gtk/history.c new file mode 100644 index 000000000..b5c019f76 --- /dev/null +++ b/gtk/history.c @@ -0,0 +1,263 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2009 Paul Blokus + * + * 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 . + */ + + +#include "desktop/history_global_core.h" +#include "desktop/plotters.h" +#include "desktop/tree.h" +#include "gtk/gui.h" +#include "gtk/history.h" +#include "gtk/plotters.h" +#include "gtk/scaffolding.h" +#include "gtk/treeview.h" +#include "utils/log.h" +#include "utils/utils.h" + +#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ + GtkMenuItem *widget, gpointer g) +#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } +#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ + gpointer g) + +struct menu_events { + const char *widget; + GCallback handler; +}; + +static void nsgtk_history_init_menu(void); + +/* file menu*/ +MENUPROTO(export); + +/* edit menu */ +MENUPROTO(delete_selected); +MENUPROTO(delete_all); +MENUPROTO(select_all); +MENUPROTO(clear_selection); + +/* view menu*/ +MENUPROTO(expand_all); +MENUPROTO(expand_directories); +MENUPROTO(expand_addresses); +MENUPROTO(collapse_all); +MENUPROTO(collapse_directories); +MENUPROTO(collapse_addresses); + +MENUPROTO(launch); + +static struct menu_events menu_events[] = { + + /* file menu*/ + MENUEVENT(export), + + /* edit menu */ + MENUEVENT(delete_selected), + MENUEVENT(delete_all), + MENUEVENT(select_all), + MENUEVENT(clear_selection), + + /* view menu*/ + MENUEVENT(expand_all), + MENUEVENT(expand_directories), + MENUEVENT(expand_addresses), + MENUEVENT(collapse_all), + MENUEVENT(collapse_directories), + MENUEVENT(collapse_addresses), + + MENUEVENT(launch), + {NULL, NULL} +}; + +static struct nsgtk_treeview *global_history_window; +static GladeXML *gladeFile; +GtkWindow *wndHistory; + + +/* exported interface, documented in gtk_history.h */ +bool nsgtk_history_init(const char *glade_file_location) +{ + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; + + gladeFile = glade_xml_new(glade_file_location, NULL, NULL); + if (gladeFile == NULL) + return false; + + glade_xml_signal_autoconnect(gladeFile); + + wndHistory = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndHistory")); + + window = wndHistory; + + scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, + "globalHistoryScrolled")); + + drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, + "globalHistoryDrawingArea")); + + global_history_window = nsgtk_treeview_create( + history_global_get_tree_flags(), window, scrolled, + drawing_area); + + if (global_history_window == NULL) + return false; + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); + CONNECT(window, "hide", nsgtk_tree_window_hide, global_history_window); + + history_global_initialise( + nsgtk_treeview_get_tree(global_history_window), + tree_directory_icon_name); + + nsgtk_history_init_menu(); + + return true; +} + + +/** + * Connects menu events in the global history window. + */ +void nsgtk_history_init_menu(void) +{ + struct menu_events *event = menu_events; + + while (event->widget != NULL) + { + GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); + g_signal_connect(G_OBJECT(w), "activate", event->handler, + global_history_window); + event++; + } +} + + +/** + * Destroys the global history window and performs any other necessary cleanup + * actions. + */ +void nsgtk_history_destroy(void) +{ + /* TODO: what about gladeFile? */ + history_global_cleanup(); + nsgtk_treeview_destroy(global_history_window); +} + + +/* file menu*/ +MENUHANDLER(export) +{ + GtkWidget *save_dialog; + save_dialog = gtk_file_chooser_dialog_new("Save File", + wndHistory, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), + getenv("HOME") ? getenv("HOME") : "/"); + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), + "history.html"); + + if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(save_dialog)); + + history_global_export(filename); + g_free(filename); + } + + gtk_widget_destroy(save_dialog); + + return TRUE; +} + +/* edit menu */ +MENUHANDLER(delete_selected) +{ + history_global_delete_selected(); + return TRUE; +} + +MENUHANDLER(delete_all) +{ + history_global_delete_all(); + return TRUE; +} + +MENUHANDLER(select_all) +{ + history_global_select_all(); + return TRUE; +} + +MENUHANDLER(clear_selection) +{ + history_global_clear_selection(); + return TRUE; +} + +/* view menu*/ +MENUHANDLER(expand_all) +{ + history_global_expand_all(); + return TRUE; +} + +MENUHANDLER(expand_directories) +{ + history_global_expand_directories(); + return TRUE; +} + +MENUHANDLER(expand_addresses) +{ + history_global_expand_addresses(); + return TRUE; +} + +MENUHANDLER(collapse_all) +{ + history_global_collapse_all(); + return TRUE; +} + +MENUHANDLER(collapse_directories) +{ + history_global_collapse_directories(); + return TRUE; +} + +MENUHANDLER(collapse_addresses) +{ + history_global_collapse_addresses(); + return TRUE; +} + +MENUHANDLER(launch) +{ + history_global_launch_selected(); + return TRUE; +} diff --git a/gtk/history.h b/gtk/history.h new file mode 100644 index 000000000..ab3c10ee6 --- /dev/null +++ b/gtk/history.h @@ -0,0 +1,40 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +#ifndef __NSGTK_HISTORY_H__ +#define __NSGTK_HISTORY_H__ + +#include + +extern GtkWindow *wndHistory; + +/** + * Creates the window for the global history tree. + * + * \param glade_file_location The glade file to use for the window. + * \return true on success false on faliure. + */ +bool nsgtk_history_init(const char *glade_file_location); + +/** + * Free global resources associated with the gtk history window. + */ +void nsgtk_history_destroy(void); + +#endif /* __NSGTK_HISTORY_H__ */ diff --git a/gtk/hotlist.c b/gtk/hotlist.c new file mode 100644 index 000000000..6a821d7a3 --- /dev/null +++ b/gtk/hotlist.c @@ -0,0 +1,279 @@ +/* + * Copyright 2009 Paul Blokus + * + * 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 . + */ + + +#include "desktop/hotlist.h" +#include "desktop/options.h" +#include "desktop/plotters.h" +#include "desktop/tree.h" +#include "gtk/gui.h" +#include "gtk/hotlist.h" +#include "gtk/options.h" +#include "gtk/plotters.h" +#include "gtk/scaffolding.h" +#include "gtk/treeview.h" +#include "utils/log.h" + +#define GLADE_NAME "hotlist.glade" + +#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \ + GtkMenuItem *widget, gpointer g) +#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) } +#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \ + gpointer g) + +struct menu_events { + const char *widget; + GCallback handler; +}; + +static void nsgtk_hotlist_init_menu(void); + +/* file menu*/ +MENUPROTO(export); +MENUPROTO(new_folder); +MENUPROTO(new_entry); + +/* edit menu */ +MENUPROTO(edit_selected); +MENUPROTO(delete_selected); +MENUPROTO(select_all); +MENUPROTO(clear_selection); + +/* view menu*/ +MENUPROTO(expand_all); +MENUPROTO(expand_directories); +MENUPROTO(expand_addresses); +MENUPROTO(collapse_all); +MENUPROTO(collapse_directories); +MENUPROTO(collapse_addresses); + +MENUPROTO(launch); + +static struct menu_events menu_events[] = { + + /* file menu*/ + MENUEVENT(export), + MENUEVENT(new_folder), + MENUEVENT(new_entry), + + /* edit menu */ + MENUEVENT(edit_selected), + MENUEVENT(delete_selected), + MENUEVENT(select_all), + MENUEVENT(clear_selection), + + /* view menu*/ + MENUEVENT(expand_all), + MENUEVENT(expand_directories), + MENUEVENT(expand_addresses), + MENUEVENT(collapse_all), + MENUEVENT(collapse_directories), + MENUEVENT(collapse_addresses), + + MENUEVENT(launch), + {NULL, NULL} +}; + +static struct nsgtk_treeview *hotlist_window; +static GladeXML *gladeFile; +GtkWindow *wndHotlist; + + +/* exported interface docuemnted in gtk_hotlist.h */ +bool nsgtk_hotlist_init(const char *glade_file_location) +{ + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; + + gladeFile = glade_xml_new(glade_file_location, NULL, NULL); + if (gladeFile == NULL) + return false; + + glade_xml_signal_autoconnect(gladeFile); + + wndHotlist = GTK_WINDOW(glade_xml_get_widget(gladeFile, "wndHotlist")); + window = wndHotlist; + + scrolled = GTK_SCROLLED_WINDOW(glade_xml_get_widget(gladeFile, + "hotlistScrolled")); + + drawing_area = GTK_DRAWING_AREA(glade_xml_get_widget(gladeFile, + "hotlistDrawingArea")); + + + hotlist_window = nsgtk_treeview_create(hotlist_get_tree_flags(), window, + scrolled, drawing_area); + + if (hotlist_window == NULL) + return false; + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + CONNECT(window, "delete_event", gtk_widget_hide_on_delete, NULL); + CONNECT(window, "hide", nsgtk_tree_window_hide, hotlist_window); + + hotlist_initialise(nsgtk_treeview_get_tree(hotlist_window), + option_hotlist_path, + tree_directory_icon_name); + + nsgtk_hotlist_init_menu(); + + return true; +} + + +/** + * Connects menu events in the hotlist window. + */ +void nsgtk_hotlist_init_menu(void) +{ + struct menu_events *event = menu_events; + + while (event->widget != NULL) + { + GtkWidget *w = glade_xml_get_widget(gladeFile, event->widget); + g_signal_connect(G_OBJECT(w), "activate", event->handler, + hotlist_window); + event++; + } +} + + +/** + * Destroys the hotlist window and performs any other necessary cleanup actions. + */ +void nsgtk_hotlist_destroy(void) +{ + /* TODO: what about gladeFile? */ + hotlist_cleanup(option_hotlist_path); + nsgtk_treeview_destroy(hotlist_window); +} + + +/* file menu*/ +MENUHANDLER(export) +{ + GtkWidget *save_dialog; + save_dialog = gtk_file_chooser_dialog_new("Save File", + wndHotlist, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), + getenv("HOME") ? getenv("HOME") : "/"); + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), + "hotlist.html"); + + if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(save_dialog)); + + hotlist_export(filename); + g_free(filename); + } + + gtk_widget_destroy(save_dialog); + + return TRUE; +} + +MENUHANDLER(new_folder) +{ + hotlist_add_folder(); + return TRUE; +} + +MENUHANDLER(new_entry) +{ + hotlist_add_entry(); + return TRUE; +} + +/* edit menu */ +MENUHANDLER(edit_selected) +{ + hotlist_edit_selected(); + return TRUE; +} + +MENUHANDLER(delete_selected) +{ + hotlist_delete_selected(); + return TRUE; +} + +MENUHANDLER(select_all) +{ + hotlist_select_all(); + return TRUE; +} + +MENUHANDLER(clear_selection) +{ + hotlist_clear_selection(); + return TRUE; +} + +/* view menu*/ +MENUHANDLER(expand_all) +{ + hotlist_expand_all(); + return TRUE; +} + +MENUHANDLER(expand_directories) +{ + hotlist_expand_directories(); + return TRUE; +} + +MENUHANDLER(expand_addresses) +{ + hotlist_expand_addresses(); + return TRUE; +} + +MENUHANDLER(collapse_all) +{ + hotlist_collapse_all(); + return TRUE; +} + +MENUHANDLER(collapse_directories) +{ + hotlist_collapse_directories(); + return TRUE; +} + +MENUHANDLER(collapse_addresses) +{ + hotlist_collapse_addresses(); + return TRUE; +} + +MENUHANDLER(launch) +{ + hotlist_launch_selected(); + return TRUE; +} diff --git a/gtk/hotlist.h b/gtk/hotlist.h new file mode 100644 index 000000000..b2477bc9f --- /dev/null +++ b/gtk/hotlist.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +/** \file + * GTK hotlist (interface). + */ + +#ifndef __NSGTK_HOTLIST_H__ +#define __NSGTK_HOTLIST_H__ + +#include + +extern GtkWindow *wndHotlist; + +/** + * Initialise the gtk specific hotlist (bookmarks) display. + * + * \param glade_hotlist_file_location the path to the glade file for the hotlist + */ +bool nsgtk_hotlist_init(const char *glade_hotlist_file_location); +void nsgtk_hotlist_destroy(void); + +#endif /* __NSGTK_HOTLIST_H__ */ diff --git a/gtk/login.c b/gtk/login.c new file mode 100644 index 000000000..44ef399af --- /dev/null +++ b/gtk/login.c @@ -0,0 +1,183 @@ +/* + * Copyright 2006 Rob Kendrick + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include "utils/log.h" +#include "gtk/gui.h" +#include "content/content.h" +#include "content/hlcache.h" +#include "content/urldb.h" +#include "desktop/browser.h" +#include "desktop/401login.h" +#include "desktop/gui.h" +#include "utils/messages.h" +#include "utils/url.h" +#include "utils/utils.h" + +struct session_401 { + char *url; /**< URL being fetched */ + char *host; /**< Host for user display */ + char *realm; /**< Authentication realm */ + nserror (*cb)(bool proceed, void *pw); /**< Continuation callback */ + void *cbpw; /**< Continuation data */ + GladeXML *x; /**< Our glade windows */ + GtkWindow *wnd; /**< The login window itself */ + GtkEntry *user; /**< Widget with username */ + GtkEntry *pass; /**< Widget with password */ +}; + +static void create_login_window(const char *url, const char *host, + const char *realm, nserror (*cb)(bool proceed, void *pw), + void *cbpw); +static void destroy_login_window(struct session_401 *session); +static void nsgtk_login_next(GtkWidget *w, gpointer data); +static void nsgtk_login_ok_clicked(GtkButton *w, gpointer data); +static void nsgtk_login_cancel_clicked(GtkButton *w, gpointer data); + +void gui_401login_open(const char *url, const char *realm, + nserror (*cb)(bool proceed, void *pw), void *cbpw) +{ + char *host; + url_func_result res; + + res = url_host(url, &host); + assert(res == URL_FUNC_OK); + + create_login_window(url, host, realm, cb, cbpw); + + free(host); +} + +void create_login_window(const char *url, const char *host, const char *realm, + nserror (*cb)(bool proceed, void *pw), void *cbpw) +{ + struct session_401 *session; + + /* create a new instance of the login window, and get handles to all + * the widgets we're interested in. + */ + + GladeXML *x = glade_xml_new(glade_login_file_location, NULL, NULL); + GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndLogin")); + GtkLabel *lhost, *lrealm; + GtkEntry *euser, *epass; + GtkButton *bok, *bcan; + + lhost = GTK_LABEL(glade_xml_get_widget(x, "labelLoginHost")); + lrealm = GTK_LABEL(glade_xml_get_widget(x, "labelLoginRealm")); + euser = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginUser")); + epass = GTK_ENTRY(glade_xml_get_widget(x, "entryLoginPass")); + bok = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginOK")); + bcan = GTK_BUTTON(glade_xml_get_widget(x, "buttonLoginCan")); + + /* create and fill in our session structure */ + + session = calloc(1, sizeof(struct session_401)); + session->url = strdup(url); + session->host = strdup(host); + session->realm = strdup(realm ? realm : "Secure Area"); + session->cb = cb; + session->cbpw = cbpw; + session->x = x; + session->wnd = wnd; + session->user = euser; + session->pass = epass; + + /* fill in our new login window */ + + gtk_label_set_text(GTK_LABEL(lhost), 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)); +} + +void destroy_login_window(struct session_401 *session) +{ + free(session->url); + free(session->host); + free(session->realm); + gtk_widget_destroy(GTK_WIDGET(session->wnd)); + g_object_unref(G_OBJECT(session->x)); + free(session); +} + +void nsgtk_login_next(GtkWidget *w, gpointer data) +{ + gtk_widget_grab_focus(GTK_WIDGET(data)); +} + +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); +} + +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); +} diff --git a/gtk/menu.c b/gtk/menu.c new file mode 100644 index 000000000..99bfde997 --- /dev/null +++ b/gtk/menu.c @@ -0,0 +1,543 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include + +#include +#include +#include + +#include "gtk/menu.h" +#include "utils/messages.h" +#include "utils/utils.h" + +/** + * adds image menu item to specified menu + * \param menu the menu to add the item to + * \param item a pointer to the item's location in the menu struct + * \param message the menu item I18n lookup value + * \param messageAccel the menu item accelerator I18n lookup value + * \param group the 'global' in a gtk sense accelerator group + */ + +static bool nsgtk_menu_add_image_item(GtkMenu *menu, + GtkImageMenuItem **item, const char *message, + const char *messageAccel, GtkAccelGroup *group) +{ + unsigned int key; + GdkModifierType mod; + *item = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic( + messages_get(message))); + if (*item == NULL) + return false; + gtk_accelerator_parse(messages_get(messageAccel), &key, &mod); + if (key > 0) + gtk_widget_add_accelerator(GTK_WIDGET(*item), "activate", + group, key, mod, GTK_ACCEL_VISIBLE); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(*item)); + gtk_widget_show(GTK_WIDGET(*item)); + return true; +} + +#define IMAGE_ITEM(p, q, r, s, t)\ + nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\ + #r "Accel", t) + +#define CHECK_ITEM(p, q, r, s)\ + 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));\ + } + +#define SET_SUBMENU(q, r) \ + do { \ + r->q##_submenu = nsgtk_menu_##q##_submenu(group); \ + if ((r->q##_submenu != NULL) && \ + (r->q##_submenu->q##_menu != NULL) && \ + (r->q##_menuitem != NULL)) { \ + gtk_menu_item_set_submenu(GTK_MENU_ITEM(r->q##_menuitem), \ + GTK_WIDGET(r->q##_submenu->q##_menu)); \ + } \ + } while(0) + +#define ADD_NAMED_SEP(q, r, s) \ + do { \ + s->r##_separator = gtk_separator_menu_item_new(); \ + if ((s->r##_separator != NULL) && (s->q##_menu != NULL)) { \ + gtk_menu_shell_append(GTK_MENU_SHELL(s->q##_menu), s->r##_separator); \ + gtk_widget_show(s->r##_separator); \ + } \ + } while(0) + +#define ADD_SEP(q, r) \ + do { \ + GtkWidget *w = gtk_separator_menu_item_new(); \ + if ((w != NULL) && (r->q##_menu != NULL)) { \ + gtk_menu_shell_append(GTK_MENU_SHELL(r->q##_menu), w); \ + gtk_widget_show(w); \ + } \ + } while(0) + +#define ATTACH_PARENT(parent, msgname, menuv, group) \ + do { \ + if (parent != NULL) { \ + /* create top level menu entry and attach to parent */ \ + menuv = GTK_MENU_ITEM(gtk_menu_item_new_with_mnemonic(messages_get(#msgname))); \ + gtk_menu_shell_append(parent, GTK_WIDGET(menuv)); \ + gtk_widget_show(GTK_WIDGET(menuv)); \ + /* attach submenu to parent */ \ + gtk_menu_item_set_submenu(menuv, GTK_WIDGET(menuv##_menu)); \ + gtk_menu_set_accel_group(menuv##_menu, group); \ + } \ + } while(0) + +/** +* creates an export submenu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *group) +{ + struct nsgtk_export_submenu *ret = malloc(sizeof(struct + nsgtk_export_submenu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->export_menu = GTK_MENU(gtk_menu_new()); + if (ret->export_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + 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; +} + +/** +* creates a scaleview submenu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu( + GtkAccelGroup *group) +{ + struct nsgtk_scaleview_submenu *ret = + malloc(sizeof(struct nsgtk_scaleview_submenu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->scaleview_menu = GTK_MENU(gtk_menu_new()); + if (ret->scaleview_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + IMAGE_ITEM(scaleview, zoomplus, gtkZoomPlus, ret, group); + IMAGE_ITEM(scaleview, zoomnormal, gtkZoomNormal, ret, group); + IMAGE_ITEM(scaleview, zoomminus, gtkZoomMinus, ret, group); + return ret; +} + +/** +* creates a tab navigation submenu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_tabs_submenu *nsgtk_menu_tabs_submenu(GtkAccelGroup *group) +{ + struct nsgtk_tabs_submenu *ret = malloc(sizeof(struct nsgtk_tabs_submenu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->tabs_menu = GTK_MENU(gtk_menu_new()); + if (ret->tabs_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + IMAGE_ITEM(tabs, nexttab, gtkNextTab, ret, group); + IMAGE_ITEM(tabs, prevtab, gtkPrevTab, ret, group); + IMAGE_ITEM(tabs, closetab, gtkCloseTab, ret, 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) +{ + struct nsgtk_images_submenu *ret = + malloc(sizeof(struct nsgtk_images_submenu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->images_menu = GTK_MENU(gtk_menu_new()); + if (ret->images_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + 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) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->toolbars_menu = GTK_MENU(gtk_menu_new()); + if (ret->toolbars_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + 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; +} + +/** +* creates a debugging submenu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_debugging_submenu *nsgtk_menu_debugging_submenu( + GtkAccelGroup *group) +{ + struct nsgtk_debugging_submenu *ret = + malloc(sizeof(struct nsgtk_debugging_submenu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->debugging_menu = GTK_MENU(gtk_menu_new()); + if (ret->debugging_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + IMAGE_ITEM(debugging, toggledebugging, gtkToggleDebugging, ret, group); + IMAGE_ITEM(debugging, saveboxtree, gtkSaveBoxTree, ret, group); + IMAGE_ITEM(debugging, savedomtree, gtkSaveDomTree, ret, group); + return ret; +} + +/** + * creates the file menu + * \param group The gtk 'global' accelerator reference + * \param parent The parent menu to attach to or NULL + */ +static struct nsgtk_file_menu *nsgtk_menu_file_submenu(GtkAccelGroup *group) +{ + struct nsgtk_file_menu *fmenu; + + fmenu = malloc(sizeof(struct nsgtk_file_menu)); + if (fmenu == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + + fmenu->file_menu = GTK_MENU(gtk_menu_new()); + if (fmenu->file_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(fmenu); + return NULL; + } + + IMAGE_ITEM(file, newwindow, gtkNewWindow, fmenu, group); + IMAGE_ITEM(file, newtab, gtkNewTab, fmenu, 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); + IMAGE_ITEM(file, print, gtkPrint, fmenu, group); + ADD_SEP(file, fmenu); + IMAGE_ITEM(file, quit, gtkQuitMenu, fmenu, group); + SET_SUBMENU(export, fmenu); + + return fmenu; +} + +/** +* creates an edit menu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_edit_menu *nsgtk_menu_edit_submenu(GtkAccelGroup *group) +{ + struct nsgtk_edit_menu *ret = malloc(sizeof(struct nsgtk_edit_menu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->edit_menu = GTK_MENU(gtk_menu_new()); + if (ret->edit_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + IMAGE_ITEM(edit, cut, gtkCut, ret, group); + IMAGE_ITEM(edit, copy, gtkCopy, ret, group); + IMAGE_ITEM(edit, paste, gtkPaste, ret, group); + IMAGE_ITEM(edit, delete, gtkDelete, ret, group); + ADD_SEP(edit, ret); + IMAGE_ITEM(edit, selectall, gtkSelectAll, ret, group); + ADD_SEP(edit, ret); + IMAGE_ITEM(edit, find, gtkFind, ret, group); + ADD_SEP(edit, ret); + IMAGE_ITEM(edit, preferences, gtkPreferences, ret, group); + + return ret; +} + +/** +* creates a view menu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_view_menu *nsgtk_menu_view_submenu(GtkAccelGroup *group) +{ + struct nsgtk_view_menu *ret = malloc(sizeof(struct nsgtk_view_menu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->view_menu = GTK_MENU(gtk_menu_new()); + if (ret->view_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + 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); + IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group); + IMAGE_ITEM(view, viewsource, gtkViewSource, ret, group); + ADD_SEP(view, ret); + IMAGE_ITEM(view, images, gtkImages, ret, group); + IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group); + IMAGE_ITEM(view, tabs, gtkTabs, ret, group); + ADD_SEP(view, ret); + IMAGE_ITEM(view, downloads, gtkDownloads, ret, group); + IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group); + IMAGE_ITEM(view, debugging, gtkDebugging, ret, group); + SET_SUBMENU(scaleview, ret); + SET_SUBMENU(images, ret); + SET_SUBMENU(toolbars, ret); + SET_SUBMENU(tabs, ret); + SET_SUBMENU(debugging, ret); + + + return ret; +} + +/** +* creates a nav menu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_nav_menu *nsgtk_menu_nav_submenu(GtkAccelGroup *group) +{ + struct nsgtk_nav_menu *ret = malloc(sizeof(struct nsgtk_nav_menu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->nav_menu = GTK_MENU(gtk_menu_new()); + if (ret->nav_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + + IMAGE_ITEM(nav, back, gtkBack, ret, group); + IMAGE_ITEM(nav, forward, gtkForward, ret, group); + IMAGE_ITEM(nav, home, gtkHome, ret, group); + ADD_SEP(nav, ret); + IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group); + IMAGE_ITEM(nav, globalhistory, gtkGlobalHistory, ret, group); + ADD_SEP(nav, ret); + IMAGE_ITEM(nav, addbookmarks, gtkAddBookMarks, ret, group); + IMAGE_ITEM(nav, showbookmarks, gtkShowBookMarks, ret, group); + ADD_SEP(nav, ret); + IMAGE_ITEM(nav, showcookies, gtkShowCookies, ret, group); + ADD_SEP(nav, ret); + IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group); + + + return ret; +} + +/** +* creates a help menu +* \param group the 'global' in a gtk sense accelerator reference +*/ + +static struct nsgtk_help_menu *nsgtk_menu_help_submenu(GtkAccelGroup *group) +{ + struct nsgtk_help_menu *ret = malloc(sizeof(struct nsgtk_help_menu)); + if (ret == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + ret->help_menu = GTK_MENU(gtk_menu_new()); + if (ret->help_menu == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(ret); + return NULL; + } + IMAGE_ITEM(help, contents, gtkContents, ret, group); + IMAGE_ITEM(help, guide, gtkGuide, ret, group); + IMAGE_ITEM(help, info, gtkUserInformation, ret, group); + ADD_SEP(help, ret); + IMAGE_ITEM(help, about, gtkAbout, ret, group); + + return ret; +} + + +/** + * Generate menubar menus. + * + * Generate the main menu structure and attach it to a menubar widget. + */ +struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkWindow *window) +{ + GtkAccelGroup *group; + struct nsgtk_bar_submenu *nmenu; + + nmenu = malloc(sizeof(struct nsgtk_bar_submenu)); + if (nmenu == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + + nmenu->bar_menu = GTK_MENU_BAR(menubar); + + group = gtk_accel_group_new(); + gtk_window_add_accel_group(window, group); + + nmenu->file_submenu = nsgtk_menu_file_submenu(group); + ATTACH_PARENT(menubar, gtkFile, nmenu->file_submenu->file, group); + + nmenu->edit_submenu = nsgtk_menu_edit_submenu(group); + ATTACH_PARENT(menubar, gtkEdit, nmenu->edit_submenu->edit, group); + + nmenu->view_submenu = nsgtk_menu_view_submenu(group); + ATTACH_PARENT(menubar, gtkView, nmenu->view_submenu->view, group); + + nmenu->nav_submenu = nsgtk_menu_nav_submenu(group); + ATTACH_PARENT(menubar, gtkNavigate, nmenu->nav_submenu->nav, group); + + nmenu->help_submenu = nsgtk_menu_help_submenu(group); + ATTACH_PARENT(menubar, gtkHelp, nmenu->help_submenu->help, group); + + return nmenu; +} + +/** + * Generate right click menu menu. + * + */ +struct nsgtk_popup_submenu *nsgtk_menu_popup_create(GtkWindow *window) +{ + GtkAccelGroup *group; + struct nsgtk_popup_submenu *nmenu; + + nmenu = malloc(sizeof(struct nsgtk_popup_submenu)); + if (nmenu == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + + group = gtk_accel_group_new(); + gtk_window_add_accel_group(window, group); + + nmenu->popup_menu = GTK_MENU(gtk_menu_new()); + + IMAGE_ITEM(popup, file, gtkFile, nmenu, group); + SET_SUBMENU(file, nmenu); + + IMAGE_ITEM(popup, edit, gtkEdit, nmenu, group); + SET_SUBMENU(edit, nmenu); + + IMAGE_ITEM(popup, view, gtkView, nmenu, group); + SET_SUBMENU(view, nmenu); + + IMAGE_ITEM(popup, nav, gtkNavigate, nmenu, group); + SET_SUBMENU(nav, nmenu); + + IMAGE_ITEM(popup, help, gtkHelp, nmenu, group); + SET_SUBMENU(help, nmenu); + + ADD_NAMED_SEP(popup, first, nmenu); + + IMAGE_ITEM(popup, opentab, gtkOpentab, nmenu, group); + IMAGE_ITEM(popup, openwin, gtkOpenwin, nmenu, group); + IMAGE_ITEM(popup, savelink, gtkSavelink, nmenu, group); + + ADD_NAMED_SEP(popup, second, nmenu); + + IMAGE_ITEM(popup, back, gtkBack, nmenu, group); + IMAGE_ITEM(popup, forward, gtkForward, nmenu, group); + + ADD_NAMED_SEP(popup, third, nmenu); + + IMAGE_ITEM(popup, stop, gtkStop, nmenu, group); + IMAGE_ITEM(popup, reload, gtkReload, nmenu, group); + 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); + + + return nmenu; +} diff --git a/gtk/menu.h b/gtk/menu.h new file mode 100644 index 000000000..84faa5f71 --- /dev/null +++ b/gtk/menu.h @@ -0,0 +1,195 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ +#ifndef _NETSURF_GTK_MENU_H_ +#define _NETSURF_GTK_MENU_H_ + +#include + +struct nsgtk_file_menu { + GtkMenuItem *file; /* File menu item on menubar */ + GtkMenu *file_menu; + GtkImageMenuItem *newwindow_menuitem; + GtkImageMenuItem *newtab_menuitem; + GtkImageMenuItem *openfile_menuitem; + GtkImageMenuItem *closewindow_menuitem; + GtkImageMenuItem *savepage_menuitem; + GtkImageMenuItem *export_menuitem; + struct nsgtk_export_submenu *export_submenu; + GtkImageMenuItem *printpreview_menuitem; + GtkImageMenuItem *print_menuitem; + GtkImageMenuItem *quit_menuitem; +}; + +struct nsgtk_edit_menu { + GtkMenuItem *edit; /* Edit menu item on menubar */ + GtkMenu *edit_menu; + GtkImageMenuItem *cut_menuitem; + GtkImageMenuItem *copy_menuitem; + GtkImageMenuItem *paste_menuitem; + GtkImageMenuItem *delete_menuitem; + GtkImageMenuItem *selectall_menuitem; + GtkImageMenuItem *find_menuitem; + GtkImageMenuItem *preferences_menuitem; +}; + +struct nsgtk_view_menu { + GtkMenuItem *view; /* View menu item on menubar */ + GtkMenu *view_menu; /* gtk menu attached to menu item */ + GtkImageMenuItem *stop_menuitem; + GtkImageMenuItem *reload_menuitem; + GtkImageMenuItem *scaleview_menuitem; + struct nsgtk_scaleview_submenu *scaleview_submenu; + GtkImageMenuItem *fullscreen_menuitem; + GtkImageMenuItem *viewsource_menuitem; + GtkImageMenuItem *images_menuitem; + struct nsgtk_images_submenu *images_submenu; + GtkImageMenuItem *toolbars_menuitem; + struct nsgtk_toolbars_submenu *toolbars_submenu; + GtkImageMenuItem *tabs_menuitem; + struct nsgtk_tabs_submenu *tabs_submenu; + GtkImageMenuItem *downloads_menuitem; + GtkImageMenuItem *savewindowsize_menuitem; + GtkImageMenuItem *debugging_menuitem; + struct nsgtk_debugging_submenu *debugging_submenu; +}; + +struct nsgtk_nav_menu { + GtkMenuItem *nav; /* Nav menu item on menubar */ + GtkMenu *nav_menu; + GtkImageMenuItem *back_menuitem; + GtkImageMenuItem *forward_menuitem; + GtkImageMenuItem *home_menuitem; + GtkImageMenuItem *localhistory_menuitem; + GtkImageMenuItem *globalhistory_menuitem; + GtkImageMenuItem *addbookmarks_menuitem; + GtkImageMenuItem *showbookmarks_menuitem; + GtkImageMenuItem *showcookies_menuitem; + GtkImageMenuItem *openlocation_menuitem; +}; + +struct nsgtk_help_menu { + GtkMenuItem *help; /* Help menu item on menubar */ + GtkMenu *help_menu; + GtkImageMenuItem *contents_menuitem; + GtkImageMenuItem *guide_menuitem; + GtkImageMenuItem *info_menuitem; + GtkImageMenuItem *about_menuitem; +}; + +struct nsgtk_export_submenu { + GtkMenu *export_menu; + GtkImageMenuItem *plaintext_menuitem; + GtkImageMenuItem *drawfile_menuitem; + GtkImageMenuItem *postscript_menuitem; + GtkImageMenuItem *pdf_menuitem; +}; + +struct nsgtk_scaleview_submenu { + GtkMenu *scaleview_menu; + GtkImageMenuItem *zoomplus_menuitem; + GtkImageMenuItem *zoomminus_menuitem; + GtkImageMenuItem *zoomnormal_menuitem; +}; + +struct nsgtk_tabs_submenu { + GtkMenu *tabs_menu; + GtkImageMenuItem *nexttab_menuitem; + GtkImageMenuItem *prevtab_menuitem; + GtkImageMenuItem *closetab_menuitem; +}; + +struct nsgtk_images_submenu { + GtkMenu *images_menu; + GtkCheckMenuItem *foregroundimages_menuitem; + GtkCheckMenuItem *backgroundimages_menuitem; +}; + +struct nsgtk_toolbars_submenu { + GtkMenu *toolbars_menu; + GtkCheckMenuItem *menubar_menuitem; + GtkCheckMenuItem *toolbar_menuitem; +}; + +struct nsgtk_debugging_submenu { + GtkMenu *debugging_menu; + GtkImageMenuItem *toggledebugging_menuitem; + GtkImageMenuItem *saveboxtree_menuitem; + GtkImageMenuItem *savedomtree_menuitem; +}; + + +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_menu *tabs_submenu; + struct nsgtk_help_menu *help_submenu; +}; + +struct nsgtk_popup_submenu { + GtkMenu *popup_menu; + + GtkImageMenuItem *file_menuitem; + struct nsgtk_file_menu *file_submenu; + + GtkImageMenuItem *edit_menuitem; + struct nsgtk_edit_menu *edit_submenu; + + GtkImageMenuItem *view_menuitem; + struct nsgtk_view_menu *view_submenu; + + GtkImageMenuItem *nav_menuitem; + struct nsgtk_nav_menu *nav_submenu; + + GtkImageMenuItem *tabs_menuitem; + struct nsgtk_tabs_menu *tabs_submenu; + + GtkImageMenuItem *help_menuitem; + struct nsgtk_help_menu *help_submenu; + + GtkWidget *first_separator; + + GtkImageMenuItem *opentab_menuitem; + GtkImageMenuItem *openwin_menuitem; + GtkImageMenuItem *savelink_menuitem; + + GtkWidget *second_separator; + + /* navigation entries */ + GtkImageMenuItem *back_menuitem; + GtkImageMenuItem *forward_menuitem; + + GtkWidget *third_separator; + + /* view entries */ + GtkImageMenuItem *stop_menuitem; + GtkImageMenuItem *reload_menuitem; + + GtkImageMenuItem *cut_menuitem; + GtkImageMenuItem *copy_menuitem; + GtkImageMenuItem *paste_menuitem; + GtkImageMenuItem *customize_menuitem; + +}; + +struct nsgtk_bar_submenu *nsgtk_menu_bar_create(GtkMenuShell *menubar, GtkWindow *window); +struct nsgtk_popup_submenu *nsgtk_menu_popup_create(GtkWindow *window); + +#endif diff --git a/gtk/plotters.c b/gtk/plotters.c new file mode 100644 index 000000000..460a65a6f --- /dev/null +++ b/gtk/plotters.c @@ -0,0 +1,570 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Target independent plotting (GDK / GTK+ and Cairo implementation). + * Can use either GDK drawing primitives (which are mostly passed straight + * to X to process, and thus accelerated) or Cairo drawing primitives (much + * higher quality, not accelerated). Cairo's fast enough, so it defaults + * to using it if it is available. It does this by checking for the + * CAIRO_VERSION define that the cairo headers set. + */ + +#include +#include +#include +#include + +#include "utils/log.h" +#include "desktop/plotters.h" +#include "gtk/font_pango.h" +#include "gtk/plotters.h" +#include "gtk/scaffolding.h" +#include "render/font.h" +#include "desktop/options.h" +#include "gtk/options.h" +#include "gtk/bitmap.h" + +#ifndef CAIRO_VERSION +#error "nsgtk requires cairo" +#endif + +GtkWidget *current_widget; +GdkDrawable *current_drawable; +GdkGC *current_gc; +cairo_t *current_cr; + +static GdkRectangle cliprect; +static float nsgtk_plot_scale = 1.0; + +struct plotter_table plot; + +/** set plotting scale factor. */ +void nsgtk_plot_set_scale(float s) +{ + nsgtk_plot_scale = s; +} + +/** get plotting scale factor. */ +float nsgtk_plot_get_scale(void) +{ + return nsgtk_plot_scale; +} + +/** Set cairo context colour to nsgtk colour. */ +void nsgtk_set_colour(colour c) +{ + int r, g, b; + GdkColor colour; + + r = c & 0xff; + g = (c & 0xff00) >> 8; + b = (c & 0xff0000) >> 16; + + colour.red = r | (r << 8); + colour.green = g | (g << 8); + colour.blue = b | (b << 8); + colour.pixel = (r << 16) | (g << 8) | b; + + gdk_color_alloc(gdk_colormap_get_system(), + &colour); + gdk_gc_set_foreground(current_gc, &colour); + + cairo_set_source_rgba(current_cr, r / 255.0, + g / 255.0, b / 255.0, 1.0); +} + +/** Plot a caret. + * + * @note It is assumed that the plotters have been set up. + */ +void nsgtk_plot_caret(int x, int y, int h) +{ + GdkColor colour; + + colour.red = 0; + colour.green = 0; + colour.blue = 0; + colour.pixel = 0; + gdk_color_alloc(gdk_colormap_get_system(), + &colour); + gdk_gc_set_foreground(current_gc, &colour); + + gdk_draw_line(current_drawable, current_gc, + x, y, + x, y + h - 1); +} + +/** Set cairo context to solid plot operation. */ +static inline void nsgtk_set_solid(void) +{ + double dashes = 0; + cairo_set_dash(current_cr, &dashes, 0, 0); +} + +/** Set cairo context to dotted plot operation. */ +static inline void nsgtk_set_dotted(void) +{ + double cdashes[] = { 1.0, 2.0 }; + cairo_set_dash(current_cr, cdashes, 2, 0); +} + +/** Set cairo context to dashed plot operation. */ +static inline void nsgtk_set_dashed(void) +{ + double cdashes[] = { 8.0, 2.0 }; + cairo_set_dash(current_cr, cdashes, 2, 0); +} + +/** Set clipping area for subsequent plot operations. */ +static bool nsgtk_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1) +{ + cairo_reset_clip(current_cr); + cairo_rectangle(current_cr, clip_x0, clip_y0, + clip_x1 - clip_x0, clip_y1 - clip_y0); + cairo_clip(current_cr); + + cliprect.x = clip_x0; + cliprect.y = clip_y0; + cliprect.width = clip_x1 - clip_x0; + cliprect.height = clip_y1 - clip_y0; + gdk_gc_set_clip_rectangle(current_gc, &cliprect); + + return true; +} + + +static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) +{ + nsgtk_set_colour(style->fill_colour); + nsgtk_set_solid(); + + cairo_set_line_width(current_cr, 1); + cairo_arc(current_cr, x, y, radius, + (angle1 + 90) * (M_PI / 180), + (angle2 + 90) * (M_PI / 180)); + cairo_stroke(current_cr); + + return true; +} + +static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style) +{ + if (style->fill_type != PLOT_OP_TYPE_NONE) { + nsgtk_set_colour(style->fill_colour); + nsgtk_set_solid(); + cairo_set_line_width(current_cr, 0); + cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); + cairo_fill(current_cr); + cairo_stroke(current_cr); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + nsgtk_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_set_dashed(); + break; + } + + if (style->stroke_width == 0) + cairo_set_line_width(current_cr, 1); + else + cairo_set_line_width(current_cr, style->stroke_width); + + cairo_arc(current_cr, x, y, radius, 0, M_PI * 2); + + cairo_stroke(current_cr); + } + + return true; +} + +static bool nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) +{ + + nsgtk_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_set_dashed(); + break; + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + 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); + + /* core expects horizontal and vertical lines to be on pixels, not + * between pixels */ + cairo_move_to(current_cr, (x0 == x1) ? x0 + 0.5 : x0, + (y0 == y1) ? y0 + 0.5 : y0); + cairo_line_to(current_cr, (x0 == x1) ? x1 + 0.5 : x1, + (y0 == y1) ? y1 + 0.5 : y1); + cairo_stroke(current_cr); + + return true; +} + + +static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) +{ + if (style->fill_type != PLOT_OP_TYPE_NONE) { + nsgtk_set_colour(style->fill_colour); + nsgtk_set_solid(); + + cairo_set_line_width(current_cr, 0); + cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_fill(current_cr); + cairo_stroke(current_cr); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + nsgtk_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_set_dashed(); + break; + } + + if (style->stroke_width == 0) + cairo_set_line_width(current_cr, 1); + else + cairo_set_line_width(current_cr, style->stroke_width); + + cairo_rectangle(current_cr, x0 + 0.5, y0 + 0.5, x1 - x0, y1 - y0); + cairo_stroke(current_cr); + } + return true; +} + +static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) +{ + unsigned int i; + + nsgtk_set_colour(style->fill_colour); + nsgtk_set_solid(); + + cairo_set_line_width(current_cr, 0); + cairo_move_to(current_cr, p[0], p[1]); + for (i = 1; i != n; i++) { + cairo_line_to(current_cr, p[i * 2], p[i * 2 + 1]); + } + cairo_fill(current_cr); + cairo_stroke(current_cr); + + return true; +} + + + + +static bool nsgtk_plot_text(int x, int y, const char *text, size_t length, + const plot_font_style_t *fstyle) +{ + return nsfont_paint(x, y, text, length, fstyle); +} + + + +static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, + GdkPixbuf *pixbuf, colour bg) +{ + /* XXX: This currently ignores the background colour supplied. + * Does this matter? + */ + + int x0, y0, x1, y1; + int dsrcx, dsrcy, dwidth, dheight; + + /* Bail early if we can */ + if (width == 0 || height == 0) + /* Nothing to plot */ + return true; + if ((x > (cliprect.x + cliprect.width)) || + ((x + width) < cliprect.x) || + (y > (cliprect.y + cliprect.height)) || + ((y + height) < cliprect.y)) { + /* Image completely outside clip region */ + return true; + } + + /* Get clip rectangle / image rectangle edge differences */ + x0 = cliprect.x - x; + y0 = cliprect.y - y; + x1 = (x + width) - (cliprect.x + cliprect.width); + y1 = (y + height) - (cliprect.y + cliprect.height); + + /* Set initial draw geometry */ + dsrcx = dsrcy = 0; + dwidth = width; + dheight = height; + + /* Manually clip draw coordinates to area of image to be rendered */ + if (x0 > 0) { + /* Clip left */ + dsrcx = x0; + x += x0; + dwidth -= x0; + } + if (y0 > 0) { + /* Clip top */ + dsrcy = y0; + y += y0; + dheight -= y0; + } + if (x1 > 0) { + /* Clip right */ + dwidth -= x1; + } + if (y1 > 0) { + /* Clip bottom */ + dheight -= y1; + } + + if (dwidth == 0 || dheight == 0) + /* Nothing to plot */ + return true; + + /* Render the bitmap */ + if (gdk_pixbuf_get_width(pixbuf) == width && + gdk_pixbuf_get_height(pixbuf) == height) { + /* Bitmap is not scaled */ + /* Plot the bitmap */ + gdk_draw_pixbuf(current_drawable, current_gc, pixbuf, + dsrcx, dsrcy, x, y, dwidth, dheight, + GDK_RGB_DITHER_MAX, 0, 0); + + } else { + /* Bitmap is scaled */ + /* Get scale factors */ + double sx = (double)width / gdk_pixbuf_get_width(pixbuf); + double sy = (double)height / gdk_pixbuf_get_height(pixbuf); + + /* Create bitmap for scaled image portion */ + GdkPixbuf *scaled = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, + dwidth, dheight); + /* Only scale up the portion of the bitmap that we are + * interested in rendering */ + gdk_pixbuf_scale(pixbuf, scaled, + 0, 0, dwidth, dheight, + -dsrcx, -dsrcy, sx, sy, + option_render_resample ? GDK_INTERP_BILINEAR : + GDK_INTERP_NEAREST); + if (!scaled) + return false; + + /* Plot the scaled bitmap */ + gdk_draw_pixbuf(current_drawable, current_gc, scaled, + 0, 0, x, y, dwidth, dheight, + GDK_RGB_DITHER_MAX, 0, 0); + + g_object_unref(scaled); + } + + return true; +} + +static bool nsgtk_plot_bitmap(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bitmap_flags_t flags) +{ + int doneheight = 0, donewidth = 0; + GdkPixbuf *primary; + GdkPixbuf *pretiled = NULL; + + bool repeat_x = (flags & BITMAPF_REPEAT_X); + bool repeat_y = (flags & BITMAPF_REPEAT_Y); + + if (!(repeat_x || repeat_y)) { + /* Not repeating at all, so just pass it on */ + primary = gtk_bitmap_get_primary(bitmap); + return nsgtk_plot_pixbuf(x, y, width, height, primary, bg); + } + + if (repeat_x && !repeat_y) + pretiled = gtk_bitmap_get_pretile_x(bitmap); + if (repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_xy(bitmap); + if (!repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_y(bitmap); + + assert(pretiled != NULL); + + primary = gtk_bitmap_get_primary(bitmap); + /* use the primary and pretiled widths to scale the w/h provided */ + width *= gdk_pixbuf_get_width(pretiled); + width /= gdk_pixbuf_get_width(primary); + height *= gdk_pixbuf_get_height(pretiled); + height /= gdk_pixbuf_get_height(primary); + + if (y > cliprect.y) + doneheight = (cliprect.y - height) + ((y - cliprect.y) % height); + else + doneheight = y; + + while (doneheight < (cliprect.y + cliprect.height)) { + if (x > cliprect.x) + donewidth = (cliprect.x - width) + ((x - cliprect.x) % width); + else + donewidth = x; + while (donewidth < (cliprect.x + cliprect.width)) { + nsgtk_plot_pixbuf(donewidth, doneheight, + width, height, pretiled, bg); + donewidth += width; + if (!repeat_x) break; + } + doneheight += height; + if (!repeat_y) break; + } + + return true; +} + +static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float width, + colour c, const float transform[6]) +{ + unsigned int i; + cairo_matrix_t old_ctm, n_ctm; + + if (n == 0) + return true; + + if (p[0] != PLOTTER_PATH_MOVE) { + LOG(("Path does not start with move")); + return false; + } + + + /* Save CTM */ + cairo_get_matrix(current_cr, &old_ctm); + + /* Set up line style and width */ + cairo_set_line_width(current_cr, 1); + nsgtk_set_solid(); + + /* Load new CTM */ + n_ctm.xx = transform[0]; + 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]; + + cairo_set_matrix(current_cr, &n_ctm); + + /* Construct path */ + for (i = 0; i < n; ) { + if (p[i] == PLOTTER_PATH_MOVE) { + cairo_move_to(current_cr, p[i+1], p[i+2]); + i += 3; + } else if (p[i] == PLOTTER_PATH_CLOSE) { + cairo_close_path(current_cr); + i++; + } else if (p[i] == PLOTTER_PATH_LINE) { + cairo_line_to(current_cr, p[i+1], p[i+2]); + i += 3; + } else if (p[i] == PLOTTER_PATH_BEZIER) { + cairo_curve_to(current_cr, p[i+1], p[i+2], + p[i+3], p[i+4], + p[i+5], p[i+6]); + i += 7; + } else { + LOG(("bad path command %f", p[i])); + /* Reset matrix for safety */ + cairo_set_matrix(current_cr, &old_ctm); + return false; + } + } + + /* Restore original CTM */ + cairo_set_matrix(current_cr, &old_ctm); + + /* Now draw path */ + if (fill != NS_TRANSPARENT) { + nsgtk_set_colour(fill); + + if (c != NS_TRANSPARENT) { + /* Fill & Stroke */ + cairo_fill_preserve(current_cr); + nsgtk_set_colour(c); + cairo_stroke(current_cr); + } else { + /* Fill only */ + cairo_fill(current_cr); + } + } else if (c != NS_TRANSPARENT) { + /* Stroke only */ + nsgtk_set_colour(c); + cairo_stroke(current_cr); + } + + return true; +} + +/** GTK plotter table */ +const struct plotter_table nsgtk_plotters = { + .clip = nsgtk_plot_clip, + .arc = nsgtk_plot_arc, + .disc = nsgtk_plot_disc, + .line = nsgtk_plot_line, + .rectangle = nsgtk_plot_rectangle, + .polygon = nsgtk_plot_polygon, + .path = nsgtk_plot_path, + .bitmap = nsgtk_plot_bitmap, + .text = nsgtk_plot_text, + .option_knockout = true +}; + + + diff --git a/gtk/plotters.h b/gtk/plotters.h new file mode 100644 index 000000000..a59ae00bb --- /dev/null +++ b/gtk/plotters.h @@ -0,0 +1,46 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +/** \file + * Target independent plotting (GDK / GTK+ interface). + */ + +#ifndef NETSURF_GTK_PLOTTERS_H +#define NETSURF_GTK_PLOTTERS_H 1 + +#include + +struct plotter_table; + +extern const struct plotter_table nsgtk_plotters; + +/* make sure this is NULL if no redraw is in progress */ +extern GtkWidget *current_widget; +extern GdkDrawable *current_drawable; +extern GdkGC *current_gc; +#ifdef CAIRO_VERSION +extern cairo_t *current_cr; +#endif + +void nsgtk_plot_set_scale(float s); +float nsgtk_plot_get_scale(void); +void nsgtk_set_colour(colour c); +void nsgtk_plot_caret(int x, int y, int h); + +#endif /* NETSURF_GTK_PLOTTERS_H */ + diff --git a/gtk/print.c b/gtk/print.c new file mode 100644 index 000000000..5f518e266 --- /dev/null +++ b/gtk/print.c @@ -0,0 +1,543 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2005 James Bursa + * Copyright 2008 Adam Blokus + * + * 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 . + */ + /** \file + * GTK printing (implementation). + * All the functions and structures necessary for printing( signal handlers, + * plotters, printer) are here. + * Most of the plotters have been copied from the gtk_plotters.c file. + */ + +#include "utils/config.h" + +#include +#include +#include +#include + +#include "content/content.h" +#include "content/hlcache.h" +#include "desktop/options.h" +#include "desktop/plotters.h" +#include "desktop/print.h" +#include "desktop/printer.h" +#include "gtk/font_pango.h" +#include "gtk/bitmap.h" +#include "gtk/print.h" +#include "gtk/scaffolding.h" +#include "gtk/options.h" +#include "render/font.h" +#include "utils/log.h" +#include "utils/utils.h" + +/* Globals */ +cairo_t *gtk_print_current_cr; +static struct print_settings* settings; +hlcache_handle *content_to_print; +static GdkRectangle cliprect; + +static inline void nsgtk_print_set_colour(colour c) +{ + int r, g, b; + GdkColor colour; + + r = c & 0xff; + g = (c & 0xff00) >> 8; + b = (c & 0xff0000) >> 16; + + colour.red = r | (r << 8); + colour.green = g | (g << 8); + colour.blue = b | (b << 8); + colour.pixel = (r << 16) | (g << 8) | b; + + gdk_color_alloc(gdk_colormap_get_system(), &colour); + + cairo_set_source_rgba(gtk_print_current_cr, r / 255.0, + g / 255.0, b / 255.0, 1.0); +} + +static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height, + GdkPixbuf *pixbuf, colour bg) +{ + /* XXX: This currently ignores the background colour supplied. + * Does this matter? + */ + + if (width == 0 || height == 0) + return true; + + if (gdk_pixbuf_get_width(pixbuf) == width && + gdk_pixbuf_get_height(pixbuf) == height) { + gdk_cairo_set_source_pixbuf(gtk_print_current_cr, pixbuf, x, y); + cairo_paint(gtk_print_current_cr); + } else { + GdkPixbuf *scaled; + scaled = gdk_pixbuf_scale_simple(pixbuf, + width, height, + /* plotting for the printer doesn't have + * to be fast so we can use always the + * interp_style that gives better quality + */ + GDK_INTERP_BILINEAR); + if (!scaled) + return false; + + gdk_cairo_set_source_pixbuf(gtk_print_current_cr, scaled, x, y); + cairo_paint(gtk_print_current_cr); + + g_object_unref(scaled); + } + + return true; +} + + +static bool gtk_print_font_paint(int x, int y, + const char *string, size_t length, + const plot_font_style_t *fstyle) +{ + PangoFontDescription *desc; + PangoLayout *layout; + gint size; + PangoLayoutLine *line; + + if (length == 0) + return true; + + desc = nsfont_style_to_description(fstyle); + size = (gint) ((double) pango_font_description_get_size(desc) * + settings->scale); + + if (pango_font_description_get_size_is_absolute(desc)) + pango_font_description_set_absolute_size(desc, size); + else + pango_font_description_set_size(desc, size); + + layout = pango_cairo_create_layout(gtk_print_current_cr); + + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, string, length); + + line = pango_layout_get_line(layout, 0); + + cairo_move_to(gtk_print_current_cr, x, y); + nsgtk_print_set_colour(fstyle->foreground); + pango_cairo_show_layout_line(gtk_print_current_cr, line); + + g_object_unref(layout); + pango_font_description_free(desc); + + return true; +} + + +/** Set cairo context to solid plot operation. */ +static inline void nsgtk_print_set_solid(void) +{ + double dashes = 0; + cairo_set_dash(gtk_print_current_cr, &dashes, 0, 0); +} + +/** Set cairo context to dotted plot operation. */ +static inline void nsgtk_print_set_dotted(void) +{ + double cdashes[] = { 1.0, 2.0 }; + cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); +} + +/** Set cairo context to dashed plot operation. */ +static inline void nsgtk_print_set_dashed(void) +{ + double cdashes[] = { 8.0, 2.0 }; + cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); +} + +/** Set clipping area for subsequent plot operations. */ +static bool nsgtk_print_plot_clip(int clip_x0, int clip_y0, int clip_x1, int clip_y1) +{ + LOG(("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", + clip_x0,clip_y0,clip_x1,clip_y1)); + + /* Normalize cllipping area - to prevent overflows. + * See comment in pdf_plot_fill. */ + clip_x0 = min(max(clip_x0, 0), settings->page_width); + clip_y0 = min(max(clip_y0, 0), settings->page_height); + clip_x1 = min(max(clip_x1, 0), settings->page_width); + clip_y1 = min(max(clip_y1, 0), settings->page_height); + + cairo_reset_clip(gtk_print_current_cr); + cairo_rectangle(gtk_print_current_cr, clip_x0, clip_y0, + clip_x1 - clip_x0, clip_y1 - clip_y0); + cairo_clip(gtk_print_current_cr); + + cliprect.x = clip_x0; + cliprect.y = clip_y0; + cliprect.width = clip_x1 - clip_x0; + cliprect.height = clip_y1 - clip_y0; + + return true; +} + +static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) +{ + nsgtk_print_set_colour(style->fill_colour); + nsgtk_print_set_solid(); + + cairo_set_line_width(gtk_print_current_cr, 1); + cairo_arc(gtk_print_current_cr, x, y, radius, + (angle1 + 90) * (M_PI / 180), + (angle2 + 90) * (M_PI / 180)); + cairo_stroke(gtk_print_current_cr); + + return true; +} + +static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *style) +{ + if (style->fill_type != PLOT_OP_TYPE_NONE) { + nsgtk_print_set_colour(style->fill_colour); + nsgtk_print_set_solid(); + cairo_set_line_width(gtk_print_current_cr, 0); + cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2); + cairo_fill(gtk_print_current_cr); + cairo_stroke(gtk_print_current_cr); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + nsgtk_print_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_print_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_print_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_print_set_dashed(); + 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); + + cairo_arc(gtk_print_current_cr, x, y, radius, 0, M_PI * 2); + + cairo_stroke(gtk_print_current_cr); + } + return true; +} + +static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) +{ + nsgtk_print_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_print_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_print_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_print_set_dashed(); + 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); + + cairo_move_to(gtk_print_current_cr, x0 + 0.5, y0 + 0.5); + cairo_line_to(gtk_print_current_cr, x1 + 0.5, y1 + 0.5); + cairo_stroke(gtk_print_current_cr); + + return true; +} + +static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) +{ + LOG(("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0,y0,x1,y1)); + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + + nsgtk_print_set_colour(style->fill_colour); + nsgtk_print_set_solid(); + + /* Normalize boundaries of the area - to prevent overflows. + * See comment in pdf_plot_fill. */ + x0 = min(max(x0, 0), settings->page_width); + y0 = min(max(y0, 0), settings->page_height); + x1 = min(max(x1, 0), settings->page_width); + y1 = min(max(y1, 0), settings->page_height); + + cairo_set_line_width(gtk_print_current_cr, 0); + cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_fill(gtk_print_current_cr); + cairo_stroke(gtk_print_current_cr); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + nsgtk_print_set_colour(style->stroke_colour); + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + nsgtk_print_set_solid(); + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + nsgtk_print_set_dotted(); + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + nsgtk_print_set_dashed(); + 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); + + cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_stroke(gtk_print_current_cr); + } + + return true; +} + +static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) +{ + unsigned int i; + + LOG(("Plotting polygon.")); + + nsgtk_print_set_colour(style->fill_colour); + nsgtk_print_set_solid(); + + cairo_set_line_width(gtk_print_current_cr, 0); + cairo_move_to(gtk_print_current_cr, p[0], p[1]); + + LOG(("Starting line at: %i\t%i",p[0],p[1])); + + for (i = 1; i != n; i++) { + cairo_line_to(gtk_print_current_cr, p[i * 2], p[i * 2 + 1]); + LOG(("Drawing line to: %i\t%i",p[i * 2], p[i * 2 + 1])); + } + + cairo_fill(gtk_print_current_cr); + cairo_stroke(gtk_print_current_cr); + + return true; +} + + +static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill, + float width, colour c, const float transform[6]) +{ + /* Only the internal SVG renderer uses this plot call currently, + * and the GTK version uses librsvg. Thus, we ignore this complexity, + * and just return true obliviously. */ + + return true; +} + +static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg, + bitmap_flags_t flags) +{ + int doneheight = 0, donewidth = 0; + GdkPixbuf *primary; + GdkPixbuf *pretiled = NULL; + + bool repeat_x = (flags & BITMAPF_REPEAT_X); + bool repeat_y = (flags & BITMAPF_REPEAT_Y); + + if (!(repeat_x || repeat_y)) { + /* Not repeating at all, so just pass it on */ + primary = gtk_bitmap_get_primary(bitmap); + return nsgtk_print_plot_pixbuf(x, y, width, height, primary, bg); + } + + if (repeat_x && !repeat_y) + pretiled = gtk_bitmap_get_pretile_x(bitmap); + if (repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_xy(bitmap); + if (!repeat_x && repeat_y) + pretiled = gtk_bitmap_get_pretile_y(bitmap); + + assert(pretiled != NULL); + + primary = gtk_bitmap_get_primary(bitmap); + + /* use the primary and pretiled widths to scale the w/h provided */ + width *= gdk_pixbuf_get_width(pretiled); + width /= gdk_pixbuf_get_width(primary); + height *= gdk_pixbuf_get_height(pretiled); + height /= gdk_pixbuf_get_height(primary); + + if (y > cliprect.y) { + doneheight = (cliprect.y - height) + + ((y - cliprect.y) % height); + } else + doneheight = y; + + while (doneheight < (cliprect.y + cliprect.height)) { + if (x > cliprect.x) { + donewidth = (cliprect.x - width) + + ((x - cliprect.x) % width); + } else + donewidth = x; + + while (donewidth < (cliprect.x + cliprect.width)) { + nsgtk_print_plot_pixbuf(donewidth, doneheight, + width, height, pretiled, bg); + donewidth += width; + if (!repeat_x) break; + } + + doneheight += height; + + if (!repeat_y) break; + } + + return true; +} + +static bool nsgtk_print_plot_text(int x, int y, const char *text, size_t length, + const plot_font_style_t *fstyle) +{ + return gtk_print_font_paint(x, y, text, length, fstyle); +} + +/** GTK print plotter table */ +static const struct plotter_table nsgtk_print_plotters = { + .clip = nsgtk_print_plot_clip, + .arc = nsgtk_print_plot_arc, + .disc = nsgtk_print_plot_disc, + .line = nsgtk_print_plot_line, + .rectangle = nsgtk_print_plot_rectangle, + .polygon = nsgtk_print_plot_polygon, + .path = nsgtk_print_plot_path, + .bitmap = nsgtk_print_plot_bitmap, + .text = nsgtk_print_plot_text, + .option_knockout = false, +}; + +static bool gtk_print_begin(struct print_settings* settings) +{ + return true; +} + +static bool gtk_print_next_page(void) +{ + return true; +} + +static void gtk_print_end(void) +{ +} + +static const struct printer gtk_printer = { + &nsgtk_print_plotters, + gtk_print_begin, + gtk_print_next_page, + gtk_print_end +}; + +/** + * Handle the begin_print signal from the GtkPrintOperation + * + * \param operation the operation which emited the signal + * \param context the print context used to set up the pages + * \param user_data nothing in here + */ +void gtk_print_signal_begin_print (GtkPrintOperation *operation, + GtkPrintContext *context, gpointer user_data) +{ + int page_number; + double height_on_page, height_to_print; + + LOG(("Begin print")); + + settings = user_data; + + settings->margins[MARGINTOP] = 0; + settings->margins[MARGINLEFT] = 0; + settings->margins[MARGINBOTTOM] = 0; + settings->margins[MARGINRIGHT] = 0; + settings->page_width = gtk_print_context_get_width(context); + settings->page_height = gtk_print_context_get_height(context); + settings->scale = 0.7;/*at 0.7 the pages look the best*/ + settings->font_func = &nsfont; + + print_set_up(content_to_print, >k_printer, + settings, &height_to_print); + + LOG(("page_width: %f ;page_height: %f; content height: %lf", + settings->page_width, settings->page_height, height_to_print)); + + height_on_page = settings->page_height; + height_on_page = height_on_page - + FIXTOFLT(FSUB(settings->margins[MARGINTOP], + settings->margins[MARGINBOTTOM])); + height_to_print *= settings->scale; + + page_number = height_to_print / height_on_page; + + if (height_to_print - page_number * height_on_page > 0) + page_number += 1; + + gtk_print_operation_set_n_pages(operation, page_number); +} + +/** + * Handle the draw_page signal from the GtkPrintOperation. + * This function changes only the cairo context to print on. + */ +void gtk_print_signal_draw_page(GtkPrintOperation *operation, + GtkPrintContext *context, gint page_nr, gpointer user_data) +{ + LOG(("Draw Page")); + gtk_print_current_cr = gtk_print_context_get_cairo_context(context); + print_draw_next_page(>k_printer, settings); +} + +/** + * Handle the end_print signal from the GtkPrintOperation. + * This functions calls only the print_cleanup function from the print interface + */ +void gtk_print_signal_end_print(GtkPrintOperation *operation, + GtkPrintContext *context, gpointer user_data) +{ + LOG(("End print")); + print_cleanup(content_to_print, >k_printer, user_data); +} + + diff --git a/gtk/print.h b/gtk/print.h new file mode 100644 index 000000000..d44fad31f --- /dev/null +++ b/gtk/print.h @@ -0,0 +1,50 @@ +/* + * Copyright 2008 Adam Blokus + * + * 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 . + */ + + /** \file + * GTK printing (interface). + */ + +#ifndef NETSURF_GTK_PRINT_PLOTTERS_H +#define NETSURF_GTK_PRINT_PLOTTERS_H + + +#include + +struct hlcache_handle; + +extern cairo_t *gtk_print_current_cr; + +extern struct hlcache_handle *content_to_print; + + +/*handlers for signals from the GTK print operation*/ +void gtk_print_signal_begin_print(GtkPrintOperation *operation, + GtkPrintContext *context, + gpointer user_data); + +void gtk_print_signal_draw_page(GtkPrintOperation *operation, + GtkPrintContext *context, + gint page_nr, + gpointer user_data); + +void gtk_print_signal_end_print(GtkPrintOperation *operation, + GtkPrintContext *context, + gpointer user_data); + +#endif diff --git a/gtk/save.c b/gtk/save.c new file mode 100644 index 000000000..a67a7e6d0 --- /dev/null +++ b/gtk/save.c @@ -0,0 +1,82 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include +#include +#include + +#include "content/content.h" +#include "desktop/save_complete.h" +#include "utils/utils.h" + +/** +* conducts the filesystem save appropriate to the gui +* \param path save path +* \param filename name of file to save +* \param len data length +* \param sourcedata pointer to data to save +* \param type content type +* \return true for success +*/ + +bool save_complete_gui_save(const char *path, const char *filename, + size_t len, const char *sourcedata, content_type type) +{ + int res; + int namelen; + namelen = strlen(path) + strlen(filename) + 2; /* '/', '\0' */ + char *fullpath = malloc(namelen); + if (!fullpath) { + warn_user("NoMemory", 0); + return false; + } + snprintf(fullpath, namelen, "%s/%s", path, filename); + FILE *f; + f = fopen(fullpath, "wb"); + free(fullpath); + if (f == NULL) + return false; + res = fwrite(sourcedata, len, 1, f); + fclose(f); + if (res != 1) + return false; + return true; +} + +/** +* wrapper for lib function htmlSaveFileFormat; front sets path from path +* + filename in a filesystem-specific way +*/ + +int save_complete_htmlSaveFileFormat(const char *path, const char *filename, + xmlDocPtr cur, const char *encoding, int format) +{ + int ret; + int len = strlen(path) + strlen(filename) + 2; + char *fullpath = malloc(len); + if (fullpath == NULL) { + warn_user("NoMemory", 0); + return -1; + } + snprintf(fullpath, len, "%s/%s", path, filename); + ret = htmlSaveFileFormat(fullpath, cur, encoding, format); + free(fullpath); + return ret; +} + diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c new file mode 100644 index 000000000..573eec70a --- /dev/null +++ b/gtk/scaffolding.c @@ -0,0 +1,2541 @@ +/* + * Copyright 2006 Rob Kendrick + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtk/scaffolding.h" +#include "content/content.h" +#include "content/hlcache.h" +#include "css/utils.h" +#include "desktop/browser.h" +#include "desktop/history_core.h" +#include "desktop/hotlist.h" +#include "desktop/gui.h" +#include "desktop/netsurf.h" +#include "desktop/options.h" +#include "desktop/plotters.h" +#include "desktop/print.h" +#include "desktop/save_complete.h" +#ifdef WITH_PDF_EXPORT +#include "desktop/save_pdf/font_haru.h" +#include "desktop/save_pdf/pdf_plotters.h" +#endif +#include "desktop/save_text.h" +#include "desktop/search.h" +#include "desktop/searchweb.h" +#include "desktop/selection.h" +#include "desktop/textinput.h" +#include "desktop/tree.h" +#include "gtk/cookies.h" +#include "gtk/completion.h" +#include "gtk/dialogs/options.h" +#include "gtk/dialogs/about.h" +#include "gtk/dialogs/source.h" +#include "gtk/bitmap.h" +#include "gtk/download.h" +#include "gtk/gui.h" +#include "gtk/history.h" +#include "gtk/hotlist.h" +#include "gtk/menu.h" +#include "gtk/plotters.h" +#include "gtk/print.h" +#include "gtk/schedule.h" +#include "gtk/search.h" +#include "gtk/tabs.h" +#include "gtk/theme.h" +#include "gtk/throbber.h" +#include "gtk/toolbar.h" +#include "gtk/treeview.h" +#include "gtk/window.h" +#include "gtk/options.h" +#include "gtk/sexy_icon_entry.h" +#include "gtk/compat.h" +#include "image/ico.h" +#include "render/box.h" +#include "render/font.h" +#include "render/form.h" +#include "render/html.h" +#include "utils/messages.h" +#include "utils/utils.h" +#include "utils/url.h" + +#include "utils/log.h" + +/** Connect a GTK signal handler to a widget */ +#define SIG_CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + +/** Obtain a GTK widget handle from glade xml object */ +#define GET_WIDGET(x) glade_xml_get_widget(g->xml, (x)) + +/** Macro to define a handler for menu, button and activate events. */ +#define MULTIHANDLER(q)\ +static gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g);\ +static gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *widget, gpointer data)\ +{\ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\ + return nsgtk_on_##q##_activate(g);\ +}\ +static gboolean nsgtk_on_##q##_activate_button(GtkButton *widget, gpointer data)\ +{\ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\ + return nsgtk_on_##q##_activate(g);\ +}\ +static gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g) + +/** Macro to define a handler for menu events. */ +#define MENUHANDLER(q)\ +static gboolean nsgtk_on_##q##_activate(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. */ +struct gtk_scaffolding { + GtkWindow *window; + GtkNotebook *notebook; + GtkWidget *url_bar; + GtkEntryCompletion *url_bar_completion; + + /** menu bar hierarchy */ + struct nsgtk_bar_submenu *menu_bar; + + /** right click popup menu hierarchy */ + struct nsgtk_popup_submenu *menu_popup; + + GtkToolbar *tool_bar; + struct nsgtk_button_connect *buttons[PLACEHOLDER_BUTTON]; + GtkImage *throbber; + GtkImage *icoFav; + struct gtk_search *search; + GtkImage *webSearchIco; + GtkWidget *webSearchEntry; + GtkPaned *status_pane; + + int offset; + int toolbarmem; + int toolbarbase; + int historybase; + + GladeXML *xml; + + struct gtk_history_window *history_window; + GtkDialog *preferences_dialog; + + int throb_frame; + struct gui_window *top_level; + int being_destroyed; + + bool fullscreen; + + /* keep global linked list for gui interface adjustments */ + struct gtk_scaffolding *next, *prev; +}; + +/** current number of open browser windows */ +static int open_windows = 0; + +/** current window for model dialogue use */ +static struct gtk_scaffolding *current_model; + +/** global list for interface changes */ +nsgtk_scaffolding *scaf_list = NULL; + +/** The box containing a link under the mouse, or 0 if none */ +static struct box *current_menu_link_box; + +/** + * Helper to hide popup menu entries by grouping + */ +static void popup_menu_hide(struct nsgtk_popup_submenu *menu, bool submenu, + bool link, bool nav, bool cnp, bool custom) +{ + 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 (link) { + gtk_widget_hide(GTK_WIDGET(menu->opentab_menuitem)); + gtk_widget_hide(GTK_WIDGET(menu->openwin_menuitem)); + gtk_widget_hide(GTK_WIDGET(menu->savelink_menuitem)); + + gtk_widget_hide(menu->second_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)); + } + + 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)); + } + +} + +/** + * Helper to show popup menu entries by grouping + */ +static void popup_menu_show(struct nsgtk_popup_submenu *menu, bool submenu, + bool link, bool nav, bool cnp, bool custom) +{ + 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 (link) { + gtk_widget_show(GTK_WIDGET(menu->opentab_menuitem)); + gtk_widget_show(GTK_WIDGET(menu->openwin_menuitem)); + gtk_widget_show(GTK_WIDGET(menu->savelink_menuitem)); + + gtk_widget_show(menu->second_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)); + } + + 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)); + } + +} + + +/* event handlers and support functions for them */ + +/** + * resource cleanup function for window closure. + */ +static void nsgtk_window_close(struct gtk_scaffolding *g) +{ + /* close all tabs first */ + gint numbertabs = gtk_notebook_get_n_pages(g->notebook); + while (numbertabs-- > 1) { + nsgtk_tab_close_current(g->notebook); + } + LOG(("Being Destroyed = %d", g->being_destroyed)); + + if ((g->history_window) && (g->history_window->window)) { + gtk_widget_destroy(GTK_WIDGET(g->history_window->window)); + } + + if (--open_windows == 0) + netsurf_quit = true; + + if (!g->being_destroyed) { + g->being_destroyed = 1; + nsgtk_window_destroy_browser(g->top_level); + } + if (g->prev != NULL) + g->prev->next = g->next; + else + scaf_list = g->next; + + if (g->next != NULL) + g->next->prev = g->prev; + +} + +static gboolean nsgtk_window_delete_event(GtkWidget *widget, + GdkEvent *event, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + if ((open_windows != 1) || + nsgtk_check_for_downloads(GTK_WINDOW(widget)) == false) { + nsgtk_window_close(g); + gtk_widget_destroy(GTK_WIDGET(g->window)); + } + return TRUE; +} + +/* exported interface documented in gtk_scaffold.h */ +void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g) +{ + /* Our top_level has asked us to die */ + LOG(("Being Destroyed = %d", g->being_destroyed)); + if (g->being_destroyed) return; + g->being_destroyed = 1; + nsgtk_window_close(g); +} + +/** + * Update the back and forward button sensitivity. + */ +static void nsgtk_window_update_back_forward(struct gtk_scaffolding *g) +{ + int width, height; + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + + g->buttons[BACK_BUTTON]->sensitivity = + history_back_available(bw->history); + g->buttons[FORWARD_BUTTON]->sensitivity = history_forward_available( + bw->history); + + nsgtk_scaffolding_set_sensitivity(g); + + /* update the url bar, particularly necessary when tabbing */ + if (bw->current_content != NULL && + content_get_url(bw->current_content) != NULL) + browser_window_refresh_url_bar(bw, + content_get_url(bw->current_content), + bw->frag_id); + + /* update the local history window, as well as queuing a redraw + * for it. + */ + history_size(bw->history, &width, &height); + gtk_widget_set_size_request(GTK_WIDGET(g->history_window->drawing_area), + width, height); + gtk_widget_queue_draw(GTK_WIDGET(g->history_window->drawing_area)); +} + +/** + * Make the throbber run. + */ +static void nsgtk_throb(void *p) +{ + struct gtk_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]); + + schedule(10, nsgtk_throb, p); +} + +static guint nsgtk_scaffolding_update_edit_actions_sensitivity( + struct gtk_scaffolding *g) +{ + GtkWidget *widget = gtk_window_get_focus(g->window); + gboolean has_selection; + + if (GTK_IS_EDITABLE(widget)) { + 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; + } else { + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + has_selection = bw->sel->defined; + + g->buttons[COPY_BUTTON]->sensitivity = has_selection; + g->buttons[CUT_BUTTON]->sensitivity = (has_selection && + bw->caret_callback != 0); + g->buttons[PASTE_BUTTON]->sensitivity = + (bw->paste_callback != 0); + } + + nsgtk_scaffolding_set_sensitivity(g); + return ((g->buttons[COPY_BUTTON]->sensitivity) | + (g->buttons[CUT_BUTTON]->sensitivity) | + (g->buttons[PASTE_BUTTON]->sensitivity)); +} + +static void nsgtk_scaffolding_enable_link_operations_sensitivity( + struct gtk_scaffolding *g) +{ + + gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->savelink_menuitem), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->opentab_menuitem), TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(g->menu_popup->openwin_menuitem), TRUE); + + popup_menu_show(g->menu_popup, false, true, false, false, false); + +} + +static void nsgtk_scaffolding_enable_edit_actions_sensitivity( + struct gtk_scaffolding *g) +{ + + g->buttons[PASTE_BUTTON]->sensitivity = true; + g->buttons[COPY_BUTTON]->sensitivity = true; + g->buttons[CUT_BUTTON]->sensitivity = true; + nsgtk_scaffolding_set_sensitivity(g); + + popup_menu_show(g->menu_popup, false, false, false, true, false); +} + +/* signal handling functions for the toolbar, URL bar, and menu bar */ +static gboolean nsgtk_window_edit_menu_clicked(GtkWidget *widget, + struct gtk_scaffolding *g) +{ + nsgtk_scaffolding_update_edit_actions_sensitivity(g); + + return TRUE; +} + +static gboolean nsgtk_window_edit_menu_hidden(GtkWidget *widget, + struct gtk_scaffolding *g) +{ + nsgtk_scaffolding_enable_edit_actions_sensitivity(g); + + return TRUE; +} + +static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget, + struct gtk_scaffolding *g) +{ + nsgtk_scaffolding_enable_link_operations_sensitivity(g); + nsgtk_scaffolding_enable_edit_actions_sensitivity(g); + return TRUE; +} + +gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data) +{ + struct gtk_scaffolding *g = data; + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + char *url; + if (search_is_url(gtk_entry_get_text(GTK_ENTRY(g->url_bar))) + == false) + url = search_web_from_term(gtk_entry_get_text(GTK_ENTRY( + g->url_bar))); + else + url = strdup(gtk_entry_get_text(GTK_ENTRY(g->url_bar))); + browser_window_go(bw, url, 0, true); + if (url != NULL) + free(url); + return TRUE; +} + + +gboolean nsgtk_window_url_changed(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + const char *prefix; + + prefix = gtk_entry_get_text(GTK_ENTRY(widget)); + nsgtk_completion_update(prefix); + + return TRUE; +} + +/** + * Event handler for popup menu on toolbar. + */ +static gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, + gint x, gint y, gint button, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + + /* set visibility for right-click popup menu */ + popup_menu_hide(g->menu_popup, true, true, false, true, false); + popup_menu_show(g->menu_popup, false, false, false, false, true); + + gtk_menu_popup(g->menu_popup->popup_menu, NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); + + return TRUE; +} + +/** + * Update the menus when the number of tabs changes. + */ +static void nsgtk_window_tabs_num_changed(GtkNotebook *notebook, + GtkWidget *page, guint page_num, struct gtk_scaffolding *g) +{ + 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; + nsgtk_scaffolding_set_sensitivity(g); +} + +/** + * Handle opening a file path. + */ +static void nsgtk_openfile_open(const char *filename) +{ + struct browser_window *bw = gui_window_get_browser_window( + current_model->top_level); + char url[strlen(filename) + FILE_SCHEME_PREFIX_LEN + 1]; + + sprintf(url, FILE_SCHEME_PREFIX"%s", filename); + + browser_window_go(bw, url, 0, true); + +} + +/* signal handlers for menu entries */ + +MULTIHANDLER(newwindow) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + const char *url = gtk_entry_get_text(GTK_ENTRY(g->url_bar)); + + browser_window_create(url, bw, NULL, false, false); + + return TRUE; +} + +MULTIHANDLER(newtab) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + + if (option_new_blank) { + browser_window_create(NULL, bw, NULL, false, true); + GtkWidget *window = gtk_notebook_get_nth_page(g->notebook, -1); + gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &((GdkColor) + {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF})); + } else { + const char *url = option_homepage_url; + + if ((url != NULL) && (url[0] == '\0')) + url = NULL; + + if (url == NULL) + url = NETSURF_HOMEPAGE; + + browser_window_create(url, bw, NULL, false, true); + } + + return TRUE; +} + +MULTIHANDLER(openfile) +{ + current_model = g; + GtkWidget *dlgOpen = gtk_file_chooser_dialog_new("Open File", + current_model->window, GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, -6, GTK_STOCK_OPEN, -5, NULL); + + gint response = gtk_dialog_run(GTK_DIALOG(dlgOpen)); + if (response == GTK_RESPONSE_OK) { + gchar *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; +} + +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 (gui_window_get_browser_window(g->top_level)->current_content + == NULL) + return FALSE; + + GtkWidget *fc = gtk_file_chooser_dialog_new( + messages_get("gtkcompleteSave"), g->window, + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + DIR *d; + char *path; + url_func_result 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 = url_nice(content_get_url(gui_window_get_browser_window( + g->top_level)->current_content), &path, false); + if (res != URL_FUNC_OK) { + path = strdup(messages_get("SaveText")); + if (path == NULL) { + warn_user("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) { + LOG(("Unable to open directory %s for complete save: %s", path, + strerror(errno))); + if (errno == ENOTDIR) + warn_user("NoDirError", path); + else + warn_user("gtkFileError", path); + gtk_widget_destroy(fc); + g_free(path); + return TRUE; + } + closedir(d); + save_complete_init(); + save_complete(gui_window_get_browser_window( + g->top_level)->current_content, path); + g_free(path); + + gtk_widget_destroy(fc); + + return TRUE; +} + + +MULTIHANDLER(pdf) +{ +#ifdef WITH_PDF_EXPORT + + GtkWidget *save_dialog; + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + struct print_settings *settings; + char filename[PATH_MAX]; + char dirname[PATH_MAX]; + char *url_name; + url_func_result res; + + LOG(("Print preview (generating PDF) started.")); + + res = url_nice(content_get_url(bw->current_content), &url_name, true); + if (res != URL_FUNC_OK) { + warn_user(messages_get(res == URL_FUNC_NOMEM ? "NoMemory" + : "URIError"), 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 synchronized 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, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_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) { + warn_user(messages_get("NoMemory"), 0); + gtk_widget_destroy(save_dialog); + return TRUE; + } + + /* This will clean up the print_settings object for us */ + print_basic_run(bw->current_content, &pdf_printer, settings); + } + + gtk_widget_destroy(save_dialog); + +#endif /* WITH_PDF_EXPORT */ + + return TRUE; +} + +MULTIHANDLER(plaintext) +{ + if (gui_window_get_browser_window(g->top_level)->current_content + == NULL) + return FALSE; + + GtkWidget *fc = gtk_file_chooser_dialog_new( + messages_get("gtkplainSave"), g->window, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + char *filename; + url_func_result res; + + res = url_nice(content_get_url(gui_window_get_browser_window( + g->top_level)->current_content), &filename, false); + if (res != URL_FUNC_OK) { + filename = strdup(messages_get("SaveText")); + if (filename == NULL) { + warn_user("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); + + 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(gui_window_get_browser_window( + g->top_level)->current_content, 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 = gui_window_get_browser_window(g->top_level); + + GtkPrintOperation *print_op; + GtkPageSetup *page_setup; + GtkPrintSettings *gtk_print_settings; + GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR; + struct print_settings *settings; + + print_op = gtk_print_operation_new(); + if (print_op == NULL) { + warn_user(messages_get("NoMemory"), 0); + return TRUE; + } + + /* use previously saved settings if any */ + gtk_print_settings = gtk_print_settings_new_from_file( + print_options_file_location, NULL); + if (gtk_print_settings != NULL) { + gtk_print_operation_set_print_settings(print_op, + gtk_print_settings); + + /* We're not interested in the settings any more */ + g_object_unref(gtk_print_settings); + } + + content_to_print = bw->current_content; + + page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL); + if (page_setup == NULL) { + warn_user(messages_get("NoMemory"), 0); + g_object_unref(print_op); + return TRUE; + } + gtk_print_operation_set_default_page_setup(print_op, page_setup); + + settings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont); + + g_signal_connect(print_op, "begin_print", + G_CALLBACK(gtk_print_signal_begin_print), settings); + 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), settings); + if (content_get_type(bw->current_content) != 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 (res == GTK_PRINT_OPERATION_RESULT_APPLY) { + /* Don't ref the settings, as we don't want to own them */ + gtk_print_settings = gtk_print_operation_get_print_settings( + print_op); + + gtk_print_settings_to_file(gtk_print_settings, + print_options_file_location, NULL); + } + + /* 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) +{ + /* close all tabs first */ + gint numbertabs = gtk_notebook_get_n_pages(g->notebook); + while (numbertabs-- > 1) { + nsgtk_tab_close_current(g->notebook); + } + nsgtk_window_close(g); + gtk_widget_destroy(GTK_WIDGET(g->window)); + return TRUE; +} + +MULTIHANDLER(quit) +{ + if (nsgtk_check_for_downloads(g->window) == false) + netsurf_quit = true; + return TRUE; +} + +MENUHANDLER(savelink) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; + struct gui_window *gui = g->top_level; + struct browser_window *bw = gui_window_get_browser_window(gui); + + if (!current_menu_link_box) + return FALSE; + + browser_window_download(bw, current_menu_link_box->href, + content_get_url(bw->current_content)); + + return TRUE; +} + +/** + * Handler for opening new window from a link. attached to the popup menu. + */ +MENUHANDLER(link_openwin) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; + struct gui_window *gui = g->top_level; + struct browser_window *bw = gui_window_get_browser_window(gui); + + if (current_menu_link_box == NULL) + return FALSE; + + browser_window_create(current_menu_link_box->href, bw, NULL, true, false); + + return TRUE; +} + +/** + * Handler for opening new tab from a link. attached to the popup menu. + */ +MENUHANDLER(link_opentab) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *) data; + struct gui_window *gui = g->top_level; + struct browser_window *bw = gui_window_get_browser_window(gui); + + temp_open_background = 1; + + if (current_menu_link_box == NULL) + return FALSE; + + browser_window_create(current_menu_link_box->href, bw, NULL, true, + true); + temp_open_background = -1; + + return TRUE; +} + + +MULTIHANDLER(cut) +{ + struct browser_window *bw = gui_window_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, KEY_CUT_SELECTION); + + return TRUE; +} + +MULTIHANDLER(copy) +{ + struct browser_window *bw = gui_window_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 + gui_copy_to_clipboard(bw->sel); + + return TRUE; +} + +MULTIHANDLER(paste) +{ + struct gui_window *gui = 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 + gui_paste_from_clipboard(gui, 0, 0); + + return TRUE; +} + +MULTIHANDLER(delete) +{ + return TRUE; +} + +MENUHANDLER(customize) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + nsgtk_toolbar_customization_init(g); + return TRUE; +} + +MULTIHANDLER(selectall) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + + if (nsgtk_widget_has_focus(GTK_WIDGET(g->url_bar))) { + LOG(("Selecting all URL bar text")); + gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1); + } else { + LOG(("Selecting all document text")); + selection_select_all(bw->sel); + } + + return TRUE; +} + +MULTIHANDLER(find) +{ + nsgtk_scaffolding_toggle_search_bar_visibility(g); + return TRUE; +} + +MULTIHANDLER(preferences) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + if (g->preferences_dialog == NULL) + g->preferences_dialog = nsgtk_options_init(bw, g->window); + else + gtk_widget_show(GTK_WIDGET(g->preferences_dialog)); + + return TRUE; +} + +MULTIHANDLER(zoomplus) +{ + struct browser_window *bw = gui_window_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 = gui_window_get_browser_window(g->top_level); + + browser_window_set_scale(bw, 1.0, true); + + return TRUE; +} + +MULTIHANDLER(zoomminus) +{ + struct browser_window *bw = gui_window_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(fullscreen) +{ + if (g->fullscreen) { + gtk_window_unfullscreen(g->window); + } else { + gtk_window_fullscreen(g->window); + } + + g->fullscreen = !g->fullscreen; + + return TRUE; +} + +MULTIHANDLER(viewsource) +{ + nsgtk_source_dialog_init(g->window, + gui_window_get_browser_window(g->top_level)); + return TRUE; +} + +MENUHANDLER(menubar) +{ + GtkWidget *w; + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + + /* if the menubar is not being shown the popup menu shows the + * menubar entries instead. + */ + 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, true); + popup_menu_hide(g->menu_popup, true, false, 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, true); + + } + return TRUE; +} + +MENUHANDLER(toolbar) +{ + GtkWidget *w; + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + + 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)); + } 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) +{ + if (GTK_IS_PANED(g->status_pane)) + option_toolbar_status_width = + gtk_paned_get_position(g->status_pane); + gtk_window_get_position(g->window, &option_window_x, + &option_window_y); + gtk_window_get_size(g->window, &option_window_width, + &option_window_height); + + + options_write(options_file_location); + + return TRUE; +} + +MULTIHANDLER(toggledebugging) +{ + html_redraw_debug = !html_redraw_debug; + nsgtk_reflow_all_windows(); + return TRUE; +} + +MULTIHANDLER(saveboxtree) +{ + GtkWidget *save_dialog; + + save_dialog = gtk_file_chooser_dialog_new("Save File", g->window, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), + getenv("HOME") ? getenv("HOME") : "/"); + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), + "boxtree.txt"); + + if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(save_dialog)); + FILE *fh; + + LOG(("Saving box tree dump to %s...\n", filename)); + + fh = fopen((const char *) filename, "w"); + if (fh == NULL) { + warn_user("Error saving box tree dump.", + "Unable to open file for writing."); + } else { + struct browser_window *bw; + bw = gui_window_get_browser_window(g->top_level); + + if (bw->current_content && + content_get_type(bw->current_content) == + CONTENT_HTML) { + box_dump(fh, + html_get_box_tree(bw->current_content), + 0); + } + + fclose(fh); + } + + g_free(filename); + } + + gtk_widget_destroy(save_dialog); + + return TRUE; +} + +MULTIHANDLER(savedomtree) +{ + GtkWidget *save_dialog; + + save_dialog = gtk_file_chooser_dialog_new("Save File", g->window, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), + getenv("HOME") ? getenv("HOME") : "/"); + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), + "domtree.txt"); + + if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *filename = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(save_dialog)); + FILE *fh; + LOG(("Saving dom tree to %s...\n", filename)); + + fh = fopen((const char *) filename, "w"); + if (fh == NULL) { + warn_user("Error saving box tree dump.", + "Unable to open file for writing."); + } else { + struct browser_window *bw; + bw = gui_window_get_browser_window(g->top_level); + + if (bw->current_content && + content_get_type(bw->current_content) == + CONTENT_HTML) { + xmlDebugDumpDocument(fh, + html_get_document(bw->current_content)); + } + + fclose(fh); + } + + g_free(filename); + } + + gtk_widget_destroy(save_dialog); + + return TRUE; +} + + +MULTIHANDLER(stop) +{ + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + + browser_window_stop(bw); + + return TRUE; +} + +MULTIHANDLER(reload) +{ + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + if (bw == NULL) + return TRUE; + + /* clear potential search effects */ + if (bw->search_context != NULL) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, bw); + + browser_window_reload(bw, true); + + return TRUE; +} + +MULTIHANDLER(back) +{ + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + + if ((bw == NULL) || (!history_back_available(bw->history))) + return TRUE; + + /* clear potential search effects */ + if (bw->search_context != NULL) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, bw); + + history_back(bw, bw->history); + nsgtk_window_update_back_forward(g); + + return TRUE; +} + +MULTIHANDLER(forward) +{ + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + + if ((bw == NULL) || (!history_forward_available(bw->history))) + return TRUE; + + /* clear potential search effects */ + if (bw->search_context != NULL) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, bw); + + history_forward(bw, bw->history); + nsgtk_window_update_back_forward(g); + + return TRUE; +} + +MULTIHANDLER(home) +{ + static const char *addr = NETSURF_HOMEPAGE; + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + + if (option_homepage_url != NULL && option_homepage_url[0] != '\0') + addr = option_homepage_url; + + browser_window_go(bw, addr, 0, true); + + return TRUE; +} + +MULTIHANDLER(localhistory) +{ + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + + int x,y, width, height, mainwidth, mainheight, margin = 20; + /* if entries of the same url but different frag_ids have been added + * the history needs redrawing (what throbber code normally does) + */ + history_size(bw->history, &width, &height); + nsgtk_window_update_back_forward(g); + gtk_window_get_position(g->window, &x, &y); + gtk_window_get_size(g->window, &mainwidth, &mainheight); + width = (width + g->historybase + margin > mainwidth) ? + mainwidth - g->historybase : width + margin; + height = (height + g->toolbarbase + margin > mainheight) ? + mainheight - g->toolbarbase : height + margin; + gtk_window_set_default_size(g->history_window->window, width, height); + gtk_widget_set_size_request(GTK_WIDGET(g->history_window->window), + -1, -1); + gtk_window_resize(g->history_window->window, width, height); + gtk_window_set_transient_for(g->history_window->window, g->window); + gtk_window_set_opacity(g->history_window->window, 0.9); + gtk_widget_show(GTK_WIDGET(g->history_window->window)); + gtk_window_move(g->history_window->window, x + g->historybase, y + + g->toolbarbase); + gdk_window_raise(GTK_WIDGET(g->history_window->window)->window); + + return TRUE; +} + +MULTIHANDLER(globalhistory) +{ + gtk_widget_show(GTK_WIDGET(wndHistory)); + gdk_window_raise(GTK_WIDGET(wndHistory)->window); + + return TRUE; +} + +MULTIHANDLER(addbookmarks) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + + if (bw == NULL || bw->current_content == NULL || + content_get_url(bw->current_content) == NULL) + return TRUE; + hotlist_add_page(content_get_url(bw->current_content)); + return TRUE; +} + +MULTIHANDLER(showbookmarks) +{ + gtk_widget_show(GTK_WIDGET(wndHotlist)); + gdk_window_raise(GTK_WIDGET(wndHotlist)->window); + gtk_window_set_focus(wndHotlist, NULL); + + return TRUE; +} + +MULTIHANDLER(showcookies) +{ + gtk_widget_show(GTK_WIDGET(wndCookies)); + gdk_window_raise(GTK_WIDGET(wndCookies)->window); + + return TRUE; +} + +MULTIHANDLER(openlocation) +{ + gtk_widget_grab_focus(GTK_WIDGET(g->url_bar)); + return TRUE; +} + +MULTIHANDLER(nexttab) +{ + gtk_notebook_next_page(g->notebook); + + return TRUE; +} + +MULTIHANDLER(prevtab) +{ + gtk_notebook_prev_page(g->notebook); + + return TRUE; +} + +MULTIHANDLER(closetab) +{ + nsgtk_tab_close_current(g->notebook); + + return TRUE; +} + +MULTIHANDLER(contents) +{ + return TRUE; +} + +MULTIHANDLER(guide) +{ + return TRUE; +} + +MULTIHANDLER(info) +{ + return TRUE; +} + +MULTIHANDLER(about) +{ + nsgtk_about_dialog_init(g->window, + gui_window_get_browser_window(g->top_level), + netsurf_version); + return TRUE; +} + +BUTTONHANDLER(history) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + return nsgtk_on_localhistory_activate(g); +} + +#undef MULTIHANDLER +#undef CHECKHANDLER +#undef BUTTONHANDLER + + +/* signal handler functions for the local history window */ +static gboolean nsgtk_history_expose_event(GtkWidget *widget, + GdkEventExpose *event, gpointer g) +{ + struct gtk_history_window *hw = (struct gtk_history_window *)g; + struct browser_window *bw = + gui_window_get_browser_window(hw->g->top_level); + + current_widget = widget; + current_drawable = widget->window; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot = nsgtk_plotters; + nsgtk_plot_set_scale(1.0); + + plot.clip(event->area.x, + event->area.y, + event->area.x + event->area.width, + event->area.y + event->area.height); + + history_redraw(bw->history); + + current_widget = NULL; + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + return FALSE; +} + + +static gboolean nsgtk_history_button_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer g) +{ + struct gtk_history_window *hw = (struct gtk_history_window *)g; + struct browser_window *bw = + gui_window_get_browser_window(hw->g->top_level); + + LOG(("X=%g, Y=%g", event->x, event->y)); + + history_click(bw, bw->history, + event->x, event->y, false); + + return TRUE; +} + + + +static void nsgtk_attach_menu_handlers(struct gtk_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), g);\ + g_signal_connect(g->menu_popup->view_submenu->toolbars_submenu->q##_menuitem, "toggled", G_CALLBACK(nsgtk_on_##q##_activate), g) + CONNECT_CHECK(menubar); + CONNECT_CHECK(toolbar); +#undef CONNECT_CHECK + +} + +/** + * Create and connect handlers to popup menu. + * + * \param g scaffoliding to attach popup menu to. + * \return true on success or false on error. + */ +static bool nsgtk_new_scaffolding_popup(struct gtk_scaffolding *g) +{ + struct nsgtk_popup_submenu *nmenu; + + nmenu = nsgtk_menu_popup_create(g->window); + + if (nmenu == NULL) + return false; + + SIG_CONNECT(nmenu->popup_menu, "hide", + nsgtk_window_popup_menu_hidden, g); + + SIG_CONNECT(nmenu->savelink_menuitem, "activate", + nsgtk_on_savelink_activate, g); + + SIG_CONNECT(nmenu->opentab_menuitem, "activate", + nsgtk_on_link_opentab_activate, g); + + SIG_CONNECT(nmenu->openwin_menuitem, "activate", + nsgtk_on_link_openwin_activate, g); + + SIG_CONNECT(nmenu->cut_menuitem, "activate", + nsgtk_on_cut_activate, g); + + SIG_CONNECT(nmenu->copy_menuitem, "activate", + nsgtk_on_copy_activate, g); + + SIG_CONNECT(nmenu->paste_menuitem, "activate", + nsgtk_on_paste_activate, g); + + SIG_CONNECT(nmenu->customize_menuitem, "activate", + nsgtk_on_customize_activate, g); + + + /* set initial popup menu visibility */ + popup_menu_hide(nmenu, true, false, false, false, true); + + g->menu_popup = nmenu; + + return true; +} + +nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel) +{ + struct gtk_scaffolding *g = malloc(sizeof(*g)); + char *searchname; + int i; + + if (g == NULL) { + warn_user("NoMemory", 0); + return NULL; + } + + LOG(("Constructing a scaffold of %p for gui_window %p", g, toplevel)); + + g->top_level = toplevel; + + open_windows++; + + /* load the window template from the glade xml file, and extract + * widget references from it for later use. + */ + g->xml = glade_xml_new(glade_netsurf_file_location, + "wndBrowser", NULL); + glade_xml_signal_autoconnect(g->xml); + g->window = GTK_WINDOW(GET_WIDGET("wndBrowser")); + g->notebook = GTK_NOTEBOOK(GET_WIDGET("notebook")); + g->tool_bar = GTK_TOOLBAR(GET_WIDGET("toolbar")); + + g->search = malloc(sizeof(struct gtk_search)); + if (g->search == NULL) { + warn_user("NoMemory", 0); + free(g); + return NULL; + } + + g->search->bar = GTK_TOOLBAR(GET_WIDGET("searchbar")); + g->search->entry = GTK_ENTRY(GET_WIDGET("searchEntry")); + + g->search->buttons[0] = GTK_TOOL_BUTTON(GET_WIDGET("searchBackButton")); + g->search->buttons[1] = GTK_TOOL_BUTTON(GET_WIDGET( + "searchForwardButton")); + g->search->buttons[2] = GTK_TOOL_BUTTON(GET_WIDGET( + "closeSearchButton")); + g->search->checkAll = GTK_CHECK_BUTTON(GET_WIDGET("checkAllSearch")); + g->search->caseSens = GTK_CHECK_BUTTON(GET_WIDGET("caseSensButton")); + + + + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + g->buttons[i] = malloc(sizeof(struct nsgtk_button_connect)); + if (g->buttons[i] == NULL) { + warn_user("NoMemory", 0); + return NULL; + } + g->buttons[i]->button = NULL; + g->buttons[i]->location = -1; + g->buttons[i]->sensitivity = true; + g->buttons[i]->main = NULL; + g->buttons[i]->rclick = NULL; + g->buttons[i]->popup = NULL; + g->buttons[i]->mhandler = NULL; + g->buttons[i]->bhandler = NULL; + g->buttons[i]->dataplus = NULL; + g->buttons[i]->dataminus = NULL; + } + /* here custom toolbutton adding code */ + g->offset = 0; + g->toolbarmem = 0; + g->toolbarbase = 0; + g->historybase = 0; + nsgtk_toolbar_customization_load(g); + nsgtk_toolbar_set_physical(g); + + g->menu_bar = nsgtk_menu_bar_create(GTK_MENU_SHELL(glade_xml_get_widget(g->xml, "menubar")), g->window); + + + g->preferences_dialog = NULL; + + /* 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 (option_window_width > 0) { + gtk_window_move(g->window, option_window_x, option_window_y); + gtk_window_resize(g->window, option_window_width, + option_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(g->window, 1000, 700); + } + + /* Default toolbar button type uses system defaults */ + if (option_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: + option_button_type = (tooliconsize == + GTK_ICON_SIZE_SMALL_TOOLBAR) ? + 1 : 2; + break; + case GTK_TOOLBAR_TEXT: + option_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 */ + option_button_type = 2; + break; + } + } + + switch (option_button_type) { + /* case 0 is 'unset' [from fresh install / clearing options] + * see above */ + + case 1: /* Small 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_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); + 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); + break; + case 4: /* Text icons only */ + gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar), + GTK_TOOLBAR_TEXT); + default: + break; + } + + gtk_toolbar_set_show_arrow(g->tool_bar, TRUE); + gtk_widget_show_all(GTK_WIDGET(g->tool_bar)); + nsgtk_tab_init(GTK_WIDGET(g->notebook)); + + gtk_widget_set_size_request(GTK_WIDGET( + g->buttons[HISTORY_BUTTON]->button), 20, -1); + + /* create the local history window to be associated with this browser */ + g->history_window = malloc(sizeof(struct gtk_history_window)); + g->history_window->g = g; + g->history_window->window = + GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_window_set_transient_for(g->history_window->window, g->window); + gtk_window_set_title(g->history_window->window, "NetSurf History"); + gtk_window_set_type_hint(g->history_window->window, + GDK_WINDOW_TYPE_HINT_UTILITY); + g->history_window->scrolled = + GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(0, 0)); + gtk_container_add(GTK_CONTAINER(g->history_window->window), + GTK_WIDGET(g->history_window->scrolled)); + + gtk_widget_show(GTK_WIDGET(g->history_window->scrolled)); + g->history_window->drawing_area = + GTK_DRAWING_AREA(gtk_drawing_area_new()); + + gtk_widget_set_events(GTK_WIDGET(g->history_window->drawing_area), + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_PRESS_MASK); + gtk_widget_modify_bg(GTK_WIDGET(g->history_window->drawing_area), + GTK_STATE_NORMAL, + &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); + gtk_scrolled_window_add_with_viewport(g->history_window->scrolled, + GTK_WIDGET(g->history_window->drawing_area)); + gtk_widget_show(GTK_WIDGET(g->history_window->drawing_area)); + + + /* set up URL bar completion */ + g->url_bar_completion = gtk_entry_completion_new(); + gtk_entry_completion_set_match_func(g->url_bar_completion, + nsgtk_completion_match, NULL, NULL); + gtk_entry_completion_set_model(g->url_bar_completion, + GTK_TREE_MODEL(nsgtk_completion_list)); + gtk_entry_completion_set_text_column(g->url_bar_completion, 0); + gtk_entry_completion_set_minimum_key_length(g->url_bar_completion, 1); + gtk_entry_completion_set_popup_completion(g->url_bar_completion, TRUE); + g_object_set(G_OBJECT(g->url_bar_completion), + "popup-set-width", TRUE, + "popup-single-match", TRUE, + NULL); + + /* set up the throbber. */ + g->throb_frame = 0; + + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + /* connect history window signals to their handlers */ + CONNECT(g->history_window->drawing_area, "expose_event", + nsgtk_history_expose_event, g->history_window); + /*CONNECT(g->history_window->drawing_area, "motion_notify_event", + nsgtk_history_motion_notify_event, g->history_window);*/ + CONNECT(g->history_window->drawing_area, "button_press_event", + nsgtk_history_button_press_event, g->history_window); + CONNECT(g->history_window->window, "delete_event", + gtk_widget_hide_on_delete, NULL); + + g_signal_connect_after(g->notebook, "page-added", + G_CALLBACK(nsgtk_window_tabs_num_changed), g); + g_signal_connect_after(g->notebook, "page-removed", + G_CALLBACK(nsgtk_window_tabs_num_changed), g); + + /* connect signals to handlers. */ + CONNECT(g->window, "delete-event", nsgtk_window_delete_event, g); + + /* toolbar URL bar menu bar search bar signal handlers */ + CONNECT(g->menu_bar->edit_submenu->edit, "show", nsgtk_window_edit_menu_clicked, g); + CONNECT(g->menu_bar->edit_submenu->edit, "hide", nsgtk_window_edit_menu_hidden, g); + CONNECT(g->search->buttons[1], "clicked", + nsgtk_search_forward_button_clicked, g); + CONNECT(g->search->buttons[0], "clicked", + nsgtk_search_back_button_clicked, g); + CONNECT(g->search->entry, "changed", nsgtk_search_entry_changed, g); + CONNECT(g->search->entry, "activate", nsgtk_search_entry_activate, g); + CONNECT(g->search->entry, "key-press-event", nsgtk_search_entry_key, g); + CONNECT(g->search->buttons[2], "clicked", + nsgtk_search_close_button_clicked, g); + CONNECT(g->search->caseSens, "toggled", nsgtk_search_entry_changed, + g); + + + CONNECT(g->tool_bar, "popup-context-menu", + nsgtk_window_tool_bar_clicked, g); + + /* create popup menu */ + nsgtk_new_scaffolding_popup(g); + + /* set up the menu signal handlers */ + nsgtk_scaffolding_toolbar_init(g); + nsgtk_toolbar_connect_all(g); + nsgtk_attach_menu_handlers(g); + + /* prepare to set the web search ico */ + + /* init web search prefs from file */ + search_web_provider_details(option_search_provider); + + /* potentially retrieve ico */ + if (search_web_ico() == NULL) + search_web_retrieve_ico(false); + + /* set entry */ + searchname = search_web_provider_name(); + if (searchname != NULL) { + char searchcontent[strlen(searchname) + SLEN("Search ") + 1]; + sprintf(searchcontent, "Search %s", searchname); + nsgtk_scaffolding_set_websearch(g, searchcontent); + free(searchname); + } + + nsgtk_scaffolding_initial_sensitivity(g); + + g->being_destroyed = 0; + + g->fullscreen = false; + + + /* attach to the list */ + if (scaf_list) + scaf_list->prev = g; + g->next = scaf_list; + g->prev = NULL; + scaf_list = g; + + /* call functions that need access from the list */ + nsgtk_theme_init(); + nsgtk_theme_implement(g); + + /* set web search ico */ + if (search_web_ico() != NULL) + gui_window_set_search_ico(search_web_ico()); + + /* finally, show the window. */ + gtk_widget_show(GTK_WIDGET(g->window)); + + LOG(("creation complete")); + + return g; +} + +void gui_window_set_title(struct gui_window *_g, const char *title) +{ + static char suffix[] = " - NetSurf"; + char nt[strlen(title) + strlen(suffix) + 1]; + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + + nsgtk_tab_set_title(_g, title); + + if (g->top_level == _g) { + if (title == NULL || title[0] == '\0') + { + gtk_window_set_title(g->window, "NetSurf"); + + } + else + { + strcpy(nt, title); + strcat(nt, suffix); + gtk_window_set_title(g->window, nt); + } + } +} + +void gui_window_set_url(struct gui_window *_g, const char *url) +{ + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + if (g->top_level != _g) return; + gtk_entry_set_text(GTK_ENTRY(g->url_bar), url); + gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1); +} + +void gui_window_start_throbber(struct gui_window* _g) +{ + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + g->buttons[STOP_BUTTON]->sensitivity = true; + g->buttons[RELOAD_BUTTON]->sensitivity = false; + nsgtk_scaffolding_set_sensitivity(g); + + nsgtk_window_update_back_forward(g); + + schedule(10, nsgtk_throb, g); +} + +void gui_window_stop_throbber(struct gui_window* _g) +{ + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + if (g == NULL) + return; + nsgtk_window_update_back_forward(g); + schedule_remove(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 gui_window_set_icon(struct gui_window *_g, hlcache_handle *icon) +{ + struct gtk_scaffolding *g = nsgtk_get_scaffold(_g); + struct bitmap *icon_bitmap; + GtkImage *iconImage = NULL; + + if (g->top_level != _g) + return; + +#ifdef WITH_BMP + if (icon != NULL && content_get_type(icon) == CONTENT_ICO) + nsico_set_bitmap_from_size(icon, 16, 16); +#endif + + icon_bitmap = (icon != NULL) ? content_get_bitmap(icon) : NULL; + + if (icon_bitmap != NULL) { + GdkPixbuf *pb = gtk_bitmap_get_primary(icon_bitmap); + if (pb != NULL && gdk_pixbuf_get_width(pb) > 0 && + gdk_pixbuf_get_height(pb) > 0) { + pb = gdk_pixbuf_scale_simple(pb, 16, 16, GDK_INTERP_HYPER); + iconImage = GTK_IMAGE(gtk_image_new_from_pixbuf(pb)); + } + } + if (iconImage == NULL) { + /** \todo Does pb need cleaning up? */ + char imagepath[strlen(res_dir_location) + + SLEN("favicon.png") + 1]; + sprintf(imagepath, "%sfavicon.png", res_dir_location); + iconImage = GTK_IMAGE(gtk_image_new_from_file(imagepath)); + } + + if (iconImage == NULL) + return; + + if (g->icoFav != NULL) + g_object_unref(g->icoFav); + g->icoFav = iconImage; + + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar), + SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(g->icoFav)); + gtk_widget_show_all(GTK_WIDGET(g->buttons[URL_BAR_ITEM]->button)); +} + +void gui_window_set_search_ico(hlcache_handle *ico) +{ + GdkPixbuf *pbico; + GtkImage *searchico; + struct bitmap *ico_bitmap; + nsgtk_scaffolding *current; + + if (ico == NULL && (ico = search_web_ico()) == NULL) + return; + +#ifdef WITH_BMP + if (content_get_type(ico) == CONTENT_ICO) + nsico_set_bitmap_from_size(ico, 20, 20); +#endif + + ico_bitmap = content_get_bitmap(ico); + if (ico_bitmap == NULL) + return; + + pbico = gtk_bitmap_get_primary(ico_bitmap); + if (pbico != NULL && gdk_pixbuf_get_width(pbico) > 0 && + gdk_pixbuf_get_height(pbico) > 0) { + pbico = gdk_pixbuf_scale_simple(pbico, 20, 20, + GDK_INTERP_HYPER); + searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico)); + } else { + /** \todo Does pbico need cleaning up? */ + return; + } + + /* add ico to each window's toolbar */ + for (current = scaf_list; current != NULL; current = current->next) { + if (searchico != NULL) { + /** \todo Are we leaking webSearchIco here? */ + current->webSearchIco = searchico; + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY( + current->webSearchEntry), + SEXY_ICON_ENTRY_PRIMARY, + current->webSearchIco); + } + if (pbico != NULL) + searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico)); + else + searchico = NULL; + } +} + +bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g) +{ + /* We are considered "busy" if the stop button is sensitive */ + return g->buttons[STOP_BUTTON]->sensitivity; +} + +GtkWindow* nsgtk_scaffolding_window(nsgtk_scaffolding *g) +{ + return g->window; +} + +GtkNotebook* nsgtk_scaffolding_notebook(nsgtk_scaffolding *g) +{ + return g->notebook; +} + +GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g) +{ + return g->url_bar; +} + +GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g) +{ + return g->webSearchEntry; +} + + +GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g) +{ + return g->tool_bar; +} + +struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g, + int i) +{ + return g->buttons[i]; +} + +struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g) +{ + return g->search; +} + +GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g) +{ + return g->menu_bar->bar_menu; +} + +struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding + *g) +{ + return g->history_window; +} + +nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g) +{ + return g->next; +} + +void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g) +{ + g->offset = 0; +} + +void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g) +{ + g->url_bar = GTK_WIDGET(gtk_bin_get_child(GTK_BIN( + nsgtk_scaffolding_button(g, URL_BAR_ITEM)->button))); + g->icoFav = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY(g->url_bar), + SEXY_ICON_ENTRY_PRIMARY); + + gtk_entry_set_completion(GTK_ENTRY(g->url_bar), + g->url_bar_completion); +} +void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g) +{ + g->throbber = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(gtk_bin_get_child( + GTK_BIN(g->buttons[THROBBER_ITEM]->button))))); +} + +void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g) +{ + g->webSearchEntry = gtk_bin_get_child(GTK_BIN( + g->buttons[WEBSEARCH_ITEM]->button)); + g->webSearchIco = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY( + g->webSearchEntry), SEXY_ICON_ENTRY_PRIMARY); +} + +void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char *content) +{ + /* this code appears technically correct, though currently has no + * effect at all - tinkering encouraged */ + 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("", content, + "", 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); +} + +void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g) +{ + gboolean vis; + struct browser_window *bw = + gui_window_get_browser_window(g->top_level); + g_object_get(G_OBJECT(g->search->bar), "visible", &vis, NULL); + if (vis) { + if ((bw != NULL) && (bw->search_context != NULL)) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, 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)); + } +} + + +struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g) +{ + return g->top_level; +} + +void nsgtk_scaffolding_set_top_level (struct gui_window *gw) +{ + nsgtk_get_scaffold(gw)->top_level = gw; + struct browser_window *bw = gui_window_get_browser_window(gw); + + assert(bw != NULL); + + /* Synchronise the history (will also update the URL bar) */ + nsgtk_window_update_back_forward(nsgtk_get_scaffold(gw)); + + /* clear effects of potential searches */ + if (bw->search_context != NULL) + search_destroy_context(bw->search_context); + + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, bw); + + /* Ensure the window's title bar as well as favicon are updated */ + if (bw->current_content != NULL) { + gui_window_set_title(gw, + content_get_title(bw->current_content)); + + if (content_get_type(bw->current_content) == CONTENT_HTML) + gui_window_set_icon(gw, + html_get_favicon(bw->current_content)); + } +} + +void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g) +{ +#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); + + int i; + SENSITIVITY(STOP) + SENSITIVITY(RELOAD) + SENSITIVITY(CUT) + SENSITIVITY(COPY) + SENSITIVITY(PASTE) + SENSITIVITY(BACK) + SENSITIVITY(FORWARD) + SENSITIVITY(NEXTTAB) + SENSITIVITY(PREVTAB) + SENSITIVITY(CLOSETAB) +#undef SENSITIVITY +} + +void nsgtk_scaffolding_initial_sensitivity(struct gtk_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) + 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); + } + gtk_widget_set_sensitive(GTK_WIDGET(g->menu_bar->view_submenu->images_menuitem), FALSE); +} + +/** + * Checks if a location is over a link. + * + * Side effect of this function is to set the global current_menu_link_box + */ +static bool is_menu_over_link(struct gtk_scaffolding *g, gdouble x, gdouble y) +{ + struct browser_window *bw = gui_window_get_browser_window(g->top_level); + current_menu_link_box = NULL; + + if ((bw->current_content != NULL) && + (content_get_type(bw->current_content) == CONTENT_HTML)) { + current_menu_link_box = box_href_at_point(bw->current_content, x, y); + } + + if (current_menu_link_box == NULL) + return false; + + return true; +} + +void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g, gdouble x, gdouble y) +{ + if (is_menu_over_link(g, x, y)) { + popup_menu_show(g->menu_popup, false, true, false, false, false); + } else { + popup_menu_hide(g->menu_popup, false, true, false, false, false); + } + + nsgtk_scaffolding_update_edit_actions_sensitivity(g); + + if (!(g->buttons[COPY_BUTTON]->sensitivity)) + gtk_widget_hide(GTK_WIDGET(g->menu_popup->copy_menuitem)); + else + gtk_widget_show(GTK_WIDGET(g->menu_popup->copy_menuitem)); + + if (!(g->buttons[CUT_BUTTON]->sensitivity)) + gtk_widget_hide(GTK_WIDGET(g->menu_popup->cut_menuitem)); + else + gtk_widget_show(GTK_WIDGET(g->menu_popup->cut_menuitem)); + + if (!(g->buttons[PASTE_BUTTON]->sensitivity)) + gtk_widget_hide(GTK_WIDGET(g->menu_popup->paste_menuitem)); + else + gtk_widget_show(GTK_WIDGET(g->menu_popup->paste_menuitem)); + + /* hide customize */ + popup_menu_hide(g->menu_popup, false, false, false, false, true); + + gtk_menu_popup(g->menu_popup->popup_menu, NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); +} + +/** + * 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) +{ + struct gtk_scaffolding *g = (struct gtk_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; + } + g->toolbarmem = alloc->x; + gtk_widget_size_allocate(widget, alloc); +} + + + + +/** + * init the array g->buttons[] + */ +void nsgtk_scaffolding_toolbar_init(struct gtk_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 = GTK_IMAGE_MENU_ITEM(\ + 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(VIEWSOURCE, view_submenu, viewsource); + ITEM_MAIN(DOWNLOADS, view_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, nav_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); + ITEM_SUB(TOGGLEDEBUGGING, view_submenu, debugging, toggledebugging); + ITEM_SUB(SAVEBOXTREE, view_submenu, debugging, saveboxtree); + ITEM_SUB(SAVEDOMTREE, view_submenu, debugging, savedomtree); + 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(CONTENTS); + SENSITIVITY(DRAWFILE); + SENSITIVITY(POSTSCRIPT); + SENSITIVITY(NEXTTAB); + SENSITIVITY(PREVTAB); + SENSITIVITY(CLOSETAB); + SENSITIVITY(GUIDE); + SENSITIVITY(INFO); +#ifndef WITH_PDF_EXPORT + SENSITIVITY(PDF); +#endif + +#undef ITEM_MAIN +#undef ITEM_SUB +#undef ITEM_BUTTON +#undef ITEM_POP +#undef SENSITIVITY + +} diff --git a/gtk/scaffolding.h b/gtk/scaffolding.h new file mode 100644 index 000000000..7e6983aa9 --- /dev/null +++ b/gtk/scaffolding.h @@ -0,0 +1,157 @@ +/* + * Copyright 2005 James Bursa + * + * 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 . + */ + +#ifndef NETSURF_GTK_SCAFFOLDING_H +#define NETSURF_GTK_SCAFFOLDING_H 1 + +#include +#include +#include + +#include "desktop/gui.h" +#include "desktop/plotters.h" +#include "gtk/menu.h" +#include "gtk/sexy_icon_entry.h" + +typedef struct gtk_scaffolding nsgtk_scaffolding; + +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 gtk_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; + GtkImageMenuItem *main; + GtkImageMenuItem *rclick; + GtkImageMenuItem *popup; + void *mhandler; /* menu item clicked */ + void *bhandler; /* button clicked */ + void *dataplus; /* customization -> toolbar */ + void *dataminus; /* customization -> store */ +}; + +extern nsgtk_scaffolding *scaf_list; + +nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel); + +bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g); + +GtkWindow *nsgtk_scaffolding_window(nsgtk_scaffolding *g); +GtkNotebook *nsgtk_scaffolding_notebook(nsgtk_scaffolding *g); +GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g); +GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g); +GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g); +struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g, + int i); +struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g); +GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g); +struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding + *g); +struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g); +void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g); +nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g); +void nsgtk_scaffolding_toolbar_init(struct gtk_scaffolding *g); +void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g); +void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g); +void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g); +void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char + *content); +void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g); +void nsgtk_scaffolding_set_top_level(struct gui_window *g); + +void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g); + +void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g); +void nsgtk_scaffolding_initial_sensitivity(struct gtk_scaffolding *g); +void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g, gdouble x, + gdouble y); +void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget, + GtkAllocation *alloc, gpointer data); + +gboolean nsgtk_window_url_activate_event(GtkWidget *, gpointer); +gboolean nsgtk_window_url_changed(GtkWidget *, GdkEventKey *, gpointer); + +#endif /* NETSURF_GTK_SCAFFOLDING_H */ diff --git a/gtk/schedule.c b/gtk/schedule.c new file mode 100644 index 000000000..9491ccb67 --- /dev/null +++ b/gtk/schedule.c @@ -0,0 +1,128 @@ +/* + * Copyright 2006-2007 Daniel Silverstone + * + * 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 . + */ + +#include +#include +#include + +#include "desktop/browser.h" +#include "gtk/schedule.h" + +#ifdef DEBUG_GTK_SCHEDULE +#include "utils/log.h" +#else +#define LOG(X) +#endif + +/** 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. */ +} _nsgtk_callback_t; + +/** List of callbacks which have occurred and are pending running. */ +static GList *pending_callbacks = NULL; +/** List of callbacks which are queued to occur in the future. */ +static GList *queued_callbacks = NULL; +/** List of callbacks which are about to be run in this ::schedule_run. */ +static GList *this_run = NULL; + +static gboolean +nsgtk_schedule_generic_callback(gpointer data) +{ + _nsgtk_callback_t *cb = (_nsgtk_callback_t *)(data); + if (cb->callback_killed) { + /* This callback instance has been killed. */ + LOG(("CB at %p already dead.", cb)); + } + queued_callbacks = g_list_remove(queued_callbacks, cb); + pending_callbacks = g_list_append(pending_callbacks, cb); + return FALSE; +} + +static void +nsgtk_schedule_kill_callback(void *_target, void *_match) +{ + _nsgtk_callback_t *target = (_nsgtk_callback_t *)_target; + _nsgtk_callback_t *match = (_nsgtk_callback_t *)_match; + if ((target->callback == match->callback) && + (target->context == match->context)) { + LOG(("Found match for %p(%p), killing.", + target->callback, target->context)); + target->callback = NULL; + target->context = NULL; + target->callback_killed = true; + } +} + +void +schedule_remove(void (*callback)(void *p), void *p) +{ + _nsgtk_callback_t cb_match = { + .callback = callback, + .context = p, + }; + + g_list_foreach(queued_callbacks, + nsgtk_schedule_kill_callback, &cb_match); + g_list_foreach(pending_callbacks, + nsgtk_schedule_kill_callback, &cb_match); + g_list_foreach(this_run, + nsgtk_schedule_kill_callback, &cb_match); +} + +void +schedule(int t, void (*callback)(void *p), void *p) +{ + const int msec_timeout = t * 10; + _nsgtk_callback_t *cb = malloc(sizeof(_nsgtk_callback_t)); + /* Kill any pending schedule of this kind. */ + schedule_remove(callback, p); + cb->callback = callback; + cb->context = p; + cb->callback_killed = false; + /* Prepend is faster right now. */ + queued_callbacks = g_list_prepend(queued_callbacks, cb); + g_timeout_add(msec_timeout, nsgtk_schedule_generic_callback, cb); +} + +bool +schedule_run(void) +{ + /* Capture this run of pending callbacks into the list. */ + this_run = pending_callbacks; + + if (this_run == NULL) + return false; /* Nothing to do */ + + /* Clear the pending list. */ + pending_callbacks = NULL; + + LOG(("Captured a run of %d callbacks to fire.", g_list_length(this_run))); + + /* Run all the callbacks which made it this far. */ + while (this_run != NULL) { + _nsgtk_callback_t *cb = (_nsgtk_callback_t *)(this_run->data); + this_run = g_list_remove(this_run, this_run->data); + if (!cb->callback_killed) + cb->callback(cb->context); + free(cb); + } + return true; +} diff --git a/gtk/schedule.h b/gtk/schedule.h new file mode 100644 index 000000000..c63215e88 --- /dev/null +++ b/gtk/schedule.h @@ -0,0 +1,25 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NETSURF_GTK_CALLBACK_H +#define NETSURF_GTK_CALLBACK_H 1 + +typedef void (*gtk_callback)(void *p); +bool schedule_run(void); + +#endif /* NETSURF_GTK_CALLBACK_H */ diff --git a/gtk/search.c b/gtk/search.c new file mode 100644 index 000000000..b4127eefb --- /dev/null +++ b/gtk/search.c @@ -0,0 +1,266 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + + + /** \file + * Free text search (front component) + */ +#include +#include +#include + +#include "gtk/search.h" +#include "gtk/scaffolding.h" +#include "gtk/window.h" +#include "utils/config.h" +#include "content/content.h" +#include "content/hlcache.h" +#include "desktop/browser.h" +#include "desktop/gui.h" +#include "desktop/search.h" +#include "desktop/searchweb.h" +#include "desktop/selection.h" +#include "render/box.h" +#include "render/html.h" +#include "utils/config.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utils.h" + +static void nsgtk_search_init(struct gtk_scaffolding *g); +static void nsgtk_search_set_status(bool found, void *p); +static void nsgtk_search_set_hourglass(bool active, void *p); +static void nsgtk_search_add_recent(const char *string, void *p); + +static struct search_callbacks nsgtk_search_callbacks = { + nsgtk_search_set_forward_state, + nsgtk_search_set_back_state, + nsgtk_search_set_status, + nsgtk_search_set_hourglass, + nsgtk_search_add_recent +}; + +/** connected to the search forward button */ + +gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + struct browser_window *bw = gui_window_get_browser_window( + nsgtk_scaffolding_top_level(g)); + nsgtk_search_init(g); + 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); + if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) + search_step(bw->search_context, flags, gtk_entry_get_text( + nsgtk_scaffolding_search(g)->entry)); + return TRUE; +} + +/** connected to the search back button */ + +gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + struct browser_window *bw = gui_window_get_browser_window( + nsgtk_scaffolding_top_level(g)); + nsgtk_search_init(g); + 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); + if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) + search_step(bw->search_context, flags, gtk_entry_get_text( + nsgtk_scaffolding_search(g)->entry)); + return TRUE; +} + +/** preparatory code when the search bar is made visible initially */ + +void nsgtk_search_init(struct gtk_scaffolding *g) +{ + hlcache_handle *c; + + assert(gui_window_get_browser_window(nsgtk_scaffolding_top_level(g)) + != NULL); + + c = gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))-> + current_content; + + if ((!c) || (content_get_type(c) != CONTENT_HTML && + content_get_type(c) != CONTENT_TEXTPLAIN)) + return; + +} + +/** connected to the search close button */ + +gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + nsgtk_scaffolding_toggle_search_bar_visibility(g); + return TRUE; +} + +/** connected to the search entry [typing] */ + +gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + struct browser_window *bw = gui_window_get_browser_window( + nsgtk_scaffolding_top_level(g)); + if ((bw != NULL) && (bw->search_context != NULL)) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, (void *)bw); + nsgtk_search_set_back_state(true, (void *)bw); + return TRUE; +} + +/** connected to the search entry [return key] */ + +gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + struct browser_window *bw = gui_window_get_browser_window( + nsgtk_scaffolding_top_level(g)); + nsgtk_search_init(g); + 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); + if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw)) + search_step(bw->search_context, flags, gtk_entry_get_text( + nsgtk_scaffolding_search(g)->entry)); + return FALSE; +} + +/** allows escape key to close search bar too */ + +gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + if (event->keyval == GDK_Escape) { + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + nsgtk_scaffolding_toggle_search_bar_visibility(g); + } + return FALSE; +} + +/** connected to the websearch entry [return key] */ + +gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data) +{ + struct gtk_scaffolding *g = (struct gtk_scaffolding *)data; + temp_open_background = 0; + search_web_new_window(gui_window_get_browser_window( + nsgtk_scaffolding_top_level(g)), + (char *)gtk_entry_get_text(GTK_ENTRY( + nsgtk_scaffolding_websearch(g)))); + temp_open_background = -1; + return TRUE; +} + +/** + * 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) +{ + struct gtk_scaffolding *g = (struct gtk_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; +} + +/** +* Change the displayed search status. +* \param found search pattern matched in text +* \param p the pointer sent to search_verify_new() / search_create_context() +*/ + +void nsgtk_search_set_status(bool found, void *p) +{ +} + +/** +* display hourglass while searching +* \param active start/stop indicator +* \param p the pointer sent to search_verify_new() / search_create_context() +*/ + +void nsgtk_search_set_hourglass(bool active, void *p) +{ +} + +/** +* add search string to recent searches list +* front is at liberty how to implement the bare notification +* should normally store a strdup() of the string; +* core gives no guarantee of the integrity of the const char * +* \param string search pattern +* \param p the pointer sent to search_verify_new() / search_create_context() +*/ + +void nsgtk_search_add_recent(const char *string, void *p) +{ +} + +/** +* activate search forwards button in gui +* \param active activate/inactivate +* \param p the pointer sent to search_verify_new() / search_create_context() +*/ + +void nsgtk_search_set_forward_state(bool active, void *p) +{ + struct browser_window *bw = (struct browser_window *)p; + if ((bw != NULL) && (bw->window != NULL)) { + struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window); + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search( + g)->buttons[1]), active); + } +} + +/** +* activate search back button in gui +* \param active activate/inactivate +* \param p the pointer sent to search_verify_new() / search_create_context() +*/ + +void nsgtk_search_set_back_state(bool active, void *p) +{ + struct browser_window *bw = (struct browser_window *)p; + if ((bw != NULL) && (bw->window != NULL)) { + struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window); + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search( + g)->buttons[0]), active); + } +} diff --git a/gtk/search.h b/gtk/search.h new file mode 100644 index 000000000..869a3cd8a --- /dev/null +++ b/gtk/search.h @@ -0,0 +1,39 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#ifndef _NETSURF_GTK_SEARCH_H_ +#define _NETSURF_GTK_SEARCH_H_ + +#include +#include "gtk/scaffolding.h" + +void nsgtk_search_bar_toggle_visibility(struct gtk_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); +void nsgtk_search_set_forward_state(bool active, void *p); +void nsgtk_search_set_back_state(bool active, void *p); + +#endif diff --git a/gtk/selection.c b/gtk/selection.c new file mode 100644 index 000000000..68ab88f71 --- /dev/null +++ b/gtk/selection.c @@ -0,0 +1,119 @@ +/* + * Copyright 2008 Mike Lester + * + * 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 . + */ + +#include +#include + +#include "utils/log.h" + +#include "desktop/gui.h" +#include "desktop/textinput.h" +#include "desktop/selection.h" +#include "desktop/browser.h" +#include "gtk/selection.h" +#include "gtk/window.h" +#include "utils/utf8.h" + +static GString *current_selection = NULL; +static GtkClipboard *clipboard; + +static bool copy_handler(const char *text, size_t length, struct box *box, + void *handle, const char *whitespace_text, + size_t whitespace_length); + + +bool gui_add_to_clipboard(const char *text, size_t length, bool space) +{ + /* add the text from this box */ + current_selection = g_string_append_len (current_selection, + text, length); + if (space) g_string_append (current_selection, " "); + return true; +} + +bool copy_handler(const char *text, size_t length, struct box *box, + void *handle, const char *whitespace_text, + size_t whitespace_length) +{ + /* add any whitespace which precedes the text from this box */ + if (whitespace_text) { + if (!gui_add_to_clipboard(whitespace_text, + whitespace_length, false)) { + return false; + } + } + /* add the text from this box */ + if (!gui_add_to_clipboard(text, length, box->space)) + return false; + + return true; +} + +bool gui_copy_to_clipboard(struct selection *s) +{ + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + if (s->defined && selection_traverse(s, copy_handler, NULL)) + gui_commit_clipboard(); + return TRUE; +} + +void gui_start_selection(struct gui_window *g) +{ + if (current_selection == NULL) + current_selection = g_string_new(NULL); + else + g_string_set_size(current_selection, 0); + + gtk_widget_grab_focus(GTK_WIDGET(nsgtk_window_get_layout(g))); +} + +void gui_clear_selection(struct gui_window *g) +{ +} + +void gui_paste_from_clipboard(struct gui_window *g, int x, int y) +{ + gchar *text; + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + text = gtk_clipboard_wait_for_text (clipboard); + /* clipboard_wait... converts the string to utf8 for us */ + if (text != NULL) + browser_window_paste_text(gui_window_get_browser_window(g), + text, strlen(text), true); + g_free(text); +} + +bool gui_empty_clipboard(void) +{ + if (!current_selection) + current_selection = g_string_new(NULL); + else + g_string_set_size(current_selection, 0); + + return true; +} + +bool gui_commit_clipboard(void) +{ + clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text(clipboard, current_selection->str, -1); + gui_empty_clipboard(); + + return true; +} + diff --git a/gtk/selection.h b/gtk/selection.h new file mode 100644 index 000000000..c2a0b35f4 --- /dev/null +++ b/gtk/selection.h @@ -0,0 +1,25 @@ +/* + * Copyright 2008 Mike Lester + * + * 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 . + */ + +#ifndef GTK_SELECTION_H +#define GTK_SELECTION_H + +#include +#include "desktop/gui.h" + +#endif diff --git a/gtk/sexy_icon_entry.c b/gtk/sexy_icon_entry.c index adf4abc2c..b71e92ebe 100644 --- a/gtk/sexy_icon_entry.c +++ b/gtk/sexy_icon_entry.c @@ -22,11 +22,11 @@ * or write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "gtk/sexy_icon_entry.h" #include #include -#include "gtk/gtk_compat.h" + +#include "gtk/sexy_icon_entry.h" +#include "gtk/compat.h" #define ICON_MARGIN 2 #define MAX_ICONS 2 diff --git a/gtk/tabs.c b/gtk/tabs.c new file mode 100644 index 000000000..07e6b3365 --- /dev/null +++ b/gtk/tabs.c @@ -0,0 +1,217 @@ +/* + * Copyright 2008 Michael Lester + * + * 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 . + */ + +#include +#include +#include "gtk/window.h" +#include "gtk/gui.h" +#include "desktop/browser.h" +#include "content/content.h" +#include "desktop/options.h" +#include "desktop/search.h" +#include "utils/utils.h" +#include "gtk/options.h" +#include "gtk/search.h" +#include "gtk/tabs.h" + +#define TAB_WIDTH_N_CHARS 15 + +static GtkWidget *nsgtk_tab_label_setup(struct gui_window *window); +static void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, + guint page); +static void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, + GtkWidget *close_button); + +static void nsgtk_tab_page_changed(GtkNotebook *notebook, gpointer *page, + gint page_num); + +void nsgtk_tab_options_changed(GtkWidget *tabs) +{ + nsgtk_tab_visibility_update(GTK_NOTEBOOK(tabs), NULL, 0); +} + +void nsgtk_tab_init(GtkWidget *tabs) +{ + g_signal_connect(tabs, "switch-page", + G_CALLBACK(nsgtk_tab_page_changed), NULL); + + g_signal_connect(tabs, "page-removed", + G_CALLBACK(nsgtk_tab_visibility_update), NULL); + g_signal_connect(tabs, "page-added", + G_CALLBACK(nsgtk_tab_visibility_update), NULL); + nsgtk_tab_options_changed(tabs); +} + +void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background) +{ + GtkWidget *tabs = GTK_WIDGET(nsgtk_scaffolding_notebook( + nsgtk_get_scaffold(window))); + GtkWidget *tabBox = nsgtk_tab_label_setup(window); + gint remember = gtk_notebook_get_current_page(GTK_NOTEBOOK(tabs)); + gtk_notebook_append_page(GTK_NOTEBOOK(tabs), tab_contents, tabBox); + /*causes gtk errors can't set a parent */ + gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(tabs), + tab_contents, + true); + gtk_widget_show_all(tab_contents); + gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), + gtk_notebook_get_n_pages(GTK_NOTEBOOK(tabs)) - 1); + if (option_new_blank) { + /*char *blankpage = malloc(strlen(res_dir_location) + + SLEN("file:///blankpage") + 1); + blankpage = g_strconcat("file:///", res_dir_location, + "blankpage", NULL); */ + /* segfaults + struct browser_window *bw = + gui_window_get_browser_window(window); + browser_window_go(bw, blankpage, 0, true); */ + /* free(blankpage); */ + } + if (background) + gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), remember); + gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_urlbar( + nsgtk_get_scaffold(window)))); +} + +void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child, + guint page) +{ + gint num_pages = gtk_notebook_get_n_pages(notebook); + if (option_show_single_tab == true || num_pages > 1) + gtk_notebook_set_show_tabs(notebook, TRUE); + else + gtk_notebook_set_show_tabs(notebook, FALSE); +} + +void nsgtk_tab_set_title(struct gui_window *g, const char *title) +{ + GtkWidget *label; + GtkWidget *tab; + tab = nsgtk_window_get_tab(g); + gboolean is_top_level = (tab != NULL); + + if (is_top_level) { + label = g_object_get_data(G_OBJECT(tab), "label"); + gtk_label_set_text(GTK_LABEL(label), title); + gtk_widget_set_tooltip_text(tab, title); + } +} + +GtkWidget *nsgtk_tab_label_setup(struct gui_window *window) +{ + GtkWidget *hbox, *label, *button, *close; + GtkRcStyle *rcstyle; + + hbox = gtk_hbox_new(FALSE, 2); + + if (option_new_blank == true) + label = gtk_label_new("New Tab"); + else + label = gtk_label_new("Loading..."); + gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); + gtk_label_set_single_line_mode(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_misc_set_padding(GTK_MISC(label), 0, 0); + gtk_widget_show(label); + + button = gtk_button_new(); + + close = gtk_image_new_from_stock("gtk-close", GTK_ICON_SIZE_MENU); + gtk_container_add(GTK_CONTAINER(button), close); + gtk_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."); + + rcstyle = gtk_rc_style_new(); + rcstyle->xthickness = rcstyle->ythickness = 0; + gtk_widget_modify_style(button, rcstyle); + g_object_unref(rcstyle); + + 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); + + 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); + + nsgtk_window_set_tab(window, hbox); + + gtk_widget_show_all(hbox); + return hbox; +} + +void nsgtk_tab_update_size(GtkWidget *hbox, GtkStyle *previous_style, + GtkWidget *close_button) +{ + PangoFontMetrics *metrics; + PangoContext *context; + int char_width, h, w; + + context = gtk_widget_get_pango_context(hbox); + metrics = pango_context_get_metrics(context, hbox->style->font_desc, + pango_context_get_language(context)); + + char_width = pango_font_metrics_get_approximate_digit_width(metrics); + pango_font_metrics_unref(metrics); + + gtk_icon_size_lookup_for_settings(gtk_widget_get_settings (hbox), + GTK_ICON_SIZE_MENU, &w, &h); + + gtk_widget_set_size_request(hbox, + TAB_WIDTH_N_CHARS * PANGO_PIXELS(char_width) + 2 * w, + -1); + + gtk_widget_set_size_request(close_button, w + 4, h + 4); +} + +void nsgtk_tab_page_changed(GtkNotebook *notebook, gpointer *page, + gint page_num) +{ + GtkWidget *window = gtk_notebook_get_nth_page(notebook, page_num); + struct gui_window *gw = g_object_get_data(G_OBJECT(window), + "gui_window"); + if (gw == NULL) + return; + struct browser_window *bw = gui_window_get_browser_window(gw); + if (bw == NULL) + return; + if (bw->search_context != NULL) + search_destroy_context(bw->search_context); + nsgtk_search_set_forward_state(true, bw); + nsgtk_search_set_back_state(true, bw); + nsgtk_scaffolding_set_top_level(gw); +} + +void nsgtk_tab_close_current(GtkNotebook *notebook) +{ + gint curr_page = gtk_notebook_get_current_page(notebook); + GtkWidget *window = gtk_notebook_get_nth_page(notebook, curr_page); + struct gui_window *gw = g_object_get_data(G_OBJECT(window), + "gui_window"); + + if (gtk_notebook_get_n_pages(notebook) < 2) + return; /* wicked things happen if we close the last tab */ + + nsgtk_window_destroy_browser(gw); + /* deletes 2 notebook tabs at a time! + gtk_notebook_remove_page(notebook, curr_page); */ +} diff --git a/gtk/tabs.h b/gtk/tabs.h new file mode 100644 index 000000000..969383001 --- /dev/null +++ b/gtk/tabs.h @@ -0,0 +1,30 @@ +/* + * Copyright 2008 Michael Lester + * + * 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 . + */ + +#ifndef _NETSURF_GTK_TABS_H_ +#define _NETSURF_GTK_TABS_H_ + +struct gui_window; + +void nsgtk_tab_init(GtkWidget *tabs); +void nsgtk_tab_add(struct gui_window *window, GtkWidget *tab_contents, bool background); +void nsgtk_tab_set_title(struct gui_window *g, const char *title); +void nsgtk_tab_options_changed(GtkWidget *tabs); +void nsgtk_tab_close_current(GtkNotebook *notebook); + +#endif diff --git a/gtk/theme.c b/gtk/theme.c new file mode 100644 index 000000000..dc5eb5ee4 --- /dev/null +++ b/gtk/theme.c @@ -0,0 +1,786 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include +#include +#include + +#include "content/content.h" +#include "content/content_type.h" +#include "content/hlcache.h" +#include "gtk/gui.h" +#include "gtk/scaffolding.h" +#include "gtk/menu.h" +#include "gtk/theme.h" +#include "gtk/window.h" +#include "gtk/options.h" +#include "gtk/dialogs/options.h" +#include "utils/container.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utils.h" + +enum image_sets { + IMAGE_SET_MAIN_MENU = 0, + IMAGE_SET_RCLICK_MENU, + IMAGE_SET_POPUP_MENU, + IMAGE_SET_BUTTONS, + IMAGE_SET_COUNT +}; + +struct nsgtk_theme_cache { + GdkPixbuf *image[PLACEHOLDER_BUTTON]; + GdkPixbuf *searchimage[SEARCH_BUTTONS_COUNT]; + /* apng throbber image */ +}; + +static char *current_theme_name = NULL; +static struct nsgtk_theme_cache *theme_cache_menu = NULL; +static struct nsgtk_theme_cache *theme_cache_toolbar = NULL; + +static struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s); +static GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, + GtkIconSize s); +static bool nsgtk_theme_verify(const char *themename); +static void nsgtk_theme_cache_image(nsgtk_toolbar_button i, + const char *filename, const char *path); +static void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i, + const char *filename, const char *path); + +#ifdef WITH_THEME_INSTALL +static nserror theme_install_callback(hlcache_handle *c, + const hlcache_event *event, void *pw); +static bool theme_install_read(const char *data, unsigned long len); +#endif + +/** + * called during gui init phase to retrieve theme name from file then + * implement + */ + +void nsgtk_theme_init(void) +{ + size_t len; + if (option_current_theme == 0) + return; + len = SLEN("themelist") + strlen(res_dir_location) + 1; + char themefile[len]; + snprintf(themefile, len, "%s%s", res_dir_location, "themelist"); + nsgtk_scaffolding *list = scaf_list; + nsgtk_theme_verify(NULL); + FILE *fp = fopen(themefile, "r"); + if (fp == NULL) + return; + char buf[50]; + int row_count = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (buf[0] == '\0') + continue; + + if (row_count++ == option_current_theme) { + if (current_theme_name != NULL) + free(current_theme_name); + /* clear the '\n' ["\n\0"->"\0\0"] */ + buf[strlen(buf) - 1] = '\0'; + current_theme_name = strdup(buf); + break; + } + } + fclose(fp); + + while (list != NULL) { + nsgtk_theme_implement(list); + list = nsgtk_scaffolding_iterate(list); + } +} + +/** + * return reference to static global current_theme_name; caller then has + * responsibility for global reference + */ + +char *nsgtk_theme_name(void) +{ + return current_theme_name; +} + +/** + * set static global current_theme_name from param; caller is responsible + * for the integrity of the global reference + */ + +void nsgtk_theme_set_name(char *name) +{ + current_theme_name = name; +} + +/** + * adds a theme name to the list of themes + */ + +void nsgtk_theme_add(const char *themename) +{ + size_t len; + GtkWidget *notification, *label; + len = SLEN("themelist") + strlen(res_dir_location) + 1; + char themefile[len]; + snprintf(themefile, len, "%s%s", res_dir_location, "themelist"); + /* conduct verification here; no adding duplicates to list */ + if (nsgtk_theme_verify(themename) == false) { + warn_user(messages_get("gtkThemeDup"), 0); + return; + } + FILE *fp = fopen(themefile, "a"); + if (fp == NULL) { + warn_user(messages_get("gtkFileError"), themefile); + return; + } + fprintf(fp, "%s\n", themename); + fclose(fp); + + /* notification that theme was added successfully */ + notification = gtk_dialog_new_with_buttons(messages_get("gtkThemeAdd"), + NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, + GTK_RESPONSE_NONE, NULL); + if (notification == NULL) { + warn_user(messages_get("NoMemory"), 0); + return; + } + len = SLEN("\t\t\t\t\t\t") + strlen(messages_get("gtkThemeAdd")) + 1; + char labelcontent[len]; + snprintf(labelcontent, len, "\t\t\t%s\t\t\t", + messages_get("gtkThemeAdd")); + label = gtk_label_new(labelcontent); + if (label == NULL) { + warn_user(messages_get("NoMemory"), 0); + return; + } + g_signal_connect_swapped(notification, "response", + G_CALLBACK(gtk_widget_destroy), notification); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notification)->vbox), label); + gtk_widget_show_all(notification); + + /* update combo */ + if (wndPreferences == NULL) + return; + nsgtk_options_combo_theme_add(themename); + +} + +/** + * \param themename contains a name of theme to check whether it may + * properly be added to the list; alternatively NULL to check the integrity + * of the list + * \return true for themename may be added / every item in the list is + * a valid directory + */ + +bool nsgtk_theme_verify(const char *themename) +{ + long filelength; + FILE *fp; + size_t val = SLEN("themelist") + strlen(res_dir_location) + 1; + char buf[50]; + char themefile[val]; + snprintf(themefile, val, "%s%s", res_dir_location, "themelist"); + if (themename == NULL) { + char *filecontent, *testfile; + struct stat sta; + fp = fopen(themefile, "r+"); + if (fp == NULL) { + warn_user(messages_get("gtkFileError"), themefile); + return true; + } + fseek(fp, 0L, SEEK_END); + filelength = ftell(fp); + filecontent = malloc(filelength + + SLEN("gtk default theme\n") + SLEN("\n") + + 1); + if (filecontent == NULL) { + warn_user(messages_get("NoMemory"), 0); + fclose(fp); + return true; + } + strcpy(filecontent, "gtk default theme\n"); + fseek(fp, 0L, SEEK_SET); + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* iterate list */ + buf[strlen(buf) - 1] = '\0'; + /* "\n\0" -> "\0\0" */ + testfile = malloc(strlen(res_dir_location) + + SLEN("themes/") + strlen(buf) + 1); + if (testfile == NULL) { + warn_user(messages_get("NoMemory"), 0); + free(filecontent); + fclose(fp); + return false; + } + sprintf(testfile, "%sthemes/%s", res_dir_location, + buf); + /* check every directory */ + if (access(testfile, R_OK) == 0) { + stat(testfile, &sta); + if (S_ISDIR(sta.st_mode)) { + buf[strlen(buf)] = '\n'; + /* "\0\0" -> "\n\0" */ + strcat(filecontent, buf); + } + } + free(testfile); + } + fclose(fp); + fp = fopen(themefile, "w"); + if (fp == NULL) { + warn_user(messages_get("gtkFileError"), themefile); + free(filecontent); + return true; + } + val = fwrite(filecontent, strlen(filecontent), 1, fp); + if (val == 0) + LOG(("empty write themelist")); + fclose(fp); + free(filecontent); + return true; + } else { + fp = fopen(themefile, "r"); + if (fp == NULL) { + warn_user(messages_get("gtkFileError"), themefile); + return false; + } + while (fgets(buf, sizeof(buf), fp) != NULL) { + buf[strlen(buf) - 1] = '\0'; + /* "\n\0" -> "\0\0" */ + if (strcmp(buf, themename) == 0) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; + } + +} + +/** + * sets the images for a particular scaffolding according to the current theme + */ + +void nsgtk_theme_implement(struct gtk_scaffolding *g) +{ + struct nsgtk_theme *theme[IMAGE_SET_COUNT]; + int i; + struct nsgtk_button_connect *button; + struct gtk_search *search; + + for (i = 0; i <= IMAGE_SET_POPUP_MENU; i++) + theme[i] = nsgtk_theme_load(GTK_ICON_SIZE_MENU); + + theme[IMAGE_SET_BUTTONS] = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) || + (i == WEBSEARCH_ITEM)) + continue; + button = nsgtk_scaffolding_button(g, i); + if (button == NULL) + continue; + /* gtk_image_menu_item_set_image accepts NULL image */ + if ((button->main != NULL) && + (theme[IMAGE_SET_MAIN_MENU] != NULL)) { + gtk_image_menu_item_set_image(button->main, + GTK_WIDGET( + theme[IMAGE_SET_MAIN_MENU]-> + image[i])); + gtk_widget_show_all(GTK_WIDGET(button->main)); + } + if ((button->rclick != NULL) && + (theme[IMAGE_SET_RCLICK_MENU] != NULL)) { + gtk_image_menu_item_set_image(button->rclick, + GTK_WIDGET( + theme[IMAGE_SET_RCLICK_MENU]-> + image[i])); + gtk_widget_show_all(GTK_WIDGET(button->rclick)); + } + if ((button->popup != NULL) && + (theme[IMAGE_SET_POPUP_MENU] != NULL)) { + gtk_image_menu_item_set_image(button->popup, + GTK_WIDGET( + theme[IMAGE_SET_POPUP_MENU]-> + image[i])); + gtk_widget_show_all(GTK_WIDGET(button->popup)); + } + if ((button->location != -1) && (button->button != NULL) && + (theme[IMAGE_SET_BUTTONS] != NULL)) { + gtk_tool_button_set_icon_widget( + GTK_TOOL_BUTTON(button->button), + GTK_WIDGET( + theme[IMAGE_SET_BUTTONS]-> + image[i])); + gtk_widget_show_all(GTK_WIDGET(button->button)); + } + } + + /* set search bar images */ + search = nsgtk_scaffolding_search(g); + if ((search != NULL) && (theme[IMAGE_SET_MAIN_MENU] != NULL)) { + /* gtk_tool_button_set_icon_widget accepts NULL image */ + if (search->buttons[SEARCH_BACK_BUTTON] != NULL) { + gtk_tool_button_set_icon_widget( + search->buttons[SEARCH_BACK_BUTTON], + GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> + searchimage[SEARCH_BACK_BUTTON])); + gtk_widget_show_all(GTK_WIDGET( + search->buttons[SEARCH_BACK_BUTTON])); + } + if (search->buttons[SEARCH_FORWARD_BUTTON] != NULL) { + gtk_tool_button_set_icon_widget( + search->buttons[SEARCH_FORWARD_BUTTON], + GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> + searchimage[SEARCH_FORWARD_BUTTON])); + gtk_widget_show_all(GTK_WIDGET( + search->buttons[ + SEARCH_FORWARD_BUTTON])); + } + if (search->buttons[SEARCH_CLOSE_BUTTON] != NULL) { + gtk_tool_button_set_icon_widget( + search->buttons[SEARCH_CLOSE_BUTTON], + GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]-> + searchimage[SEARCH_CLOSE_BUTTON])); + gtk_widget_show_all(GTK_WIDGET( + search->buttons[SEARCH_CLOSE_BUTTON])); + } + } + for (i = 0; i < IMAGE_SET_COUNT; i++) + if (theme[i] != NULL) + free(theme[i]); +} + +/** + * creates a set of images to add to buttons / menus + * loads images from cache, calling an update to the cache when necessary + * \return a struct nsgtk_theme is an array of images + */ + +struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s) +{ + if (current_theme_name == NULL) + return nsgtk_theme_default(s); + + struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme)); + if (theme == NULL) + return theme; + + if ((theme_cache_menu == NULL) || (theme_cache_toolbar == NULL)) + nsgtk_theme_prepare(); + + /* load theme from cache */ + struct nsgtk_theme_cache *cachetheme = (s == GTK_ICON_SIZE_MENU) ? + theme_cache_menu : theme_cache_toolbar; + if (cachetheme == NULL) { + free(theme); + return NULL; + } + +#define SET_BUTTON_IMAGE(p, q, r)\ + if (p->image[q##_BUTTON] != NULL)\ + r->image[q##_BUTTON] = GTK_IMAGE(gtk_image_new_from_pixbuf(\ + p->image[q##_BUTTON]));\ + else\ + r->image[q##_BUTTON] = nsgtk_theme_image_default(\ + q##_BUTTON, s); + + SET_BUTTON_IMAGE(cachetheme, BACK, theme) + SET_BUTTON_IMAGE(cachetheme, HISTORY, theme) + SET_BUTTON_IMAGE(cachetheme, FORWARD, theme) + SET_BUTTON_IMAGE(cachetheme, STOP, theme) + SET_BUTTON_IMAGE(cachetheme, RELOAD, theme) + SET_BUTTON_IMAGE(cachetheme, HOME, theme) + SET_BUTTON_IMAGE(cachetheme, NEWWINDOW, theme) + SET_BUTTON_IMAGE(cachetheme, NEWTAB, theme) + SET_BUTTON_IMAGE(cachetheme, OPENFILE, theme) + SET_BUTTON_IMAGE(cachetheme, CLOSETAB, theme) + SET_BUTTON_IMAGE(cachetheme, CLOSEWINDOW, theme) + SET_BUTTON_IMAGE(cachetheme, SAVEPAGE, theme) + SET_BUTTON_IMAGE(cachetheme, PRINTPREVIEW, theme) + SET_BUTTON_IMAGE(cachetheme, PRINT, theme) + SET_BUTTON_IMAGE(cachetheme, QUIT, theme) + SET_BUTTON_IMAGE(cachetheme, CUT, theme) + SET_BUTTON_IMAGE(cachetheme, COPY, theme) + SET_BUTTON_IMAGE(cachetheme, PASTE, theme) + SET_BUTTON_IMAGE(cachetheme, DELETE, theme) + SET_BUTTON_IMAGE(cachetheme, SELECTALL, theme) + SET_BUTTON_IMAGE(cachetheme, PREFERENCES, theme) + SET_BUTTON_IMAGE(cachetheme, ZOOMPLUS, theme) + SET_BUTTON_IMAGE(cachetheme, ZOOMMINUS, theme) + SET_BUTTON_IMAGE(cachetheme, ZOOMNORMAL, theme) + SET_BUTTON_IMAGE(cachetheme, FULLSCREEN, theme) + SET_BUTTON_IMAGE(cachetheme, VIEWSOURCE, theme) + SET_BUTTON_IMAGE(cachetheme, CONTENTS, theme) + SET_BUTTON_IMAGE(cachetheme, ABOUT, theme) + SET_BUTTON_IMAGE(cachetheme, PDF, theme) + SET_BUTTON_IMAGE(cachetheme, PLAINTEXT, theme) + SET_BUTTON_IMAGE(cachetheme, DRAWFILE, theme) + SET_BUTTON_IMAGE(cachetheme, POSTSCRIPT, theme) + SET_BUTTON_IMAGE(cachetheme, FIND, theme) + SET_BUTTON_IMAGE(cachetheme, DOWNLOADS, theme) + SET_BUTTON_IMAGE(cachetheme, SAVEWINDOWSIZE, theme) + SET_BUTTON_IMAGE(cachetheme, TOGGLEDEBUGGING, theme) + SET_BUTTON_IMAGE(cachetheme, SAVEBOXTREE, theme) + SET_BUTTON_IMAGE(cachetheme, SAVEDOMTREE, theme) + SET_BUTTON_IMAGE(cachetheme, LOCALHISTORY, theme) + SET_BUTTON_IMAGE(cachetheme, GLOBALHISTORY, theme) + SET_BUTTON_IMAGE(cachetheme, ADDBOOKMARKS, theme) + SET_BUTTON_IMAGE(cachetheme, SHOWBOOKMARKS, theme) + SET_BUTTON_IMAGE(cachetheme, SHOWCOOKIES, theme) + SET_BUTTON_IMAGE(cachetheme, OPENLOCATION, theme) + SET_BUTTON_IMAGE(cachetheme, NEXTTAB, theme) + SET_BUTTON_IMAGE(cachetheme, PREVTAB, theme) + SET_BUTTON_IMAGE(cachetheme, GUIDE, theme) + SET_BUTTON_IMAGE(cachetheme, INFO, theme) +#undef SET_BUTTON_IMAGE +#define SET_BUTTON_IMAGE(p, q, qq, r)\ + if (qq->searchimage[SEARCH_##p##_BUTTON] != NULL)\ + r->searchimage[SEARCH_##p##_BUTTON] =\ + GTK_IMAGE(gtk_image_new_from_pixbuf(\ + qq->searchimage[\ + SEARCH_##p##_BUTTON]));\ + else if (qq->image[q##_BUTTON] != NULL)\ + r->searchimage[SEARCH_##p##_BUTTON] =\ + GTK_IMAGE(gtk_image_new_from_pixbuf(\ + qq->image[q##_BUTTON]));\ + else\ + r->searchimage[SEARCH_##p##_BUTTON] =\ + nsgtk_theme_image_default(\ + PLACEHOLDER_BUTTON + SEARCH_##p##_BUTTON, s); + + SET_BUTTON_IMAGE(BACK, BACK, cachetheme, theme) + SET_BUTTON_IMAGE(FORWARD, FORWARD, cachetheme, theme) + SET_BUTTON_IMAGE(CLOSE, CLOSEWINDOW, cachetheme, theme) +#undef SET_BUTTON_IMAGE + return theme; +} + +/** + * caches individual theme images from file + * \param i the toolbar button reference + * \param filename the image file name + * \param path the path to the theme folder + */ +void nsgtk_theme_cache_image(nsgtk_toolbar_button i, const char *filename, + const char *path) +{ + char fullpath[strlen(filename) + strlen(path) + 1]; + sprintf(fullpath, "%s%s", path, filename); + if (theme_cache_toolbar != NULL) + theme_cache_toolbar->image[i] = + gdk_pixbuf_new_from_file_at_size(fullpath, + 24, 24, NULL); + if (theme_cache_menu != NULL) + theme_cache_menu->image[i] = gdk_pixbuf_new_from_file_at_size( + fullpath, 16, 16, NULL); +} + +void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i, + const char *filename, const char *path) +{ + char fullpath[strlen(filename) + strlen(path) + 1]; + sprintf(fullpath, "%s%s", path, filename); + if (theme_cache_toolbar != NULL) + theme_cache_toolbar->searchimage[i] = + gdk_pixbuf_new_from_file_at_size(fullpath, + 24, 24, NULL); + if (theme_cache_menu != NULL) + theme_cache_menu->searchimage[i] = + gdk_pixbuf_new_from_file_at_size(fullpath, + 16, 16, NULL); +} + +/** + * caches theme images from file as pixbufs + */ +void nsgtk_theme_prepare(void) +{ + if (current_theme_name == NULL) + return; + if (theme_cache_menu == NULL) + theme_cache_menu = malloc(sizeof(struct nsgtk_theme_cache)); + if (theme_cache_toolbar == NULL) + theme_cache_toolbar = malloc(sizeof(struct nsgtk_theme_cache)); + size_t len = strlen(res_dir_location) + SLEN("/themes/") + + strlen(current_theme_name) + 1; + char path[len]; + snprintf(path, len, "%sthemes/%s/", res_dir_location, + current_theme_name); +#define CACHE_IMAGE(p, q, r)\ + nsgtk_theme_cache_image(p##_BUTTON, #q ".png", r) + + CACHE_IMAGE(BACK, back, path); + CACHE_IMAGE(HISTORY, history, path); + CACHE_IMAGE(FORWARD, forward, path); + CACHE_IMAGE(STOP, stop, path); + CACHE_IMAGE(RELOAD, reload, path); + CACHE_IMAGE(HOME, home, path); + CACHE_IMAGE(NEWWINDOW, newwindow, path); + CACHE_IMAGE(NEWTAB, newtab, path); + CACHE_IMAGE(OPENFILE, openfile, path); + CACHE_IMAGE(CLOSETAB, closetab, path); + CACHE_IMAGE(CLOSEWINDOW, closewindow, path); + CACHE_IMAGE(SAVEPAGE, savepage, path); + CACHE_IMAGE(PRINTPREVIEW, printpreview, path); + CACHE_IMAGE(PRINT, print, path); + CACHE_IMAGE(QUIT, quit, path); + CACHE_IMAGE(CUT, cut, path); + CACHE_IMAGE(COPY, copy, path); + CACHE_IMAGE(PASTE, paste, path); + CACHE_IMAGE(DELETE, delete, path); + CACHE_IMAGE(SELECTALL, selectall, path); + CACHE_IMAGE(PREFERENCES, preferences, path); + CACHE_IMAGE(ZOOMPLUS, zoomplus, path); + CACHE_IMAGE(ZOOMMINUS, zoomminus, path); + CACHE_IMAGE(ZOOMNORMAL, zoomnormal, path); + CACHE_IMAGE(FULLSCREEN, fullscreen, path); + CACHE_IMAGE(VIEWSOURCE, viewsource, path); + CACHE_IMAGE(CONTENTS, helpcontents, path); + CACHE_IMAGE(ABOUT, helpabout, path); + CACHE_IMAGE(PDF, pdf, path); + CACHE_IMAGE(PLAINTEXT, plaintext, path); + CACHE_IMAGE(DRAWFILE, drawfile, path); + CACHE_IMAGE(POSTSCRIPT, postscript, path); + CACHE_IMAGE(FIND, find, path); + CACHE_IMAGE(DOWNLOADS, downloads, path); + CACHE_IMAGE(SAVEWINDOWSIZE, savewindowsize, path); + CACHE_IMAGE(TOGGLEDEBUGGING, toggledebugging, path); + CACHE_IMAGE(SAVEBOXTREE, boxtree, path); + CACHE_IMAGE(SAVEDOMTREE, domtree, path); + CACHE_IMAGE(LOCALHISTORY, localhistory, path); + CACHE_IMAGE(GLOBALHISTORY, globalhistory, path); + CACHE_IMAGE(ADDBOOKMARKS, addbookmarks, path); + CACHE_IMAGE(SHOWBOOKMARKS, showbookmarks, path); + CACHE_IMAGE(SHOWCOOKIES, showcookies, path); + CACHE_IMAGE(OPENLOCATION, openlocation, path); + CACHE_IMAGE(NEXTTAB, nexttab, path); + CACHE_IMAGE(PREVTAB, prevtab, path); + CACHE_IMAGE(GUIDE, helpguide, path); + CACHE_IMAGE(INFO, helpinfo, path); +#undef CACHE_IMAGE +#define CACHE_IMAGE(p, q, r)\ + nsgtk_theme_cache_searchimage(p, #q ".png", r); + + CACHE_IMAGE(SEARCH_BACK_BUTTON, searchback, path); + CACHE_IMAGE(SEARCH_FORWARD_BUTTON, searchforward, path); + CACHE_IMAGE(SEARCH_CLOSE_BUTTON, searchclose, path); +#undef CACHE_IMAGE +} + +/** + * returns default image for buttons / menu items from gtk stock items + * \param i button reference + */ + +GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, GtkIconSize s) +{ + char *imagefile; + GtkImage *image; + switch(i) { +#define BUTTON_IMAGE(p, q)\ + case p##_BUTTON:\ + return GTK_IMAGE(gtk_image_new_from_stock(#q, s)) + + BUTTON_IMAGE(BACK, gtk-go-back); + case HISTORY_BUTTON: { + size_t len = SLEN("arrow_down_8x32.png") + + strlen(res_dir_location) + 1; + imagefile = malloc(len); + if (imagefile == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + snprintf(imagefile, len, "%sarrow_down_8x32.png", + res_dir_location); + image = GTK_IMAGE(gtk_image_new_from_file(imagefile)); + free(imagefile); + return image; + } + BUTTON_IMAGE(FORWARD, gtk-go-forward); + BUTTON_IMAGE(STOP, gtk-stop); + BUTTON_IMAGE(RELOAD, gtk-refresh); + BUTTON_IMAGE(HOME, gtk-home); + BUTTON_IMAGE(NEWWINDOW, gtk-new); + BUTTON_IMAGE(NEWTAB, gtk-new); + BUTTON_IMAGE(OPENFILE, gtk-open); + BUTTON_IMAGE(CLOSETAB, gtk-close); + BUTTON_IMAGE(CLOSEWINDOW, gtk-close); + BUTTON_IMAGE(SAVEPAGE, gtk-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, gtk-find); + BUTTON_IMAGE(PREFERENCES, gtk-preferences); + BUTTON_IMAGE(ZOOMPLUS, gtk-zoom-in); + BUTTON_IMAGE(ZOOMMINUS, gtk-zoom-out); + BUTTON_IMAGE(ZOOMNORMAL, gtk-zoom-100); + BUTTON_IMAGE(FULLSCREEN, gtk-fullscreen); + BUTTON_IMAGE(VIEWSOURCE, gtk-index); + BUTTON_IMAGE(CONTENTS, gtk-help); + BUTTON_IMAGE(ABOUT, gtk-about); +#undef BUTTON_IMAGE + case (PLACEHOLDER_BUTTON + SEARCH_BACK_BUTTON): + return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-back", s)); + case (PLACEHOLDER_BUTTON + SEARCH_FORWARD_BUTTON): + return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-forward", + s)); + case (PLACEHOLDER_BUTTON + SEARCH_CLOSE_BUTTON): + return GTK_IMAGE(gtk_image_new_from_stock("gtk-close", s)); + default: { + size_t len = SLEN("themes/Alpha.png") + + strlen(res_dir_location) + 1; + imagefile = malloc(len); + if (imagefile == NULL) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + snprintf(imagefile, len, "%sthemes/Alpha.png", + res_dir_location); + image = GTK_IMAGE( + gtk_image_new_from_file(imagefile)); + free(imagefile); + return image; + } + } +} + + +#ifdef WITH_THEME_INSTALL +/** + * when CONTENT_THEME needs handling call this function + */ +void theme_install_start(hlcache_handle *c) +{ + assert(c); + assert(content_get_type(c) == CONTENT_THEME); + + /* stop theme sitting in memory cache */ + content_invalidate_reuse_data(c); + + hlcache_handle_replace_callback(c, theme_install_callback, NULL); +} + + +/** + * Callback for fetchcache() for theme install fetches. + */ + +nserror theme_install_callback(hlcache_handle *c, + const hlcache_event *event, void *pw) +{ + switch (event->type) { + case CONTENT_MSG_READY: + break; + + case CONTENT_MSG_DONE: + { + const char *source_data; + unsigned long source_size; + + source_data = content_get_source_data(c, &source_size); + + if (!theme_install_read(source_data, source_size)) + warn_user("ThemeInvalid", 0); + + hlcache_handle_release(c); + } + break; + + case CONTENT_MSG_ERROR: + warn_user(event->data.error, 0); + break; + + case CONTENT_MSG_STATUS: + break; + + case CONTENT_MSG_LOADING: + case CONTENT_MSG_REFORMAT: + case CONTENT_MSG_REDRAW: + default: + assert(0); + break; + } + + return NSERROR_OK; +} + +/** + * handler saves theme data content as a local theme + */ + +bool theme_install_read(const char *data, unsigned long len) +{ + char *filename, *newfilename; + size_t namelen; + int handle = g_file_open_tmp("nsgtkthemeXXXXXX", &filename, NULL); + if (handle == -1) { + warn_user(messages_get("gtkFileError"), + "temporary theme file"); + return false; + } + ssize_t written = write(handle, data, len); + close(handle); + if ((unsigned)written != len) + return false; + + /* get name of theme; set as dirname */ + namelen = SLEN("themes/") + strlen(res_dir_location) + 1; + char dirname[namelen]; + snprintf(dirname, namelen, "%sthemes/", res_dir_location); + + /* save individual files in theme */ + newfilename = container_extract_theme(filename, dirname); + g_free(filename); + if (newfilename == NULL) + return false; + nsgtk_theme_add(newfilename); + free(newfilename); + + return true; +} +#endif + +/** + * loads the set of default images for the toolbar / menus + */ + +struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s) +{ + struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme)); + if (theme == NULL) { + warn_user("NoMemory", 0); + return NULL; + } + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON + + SEARCH_BUTTONS_COUNT; i++) + theme->image[i] = nsgtk_theme_image_default(i, s); + return theme; +} + diff --git a/gtk/theme.h b/gtk/theme.h new file mode 100644 index 000000000..117207037 --- /dev/null +++ b/gtk/theme.h @@ -0,0 +1,46 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#ifndef _NETSURF_GTK_THEME_H_ +#define _NETSURF_GTK_THEME_H_ + +#include +#include "gtk/scaffolding.h" + +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 */ +}; + +struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s); +void nsgtk_theme_add(const char *themename); +void nsgtk_theme_init(void); +void nsgtk_theme_prepare(void); +void nsgtk_theme_implement(struct gtk_scaffolding *g); +char *nsgtk_theme_name(void); +void nsgtk_theme_set_name(char *name); + +#endif diff --git a/gtk/throbber.c b/gtk/throbber.c new file mode 100644 index 000000000..987b9dd42 --- /dev/null +++ b/gtk/throbber.c @@ -0,0 +1,106 @@ +/* + * Copyright 2008 Rob Kendrick + * Copyright 2008 Sean Fox + * + * 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 . + */ + +#include +#include +#include +#ifdef WITH_GIF +#include +#endif +#include "utils/log.h" +#include "gtk/throbber.h" +#include "gtk/bitmap.h" + +struct nsgtk_throbber *nsgtk_throbber = NULL; + +/** + * Creates the throbber using a PNG for each frame. The number of frames must + * be at least two. The first frame is the inactive frame, others are the + * active frames. + * + * \param frames The number of frames. Must be at least two. + * \param ... Filenames of PNGs containing frames. + * \return true on success. + */ +bool nsgtk_throbber_initialise_from_png(const int frames, char** frame_files) +{ + GError *err = NULL; + struct nsgtk_throbber *throb; /**< structure we generate */ + bool errors_when_loading = false; /**< true if a frame failed */ + int frame_loop; + + if (frames < 2) { + /* we need at least two frames - one for idle, one for active */ + LOG(("Insufficent number of frames in throbber animation!")); + LOG(("(called with %d frames, where 2 is a minimum.)", + frames)); + return false; + } + + throb = malloc(sizeof(*throb)); + if (throb == NULL) + return false; + + throb->nframes = frames; + throb->framedata = malloc(sizeof(GdkPixbuf *) * throb->nframes); + if (throb->framedata == NULL) { + free(throb); + return false; + } + + for (frame_loop = 0; frame_loop < frames; frame_loop++) { + throb->framedata[frame_loop] = gdk_pixbuf_new_from_file(frame_files[frame_loop], &err); + if (err != NULL) { + LOG(("Error when loading %s: %s (%d)", + frame_files[frame_loop], err->message, err->code)); + throb->framedata[frame_loop] = NULL; + errors_when_loading = true; + } + } + + if (errors_when_loading == true) { + for (frame_loop = 0; frame_loop < frames; frame_loop++) { + if (throb->framedata[frame_loop] != NULL) + gdk_pixbuf_unref(throb->framedata[frame_loop]); + } + + free(throb->framedata); + free(throb); + + return false; + } + + nsgtk_throbber = throb; + + return true; +} + +void nsgtk_throbber_finalise(void) +{ + int i; + + for (i = 0; i < nsgtk_throbber->nframes; i++) + gdk_pixbuf_unref(nsgtk_throbber->framedata[i]); + + free(nsgtk_throbber->framedata); + free(nsgtk_throbber); + + nsgtk_throbber = NULL; +} + diff --git a/gtk/throbber.h b/gtk/throbber.h new file mode 100644 index 000000000..1463c9b26 --- /dev/null +++ b/gtk/throbber.h @@ -0,0 +1,35 @@ +/* + * Copyright 2008 Rob Kendrick + * + * 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 . + */ + +#ifndef __GTK_THROBBER_H__ +#define __GTK_THROBBER_H__ + +#include + +struct nsgtk_throbber +{ + int nframes; /**< Number of frames in the throbber */ + GdkPixbuf **framedata; +}; + +extern struct nsgtk_throbber *nsgtk_throbber; + +bool nsgtk_throbber_initialise_from_png(const int frames, char** frame_files); +void nsgtk_throbber_finalise(void); + +#endif /* __GTK_THROBBER_H__ */ diff --git a/gtk/thumbnail.c b/gtk/thumbnail.c new file mode 100644 index 000000000..53d62fe30 --- /dev/null +++ b/gtk/thumbnail.c @@ -0,0 +1,138 @@ +/* + * Copyright 2006 Rob Kendrick + * + * 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 . + */ + +/** \file + * Page thumbnail creation (implementation). + * + * Thumbnails are created by setting the current drawing contexts to the + * bitmap (a gdk pixbuf) we are passed, and plotting the page at a small + * scale. + */ + +#include +#include +#include "content/content.h" +#include "content/hlcache.h" +#include "content/urldb.h" +#include "desktop/plotters.h" +#include "desktop/browser.h" +#include "gtk/scaffolding.h" +#include "gtk/plotters.h" +#include "gtk/bitmap.h" +#include "image/bitmap.h" +#include "render/font.h" +#include "utils/log.h" +#include "utils/utils.h" + +/** + * Create a thumbnail of a page. + * + * \param content content structure to thumbnail + * \param bitmap the bitmap to draw to + * \param url the URL the thumnail belongs to, or NULL + */ +bool thumbnail_create(hlcache_handle *content, struct bitmap *bitmap, + const char *url) +{ + GdkPixbuf *pixbuf; + int cwidth, cheight; + gint width; + gint height; + gint depth; + GdkPixmap *pixmap; + GdkPixbuf *big; + + assert(content); + assert(bitmap); + + cwidth = min(content_get_width(content), 1024); + cheight = min(content_get_height(content), 768); + + pixbuf = gtk_bitmap_get_primary(bitmap); + width = gdk_pixbuf_get_width(pixbuf); + height = gdk_pixbuf_get_height(pixbuf); + depth = (gdk_screen_get_system_visual(gdk_screen_get_default()))->depth; + + LOG(("Trying to create a thumbnail pixmap for a content of %dx%d@%d", + content_get_width(content), content_get_height(content), + depth)); + + pixmap = gdk_pixmap_new(NULL, cwidth, cwidth, depth); + + if (pixmap == NULL) { + /* the creation failed for some reason: most likely because + * we've been asked to create with with at least one dimention + * as zero. The RISC OS thumbnail generator returns false + * from here when it can't create a bitmap, so we assume it's + * safe to do so here too. + */ + return false; + } + + gdk_drawable_set_colormap(pixmap, gdk_colormap_get_system()); + + /* set the plotting functions up */ + plot = nsgtk_plotters; + + nsgtk_plot_set_scale((double) cwidth / + (double) content_get_width(content)); + + /* set to plot to pixmap */ + current_drawable = pixmap; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot.rectangle(0, 0, cwidth, cwidth, plot_style_fill_white); + + plot.clip(0, 0, content_get_width(content), content_get_width(content)); + + /* render the content */ + content_redraw(content, 0, 0, content_get_width(content), + content_get_width(content), + 0, 0, content_get_width(content), + content_get_width(content), 1.0, 0xFFFFFF); + + /* resample the large plot down to the size of our thumbnail */ + big = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0, + cwidth, cwidth); + + gdk_pixbuf_scale(big, pixbuf, 0, 0, width, height, 0, 0, + (double)width / (double)cwidth, + (double)height / (double)cwidth, + GDK_INTERP_TILES); + + /* As a debugging aid, try this to dump out a copy of the thumbnail as + * a PNG: gdk_pixbuf_save(pixbuf, "thumbnail.png", "png", NULL, NULL); + */ + + /* register the thumbnail with the URL */ + if (url) + urldb_set_thumbnail(url, bitmap); + + bitmap_modified(bitmap); + + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + g_object_unref(pixmap); + g_object_unref(big); + + return true; +} diff --git a/gtk/toolbar.c b/gtk/toolbar.c new file mode 100644 index 000000000..b8ad9bcdb --- /dev/null +++ b/gtk/toolbar.c @@ -0,0 +1,1113 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#include +#include "desktop/searchweb.h" +#include "gtk/toolbar.h" +#include "gtk/gui.h" +#include "gtk/scaffolding.h" +#include "gtk/search.h" +#include "gtk/theme.h" +#include "gtk/throbber.h" +#include "gtk/window.h" +#include "gtk/sexy_icon_entry.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "utils/utils.h" + +static GtkTargetEntry entry = {(char *)"nsgtk_button_data", + GTK_TARGET_SAME_APP, 0}; + +static bool edit_mode = false; + +struct nsgtk_toolbar_custom_store { + GtkWidget *window; + GtkWidget *store_buttons[PLACEHOLDER_BUTTON]; + GtkWidget *widgetvbox; + GtkWidget *currentbar; + char numberh; /* current horizontal location while adding */ + GladeXML *glade; /* button widgets to store */ + int buttonlocations[PLACEHOLDER_BUTTON]; + int currentbutton; + bool fromstore; +}; +/* the number of buttons that fit in the width of the store window */ +#define NSGTK_STORE_WIDTH 6 + +/* the 'standard' width of a button that makes sufficient of its label +visible */ +#define NSGTK_BUTTON_WIDTH 111 + +/* the 'standard' height of a button that fits as many toolbars as +possible into the store */ +#define NSGTK_BUTTON_HEIGHT 70 + +/* the 'normal' width of the websearch bar */ +#define NSGTK_WEBSEARCH_WIDTH 150 + +static struct nsgtk_toolbar_custom_store store; +static struct nsgtk_toolbar_custom_store *window = &store; + +static void nsgtk_toolbar_close(nsgtk_scaffolding *g); +static void nsgtk_toolbar_window_open(nsgtk_scaffolding *g); +static void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g); +static void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i, + struct nsgtk_theme *theme); +static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget); +static gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, gpointer data); +static gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, gint x, gint y, guint time, gpointer data); +static gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext + *drag_context, gint x, gint y, guint time, gpointer data); +gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, guint time, gpointer data); +static gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext + *gdc, gint x, gint y, GtkSelectionData *selection, guint info, + guint time, gpointer data); +static void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint + time, gpointer data); +static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, + gpointer data); +static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data); +static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data); +static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data); +static void nsgtk_toolbar_cast(nsgtk_scaffolding *g); +static GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g, + nsgtk_toolbar_button i, struct nsgtk_theme *theme); +static void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, + nsgtk_toolbar_button i); +static void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, + nsgtk_toolbar_button i); +static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data); +static nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location( + nsgtk_scaffolding *g, int i); + +/** + * change behaviour of scaffoldings while editing toolbar; all buttons as + * well as window clicks are desensitized; then buttons in the front window + * are changed to movable buttons + */ +void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g) +{ + int i; + nsgtk_scaffolding *list = scaf_list; + edit_mode = true; + + while (list) { + g_signal_handler_block(GTK_WIDGET( + nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + nsgtk_window_get_signalhandler( + nsgtk_scaffolding_top_level(list), + NSGTK_WINDOW_SIGNAL_CLICK)); + g_signal_handler_block(GTK_WIDGET( + nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + nsgtk_window_get_signalhandler( + nsgtk_scaffolding_top_level(list), + NSGTK_WINDOW_SIGNAL_REDRAW)); + gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + GTK_STATE_NORMAL, &((GdkColor) + {0, 0xEEEE, 0xEEEE, 0xEEEE})); + + if (list == g) { + list = nsgtk_scaffolding_iterate(list); + continue; + } + /* set sensitive for all gui_windows save g */ + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_window( + list)), FALSE); + list = nsgtk_scaffolding_iterate(list); + } + /* set sensitive for all of g save toolbar */ + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), + FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), + FALSE); + + /* set editable aspect for toolbar */ + gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), + nsgtk_toolbar_clear_toolbar, g); + nsgtk_toolbar_set_physical(g); + /* memorize button locations, set editable */ + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + window->buttonlocations[i] = nsgtk_scaffolding_button(g, i) + ->location; + if ((window->buttonlocations[i] == -1) || (i == URL_BAR_ITEM)) + continue; + gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( + nsgtk_scaffolding_button(g, i)->button), TRUE); + gtk_drag_source_set(GTK_WIDGET(nsgtk_scaffolding_button( + g, i)->button), GDK_BUTTON1_MASK, &entry, 1, + GDK_ACTION_COPY); + nsgtk_toolbar_temp_connect(g, i); + } + + /* add move button listeners */ + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), + "drag-drop", G_CALLBACK(nsgtk_toolbar_data), g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), + "drag-data-received", G_CALLBACK( + nsgtk_toolbar_move_complete), g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), + "drag-motion", G_CALLBACK(nsgtk_toolbar_action), g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), + "drag-leave", G_CALLBACK( + nsgtk_toolbar_clear), g); + + /* set data types */ + gtk_drag_dest_set(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)), + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, + &entry, 1, GDK_ACTION_COPY); + + /* open toolbar window */ + nsgtk_toolbar_window_open(g); +} + +/** + * create store window + */ +void nsgtk_toolbar_window_open(nsgtk_scaffolding *g) +{ + int x = 0, y = 0; + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + warn_user(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + return; + } + window->glade = glade_xml_new(glade_toolbar_file_location, + "toolbarwindow", NULL); + if (window->glade == NULL) { + warn_user(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + } + glade_xml_signal_autoconnect(window->glade); + + window->window = glade_xml_get_widget(window->glade, "toolbarwindow"); + if (window->window == NULL) { + warn_user(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + free(theme); + return; + } + window->widgetvbox = glade_xml_get_widget(window->glade, "widgetvbox"); + if (window->widgetvbox == NULL) { + warn_user(messages_get("NoMemory"), 0); + nsgtk_toolbar_cancel_clicked(NULL, g); + free(theme); + return; + } + + window->numberh = NSGTK_STORE_WIDTH; /* preset to width [in buttons] of */ + /* store to cause creation of a new toolbar */ + window->currentbutton = -1; + /* load toolbuttons */ + /* add toolbuttons to window */ + /* set event handlers */ + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + if (i == URL_BAR_ITEM) + continue; + window->store_buttons[i] = + nsgtk_toolbar_make_widget(g, i, theme); + if (window->store_buttons[i] == NULL) { + warn_user(messages_get("NoMemory"), 0); + continue; + } + nsgtk_toolbar_add_store_widget(window->store_buttons[i]); + g_signal_connect(window->store_buttons[i], "drag-data-get", + G_CALLBACK( + nsgtk_scaffolding_button(g, i)->dataplus), g); + } + free(theme); + gtk_window_set_transient_for(GTK_WINDOW(window->window), + nsgtk_scaffolding_window(g)); + gtk_window_set_title(GTK_WINDOW(window->window), messages_get( + "gtkToolBarTitle")); + gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE); + gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY); + gtk_widget_show_all(window->window); + gtk_window_set_position(GTK_WINDOW(window->window), + GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_get_position(nsgtk_scaffolding_window(g), &x, &y); + gtk_window_move(GTK_WINDOW(window->window), x, y + 100); + g_signal_connect(glade_xml_get_widget(window->glade, "cancelbutton"), + "clicked", G_CALLBACK( + nsgtk_toolbar_cancel_clicked), g); + g_signal_connect(glade_xml_get_widget(window->glade, "okbutton"), + "clicked", G_CALLBACK(nsgtk_toolbar_persist), g); + g_signal_connect(glade_xml_get_widget(window->glade, "resetbutton"), + "clicked", G_CALLBACK(nsgtk_toolbar_reset), g); + g_signal_connect(window->window, "delete-event", + G_CALLBACK(nsgtk_toolbar_delete), g); + g_signal_connect(window->window, "drag-drop", + G_CALLBACK(nsgtk_toolbar_store_return), g); + g_signal_connect(window->window, "drag-motion", + G_CALLBACK(nsgtk_toolbar_store_action), g); +} + +/** + * when titlebar / alt-F4 window close event happens + */ +gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event, + gpointer data) +{ + edit_mode = false; + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + /* reset g->buttons->location */ + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + nsgtk_scaffolding_button(g, i)->location = + window->buttonlocations[i]; + } + nsgtk_toolbar_set_physical(g); + nsgtk_toolbar_connect_all(g); + nsgtk_toolbar_close(g); + nsgtk_scaffolding_set_sensitivity(g); + gtk_widget_destroy(window->window); + return TRUE; +} + +/** + * when cancel button is clicked + */ +gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data) +{ + edit_mode = false; + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + /* reset g->buttons->location */ + for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + nsgtk_scaffolding_button(g, i)->location = + window->buttonlocations[i]; + } + nsgtk_toolbar_set_physical(g); + nsgtk_toolbar_connect_all(g); + nsgtk_toolbar_close(g); + nsgtk_scaffolding_set_sensitivity(g); + gtk_widget_destroy(window->window); + return TRUE; +} + +/** + * when 'save settings' button is clicked + */ +gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data) +{ + edit_mode = false; + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + /* save state to file, update toolbars for all windows */ + nsgtk_toolbar_customization_save(g); + nsgtk_toolbar_cast(g); + nsgtk_toolbar_set_physical(g); + nsgtk_toolbar_close(g); + gtk_widget_destroy(window->window); + return TRUE; +} + +/** + * when 'reload defaults' button is clicked + */ +gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + int i; + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) + nsgtk_scaffolding_button(g, i)->location = + (i <= THROBBER_ITEM) ? i : -1; + nsgtk_toolbar_set_physical(g); + for (i = BACK_BUTTON; i <= THROBBER_ITEM; i++) { + if (i == URL_BAR_ITEM) + continue; + gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( + nsgtk_scaffolding_button(g, i)->button), TRUE); + gtk_drag_source_set(GTK_WIDGET( + nsgtk_scaffolding_button(g, i)->button), + GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY); + nsgtk_toolbar_temp_connect(g, i); + } + return TRUE; +} + +/** + * set toolbar logical -> physical; physically visible toolbar buttons are made + * to correspond to the logically stored schema in terms of location + * visibility etc + */ +void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g) +{ + int i; + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + warn_user(messages_get("NoMemory"), 0); + return; + } + /* simplest is to clear the toolbar then reload it from memory */ + gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), + nsgtk_toolbar_clear_toolbar, g); + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) + nsgtk_toolbar_add_item_to_toolbar(g, i, theme); + gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g))); + free(theme); +} + +/** + * cleanup code physical update of all toolbars; resensitize + * \param g the 'front' scaffolding that called customize + */ +void nsgtk_toolbar_close(nsgtk_scaffolding *g) +{ + int i; + nsgtk_scaffolding *list = scaf_list; + while (list) { + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + warn_user(messages_get("NoMemory"), 0); + continue; + } + /* clear toolbar */ + gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar( + list)), nsgtk_toolbar_clear_toolbar, list); + /* then add items */ + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + nsgtk_toolbar_add_item_to_toolbar(list, i, theme); + } + nsgtk_toolbar_connect_all(list); + gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar( + list))); + nsgtk_scaffolding_set_sensitivity(list); + gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + GTK_STATE_NORMAL, &((GdkColor) + {0, 0xFFFF, 0xFFFF, 0xFFFF})); + g_signal_handler_unblock(GTK_WIDGET( + nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + nsgtk_window_get_signalhandler( + nsgtk_scaffolding_top_level(list), + NSGTK_WINDOW_SIGNAL_CLICK)); + g_signal_handler_unblock(GTK_WIDGET( + nsgtk_window_get_layout( + nsgtk_scaffolding_top_level(list))), + nsgtk_window_get_signalhandler( + nsgtk_scaffolding_top_level(list), + NSGTK_WINDOW_SIGNAL_REDRAW)); + if ((gui_window_get_browser_window(nsgtk_scaffolding_top_level( + list))->current_content != NULL) && + (content_get_url(gui_window_get_browser_window( + nsgtk_scaffolding_top_level(list))-> + current_content) != NULL)) + browser_window_refresh_url_bar( + gui_window_get_browser_window( + nsgtk_scaffolding_top_level(list)), + content_get_url( + gui_window_get_browser_window( + nsgtk_scaffolding_top_level(list))-> + current_content), + gui_window_get_browser_window( + nsgtk_scaffolding_top_level(list))-> + frag_id); + + if (list != g) + gtk_widget_set_sensitive(GTK_WIDGET( + nsgtk_scaffolding_window(list)), TRUE); + free(theme); + list = nsgtk_scaffolding_iterate(list); + } + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)), + TRUE); + gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)), + TRUE); + /* update favicon etc */ + nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g)); + if (search_web_ico()) + gui_window_set_search_ico(search_web_ico()); +} + +/** + * callback function to iterate toolbar's widgets + */ +void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), widget); +} + +/** + * add item to toolbar + * \param g the scaffolding whose toolbar an item is added to + * \param i the location in the toolbar + * the function should be called, when multiple items are being added, + * in ascending order + */ +void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i, + struct nsgtk_theme *theme) +{ + int q; + for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) + if (nsgtk_scaffolding_button(g, q)->location == i) { + nsgtk_scaffolding_button(g, q)->button = GTK_TOOL_ITEM( + nsgtk_toolbar_make_widget(g, q, + theme)); + gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), + nsgtk_scaffolding_button(g, q)->button, + i); + break; + } +} + +/** + * physically add widgets to store window + */ +bool nsgtk_toolbar_add_store_widget(GtkWidget *widget) +{ + if (window->numberh >= NSGTK_STORE_WIDTH) { + window->currentbar = gtk_toolbar_new(); + if (window->currentbar == NULL) { + warn_user("NoMemory", 0); + return false; + } + gtk_toolbar_set_style(GTK_TOOLBAR(window->currentbar), + GTK_TOOLBAR_BOTH); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(window->currentbar), + GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start(GTK_BOX(window->widgetvbox), + window->currentbar, FALSE, FALSE, 0); + window->numberh = 0; + } + gtk_widget_set_size_request(widget, NSGTK_BUTTON_WIDTH, + NSGTK_BUTTON_HEIGHT); + gtk_toolbar_insert(GTK_TOOLBAR(window->currentbar), GTK_TOOL_ITEM( + widget), window->numberh++); + gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(widget), TRUE); + gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &entry, 1, + GDK_ACTION_COPY); + gtk_widget_show_all(window->window); + return true; +} + +/** + * called when a widget is dropped onto the toolbar + */ +gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *gdc, gint x, + gint y, guint time, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g), + x, y); + int q, i; + if (window->currentbutton == -1) + return TRUE; + struct nsgtk_theme *theme = + nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR); + if (theme == NULL) { + warn_user(messages_get("NoMemory"), 0); + return TRUE; + } + if (nsgtk_scaffolding_button(g, window->currentbutton)->location + != -1) { + /* widget was already in the toolbar; so replace */ + if (nsgtk_scaffolding_button(g, window->currentbutton)-> + location < ind) + ind--; + gtk_container_remove(GTK_CONTAINER( + nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( + nsgtk_scaffolding_button(g, + window->currentbutton)->button)); + /* 'move' all widgets further right than the original location, + * one place to the left in logical schema */ + for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> + location + 1; i < PLACEHOLDER_BUTTON; i++) { + q = nsgtk_toolbar_get_id_at_location(g, i); + if (q == -1) + continue; + nsgtk_scaffolding_button(g, q)->location--; + } + nsgtk_scaffolding_button(g, window->currentbutton)-> + location = -1; + } + nsgtk_scaffolding_button(g, window->currentbutton)->button = + GTK_TOOL_ITEM(nsgtk_toolbar_make_widget(g, + window->currentbutton, theme)); + free(theme); + if (nsgtk_scaffolding_button(g, window->currentbutton)->button + == NULL) { + warn_user("NoMemory", 0); + return TRUE; + } + /* update logical schema */ + nsgtk_scaffolding_reset_offset(g); + /* 'move' all widgets further right than the new location, one place to + * the right in logical schema */ + for (i = PLACEHOLDER_BUTTON - 1; i >= ind; i--) { + q = nsgtk_toolbar_get_id_at_location(g, i); + if (q == -1) + continue; + nsgtk_scaffolding_button(g, q)->location++; + } + nsgtk_scaffolding_button(g, window->currentbutton)->location = ind; + + /* complete action */ + gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g), + nsgtk_scaffolding_button(g, + window->currentbutton)->button, ind); + gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM( + nsgtk_scaffolding_button(g, + window->currentbutton)->button), TRUE); + gtk_drag_source_set(GTK_WIDGET( + nsgtk_scaffolding_button(g, + window->currentbutton)->button), + GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY); + nsgtk_toolbar_temp_connect(g, window->currentbutton); + gtk_widget_show_all(GTK_WIDGET( + nsgtk_scaffolding_button(g, + window->currentbutton)->button)); + window->currentbutton = -1; + return TRUE; +} + +/** + * connected to toolbutton drop; perhaps one day it'll work properly so it may + * replace the global current_button + */ + +gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, GtkSelectionData *selection, guint info, + guint time, gpointer data) +{ + return FALSE; +} + +/** + * called when a widget is dropped onto the store window + */ +gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, guint time, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + int q, i; + + if ((window->fromstore) || (window->currentbutton == -1)) { + window->currentbutton = -1; + return FALSE; + } + if (nsgtk_scaffolding_button(g, window->currentbutton)->location + != -1) { + /* 'move' all widgets further right, one place to the left + * in logical schema */ + for (i = nsgtk_scaffolding_button(g, window->currentbutton)-> + location + 1; i < PLACEHOLDER_BUTTON; i++) { + q = nsgtk_toolbar_get_id_at_location(g, i); + if (q == -1) + continue; + nsgtk_scaffolding_button(g, q)->location--; + } + gtk_container_remove(GTK_CONTAINER( + nsgtk_scaffolding_toolbar(g)), GTK_WIDGET( + nsgtk_scaffolding_button(g, + window->currentbutton)->button)); + nsgtk_scaffolding_button(g, window->currentbutton)->location + = -1; + } + window->currentbutton = -1; + gtk_drag_finish(gdc, TRUE, TRUE, time); + return FALSE; +} +/** + * called when hovering an item above the toolbar + */ +gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x, + gint y, guint time, gpointer data) +{ + nsgtk_scaffolding *g = (nsgtk_scaffolding *)data; + GtkToolItem *item = gtk_tool_button_new(NULL, NULL); + if (item != NULL) + gtk_toolbar_set_drop_highlight_item( + nsgtk_scaffolding_toolbar(g), + GTK_TOOL_ITEM(item), + gtk_toolbar_get_drop_index( + nsgtk_scaffolding_toolbar(g), x, y)); + return FALSE; +} + +/** + * called when hovering above the store + */ +gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc, + gint x, gint y, guint time, gpointer data) +{ + return FALSE; +} +/** + * called when hovering stops + */ +void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time, + gpointer data) +{ + gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0); +} + +/** + * widget factory for creation of toolbar item widgets + * \param g the reference scaffolding + * \param i the id of the widget + * \param theme the theme to make the widgets from + */ +GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g, + nsgtk_toolbar_button i, struct nsgtk_theme *theme) +{ + switch(i) { + +/* gtk_tool_button_new() accepts NULL args */ +#define MAKE_STOCKBUTTON(p, q) case p##_BUTTON: {\ + GtkStockItem item;\ + char *label = NULL;\ + gtk_stock_lookup(#q, &item);\ + if (item.label != NULL)\ + label = remove_underscores(item.label, false);\ + GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\ + theme->image[p##_BUTTON]), label));\ + if (label != NULL) {\ + free(label);\ + label = NULL;\ + }\ + return w;\ + } + + MAKE_STOCKBUTTON(HOME, gtk-home) + MAKE_STOCKBUTTON(BACK, gtk-go-back) + MAKE_STOCKBUTTON(FORWARD, gtk-go-forward) + MAKE_STOCKBUTTON(STOP, gtk-stop) + MAKE_STOCKBUTTON(RELOAD, gtk-refresh) +#undef MAKE_STOCKBUTTON + case HISTORY_BUTTON: + return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( + theme->image[HISTORY_BUTTON]), "")); + case URL_BAR_ITEM: { + char imagefile[strlen(res_dir_location) + SLEN("favicon.png") + + 1]; + sprintf(imagefile, "%sfavicon.png", res_dir_location); + GtkWidget *image = GTK_WIDGET(gtk_image_new_from_file( + imagefile)); + GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new()); + GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); + + if ((entry == NULL) || (w == NULL)) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + + if (image != NULL) + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry), + SEXY_ICON_ENTRY_PRIMARY, + GTK_IMAGE(image)); + + gtk_container_add(GTK_CONTAINER(w), entry); + gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE); + return w; + } + case THROBBER_ITEM: { + if (edit_mode) + return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( + gtk_image_new_from_pixbuf( + nsgtk_throbber->framedata[0])), + "[throbber]")); + if ((nsgtk_throbber == NULL) || (nsgtk_throbber->framedata == + NULL) || (nsgtk_throbber->framedata[0] == + NULL)) + return NULL; + GtkWidget *image = GTK_WIDGET(gtk_image_new_from_pixbuf( + nsgtk_throbber->framedata[0])); + GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); + GtkWidget *al = GTK_WIDGET(gtk_alignment_new(0.5, 0.5, 1, 1)); + if ((w == NULL) || (al == NULL)) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + gtk_alignment_set_padding(GTK_ALIGNMENT(al), 0, 0, 3, 3); + if (image != NULL) + gtk_container_add(GTK_CONTAINER(al), image); + gtk_container_add(GTK_CONTAINER(w), al); + return w; + } + case WEBSEARCH_ITEM: { + if (edit_mode) + return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET( + gtk_image_new_from_stock("gtk-find", + GTK_ICON_SIZE_LARGE_TOOLBAR)), + "[websearch]")); + GtkWidget *image = GTK_WIDGET(gtk_image_new_from_stock( + "gtk-info", GTK_ICON_SIZE_LARGE_TOOLBAR)); + GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new()); + GtkWidget *w = GTK_WIDGET(gtk_tool_item_new()); + + if ((entry == NULL) || (w == NULL)) { + warn_user(messages_get("NoMemory"), 0); + return NULL; + } + + gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH, + -1); + if (image != NULL) + sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry), + SEXY_ICON_ENTRY_PRIMARY, + GTK_IMAGE(image)); + + gtk_container_add(GTK_CONTAINER(w), entry); + return w; + } + +/* gtk_tool_button_new accepts NULL args */ +#define MAKE_MENUBUTTON(p, q) case p##_BUTTON: {\ + char *label = NULL;\ + label = remove_underscores(messages_get(#q), false);\ + GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\ + theme->image[p##_BUTTON]), label));\ + if (label != NULL)\ + free(label);\ + return w;\ + } + + MAKE_MENUBUTTON(NEWWINDOW, gtkNewWindow) + MAKE_MENUBUTTON(NEWTAB, gtkNewTab) + MAKE_MENUBUTTON(OPENFILE, gtkOpenFile) + MAKE_MENUBUTTON(CLOSETAB, gtkCloseTab) + MAKE_MENUBUTTON(CLOSEWINDOW, gtkCloseWindow) + MAKE_MENUBUTTON(SAVEPAGE, gtkSavePage) + MAKE_MENUBUTTON(PRINTPREVIEW, gtkPrintPreview) + MAKE_MENUBUTTON(PRINT, gtkPrint) + MAKE_MENUBUTTON(QUIT, gtkQuitMenu) + MAKE_MENUBUTTON(CUT, gtkCut) + MAKE_MENUBUTTON(COPY, gtkCopy) + MAKE_MENUBUTTON(PASTE, gtkPaste) + MAKE_MENUBUTTON(DELETE, gtkDelete) + MAKE_MENUBUTTON(SELECTALL, gtkSelectAll) + MAKE_MENUBUTTON(PREFERENCES, gtkPreferences) + MAKE_MENUBUTTON(ZOOMPLUS, gtkZoomPlus) + MAKE_MENUBUTTON(ZOOMMINUS, gtkZoomMinus) + MAKE_MENUBUTTON(ZOOMNORMAL, gtkZoomNormal) + MAKE_MENUBUTTON(FULLSCREEN, gtkFullScreen) + MAKE_MENUBUTTON(VIEWSOURCE, gtkViewSource) + MAKE_MENUBUTTON(CONTENTS, gtkContents) + MAKE_MENUBUTTON(ABOUT, gtkAbout) + MAKE_MENUBUTTON(PDF, gtkPDF) + MAKE_MENUBUTTON(PLAINTEXT, gtkPlainText) + MAKE_MENUBUTTON(DRAWFILE, gtkDrawFile) + MAKE_MENUBUTTON(POSTSCRIPT, gtkPostScript) + MAKE_MENUBUTTON(FIND, gtkFind) + MAKE_MENUBUTTON(DOWNLOADS, gtkDownloads) + MAKE_MENUBUTTON(SAVEWINDOWSIZE, gtkSaveWindowSize) + MAKE_MENUBUTTON(TOGGLEDEBUGGING, gtkToggleDebugging) + MAKE_MENUBUTTON(SAVEBOXTREE, gtkSaveBoxTree) + MAKE_MENUBUTTON(SAVEDOMTREE, gtkSaveDomTree) + MAKE_MENUBUTTON(LOCALHISTORY, gtkLocalHistory) + MAKE_MENUBUTTON(GLOBALHISTORY, gtkGlobalHistory) + MAKE_MENUBUTTON(ADDBOOKMARKS, gtkAddBookMarks) + MAKE_MENUBUTTON(SHOWBOOKMARKS, gtkShowBookMarks) + MAKE_MENUBUTTON(SHOWCOOKIES, gtkShowCookies) + MAKE_MENUBUTTON(OPENLOCATION, gtkOpenLocation) + MAKE_MENUBUTTON(NEXTTAB, gtkNextTab) + MAKE_MENUBUTTON(PREVTAB, gtkPrevTab) + MAKE_MENUBUTTON(GUIDE, gtkGuide) + MAKE_MENUBUTTON(INFO, gtkUserInformation) + default: + return NULL; +#undef MAKE_MENUBUTTON + } +} + +/** + * \return toolbar item id when a widget is an element of the scaffolding + * else -1 + */ +int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, nsgtk_scaffolding *g) +{ + int i; + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + if ((nsgtk_scaffolding_button(g, i)->location != -1) + && (widget == GTK_WIDGET( + nsgtk_scaffolding_button(g, i)->button))) { + return i; + } + } + return -1; +} + +/** + * \return toolbar item id from location when there is an item at that logical + * location; else -1 + */ +nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(nsgtk_scaffolding *g, + int i) +{ + int q; + for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++) + if (nsgtk_scaffolding_button(g, q)->location == i) + return q; + return -1; +} + +/** + * connect 'normal' handlers to toolbar buttons + */ + +void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g) +{ + int q, i; + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + q = nsgtk_toolbar_get_id_at_location(g, i); + if (q == -1) + continue; + if (nsgtk_scaffolding_button(g, q)->button != NULL) + g_signal_connect( + nsgtk_scaffolding_button(g, q)->button, + "size-allocate", G_CALLBACK( + nsgtk_scaffolding_toolbar_size_allocate + ), g); + nsgtk_toolbar_set_handler(g, q); + } +} + +/** + * add handlers to factory widgets + * \param g the scaffolding to attach handlers to + * \param i the toolbar item id + */ +void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, nsgtk_toolbar_button i) +{ + switch(i){ + case URL_BAR_ITEM: + nsgtk_scaffolding_update_url_bar_ref(g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), + "activate", G_CALLBACK( + nsgtk_window_url_activate_event), g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)), + "changed", G_CALLBACK( + nsgtk_window_url_changed), g); + break; + case THROBBER_ITEM: + nsgtk_scaffolding_update_throbber_ref(g); + break; + case WEBSEARCH_ITEM: + nsgtk_scaffolding_update_websearch_ref(g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), + "activate", G_CALLBACK( + nsgtk_websearch_activate), g); + g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)), + "button-press-event", G_CALLBACK( + nsgtk_websearch_clear), g); + break; + default: + if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) && + (nsgtk_scaffolding_button(g, i)->button + != NULL)) + g_signal_connect(nsgtk_scaffolding_button(g, i)-> + button, "clicked", + G_CALLBACK(nsgtk_scaffolding_button(g, + i)->bhandler), g); + break; + } +} + +#define DATAHANDLER(p, q, r)\ +gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ + *cont, GtkSelectionData *selection, guint info, guint time,\ + gpointer data)\ +{\ + r->currentbutton = q##_BUTTON;\ + r->fromstore = true;\ + return TRUE;\ +}\ +gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ + GdkDragContext *cont, GtkSelectionData *selection, guint info,\ + guint time, gpointer data)\ +{\ + r->currentbutton = q##_BUTTON;\ + r->fromstore = false;\ + return TRUE;\ +} + +DATAHANDLER(home, HOME, window) +DATAHANDLER(forward, FORWARD, window) +DATAHANDLER(back, BACK, window) +DATAHANDLER(stop, STOP, window) +DATAHANDLER(reload, RELOAD, window) +DATAHANDLER(history, HISTORY, window) +DATAHANDLER(newwindow, NEWWINDOW, window) +DATAHANDLER(newtab, NEWTAB, window) +DATAHANDLER(openfile, OPENFILE, window) +DATAHANDLER(closetab, CLOSETAB, window) +DATAHANDLER(closewindow, CLOSEWINDOW, window) +DATAHANDLER(savepage, SAVEPAGE, window) +DATAHANDLER(printpreview, PRINTPREVIEW, window) +DATAHANDLER(print, PRINT, window) +DATAHANDLER(quit, QUIT, window) +DATAHANDLER(cut, CUT, window) +DATAHANDLER(copy, COPY, window) +DATAHANDLER(paste, PASTE, window) +DATAHANDLER(delete, DELETE, window) +DATAHANDLER(selectall, SELECTALL, window) +DATAHANDLER(preferences, PREFERENCES, window) +DATAHANDLER(zoomplus, ZOOMPLUS, window) +DATAHANDLER(zoomminus, ZOOMMINUS, window) +DATAHANDLER(zoomnormal, ZOOMNORMAL, window) +DATAHANDLER(fullscreen, FULLSCREEN, window) +DATAHANDLER(viewsource, VIEWSOURCE, window) +DATAHANDLER(contents, CONTENTS, window) +DATAHANDLER(about, ABOUT, window) +DATAHANDLER(pdf, PDF, window) +DATAHANDLER(plaintext, PLAINTEXT, window) +DATAHANDLER(drawfile, DRAWFILE, window) +DATAHANDLER(postscript, POSTSCRIPT, window) +DATAHANDLER(find, FIND, window) +DATAHANDLER(downloads, DOWNLOADS, window) +DATAHANDLER(savewindowsize, SAVEWINDOWSIZE, window) +DATAHANDLER(toggledebugging, TOGGLEDEBUGGING, window) +DATAHANDLER(saveboxtree, SAVEBOXTREE, window) +DATAHANDLER(savedomtree, SAVEDOMTREE, window) +DATAHANDLER(localhistory, LOCALHISTORY, window) +DATAHANDLER(globalhistory, GLOBALHISTORY, window) +DATAHANDLER(addbookmarks, ADDBOOKMARKS, window) +DATAHANDLER(showbookmarks, SHOWBOOKMARKS, window) +DATAHANDLER(showcookies, SHOWCOOKIES, window) +DATAHANDLER(openlocation, OPENLOCATION, window) +DATAHANDLER(nexttab, NEXTTAB, window) +DATAHANDLER(prevtab, PREVTAB, window) +DATAHANDLER(guide, GUIDE, window) +DATAHANDLER(info, INFO, window) +#undef DATAHANDLER +#define DATAHANDLER(p, q, r)\ +gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\ + *cont, GtkSelectionData *selection, guint info, guint time,\ + gpointer data)\ +{\ + r->currentbutton = q##_ITEM;\ + r->fromstore = true;\ + return TRUE;\ +}\ +gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\ + GdkDragContext *cont, GtkSelectionData *selection, guint info,\ + guint time, gpointer data)\ +{\ + r->currentbutton = q##_ITEM;\ + r->fromstore = false;\ + return TRUE;\ +} + +DATAHANDLER(throbber, THROBBER, window) +DATAHANDLER(websearch, WEBSEARCH, window) +#undef DATAHANDLER + +/** + * connect temporary handler for toolbar edit events + */ +void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, nsgtk_toolbar_button i) +{ + if ((i == URL_BAR_ITEM) || + (nsgtk_scaffolding_button(g, i)->button == NULL) || + (nsgtk_scaffolding_button(g, i)->dataminus == NULL)) + return; + g_signal_connect(nsgtk_scaffolding_button(g, i)->button, + "drag-data-get", G_CALLBACK(nsgtk_scaffolding_button( + g, i)->dataminus), g); +} + +/** + * load toolbar settings from file; file is a set of fields arranged as + * ;|;| etc + */ +void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g) +{ + int i, ii; + char *val; + char buffer[SLEN("11;|") * 2 * PLACEHOLDER_BUTTON]; /* numbers 0-99 */ + buffer[0] = '\0'; + char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL; + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) + nsgtk_scaffolding_button(g, i)->location = + (i <= THROBBER_ITEM) ? i : -1; + FILE *f = fopen(toolbar_indices_file_location, "r"); + if (f == NULL) { + warn_user(messages_get("gtkFileError"), + toolbar_indices_file_location); + return; + } + val = fgets(buffer, sizeof buffer, f); + if (val == NULL) + LOG(("empty read toolbar settings")); + fclose(f); + i = BACK_BUTTON; + ii = BACK_BUTTON; + buffer1 = strtok_r(buffer, "|", &ptr); + while (buffer1 != NULL) { + subbuffer = strtok_r(buffer1, ";", &pter); + i = atoi(subbuffer); + subbuffer = strtok_r(NULL, ";", &pter); + ii = atoi(subbuffer); + if ((i >= BACK_BUTTON) && (i < PLACEHOLDER_BUTTON) && + (ii >= -1) && (ii < PLACEHOLDER_BUTTON)) { + nsgtk_scaffolding_button(g, i)->location = ii; + } + buffer1 = strtok_r(NULL, "|", &ptr); + } +} + +/** + * cast toolbar settings to all scaffoldings referenced from the global linked + * list of gui_windows + */ +void nsgtk_toolbar_cast(nsgtk_scaffolding *g) +{ + int i; + nsgtk_scaffolding *list = scaf_list; + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) + window->buttonlocations[i] = + ((nsgtk_scaffolding_button(g, i)->location + >= -1) && + (nsgtk_scaffolding_button(g, i)->location + < PLACEHOLDER_BUTTON)) ? + nsgtk_scaffolding_button(g, i)->location : -1; + while (list) { + if (list != g) + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) + nsgtk_scaffolding_button(list, i)->location = + window->buttonlocations[i]; + list = nsgtk_scaffolding_iterate(list); + } +} + +/** + * save toolbar settings to file + */ +void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g) +{ + int i; + FILE *f = fopen(toolbar_indices_file_location, "w"); + if (f == NULL){ + warn_user("gtkFileError", toolbar_indices_file_location); + return; + } + for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) { + fprintf(f, "%d;%d|", i, nsgtk_scaffolding_button(g, i)->location); + } + fclose(f); +} + diff --git a/gtk/toolbar.h b/gtk/toolbar.h new file mode 100644 index 000000000..bcad5cd7e --- /dev/null +++ b/gtk/toolbar.h @@ -0,0 +1,92 @@ +/* + * Copyright 2009 Mark Benjamin + * + * 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 . + */ + +#ifndef _NETSURF_GTK_TOOLBAR_H_ +#define _NETSURF_GTK_TOOLBAR_H_ + +#include + +#include "gtk/scaffolding.h" + +void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g); +void nsgtk_toolbar_init(nsgtk_scaffolding *g); +void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g); +void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g); +void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g); +int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, 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(saveboxtree); +TOOLPROTO(savedomtree); +TOOLPROTO(contents); +TOOLPROTO(guide); +TOOLPROTO(info); +TOOLPROTO(about); +#undef TOOLPROTO + +#endif diff --git a/gtk/treeview.c b/gtk/treeview.c new file mode 100644 index 000000000..a84a502c6 --- /dev/null +++ b/gtk/treeview.c @@ -0,0 +1,556 @@ +/* + * Copyright 2004 Richard Wilson + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +/** \file + * Generic tree handling (implementation). + */ + +#include +#include +#include +#include +#include + +#include "desktop/tree.h" +#include "desktop/tree_url_node.h" +#include "desktop/plotters.h" +#include "gtk/gui.h" +#include "gtk/plotters.h" +#include "gtk/treeview.h" +#include "utils/log.h" +#include "utils/utils.h" + +struct nsgtk_treeview { + GtkWindow *window; + GtkScrolledWindow *scrolled; + GtkDrawingArea *drawing_area; + int mouse_pressed_x; + int mouse_pressed_y; + int last_x, last_y; + browser_mouse_state mouse_state; + struct tree *tree; +}; + +const char tree_directory_icon_name[] = "directory.png"; +const char tree_content_icon_name[] = "content.png"; + +void nsgtk_treeview_destroy(struct nsgtk_treeview *tv) +{ + tree_delete(tv->tree); + gtk_widget_destroy(GTK_WIDGET(tv->window)); + free(tv); +} + +struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv) +{ + return tv->tree; +} + +static void nsgtk_tree_redraw_request(int x, int y, int width, int height, void *data) +{ + struct nsgtk_treeview *tw = data; + + gtk_widget_queue_draw_area(GTK_WIDGET(tw->drawing_area), + x, y, width, height); +} + + +/** + * Updates the tree owner following a tree resize + * + * \param tree the tree to update the owner of + */ +static void nsgtk_tree_resized(struct tree *tree, int width, int height, void *data) +{ + struct nsgtk_treeview *tw = data; + + gtk_widget_set_size_request(GTK_WIDGET(tw->drawing_area), + width, height); + return; +} + +/** + * Translates a content_type to the name of a respective icon + * + * \param content_type content type + * \param buffer buffer for the icon name + */ +void tree_icon_name_from_content_type(char *buffer, content_type type) +{ + // TODO: design/acquire icons + switch (type) { + case CONTENT_HTML: + case CONTENT_TEXTPLAIN: + case CONTENT_CSS: +#if defined(WITH_MNG) || defined(WITH_PNG) + case CONTENT_PNG: +#endif +#ifdef WITH_MNG + case CONTENT_JNG: + case CONTENT_MNG: +#endif +#ifdef WITH_JPEG + case CONTENT_JPEG: +#endif +#ifdef WITH_GIF + case CONTENT_GIF: +#endif +#ifdef WITH_BMP + case CONTENT_BMP: + case CONTENT_ICO: +#endif +#ifdef WITH_SPRITE + case CONTENT_SPRITE: +#endif +#ifdef WITH_DRAW + case CONTENT_DRAW: +#endif +#ifdef WITH_ARTWORKS + case CONTENT_ARTWORKS: +#endif +#ifdef WITH_NS_SVG + case CONTENT_SVG: +#endif + default: + sprintf(buffer, tree_content_icon_name); + break; + } +} + +/** + * Scrolls the tree to make an element visible + * + * \param y Y coordinate of the element + * \param height height of the element + * \param data user data assigned to the tree on tree creation + */ +static void nsgtk_tree_scroll_visible(int y, int height, void *data) +{ + int y0, y1; + gdouble page; + struct nsgtk_treeview *tw = data; + GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled); + + assert(vadj); + + g_object_get(vadj, "page-size", &page, NULL); + + y0 = (int)(gtk_adjustment_get_value(vadj)); + y1 = y0 + page; + + 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); +} + + +/** + * Retrieves the dimensions of the window with the tree + * + * \param data user data assigned to the tree on tree creation + * \param width will be updated to window width if not NULL + * \param height will be updated to window height if not NULL + */ +static void nsgtk_tree_get_window_dimensions(int *width, int *height, void *data) +{ + struct nsgtk_treeview *tw = data; + GtkAdjustment *vadj; + GtkAdjustment *hadj; + gdouble page; + + if (width != NULL) { + hadj = gtk_scrolled_window_get_hadjustment(tw->scrolled); + g_object_get(hadj, "page-size", &page, NULL); + *width = page; + } + + if (height != NULL) { + vadj = gtk_scrolled_window_get_vadjustment(tw->scrolled); + g_object_get(vadj, "page-size", &page, NULL); + *height = page; + } +} + +/* signal handler functions for a tree window */ +gboolean nsgtk_tree_window_expose_event(GtkWidget *widget, + GdkEventExpose *event, gpointer g) +{ + struct tree *tree = (struct tree *) g; + int x, y, width, height; + + x = event->area.x; + y = event->area.y; + width = event->area.width; + height = event->area.height; + + current_widget = widget; + current_drawable = widget->window; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot = nsgtk_plotters; + nsgtk_plot_set_scale(1.0);current_widget = widget; + current_drawable = widget->window; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + plot = nsgtk_plotters; + nsgtk_plot_set_scale(1.0); + + tree_set_redraw(tree, true); + tree_draw(tree, 0, 0, x, y, width, height); + + current_widget = NULL; + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + + return FALSE; +} + +void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g) +{ + struct nsgtk_treeview *tw = g; + struct tree *tree = tw->tree; + + if (tree != NULL) + tree_set_redraw(tree, false); +} + +gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer g) +{ + struct nsgtk_treeview *tw = g; + struct tree *tree = tw->tree; + + gtk_widget_grab_focus(GTK_WIDGET(tw->drawing_area)); + + + tw->mouse_pressed_x = event->x; + tw->mouse_pressed_y = event->y; + + if (event->type == GDK_2BUTTON_PRESS) + tw->mouse_state = BROWSER_MOUSE_DOUBLE_CLICK; + + switch (event->button) { + case 1: tw->mouse_state |= BROWSER_MOUSE_PRESS_1; break; + case 3: tw->mouse_state |= BROWSER_MOUSE_PRESS_2; break; + } + /* Handle the modifiers too */ + if (event->state & GDK_SHIFT_MASK) + tw->mouse_state |= BROWSER_MOUSE_MOD_1; + if (event->state & GDK_CONTROL_MASK) + tw->mouse_state |= BROWSER_MOUSE_MOD_2; + if (event->state & GDK_MOD1_MASK) + tw->mouse_state |= BROWSER_MOUSE_MOD_3; + + /* Record where we pressed, for use when determining whether to start + * a drag in motion notify events. */ + tw->last_x = event->x; + tw->last_y = event->y; + + tree_mouse_action(tree, tw->mouse_state, event->x, event->y); + + return TRUE; +} + +gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget, + GdkEventButton *event, gpointer g) +{ + bool shift = event->state & GDK_SHIFT_MASK; + bool ctrl = event->state & GDK_CONTROL_MASK; + bool alt = event->state & GDK_MOD1_MASK; + struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; + struct tree *tree = tw->tree; + + /* We consider only button 1 clicks as double clicks. + * 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 (tw->mouse_state & BROWSER_MOUSE_DOUBLE_CLICK) { + + if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) + tw->mouse_state ^= BROWSER_MOUSE_PRESS_1 | + BROWSER_MOUSE_CLICK_1; + else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) + tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | + BROWSER_MOUSE_CLICK_2 | + BROWSER_MOUSE_DOUBLE_CLICK); + + } else if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) + tw->mouse_state ^= + (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); + else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2) + tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | + BROWSER_MOUSE_CLICK_2); + + /* Handle modifiers being removed */ + if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) + tw->mouse_state ^= BROWSER_MOUSE_MOD_1; + if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) + tw->mouse_state ^= BROWSER_MOUSE_MOD_2; + if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) + tw->mouse_state ^= BROWSER_MOUSE_MOD_3; + + + if (tw->mouse_state & + (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 + | BROWSER_MOUSE_DOUBLE_CLICK)) + tree_mouse_action(tree, tw->mouse_state, + event->x, event->y); + else + tree_drag_end(tree, tw->mouse_state, + tw->mouse_pressed_x, + tw->mouse_pressed_y, + event->x, event->y); + + + tw->mouse_state = 0; + + + return TRUE; +} + +gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget, + GdkEventButton *event, gpointer g) +{ + bool shift = event->state & GDK_SHIFT_MASK; + bool ctrl = event->state & GDK_CONTROL_MASK; + bool alt = event->state & GDK_MOD1_MASK; + struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; + struct tree *tree = tw->tree; + + if ((abs(event->x - tw->last_x) < 5) && + (abs(event->y - tw->last_y) < 5)) { + /* Mouse hasn't moved far enough from press coordinate for this + * to be considered a drag. */ + return FALSE; + } else { + /* This is a drag, ensure it's always treated as such, even if + * we drag back over the press location */ + tw->last_x = INT_MIN; + tw->last_y = INT_MIN; + } + + /* Handle modifiers being removed */ + if (tw->mouse_state & BROWSER_MOUSE_MOD_1 && !shift) + tw->mouse_state ^= BROWSER_MOUSE_MOD_1; + if (tw->mouse_state & BROWSER_MOUSE_MOD_2 && !ctrl) + tw->mouse_state ^= BROWSER_MOUSE_MOD_2; + if (tw->mouse_state & BROWSER_MOUSE_MOD_3 && !alt) + tw->mouse_state ^= BROWSER_MOUSE_MOD_3; + + if (tw->mouse_state & BROWSER_MOUSE_PRESS_1) { + /* Start button 1 drag */ + tree_mouse_action(tree, BROWSER_MOUSE_DRAG_1, + tw->mouse_pressed_x, tw->mouse_pressed_y); + /* Replace PRESS with HOLDING and declare drag in progress */ + tw->mouse_state ^= (BROWSER_MOUSE_PRESS_1 | + BROWSER_MOUSE_HOLDING_1); + tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; + return TRUE; + } + else if (tw->mouse_state & BROWSER_MOUSE_PRESS_2){ + /* Start button 2s drag */ + tree_mouse_action(tree, BROWSER_MOUSE_DRAG_2, + tw->mouse_pressed_x, tw->mouse_pressed_y); + /* Replace PRESS with HOLDING and declare drag in progress */ + tw->mouse_state ^= (BROWSER_MOUSE_PRESS_2 | + BROWSER_MOUSE_HOLDING_2); + tw->mouse_state |= BROWSER_MOUSE_DRAG_ON; + return TRUE; + } + + if (tw->mouse_state & (BROWSER_MOUSE_HOLDING_1 | + BROWSER_MOUSE_HOLDING_2)) + tree_mouse_action(tree, tw->mouse_state, event->x, + event->y); + + return TRUE; +} + + +gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event, + gpointer g) +{ + struct nsgtk_treeview *tw = (struct nsgtk_treeview *) g; + struct tree *tree = tw->tree; + uint32_t nskey; + double value; + GtkAdjustment *vscroll; + GtkAdjustment *hscroll; + GtkAdjustment *scroll = NULL; + gdouble hpage, vpage; + bool edited; + + nskey = gtk_gui_gdkkey_to_nskey(event); + + + vscroll = gtk_scrolled_window_get_vadjustment(tw->scrolled); + hscroll = gtk_scrolled_window_get_hadjustment(tw->scrolled); + g_object_get(vscroll, "page-size", &vpage, NULL); + g_object_get(hscroll, "page-size", &hpage, NULL); + + + edited = tree_is_edited(tree); + + switch (event->keyval) { + case GDK_Home: + case GDK_KP_Home: + if (edited) + break; + scroll = vscroll; + value = scroll->lower; + break; + + case GDK_End: + case GDK_KP_End: + if (edited) + break; + scroll = vscroll; + value = scroll->upper - vpage; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Left: + case GDK_KP_Left: + if (edited) + break; + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->step_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Up: + case GDK_KP_Up: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->step_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Right: + case GDK_KP_Right: + if (edited) + break; + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->step_increment; + if (value > scroll->upper - hpage) + value = scroll->upper - hpage; + break; + + case GDK_Down: + case GDK_KP_Down: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->step_increment; + if (value > scroll->upper - vpage) + value = scroll->upper - vpage; + break; + + case GDK_Page_Up: + case GDK_KP_Page_Up: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->page_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Page_Down: + case GDK_KP_Page_Down: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->page_increment; + if (value > scroll->upper - vpage) + value = scroll->upper - vpage; + break; + default: + tree_keypress(tree, nskey); + return TRUE; + } + + if (scroll != NULL) + gtk_adjustment_set_value(scroll, value); + + tree_keypress(tree, nskey); + + return TRUE; +} + +static const struct treeview_table nsgtk_tree_callbacks = { + .redraw_request = nsgtk_tree_redraw_request, + .resized = nsgtk_tree_resized, + .scroll_visible = nsgtk_tree_scroll_visible, + .get_window_dimensions = nsgtk_tree_get_window_dimensions +}; + +struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags, + GtkWindow *window, GtkScrolledWindow *scrolled, + GtkDrawingArea *drawing_area) +{ + struct nsgtk_treeview *tv; + + tv = malloc(sizeof(struct nsgtk_treeview)); + if (tv == NULL) { + LOG(("malloc failed")); + warn_user("NoMemory", 0); + return NULL; + } + + tv->window = window; + tv->scrolled = scrolled; + tv->drawing_area = drawing_area; + tv->tree = tree_create(flags, &nsgtk_tree_callbacks, tv); + tv->mouse_state = 0; + + gtk_widget_modify_bg(GTK_WIDGET(drawing_area), GTK_STATE_NORMAL, + &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + + CONNECT(drawing_area, "expose_event", + nsgtk_tree_window_expose_event, + tv->tree); + CONNECT(drawing_area, "button_press_event", + nsgtk_tree_window_button_press_event, + tv); + CONNECT(drawing_area, "button_release_event", + nsgtk_tree_window_button_release_event, + tv); + CONNECT(drawing_area, "motion_notify_event", + nsgtk_tree_window_motion_notify_event, + tv); + CONNECT(drawing_area, "key_press_event", + nsgtk_tree_window_keypress_event, + tv); + return tv; +} diff --git a/gtk/treeview.h b/gtk/treeview.h new file mode 100644 index 000000000..c7520465e --- /dev/null +++ b/gtk/treeview.h @@ -0,0 +1,54 @@ +/* + * Copyright 2004 Richard Wilson + * Copyright 2009 Paul Blokus + * + * 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 . + */ + +/** \file + * Generic tree handling. + */ + +#ifndef __NSGTK_TREEVIEW_H__ +#define __NSGTK_TREEVIEW_H__ + +#include "desktop/browser.h" + +/* defined in front end code */ +extern const char tree_directory_icon_name[]; +extern const char tree_content_icon_name[]; + +struct nsgtk_treeview; + +struct nsgtk_treeview *nsgtk_treeview_create(unsigned int flags, + GtkWindow *window, GtkScrolledWindow *scrolled, + GtkDrawingArea *drawing_area); +void nsgtk_treeview_destroy(struct nsgtk_treeview *tv); + +struct tree *nsgtk_treeview_get_tree(struct nsgtk_treeview *tv); + +gboolean nsgtk_tree_window_expose_event(GtkWidget *, GdkEventExpose *, + gpointer g); +void nsgtk_tree_window_hide(GtkWidget *widget, gpointer g); +gboolean nsgtk_tree_window_button_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer g); +gboolean nsgtk_tree_window_button_release_event(GtkWidget *widget, + GdkEventButton *event, gpointer g); +gboolean nsgtk_tree_window_motion_notify_event(GtkWidget *widget, + GdkEventButton *event, gpointer g); +gboolean nsgtk_tree_window_keypress_event(GtkWidget *widget, GdkEventKey *event, + gpointer g); + +#endif /*__NSGTK_TREEVIEW_H__*/ diff --git a/gtk/window.c b/gtk/window.c new file mode 100644 index 000000000..d3ab49d3e --- /dev/null +++ b/gtk/window.c @@ -0,0 +1,1123 @@ +/* + * Copyright 2006 Daniel Silverstone + * Copyright 2006 Rob Kendrick + * + * 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 . + */ + +#include +#include +#include +#include + +#include + +#include "content/hlcache.h" +#include "gtk/window.h" +#include "desktop/browser.h" +#include "desktop/mouse.h" +#include "desktop/options.h" +#include "desktop/searchweb.h" +#include "desktop/textinput.h" +#include "desktop/selection.h" +#include "gtk/compat.h" +#include "gtk/gui.h" +#include "gtk/options.h" +#include "gtk/scaffolding.h" +#include "gtk/plotters.h" +#include "gtk/schedule.h" +#include "gtk/tabs.h" +#include "utils/log.h" +#include "utils/utils.h" + +struct gui_window { + /* All gui_window objects have an ultimate scaffold */ + nsgtk_scaffolding *scaffold; + /**< the gtk object containing menu, buttons, url bar, [tabs], + * drawing area, etc that may contain 1 -> several gui_windows */ + struct browser_window *bw; + /**< the 'content' window that is rendered in the gui_window*/ + + struct { + struct gui_window *gui; + struct box *box; + + gdouble pressed_x; + gdouble pressed_y; + gboolean waiting; + browser_mouse_state state; + } mouse; /**< contains mouse state / events */ + + int caretx, carety, careth; + /**< storage caret dimension / location for rendering */ + gui_pointer_shape current_pointer; + /**< storage caret shape for rendering */ + int last_x, last_y; + /**< storage caret location for rendering */ + + GtkLayout *layout; /**< display widget for this page or frame */ + GtkScrolledWindow *scrolledwindow; + /**< frames only; top level of gtk structure of gui_window */ + GtkWidget *tab; /**< the visible tab */ + GtkLabel *status_bar; + GtkPaned *paned; /**< statusbar/scrollbar paned */ + gulong signalhandler[NSGTK_WINDOW_SIGNAL_COUNT]; + /**< to allow disactivation / resume of normal window behaviour */ + struct gui_window *next, *prev; /**< list for eventual cleanup */ +}; + +struct gui_window *window_list = NULL; /**< first entry in win list*/ +int temp_open_background = -1; + + +static void nsgtk_gui_window_attach_child(struct gui_window *parent, + struct gui_window *child); +/* Methods which apply only to a gui_window */ +static gboolean nsgtk_window_expose_event(GtkWidget *, GdkEventExpose *, + gpointer); +static gboolean nsgtk_window_motion_notify_event(GtkWidget *, GdkEventMotion *, + gpointer); +static gboolean nsgtk_window_button_press_event(GtkWidget *, GdkEventButton *, + gpointer); +static gboolean nsgtk_window_button_release_event(GtkWidget *, GdkEventButton *, + gpointer); +static gboolean nsgtk_window_scroll_event(GtkWidget *, GdkEventScroll *, + gpointer); +static gboolean nsgtk_window_keypress_event(GtkWidget *, GdkEventKey *, + gpointer); +static gboolean nsgtk_window_size_allocate_event(GtkWidget *, GtkAllocation *, + gpointer); + +/* Other useful bits */ +static void nsgtk_redraw_caret(struct gui_window *g); + +static GdkCursor *nsgtk_create_menu_cursor(void); + +nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g) +{ + return g->scaffold; +} + +struct browser_window *gui_window_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 g->bw->scale; +} + +/* Create a gui_window */ +struct gui_window *gui_create_browser_window(struct browser_window *bw, + struct browser_window *clone, + bool new_tab) +{ + struct gui_window *g; /**< what we're creating to return */ + GtkPolicyType scrollpolicy; + + g = calloc(1, sizeof(*g)); + if (!g) { + warn_user("NoMemory", 0); + return 0; + } + + LOG(("Creating gui window %p for browser window %p", g, bw)); + + g->bw = bw; + g->paned = NULL; + g->mouse.state = 0; + g->current_pointer = GUI_POINTER_DEFAULT; + if (clone != NULL) + bw->scale = clone->scale; + else + bw->scale = (float) option_scale / 100; + + g->careth = 0; + + if (bw->parent != NULL) + /* Find our parent's scaffolding */ + g->scaffold = bw->parent->window->scaffold; + else if (new_tab) + g->scaffold = clone->window->scaffold; + else + /* Now construct and attach a scaffold */ + g->scaffold = nsgtk_new_scaffolding(g); + if (g->scaffold == NULL) { + warn_user("NoMemory", 0); + free(g); + return NULL; + } + + /* Construct our primary elements */ + if (bw->parent == NULL) { + /* top-level document (not a frame) => create a new tab */ + GladeXML *xml = glade_xml_new(glade_netsurf_file_location, "tabContents", NULL); + if (!xml) { + warn_user("MiscError", "Failed to create tab contents"); + free(g); + return 0; + } + + GtkWidget *tab_contents = glade_xml_get_widget(xml, "tabContents"); + g->layout = GTK_LAYOUT(glade_xml_get_widget(xml, "layout")); + g->status_bar = GTK_LABEL(glade_xml_get_widget(xml, "status_bar")); + g->paned = GTK_PANED(glade_xml_get_widget(xml, "hpaned1")); + + /* connect the scrollbars to the layout widget */ + gtk_layout_set_hadjustment(g->layout, + gtk_range_get_adjustment(GTK_RANGE( + glade_xml_get_widget(xml, "hscrollbar")))); + gtk_layout_set_vadjustment(g->layout, + gtk_range_get_adjustment(GTK_RANGE( + glade_xml_get_widget(xml, "vscrollbar")))); + + /* add the tab to the scaffold */ + bool tempback = true; + switch (temp_open_background) { + case -1: + tempback = !(option_focus_new); + break; + case 0: + tempback = false; + break; + case 1: + tempback = true; + break; + } + g_object_set_data(G_OBJECT(tab_contents), "gui_window", g); + nsgtk_tab_add(g, tab_contents, tempback); + + g_object_unref(xml); + + } else { + /* frame or iframe => create a child layout */ + g->layout = GTK_LAYOUT(gtk_layout_new(NULL, NULL)); + gtk_container_set_border_width(GTK_CONTAINER(g->layout), 0); + + g->scrolledwindow = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + g_object_set_data(G_OBJECT(g->scrolledwindow), "gui_window", g); + gtk_container_add(GTK_CONTAINER(g->scrolledwindow), GTK_WIDGET(g->layout)); + gtk_scrolled_window_set_shadow_type(g->scrolledwindow, + GTK_SHADOW_NONE); + g->tab = NULL; + + /* Attach ourselves into our parent at the right point */ + nsgtk_gui_window_attach_child(bw->parent->window, g); + + gtk_widget_show(GTK_WIDGET(g->scrolledwindow)); + } + + switch(bw->scrolling) { + case SCROLLING_NO: + scrollpolicy = GTK_POLICY_NEVER; + break; + case SCROLLING_YES: + scrollpolicy = GTK_POLICY_ALWAYS; + break; + case SCROLLING_AUTO: + default: + scrollpolicy = GTK_POLICY_AUTOMATIC; + break; + } + + switch (bw->browser_window_type) { + case BROWSER_WINDOW_FRAMESET: + if (g->scrolledwindow) + gtk_scrolled_window_set_policy(g->scrolledwindow, + GTK_POLICY_NEVER, + GTK_POLICY_NEVER); + break; + case BROWSER_WINDOW_FRAME: + if (g->scrolledwindow) + gtk_scrolled_window_set_policy(g->scrolledwindow, + scrollpolicy, + scrollpolicy); + break; + case BROWSER_WINDOW_NORMAL: + if (g->scrolledwindow) + gtk_scrolled_window_set_policy(g->scrolledwindow, + scrollpolicy, + scrollpolicy); + break; + case BROWSER_WINDOW_IFRAME: + if (g->scrolledwindow) + gtk_scrolled_window_set_policy(g->scrolledwindow, + scrollpolicy, + scrollpolicy); + break; + } + + /* Attach ourselves to the list (push_top) */ + if (window_list) + window_list->prev = g; + g->next = window_list; + g->prev = NULL; + window_list = g; + + /* set the events we're interested in receiving from the browser's + * drawing area. + */ + gtk_widget_add_events(GTK_WIDGET(g->layout), + GDK_EXPOSURE_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_SCROLL_MASK); + nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); + + /* set the default background colour of the drawing area to white. */ + gtk_widget_modify_bg(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, + &((GdkColor) { 0, 0xffff, 0xffff, 0xffff } )); + +#define CONNECT(obj, sig, callback, ptr) \ + g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) + g->signalhandler[NSGTK_WINDOW_SIGNAL_REDRAW] = + CONNECT(g->layout, "expose_event", + nsgtk_window_expose_event, g); + CONNECT(g->layout, "motion_notify_event", + nsgtk_window_motion_notify_event, g); + g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = + CONNECT(g->layout, "button_press_event", + nsgtk_window_button_press_event, g); + CONNECT(g->layout, "button_release_event", + nsgtk_window_button_release_event, g); + CONNECT(g->layout, "key_press_event", + nsgtk_window_keypress_event, g); + CONNECT(g->layout, "size_allocate", + nsgtk_window_size_allocate_event, g); + CONNECT(g->layout, "scroll_event", + nsgtk_window_scroll_event, g); + return g; +} + +static void nsgtk_gui_window_attach_child(struct gui_window *parent, + struct gui_window *child) +{ + /* Attach the child gui_window (frame) into the parent. + * It will be resized later on. + */ + GtkLayout *parent_layout = parent->layout; + GtkWidget *child_widget = GTK_WIDGET(child->scrolledwindow); + gtk_layout_put(parent_layout, child_widget, 0, 0); +} + +void gui_window_position_frame(struct gui_window *g, int x0, int y0, int x1, int y1) +{ + /* g is a child frame, we need to place it relative to its parent */ + GtkWidget *w = GTK_WIDGET(g->scrolledwindow); + GtkLayout *f = g->bw->parent->window->layout; + int width = x1 - x0 + 2, height = y1 - y0 + 2; + assert(w); + assert(f); + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + LOG(("%s: %d,%d %dx%d", g->bw->name, x0, y0, width, height)); + + /* if the window has not changed position or size, do not bother + * moving/resising it. + */ + + LOG((" current: %d,%d %dx%d", + w->allocation.x, w->allocation.y, + w->allocation.width, w->allocation.height)); + + if (w->allocation.x != x0 || w->allocation.y != y0 || + w->allocation.width != width || + w->allocation.height != height) { + LOG((" frame has moved/resized.")); + gtk_layout_move(f, w, x0, y0); + gtk_widget_set_size_request(w, width, height); + } +} + +gboolean nsgtk_window_expose_event(GtkWidget *widget, + GdkEventExpose *event, gpointer data) +{ + struct gui_window *g = data; + hlcache_handle *c; + float scale = g->bw->scale; + + assert(g); + assert(g->bw); + + struct gui_window *z; + for (z = window_list; z && z != g; z = z->next) + continue; + assert(z); + assert(GTK_WIDGET(g->layout) == widget); + + c = g->bw->current_content; + if (c == NULL) + return FALSE; + + /* HTML rendering handles scale itself */ + if (content_get_type(c) == CONTENT_HTML) + scale = 1; + + current_widget = (GtkWidget *)g->layout; + current_drawable = g->layout->bin_window; + current_gc = gdk_gc_new(current_drawable); +#ifdef CAIRO_VERSION + current_cr = gdk_cairo_create(current_drawable); +#endif + + plot = nsgtk_plotters; + nsgtk_plot_set_scale(g->bw->scale); + current_redraw_browser = g->bw; + + plot.clip(event->area.x, + event->area.y, + event->area.x + event->area.width, + event->area.y + event->area.height); + + content_redraw(c, 0, 0, + content_get_width(c) * scale, + content_get_height(c) * scale, + event->area.x, + event->area.y, + event->area.x + event->area.width, + event->area.y + event->area.height, + g->bw->scale, 0xFFFFFF); + current_redraw_browser = NULL; + + if (g->careth != 0) + nsgtk_plot_caret(g->caretx, g->carety, g->careth); + + current_widget = NULL; + g_object_unref(current_gc); +#ifdef CAIRO_VERSION + cairo_destroy(current_cr); +#endif + + return FALSE; +} + +gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, + GdkEventMotion *event, gpointer data) +{ + struct gui_window *g = data; + bool shift = event->state & GDK_SHIFT_MASK; + bool ctrl = event->state & GDK_CONTROL_MASK; + + if ((abs(event->x - g->last_x) < 5) && + (abs(event->y - g->last_y) < 5)) { + /* Mouse hasn't moved far enough from press coordinate for this + * to be considered a drag. */ + return FALSE; + } else { + /* This is a drag, ensure it's always treated as such, even if + * we drag back over the press location */ + g->last_x = INT_MIN; + g->last_y = INT_MIN; + } + + if (g->mouse.state & BROWSER_MOUSE_PRESS_1){ + /* Start button 1 drag */ + browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, + g->mouse.pressed_x, g->mouse.pressed_y); + /* Replace PRESS with HOLDING and declare drag in progress */ + g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | + BROWSER_MOUSE_HOLDING_1); + g->mouse.state |= BROWSER_MOUSE_DRAG_ON; + } + else if (g->mouse.state & BROWSER_MOUSE_PRESS_2){ + /* Start button 2 drag */ + browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, + g->mouse.pressed_x, g->mouse.pressed_y); + /* Replace PRESS with HOLDING and declare drag in progress */ + g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | + BROWSER_MOUSE_HOLDING_2); + g->mouse.state |= BROWSER_MOUSE_DRAG_ON; + } + /* Handle modifiers being removed */ + if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) + g->mouse.state ^= BROWSER_MOUSE_MOD_1; + 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 / g->bw->scale, event->y / g->bw->scale); + + return TRUE; +} + +gboolean nsgtk_window_button_press_event(GtkWidget *widget, + GdkEventButton *event, gpointer data) +{ + struct gui_window *g = data; + + gtk_widget_grab_focus(GTK_WIDGET(g->layout)); + gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( + g->scaffold)->window)); + + g->mouse.pressed_x = event->x / g->bw->scale; + g->mouse.pressed_y = event->y / g->bw->scale; + + switch (event->button) { + case 1: + /* Left button, usually. + * Pass to core as BUTTON 1. */ + g->mouse.state = BROWSER_MOUSE_PRESS_1; + break; + case 2: + /* Middle button, usually. + * Pass to core as BUTTON 2 */ + g->mouse.state = BROWSER_MOUSE_PRESS_2; + break; + case 3: + /* Right button, usually. + * Front end action button -- context menu. */ + browser_window_remove_caret(g->bw); + nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, + g->mouse.pressed_y); + return TRUE; + default: + return FALSE; + } + /* Handle the modifiers too */ + if (event->state & GDK_SHIFT_MASK) + g->mouse.state |= BROWSER_MOUSE_MOD_1; + if (event->state & GDK_CONTROL_MASK) + g->mouse.state |= BROWSER_MOUSE_MOD_2; + + /* Record where we pressed, for use when determining whether to start + * a drag in motion notify events. */ + 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); + + return TRUE; +} + +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; + + /* 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) + g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); + 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) + g->mouse.state ^= BROWSER_MOUSE_MOD_1; + if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) + 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 / g->bw->scale, + event->y / g->bw->scale); + else + browser_window_mouse_drag_end(g->bw, 0, event->x / g->bw->scale, + event->y / g->bw->scale); + + g->mouse.state = 0; + return TRUE; +} + +gboolean nsgtk_window_scroll_event(GtkWidget *widget, + GdkEventScroll *event, gpointer data) +{ + struct gui_window *g = data; + double value; + GtkAdjustment *vscroll = gtk_layout_get_vadjustment(g->layout); + GtkAdjustment *hscroll = gtk_layout_get_hadjustment(g->layout); + GtkAdjustment *scroll; + const GtkAllocation *const alloc = + >K_WIDGET(g->layout)->allocation; + + switch (event->direction) { + case GDK_SCROLL_LEFT: + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) - + (scroll->step_increment * 2); + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_SCROLL_UP: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) - + (scroll->step_increment * 2); + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_SCROLL_RIGHT: + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) + + (scroll->step_increment * 2); + if (value > scroll->upper - alloc->width) + value = scroll->upper - alloc->width; + break; + + case GDK_SCROLL_DOWN: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) + + (scroll->step_increment * 2); + if (value > scroll->upper - alloc->height) + value = scroll->upper - alloc->height; + break; + default: + return TRUE; + } + + gtk_adjustment_set_value(scroll, value); + + return TRUE; +} + +gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, + gpointer data) +{ + struct gui_window *g = data; + uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); + if (browser_window_key_press(g->bw, nskey)) + return TRUE; + + if ((event->state & 0x7) == 0) { + double value; + GtkAdjustment *vscroll = gtk_layout_get_vadjustment(g->layout); + + GtkAdjustment *hscroll = gtk_layout_get_hadjustment(g->layout); + + GtkAdjustment *scroll; + + const GtkAllocation *const alloc = + >K_WIDGET(g->layout)->allocation; + + switch (event->keyval) { + default: + return TRUE; + + case GDK_Home: + case GDK_KP_Home: + scroll = vscroll; + value = scroll->lower; + break; + + case GDK_End: + case GDK_KP_End: + scroll = vscroll; + value = scroll->upper - alloc->height; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Left: + case GDK_KP_Left: + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->step_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Up: + case GDK_KP_Up: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->step_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Right: + case GDK_KP_Right: + scroll = hscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->step_increment; + if (value > scroll->upper - alloc->width) + value = scroll->upper - alloc->width; + break; + + case GDK_Down: + case GDK_KP_Down: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->step_increment; + if (value > scroll->upper - alloc->height) + value = scroll->upper - alloc->height; + break; + + case GDK_Page_Up: + case GDK_KP_Page_Up: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) - + scroll->page_increment; + if (value < scroll->lower) + value = scroll->lower; + break; + + case GDK_Page_Down: + case GDK_KP_Page_Down: + scroll = vscroll; + value = gtk_adjustment_get_value(scroll) + + scroll->page_increment; + if (value > scroll->upper - alloc->height) + value = scroll->upper - alloc->height; + break; + } + + gtk_adjustment_set_value(scroll, value); + } + + return TRUE; +} + +gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, + GtkAllocation *allocation, gpointer data) +{ + struct gui_window *g = data; + + g->bw->reformat_pending = true; + browser_reformat_pending = true; + + if (g->paned != NULL) { + /* Set status bar / scroll bar proportion according to + * option_toolbar_status_width */ + /* TODO: Probably want to detect when the user adjusts the + * status bar width, remember that proportion for the + * window, and use that here. */ + gtk_paned_set_position(g->paned, (option_toolbar_status_width * + allocation->width) / 10000); + } + + return TRUE; +} + + +void nsgtk_reflow_all_windows(void) +{ + for (struct gui_window *g = window_list; g; g = g->next) { + nsgtk_tab_options_changed(GTK_WIDGET( + nsgtk_scaffolding_notebook(g->scaffold))); + g->bw->reformat_pending = true; + } + + browser_reformat_pending = true; +} + + +/** + * Process pending reformats + */ + +void nsgtk_window_process_reformats(void) +{ + struct gui_window *g; + + browser_reformat_pending = false; + for (g = window_list; g; g = g->next) { + GtkWidget *widget = GTK_WIDGET(g->layout); + if (!g->bw->reformat_pending) + continue; + g->bw->reformat_pending = false; + browser_window_reformat(g->bw, + widget->allocation.width, + widget->allocation.height); + } +} + + +void nsgtk_window_destroy_browser(struct gui_window *g) +{ + browser_window_destroy(g->bw); +} + +void gui_window_destroy(struct gui_window *g) +{ + if (g->prev) + g->prev->next = g->next; + else + window_list = g->next; + + if (g->next) + g->next->prev = g->prev; + + + LOG(("Destroying gui_window %p", g)); + assert(g != NULL); + assert(g->bw != NULL); + LOG((" Scaffolding: %p", g->scaffold)); + LOG((" Window name: %s", g->bw->name)); + + if (g->scrolledwindow == NULL) { + /* tab => remove tab */ + gtk_widget_destroy(gtk_widget_get_parent(GTK_WIDGET(g->layout))); + /* if it was the last tab, destroy scaffold too */ + gint numbertabs = gtk_notebook_get_n_pages(nsgtk_scaffolding_notebook(g->scaffold)); + if (numbertabs == 0) + nsgtk_scaffolding_destroy(g->scaffold); + } else { + /* frame within a document => destroy frame only */ + gtk_widget_destroy(GTK_WIDGET(g->scrolledwindow)); + } + + free(g); + +} + +void nsgtk_redraw_caret(struct gui_window *g) +{ + if (g->careth == 0) + return; + + gui_window_redraw(g, g->caretx, g->carety, + g->caretx, g->carety + g->careth); +} + +void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1) +{ + int sx, sy; + + gui_window_get_scroll(g, &sx, &sy); + + gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), + x0 - sx, y0 - sy, x1-x0+1, y1-y0+1); +} + +void gui_window_redraw_window(struct gui_window *g) +{ + gtk_widget_queue_draw(GTK_WIDGET(g->layout)); +} + +void gui_window_update_box(struct gui_window *g, + const union content_msg_data *data) +{ + int sx, sy; + hlcache_handle *c = g->bw->current_content; + + if (c == NULL) + return; + + gui_window_get_scroll(g, &sx, &sy); + + gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), + data->redraw.x * g->bw->scale - sx, + data->redraw.y * g->bw->scale - sy, + data->redraw.width * g->bw->scale, + data->redraw.height * g->bw->scale); +} + +void gui_window_set_status(struct gui_window *g, const char *text) +{ + assert(g); + assert(g->status_bar); + gtk_label_set_text(g->status_bar, text); +} + +bool gui_window_get_scroll(struct gui_window *g, int *sx, int *sy) +{ + GtkAdjustment *vadj = gtk_layout_get_vadjustment(g->layout); + GtkAdjustment *hadj = gtk_layout_get_hadjustment(g->layout); + + assert(vadj); + assert(hadj); + + *sy = (int)(gtk_adjustment_get_value(vadj)); + *sx = (int)(gtk_adjustment_get_value(hadj)); + + return true; +} + +void gui_window_set_scroll(struct gui_window *g, int sx, int sy) +{ + GtkAdjustment *vadj = gtk_layout_get_vadjustment(g->layout); + GtkAdjustment *hadj = gtk_layout_get_hadjustment(g->layout); + gdouble vlower, vpage, vupper, hlower, hpage, hupper, x = (double)sx, y = (double)sy; + + assert(vadj); + assert(hadj); + + g_object_get(vadj, "page-size", &vpage, "lower", &vlower, "upper", &vupper, NULL); + g_object_get(hadj, "page-size", &hpage, "lower", &hlower, "upper", &hupper, NULL); + + if (x < hlower) + x = hlower; + if (x > (hupper - hpage)) + x = hupper - hpage; + if (y < vlower) + y = vlower; + if (y > (vupper - vpage)) + y = vupper - vpage; + + gtk_adjustment_set_value(vadj, y); + gtk_adjustment_set_value(hadj, x); +} + +void gui_window_scroll_visible(struct gui_window *g, int x0, int y0, + int x1, int y1) +{ + gui_window_set_scroll(g,x0,y0); +} + + +/** + * Set the scale setting of a window + * + * \param g gui window + * \param scale scale value (1.0 == normal scale) + */ + +void gui_window_set_scale(struct gui_window *g, float scale) +{ +} + + +void gui_window_update_extent(struct gui_window *g) +{ + if (!g->bw->current_content) + return; + + gtk_layout_set_size(g->layout, + content_get_width(g->bw->current_content) * g->bw->scale, + content_get_height(g->bw->current_content) * g->bw->scale); +} + +static GdkCursor *nsgtk_create_menu_cursor(void) +{ + static char menu_cursor_bits[] = { + 0x00, 0x00, 0x80, 0x7F, 0x88, 0x40, 0x9E, 0x5E, 0x88, 0x40, 0x80, 0x56, + 0x80, 0x40, 0x80, 0x5A, 0x80, 0x40, 0x80, 0x5E, 0x80, 0x40, 0x80, 0x56, + 0x80, 0x40, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x00, }; + + static char menu_cursor_mask_bits[] = { + 0xC0, 0xFF, 0xC8, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xC8, 0xFF, + 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, + 0xC0, 0xFF, 0xC0, 0xFF, 0xC0, 0xFF, 0x00, 0x00, }; + + static GdkCursor *r; + static GdkColor fg = { 0, 0, 0, 0 }; + static GdkColor bg = { 0, 65535, 65535, 65535 }; + + GdkPixmap *source, *mask; + + if (r != NULL) + return r; + + source = gdk_bitmap_create_from_data(NULL, menu_cursor_bits, + 16, 16); + mask = gdk_bitmap_create_from_data (NULL, menu_cursor_mask_bits, + 16, 16); + + r = gdk_cursor_new_from_pixmap(source, mask, &fg, &bg, 0, 3); + gdk_pixmap_unref(source); + gdk_pixmap_unref(mask); + + return r; +} + +void gui_window_set_pointer(struct gui_window *g, gui_pointer_shape shape) +{ + GdkCursor *cursor = NULL; + GdkCursorType cursortype; + bool nullcursor = false; + + if (g->current_pointer == shape) + return; + + g->current_pointer = shape; + + switch (shape) { + case GUI_POINTER_POINT: + cursortype = GDK_HAND2; + break; + case GUI_POINTER_CARET: + cursortype = GDK_XTERM; + break; + case GUI_POINTER_UP: + cursortype = GDK_TOP_SIDE; + break; + case GUI_POINTER_DOWN: + cursortype = GDK_BOTTOM_SIDE; + break; + case GUI_POINTER_LEFT: + cursortype = GDK_LEFT_SIDE; + break; + case GUI_POINTER_RIGHT: + cursortype = GDK_RIGHT_SIDE; + break; + case GUI_POINTER_LD: + cursortype = GDK_BOTTOM_LEFT_CORNER; + break; + case GUI_POINTER_RD: + cursortype = GDK_BOTTOM_RIGHT_CORNER; + break; + case GUI_POINTER_LU: + cursortype = GDK_TOP_LEFT_CORNER; + break; + case GUI_POINTER_RU: + cursortype = GDK_TOP_RIGHT_CORNER; + break; + case GUI_POINTER_CROSS: + cursortype = GDK_CROSS; + break; + case GUI_POINTER_MOVE: + cursortype = GDK_FLEUR; + break; + case GUI_POINTER_WAIT: + cursortype = GDK_WATCH; + break; + case GUI_POINTER_HELP: + cursortype = GDK_QUESTION_ARROW; + break; + case GUI_POINTER_MENU: + cursor = nsgtk_create_menu_cursor(); + nullcursor = true; + break; + case GUI_POINTER_PROGRESS: + /* In reality, this needs to be the funky left_ptr_watch + * which we can't do easily yet. + */ + cursortype = GDK_WATCH; + break; + /* The following we're not sure about */ + case GUI_POINTER_NO_DROP: + case GUI_POINTER_NOT_ALLOWED: + case GUI_POINTER_DEFAULT: + default: + nullcursor = true; + } + + if (!nullcursor) + cursor = gdk_cursor_new_for_display( + gtk_widget_get_display( + GTK_WIDGET(g->layout)), + cursortype); + gdk_window_set_cursor(GTK_WIDGET(g->layout)->window, cursor); + + if (!nullcursor) + gdk_cursor_unref(cursor); +} + +void gui_window_hide_pointer(struct gui_window *g) +{ + +} + +void gui_window_place_caret(struct gui_window *g, int x, int y, int height) +{ + nsgtk_redraw_caret(g); + + g->caretx = x; + g->carety = y + 1; + g->careth = height - 2; + + nsgtk_redraw_caret(g); + + gtk_widget_grab_focus(GTK_WIDGET(g->layout)); +} + +void gui_window_remove_caret(struct gui_window *g) +{ + int oh = g->careth; + + if (oh == 0) + return; + + g->careth = 0; + + gui_window_redraw(g, g->caretx, g->carety, + g->caretx, g->carety + oh); +} + +void gui_window_new_content(struct gui_window *g) +{ + +} + +bool gui_window_scroll_start(struct gui_window *g) +{ + return true; +} + +bool gui_window_box_scroll_start(struct gui_window *g, + int x0, int y0, int x1, int y1) +{ + return true; +} + +void gui_drag_save_object(gui_save_type type, hlcache_handle *c, + struct gui_window *g) +{ + +} + +void gui_drag_save_selection(struct selection *s, struct gui_window *g) +{ + +} + +void gui_window_get_dimensions(struct gui_window *g, int *width, int *height, + bool scaled) +{ + *width = GTK_WIDGET(g->layout)->allocation.width; + *height = GTK_WIDGET(g->layout)->allocation.height; + + if (scaled) { + *width /= g->bw->scale; + *height /= g->bw->scale; + } + LOG(("\tWINDOW WIDTH: %i\n", *width)); + LOG(("\tWINDOW HEIGHT: %i\n", *height)); +} + +bool gui_window_frame_resize_start(struct gui_window *g) +{ + return true; +} diff --git a/gtk/window.h b/gtk/window.h new file mode 100644 index 000000000..abb722212 --- /dev/null +++ b/gtk/window.h @@ -0,0 +1,51 @@ +/* + * Copyright 2006 Daniel Silverstone + * + * 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 . + */ + +#ifndef NETSURF_GTK_WINDOW_H +#define NETSURF_GTK_WINDOW_H 1 + +#include "desktop/gui.h" +#include "desktop/browser.h" +#include "gtk/scaffolding.h" + + +typedef enum nsgtk_window_signals { + NSGTK_WINDOW_SIGNAL_CLICK, + NSGTK_WINDOW_SIGNAL_REDRAW, + NSGTK_WINDOW_SIGNAL_COUNT +} nsgtk_window_signal; + +extern struct gui_window *window_list; +extern int temp_open_background; + +void nsgtk_reflow_all_windows(void); +void nsgtk_window_process_reformats(void); + +nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g); + +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); + + +#endif /* NETSURF_GTK_WINDOW_H */ -- cgit v1.2.3