setup project. initial import of uzbl
[uzbl-mobile] / uzbl.c
diff --git a/uzbl.c b/uzbl.c
index 278f3de..1bb5ee2 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -31,7 +31,6 @@
 
 
 #define LENGTH(x) (sizeof x / sizeof x[0])
-#define MAX_BINDINGS 256
 #define _POSIX_SOURCE
 
 #include <gtk/gtk.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <assert.h>
+#include <poll.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <assert.h>
 #include "uzbl.h"
 #include "config.h"
 
@@ -64,123 +68,131 @@ const
 GOptionEntry entries[] =
 {
     { "uri",      'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
-        "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
+        "Uri to load at startup (equivalent to 'uzbl <uri>' or 'set uri = URI' after uzbl has launched)", "URI" },
     { "verbose",  'v', 0, G_OPTION_ARG_NONE,   &uzbl.state.verbose,
         "Whether to print all messages or just errors.", NULL },
-    { "name",     'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, 
+    { "name",     'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
         "Name of the current instance (defaults to Xorg window id)", "NAME" },
-    { "config",   'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   
-        "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
-    { "socket",   's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,   
+    { "config",   'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
+        "Path to config file or '-' for stdin", "FILE" },
+    { "socket",   's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
         "Socket ID", "SOCKET" },
-    { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry, 
+    { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry,
         "Set window geometry (format: WIDTHxHEIGHT+-X+-Y)", "GEOMETRY" },
     { "version",  'V', 0, G_OPTION_ARG_NONE, &uzbl.behave.print_version,
         "Print the version and exit", NULL },
     { NULL,      0, 0, 0, NULL, NULL, NULL }
 };
 
+enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT};
+
 /* associate command names to their properties */
-typedef const struct {
-    /* TODO: Make this ambiguous void **ptr into a union { char *char_p; int *int_p; float *float_p; } val;
-             the PTR() macro is kind of preventing this change at the moment. */
-    void **ptr;
-    int type;
+typedef struct {
+    enum ptr_type type;
+    union {
+        int *i;
+        float *f;
+        gchar **s;
+    } ptr;
     int dump;
     int writeable;
-    void (*func)(void);
+    /*@null@*/ void (*func)(void);
 } uzbl_cmdprop;
 
-enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
-
 /* abbreviations to help keep the table's width humane */
-#define PTR_V(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .writeable = 1, .func = fun }
-#define PTR_C(var, t,    fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = 0, .writeable = 0, .func = fun }
-
-const struct {
-    char *name;
+#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
+#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
+#define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun }
+#define PTR_C_STR(var,    fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun }
+#define PTR_C_INT(var,    fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun }
+#define PTR_C_FLOAT(var,  fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun }
+
+const struct var_name_to_ptr_t {
+    const char *name;
     uzbl_cmdprop cp;
 } var_name_to_ptr[] = {
-/*    variable name         pointer to variable in code            type  dump callback function    */
+/*    variable name            pointer to variable in code                     dump callback function    */
 /*  ---------------------------------------------------------------------------------------------- */
-    { "uri",                 PTR_V(uzbl.state.uri,                  STR,  1,   cmd_load_uri)},
-    { "verbose",             PTR_V(uzbl.state.verbose,              INT,  1,   NULL)},
-    { "mode",                PTR_V(uzbl.behave.mode,                INT,  0,   NULL)},
-    { "inject_html",         PTR_V(uzbl.behave.inject_html,         STR,  0,   cmd_inject_html)},
-    { "base_url",            PTR_V(uzbl.behave.base_url,            STR,  1,   NULL)},
-    { "html_endmarker",      PTR_V(uzbl.behave.html_endmarker,      STR,  1,   NULL)},
-    { "html_mode_timeout",   PTR_V(uzbl.behave.html_timeout,        INT,  1,   NULL)},
-    { "keycmd",              PTR_V(uzbl.state.keycmd,               STR,  1,   set_keycmd)},
-    { "status_message",      PTR_V(uzbl.gui.sbar.msg,               STR,  1,   update_title)},
-    { "show_status",         PTR_V(uzbl.behave.show_status,         INT,  1,   cmd_set_status)},
-    { "status_top",          PTR_V(uzbl.behave.status_top,          INT,  1,   move_statusbar)},
-    { "status_format",       PTR_V(uzbl.behave.status_format,       STR,  1,   update_title)},
-    { "status_pbar_done",    PTR_V(uzbl.gui.sbar.progress_s,        STR,  1,   update_title)},
-    { "status_pbar_pending", PTR_V(uzbl.gui.sbar.progress_u,        STR,  1,   update_title)},
-    { "status_pbar_width",   PTR_V(uzbl.gui.sbar.progress_w,        INT,  1,   update_title)},
-    { "status_background",   PTR_V(uzbl.behave.status_background,   STR,  1,   update_title)},
-    { "insert_indicator",    PTR_V(uzbl.behave.insert_indicator,    STR,  1,   update_title)},
-    { "command_indicator",   PTR_V(uzbl.behave.cmd_indicator,       STR,  1,   update_title)},
-    { "title_format_long",   PTR_V(uzbl.behave.title_format_long,   STR,  1,   update_title)},
-    { "title_format_short",  PTR_V(uzbl.behave.title_format_short,  STR,  1,   update_title)},
-    { "icon",                PTR_V(uzbl.gui.icon,                   STR,  1,   set_icon)},
-    { "insert_mode",         PTR_V(uzbl.behave.insert_mode,         INT,  1,   set_mode_indicator)},
-    { "always_insert_mode",  PTR_V(uzbl.behave.always_insert_mode,  INT,  1,   cmd_always_insert_mode)},
-    { "reset_command_mode",  PTR_V(uzbl.behave.reset_command_mode,  INT,  1,   NULL)},
-    { "modkey",              PTR_V(uzbl.behave.modkey,              STR,  1,   cmd_modkey)},
-    { "load_finish_handler", PTR_V(uzbl.behave.load_finish_handler, STR,  1,   NULL)},
-    { "load_start_handler",  PTR_V(uzbl.behave.load_start_handler,  STR,  1,   NULL)},
-    { "load_commit_handler", PTR_V(uzbl.behave.load_commit_handler, STR,  1,   NULL)},
-    { "history_handler",     PTR_V(uzbl.behave.history_handler,     STR,  1,   NULL)},
-    { "download_handler",    PTR_V(uzbl.behave.download_handler,    STR,  1,   NULL)},
-    { "cookie_handler",      PTR_V(uzbl.behave.cookie_handler,      STR,  1,   cmd_cookie_handler)},
-    { "new_window",          PTR_V(uzbl.behave.new_window,          STR,  1,   cmd_new_window)},
-    { "fifo_dir",            PTR_V(uzbl.behave.fifo_dir,            STR,  1,   cmd_fifo_dir)},
-    { "socket_dir",          PTR_V(uzbl.behave.socket_dir,          STR,  1,   cmd_socket_dir)},
-    { "http_debug",          PTR_V(uzbl.behave.http_debug,          INT,  1,   cmd_http_debug)},
-    { "shell_cmd",           PTR_V(uzbl.behave.shell_cmd,           STR,  1,   NULL)},
-    { "proxy_url",           PTR_V(uzbl.net.proxy_url,              STR,  1,   set_proxy_url)},
-    { "max_conns",           PTR_V(uzbl.net.max_conns,              INT,  1,   cmd_max_conns)},
-    { "max_conns_host",      PTR_V(uzbl.net.max_conns_host,         INT,  1,   cmd_max_conns_host)},
-    { "useragent",           PTR_V(uzbl.net.useragent,              STR,  1,   cmd_useragent)},
+    { "uri",                    PTR_V_STR(uzbl.state.uri,                       1,   cmd_load_uri)},
+    { "verbose",                PTR_V_INT(uzbl.state.verbose,                   1,   NULL)},
+    { "inject_html",            PTR_V_STR(uzbl.behave.inject_html,              0,   cmd_inject_html)},
+    { "keycmd",                 PTR_V_STR(uzbl.state.keycmd,                    1,   set_keycmd)},
+    { "status_message",         PTR_V_STR(uzbl.gui.sbar.msg,                    1,   update_title)},
+    { "show_status",            PTR_V_INT(uzbl.behave.show_status,              1,   cmd_set_status)},
+    { "status_top",             PTR_V_INT(uzbl.behave.status_top,               1,   move_statusbar)},
+    { "status_format",          PTR_V_STR(uzbl.behave.status_format,            1,   update_title)},
+    { "status_pbar_done",       PTR_V_STR(uzbl.gui.sbar.progress_s,             1,   update_title)},
+    { "status_pbar_pending",    PTR_V_STR(uzbl.gui.sbar.progress_u,             1,   update_title)},
+    { "status_pbar_width",      PTR_V_INT(uzbl.gui.sbar.progress_w,             1,   update_title)},
+    { "status_background",      PTR_V_STR(uzbl.behave.status_background,        1,   update_title)},
+    { "insert_indicator",       PTR_V_STR(uzbl.behave.insert_indicator,         1,   update_indicator)},
+    { "command_indicator",      PTR_V_STR(uzbl.behave.cmd_indicator,            1,   update_indicator)},
+    { "title_format_long",      PTR_V_STR(uzbl.behave.title_format_long,        1,   update_title)},
+    { "title_format_short",     PTR_V_STR(uzbl.behave.title_format_short,       1,   update_title)},
+    { "icon",                   PTR_V_STR(uzbl.gui.icon,                        1,   set_icon)},
+    { "insert_mode",            PTR_V_INT(uzbl.behave.insert_mode,              1,   set_mode_indicator)},
+    { "always_insert_mode",     PTR_V_INT(uzbl.behave.always_insert_mode,       1,   cmd_always_insert_mode)},
+    { "reset_command_mode",     PTR_V_INT(uzbl.behave.reset_command_mode,       1,   NULL)},
+    { "modkey",                 PTR_V_STR(uzbl.behave.modkey,                   1,   cmd_modkey)},
+    { "load_finish_handler",    PTR_V_STR(uzbl.behave.load_finish_handler,      1,   NULL)},
+    { "load_start_handler",     PTR_V_STR(uzbl.behave.load_start_handler,       1,   NULL)},
+    { "load_commit_handler",    PTR_V_STR(uzbl.behave.load_commit_handler,      1,   NULL)},
+    { "download_handler",       PTR_V_STR(uzbl.behave.download_handler,         1,   NULL)},
+    { "cookie_handler",         PTR_V_STR(uzbl.behave.cookie_handler,           1,   cmd_cookie_handler)},
+    { "new_window",             PTR_V_STR(uzbl.behave.new_window,               1,   NULL)},
+    { "scheme_handler",         PTR_V_STR(uzbl.behave.scheme_handler,           1,   cmd_scheme_handler)},
+    { "fifo_dir",               PTR_V_STR(uzbl.behave.fifo_dir,                 1,   cmd_fifo_dir)},
+    { "socket_dir",             PTR_V_STR(uzbl.behave.socket_dir,               1,   cmd_socket_dir)},
+    { "http_debug",             PTR_V_INT(uzbl.behave.http_debug,               1,   cmd_http_debug)},
+    { "shell_cmd",              PTR_V_STR(uzbl.behave.shell_cmd,                1,   NULL)},
+    { "proxy_url",              PTR_V_STR(uzbl.net.proxy_url,                   1,   set_proxy_url)},
+    { "max_conns",              PTR_V_INT(uzbl.net.max_conns,                   1,   cmd_max_conns)},
+    { "max_conns_host",         PTR_V_INT(uzbl.net.max_conns_host,              1,   cmd_max_conns_host)},
+    { "useragent",              PTR_V_STR(uzbl.net.useragent,                   1,   cmd_useragent)},
 
     /* exported WebKitWebSettings properties */
-    { "zoom_level",          PTR_V(uzbl.behave.zoom_level,          FLOAT,1,   cmd_zoom_level)},
-    { "font_size",           PTR_V(uzbl.behave.font_size,           INT,  1,   cmd_font_size)},
-    { "monospace_size",      PTR_V(uzbl.behave.monospace_size,      INT,  1,   cmd_font_size)},
-    { "minimum_font_size",   PTR_V(uzbl.behave.minimum_font_size,   INT,  1,   cmd_minimum_font_size)},
-    { "disable_plugins",     PTR_V(uzbl.behave.disable_plugins,     INT,  1,   cmd_disable_plugins)},
-    { "disable_scripts",     PTR_V(uzbl.behave.disable_scripts,     INT,  1,   cmd_disable_scripts)},
-    { "autoload_images",     PTR_V(uzbl.behave.autoload_img,        INT,  1,   cmd_autoload_img)},
-    { "autoshrink_images",   PTR_V(uzbl.behave.autoshrink_img,      INT,  1,   cmd_autoshrink_img)},
-    { "enable_spellcheck",   PTR_V(uzbl.behave.enable_spellcheck,   INT,  1,   cmd_enable_spellcheck)},
-    { "enable_private",      PTR_V(uzbl.behave.enable_private,      INT,  1,   cmd_enable_private)},
-    { "print_backgrounds",   PTR_V(uzbl.behave.print_bg,            INT,  1,   cmd_print_bg)},
-    { "stylesheet_uri",      PTR_V(uzbl.behave.style_uri,           STR,  1,   cmd_style_uri)},
-    { "resizable_text_areas",PTR_V(uzbl.behave.resizable_txt,       INT,  1,   cmd_resizable_txt)},
-    { "default_encoding",    PTR_V(uzbl.behave.default_encoding,    STR,  1,   cmd_default_encoding)},
-    { "enforce_96_dpi",      PTR_V(uzbl.behave.enforce_96dpi,       INT,  1,   cmd_enforce_96dpi)},
-    { "caret_browsing",      PTR_V(uzbl.behave.caret_browsing,      INT,  1,   cmd_caret_browsing)},
+    { "zoom_level",             PTR_V_FLOAT(uzbl.behave.zoom_level,             1,   cmd_zoom_level)},
+    { "font_size",              PTR_V_INT(uzbl.behave.font_size,                1,   cmd_font_size)},
+    { "default_font_family",    PTR_V_STR(uzbl.behave.default_font_family,      1,   cmd_default_font_family)},
+    { "monospace_font_family",  PTR_V_STR(uzbl.behave.monospace_font_family,    1,   cmd_monospace_font_family)},
+    { "cursive_font_family",    PTR_V_STR(uzbl.behave.cursive_font_family,      1,   cmd_cursive_font_family)},
+    { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family,   1,   cmd_sans_serif_font_family)},
+    { "serif_font_family",      PTR_V_STR(uzbl.behave.serif_font_family,        1,   cmd_serif_font_family)},
+    { "fantasy_font_family",    PTR_V_STR(uzbl.behave.fantasy_font_family,      1,   cmd_fantasy_font_family)},
+    { "monospace_size",         PTR_V_INT(uzbl.behave.monospace_size,           1,   cmd_font_size)},
+    { "minimum_font_size",      PTR_V_INT(uzbl.behave.minimum_font_size,        1,   cmd_minimum_font_size)},
+    { "disable_plugins",        PTR_V_INT(uzbl.behave.disable_plugins,          1,   cmd_disable_plugins)},
+    { "disable_scripts",        PTR_V_INT(uzbl.behave.disable_scripts,          1,   cmd_disable_scripts)},
+    { "autoload_images",        PTR_V_INT(uzbl.behave.autoload_img,             1,   cmd_autoload_img)},
+    { "autoshrink_images",      PTR_V_INT(uzbl.behave.autoshrink_img,           1,   cmd_autoshrink_img)},
+    { "enable_spellcheck",      PTR_V_INT(uzbl.behave.enable_spellcheck,        1,   cmd_enable_spellcheck)},
+    { "enable_private",         PTR_V_INT(uzbl.behave.enable_private,           1,   cmd_enable_private)},
+    { "print_backgrounds",      PTR_V_INT(uzbl.behave.print_bg,                 1,   cmd_print_bg)},
+    { "stylesheet_uri",         PTR_V_STR(uzbl.behave.style_uri,                1,   cmd_style_uri)},
+    { "resizable_text_areas",   PTR_V_INT(uzbl.behave.resizable_txt,            1,   cmd_resizable_txt)},
+    { "default_encoding",       PTR_V_STR(uzbl.behave.default_encoding,         1,   cmd_default_encoding)},
+    { "enforce_96_dpi",         PTR_V_INT(uzbl.behave.enforce_96dpi,            1,   cmd_enforce_96dpi)},
+    { "caret_browsing",         PTR_V_INT(uzbl.behave.caret_browsing,           1,   cmd_caret_browsing)},
 
   /* constants (not dumpable or writeable) */
-    { "WEBKIT_MAJOR",        PTR_C(uzbl.info.webkit_major,          INT,       NULL)},
-    { "WEBKIT_MINOR",        PTR_C(uzbl.info.webkit_minor,          INT,       NULL)},
-    { "WEBKIT_MICRO",        PTR_C(uzbl.info.webkit_micro,          INT,       NULL)},
-    { "ARCH_UZBL",           PTR_C(uzbl.info.arch,                  STR,       NULL)},
-    { "COMMIT",              PTR_C(uzbl.info.commit,                STR,       NULL)},
-    { "LOAD_PROGRESS",       PTR_C(uzbl.gui.sbar.load_progress,     INT,       NULL)},
-    { "LOAD_PROGRESSBAR",    PTR_C(uzbl.gui.sbar.progress_bar,      STR,       NULL)},
-    { "TITLE",               PTR_C(uzbl.gui.main_title,             STR,       NULL)},
-    { "SELECTED_URI",        PTR_C(uzbl.state.selected_url,         STR,       NULL)},
-    { "MODE",                PTR_C(uzbl.gui.sbar.mode_indicator,    STR,       NULL)},
-    { "NAME",                PTR_C(uzbl.state.instance_name,        STR,       NULL)},
-
-    { NULL,                  {.ptr = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
-}, *n2v_p = var_name_to_ptr;
+    { "WEBKIT_MAJOR",           PTR_C_INT(uzbl.info.webkit_major,                    NULL)},
+    { "WEBKIT_MINOR",           PTR_C_INT(uzbl.info.webkit_minor,                    NULL)},
+    { "WEBKIT_MICRO",           PTR_C_INT(uzbl.info.webkit_micro,                    NULL)},
+    { "ARCH_UZBL",              PTR_C_STR(uzbl.info.arch,                            NULL)},
+    { "COMMIT",                 PTR_C_STR(uzbl.info.commit,                          NULL)},
+    { "LOAD_PROGRESS",          PTR_C_INT(uzbl.gui.sbar.load_progress,               NULL)},
+    { "LOAD_PROGRESSBAR",       PTR_C_STR(uzbl.gui.sbar.progress_bar,                NULL)},
+    { "TITLE",                  PTR_C_STR(uzbl.gui.main_title,                       NULL)},
+    { "SELECTED_URI",           PTR_C_STR(uzbl.state.selected_url,                   NULL)},
+    { "MODE",                   PTR_C_STR(uzbl.gui.sbar.mode_indicator,              NULL)},
+    { "NAME",                   PTR_C_STR(uzbl.state.instance_name,                  NULL)},
+
+    { NULL,                     {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
+};
 
 
 const struct {
-    char *key;
+    /*@null@*/ char *key;
     guint mask;
 } modkeys[] = {
     { "SHIFT",   GDK_SHIFT_MASK   }, // shift
@@ -206,17 +218,20 @@ const struct {
 /* construct a hash from the var_name_to_ptr array for quick access */
 void
 make_var_to_name_hash() {
+    const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
     uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
     while(n2v_p->name) {
-        g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
+        g_hash_table_insert(uzbl.comm.proto_var,
+                (gpointer) n2v_p->name,
+                (gpointer) &n2v_p->cp);
         n2v_p++;
     }
 }
 
 /* --- UTILITY FUNCTIONS --- */
-enum {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
-guint
-get_exp_type(gchar *s) {
+enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
+enum exp_type
+get_exp_type(const gchar *s) {
     /* variables */
     if(*(s+1) == '(')
         return EXP_EXPR;
@@ -229,6 +244,7 @@ get_exp_type(gchar *s) {
     else
         return EXP_SIMPLE_VAR;
 
+    /*@notreached@*/
 return EXP_ERR;
 }
 
@@ -237,13 +253,11 @@ return EXP_ERR;
  * recurse == 2: don't expand '@<java script>@'
  */
 gchar *
-expand(char *s, guint recurse) {
+expand(const char *s, guint recurse) {
     uzbl_cmdprop *c;
-    guint etype;
-    char upto = ' ';
+    enum exp_type etype;
     char *end_simple_var = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½";
-    char str_end[2];
-    char ret[4096];
+    char *ret = NULL;
     char *vend = NULL;
     GError *err = NULL;
     gchar *cmd_stdout = NULL;
@@ -268,48 +282,44 @@ expand(char *s, guint recurse) {
                         if(!vend) vend = strchr(s, '\0');
                         break;
                     case EXP_BRACED_VAR:
-                        s++; upto = '}';
-                        vend = strchr(s, upto);
+                        s++;
+                        vend = strchr(s, '}');
                         if(!vend) vend = strchr(s, '\0');
                         break;
                     case EXP_EXPR:
                         s++;
-                        strcpy(str_end, ")@");
-                        str_end[2] = '\0';
-                        vend = strstr(s, str_end);
+                        vend = strstr(s, ")@");
                         if(!vend) vend = strchr(s, '\0');
                         break;
                     case EXP_JS:
                         s++;
-                        strcpy(str_end, ">@");
-                        str_end[2] = '\0';
-                        vend = strstr(s, str_end);
+                        vend = strstr(s, ">@");
                         if(!vend) vend = strchr(s, '\0');
                         break;
                     case EXP_ESCAPE:
                         s++;
-                        strcpy(str_end, "]@");
-                        str_end[2] = '\0';
-                        vend = strstr(s, str_end);
+                        vend = strstr(s, "]@");
                         if(!vend) vend = strchr(s, '\0');
                         break;
+                    /*@notreached@*/
+                    case EXP_ERR:
+                        break;
                 }
+                assert(vend);
 
-                if(vend) {
-                    strncpy(ret, s, vend-s);
-                    ret[vend-s] = '\0';
-                }
+                ret = g_strndup(s, vend-s);
 
                 if(etype == EXP_SIMPLE_VAR ||
                    etype == EXP_BRACED_VAR) {
                     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
-                        if(c->type == TYPE_STR && *c->ptr != NULL) {
-                            g_string_append(buf, (gchar *)*c->ptr);
-                        } else if(c->type == TYPE_INT) {
-                            g_string_append_printf(buf, "%d", (int)*c->ptr);
+                        if(c->type == TYPE_STR && *c->ptr.s != NULL) {
+                            g_string_append(buf, (gchar *)*c->ptr.s);
+                        }
+                        else if(c->type == TYPE_INT) {
+                            g_string_append_printf(buf, "%d", *c->ptr.i);
                         }
                         else if(c->type == TYPE_FLOAT) {
-                            g_string_append_printf(buf, "%f", *(float *)c->ptr);
+                            g_string_append_printf(buf, "%f", *c->ptr.f);
                         }
                     }
 
@@ -329,10 +339,10 @@ expand(char *s, guint recurse) {
                         g_error_free (err);
                     }
                     else if (*cmd_stdout) {
-                        int len = strlen(cmd_stdout);
+                        size_t len = strlen(cmd_stdout);
 
-                        if(cmd_stdout[len-1] == '\n')
-                            cmd_stdout[--len] = 0; /* strip trailing newline */
+                        if(len > 0 && cmd_stdout[len-1] == '\n')
+                            cmd_stdout[--len] = '\0'; /* strip trailing newline */
 
                         g_string_append(buf, cmd_stdout);
                         g_free(cmd_stdout);
@@ -362,6 +372,9 @@ expand(char *s, guint recurse) {
                     g_free(mycmd);
                     s = vend+2;
                 }
+
+                g_free(ret);
+                ret = NULL;
                 break;
 
             default:
@@ -401,7 +414,7 @@ str_replace (const char* search, const char* replace, const char* string) {
 }
 
 GArray*
-read_file_by_line (gchar *path) {
+read_file_by_line (const gchar *path) {
     GIOChannel *chan = NULL;
     gchar *readbuf = NULL;
     gsize len;
@@ -477,21 +490,6 @@ clean_up(void) {
     g_free(uzbl.state.keycmd);
     g_hash_table_destroy(uzbl.bindings);
     g_hash_table_destroy(uzbl.behave.commands);
-    g_scanner_destroy(uzbl.scan);
-}
-
-/* used for html_mode_timeout
- * be sure to extend this function to use
- * more timers if needed in other places
-*/
-void
-set_timeout(int seconds) {
-    struct itimerval t;
-    memset(&t, 0, sizeof t);
-
-    t.it_value.tv_sec =  seconds;
-    t.it_value.tv_usec = 0;
-    setitimer(ITIMER_REAL, &t, NULL);
 }
 
 /* --- SIGNAL HANDLER --- */
@@ -509,16 +507,45 @@ catch_sigint(int s) {
     exit(EXIT_SUCCESS);
 }
 
-void
-catch_alrm(int s) {
-    (void) s;
+/* --- CALLBACKS --- */
 
-    set_var_value("mode", "0");
-    render_html();
-}
+gboolean
+navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
+    (void) web_view;
+    (void) frame;
+    (void) navigation_action;
+    (void) user_data;
+
+    const gchar* uri = webkit_network_request_get_uri (request);
+    gboolean decision_made = FALSE;
 
+    if (uzbl.state.verbose)
+        printf("Navigation requested -> %s\n", uri);
 
-/* --- CALLBACKS --- */
+    if (uzbl.behave.scheme_handler) {
+        GString *s = g_string_new ("");
+        g_string_printf(s, "'%s'", uri);
+
+        run_handler(uzbl.behave.scheme_handler, s->str);
+
+        if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
+            char *p = strchr(uzbl.comm.sync_stdout, '\n' );
+            if ( p != NULL ) *p = '\0';
+            if (!strcmp(uzbl.comm.sync_stdout, "USED")) {
+                webkit_web_policy_decision_ignore(policy_decision);
+                decision_made = TRUE;
+            }
+        }
+        if (uzbl.comm.sync_stdout)
+            uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+
+        g_string_free(s, TRUE);
+    }
+    if (!decision_made)
+        webkit_web_policy_decision_use(policy_decision);
+
+    return TRUE;
+}
 
 gboolean
 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
@@ -551,7 +578,7 @@ mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequ
     return TRUE;
 }
 
-WebKitWebView*
+/*@null@*/ WebKitWebView*
 create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer user_data) {
     (void) web_view;
     (void) frame;
@@ -576,7 +603,17 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
         if (uzbl.state.verbose)
             printf("Download -> %s\n",uri);
         /* if urls not escaped, we may have to escape and quote uri before this call */
-        run_handler(uzbl.behave.download_handler, uri);
+
+        GString *args = g_string_new(uri);
+
+        if (uzbl.net.proxy_url) {
+           g_string_append_c(args, ' ');
+           g_string_append(args, uzbl.net.proxy_url);
+        }
+
+        run_handler(uzbl.behave.download_handler, args->str);
+
+        g_string_free(args, TRUE);
     }
     return (FALSE);
 }
@@ -635,12 +672,12 @@ cmd_set_geometry() {
         if(uzbl.state.verbose)
             printf("Error in geometry string: %s\n", uzbl.gui.geometry);
     }
-    /* update geometry var with the actual geometry 
+    /* update geometry var with the actual geometry
        this is necessary as some WMs don't seem to honour
        the above setting and we don't want to end up with
        wrong geometry information
     */
-    retreive_geometry();
+    retrieve_geometry();
 }
 
 void
@@ -734,7 +771,6 @@ load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
     (void) frame;
     (void) data;
     uzbl.gui.sbar.load_progress = 0;
-    clear_keycmd(); // don't need old commands to remain on new page?
     if (uzbl.behave.load_start_handler)
         run_handler(uzbl.behave.load_start_handler, "");
 }
@@ -761,19 +797,6 @@ destroy_cb (GtkWidget* widget, gpointer data) {
     gtk_main_quit ();
 }
 
-void
-log_history_cb () {
-   if (uzbl.behave.history_handler) {
-       time_t rawtime;
-       struct tm * timeinfo;
-       char date [80];
-       time ( &rawtime );
-       timeinfo = localtime ( &rawtime );
-       strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
-       run_handler(uzbl.behave.history_handler, date);
-   }
-}
-
 
 /* VIEW funcs (little webkit wrappers) */
 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
@@ -787,7 +810,7 @@ VIEWFUNC(go_forward)
 #undef VIEWFUNC
 
 /* -- command to callback/function map for things we cannot attach to any signals */
-struct {char *key; CommandInfo value;} cmdlist[] =
+struct {const char *key; CommandInfo value;} cmdlist[] =
 {   /* key                   function      no_split      */
     { "back",               {view_go_back, 0}              },
     { "forward",            {view_go_forward, 0}           },
@@ -809,6 +832,7 @@ struct {char *key; CommandInfo value;} cmdlist[] =
     { "sync_spawn",         {spawn_sync, 0}                }, // needed for cookie handler
     { "sh",                 {spawn_sh, 0}                  },
     { "sync_sh",            {spawn_sh_sync, 0}             }, // needed for cookie handler
+    { "talk_to_socket",     {talk_to_socket, 0}            },
     { "exit",               {close_uzbl, 0}                },
     { "search",             {search_forward_text, TRUE}    },
     { "search_reverse",     {search_reverse_text, TRUE}    },
@@ -822,7 +846,8 @@ struct {char *key; CommandInfo value;} cmdlist[] =
     { "keycmd_nl",          {keycmd_nl, TRUE}              },
     { "keycmd_bs",          {keycmd_bs, 0}                 },
     { "chain",              {chain, 0}                     },
-    { "print",              {print, TRUE}                  }
+    { "print",              {print, TRUE}                  },
+    { "update_gui",         {update_gui, TRUE}           }
 };
 
 void
@@ -832,7 +857,7 @@ commands_hash(void)
     uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
 
     for (i = 0; i < LENGTH(cmdlist); i++)
-        g_hash_table_insert(uzbl.behave.commands, cmdlist[i].key, &cmdlist[i].value);
+        g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
 }
 
 /* -- CORE FUNCTIONS -- */
@@ -877,6 +902,13 @@ set_var(WebKitWebView *page, GArray *argv, GString *result) {
 }
 
 void
+update_gui(WebKitWebView *page, GArray *argv, GString *result) {
+    (void) page; (void) argv; (void) result;
+
+    update_title();
+}
+
+void
 print(WebKitWebView *page, GArray *argv, GString *result) {
     (void) page; (void) result;
     gchar* buf;
@@ -915,6 +947,12 @@ set_mode_indicator() {
 }
 
 void
+update_indicator() {
+  set_mode_indicator();
+  update_title();
+}
+
+void
 set_insert_mode(gboolean mode) {
     uzbl.behave.insert_mode = mode;
     set_mode_indicator();
@@ -947,7 +985,7 @@ load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
             run_js(web_view, argv, NULL);
             return;
         }
-        if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
+        if (!soup_uri_new(argv_idx(argv, 0)))
             g_string_prepend (newuri, "http://");
         /* if we do handle cookies, ask our handler for them */
         webkit_web_view_load_uri (web_view, newuri->str);
@@ -1291,7 +1329,7 @@ run_command (const gchar *command, const guint npre, const gchar **args,
     return result;
 }
 
-gchar**
+/*@null@*/ gchar**
 split_quoted(const gchar* src, const gboolean unquote) {
     /* split on unquoted space, return array of strings;
        remove a layer of quotes and backslashes if unquote */
@@ -1389,6 +1427,118 @@ spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
 }
 
 void
+talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
+    (void)web_view; (void)result;
+
+    int fd, len;
+    struct sockaddr_un sa;
+    char* sockpath;
+    ssize_t ret;
+    struct pollfd pfd;
+    struct iovec* iov;
+    guint i;
+
+    if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+
+    /* This function could be optimised by storing a hash table of socket paths
+       and associated connected file descriptors rather than closing and
+       re-opening for every call. Also we could launch a script if socket connect
+       fails. */
+
+    /* First element argv[0] is path to socket. Following elements are tokens to
+       write to the socket. We write them as a single packet with each token
+       separated by an ASCII nul (\0). */
+    if(argv->len < 2) {
+        g_printerr("talk_to_socket called with only %d args (need at least two).\n",
+            (int)argv->len);
+        return;
+    }
+
+    /* copy socket path, null terminate result */
+    sockpath = g_array_index(argv, char*, 0);
+    g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
+    sa.sun_family = AF_UNIX;
+
+    /* create socket file descriptor and connect it to path */
+    fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+    if(fd == -1) {
+        g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
+        return;
+    }
+    if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
+        g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
+        close(fd);
+        return;
+    }
+
+    /* build request vector */
+    iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
+    if(!iov) {
+        g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
+        close(fd);
+        return;
+    }
+    for(i = 1; i < argv->len; ++i) {
+        iov[i - 1].iov_base = g_array_index(argv, char*, i);
+        iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
+    }
+
+    /* write request */
+    ret = writev(fd, iov, argv->len - 1);
+    g_free(iov);
+    if(ret == -1) {
+        g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
+        close(fd);
+        return;
+    }
+
+    /* wait for a response, with a 500ms timeout */
+    pfd.fd = fd;
+    pfd.events = POLLIN;
+    while(1) {
+        ret = poll(&pfd, 1, 500);
+        if(ret == 1) break;
+        if(ret == 0) errno = ETIMEDOUT;
+        if(errno == EINTR) continue;
+        g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
+            strerror(errno));
+        close(fd);
+        return;
+    }
+
+    /* get length of response */
+    if(ioctl(fd, FIONREAD, &len) == -1) {
+        g_printerr("talk_to_socket: cannot find daemon response length, "
+            "ioctl failed (%s)\n", strerror(errno));
+        close(fd);
+        return;
+    }
+
+    /* if there is a response, read it */
+    if(len) {
+        uzbl.comm.sync_stdout = g_malloc(len + 1);
+        if(!uzbl.comm.sync_stdout) {
+            g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
+            close(fd);
+            return;
+        }
+        uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
+
+        ret = read(fd, uzbl.comm.sync_stdout, len);
+        if(ret == -1) {
+            g_printerr("talk_to_socket: failed to read from socket (%s)\n",
+                strerror(errno));
+            close(fd);
+            return;
+        }
+    }
+
+    /* clean up */
+    close(fd);
+    return;
+}
+
+void
 parse_command(const char *cmd, const char *param, GString *result) {
     CommandInfo *c;
 
@@ -1409,7 +1559,7 @@ parse_command(const char *cmd, const char *param, GString *result) {
 
                 c->function(uzbl.gui.web_view, a, result_print);
                 if (result_print->len)
-                    printf("%*s\n", result_print->len, result_print->str);
+                    printf("%*s\n", (int)result_print->len, result_print->str);
 
                 g_string_free(result_print, TRUE);
             } else {
@@ -1426,8 +1576,7 @@ void
 set_proxy_url() {
     SoupURI *suri;
 
-    if(*uzbl.net.proxy_url == ' '
-       || uzbl.net.proxy_url == NULL) {
+    if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
         soup_session_remove_feature_by_type(uzbl.net.soup_session,
                 (GType) SOUP_SESSION_PROXY_URI);
     }
@@ -1511,6 +1660,42 @@ cmd_font_size() {
 }
 
 void
+cmd_default_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "default-font-family",
+            uzbl.behave.default_font_family, NULL);
+}
+
+void
+cmd_monospace_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
+            uzbl.behave.monospace_font_family, NULL);
+}
+
+void
+cmd_sans_serif_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
+            uzbl.behave.sans_serif_font_family, NULL);
+}
+
+void
+cmd_serif_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "serif-font-family",
+            uzbl.behave.serif_font_family, NULL);
+}
+
+void
+cmd_cursive_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
+            uzbl.behave.cursive_font_family, NULL);
+}
+
+void
+cmd_fantasy_font_family() {
+    g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
+            uzbl.behave.fantasy_font_family, NULL);
+}
+
+void
 cmd_zoom_level() {
     webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
 }
@@ -1608,14 +1793,14 @@ cmd_cookie_handler() {
 }
 
 void
-cmd_new_window() {
-    gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
+cmd_scheme_handler() {
+    gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2);
     /* pitfall: doesn't handle chain actions; must the sync_ action manually */
     if ((g_strcmp0(split[0], "sh") == 0) ||
         (g_strcmp0(split[0], "spawn") == 0)) {
-        g_free (uzbl.behave.new_window);
-        uzbl.behave.new_window =
-            g_strdup_printf("%s %s", split[0], split[1]);
+        g_free (uzbl.behave.scheme_handler);
+        uzbl.behave.scheme_handler =
+            g_strdup_printf("sync_%s %s", split[0], split[1]);
     }
     g_strfreev (split);
 }
@@ -1669,6 +1854,10 @@ cmd_useragent() {
 
 void
 move_statusbar() {
+    if (!uzbl.gui.scrolled_win &&
+            !uzbl.gui.mainbar)
+        return;
+
     gtk_widget_ref(uzbl.gui.scrolled_win);
     gtk_widget_ref(uzbl.gui.mainbar);
     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
@@ -1689,71 +1878,61 @@ move_statusbar() {
 }
 
 gboolean
-set_var_value(gchar *name, gchar *val) {
+set_var_value(const gchar *name, gchar *val) {
     uzbl_cmdprop *c = NULL;
     char *endp = NULL;
     char *buf = NULL;
+    char *invalid_chars = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½";
 
     if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
-        if(!c->writeable) return TRUE;
+        if(!c->writeable) return FALSE;
 
         /* check for the variable type */
         if (c->type == TYPE_STR) {
             buf = expand(val, 0);
-            g_free(*c->ptr);
-            *c->ptr = buf;
+            g_free(*c->ptr.s);
+            *c->ptr.s = buf;
         } else if(c->type == TYPE_INT) {
-            int *ip = (int *)c->ptr;
             buf = expand(val, 0);
-            *ip = (int)strtoul(buf, &endp, 10);
+            *c->ptr.i = (int)strtoul(buf, &endp, 10);
             g_free(buf);
         } else if (c->type == TYPE_FLOAT) {
-            float *fp = (float *)c->ptr;
             buf = expand(val, 0);
-            *fp = strtod(buf, &endp);
+            *c->ptr.f = strtod(buf, &endp);
             g_free(buf);
         }
 
         /* invoke a command specific function */
         if(c->func) c->func();
-    }
-    return TRUE;
-}
-
-void
-render_html() {
-    Behaviour *b = &uzbl.behave;
+    } else {
+        /* check wether name violates our naming scheme */
+        if(strpbrk(name, invalid_chars)) {
+            if (uzbl.state.verbose)
+                printf("Invalid variable name\n");
+            return FALSE;
+        }
 
-    if(b->html_buffer->str) {
-        webkit_web_view_load_html_string (uzbl.gui.web_view,
-                b->html_buffer->str, b->base_url);
-        g_string_free(b->html_buffer, TRUE);
-        b->html_buffer = g_string_new("");
+        /* custom vars */
+        c = malloc(sizeof(uzbl_cmdprop));
+        c->type = TYPE_STR;
+        c->dump = 0;
+        c->func = NULL;
+        c->writeable = 1;
+        buf = expand(val, 0);
+        c->ptr.s = malloc(sizeof(char *));
+        *c->ptr.s = buf;
+        g_hash_table_insert(uzbl.comm.proto_var,
+                g_strdup(name), (gpointer) c);
     }
+    return TRUE;
 }
 
 enum {M_CMD, M_HTML};
 void
 parse_cmd_line(const char *ctl_line, GString *result) {
-    Behaviour *b = &uzbl.behave;
     size_t len=0;
 
-    if(b->mode == M_HTML) {
-        len = strlen(b->html_endmarker);
-        /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
-        if(len == strlen(ctl_line)-1 &&
-           !strncmp(b->html_endmarker, ctl_line, len)) {
-            set_timeout(0);
-            set_var_value("mode", "0");
-            render_html();
-            return;
-        }
-        else {
-            set_timeout(b->html_timeout);
-            g_string_append(b->html_buffer, ctl_line);
-        }
-    }
-    else if((ctl_line[0] == '#') /* Comments */
+    if((ctl_line[0] == '#') /* Comments */
             || (ctl_line[0] == ' ')
             || (ctl_line[0] == '\n'))
         ; /* ignore these lines */
@@ -1773,7 +1952,7 @@ parse_cmd_line(const char *ctl_line, GString *result) {
     }
 }
 
-gchar*
+/*@null@*/ gchar*
 build_stream_name(int type, const gchar* dir) {
     State *s = &uzbl.state;
     gchar *str = NULL;
@@ -1814,7 +1993,7 @@ control_fifo(GIOChannel *gio, GIOCondition condition) {
     return TRUE;
 }
 
-gchar*
+/*@null@*/ gchar*
 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
         if (unlink(uzbl.comm.fifo_path) == -1)
@@ -1938,7 +2117,7 @@ control_client_socket(GIOChannel *clientchan) {
     return TRUE;
 }
 
-gchar*
+/*@null@*/ gchar*
 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
         if (unlink(uzbl.comm.socket_path) == -1)
@@ -2028,7 +2207,7 @@ configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
     (void) window;
     (void) event;
 
-    retreive_geometry();
+    retrieve_geometry();
     return FALSE;
 }
 
@@ -2042,6 +2221,8 @@ key_press_cb (GtkWidget* window, GdkEventKey* event)
     if (event->type   != GDK_KEY_PRESS ||
         event->keyval == GDK_Page_Up   ||
         event->keyval == GDK_Page_Down ||
+        event->keyval == GDK_Home      ||
+        event->keyval == GDK_End       ||
         event->keyval == GDK_Up        ||
         event->keyval == GDK_Down      ||
         event->keyval == GDK_Left      ||
@@ -2057,8 +2238,8 @@ key_press_cb (GtkWidget* window, GdkEventKey* event)
         return TRUE;
     }
 
-    if (uzbl.behave.insert_mode && 
-        ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || 
+    if (uzbl.behave.insert_mode &&
+        ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
           (!uzbl.behave.modmask)
         )
        )
@@ -2163,30 +2344,23 @@ exec_paramcmd(const Action *act, const guint i) {
 }
 
 
-GtkWidget*
+void
 create_browser () {
     GUI *g = &uzbl.gui;
 
-    GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-    //main_window_ref = g_object_ref(scrolled_window);
-    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
-
     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
-    gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
 
     g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
     g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
-    g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
+    g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
     g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
-
-    return scrolled_window;
 }
 
 GtkWidget*
@@ -2253,7 +2427,8 @@ inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *ne
     if ((g_strcmp0(actname, "spawn") == 0) ||
         (g_strcmp0(actname, "sh") == 0) ||
         (g_strcmp0(actname, "sync_spawn") == 0) ||
-        (g_strcmp0(actname, "sync_sh") == 0)) {
+        (g_strcmp0(actname, "sync_sh") == 0) ||
+        (g_strcmp0(actname, "talk_to_socket") == 0)) {
         guint i;
         GString *a = g_string_new("");
         gchar **spawnparts = split_quoted(origargs, FALSE);
@@ -2351,7 +2526,7 @@ add_binding (const gchar *key, const gchar *act) {
     g_strfreev(parts);
 }
 
-gchar*
+/*@null@*/ gchar*
 get_xdg_var (XDG_Var xdg) {
     const gchar* actual_value = getenv (xdg.environmental);
     const gchar* home         = getenv ("HOME");
@@ -2370,8 +2545,8 @@ get_xdg_var (XDG_Var xdg) {
     return return_value;
 }
 
-gchar*
-find_xdg_file (int xdg_type, char* filename) {
+/*@null@*/ gchar*
+find_xdg_file (int xdg_type, const char* filename) {
     /* xdg_type = 0 => config
        xdg_type = 1 => data
        xdg_type = 2 => cache*/
@@ -2400,6 +2575,7 @@ find_xdg_file (int xdg_type, char* filename) {
     if (file_exists (temporary_file)) {
         return temporary_file;
     } else {
+        g_free(temporary_file);
         return NULL;
     }
 }
@@ -2581,11 +2757,11 @@ dump_var_hash(gpointer k, gpointer v, gpointer ud) {
         return;
 
     if(c->type == TYPE_STR)
-        printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
+        printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
     else if(c->type == TYPE_INT)
-        printf("set %s = %d\n", (char *)k, (int)*c->ptr);
+        printf("set %s = %d\n", (char *)k, *c->ptr.i);
     else if(c->type == TYPE_FLOAT)
-        printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
+        printf("set %s = %f\n", (char *)k, *c->ptr.f);
 }
 
 void
@@ -2604,7 +2780,7 @@ dump_config() {
 }
 
 void
-retreive_geometry() {
+retrieve_geometry() {
     int w, h, x, y;
     GString *buf = g_string_new("");
 
@@ -2622,7 +2798,6 @@ retreive_geometry() {
  * external applications need to do anyhow */
 void
 initialize(int argc, char *argv[]) {
-    gtk_init (&argc, &argv);
     if (!g_thread_supported ())
         g_thread_init (NULL);
     uzbl.state.executable_path = g_strdup(argv[0]);
@@ -2637,7 +2812,7 @@ initialize(int argc, char *argv[]) {
 
     if (uzbl.behave.print_version) {
         printf("Commit: %s\n", COMMIT);
-        exit(0);
+        exit(EXIT_SUCCESS);
     }
 
     /* initialize hash table */
@@ -2650,19 +2825,11 @@ initialize(int argc, char *argv[]) {
         fprintf(stderr, "uzbl: error hooking SIGTERM\n");
     if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
         fprintf(stderr, "uzbl: error hooking SIGINT\n");
-    if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
-        fprintf(stderr, "uzbl: error hooking SIGALARM\n");
 
-    uzbl.gui.sbar.progress_s = g_strdup("=");
+    uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
     uzbl.gui.sbar.progress_u = g_strdup("·");
     uzbl.gui.sbar.progress_w = 10;
 
-    /* HTML mode defaults*/
-    uzbl.behave.html_buffer = g_string_new("");
-    uzbl.behave.html_endmarker = g_strdup(".");
-    uzbl.behave.html_timeout = 60;
-    uzbl.behave.base_url = g_strdup("http://invalid");
-
     /* default mode indicators */
     uzbl.behave.insert_indicator = g_strdup("I");
     uzbl.behave.cmd_indicator    = g_strdup("C");
@@ -2676,7 +2843,7 @@ initialize(int argc, char *argv[]) {
     commands_hash ();
     make_var_to_name_hash();
 
-    uzbl.gui.scrolled_win = create_browser();
+    create_browser();
 }
 
 #ifndef UZBL_LIBRARY
@@ -2685,6 +2852,16 @@ int
 main (int argc, char* argv[]) {
     initialize(argc, argv);
 
+    gtk_init (&argc, &argv);
+
+    uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+    //main_window_ref = g_object_ref(scrolled_window);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
+        GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
+
+    gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
+        GTK_WIDGET (uzbl.gui.web_view));
+
     uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
 
     create_mainbar();
@@ -2717,6 +2894,7 @@ main (int argc, char* argv[]) {
             printf("window_id %i\n",(int) uzbl.xwin);
         printf("pid %i\n", getpid ());
         printf("name: %s\n", uzbl.state.instance_name);
+        printf("commit: %s\n", uzbl.info.commit);
     }
 
     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
@@ -2725,16 +2903,23 @@ main (int argc, char* argv[]) {
     uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
     gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
 
-    if(uzbl.gui.geometry)
-        cmd_set_geometry();
-    else
-        retreive_geometry();
+    /* Check uzbl is in window mode before getting/setting geometry */
+    if (uzbl.gui.main_window) {
+        if(uzbl.gui.geometry)
+            cmd_set_geometry();
+        else
+            retrieve_geometry();
+    }
 
     gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
+    if (argc > 1 && !uzbl.state.uri)
+        uri_override = g_strdup(argv[1]);
     gboolean verbose_override = uzbl.state.verbose;
 
     settings_init ();
-    set_insert_mode(FALSE);
+
+    if (!uzbl.behave.always_insert_mode)
+      set_insert_mode(FALSE);
 
     if (!uzbl.behave.show_status)
         gtk_widget_hide(uzbl.gui.mainbar);
@@ -2751,7 +2936,7 @@ main (int argc, char* argv[]) {
         set_var_value("uri", uri_override);
         g_free(uri_override);
     } else if (uzbl.state.uri)
-        cmd_load_uri(uzbl.gui.web_view, NULL);
+        cmd_load_uri();
 
     gtk_main ();
     clean_up();