Merge commit 'rob/config-refactor' into experimental
authorDuClare <akarinotengoku@gmail.com>
Wed, 13 May 2009 13:26:05 +0000 (16:26 +0300)
committerDuClare <akarinotengoku@gmail.com>
Wed, 13 May 2009 13:26:05 +0000 (16:26 +0300)
Conflicts:
uzbl.c

INSTALL
README
TODO
docs/config-syntax
examples/duclare/clipboard.sh [new file with mode: 0755]
examples/duclare/session.sh [new file with mode: 0755]
examples/duclare/uzbl.conf [new file with mode: 0644]
examples/scripts/yank.sh [new file with mode: 0755]
uzbl.c
uzbl.h

diff --git a/INSTALL b/INSTALL
index decf316..c228f5c 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -13,6 +13,9 @@ From source
        $ cd uzbl
        $ make
        $ sudo make install
+If you want to remove uzbl again, you can issue:
+
+       $ make uninstall
 
 Dependencies
 ------------
diff --git a/README b/README
index a16638d..42db76a 100644 (file)
--- a/README
+++ b/README
@@ -38,6 +38,7 @@ Right now uzbl is in a very early state but here are some ideas I would like to
   alternatives:
   ->  /etc/hosts (not very good cause you need root and it affects the whole system)-> uzblctrl would need to support an option to list all images on a page, so you can easily pick the links to ads to add them to your /etc/hosts. (dmenu can again be great here to automate this)
   -> privoxy looks cool and perfectly demonstrates the unix philosphy.
+  -> same for http://bfilter.sourceforge.net
 - no download manager. allow user to pick wget/curl/a custom script/... 
 - no build in command interpreters like ubiquity.  uzbl should be accessible and you should use a shell or similar.
 - no "clear cookies/cache/..." menu items. rm ~/$XDG_{DATA,CACHE}_DIR/uzbl/{cache,cookies}/* 
diff --git a/TODO b/TODO
index 1191626..f757a2d 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,4 @@
 * implement all the ideas from README
-* get a logo
-* when launching new instance, don't just try 'uzbl' and then './uzbl', rather launch a new uzbl in the same way the current uzbl instance was started. (same command, same arguments, except --uri)
 * implement a more advanced dmenu alike that behaves like FF's awesomebar and where you can search in url + window title, with support for Xorg copy paste
   ideal uri editor: awesome mode like FF, some keyb shortcuts (erase search string, go to end/begin of string,..), history (if you patch dmenu to be in vertical mode and you order correctly, that's it), support copy paste
   isolate the search field feature from midori and make into a separate dmenu-like-but-more-powerful program?
 * when loading page foo.com, it can have img src=http://bar/..., uri in uzbl will be set to foo. we must pass bar to cookie handler
 * set default statusbar. line 1284
 * keybinds to open "next" or "previous" by looking for next/prev links and/or looking for numbers in the uri we can inc/decrement
-* variable replacing:
-user agent -> str_replace(all vars) DONE
-title bar -> str_replace(all vars)
-status bar ->  str_replace(all vars) -> pango markup thingie
+* variable replacing for title bar in "statusbar_visible" and statusbar_invisible states
 * get rid of config files -> send everything as commands to stdin on program launch -> you can change config at runtime.  
   how to handle launching new windows? serialize state with tpl? (can also be useful for session saving), fork()ing? if so, how do we handle Xorg window id's?
+* handler for (broken) ssl certs.
+* bring readme up to date and put it on website
+* handlers for mailto: and maybe other thingies?
+* only_on_put
+* configure script
+* a variable that holds the page state: loading, pending, seen. this can be shown in titlebar/statusbar and used for multiple instances management
+* proxy_url is not a good var name. it's not a url.
 
 
 
index 2315b6c..30cf91f 100644 (file)
@@ -35,4 +35,22 @@ spawn            <filename for process to start asynchronously>
 exit
 search           <string>
 
-The 'set' command may do more then just set the variable. eg 'set uri' commands will also cause uzbl to navigate to the uri.
\ No newline at end of file
+The 'set' command may do more then just set the variable. eg 'set uri' commands will also cause uzbl to navigate to the uri.
+
+
+
+Rationale. AKA "why not config files?"
+-> unify code to configure uzbl and to accept incoming commands
+-> no more code needed for config file parsing/handling
+-> runtime changing of configuration
+
+issues
+-> new instances (open link etc) need same config/state
+   solutions?
+   - serialize all state structs -> some libs available, could work. but:
+                                    - binary format not very user friendly
+                                    - not that easy (C has no introspection etc)
+   - iterate over state structs and generate appropriate commands to bring an instance in this state.
+     - plaintext :)
+     - user editable
+     - also useful for saving state if we need to update/shutdown/..
\ No newline at end of file
diff --git a/examples/duclare/clipboard.sh b/examples/duclare/clipboard.sh
new file mode 100755 (executable)
index 0000000..a2b3717
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+fifo="$5"
+action="$1"
+url="$7"
+selection=$(xclip -o)
+
+case $action in
+  "yank" ) echo -n "$url" | xclip;;
+  "goto" ) echo "uri $selection" > "$fifo";;
+  * ) echo "clipboard.sh: invalid action";;
+esac
+
diff --git a/examples/duclare/session.sh b/examples/duclare/session.sh
new file mode 100755 (executable)
index 0000000..4dd4a39
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Simple session manager for uzbl.  When called with "endsession" as the
+# argument, it'lla empty the sessionfile, look for fifos in $fifodir and
+# instruct each of them to store their current url in $sessionfile and
+# terminate themselves.  Run with "launch" as the argument and an instance of
+# uzbl will be launched for each stored url.  "endinstance" is used internally
+# and doesn't need to be called manually at any point.
+
+
+scriptfile=~/.uzbl/session.sh # this script
+sessionfile=~/.uzbl/session # the file in which the "session" (i.e. urls) are stored
+
+# a simple script that calls the executable with --config <cfgpath> and args
+launcher=~/.uzbl/launch
+
+fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere
+thisfifo="$5"
+act="$1"
+url="$7"
+
+case $act in
+  "launch" )
+    for url in $(cat $sessionfile); do
+      $launcher --uri "$url" &
+    done
+    exit 0;;
+  "endinstance" )
+    if [ "$url" != "(null)" ]; then
+      echo "$url" >> $sessionfile; echo "exit" > "$thisfifo"
+    else
+      echo "exit" > "$thisfifo"
+    fi;;
+  "endsession" )
+    echo -n "" > "$sessionfile"
+    for fifo in $fifodir/uzbl_fifo_*; do
+      if [ "$fifo" != "$thisfifo" ]; then
+        echo "spawn $scriptfile endinstance" > "$fifo"
+      fi
+    done
+    echo "spawn $scriptfile endinstance" > "$thisfifo";;
+  * ) echo "session manager: bad action";;
+esac
+
diff --git a/examples/duclare/uzbl.conf b/examples/duclare/uzbl.conf
new file mode 100644 (file)
index 0000000..1ce5944
--- /dev/null
@@ -0,0 +1,75 @@
+
+# example uzbl config. in a real config, we should obey the xdg spec
+
+# all keys in the behavior group are optional.  if not set, the corresponding behavior is disabed.
+# bindings_internal denote keys to trigger actions internally in uzbl
+# bindings_external denote keys to trigger scripts outside uzbl
+
+# keyboard behavior is vimstyle by default (all actions -> 1 key). set
+# always_insert_mode to always be in insert mode and disable going out of it.
+# if you do this, make sure you've set a modkey so you can reach the actions
+# from insert mode by combining them with the modkey
+
+[behavior]
+history_handler = /home/duclare/.uzbl/history.sh
+download_handler = ~/.uzbl/download.sh
+cookie_handler = ~/.uzbl/cookie.sh
+status_format = <span font_family="monospace"><span background="darkblue" foreground="white">MODE</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="blue">URI</span> <span foreground="blue" weight="bold">NAME</span></span>
+fifo_dir = /tmp
+socket_dir = /tmp
+always_insert_mode = 0
+modkey = Mod1
+show_status = 1
+status_top = 0
+never_reset_mode = 0
+
+[bindings]
+# scroll down/up/left/right
+j = scroll_vert 40
+k = scroll_vert -40
+h = scroll_horz -20
+l = scroll_horz 20
+b = back
+m = forward
+s = stop
+r = reload
+R = reload_ign_cache
+w = follow_link_new_window
++ = zoom_in
+- = zoom_out
+t = toggle_status
+#hilight matches
+/* = search %s
+#jump to next
+; = search
+gh      = uri http://www.uzbl.org
+o_     = uri %s
+:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go
+ew_ = uri http://en.wikipedia.org/w/index.php?title=Special%3ASearch&search=%s&go=Go
+
+g_    = uri http://www.google.com/search?q=%s
+i = insert_mode
+B = spawn /home/duclare/.uzbl/insert_bookmark.sh
+u = spawn /home/duclare/.uzbl/load_url_from_history.sh
+U = spawn /home/duclare/.uzbl/load_url_from_bookmarks.sh
+y = spawn /home/duclare/.uzbl/clipboard.sh yank
+p = spawn /home/duclare/.uzbl/clipboard.sh goto
+W = spawn /home/duclare/.uzbl/launch
+ZZ = exit
+:q = spawn /home/duclare/.uzbl/session.sh endsession
+
+# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now...
+# Vimperator-like hints, except that you can't type text to narrow on targets.  You can still the text of a link from the beginning, and it'll activate as soon as the word is unique
+f* = script var uzblid = 'uzbl_link_hint'; var uzbldivid = uzblid+'_div_container'; var links = document.links; try { HTMLElement.prototype.click = function () {if (typeof this.onclick == 'function') this.onclick({type: 'click'}); } } catch (e) {}  function removeOldHints() { var elements = document.getElementById(uzbldivid); if( elements) elements.parentNode.removeChild(elements); }  function keyPressHandler(e) {var kC  = (window.event) ? event.keyCode : e.keyCode; var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE; if(kC==Esc) removeOldHints();} function isVisible(obj) { if (obj == document) return true; if (!obj) return false; if (!obj.parentNode) return false; if (obj.style) { if (obj.style.display == 'none') return false; if (obj.style.visibility == 'hidden') return false; } return isVisible(obj.parentNode); }  function elementPosition(el) { var up = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while(el.offsetParent) { el = el.offsetParent; up += el.offsetTop; left += el.offsetLeft; } return [up,left,width,height]; }  function elementInViewport(el) { offset = elementPosition(el); var up = offset[0]; var left = offset[1]; var width = offset[2]; var height = offset[3]; return (up < (window.pageYOffset + window.innerHeight) && left < (window.pageXOffset + window.innerWidth) && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset); }  function generateHints(items, l) { var hintdiv = document.createElement('div'); hintdiv.setAttribute('id', uzbldivid); for (var i=0; i < items.length; i++) { var nr = items[i]; var li = links[nr]; var pos = elementPosition(li); var hint = document.createElement('div'); hint.setAttribute('name',uzblid); var n = (nr+'').length; for (n; n<l; n++) { nr = '0'+nr; } hint.innerText = nr; hint.style.display='inline'; hint.style.backgroundColor='#B9FF00'; hint.style.border='1px solid #4A6600'; hint.style.color='black'; hint.style.zIndex='1000'; hint.style.opacity='0.7'; hint.style.fontSize='11px'; hint.style.fontWeight='bold'; hint.style.lineHeight='9px'; hint.style.margin='0px'; hint.style.padding='1px'; hint.style.position='absolute'; hint.style.left=pos[1]+'px'; hint.style.top=pos[0]+'px'; var img = li.getElementsByTagName('img'); if (img.length>0) { hint.style.left=pos[1]+(img[0].width/2)+'px'; } hint.style.textDecoration='none'; hint.style.webkitBorderRadius='6px'; hint.style.webkitTransform='scale(0.9) rotate(0deg) translate(-6px,-5px)'; hintdiv.appendChild(hint); } document.body.appendChild(hintdiv); }  function clickLink(item) { removeOldHints(); if (item) { item.click(); window.location = item.href; } }  function followLink(follow) { document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); var s = follow.split(''); var linktexts = [[],[]]; for (var i=0; i < links.length; i++) { var li = links[i]; if (isVisible(li) && elementInViewport(li)) { linktexts[0].push(i); linktexts[1].push(li.innerText); } } var leftovers = []; var nrlength = (linktexts[0][linktexts[0].length-1]+'').length; var linknr = parseInt(follow, 10); if (s.length == nrlength) { clickLink(links[linknr]); } else { for (var j=0; j < linktexts[0].length; j++) { var b = true; for (var k=0; k < s.length; k++) { b = (b && (linktexts[1][j].charAt(k)==s[k])); } if (b) { leftovers.push(linktexts[0][j]); } } if (leftovers.length == 1 && s.length >= nrlength) { clickLink(links[leftovers[0]]); } else if (!document.getElementById(uzbldivid)) { generateHints(linktexts[0], nrlength); } } } followLink('%s');
+
+[network]
+# to start a local socks server, do : ssh -fND localhost:8118 localhost
+#proxy_server = http://127.0.0.1:8118
+#values 0-3
+http_debug = 0
+user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%)
+# Example user agent containing everything:
+#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%)
+max_conns = 
+max_conns_per_host = 
+
diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh
new file mode 100755 (executable)
index 0000000..0429f19
--- /dev/null
@@ -0,0 +1,10 @@
+# use this script to pipe any variable to xclip, so you have it in your clipboard
+exit
+# this script is not done yet
+
+# can we make this universal?
+# add xclip to optdeps
+
+which xclip &>/dev/null || exit 1
+
+echo -n `eval "$3"` #| xclip
\ No newline at end of file
diff --git a/uzbl.c b/uzbl.c
index c55c572..0a11099 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -272,12 +272,26 @@ progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
 }
 
 static void
+load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
+    (void) page;
+    (void) data;
+    if (uzbl.behave.load_finish_handler) {
+        run_command_async(uzbl.behave.load_finish_handler, NULL);
+    }
+}
+
+static void
 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
     (void) page;
     (void) data;
     free (uzbl.state.uri);
     GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
     uzbl.state.uri = g_string_free (newuri, FALSE);
+    if ((!uzbl.behave.never_reset_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?
 }
 
 static void
@@ -676,7 +690,10 @@ setup_regex() {
             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("^CMD\\s+([^ \\n]+)\\s*([^\\n]*)?$",
+            G_REGEX_OPTIMIZE, 0, &err);
 }
+
 static gboolean
 get_var_value(gchar *name) {
     void **p = NULL;
@@ -758,6 +775,16 @@ parse_cmd_line(char *ctl_line) {
         else 
             printf("Error in command: %s\n", tokens[0]);
     }
+    /* CMD command */
+    else if(ctl_line[0] == 'C') {
+        tokens = g_regex_split(uzbl.comm.cmd_regex, ctl_line, 0);
+        if(tokens[0][0] == 0) {
+            parse_command(tokens[1], tokens[2]);
+            g_strfreev(tokens);
+        }
+        else
+            printf("Error in command: %s\n", tokens[0]);
+    }
     /* Comments */
     else if(   (ctl_line[0] == '#')
             || (ctl_line[0] == ' ')
@@ -1044,7 +1071,7 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
     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_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right || event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R)
         return FALSE;
 
     /* turn off insert mode (if always_insert_mode is not used) */
@@ -1054,7 +1081,7 @@ key_press_cb (WebKitWebView* page, 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)))
         return FALSE;
 
     if (event->keyval == GDK_Escape) {
@@ -1082,49 +1109,61 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event)
     if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
         g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
         update_title();
-        return TRUE;
     }
 
-    if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) {
-        GString* short_keys = g_string_new ("");
-        unsigned int i;
-        for (i=0; i<(uzbl.state.keycmd->len); i++) {
-            g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
-            g_string_append_c(short_keys, '_');
-            
-            //printf("\nTesting string: @%s@\n", short_keys->str);
-            if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
-                GString* parampart = g_string_new (uzbl.state.keycmd->str);
-                g_string_erase (parampart, 0, i+1);
-                //printf("\nParameter: @%s@\n", parampart->str);
-                GString* actionname = g_string_new ("");
-                if (action->name)
-                    g_string_printf (actionname, action->name, parampart->str);
-                GString* actionparam = g_string_new ("");
-                if (action->param)
-                    g_string_printf (actionparam, action->param, parampart->str);
-                parse_command(actionname->str, actionparam->str);
-                g_string_free (actionname, TRUE);
-                g_string_free (actionparam, TRUE);
-                g_string_free (parampart, TRUE);
-                g_string_truncate(uzbl.state.keycmd, 0);
-                update_title();
-            }          
-
-            g_string_truncate(short_keys, short_keys->len - 1);
-        }
-        g_string_free (short_keys, TRUE);
-        return (!uzbl.behave.insert_mode);
-    }
+    gboolean key_ret = FALSE;
+    if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
+        key_ret = TRUE;
 
-    g_string_append(uzbl.state.keycmd, event->string);
+    if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
     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);
     }
 
-    update_title();
+    GString* short_keys = g_string_new ("");
+    GString* short_keys_inc = g_string_new ("");
+    unsigned int i;
+    for (i=0; i<(uzbl.state.keycmd->len); i++) {
+        g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
+        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
+        } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
+            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
+        }
 
+        if (exec_now) {
+            GString* parampart = g_string_new (uzbl.state.keycmd->str);
+            GString* actionname = g_string_new ("");
+            GString* actionparam = g_string_new ("");
+            g_string_erase (parampart, 0, i+1);
+            if (action->name)
+                g_string_printf (actionname, action->name, parampart->str);
+            if (action->param)
+                g_string_printf (actionparam, action->param, parampart->str);
+            parse_command(actionname->str, actionparam->str);
+            g_string_free (actionname, TRUE);
+            g_string_free (actionparam, TRUE);
+            g_string_free (parampart, TRUE);
+            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;
 }
 
@@ -1142,6 +1181,7 @@ create_browser () {
     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 (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); 
@@ -1252,6 +1292,7 @@ settings_init () {
     }
 
     if (res) {
+        b->load_finish_handler= g_key_file_get_value   (config, "behavior", "load_finish_handler",NULL);
         b->history_handler    = g_key_file_get_value   (config, "behavior", "history_handler",    NULL);
         b->download_handler   = g_key_file_get_value   (config, "behavior", "download_handler",   NULL);
         b->cookie_handler     = g_key_file_get_string  (config, "behavior", "cookie_handler",     NULL);
@@ -1259,6 +1300,7 @@ settings_init () {
         b->show_status        = g_key_file_get_boolean (config, "behavior", "show_status",        NULL);
         b->modkey             = g_key_file_get_value   (config, "behavior", "modkey",             NULL);
         b->status_top         = g_key_file_get_boolean (config, "behavior", "status_top",         NULL);
+        b->never_reset_mode   = g_key_file_get_boolean (config, "behavior", "never_reset_mode",   NULL);
         b->status_format      = g_key_file_get_string  (config, "behavior", "status_format",      NULL);
         b->status_background  = g_key_file_get_string  (config, "behavior", "status_background",  NULL);
         if (! b->fifo_dir)
@@ -1274,10 +1316,11 @@ settings_init () {
     printf ("Fifo directory: %s\n",     (b->fifo_dir           ? b->fifo_dir         : "disabled"));
     printf ("Socket directory: %s\n",   (b->socket_dir         ? b->socket_dir       : "disabled"));
     printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE"              : "FALSE"));
+    printf ("Don't reset mode: %s\n",   (b->never_reset_mode   ? "TRUE"              : "FALSE"));
     printf ("Show status: %s\n",        (b->show_status        ? "TRUE"              : "FALSE"));
     printf ("Status top: %s\n",         (b->status_top         ? "TRUE"              : "FALSE"));
     printf ("Modkey: %s\n",             (b->modkey             ? b->modkey           : "disabled"));
-    printf ("Status format: %s\n",             (b->status_format            ? b->status_format           : "none"));
+    printf ("Status format: %s\n",      (b->status_format      ? b->status_format    : "none"));
 
     if (!b->modkey)
         b->modkey = "";
@@ -1441,7 +1484,7 @@ main (int argc, char* argv[]) {
     /* 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.net.soup_session = webkit_get_default_session();
     uzbl.state.keycmd = g_string_new("");
 
     settings_init ();
diff --git a/uzbl.h b/uzbl.h
index 7c6b811..d9b4b06 100644 (file)
--- a/uzbl.h
+++ b/uzbl.h
@@ -62,7 +62,8 @@ typedef struct {
     /* stores (key)"variable name" -> (value)"pointer to this var*/
     GHashTable     *proto_var;
     /* command parsing regexes */
-    GRegex         *set_regex; 
+    GRegex         *set_regex;
+    GRegex         *cmd_regex;
     GRegex         *get_regex; 
     GRegex         *bind_regex; 
 } Communication;
@@ -95,6 +96,7 @@ typedef struct {
 
 /* behaviour */
 typedef struct {
+    gchar*   load_finish_handler;
     gchar*   status_format;
     gchar*   status_background;
     gchar*   history_handler;
@@ -106,6 +108,7 @@ typedef struct {
     gboolean show_status;
     gboolean insert_mode;
     gboolean status_top;
+    gboolean never_reset_mode;
     gchar*   modkey;
     guint    modmask;
     guint    http_debug;
@@ -179,6 +182,9 @@ static void
 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data);
 
 static void
+load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data);
+
+static void
 destroy_cb (GtkWidget* widget, gpointer data);
 
 static void