summaryrefslogtreecommitdiff
path: root/frontends/gtk/gui.c
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/gtk/gui.c')
-rw-r--r--frontends/gtk/gui.c1333
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;
}