diff options
Diffstat (limited to 'frontends/gtk/gui.c')
-rw-r--r-- | frontends/gtk/gui.c | 1361 |
1 files changed, 636 insertions, 725 deletions
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c index e5006d954..661176ded 100644 --- a/frontends/gtk/gui.c +++ b/frontends/gtk/gui.c @@ -43,12 +43,11 @@ #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" @@ -70,34 +69,191 @@ #include "gtk/selection.h" #include "gtk/search.h" #include "gtk/bitmap.h" +#include "gtk/misc.h" #include "gtk/resources.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 */ +/** favicon default pixbuf */ +GdkPixbuf *favicon_pixbuf; + +/** default window icon pixbuf */ +GdkPixbuf *win_default_icon_pixbuf; GtkBuilder *warning_builder; -char **respaths; /** resource search path vector */ +/** resource search path vector */ +char **respaths; -/** - * 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) + +/* exported function documented in gtk/warn.h */ +nserror nsgtk_warning(const char *warning, const char *detail) { - fprintf(stderr, "%s", error); - exit(EXIT_FAILURE); + char buf[300]; /* 300 is the size the RISC OS GUI uses */ + static GtkWindow *nsgtk_warning_window; + GtkLabel *WarningLabel; + + NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : ""); + fflush(stdout); + + nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning")); + WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder, + "labelWarning")); + + snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), + detail ? detail : ""); + buf[sizeof(buf) - 1] = 0; + + gtk_label_set_text(WarningLabel, buf); + + gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window)); + + return NSERROR_OK; +} + + +/* 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 + * everything that the RISC OS version does. But this will do for + * now. I hope. + */ + switch (key->keyval) { + + case GDK_KEY(Tab): + return NS_KEY_TAB; + + 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; + + case GDK_KEY(Linefeed): + return 13; + + case GDK_KEY(Return): + return 10; + + 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): + case GDK_KEY(KP_Up): + return NS_KEY_UP; + + case GDK_KEY(Down): + case GDK_KEY(KP_Down): + return NS_KEY_DOWN; + + case GDK_KEY(Home): + case GDK_KEY(KP_Home): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_LINE_START; + else + return NS_KEY_TEXT_START; + + case GDK_KEY(End): + case GDK_KEY(KP_End): + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_LINE_END; + else + return NS_KEY_TEXT_END; + + case GDK_KEY(Page_Up): + case GDK_KEY(KP_Page_Up): + return NS_KEY_PAGE_UP; + + case GDK_KEY(Page_Down): + case GDK_KEY(KP_Page_Down): + return NS_KEY_PAGE_DOWN; + + case 'a': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_SELECT_ALL; + return gdk_keyval_to_unicode(key->keyval); + + case 'u': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_DELETE_LINE; + return gdk_keyval_to_unicode(key->keyval); + + case 'c': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_COPY_SELECTION; + return gdk_keyval_to_unicode(key->keyval); + + case 'v': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_PASTE; + return gdk_keyval_to_unicode(key->keyval); + + case 'x': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_CUT_SELECTION; + return gdk_keyval_to_unicode(key->keyval); + + case 'Z': + case 'y': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_REDO; + return gdk_keyval_to_unicode(key->keyval); + + case 'z': + if (key->state & GDK_CONTROL_MASK) + return NS_KEY_UNDO; + return gdk_keyval_to_unicode(key->keyval); + + case GDK_KEY(Escape): + return NS_KEY_ESCAPE; + + /* Modifiers - do nothing for now */ + case GDK_KEY(Shift_L): + case GDK_KEY(Shift_R): + case GDK_KEY(Control_L): + case GDK_KEY(Control_R): + case GDK_KEY(Caps_Lock): + case GDK_KEY(Shift_Lock): + case GDK_KEY(Meta_L): + case GDK_KEY(Meta_R): + case GDK_KEY(Alt_L): + case GDK_KEY(Alt_R): + case GDK_KEY(Super_L): + case GDK_KEY(Super_R): + case GDK_KEY(Hyper_L): + case GDK_KEY(Hyper_R): + return 0; + + } + return gdk_keyval_to_unicode(key->keyval); } + /** * Create an array of valid paths to search for resources. * @@ -156,6 +312,176 @@ nsgtk_init_resource_path(const char *config_home) /** + * create directory name and check it is acessible and a directory. + */ +static nserror +check_dirname(const char *path, const char *leaf, char **dirname_out) +{ + nserror ret; + char *dirname = NULL; + struct stat dirname_stat; + + ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf); + if (ret != NSERROR_OK) { + return ret; + } + + /* ensure access is possible and the entry is actualy + * a directory. + */ + if (stat(dirname, &dirname_stat) == 0) { + if (S_ISDIR(dirname_stat.st_mode)) { + if (access(dirname, R_OK | W_OK) == 0) { + *dirname_out = dirname; + return NSERROR_OK; + } else { + ret = NSERROR_PERMISSION; + } + } else { + ret = NSERROR_NOT_DIRECTORY; + } + } else { + ret = NSERROR_NOT_FOUND; + } + + free(dirname); + + return ret; +} + + +/** + * Get the path to the config directory. + * + * @param config_home_out Path to configuration directory. + * @return NSERROR_OK on sucess and \a config_home_out updated else error code. + */ +static nserror get_config_home(char **config_home_out) +{ + nserror ret; + char *home_dir; + char *xdg_config_dir; + char *config_home; + + home_dir = getenv("HOME"); + + /* The old $HOME/.netsurf/ directory should be used if it + * exists and is accessible. + */ + if (home_dir != NULL) { + ret = check_dirname(home_dir, ".netsurf", &config_home); + if (ret == NSERROR_OK) { + NSLOG(netsurf, INFO, "\"%s\"", config_home); + *config_home_out = config_home; + return ret; + } + } + + /* $XDG_CONFIG_HOME defines the base directory + * relative to which user specific configuration files + * should be stored. + */ + xdg_config_dir = getenv("XDG_CONFIG_HOME"); + + if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) { + /* If $XDG_CONFIG_HOME is either not set or empty, a + * default equal to $HOME/.config should be used. + */ + + /** @todo the meaning of empty is never defined so I + * am assuming it is a zero length string but is it + * supposed to mean "whitespace" and if so what counts + * as whitespace? (are tabs etc. counted or should + * isspace() be used) + */ + + /* the HOME envvar is required */ + if (home_dir == NULL) { + return NSERROR_NOT_DIRECTORY; + } + + ret = check_dirname(home_dir, ".config/netsurf", &config_home); + if (ret != NSERROR_OK) { + return ret; + } + } else { + ret = check_dirname(xdg_config_dir, "netsurf", &config_home); + if (ret != NSERROR_OK) { + return ret; + } + } + + NSLOG(netsurf, INFO, "\"%s\"", config_home); + + *config_home_out = config_home; + return NSERROR_OK; +} + + +static nserror create_config_home(char **config_home_out) +{ + char *config_home = NULL; + char *home_dir; + char *xdg_config_dir; + nserror ret; + + NSLOG(netsurf, INFO, "Attempting to create configuration directory"); + + /* $XDG_CONFIG_HOME defines the base directory + * relative to which user specific configuration files + * should be stored. + */ + xdg_config_dir = getenv("XDG_CONFIG_HOME"); + + if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) { + home_dir = getenv("HOME"); + + if ((home_dir == NULL) || (*home_dir == 0)) { + return NSERROR_NOT_DIRECTORY; + } + + ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/"); + if (ret != NSERROR_OK) { + return ret; + } + } else { + ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/"); + if (ret != NSERROR_OK) { + return ret; + } + } + + /* ensure all elements of path exist (the trailing / is required) */ + ret = netsurf_mkdir_all(config_home); + if (ret != NSERROR_OK) { + free(config_home); + return ret; + } + + /* strip the trailing separator */ + config_home[strlen(config_home) - 1] = 0; + + NSLOG(netsurf, INFO, "\"%s\"", config_home); + + *config_home_out = config_home; + + 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. @@ -250,7 +576,7 @@ static nserror set_defaults(struct nsoption_s *defaults) /* set default items in toolbar */ nsoption_set_charp(toolbar_items, - strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu")); + strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu")); /* set default for menu and tool bar visibility */ nsoption_set_charp(bar_show, strdup("tool")); @@ -258,6 +584,253 @@ static nserror set_defaults(struct nsoption_s *defaults) 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. + * + * @param cache_home_out Path to cache directory. + * @return NSERROR_OK on sucess and \a cache_home_out updated else error code. + */ +static nserror get_cache_home(char **cache_home_out) +{ + nserror ret; + char *xdg_cache_dir; + char *cache_home; + char *home_dir; + + /* $XDG_CACHE_HOME defines the base directory relative to + * which user specific non-essential data files should be + * stored. + */ + xdg_cache_dir = getenv("XDG_CACHE_HOME"); + + if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) { + /* If $XDG_CACHE_HOME is either not set or empty, a + * default equal to $HOME/.cache should be used. + */ + + home_dir = getenv("HOME"); + + /* the HOME envvar is required */ + if (home_dir == NULL) { + return NSERROR_NOT_DIRECTORY; + } + + ret = check_dirname(home_dir, ".cache/netsurf", &cache_home); + if (ret != NSERROR_OK) { + return ret; + } + } else { + ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home); + if (ret != NSERROR_OK) { + return ret; + } + } + + NSLOG(netsurf, INFO, "\"%s\"", cache_home); + + *cache_home_out = cache_home; + return NSERROR_OK; +} + + +/** + * create a cache directory + */ +static nserror create_cache_home(char **cache_home_out) +{ + char *cache_home = NULL; + char *home_dir; + char *xdg_cache_dir; + nserror ret; + + NSLOG(netsurf, INFO, "Attempting to create cache directory"); + + /* $XDG_CACHE_HOME defines the base directory + * relative to which user specific cache files + * should be stored. + */ + xdg_cache_dir = getenv("XDG_CACHE_HOME"); + + if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) { + home_dir = getenv("HOME"); + + if ((home_dir == NULL) || (*home_dir == 0)) { + return NSERROR_NOT_DIRECTORY; + } + + ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/"); + if (ret != NSERROR_OK) { + return ret; + } + } else { + ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/"); + if (ret != NSERROR_OK) { + return ret; + } + } + + /* ensure all elements of path exist (the trailing / is required) */ + ret = netsurf_mkdir_all(cache_home); + if (ret != NSERROR_OK) { + free(cache_home); + return ret; + } + + /* strip the trailing separator */ + cache_home[strlen(cache_home) - 1] = 0; + + NSLOG(netsurf, INFO, "\"%s\"", cache_home); + + *cache_home_out = cache_home; + + return NSERROR_OK; +} + + +/** + * GTK specific initialisation + */ +static nserror nsgtk_init(int *pargc, char ***pargv, char **cache_home) +{ + nserror ret; + + /* Locate the correct user configuration directory path */ + ret = get_config_home(&nsgtk_config_home); + if (ret == NSERROR_NOT_FOUND) { + /* no config directory exists yet so try to create one */ + ret = create_config_home(&nsgtk_config_home); + } + if (ret != NSERROR_OK) { + NSLOG(netsurf, INFO, + "Unable to locate a configuration directory."); + nsgtk_config_home = NULL; + } + + /* Initialise gtk */ + 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, pargc, *pargv); + + /* build the common resource path list */ + respaths = nsgtk_init_resource_path(nsgtk_config_home); + if (respaths == NULL) { + fprintf(stderr, "Unable to locate resources\n"); + return 1; + } + + /* initialise the gtk resource handling */ + ret = nsgtk_init_resources(respaths); + if (ret != NSERROR_OK) { + fprintf(stderr, "GTK resources failed to initialise (%s)\n", + messages_get_errorcode(ret)); + return ret; + } + + /* Initialise user options */ + ret = nsgtk_option_init(pargc, *pargv); + if (ret != NSERROR_OK) { + fprintf(stderr, "Options failed to initialise (%s)\n", + messages_get_errorcode(ret)); + return ret; + } + + /* Initialise translated messages */ + ret = nsgtk_messages_init(respaths); + if (ret != NSERROR_OK) { + fprintf(stderr, "Unable to load translated messages (%s)\n", + messages_get_errorcode(ret)); + 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); + if (ret == NSERROR_NOT_FOUND) { + /* no cache directory exists yet so try to create one */ + ret = create_cache_home(cache_home); + } + if (ret != NSERROR_OK) { + NSLOG(netsurf, INFO, "Unable to locate a cache directory."); + } + + + return NSERROR_OK; +} + + #if GTK_CHECK_VERSION(3,14,0) /** @@ -266,7 +839,7 @@ static nserror set_defaults(struct nsoption_s *defaults) static nserror nsgtk_add_named_icons_to_theme(void) { gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(), - "/org/netsurf/icons"); + "/org/netsurf/icons"); return NSERROR_OK; } @@ -280,7 +853,7 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y) char *resname; int resnamelen; - /* resource name string length allowing for / .png and termination */ + /* resource name string length allowing for / .png and termination */ resnamelen = strlen(prefix) + strlen(name) + 5 + 1 + 4 + 1; resname = malloc(resnamelen); if (resname == NULL) { @@ -299,13 +872,14 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y) 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 + * gtk/res/netsurf.gresource.xml */ add_builtin_icon("", "local-history", 8, 32); add_builtin_icon("", "show-cookie", 24, 24); @@ -327,13 +901,13 @@ static nserror nsgtk_add_named_icons_to_theme(void) /** - * Initialize GTK specific parts of the browser. + * 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_init(int argc, char** argv, char **respath) +static nserror nsgtk_setup(int argc, char** argv, char **respath) { char buf[PATH_MAX]; char *resource_filename; @@ -407,6 +981,11 @@ static nserror nsgtk_init(int argc, char** argv, char **respath) 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); @@ -467,19 +1046,6 @@ static nserror nsgtk_init(int argc, char** argv, char **respath) } - -/** - * 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. * @@ -540,7 +1106,10 @@ static void nsgtk_main(void) } -static void gui_quit(void) +/** + * finalise the browser + */ +static void nsgtk_finalise(void) { nserror res; @@ -592,630 +1161,28 @@ static void gui_quit(void) free(nsgtk_config_home); gtk_fetch_filetype_fin(); -} -static nserror gui_launch_url(struct nsurl *url) -{ - gboolean ok; - GError *error = NULL; - - ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error); - if (ok == TRUE) { - return NSERROR_OK; - } - - if (error) { - nsgtk_warning(messages_get("URIOpenError"), error->message); - g_error_free(error); - } - return NSERROR_NO_FETCH_HANDLER; -} - -/* exported function documented in gtk/warn.h */ -nserror nsgtk_warning(const char *warning, const char *detail) -{ - char buf[300]; /* 300 is the size the RISC OS GUI uses */ - static GtkWindow *nsgtk_warning_window; - GtkLabel *WarningLabel; - - NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : ""); - fflush(stdout); - - nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning")); - WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder, - "labelWarning")); - - snprintf(buf, sizeof(buf), "%s %s", messages_get(warning), - detail ? detail : ""); - buf[sizeof(buf) - 1] = 0; - - gtk_label_set_text(WarningLabel, buf); - - gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window)); - - return NSERROR_OK; -} - - -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)); -} - - -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_KEY(Tab): - return NS_KEY_TAB; - - case GDK_KEY(BackSpace): - if (key->state & GDK_SHIFT_MASK) - return NS_KEY_DELETE_LINE_START; - else - return NS_KEY_DELETE_LEFT; - - case GDK_KEY(Delete): - if (key->state & GDK_SHIFT_MASK) - return NS_KEY_DELETE_LINE_END; - else - return NS_KEY_DELETE_RIGHT; - - case GDK_KEY(Linefeed): - return 13; - - case GDK_KEY(Return): - return 10; - - case GDK_KEY(Left): - case GDK_KEY(KP_Left): - return NS_KEY_LEFT; - - case GDK_KEY(Right): - case GDK_KEY(KP_Right): - return NS_KEY_RIGHT; - - case GDK_KEY(Up): - case GDK_KEY(KP_Up): - return NS_KEY_UP; - - case GDK_KEY(Down): - case GDK_KEY(KP_Down): - return NS_KEY_DOWN; - - case GDK_KEY(Home): - case GDK_KEY(KP_Home): - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_LINE_START; - else - return NS_KEY_TEXT_START; - - case GDK_KEY(End): - case GDK_KEY(KP_End): - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_LINE_END; - else - return NS_KEY_TEXT_END; - - case GDK_KEY(Page_Up): - case GDK_KEY(KP_Page_Up): - return NS_KEY_PAGE_UP; - - case GDK_KEY(Page_Down): - case GDK_KEY(KP_Page_Down): - return NS_KEY_PAGE_DOWN; - - case 'a': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_SELECT_ALL; - return gdk_keyval_to_unicode(key->keyval); - - case 'u': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_DELETE_LINE; - return gdk_keyval_to_unicode(key->keyval); - - case 'c': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_COPY_SELECTION; - return gdk_keyval_to_unicode(key->keyval); - - case 'v': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_PASTE; - return gdk_keyval_to_unicode(key->keyval); - - case 'x': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_CUT_SELECTION; - return gdk_keyval_to_unicode(key->keyval); - - case 'Z': - case 'y': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_REDO; - return gdk_keyval_to_unicode(key->keyval); - - case 'z': - if (key->state & GDK_CONTROL_MASK) - return NS_KEY_UNDO; - return gdk_keyval_to_unicode(key->keyval); - - case GDK_KEY(Escape): - return NS_KEY_ESCAPE; - - /* Modifiers - do nothing for now */ - case GDK_KEY(Shift_L): - case GDK_KEY(Shift_R): - case GDK_KEY(Control_L): - case GDK_KEY(Control_R): - case GDK_KEY(Caps_Lock): - case GDK_KEY(Shift_Lock): - case GDK_KEY(Meta_L): - case GDK_KEY(Meta_R): - case GDK_KEY(Alt_L): - case GDK_KEY(Alt_R): - case GDK_KEY(Super_L): - case GDK_KEY(Super_R): - case GDK_KEY(Hyper_L): - case GDK_KEY(Hyper_R): - return 0; - - } - return gdk_keyval_to_unicode(key->keyval); -} - - -/** - * create directory name and check it is acessible and a directory. - */ -static nserror -check_dirname(const char *path, const char *leaf, char **dirname_out) -{ - nserror ret; - char *dirname = NULL; - struct stat dirname_stat; - - ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf); - if (ret != NSERROR_OK) { - return ret; - } - - /* ensure access is possible and the entry is actualy - * a directory. - */ - if (stat(dirname, &dirname_stat) == 0) { - if (S_ISDIR(dirname_stat.st_mode)) { - if (access(dirname, R_OK | W_OK) == 0) { - *dirname_out = dirname; - return NSERROR_OK; - } else { - ret = NSERROR_PERMISSION; - } - } else { - ret = NSERROR_NOT_DIRECTORY; - } - } else { - ret = NSERROR_NOT_FOUND; - } - - free(dirname); - - return ret; -} - -/** - * Get the path to the config directory. - * - * @param config_home_out Path to configuration directory. - * @return NSERROR_OK on sucess and \a config_home_out updated else error code. - */ -static nserror get_config_home(char **config_home_out) -{ - nserror ret; - char *home_dir; - char *xdg_config_dir; - char *config_home; - - home_dir = getenv("HOME"); - - /* The old $HOME/.netsurf/ directory should be used if it - * exists and is accessible. - */ - if (home_dir != NULL) { - ret = check_dirname(home_dir, ".netsurf", &config_home); - if (ret == NSERROR_OK) { - NSLOG(netsurf, INFO, "\"%s\"", config_home); - *config_home_out = config_home; - return ret; - } - } - - /* $XDG_CONFIG_HOME defines the base directory - * relative to which user specific configuration files - * should be stored. - */ - xdg_config_dir = getenv("XDG_CONFIG_HOME"); - - if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) { - /* If $XDG_CONFIG_HOME is either not set or empty, a - * default equal to $HOME/.config should be used. - */ - - /** @todo the meaning of empty is never defined so I - * am assuming it is a zero length string but is it - * supposed to mean "whitespace" and if so what counts - * as whitespace? (are tabs etc. counted or should - * isspace() be used) - */ - - /* the HOME envvar is required */ - if (home_dir == NULL) { - return NSERROR_NOT_DIRECTORY; - } - - ret = check_dirname(home_dir, ".config/netsurf", &config_home); - if (ret != NSERROR_OK) { - return ret; - } - } else { - ret = check_dirname(xdg_config_dir, "netsurf", &config_home); - if (ret != NSERROR_OK) { - return ret; - } - } - - NSLOG(netsurf, INFO, "\"%s\"", config_home); - - *config_home_out = config_home; - return NSERROR_OK; -} - -static nserror create_config_home(char **config_home_out) -{ - char *config_home = NULL; - char *home_dir; - char *xdg_config_dir; - nserror ret; - - NSLOG(netsurf, INFO, "Attempting to create configuration directory"); - - /* $XDG_CONFIG_HOME defines the base directory - * relative to which user specific configuration files - * should be stored. - */ - xdg_config_dir = getenv("XDG_CONFIG_HOME"); - - if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) { - home_dir = getenv("HOME"); - - if ((home_dir == NULL) || (*home_dir == 0)) { - return NSERROR_NOT_DIRECTORY; - } - - ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/"); - if (ret != NSERROR_OK) { - return ret; - } - } else { - ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/"); - if (ret != NSERROR_OK) { - return ret; - } - } - - /* ensure all elements of path exist (the trailing / is required) */ - ret = netsurf_mkdir_all(config_home); - if (ret != NSERROR_OK) { - free(config_home); - return ret; - } - - /* strip the trailing separator */ - config_home[strlen(config_home) - 1] = 0; - - NSLOG(netsurf, INFO, "\"%s\"", config_home); - - *config_home_out = config_home; - - return NSERROR_OK; -} - -/** - * Get the path to the cache directory. - * - * @param cache_home_out Path to cache directory. - * @return NSERROR_OK on sucess and \a cache_home_out updated else error code. - */ -static nserror get_cache_home(char **cache_home_out) -{ - nserror ret; - char *xdg_cache_dir; - char *cache_home; - char *home_dir; - - /* $XDG_CACHE_HOME defines the base directory relative to - * which user specific non-essential data files should be - * stored. - */ - xdg_cache_dir = getenv("XDG_CACHE_HOME"); - - if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) { - /* If $XDG_CACHE_HOME is either not set or empty, a - * default equal to $HOME/.cache should be used. - */ - - home_dir = getenv("HOME"); - - /* the HOME envvar is required */ - if (home_dir == NULL) { - return NSERROR_NOT_DIRECTORY; - } - - ret = check_dirname(home_dir, ".cache/netsurf", &cache_home); - if (ret != NSERROR_OK) { - return ret; - } - } else { - ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home); - if (ret != NSERROR_OK) { - return ret; - } - } - - NSLOG(netsurf, INFO, "\"%s\"", cache_home); - - *cache_home_out = cache_home; - return NSERROR_OK; -} - -static nserror create_cache_home(char **cache_home_out) -{ - char *cache_home = NULL; - char *home_dir; - char *xdg_cache_dir; - nserror ret; - - NSLOG(netsurf, INFO, "Attempting to create configuration directory"); - - /* $XDG_CACHE_HOME defines the base directory - * relative to which user specific cache files - * should be stored. - */ - xdg_cache_dir = getenv("XDG_CACHE_HOME"); - - if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) { - home_dir = getenv("HOME"); - - if ((home_dir == NULL) || (*home_dir == 0)) { - return NSERROR_NOT_DIRECTORY; - } - - ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/"); - if (ret != NSERROR_OK) { - return ret; - } - } else { - ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/"); - if (ret != NSERROR_OK) { - return ret; - } - } - - /* ensure all elements of path exist (the trailing / is required) */ - ret = netsurf_mkdir_all(cache_home); - if (ret != NSERROR_OK) { - free(cache_home); - return ret; - } - - /* strip the trailing separator */ - cache_home[strlen(cache_home) - 1] = 0; - - NSLOG(netsurf, INFO, "\"%s\"", cache_home); - - *cache_home_out = cache_home; - - 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); + /* common finalisation */ + netsurf_exit(); - /* ensure all options fall within sensible bounds */ + /* finalise options */ + nsoption_finalise(nsoptions, nsoptions_default); - /* 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); - } + /* finalise logging */ + nslog_finalise(); - return NSERROR_OK; } -static struct gui_misc_table nsgtk_misc_table = { - .schedule = nsgtk_schedule, - - .quit = gui_quit, - .launch_url = gui_launch_url, - .pdf_password = nsgtk_pdf_password, - .present_cookies = nsgtk_cookies_present, -}; - - -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. */ int main(int argc, char** argv) { + nserror res; char *cache_home = NULL; - nserror ret; struct netsurf_table nsgtk_table = { - .misc = &nsgtk_misc_table, + .misc = nsgtk_misc_table, .window = nsgtk_window_table, .clipboard = nsgtk_clipboard_table, .download = nsgtk_download_table, @@ -1227,99 +1194,43 @@ int main(int argc, char** argv) .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); - if (ret == NSERROR_NOT_FOUND) { - /* no config directory exists yet so try to create one */ - ret = create_config_home(&nsgtk_config_home); - } - if (ret != NSERROR_OK) { - NSLOG(netsurf, INFO, - "Unable to locate a configuration directory."); - nsgtk_config_home = NULL; - } - - /* Initialise gtk */ - gtk_init(&argc, &argv); - - /* initialise logging. Not fatal if it fails but not much we - * can do about it either. - */ - nslog_init(nslog_stream_configure, &argc, argv); - - /* build the common resource path list */ - respaths = nsgtk_init_resource_path(nsgtk_config_home); - if (respaths == NULL) { - fprintf(stderr, "Unable to locate resources\n"); - return 1; - } - - /* initialise the gtk resource handling */ - ret = nsgtk_init_resources(respaths); - if (ret != NSERROR_OK) { - fprintf(stderr, "GTK resources failed to initialise (%s)\n", - messages_get_errorcode(ret)); - return 1; - } - - /* Initialise user options */ - ret = nsgtk_option_init(&argc, argv); - if (ret != NSERROR_OK) { - fprintf(stderr, "Options failed to initialise (%s)\n", - messages_get_errorcode(ret)); + res = netsurf_register(&nsgtk_table); + if (res != NSERROR_OK) { + fprintf(stderr, + "NetSurf operation table failed registration (%s)\n", + messages_get_errorcode(res)); return 1; } - /* Initialise translated messages */ - ret = nsgtk_messages_init(respaths); - if (ret != NSERROR_OK) { - fprintf(stderr, "Unable to load translated messages (%s)\n", - messages_get_errorcode(ret)); - 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); - if (ret == NSERROR_NOT_FOUND) { - /* no cache directory exists yet so try to create one */ - ret = create_cache_home(&cache_home); - } - if (ret != NSERROR_OK) { - NSLOG(netsurf, INFO, "Unable to locate a cache directory."); + /* 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 */ - ret = netsurf_init(cache_home); + res = netsurf_init(cache_home); free(cache_home); - if (ret != NSERROR_OK) { + if (res != NSERROR_OK) { fprintf(stderr, "NetSurf core failed to initialise (%s)\n", - messages_get_errorcode(ret)); - return 1; + messages_get_errorcode(res)); + return 3; } /* 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)); - } else { - nsgtk_main(); + 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; } - /* common finalisation */ - netsurf_exit(); + nsgtk_main(); - /* finalise options */ - nsoption_finalise(nsoptions, nsoptions_default); - - /* finalise logging */ - nslog_finalise(); + nsgtk_finalise(); return 0; } |