fixed failing to load argument to --uri
[uzbl-mobile] / uzbl.c
diff --git a/uzbl.c b/uzbl.c
index abb01e1..43178e9 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -69,6 +69,8 @@ const struct {
     { "status_top",         (void *)&uzbl.behave.status_top         },
     { "status_format",      (void *)&uzbl.behave.status_format      },
     { "status_background",  (void *)&uzbl.behave.status_background  },
+    { "title_format_long",  (void *)&uzbl.behave.title_format_long  },
+    { "title_format_short", (void *)&uzbl.behave.title_format_short },
     { "insert_mode",        (void *)&uzbl.behave.insert_mode        },
     { "always_insert_mode", (void *)&uzbl.behave.always_insert_mode },
     { "reset_command_mode", (void *)&uzbl.behave.reset_command_mode },
@@ -80,6 +82,9 @@ const struct {
     { "fifo_dir",           (void *)&uzbl.behave.fifo_dir           },
     { "socket_dir",         (void *)&uzbl.behave.socket_dir         },
     { "http_debug",         (void *)&uzbl.behave.http_debug         },
+    { "default_font_size",  (void *)&uzbl.behave.default_font_size  },
+    { "minimum_font_size",  (void *)&uzbl.behave.minimum_font_size  },
+    { "shell_cmd",          (void *)&uzbl.behave.shell_cmd          },
     { "proxy_url",          (void *)&uzbl.net.proxy_url             },
     { "max_conns",          (void *)&uzbl.net.max_conns             },
     { "max_conns_host",     (void *)&uzbl.net.max_conns_host        },
@@ -123,19 +128,15 @@ make_var_to_name_hash() {
 /* commandline arguments (set initial values for the state variables) */
 static GOptionEntry entries[] =
 {
-    { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load", "URI" },
-    { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
-    { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file", "FILE" },
+    { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load at startup (equivalent to 'set uri = URI')", "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 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" },
     { NULL,      0, 0, 0, NULL, NULL, NULL }
 };
 
 typedef void (*Command)(WebKitWebView*, const char *);
 
-/* XDG stuff */
-static char *XDG_CONFIG_HOME_default[256];
-static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
-
-
 /* --- UTILITY FUNCTIONS --- */
 
 char *
@@ -146,6 +147,18 @@ itos(int val) {
     return g_strdup(tmp);
 }
 
+static char *
+str_replace (const char* search, const char* replace, const char* string) {
+    gchar **buf;
+    char *ret;
+
+    buf = g_strsplit (string, search, -1);
+    ret = g_strjoinv (replace, buf);
+    g_strfreev(buf);
+
+    return ret;
+}
+
 static sigfunc*
 setup_signal(int signr, sigfunc *shandler) {
     struct sigaction nh, oh;
@@ -181,6 +194,13 @@ catch_sigterm(int s) {
     clean_up();
 }
 
+static void
+catch_sigint(int s) {
+    (void) s;
+    clean_up();
+    exit(EXIT_SUCCESS);
+}
+
 /* --- CALLBACKS --- */
 
 static gboolean
@@ -191,7 +211,8 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequ
     (void) policy_decision;
     (void) user_data;
     const gchar* uri = webkit_network_request_get_uri (request);
-    printf("New window requested -> %s \n", uri);
+    if (uzbl.state.verbose)
+        printf("New window requested -> %s \n", uri);
     new_window_load_uri(uri);
     return (FALSE);
 }
@@ -202,10 +223,12 @@ create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer us
     (void) frame;
     (void) user_data;
     if (uzbl.state.selected_url[0]!=0) {
-        printf("\nNew web view -> %s\n",uzbl.state.selected_url);
+        if (uzbl.state.verbose)
+            printf("\nNew web view -> %s\n",uzbl.state.selected_url);
         new_window_load_uri(uzbl.state.selected_url);
     } else {
-        printf("New web view -> %s\n","Nothing to open, exiting");
+        if (uzbl.state.verbose)
+            printf("New web view -> %s\n","Nothing to open, exiting");
     }
     return (NULL);
 }
@@ -216,8 +239,9 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
     (void) user_data;
     if (uzbl.behave.download_handler) {
         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
-        printf("Download -> %s\n",uri);
-        run_command_async(uzbl.behave.download_handler, uri);
+        if (uzbl.state.verbose)
+            printf("Download -> %s\n",uri);
+        run_command(uzbl.behave.download_handler, uri, FALSE, NULL);
     }
     return (FALSE);
 }
@@ -285,8 +309,8 @@ static void
 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
     (void) page;
     (void) title;
-    (void) data;    
-    //ADD HOVER URL TO WINDOW TITLE
+    (void) data;
+    //Set selected_url state variable
     uzbl.state.selected_url[0] = '\0';
     if (link) {
         strcpy (uzbl.state.selected_url, link);
@@ -319,7 +343,7 @@ load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
     (void) frame;
     (void) data;
     if (uzbl.behave.load_finish_handler) {
-        run_command_async(uzbl.behave.load_finish_handler, NULL);
+        run_command(uzbl.behave.load_finish_handler, NULL, FALSE, NULL);
     }
 }
 
@@ -333,7 +357,7 @@ load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
     if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
         uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
         update_title();
-    }    
+    }
     g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
 }
 
@@ -355,7 +379,7 @@ log_history_cb () {
        strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
        GString* args = g_string_new ("");
        g_string_printf (args, "'%s'", date);
-       run_command_async(uzbl.behave.history_handler, args->str);
+       run_command(uzbl.behave.history_handler, args->str, FALSE, NULL);
        g_string_free (args, TRUE);
    }
 }
@@ -383,7 +407,7 @@ static struct {char *name; Command command;} cmdlist[] =
     { "scroll_horz",      scroll_horz             },
     { "scroll_begin",     scroll_begin            },
     { "scroll_end",       scroll_end              },
-    { "reload",           view_reload,            }, 
+    { "reload",           view_reload,            },
     { "reload_ign_cache", view_reload_bypass_cache},
     { "stop",             view_stop_loading,      },
     { "zoom_in",          view_zoom_in,           }, //Can crash (when max zoom reached?).
@@ -392,8 +416,10 @@ static struct {char *name; Command command;} cmdlist[] =
     { "script",           run_js                  },
     { "toggle_status",    toggle_status_cb        },
     { "spawn",            spawn                   },
+    { "sh",               spawn_sh                },
     { "exit",             close_uzbl              },
-    { "search",           search_text             },
+    { "search",           search_forward_text     },
+    { "search_reverse",   search_reverse_text     },
     { "insert_mode",      set_insert_mode         },
     { "runcmd",           runcmd                  }
 };
@@ -434,15 +460,10 @@ new_action(const gchar *name, const gchar *param) {
 
 static bool
 file_exists (const char * filename) {
-    FILE *file = fopen (filename, "r");
-    if (file) {
-        fclose (file);
-        return true;
-    }
-    return false;
+    return (access(filename, F_OK) == 0);
 }
 
-void
+static void
 set_insert_mode(WebKitWebView *page, const gchar *param) {
     (void)page;
     (void)param;
@@ -457,7 +478,7 @@ load_uri (WebKitWebView * web_view, const gchar *param) {
         GString* newuri = g_string_new (param);
         if (g_strrstr (param, "://") == NULL)
             g_string_prepend (newuri, "http://");
-               /* if we do handle cookies, ask our handler for them */
+        /* if we do handle cookies, ask our handler for them */
         webkit_web_view_load_uri (web_view, newuri->str);
         g_string_free (newuri, TRUE);
     }
@@ -470,33 +491,45 @@ run_js (WebKitWebView * web_view, const gchar *param) {
 }
 
 static void
-search_text (WebKitWebView *page, const char *param) {
+search_text (WebKitWebView *page, const char *param, const gboolean forward) {
     if ((param) && (param[0] != '\0')) {
         strcpy(uzbl.state.searchtx, param);
     }
     if (uzbl.state.searchtx[0] != '\0') {
-        printf ("Searching: %s\n", uzbl.state.searchtx);
+        if (uzbl.state.verbose)
+            printf ("Searching: %s\n", uzbl.state.searchtx);
         webkit_web_view_unmark_text_matches (page);
         webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
         webkit_web_view_set_highlight_text_matches (page, TRUE);
-        webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
+        webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
     }
 }
 
 static void
+search_forward_text (WebKitWebView *page, const char *param) {
+    search_text(page, param, TRUE);
+}
+
+static void
+search_reverse_text (WebKitWebView *page, const char *param) {
+    search_text(page, param, FALSE);
+}
+
+static void
 new_window_load_uri (const gchar * uri) {
     GString* to_execute = g_string_new ("");
     g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
     int i;
     for (i = 0; entries[i].long_name != NULL; i++) {
-        if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
+        if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
             gchar** str = (gchar**)entries[i].arg_data;
             if (*str!=NULL) {
                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
             }
         }
     }
-    printf("\n%s\n", to_execute->str);
+    if (uzbl.state.verbose)
+        printf("\n%s\n", to_execute->str);
     g_spawn_command_line_async (to_execute->str, NULL);
     g_string_free (to_execute, TRUE);
 }
@@ -519,13 +552,11 @@ build_progressbar_ascii(int percent) {
    l = (double)percent*((double)width/100.);
    l = (int)(l+.5)>=(int)l ? l+.5 : l;
 
-   g_string_append(bar, "[");
    for(i=0; i<(int)l; i++)
        g_string_append(bar, "=");
-          
+
    for(; i<width; i++)
        g_string_append(bar, "ยท");
-   g_string_append(bar, "]");
 
    return g_string_free(bar, FALSE);
 }
@@ -579,7 +610,8 @@ setup_scanner() {
      uzbl.scan = g_scanner_new(&scan_config);
      while(symp->symbol_name) {
          g_scanner_scope_add_symbol(uzbl.scan, 0,
-                         symp->symbol_name, (gulong*)&(symp->symbol_token));
+                         symp->symbol_name,
+                         GINT_TO_POINTER(symp->symbol_token));
          symp++;
      }
 }
@@ -587,23 +619,25 @@ setup_scanner() {
 static gchar *
 expand_template(const char *template) {
      if(!template) return NULL;
-     
+
      GTokenType token = G_TOKEN_NONE;
      GString *ret = g_string_new("");
      char *buf=NULL;
-     gulong sym;
+     int sym;
 
      g_scanner_input_text(uzbl.scan, template, strlen(template));
      while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
          token = g_scanner_get_next_token(uzbl.scan);
 
          if(token == G_TOKEN_SYMBOL) {
-             sym = *((gulong*)g_scanner_cur_value(uzbl.scan).v_int);
+             sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
              switch(sym) {
                  case SYM_URI:
-                     g_string_append(ret, 
-                         uzbl.state.uri?
-                         g_markup_printf_escaped("%s", uzbl.state.uri):"");
+                     buf = uzbl.state.uri?
+                         g_markup_printf_escaped("%s", uzbl.state.uri) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
                  case SYM_LOADPRGS:
                      buf = itos(uzbl.gui.sbar.load_progress);
@@ -616,27 +650,38 @@ expand_template(const char *template) {
                      g_free(buf);
                      break;
                  case SYM_TITLE:
-                     g_string_append(ret,
-                         uzbl.gui.main_title?
-                         g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
+                     buf = uzbl.gui.main_title?
+                         g_markup_printf_escaped("%s", uzbl.gui.main_title) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
+                 case SYM_SELECTED_URI:
+                     buf = uzbl.state.selected_url?
+                         g_markup_printf_escaped("%s", uzbl.state.selected_url) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
+                    break;
                  case SYM_NAME:
                      buf = itos(uzbl.xwin);
-                     g_string_append(ret, 
+                     g_string_append(ret,
                          uzbl.state.instance_name?uzbl.state.instance_name:buf);
                      free(buf);
                      break;
                  case SYM_KEYCMD:
-                     g_string_append(ret, 
-                         uzbl.state.keycmd->str ?
-                         g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
+                     buf = uzbl.state.keycmd->str?
+                         g_markup_printf_escaped("%s", uzbl.state.keycmd->str) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
                  case SYM_MODE:
-                     g_string_append(ret, 
+                     g_string_append(ret,
                          uzbl.behave.insert_mode?"[I]":"[C]");
                      break;
                  case SYM_MSG:
-                     g_string_append(ret, 
+                     g_string_append(ret,
                          uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
                      break;
                      /* useragent syms */
@@ -677,7 +722,7 @@ expand_template(const char *template) {
                  case SYM_DOMAINNAME:
                      g_string_append(ret, uzbl.state.unameinfo.domainname);
                      break;
-#endif           
+#endif
                  case SYM_COMMIT:
                      g_string_append(ret, COMMIT);
                      break;
@@ -703,46 +748,71 @@ expand_template(const char *template) {
 /* --End Statusbar functions-- */
 
 
-// make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
+// make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
 static gboolean
-run_command_async(const char *command, const char *args) {
+run_command (const char *command, const char *args, const gboolean sync, char **stdout) {
    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
-    GString* to_execute = g_string_new ("");
+    GString *to_execute = g_string_new ("");
+    GError *err = NULL;
+    gchar *cmd = g_strstrip(g_strdup(command));
+    gchar *qcfg = (uzbl.state.config_file ? g_shell_quote(uzbl.state.config_file) : g_strdup("''"));
+    gchar *qfifo = (uzbl.comm.fifo_path ? g_shell_quote(uzbl.comm.fifo_path) : g_strdup("''"));
+    gchar *qsock = (uzbl.comm.socket_path ? g_shell_quote(uzbl.comm.socket_path) : g_strdup("''"));
+    gchar *quri = (uzbl.state.uri ? g_shell_quote(uzbl.state.uri) : g_strdup("''"));
+    gchar *qtitle = (uzbl.gui.main_title ? g_shell_quote(uzbl.gui.main_title) : g_strdup("''"));
+
     gboolean result;
-    g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", 
-                    command, uzbl.state.config_file, (int) getpid() ,
-                    (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
-    g_string_append_printf (to_execute, " '%s' '%s'", 
-                    uzbl.state.uri, "TODO title here");
-    if(args) {
-        g_string_append_printf (to_execute, " %s", args);
-    }
-    result = g_spawn_command_line_async (to_execute->str, NULL);
-    printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
+    g_string_printf (to_execute, "%s %s '%i' '%i' %s %s",
+                     cmd, qcfg, (int) getpid(), (int) uzbl.xwin, qfifo, qsock);
+    g_string_append_printf (to_execute, " %s %s", quri, qtitle);
+    if(args) g_string_append_printf (to_execute, " %s", args);
+
+    if (sync) {
+        result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, &err);
+    } else result = g_spawn_command_line_async (to_execute->str, &err);
+    if (uzbl.state.verbose)
+        printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
     g_string_free (to_execute, TRUE);
+    if (err) {
+        g_printerr("error on run_command: %s\n", err->message);
+        g_error_free (err);
+    }
+
+    g_free (qcfg);
+    g_free (qfifo);
+    g_free (qsock);
+    g_free (quri);
+    g_free (qtitle);
+    g_free (cmd);
     return result;
 }
 
-static gboolean
-run_command_sync(const char *command, const char *args, char **stdout) {
-       //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
-    GString* to_execute = g_string_new ("");
-    gboolean result;
-    g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
-    g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
-    if(args) {
-        g_string_append_printf (to_execute, " %s", args);
+static void
+spawn(WebKitWebView *web_view, const char *param) {
+    (void)web_view;
+/*
+   TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
+    gchar** cmd = g_strsplit(param, " ", 2);
+    gchar * args = NULL;
+    if (cmd[1]) {
+        args = g_shell_quote(cmd[1]);
     }
-    result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
-    printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
-    g_string_free (to_execute, TRUE);
-    return result;
+    if (cmd) {
+        run_command(cmd[0], args, FALSE, NULL);
+    }
+    if (args) {
+        g_free(args);
+    }
+*/
+    run_command(param, NULL, FALSE, NULL);
 }
 
 static void
-spawn(WebKitWebView *web_view, const char *param) {
+spawn_sh(WebKitWebView *web_view, const char *param) {
     (void)web_view;
-    run_command_async(param, NULL);
+    gchar *cmd = g_strdup_printf(uzbl.behave.shell_cmd, param);
+    spawn(NULL, cmd);
+    g_free(cmd);
 }
 
 static void
@@ -758,27 +828,42 @@ parse_command(const char *cmd, const char *param) {
 /* command parser */
 static void
 setup_regex() {
-    GError *err=NULL;
-
-    uzbl.comm.get_regex  = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$", 
-            G_REGEX_OPTIMIZE, 0, &err);
+    uzbl.comm.get_regex  = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
+            G_REGEX_OPTIMIZE, 0, NULL);
     uzbl.comm.set_regex  = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
-            G_REGEX_OPTIMIZE, 0, &err);
-    uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$", 
-            G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err);
-    uzbl.comm.cmd_regex = g_regex_new("^[Cc][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
-            G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_OPTIMIZE, 0, NULL);
+    uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
+            G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
+    uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
+            G_REGEX_OPTIMIZE, 0, NULL);
+    uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
+            G_REGEX_OPTIMIZE, 0, NULL);
 }
 
 static gboolean
 get_var_value(gchar *name) {
     void **p = NULL;
-    
+
     if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
-        if(var_is("status_format", name)
-           || var_is("useragent", name)) {
+        if(var_is("uri", name)
+           || var_is("status_message", name)
+           || var_is("status_format", name)
+           || var_is("status_background", name)
+           || var_is("title_format_short", name)
+           || var_is("title_format_long", name)
+           || var_is("modkey", name)
+           || var_is("load_finish_handler", name)
+           || var_is("history_handler", name)
+           || var_is("download_handler", name)
+           || var_is("cookie_handler", name)
+           || var_is("fifo_dir", name)
+           || var_is("socket_dir", name)
+           || var_is("shell_cmd", name)
+           || var_is("proxy_url", name)
+           || var_is("useragent", name))
+           {
             printf("VAR: %s VALUE: %s\n", name, (char *)*p);
-        } else printf("VAR: %s VALUE: %d\n", name, *((int *)p));
+        } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
     }
     return TRUE;
 }
@@ -805,7 +890,7 @@ set_proxy_url() {
 
 static void
 move_statusbar() {
-    gtk_widget_ref(uzbl.gui.scrolled_win); 
+    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);
     gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
@@ -832,11 +917,14 @@ static gboolean
 set_var_value(gchar *name, gchar *val) {
     void **p = NULL;
     char *endp = NULL;
+    char *buf=NULL;
 
     if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
         if(var_is("status_message", name)
            || var_is("status_background", name)
            || var_is("status_format", name)
+           || var_is("title_format_long", name)
+           || var_is("title_format_short", name)
            || var_is("load_finish_handler", name)
            || var_is("history_handler", name)
            || var_is("download_handler", name)
@@ -845,12 +933,12 @@ set_var_value(gchar *name, gchar *val) {
                 free(*p);
             *p = g_strdup(val);
             update_title();
-        } 
+        }
         else if(var_is("uri", name)) {
             if(*p) free(*p);
             *p = g_strdup(val);
             load_uri(uzbl.gui.web_view, (const gchar*)*p);
-        } 
+        }
         else if(var_is("proxy_url", name)) {
             if(*p) free(*p);
             *p = g_strdup(val);
@@ -858,11 +946,13 @@ set_var_value(gchar *name, gchar *val) {
         }
         else if(var_is("fifo_dir", name)) {
             if(*p) free(*p);
-            *p = init_fifo(g_strdup(val));
+            buf = init_fifo(val);
+            *p = buf?buf:g_strdup("");
         }
         else if(var_is("socket_dir", name)) {
             if(*p) free(*p);
-            *p = init_socket(g_strdup(val));
+            buf = init_socket(val);
+            *p = buf?buf:g_strdup("");
         }
         else if(var_is("modkey", name)) {
             if(*p) free(*p);
@@ -876,7 +966,12 @@ set_var_value(gchar *name, gchar *val) {
         }
         else if(var_is("useragent", name)) {
             if(*p) free(*p);
-            *p = set_useragent(g_strdup(val));
+            buf = set_useragent(val);
+            *p = buf?buf:g_strdup("");
+        }
+        else if(var_is("shell_cmd", name)) {
+            if(*p) free(*p);
+            *p = g_strdup(val);
         }
         /* variables that take int values */
         else {
@@ -887,7 +982,7 @@ set_var_value(gchar *name, gchar *val) {
                 cmd_set_status();
             }
             else if(var_is("always_insert_mode", name)) {
-                uzbl.behave.insert_mode = 
+                uzbl.behave.insert_mode =
                     uzbl.behave.always_insert_mode ?  TRUE : FALSE;
                 update_title();
             }
@@ -900,13 +995,11 @@ set_var_value(gchar *name, gchar *val) {
                              SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
             }
             else if (var_is("http_debug", name)) {
-                //soup_session_remove_feature
-                //    (uzbl.net.soup_session, uzbl.net.soup_logger);
                 soup_session_remove_feature
                     (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
                 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
                 /*g_free(uzbl.net.soup_logger);*/
-                  
+
                 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
                 soup_session_add_feature(uzbl.net.soup_session,
                                          SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
@@ -914,6 +1007,14 @@ set_var_value(gchar *name, gchar *val) {
             else if (var_is("status_top", name)) {
                 move_statusbar();
             }
+            else if (var_is("default_font_size", name)) {
+                WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
+                g_object_set (G_OBJECT(ws), "default-font-size", *ip, NULL);
+            }
+            else if (var_is("minimum_font_size", name)) {
+                WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
+                g_object_set (G_OBJECT(ws), "minimum-font-size", *ip, NULL);
+            }
         }
     }
     return TRUE;
@@ -925,7 +1026,7 @@ runcmd(WebKitWebView* page, const char *param) {
     parse_cmd_line(param);
 }
 
-static void 
+static void
 parse_cmd_line(const char *ctl_line) {
     gchar **tokens;
 
@@ -936,7 +1037,7 @@ parse_cmd_line(const char *ctl_line) {
             set_var_value(tokens[1], tokens[2]);
             g_strfreev(tokens);
         }
-        else 
+        else
             printf("Error in command: %s\n", tokens[0]);
     }
     /* GET command */
@@ -946,9 +1047,9 @@ parse_cmd_line(const char *ctl_line) {
             get_var_value(tokens[1]);
             g_strfreev(tokens);
         }
-        else 
+        else
             printf("Error in command: %s\n", tokens[0]);
-    } 
+    }
     /* BIND command */
     else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
         tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
@@ -956,12 +1057,12 @@ parse_cmd_line(const char *ctl_line) {
             add_binding(tokens[1], tokens[2]);
             g_strfreev(tokens);
         }
-        else 
+        else
             printf("Error in command: %s\n", tokens[0]);
     }
-    /* CMD command */
-    else if(ctl_line[0] == 'C' || ctl_line[0] == 'c') {
-        tokens = g_regex_split(uzbl.comm.cmd_regex, ctl_line, 0);
+    /* ACT command */
+    else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
+        tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
         if(tokens[0][0] == 0) {
             parse_command(tokens[1], tokens[2]);
             g_strfreev(tokens);
@@ -969,6 +1070,18 @@ parse_cmd_line(const char *ctl_line) {
         else
             printf("Error in command: %s\n", tokens[0]);
     }
+    /* KEYCMD command */
+    else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
+        tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
+        if(tokens[0][0] == 0) {
+            /* should incremental commands want each individual "keystroke"
+               sent in a loop or the whole string in one go like now? */
+            g_string_assign(uzbl.state.keycmd, tokens[1]);
+            run_keycmd(FALSE);
+            update_title();
+            g_strfreev(tokens);
+        }
+    }
     /* Comments */
     else if(   (ctl_line[0] == '#')
             || (ctl_line[0] == ' ')
@@ -1002,20 +1115,23 @@ build_stream_name(int type, const gchar* dir) {
 
 static gboolean
 control_fifo(GIOChannel *gio, GIOCondition condition) {
-    printf("triggered\n");
+    if (uzbl.state.verbose)
+        printf("triggered\n");
     gchar *ctl_line;
     GIOStatus ret;
     GError *err = NULL;
 
-    if (condition & G_IO_HUP) 
+    if (condition & G_IO_HUP)
         g_error ("Fifo: Read end of pipe died!\n");
 
     if(!gio)
        g_error ("Fifo: GIOChannel broke\n");
 
     ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
-    if (ret == G_IO_STATUS_ERROR)
+    if (ret == G_IO_STATUS_ERROR) {
         g_error ("Fifo: Error reading: %s\n", err->message);
+        g_error_free (err);
+    }
 
     parse_cmd_line(ctl_line);
     g_free(ctl_line);
@@ -1033,21 +1149,21 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     }
 
     if (*dir == ' ') { /* space unsets the variable */
-        g_free(dir);
         return NULL;
     }
 
     GIOChannel *chan = NULL;
     GError *error = NULL;
     gchar *path = build_stream_name(FIFO, dir);
-    
+
     if (!file_exists(path)) {
         if (mkfifo (path, 0666) == 0) {
-            // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.            
+            // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.
             chan = g_io_channel_new_file(path, "r+", &error);
             if (chan) {
                 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
-                    printf ("init_fifo: created successfully as %s\n", path);
+                    if (uzbl.state.verbose)
+                        printf ("init_fifo: created successfully as %s\n", path);
                     uzbl.comm.fifo_path = path;
                     return dir;
                 } else g_warning ("init_fifo: could not add watch on %s\n", path);
@@ -1056,24 +1172,18 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     } else g_warning ("init_fifo: can't create %s: file exists\n", path);
 
     /* if we got this far, there was an error; cleanup */
+    if (error) g_error_free (error);
     g_free(path);
-    g_free(dir);
     return NULL;
 }
 
 static gboolean
 control_stdin(GIOChannel *gio, GIOCondition condition) {
+    (void) condition;
     gchar *ctl_line = NULL;
-    gsize ctl_line_len = 0;
     GIOStatus ret;
-    GError *err = NULL;
-
-    if (condition & G_IO_HUP) { 
-        ret = g_io_channel_shutdown (gio, FALSE, &err);
-        return FALSE;
-    }
 
-    ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
+    ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
     if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
         return FALSE;
 
@@ -1093,14 +1203,16 @@ create_stdin () {
         if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
             g_error ("Stdin: could not add watch\n");
         } else {
-            printf ("Stdin: watch added successfully\n");
+            if (uzbl.state.verbose)
+                printf ("Stdin: watch added successfully\n");
         }
     } else {
         g_error ("Stdin: Error while opening: %s\n", error->message);
     }
+    if (error) g_error_free (error);
 }
 
-static void
+static gboolean
 control_socket(GIOChannel *chan) {
     struct sockaddr_un remote;
     char buffer[512], *ctl_line;
@@ -1151,7 +1263,7 @@ control_socket(GIOChannel *chan) {
 */
 
     g_free(ctl_line);
-    return;
+    return TRUE;
 }
 
 static gchar*
@@ -1162,7 +1274,7 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
         g_free(uzbl.comm.socket_path);
         uzbl.comm.socket_path = NULL;
     }
-    
+
     if (*dir == ' ') {
         g_free(dir);
         return NULL;
@@ -1172,7 +1284,7 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
     int sock, len;
     struct sockaddr_un local;
     gchar *path = build_stream_name(SOCKET, dir);
-    
+
     sock = socket (AF_UNIX, SOCK_STREAM, 0);
 
     local.sun_family = AF_UNIX;
@@ -1181,7 +1293,8 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
 
     len = strlen (local.sun_path) + sizeof (local.sun_family);
     if (bind (sock, (struct sockaddr *) &local, len) != -1) {
-        printf ("init_socket: opened in %s\n", path);
+        if (uzbl.state.verbose)
+            printf ("init_socket: opened in %s\n", path);
         listen (sock, 5);
 
         if( (chan = g_io_channel_unix_new(sock)) ) {
@@ -1197,60 +1310,40 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
     return NULL;
 }
 
+/*
+ NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
+ it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
+*/
+// this function may be called very early when the templates are not set (yet), hence the checks
 static void
 update_title (void) {
-    GString* string_long = g_string_new ("");
-    GString* string_short = g_string_new ("");
-    char* iname = NULL;
-    gchar *statln;
-    int iname_len;
-    State *s = &uzbl.state;
     Behaviour *b = &uzbl.behave;
-
-    if(s->instance_name) {
-            iname_len = strlen(s->instance_name)+4;
-            iname = malloc(iname_len);
-            snprintf(iname, iname_len, "<%s> ", s->instance_name);
-            
-            g_string_prepend(string_long, iname);
-            g_string_prepend(string_short, iname);
-            free(iname);
-    }
-
-    g_string_append_printf(string_long, "%s ", s->keycmd->str);
-    if (!b->always_insert_mode)
-        g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
-    if (uzbl.gui.main_title) {
-        g_string_append (string_long, uzbl.gui.main_title);
-        g_string_append (string_short, uzbl.gui.main_title);
-    }
-    g_string_append (string_long, " - Uzbl browser");
-    g_string_append (string_short, " - Uzbl browser");
-    if (s->selected_url[0]!=0) {
-        g_string_append_printf (string_long, " -> (%s)", s->selected_url);
-    }
-
-    gchar* title_long = g_string_free (string_long, FALSE);
-    gchar* title_short = g_string_free (string_short, FALSE);
+    gchar *parsed;
 
     if (b->show_status) {
-        gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
-        // TODO: we should probably not do this every time we want to update the title..?
-        statln = expand_template(uzbl.behave.status_format);
-        gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
+        if (b->title_format_short) {
+            parsed = expand_template(b->title_format_short);
+            gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+            g_free(parsed);
+        }
+        if (b->status_format) {
+            parsed = expand_template(b->status_format);
+            gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
+            g_free(parsed);
+        }
         if (b->status_background) {
             GdkColor color;
             gdk_color_parse (b->status_background, &color);
             //labels and hboxes do not draw their own background.  applying this on the window is ok as we the statusbar is the only affected widget.  (if not, we could also use GtkEventBox)
             gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
         }
-        g_free(statln);
     } else {
-        gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
+        if (b->title_format_long) {
+            parsed = expand_template(b->title_format_long);
+            gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+            g_free(parsed);
+        }
     }
-
-    g_free (title_long);
-    g_free (title_short);
 }
 
 static gboolean
@@ -1259,7 +1352,6 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
     //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
 
     (void) page;
-    Action *action;
 
     if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
         || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right || event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R)
@@ -1287,10 +1379,10 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
         if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
             str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
         } else {
-            str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); 
+            str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
         }
         if (str) {
-            g_string_append_printf (uzbl.state.keycmd, "%s",  str);
+            g_string_append (uzbl.state.keycmd, str);
             update_title ();
             free (str);
         }
@@ -1305,13 +1397,25 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
     gboolean key_ret = FALSE;
     if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
         key_ret = TRUE;
-
     if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
+
+    run_keycmd(key_ret);
+    update_title();
+    if (key_ret) return (!uzbl.behave.insert_mode);
+    return TRUE;
+}
+
+static void
+run_keycmd(const gboolean key_ret) {
+    /* run the keycmd immediately if it isn't incremental and doesn't take args */
+    Action *action;
     if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
         g_string_truncate(uzbl.state.keycmd, 0);
         parse_command(action->name, action->param);
+        return;
     }
 
+    /* try if it's an incremental keycmd or one that takes args, and run it */
     GString* short_keys = g_string_new ("");
     GString* short_keys_inc = g_string_new ("");
     unsigned int i;
@@ -1320,15 +1424,15 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
         g_string_assign(short_keys_inc, short_keys->str);
         g_string_append_c(short_keys, '_');
         g_string_append_c(short_keys_inc, '*');
-            
+
         gboolean exec_now = FALSE;
         if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
-            if (key_ret) exec_now = TRUE; // run normal cmds only if return was pressed
+            if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
         } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
-            if (key_ret) { // just quit the incremental command on return
+            if (key_ret) { /* just quit the incremental command on return */
                 g_string_truncate(uzbl.state.keycmd, 0);
                 break;
-            } else exec_now = TRUE; // always exec inc. commands on keys other than return
+            } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
         }
 
         if (exec_now) {
@@ -1347,15 +1451,12 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
             if (key_ret)
                 g_string_truncate(uzbl.state.keycmd, 0);
             break;
-        }      
-        
+        }
+
         g_string_truncate(short_keys, short_keys->len - 1);
     }
     g_string_free (short_keys, TRUE);
     g_string_free (short_keys_inc, TRUE);
-    update_title();
-    if (key_ret) return (!uzbl.behave.insert_mode);
-    return TRUE;
 }
 
 static GtkWidget*
@@ -1363,7 +1464,6 @@ 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 ());
@@ -1372,13 +1472,13 @@ create_browser () {
     g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
     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-committed", G_CALLBACK (log_history_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), "key-press-event", G_CALLBACK (key_press_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), "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);
 
     return scrolled_window;
 }
@@ -1389,10 +1489,7 @@ create_mainbar () {
 
     g->mainbar = gtk_hbox_new (FALSE, 0);
 
-    /* keep a reference to the bar so we can re-pack it at runtime*/
-    //sbar_ref = g_object_ref(g->mainbar);
-
-    g->mainbar_label = gtk_label_new ("");  
+    g->mainbar_label = gtk_label_new ("");
     gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
     gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
@@ -1420,72 +1517,109 @@ add_binding (const gchar *key, const gchar *act) {
         return;
 
     //Debug:
-    printf ("Binding %-10s : %s\n", key, act);
+    if (uzbl.state.verbose)
+        printf ("Binding %-10s : %s\n", key, act);
+
     action = new_action(parts[0], parts[1]);
-    
-    if(g_hash_table_lookup(uzbl.bindings, key))
-        g_hash_table_remove(uzbl.bindings, key);
-    g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
+    g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
 
     g_strfreev(parts);
 }
 
+static gchar*
+get_xdg_var (XDG_Var xdg) {
+    const gchar* actual_value = getenv (xdg.environmental);
+    const gchar* home         = getenv ("HOME");
+
+    gchar* return_value = str_replace ("~", home, actual_value);
+
+    if (! actual_value || strcmp (actual_value, "") == 0) {
+        if (xdg.default_value) {
+            return_value = str_replace ("~", home, xdg.default_value);
+        } else {
+            return_value = NULL;
+        }
+    }
+    return return_value;
+}
+
+static gchar*
+find_xdg_file (int xdg_type, char* filename) {
+    /* xdg_type = 0 => config
+       xdg_type = 1 => data
+       xdg_type = 2 => cache*/
+
+    gchar* temporary_file   = malloc (1024);
+    gchar* temporary_string = NULL;
+    char*  saveptr;
+    char*  buf;
+
+    buf = get_xdg_var (XDG[xdg_type]);
+    strcpy (temporary_file, buf);
+    strcat (temporary_file, filename);
+    free(buf);
+
+    if (! file_exists (temporary_file) && xdg_type != 2) {
+        buf = get_xdg_var (XDG[3 + xdg_type]);
+        temporary_string = (char *) strtok_r (buf, ":", &saveptr);
+        free(buf);
+
+        while (temporary_string && ! file_exists (temporary_file)) {
+            strcpy (temporary_file, temporary_string);
+            strcat (temporary_file, filename);
+            temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
+        }
+    }
+
+    if (file_exists (temporary_file)) {
+        return temporary_file;
+    } else {
+        return NULL;
+    }
+}
+
 static void
 settings_init () {
-    GKeyFile* config = NULL;
-    gboolean res  = FALSE;
-    char *saveptr;
     State *s = &uzbl.state;
     Network *n = &uzbl.net;
 
     uzbl.behave.reset_command_mode = 1;
 
     if (!s->config_file) {
-        const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
-        if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
-          XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
-        }
-        printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
-    
-        strcpy (s->config_file_path, XDG_CONFIG_HOME);
-        strcat (s->config_file_path, "/uzbl/config");
-        if (file_exists (s->config_file_path)) {
-          printf ("Config file %s found.\n", s->config_file_path);
-          s->config_file = &s->config_file_path[0];
-        } else {
-            // Now we check $XDG_CONFIG_DIRS
-            char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
-            if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
-                XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
-
-            printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
-
-            char buffer[512];
-            strcpy (buffer, XDG_CONFIG_DIRS);
-            const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
-            while (dir && ! file_exists (s->config_file_path)) {
-                strcpy (s->config_file_path, dir);
-                strcat (s->config_file_path, "/uzbl/config_file_pathig");
-                if (file_exists (s->config_file_path)) {
-                    printf ("Config file %s found.\n", s->config_file_path);
-                    s->config_file = &s->config_file_path[0];
-                }
-                dir = (char * ) strtok_r (NULL, ":", &saveptr);
-            }
-        }
+        s->config_file = find_xdg_file (0, "/uzbl/config");
     }
 
     if (s->config_file) {
-        config = g_key_file_new ();
-        res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
-          if (res) {
-            printf ("Config %s loaded\n", s->config_file);
-          } else {
-            fprintf (stderr, "Config %s loading failed\n", s->config_file);
+        GIOChannel *chan = NULL;
+        gchar *readbuf = NULL;
+        gsize len;
+
+        chan = g_io_channel_new_file(s->config_file, "r", NULL);
+
+        if (chan) {
+            while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
+                    == G_IO_STATUS_NORMAL) {
+                parse_cmd_line(readbuf);
+                g_free (readbuf);
+            }
+
+            g_io_channel_unref (chan);
+            if (uzbl.state.verbose)
+                printf ("Config %s loaded\n", s->config_file);
+        } else {
+            fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
         }
     } else {
-        printf ("No configuration.\n");
+        if (uzbl.state.verbose)
+            printf ("No configuration file loaded.\n");
     }
+    if (!uzbl.behave.status_format)
+        set_var_value("status_format", STATUS_DEFAULT);
+    if (!uzbl.behave.title_format_long)
+        set_var_value("title_format_long", TITLE_LONG_DEFAULT);
+    if (!uzbl.behave.title_format_short)
+        set_var_value("title_format_short", TITLE_SHORT_DEFAULT);
+
 
     g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
 }
@@ -1506,13 +1640,13 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use
     (void) session;
     (void) user_data;
     if (!uzbl.behave.cookie_handler) return;
-    
+
     gchar * stdout = NULL;
     soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
     GString* args = g_string_new ("");
     SoupURI * soup_uri = soup_message_get_uri(msg);
     g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
-    run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout);
+    run_command(uzbl.behave.cookie_handler, args->str, TRUE, &stdout);
     if(stdout) {
         soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
     }
@@ -1529,7 +1663,7 @@ save_cookies (SoupMessage *msg, gpointer user_data){
         GString* args = g_string_new ("");
         SoupURI * soup_uri = soup_message_get_uri(msg);
         g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
-        run_command_async(uzbl.behave.cookie_handler, args->str);
+        run_command(uzbl.behave.cookie_handler, args->str, FALSE, NULL);
         g_string_free(args, TRUE);
         free(cookie);
     }
@@ -1543,26 +1677,32 @@ main (int argc, char* argv[]) {
     if (!g_thread_supported ())
         g_thread_init (NULL);
 
-    printf("Uzbl start location: %s\n", argv[0]);
     strcpy(uzbl.state.executable_path,argv[0]);
 
-    strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
-    strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
-
-    GError *error = NULL;
     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
     g_option_context_add_main_entries (context, entries, NULL);
     g_option_context_add_group (context, gtk_get_option_group (TRUE));
-    g_option_context_parse (context, &argc, &argv, &error);
+    g_option_context_parse (context, &argc, &argv, NULL);
+    g_option_context_free(context);
     /* initialize hash table */
     uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
-       
+
     uzbl.net.soup_session = webkit_get_default_session();
     uzbl.state.keycmd = g_string_new("");
 
-    settings_init ();
+    if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
+        fprintf(stderr, "uzbl: error hooking SIGTERM\n");
+    if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
+        fprintf(stderr, "uzbl: error hooking SIGINT\n");
+
+    if(uname(&uzbl.state.unameinfo) == -1)
+        g_printerr("Can't retrieve unameinfo.  Your useragent might appear wrong.\n");
+
+    setup_regex();
+    setup_scanner();
     commands_hash ();
-       
+    make_var_to_name_hash();
+
 
     uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
 
@@ -1572,18 +1712,21 @@ main (int argc, char* argv[]) {
     /* initial packing */
     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
     gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
-    
+
     uzbl.gui.main_window = create_window ();
     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
 
-    load_uri (uzbl.gui.web_view, uzbl.state.uri);
 
     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
     gtk_widget_show_all (uzbl.gui.main_window);
     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
-    printf("window_id %i\n",(int) uzbl.xwin);
-    printf("pid %i\n", getpid ());
-    printf("name: %s\n", uzbl.state.instance_name);
+
+    if (uzbl.state.verbose) {
+        printf("Uzbl start location: %s\n", argv[0]);
+        printf("window_id %i\n",(int) uzbl.xwin);
+        printf("pid %i\n", getpid ());
+        printf("name: %s\n", uzbl.state.instance_name);
+    }
 
     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
@@ -1591,26 +1734,19 @@ 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);
 
+    settings_init ();
 
-    if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
-        fprintf(stderr, "uzbl: error hooking SIGTERM\n");
-
-    if(uname(&uzbl.state.unameinfo) == -1)
-        g_printerr("Can't retrieve unameinfo.  Your useragent might appear wrong.\n");
-
-    setup_regex();
-    setup_scanner();
-
-    if (!uzbl.behave.status_format)
-        uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
     if (!uzbl.behave.show_status)
         gtk_widget_hide(uzbl.gui.mainbar);
     else
         update_title();
 
-    make_var_to_name_hash();
     create_stdin();
 
+    if(uzbl.state.uri)
+        load_uri (uzbl.gui.web_view, uzbl.state.uri);
+
+
     gtk_main ();
     clean_up();