diff options
Diffstat (limited to 'frontends/gtk/gui.c')
-rw-r--r-- | frontends/gtk/gui.c | 1333 |
1 files changed, 675 insertions, 658 deletions
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c index 3163be16d..661176ded 100644 --- a/frontends/gtk/gui.c +++ b/frontends/gtk/gui.c @@ -41,13 +41,13 @@ #include "netsurf/keypress.h" #include "netsurf/url_db.h" #include "netsurf/cookie_db.h" +#include "netsurf/browser.h" #include "netsurf/browser_window.h" -#include "netsurf/misc.h" #include "netsurf/netsurf.h" +#include "netsurf/bitmap.h" #include "content/fetch.h" #include "content/backing_store.h" #include "desktop/save_complete.h" -#include "desktop/save_pdf.h" #include "desktop/searchweb.h" #include "desktop/hotlist.h" @@ -62,446 +62,34 @@ #include "gtk/global_history.h" #include "gtk/hotlist.h" #include "gtk/throbber.h" +#include "gtk/toolbar_items.h" #include "gtk/scaffolding.h" #include "gtk/window.h" #include "gtk/schedule.h" #include "gtk/selection.h" #include "gtk/search.h" -#include "gtk/ssl_cert.h" #include "gtk/bitmap.h" +#include "gtk/misc.h" #include "gtk/resources.h" -#include "gtk/login.h" #include "gtk/layout_pango.h" #include "gtk/accelerator.h" bool nsgtk_complete = false; -char *nsgtk_config_home; /* exported global defined in gtk/gui.h */ +/* exported global defined in gtk/gui.h */ +char *nsgtk_config_home; -GdkPixbuf *favicon_pixbuf; /** favicon default pixbuf */ -GdkPixbuf *win_default_icon_pixbuf; /** default window icon pixbuf */ -GdkPixbuf *arrow_down_pixbuf; /** arrow down pixbuf */ +/** favicon default pixbuf */ +GdkPixbuf *favicon_pixbuf; -GtkBuilder *warning_builder; - -char **respaths; /** resource search path vector */ - -/** - * Cause an abnormal program termination. - * - * \note This never returns and is intended to terminate without any cleanup. - * - * \param error The message to display to the user. - */ -static void die(const char * const error) -{ - fprintf(stderr, "%s", error); - exit(EXIT_FAILURE); -} - -/** - * Create an array of valid paths to search for resources. - * - * The idea is that all the complex path computation to find resources - * is performed here, once, rather than every time a resource is - * searched for. - */ -static char ** -nsgtk_init_resource_path(const char *config_home) -{ - char *resource_path; - int resource_path_len; - const gchar * const *langv; - char **pathv; /* resource path string vector */ - char **respath; /* resource paths vector */ - - if (config_home != NULL) { - resource_path_len = snprintf(NULL, 0, - "%s:${NETSURFRES}:%s", - config_home, - GTK_RESPATH); - resource_path = malloc(resource_path_len + 1); - if (resource_path == NULL) { - return NULL; - } - snprintf(resource_path, resource_path_len + 1, - "%s:${NETSURFRES}:%s", - config_home, - GTK_RESPATH); - } else { - resource_path_len = snprintf(NULL, 0, - "${NETSURFRES}:%s", - GTK_RESPATH); - resource_path = malloc(resource_path_len + 1); - if (resource_path == NULL) { - return NULL; - } - snprintf(resource_path, - resource_path_len + 1, - "${NETSURFRES}:%s", - GTK_RESPATH); - } - - pathv = filepath_path_to_strvec(resource_path); - - langv = g_get_language_names(); - - respath = filepath_generate(pathv, langv); - - filepath_free_strvec(pathv); - - free(resource_path); - - return respath; -} - - -/** - * Set option defaults for gtk frontend. - * - * @param defaults The option table to update. - * @return error status. - */ -static nserror set_defaults(struct nsoption_s *defaults) -{ - char *fname; - - /* cookie file default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); - if (fname != NULL) { - nsoption_setnull_charp(cookie_file, fname); - } - - /* cookie jar default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); - if (fname != NULL) { - nsoption_setnull_charp(cookie_jar, fname); - } - - /* url database default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs"); - if (fname != NULL) { - nsoption_setnull_charp(url_file, fname); - } - - /* bookmark database default */ - fname = NULL; - netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist"); - if (fname != NULL) { - nsoption_setnull_charp(hotlist_path, fname); - } - - /* download directory default */ - fname = getenv("HOME"); - if (fname != NULL) { - nsoption_setnull_charp(downloads_directory, strdup(fname)); - } - - /* default path to certificates */ - nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs")); - - if ((nsoption_charp(cookie_file) == NULL) || - (nsoption_charp(cookie_jar) == NULL) || - (nsoption_charp(url_file) == NULL) || - (nsoption_charp(hotlist_path) == NULL) || - (nsoption_charp(downloads_directory) == NULL) || - (nsoption_charp(ca_path) == NULL)) { - NSLOG(netsurf, INFO, - "Failed initialising default resource paths"); - return NSERROR_BAD_PARAMETER; - } - - /* set default font names */ - nsoption_set_charp(font_sans, strdup("Sans")); - nsoption_set_charp(font_serif, strdup("Serif")); - nsoption_set_charp(font_mono, strdup("Monospace")); - nsoption_set_charp(font_cursive, strdup("Serif")); - nsoption_set_charp(font_fantasy, strdup("Serif")); - - return NSERROR_OK; -} - - - - -/** - * Initialize GTK specific parts of the browser. - * - * \param argc The number of arguments on the command line - * \param argv A string vector of command line arguments. - * \respath A string vector of the path elements of resources - */ -static nserror nsgtk_init(int argc, char** argv, char **respath) -{ - char buf[PATH_MAX]; - char *resource_filename; - char *addr = NULL; - nsurl *url; - nserror res; - - /* Initialise gtk accelerator table */ - res = nsgtk_accelerator_init(respaths); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Unable to load gtk accelerator configuration"); - /* not fatal if this does not load */ - } - - /* initialise warning dialog */ - res = nsgtk_builder_new_from_resname("warning", &warning_builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise warning dialog"); - return res; - } - - gtk_builder_connect_signals(warning_builder, NULL); - - /* set default icon if its available */ - res = nsgdk_pixbuf_new_from_resname("netsurf.xpm", - &win_default_icon_pixbuf); - if (res == NSERROR_OK) { - NSLOG(netsurf, INFO, "Seting default window icon"); - gtk_window_set_default_icon(win_default_icon_pixbuf); - } - - /* Search engine sources */ - resource_filename = filepath_find(respath, "SearchEngines"); - search_web_init(resource_filename); - if (resource_filename != NULL) { - NSLOG(netsurf, INFO, "Using '%s' as Search Engines file", - resource_filename); - free(resource_filename); - } - - /* Default favicon */ - res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf); - if (res != NSERROR_OK) { - favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - false, 8, 16, 16); - } - - /* arrow down icon */ - res = nsgdk_pixbuf_new_from_resname("arrow_down_8x32.png", - &arrow_down_pixbuf); - if (res != NSERROR_OK) { - arrow_down_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, - false, 8, 8, 32); - } - - /* initialise throbber */ - res = nsgtk_throbber_init(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise throbber."); - return res; - } - - /* Initialise completions - cannot fail */ - nsgtk_completion_init(); - - /* The tree view system needs to know the screen's DPI, so we - * find that out here, rather than when we create a first browser - * window. - */ - browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default())); - NSLOG(netsurf, INFO, "Set CSS DPI to %d", browser_get_dpi()); - - filepath_sfinddef(respath, buf, "mime.types", "/etc/"); - gtk_fetch_filetype_init(buf); - - save_complete_init(); - - urldb_load(nsoption_charp(url_file)); - urldb_load_cookies(nsoption_charp(cookie_file)); - hotlist_init(nsoption_charp(hotlist_path), - nsoption_charp(hotlist_path)); - - /* Initialise top level UI elements */ - res = nsgtk_download_init(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to initialise download window."); - return res; - } - - /* If there is a url specified on the command line use it */ - if (argc > 1) { - struct stat fs; - if (stat(argv[1], &fs) == 0) { - size_t addrlen; - char *rp = realpath(argv[1], NULL); - assert(rp != NULL); - - /* calculate file url length including terminator */ - addrlen = SLEN("file://") + strlen(rp) + 1; - addr = malloc(addrlen); - assert(addr != NULL); - snprintf(addr, addrlen, "file://%s", rp); - free(rp); - } else { - addr = strdup(argv[1]); - } - } - if (addr != NULL) { - /* managed to set up based on local launch */ - } else if (nsoption_charp(homepage_url) != NULL) { - addr = strdup(nsoption_charp(homepage_url)); - } else { - addr = strdup(NETSURF_HOMEPAGE); - } - - /* create an initial browser window */ - res = nsurl_create(addr, &url); - if (res == NSERROR_OK) { - res = browser_window_create(BW_CREATE_HISTORY, - url, - NULL, - NULL, - NULL); - nsurl_unref(url); - } - - free(addr); - - return res; -} - - - -/** - * Ensures output logging stream is correctly configured - */ -static bool nslog_stream_configure(FILE *fptr) -{ - /* set log stream to be non-buffering */ - setbuf(fptr, NULL); - - return true; -} - - -/** - * Run the gtk event loop. - * - * The same as the standard gtk_main loop except this ensures active - * FD are added to the gtk poll event set. - */ -static void nsgtk_main(void) -{ - fd_set read_fd_set, write_fd_set, exc_fd_set; - int max_fd; - GPollFD *fd_list[1000]; - unsigned int fd_count; - - while (!nsgtk_complete) { - max_fd = -1; - fd_count = 0; - FD_ZERO(&read_fd_set); - FD_ZERO(&write_fd_set); - FD_ZERO(&exc_fd_set); - - fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); - for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, &read_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - if (FD_ISSET(i, &write_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_OUT | G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - if (FD_ISSET(i, &exc_fd_set)) { - GPollFD *fd = malloc(sizeof *fd); - fd->fd = i; - fd->events = G_IO_ERR; - g_main_context_add_poll(0, fd, 0); - fd_list[fd_count++] = fd; - } - } - - schedule_run(); +/** default window icon pixbuf */ +GdkPixbuf *win_default_icon_pixbuf; - gtk_main_iteration(); - - for (unsigned int i = 0; i != fd_count; i++) { - g_main_context_remove_poll(0, fd_list[i]); - free(fd_list[i]); - } - } -} - - -static void gui_quit(void) -{ - nserror res; - - NSLOG(netsurf, INFO, "Quitting GUI"); - - /* Ensure all scaffoldings are destroyed before we go into exit */ - nsgtk_download_destroy(); - urldb_save_cookies(nsoption_charp(cookie_jar)); - urldb_save(nsoption_charp(url_file)); - - res = nsgtk_cookies_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising cookie viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_local_history_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Error finalising local history viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_global_history_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Error finalising global history viewer: %s", - messages_get_errorcode(res)); - } - - res = nsgtk_hotlist_destroy(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising hotlist viewer: %s", - messages_get_errorcode(res)); - } - - res = hotlist_fini(); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Error finalising hotlist: %s", - messages_get_errorcode(res)); - } - - free(nsgtk_config_home); - - gtk_fetch_filetype_fin(); -} - -static nserror gui_launch_url(struct nsurl *url) -{ - gboolean ok; - GError *error = NULL; +GtkBuilder *warning_builder; - ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error); - if (ok == TRUE) { - return NSERROR_OK; - } +/** resource search path vector */ +char **respaths; - if (error) { - nsgtk_warning(messages_get("URIOpenError"), error->message); - g_error_free(error); - } - return NSERROR_NO_FETCH_HANDLER; -} /* exported function documented in gtk/warn.h */ nserror nsgtk_warning(const char *warning, const char *detail) @@ -518,7 +106,7 @@ nserror nsgtk_warning(const char *warning, const char *detail) "labelWarning")); snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), - detail ? detail : ""); + detail ? detail : ""); buf[sizeof(buf) - 1] = 0; gtk_label_set_text(WarningLabel, buf); @@ -529,129 +117,7 @@ nserror nsgtk_warning(const char *warning, const char *detail) } -static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data) -{ - char **owner_pass = ((void **)data)[0]; - char **user_pass = ((void **)data)[1]; - GtkWindow *wnd = ((void **)data)[2]; - GtkBuilder *password_builder = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - char *op, *op1; - char *up, *up1; - - op = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFOwnerPassword")))); - op1 = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFOwnerPassword1")))); - up = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFUserPassword")))); - up1 = strdup(gtk_entry_get_text( - GTK_ENTRY(gtk_builder_get_object(password_builder, - "entryPDFUserPassword1")))); - - - if (op[0] == '\0') { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), - "Owner password must be at least 1 character long:"); - free(op); - free(up); - } else if (!strcmp(op, up)) { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), - "User and owner passwords must be different:"); - free(op); - free(up); - } else if (!strcmp(op, op1) && !strcmp(up, up1)) { - - *owner_pass = op; - if (up[0] == '\0') - free(up); - else - *user_pass = up; - - free(data); - gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(password_builder)); - - save_pdf(path); - - free(path); - } else { - gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder, - "labelInfo")), "Passwords not confirmed:"); - free(op); - free(up); - } - - free(op1); - free(up1); -} - -static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data) -{ - GtkWindow *wnd = ((void **)data)[2]; - GtkBuilder *password_builder = ((void **)data)[3]; - char *path = ((void **)data)[4]; - - free(data); - - gtk_widget_destroy(GTK_WIDGET(wnd)); - g_object_unref(G_OBJECT(password_builder)); - - save_pdf(path); - - free(path); -} - -static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path) -{ - GtkButton *ok, *no; - GtkWindow *wnd; - void **data; - GtkBuilder *password_builder; - nserror res; - - res = nsgtk_builder_new_from_resname("password", &password_builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Password UI builder init failed"); - return; - } - - gtk_builder_connect_signals(password_builder, NULL); - - wnd = GTK_WINDOW(gtk_builder_get_object(password_builder, - "wndPDFPassword")); - - data = malloc(5 * sizeof(void *)); - - *owner_pass = NULL; - *user_pass = NULL; - - data[0] = owner_pass; - data[1] = user_pass; - data[2] = wnd; - data[3] = password_builder; - data[4] = path; - - ok = GTK_BUTTON(gtk_builder_get_object(password_builder, - "buttonPDFSetPassword")); - no = GTK_BUTTON(gtk_builder_get_object(password_builder, - "buttonPDFNoPassword")); - - g_signal_connect(G_OBJECT(ok), "clicked", - G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data); - g_signal_connect(G_OBJECT(no), "clicked", - G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data); - - gtk_widget_show(GTK_WIDGET(wnd)); -} - - +/* exported interface documented in gtk/gui.h */ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) { /* this function will need to become much more complex to support @@ -666,12 +132,16 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) case GDK_KEY(BackSpace): if (key->state & GDK_SHIFT_MASK) return NS_KEY_DELETE_LINE_START; + else if (key->state & GDK_CONTROL_MASK) + return NS_KEY_DELETE_WORD_LEFT; else return NS_KEY_DELETE_LEFT; case GDK_KEY(Delete): if (key->state & GDK_SHIFT_MASK) return NS_KEY_DELETE_LINE_END; + else if (key->state & GDK_CONTROL_MASK) + return NS_KEY_DELETE_WORD_RIGHT; else return NS_KEY_DELETE_RIGHT; @@ -683,10 +153,14 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) case GDK_KEY(Left): case GDK_KEY(KP_Left): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_WORD_LEFT; return NS_KEY_LEFT; case GDK_KEY(Right): case GDK_KEY(KP_Right): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_WORD_RIGHT; return NS_KEY_RIGHT; case GDK_KEY(Up): @@ -781,6 +255,63 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key) /** + * Create an array of valid paths to search for resources. + * + * The idea is that all the complex path computation to find resources + * is performed here, once, rather than every time a resource is + * searched for. + */ +static char ** +nsgtk_init_resource_path(const char *config_home) +{ + char *resource_path; + int resource_path_len; + const gchar * const *langv; + char **pathv; /* resource path string vector */ + char **respath; /* resource paths vector */ + + if (config_home != NULL) { + resource_path_len = snprintf(NULL, 0, + "%s:${NETSURFRES}:%s", + config_home, + GTK_RESPATH); + resource_path = malloc(resource_path_len + 1); + if (resource_path == NULL) { + return NULL; + } + snprintf(resource_path, resource_path_len + 1, + "%s:${NETSURFRES}:%s", + config_home, + GTK_RESPATH); + } else { + resource_path_len = snprintf(NULL, 0, + "${NETSURFRES}:%s", + GTK_RESPATH); + resource_path = malloc(resource_path_len + 1); + if (resource_path == NULL) { + return NULL; + } + snprintf(resource_path, + resource_path_len + 1, + "${NETSURFRES}:%s", + GTK_RESPATH); + } + + pathv = filepath_path_to_strvec(resource_path); + + langv = g_get_language_names(); + + respath = filepath_generate(pathv, langv); + + filepath_free_strvec(pathv); + + free(resource_path); + + return respath; +} + + +/** * create directory name and check it is acessible and a directory. */ static nserror @@ -818,6 +349,7 @@ check_dirname(const char *path, const char *leaf, char **dirname_out) return ret; } + /** * Get the path to the config directory. * @@ -885,6 +417,7 @@ static nserror get_config_home(char **config_home_out) return NSERROR_OK; } + static nserror create_config_home(char **config_home_out) { char *config_home = NULL; @@ -935,6 +468,192 @@ static nserror create_config_home(char **config_home_out) return NSERROR_OK; } + +/** + * Ensures output logging stream is correctly configured + */ +static bool nslog_stream_configure(FILE *fptr) +{ + /* set log stream to be non-buffering */ + setbuf(fptr, NULL); + + return true; +} + + +/** + * Set option defaults for gtk frontend. + * + * \param defaults The option table to update. + * \return error status. + */ +static nserror set_defaults(struct nsoption_s *defaults) +{ + char *fname; + GtkSettings *settings; + GtkIconSize tooliconsize; + GtkToolbarStyle toolbarstyle; + + /* cookie file default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); + if (fname != NULL) { + nsoption_setnull_charp(cookie_file, fname); + } + + /* cookie jar default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Cookies"); + if (fname != NULL) { + nsoption_setnull_charp(cookie_jar, fname); + } + + /* url database default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "URLs"); + if (fname != NULL) { + nsoption_setnull_charp(url_file, fname); + } + + /* bookmark database default */ + fname = NULL; + netsurf_mkpath(&fname, NULL, 2, nsgtk_config_home, "Hotlist"); + if (fname != NULL) { + nsoption_setnull_charp(hotlist_path, fname); + } + + /* download directory default */ + fname = getenv("HOME"); + if (fname != NULL) { + nsoption_setnull_charp(downloads_directory, strdup(fname)); + } + + if ((nsoption_charp(cookie_file) == NULL) || + (nsoption_charp(cookie_jar) == NULL) || + (nsoption_charp(url_file) == NULL) || + (nsoption_charp(hotlist_path) == NULL) || + (nsoption_charp(downloads_directory) == NULL)) { + NSLOG(netsurf, INFO, + "Failed initialising default resource paths"); + return NSERROR_BAD_PARAMETER; + } + + /* set default font names */ + nsoption_set_charp(font_sans, strdup("Sans")); + nsoption_set_charp(font_serif, strdup("Serif")); + nsoption_set_charp(font_mono, strdup("Monospace")); + nsoption_set_charp(font_cursive, strdup("Serif")); + nsoption_set_charp(font_fantasy, strdup("Serif")); + + /* Default toolbar button type to system defaults */ + + settings = gtk_settings_get_default(); + g_object_get(settings, + "gtk-toolbar-icon-size", &tooliconsize, + "gtk-toolbar-style", &toolbarstyle, NULL); + + switch (toolbarstyle) { + case GTK_TOOLBAR_ICONS: + if (tooliconsize == GTK_ICON_SIZE_SMALL_TOOLBAR) { + nsoption_set_int(button_type, 1); + } else { + nsoption_set_int(button_type, 2); + } + break; + + case GTK_TOOLBAR_TEXT: + nsoption_set_int(button_type, 4); + break; + + case GTK_TOOLBAR_BOTH: + case GTK_TOOLBAR_BOTH_HORIZ: + /* no labels in default configuration */ + default: + /* No system default, so use large icons */ + nsoption_set_int(button_type, 2); + break; + } + + /* set default items in toolbar */ + nsoption_set_charp(toolbar_items, + strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu")); + + /* set default for menu and tool bar visibility */ + nsoption_set_charp(bar_show, strdup("tool")); + + return NSERROR_OK; +} + + +/** + * Initialise user options + * + * Initialise the browser configuration options. These are set by: + * - set generic defaults suitable for the gtk frontend + * - user choices loaded from Choices file + * - command line parameters + */ +static nserror nsgtk_option_init(int *pargc, char** argv) +{ + nserror ret; + char *choices = NULL; + + /* user options setup */ + ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); + if (ret != NSERROR_OK) { + return ret; + } + + /* Attempt to load the user choices */ + ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); + if (ret == NSERROR_OK) { + nsoption_read(choices, nsoptions); + free(choices); + } + + /* overide loaded options with those from commandline */ + nsoption_commandline(pargc, argv, nsoptions); + + /* ensure all options fall within sensible bounds */ + + /* Attempt to handle nonsense status bar widths. These may exist + * in people's Choices as the GTK front end used to abuse the + * status bar width option by using it for an absolute value in px. + * The GTK front end now correctly uses it as a proportion of window + * width. Here we assume that a value of less than 15% is wrong + * and set to the default two thirds. */ + if (nsoption_int(toolbar_status_size) < 1500) { + nsoption_set_int(toolbar_status_size, 6667); + } + + return NSERROR_OK; +} + + +/** + * initialise message translation + */ +static nserror nsgtk_messages_init(char **respaths) +{ + const char *messages; + nserror ret; + const uint8_t *data; + size_t data_size; + + ret = nsgtk_data_from_resname("Messages", &data, &data_size); + if (ret == NSERROR_OK) { + ret = messages_add_from_inline(data, data_size); + } else { + /* Obtain path to messages */ + ret = nsgtk_path_from_resname("Messages", &messages); + if (ret == NSERROR_OK) { + ret = messages_add_from_file(messages); + } + } + return ret; +} + + /** * Get the path to the cache directory. * @@ -983,6 +702,10 @@ static nserror get_cache_home(char **cache_home_out) return NSERROR_OK; } + +/** + * create a cache directory + */ static nserror create_cache_home(char **cache_home_out) { char *cache_home = NULL; @@ -990,7 +713,7 @@ static nserror create_cache_home(char **cache_home_out) char *xdg_cache_dir; nserror ret; - NSLOG(netsurf, INFO, "Attempting to create configuration directory"); + NSLOG(netsurf, INFO, "Attempting to create cache directory"); /* $XDG_CACHE_HOME defines the base directory * relative to which user specific cache files @@ -1033,98 +756,13 @@ static nserror create_cache_home(char **cache_home_out) return NSERROR_OK; } -static nserror nsgtk_option_init(int *pargc, char** argv) -{ - nserror ret; - char *choices = NULL; - - /* user options setup */ - ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default); - if (ret != NSERROR_OK) { - return ret; - } - - /* Attempt to load the user choices */ - ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices"); - if (ret == NSERROR_OK) { - nsoption_read(choices, nsoptions); - free(choices); - } - - /* overide loaded options with those from commandline */ - nsoption_commandline(pargc, argv, nsoptions); - - /* ensure all options fall within sensible bounds */ - - /* Attempt to handle nonsense status bar widths. These may exist - * in people's Choices as the GTK front end used to abuse the - * status bar width option by using it for an absolute value in px. - * The GTK front end now correctly uses it as a proportion of window - * width. Here we assume that a value of less than 15% is wrong - * and set to the default two thirds. */ - if (nsoption_int(toolbar_status_size) < 1500) { - nsoption_set_int(toolbar_status_size, 6667); - } - - return NSERROR_OK; -} - -static struct gui_misc_table nsgtk_misc_table = { - .schedule = nsgtk_schedule, - .warning = nsgtk_warning, - - .quit = gui_quit, - .launch_url = gui_launch_url, - .cert_verify = gtk_cert_verify, - .login = gui_401login_open, - .pdf_password = nsgtk_pdf_password, -}; - - -static nserror nsgtk_messages_init(char **respaths) -{ - const char *messages; - nserror ret; - const uint8_t *data; - size_t data_size; - - ret = nsgtk_data_from_resname("Messages", &data, &data_size); - if (ret == NSERROR_OK) { - ret = messages_add_from_inline(data, data_size); - } else { - /* Obtain path to messages */ - ret = nsgtk_path_from_resname("Messages", &messages); - if (ret == NSERROR_OK) { - ret = messages_add_from_file(messages); - } - } - return ret; -} /** - * Main entry point from OS. + * GTK specific initialisation */ -int main(int argc, char** argv) +static nserror nsgtk_init(int *pargc, char ***pargv, char **cache_home) { - char *cache_home = NULL; nserror ret; - struct netsurf_table nsgtk_table = { - .misc = &nsgtk_misc_table, - .window = nsgtk_window_table, - .clipboard = nsgtk_clipboard_table, - .download = nsgtk_download_table, - .fetch = nsgtk_fetch_table, - .llcache = filesystem_llcache_table, - .search = nsgtk_search_table, - .search_web = nsgtk_search_web_table, - .bitmap = nsgtk_bitmap_table, - .layout = nsgtk_layout_table, - }; - - ret = netsurf_register(&nsgtk_table); - if (ret != NSERROR_OK) { - die("NetSurf operation table failed registration\n"); - } /* Locate the correct user configuration directory path */ ret = get_config_home(&nsgtk_config_home); @@ -1139,12 +777,12 @@ int main(int argc, char** argv) } /* Initialise gtk */ - gtk_init(&argc, &argv); + gtk_init(pargc, pargv); /* initialise logging. Not fatal if it fails but not much we * can do about it either. */ - nslog_init(nslog_stream_configure, &argc, argv); + nslog_init(nslog_stream_configure, pargc, *pargv); /* build the common resource path list */ respaths = nsgtk_init_resource_path(nsgtk_config_home); @@ -1158,15 +796,15 @@ int main(int argc, char** argv) if (ret != NSERROR_OK) { fprintf(stderr, "GTK resources failed to initialise (%s)\n", messages_get_errorcode(ret)); - return 1; + return ret; } /* Initialise user options */ - ret = nsgtk_option_init(&argc, argv); + ret = nsgtk_option_init(pargc, *pargv); if (ret != NSERROR_OK) { fprintf(stderr, "Options failed to initialise (%s)\n", messages_get_errorcode(ret)); - return 1; + return ret; } /* Initialise translated messages */ @@ -1177,35 +815,353 @@ int main(int argc, char** argv) NSLOG(netsurf, INFO, "Unable to load translated messages"); /** \todo decide if message load faliure should be fatal */ } - + /* Locate the correct user cache directory path */ - ret = get_cache_home(&cache_home); + ret = get_cache_home(cache_home); if (ret == NSERROR_NOT_FOUND) { /* no cache directory exists yet so try to create one */ - ret = create_cache_home(&cache_home); + ret = create_cache_home(cache_home); } if (ret != NSERROR_OK) { NSLOG(netsurf, INFO, "Unable to locate a cache directory."); } - /* core initialisation */ - ret = netsurf_init(cache_home); - free(cache_home); - if (ret != NSERROR_OK) { - fprintf(stderr, "NetSurf core failed to initialise (%s)\n", - messages_get_errorcode(ret)); - return 1; + + return NSERROR_OK; +} + + +#if GTK_CHECK_VERSION(3,14,0) + +/** + * adds named icons into gtk theme + */ +static nserror nsgtk_add_named_icons_to_theme(void) +{ + gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(), + "/org/netsurf/icons"); + return NSERROR_OK; +} + +#else + +static nserror +add_builtin_icon(const char *prefix, const char *name, int x, int y) +{ + GdkPixbuf *pixbuf; + nserror res; + char *resname; + int resnamelen; + + /* resource name string length allowing for / .png and termination */ + resnamelen = strlen(prefix) + strlen(name) + 5 + 1 + 4 + 1; + resname = malloc(resnamelen); + if (resname == NULL) { + return NSERROR_NOMEM; } + snprintf(resname, resnamelen, "icons%s/%s.png", prefix, name); - /* gtk specific initalisation and main run loop */ - ret = nsgtk_init(argc, argv, respaths); - if (ret != NSERROR_OK) { - fprintf(stderr, "NetSurf gtk initialise failed (%s)\n", - messages_get_errorcode(ret)); + res = nsgdk_pixbuf_new_from_resname(resname, &pixbuf); + NSLOG(netsurf, DEEPDEBUG, "%d %s", res, resname); + free(resname); + if (res != NSERROR_OK) { + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, x, y); + } + gtk_icon_theme_add_builtin_icon(name, y, pixbuf); + + return NSERROR_OK; +} + + +/** + * adds named icons into gtk theme + */ +static nserror nsgtk_add_named_icons_to_theme(void) +{ + /* these must also be in gtk/resources.c pixbuf_resource *and* + * gtk/res/netsurf.gresource.xml + */ + add_builtin_icon("", "local-history", 8, 32); + add_builtin_icon("", "show-cookie", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-insecure", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-internal", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-local", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-secure", 24, 24); + add_builtin_icon("/24x24/actions", "page-info-warning", 24, 24); + add_builtin_icon("/48x48/actions", "page-info-insecure", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-internal", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-local", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-secure", 48, 48); + add_builtin_icon("/48x48/actions", "page-info-warning", 48, 48); + + return NSERROR_OK; +} + +#endif + + +/** + * setup GTK specific parts of the browser. + * + * \param argc The number of arguments on the command line + * \param argv A string vector of command line arguments. + * \respath A string vector of the path elements of resources + */ +static nserror nsgtk_setup(int argc, char** argv, char **respath) +{ + char buf[PATH_MAX]; + char *resource_filename; + char *addr = NULL; + nsurl *url; + nserror res; + + /* Initialise gtk accelerator table */ + res = nsgtk_accelerator_init(respaths); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Unable to load gtk accelerator configuration"); + /* not fatal if this does not load */ + } + + /* initialise warning dialog */ + res = nsgtk_builder_new_from_resname("warning", &warning_builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise warning dialog"); + return res; + } + + gtk_builder_connect_signals(warning_builder, NULL); + + /* set default icon if its available */ + res = nsgdk_pixbuf_new_from_resname("netsurf.xpm", + &win_default_icon_pixbuf); + if (res == NSERROR_OK) { + NSLOG(netsurf, INFO, "Seting default window icon"); + gtk_window_set_default_icon(win_default_icon_pixbuf); + } + + /* Search engine sources */ + resource_filename = filepath_find(respath, "SearchEngines"); + search_web_init(resource_filename); + if (resource_filename != NULL) { + NSLOG(netsurf, INFO, "Using '%s' as Search Engines file", + resource_filename); + free(resource_filename); + } + search_web_select_provider(nsoption_int(search_provider)); + + /* Default favicon */ + res = nsgdk_pixbuf_new_from_resname("favicon.png", &favicon_pixbuf); + if (res != NSERROR_OK) { + favicon_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, + false, 8, 16, 16); + } + + /* add named icons to gtk theme */ + res = nsgtk_add_named_icons_to_theme(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to add named icons to GTK theme."); + return res; + } + + /* initialise throbber */ + res = nsgtk_throbber_init(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise throbber."); + return res; + } + + /* Initialise completions - cannot fail */ + nsgtk_completion_init(); + + /* The tree view system needs to know the screen's DPI, so we + * find that out here, rather than when we create a first browser + * window. + */ + browser_set_dpi(gdk_screen_get_resolution(gdk_screen_get_default())); + NSLOG(netsurf, INFO, "Set CSS DPI to %d", browser_get_dpi()); + + bitmap_set_format(&(bitmap_fmt_t) { + .layout = BITMAP_LAYOUT_ARGB8888, + .pma = true, + }); + + filepath_sfinddef(respath, buf, "mime.types", "/etc/"); + gtk_fetch_filetype_init(buf); + + save_complete_init(); + + urldb_load(nsoption_charp(url_file)); + urldb_load_cookies(nsoption_charp(cookie_file)); + hotlist_init(nsoption_charp(hotlist_path), + nsoption_charp(hotlist_path)); + + /* Initialise top level UI elements */ + res = nsgtk_download_init(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to initialise download window."); + return res; + } + + /* If there is a url specified on the command line use it */ + if (argc > 1) { + struct stat fs; + if (stat(argv[1], &fs) == 0) { + size_t addrlen; + char *rp = realpath(argv[1], NULL); + assert(rp != NULL); + + /* calculate file url length including terminator */ + addrlen = SLEN("file://") + strlen(rp) + 1; + addr = malloc(addrlen); + assert(addr != NULL); + snprintf(addr, addrlen, "file://%s", rp); + free(rp); + } else { + addr = strdup(argv[1]); + } + } + if (addr != NULL) { + /* managed to set up based on local launch */ + } else if (nsoption_charp(homepage_url) != NULL) { + addr = strdup(nsoption_charp(homepage_url)); } else { - nsgtk_main(); + addr = strdup(NETSURF_HOMEPAGE); + } + + /* create an initial browser window */ + res = nsurl_create(addr, &url); + if (res == NSERROR_OK) { + res = browser_window_create(BW_CREATE_HISTORY, + url, + NULL, + NULL, + NULL); + nsurl_unref(url); + } + + free(addr); + + return res; +} + + +/** + * Run the gtk event loop. + * + * The same as the standard gtk_main loop except this ensures active + * FD are added to the gtk poll event set. + */ +static void nsgtk_main(void) +{ + fd_set read_fd_set, write_fd_set, exc_fd_set; + int max_fd; + GPollFD *fd_list[1000]; + unsigned int fd_count; + + while (!nsgtk_complete) { + max_fd = -1; + fd_count = 0; + FD_ZERO(&read_fd_set); + FD_ZERO(&write_fd_set); + FD_ZERO(&exc_fd_set); + + while (gtk_events_pending()) + gtk_main_iteration_do(TRUE); + + schedule_run(); + + fetch_fdset(&read_fd_set, &write_fd_set, &exc_fd_set, &max_fd); + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, &read_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_IN | G_IO_HUP | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &write_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_OUT | G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + if (FD_ISSET(i, &exc_fd_set)) { + GPollFD *fd = malloc(sizeof *fd); + fd->fd = i; + fd->events = G_IO_ERR; + g_main_context_add_poll(0, fd, 0); + fd_list[fd_count++] = fd; + } + } + + gtk_main_iteration(); + + for (unsigned int i = 0; i != fd_count; i++) { + g_main_context_remove_poll(0, fd_list[i]); + free(fd_list[i]); + } + } +} + + +/** + * finalise the browser + */ +static void nsgtk_finalise(void) +{ + nserror res; + + NSLOG(netsurf, INFO, "Quitting GUI"); + + /* Ensure all scaffoldings are destroyed before we go into exit */ + nsgtk_download_destroy(); + urldb_save_cookies(nsoption_charp(cookie_jar)); + urldb_save(nsoption_charp(url_file)); + + res = nsgtk_cookies_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising cookie viewer: %s", + messages_get_errorcode(res)); + } + + res = nsgtk_local_history_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Error finalising local history viewer: %s", + messages_get_errorcode(res)); } + res = nsgtk_global_history_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Error finalising global history viewer: %s", + messages_get_errorcode(res)); + } + + res = nsgtk_hotlist_destroy(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising hotlist viewer: %s", + messages_get_errorcode(res)); + } + + res = hotlist_fini(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising hotlist: %s", + messages_get_errorcode(res)); + } + + res = save_complete_finalise(); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Error finalising save complete: %s", + messages_get_errorcode(res)); + } + + free(nsgtk_config_home); + + gtk_fetch_filetype_fin(); + /* common finalisation */ netsurf_exit(); @@ -1215,5 +1171,66 @@ int main(int argc, char** argv) /* finalise logging */ nslog_finalise(); +} + + +/** + * Main entry point from OS. + */ +int main(int argc, char** argv) +{ + nserror res; + char *cache_home = NULL; + struct netsurf_table nsgtk_table = { + .misc = nsgtk_misc_table, + .window = nsgtk_window_table, + .clipboard = nsgtk_clipboard_table, + .download = nsgtk_download_table, + .fetch = nsgtk_fetch_table, + .llcache = filesystem_llcache_table, + .search = nsgtk_search_table, + .search_web = nsgtk_search_web_table, + .bitmap = nsgtk_bitmap_table, + .layout = nsgtk_layout_table, + }; + + res = netsurf_register(&nsgtk_table); + if (res != NSERROR_OK) { + fprintf(stderr, + "NetSurf operation table failed registration (%s)\n", + messages_get_errorcode(res)); + return 1; + } + + /* gtk specific initialisation */ + res = nsgtk_init(&argc, &argv, &cache_home); + if (res != NSERROR_OK) { + fprintf(stderr, "NetSurf gtk failed to initialise (%s)\n", + messages_get_errorcode(res)); + return 2; + } + + /* core initialisation */ + res = netsurf_init(cache_home); + free(cache_home); + if (res != NSERROR_OK) { + fprintf(stderr, "NetSurf core failed to initialise (%s)\n", + messages_get_errorcode(res)); + return 3; + } + + /* gtk specific initalisation and main run loop */ + res = nsgtk_setup(argc, argv, respaths); + if (res != NSERROR_OK) { + nsgtk_finalise(); + fprintf(stderr, "NetSurf gtk setup failed (%s)\n", + messages_get_errorcode(res)); + return 4; + } + + nsgtk_main(); + + nsgtk_finalise(); + return 0; } |