aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--AUTHORS9
-rw-r--r--Makefile4
-rw-r--r--README13
-rw-r--r--TODO5
-rw-r--r--docs/config-syntax56
-rw-r--r--examples/configs/sampleconfig70
-rw-r--r--examples/configs/sampleconfig-dev117
-rwxr-xr-xexamples/scripts/clipboard.sh15
-rwxr-xr-xexamples/scripts/load_url_from_bookmarks.sh12
-rwxr-xr-xexamples/scripts/load_url_from_history.sh13
-rwxr-xr-xexamples/scripts/session.sh42
-rw-r--r--uzbl.c903
-rw-r--r--uzbl.h86
13 files changed, 893 insertions, 452 deletions
diff --git a/AUTHORS b/AUTHORS
index ff39641..8a470d0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,12 +1,13 @@
Developers:
- Dieter Plaetinck (Dieter@be) <dieter@plaetinck.be>
+ Dieter Plaetinck (Dieter@be) <email is dieter AT plaetinck.be>
Dusan Popovic (dusanx)
- Michael Walker (Barrucadu) <mike@barrucadu.co.uk>
- Přemysl Hrubý, (anydot) <dfenze@gmail.com>
+ Michael Walker (Barrucadu) <email is mike AT barrucadu.co.uk>
+ Přemysl Hrubý, (anydot) <email is dfenze AT gmail.com>
+ Robert Manea (robm)
Contributors:
- Robert Manea - Various improvements
+ (DuClare) - Various improvements
Zane Ashby (HashBox) - Rewrote FIFO interface. Fixed various bugs.
(sentientswitch) - Cleaned up code. Added some commands.
Jan Kolkmeier (jouz) - scrolling, link following
diff --git a/Makefile b/Makefile
index 622a79a..2d6b8c9 100644
--- a/Makefile
+++ b/Makefile
@@ -6,10 +6,10 @@ test: uzbl
./uzbl --uri http://www.uzbl.org
test-config: uzbl
- ./uzbl --uri http://www.uzbl.org --config examples/configs/sampleconfig-dev
+ ./uzbl --uri http://www.uzbl.org < examples/configs/sampleconfig-dev
test-config-real: uzbl
- ./uzbl --uri http://www.uzbl.org --config /usr/share/uzbl/examples/configs/sampleconfig
+ ./uzbl --uri http://www.uzbl.org < /usr/share/uzbl/examples/configs/sampleconfig
clean:
rm -f uzbl
diff --git a/README b/README
index 42db76a..60ed089 100644
--- a/README
+++ b/README
@@ -128,3 +128,16 @@ KNOWN BUGS
- Something in the FIFO code causes CPU usage to jump.
Report new issues @ uzbl.org/bugs
+
+
+VALGRIND PROFILING
+add this to Makefile header: CFLAGS=-g
+recompile
+valgrind --tool=callgrind ./uzbl ....
+kcachegrind callgrind.out.foo
+
+CONFIG FILE
+** Variable replacement and markup format
+See http://library.gnome.org/devel/pango/stable/PangoMarkupFormat.html for
+what you can do, markup wise.
+TODO: document possible variables, and what you can do with useragent/title/statusbar
diff --git a/TODO b/TODO
index f757a2d..6e4004d 100644
--- a/TODO
+++ b/TODO
@@ -52,6 +52,11 @@
+* config: check in the default place (XDG_CONFIG_HOME/..) for a config file, and if needed, do file reading (interpret line by line). not ini-based.
+* readd the --config flag to allow entering the same commands either through the file/stdin/fifo/socket
+* check for real command name, not just the first letter.
+
+
SOMEDAY:
check if we can make the settings loading less hard coded. eg( keep a list of all settings, and for each one, try to load it)
figure out caching with webkit and in general how we can speed up everything
diff --git a/docs/config-syntax b/docs/config-syntax
new file mode 100644
index 0000000..30cf91f
--- /dev/null
+++ b/docs/config-syntax
@@ -0,0 +1,56 @@
+Configuration setting at startup and changing at runtime happens through one of these:
+- stdin at startup (TODO: see if we can keep listening while running) (write command to it + "\n")
+- fifo (write command to it + "\n")
+- socket (uzblctrl -s <file> -c <comand>
+
+Lines written to the above starting with '#' or being empty, are ignored.
+
+** Command syntax:
+commands can have no, one or 2 arguments.
+
+<command>[\t<arg1>[\t<arg2>]]
+
+The 'bind' command is a special command, where argument 1 is a keyboard character (combo) and argument 2 is a command as specified above.
+You can also use a '_' in the <chars> part to denote where you pass on whatever you want, which will be replaced into the specififed command whereever %s is mentioned
+
+** commands
+Commands where one of the arguments is "parameter" expect this arugment to be a valid variable identifier (eg uzbl.behave.status_format)
+
+set parameter value # make sure the value complies with the datatype.
+toggle parameter # expects parameter to be a gboolean. (eg status, insert_mode, ..)
+get parameter
+bind <chars> <command>
+script <JS code to execute>
+script_file <filename containing JS code to execute>
+back
+forward
+scroll_vert <int>
+scroll_horz <int>
+reload
+reload_ign_cache
+stop
+zoom_in
+zoom_out
+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.
+
+
+
+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/configs/sampleconfig b/examples/configs/sampleconfig
deleted file mode 100644
index 92a7cfc..0000000
--- a/examples/configs/sampleconfig
+++ /dev/null
@@ -1,70 +0,0 @@
-
-# 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 = /usr/share/uzbl/examples/scripts/history.sh
-download_handler = /usr/share/uzbl/examples/scripts/download.sh
-cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh
-status_format = <span font_family="monospace"><span background="khaki" foreground="black">MODE</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="#99FF66">URI</span> <span foreground="khaki">NAME</span></span>
-# you can optionally use this setting to override the background color of the statusbar from your GTK theme.
-status_background = #303030
-fifo_dir = /tmp
-socket_dir = /tmp
-always_insert_mode = 0
-modkey = Mod1
-show_status = 1
-status_top = 0
-
-[bindings]
-# scroll down/up/left/right
-j = scroll_vert 20
-k = scroll_vert -20
-h = scroll_horz -20
-l = scroll_horz 20
-b = back
-m = forward
-s = stop
-r = reload
-R = reload_ign_cache
-+ = 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
-gg _ = uri http://www.google.com/search?q=%s
-i = insert_mode
-B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh
-u = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh
-U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh
-ZZ = exit
-S = script alert("hi");
-
-# 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...
-#hit F to toggle the Hints (now in form of link numbering)
-F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}}
-#hit f followed by linknumber and ENTER to follow that link
-f_ = script window.location = document.links[%s].href;
-
-[network]
-proxy_server =
-#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/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev
index 69c7362..761a4f9 100644
--- a/examples/configs/sampleconfig-dev
+++ b/examples/configs/sampleconfig-dev
@@ -1,72 +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
+# all settings are optional. you can use uzbl without any config at all (but it won't do much)
# 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 = ./examples/scripts/history.sh
-download_handler = ./examples/scripts/download.sh
-cookie_handler = ./examples/scripts/cookies.sh
-fifo_dir = /tmp
-socket_dir = /tmp
-always_insert_mode = 0
-modkey = Mod1
-show_status = 1
-status_top = 0
-status_format = <span font_family="monospace"><span background="khaki" foreground="black">MODE</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="#99FF66">URI</span> <span foreground="khaki">NAME</span></span>
-# you can optionally use this setting to override the background color of the statusbar from your GTK theme.
-status_background = #303030
+# TODO: ability to attach misc things (spawn <foo>, script <bar>,.. to internal events)
+set history_handler = ./examples/scripts/history.sh
+set download_handler = ./examples/scripts/download.sh
+set cookie_handler = ./examples/scripts/cookies.sh
-[bindings]
-# scroll down/up/left/right
-j = scroll_vert 20
-k = scroll_vert -20
-h = scroll_horz -20
-l = scroll_horz 20
-b = back
-m = forward
-s = stop
-r = reload
-R = reload_ign_cache
-+ = 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
-gg _ = uri http://www.google.com/search?q=%s
-i = insert_mode
-B = spawn ./examples/scripts/insert_bookmark.sh
-u = spawn ./examples/scripts/load_url_from_history.sh
-U = spawn ./examples/scripts/load_url_from_bookmarks.sh
-ZZ = exit
-S = script alert("hi");
-# 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...
-#hit F to toggle the Hints (now in form of link numbering)
-F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}}
-#hit f followed by linknumber and ENTER to follow that link
-f_ = script window.location = document.links[%s].href;
-[network]
+# Behaviour and appearance
+set show_status = 1
+# you can optionally use this setting to override the background color of the statusbar from your GTK theme.
+set status_background = #303030
+set status_format = <span font_family="monospace"><span background="khaki" foreground="black">MODE</span> [<span weight="bold" foreground="red">KEYCMD</span>] <span foreground="#606060"> LOAD_PROGRESSBAR </span><span foreground="#99FF66">URI</span> <span foreground="khaki">NAME</span> <span foreground="orange">MSG</span></span>
+set status_top = 0
+
+set modkey = Mod1
+# reset to command mode when new page is loaded
+set reset_command_mode = 1
+# this var has precedence over reset_command_mode
+set always_insert_mode = 0
# to start a local socks server, do : ssh -fND localhost:8118 localhost
-#proxy_server = http://127.0.0.1:8118
+#set proxy_url = http://127.0.0.1:8118
#values 0-3
-http_debug = 0
-user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%)
+#set http_debug = 0
+#set useragent 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 =
+#set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%)
+#set max_conns 0
+#set max_conns_host 0
+
+set fifo_dir = /tmp
+set socket_dir = /tmp
+# Key bindings
+bind j = scroll_vert 20
+bind k = scroll_vert -20
+bind h = scroll_horz -20
+bind l = scroll_horz 20
+bind b = back
+bind m = forward
+bind s = stop
+bind r = reload
+bind R = reload_ign_cache
+bind + = zoom_in
+bind - = zoom_out
+bind t = toggle_status
+#hilight matches
+bind /_ = search %s
+#jump to next
+bind ; = search
+bind gh = uri http://www.uzbl.org
+#TODO: set uri?
+bind o _ = uri %s
+bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go
+bind gg _ = uri http://www.google.com/search?q=%s
+bind i = insert_mode
+#TODO: no 'toggle' command?
+bind B = spawn ./examples/scripts/insert_bookmark.sh
+bind u = spawn ./examples/scripts/load_url_from_history.sh
+bind U = spawn ./examples/scripts/load_url_from_bookmarks.sh
+bind ZZ = exit
+bind S = script alert("hi");
+# 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...
+#hit F to toggle the Hints (now in form of link numbering)
+bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}}
+#hit f followed by linknumber and ENTER to follow that link
+bind f_ = script window.location = document.links[%s].href;
diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh
new file mode 100755
index 0000000..c64b65c
--- /dev/null
+++ b/examples/scripts/clipboard.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard.
+
+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/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh
index 35c772c..2d19067 100755
--- a/examples/scripts/load_url_from_bookmarks.sh
+++ b/examples/scripts/load_url_from_bookmarks.sh
@@ -1,5 +1,11 @@
#!/bin/bash
+if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'
+then
+ DMENU="dmenu -i -xs -rs -l 10" # vertical patch
+else
+ DMENU="dmenu -i"
+fi
# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks)
if [ -f /usr/share/uzbl/examples/data/bookmarks ]
then
@@ -8,6 +14,6 @@ else
file=./examples/data/bookmarks #useful when developing
fi
-goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes.
-#[ -n "$goto" ] && echo "uri $goto" > $4
-[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto"
+goto=`awk '{print $1}' $file | $DMENU` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes.
+#[ -n "$goto" ] && echo "cmd uri $goto" > $4
+[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto"
diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh
index 3e2e2ee..9dd56d2 100755
--- a/examples/scripts/load_url_from_history.sh
+++ b/examples/scripts/load_url_from_history.sh
@@ -2,10 +2,17 @@
# you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history)
history_file=/tmp/uzbl.history
+if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'
+then
+ DMENU="dmenu -i -xs -rs -l 10" # vertical patch
+else
+ DMENU="dmenu -i"
+fi
+
# choose from all entries, sorted and uniqued
# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i`
# choose from all entries, the first one being current url, and after that all others, sorted and uniqued.
-current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | dmenu -i`
-#[ -n "$goto" ] && echo "uri $goto" > $4
-[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto"
+current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU`
+#[ -n "$goto" ] && echo "cmd uri $goto" > $4
+[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto"
diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh
new file mode 100755
index 0000000..5087af0
--- /dev/null
+++ b/examples/scripts/session.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Very 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=$XDG_CONFIG_HOME/uzbl/session.sh # this script
+sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored
+UZBL="uzbl" # add custom flags and whatever here.
+
+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
+ $UZBL --uri "$url" &
+ done
+ exit 0;;
+ "endinstance" )
+ if [ "$url" != "(null)" ]; then
+ echo "$url" >> $sessionfile;
+ fi
+ echo "exit" > "$thisfifo"
+ ;;
+ "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/uzbl.c b/uzbl.c
index a8ad802..4c65c39 100644
--- a/uzbl.c
+++ b/uzbl.c
@@ -58,6 +58,67 @@
static Uzbl uzbl;
+/* define names and pointers to all config specific variables */
+const struct {
+ char *name;
+ void **ptr;
+} var_name_to_ptr[] = {
+ { "uri", (void *)&uzbl.state.uri },
+ { "status_message", (void *)&uzbl.gui.sbar.msg },
+ { "show_status", (void *)&uzbl.behave.show_status },
+ { "status_top", (void *)&uzbl.behave.status_top },
+ { "status_format", (void *)&uzbl.behave.status_format },
+ { "status_background", (void *)&uzbl.behave.status_background },
+ { "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 },
+ { "modkey" , (void *)&uzbl.behave.modkey },
+ { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler},
+ { "history_handler", (void *)&uzbl.behave.history_handler },
+ { "download_handler", (void *)&uzbl.behave.download_handler },
+ { "cookie_handler", (void *)&uzbl.behave.cookie_handler },
+ { "fifo_dir", (void *)&uzbl.behave.fifo_dir },
+ { "socket_dir", (void *)&uzbl.behave.socket_dir },
+ { "http_debug", (void *)&uzbl.behave.http_debug },
+ { "proxy_url", (void *)&uzbl.net.proxy_url },
+ { "max_conns", (void *)&uzbl.net.max_conns },
+ { "max_conns_host", (void *)&uzbl.net.max_conns_host },
+ { "useragent", (void *)&uzbl.net.useragent },
+ { NULL, NULL }
+}, *n2v_p = var_name_to_ptr;
+
+const struct {
+ char *key;
+ guint mask;
+} modkeys[] = {
+ { "SHIFT", GDK_SHIFT_MASK }, // shift
+ { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
+ { "CONTROL", GDK_CONTROL_MASK }, // control
+ { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
+ { "MOD2", GDK_MOD2_MASK }, // 5th mod
+ { "MOD3", GDK_MOD3_MASK }, // 6th mod
+ { "MOD4", GDK_MOD4_MASK }, // 7th mod
+ { "MOD5", GDK_MOD5_MASK }, // 8th mod
+ { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
+ { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
+ { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
+ { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
+ { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
+ { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
+ { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
+ { "META", GDK_META_MASK }, // meta (since 2.10)
+ { NULL, NULL }
+};
+
+/* construct a hash from the var_name_to_ptr array for quick access */
+static void
+make_var_to_name_hash() {
+ 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, n2v_p->ptr);
+ n2v_p++;
+ }
+}
/* commandline arguments (set initial values for the state variables) */
static GOptionEntry entries[] =
@@ -85,11 +146,6 @@ itos(int val) {
return g_strdup(tmp);
}
-static char *
-str_replace (const char* search, const char* replace, const char* string) {
- return g_strjoinv (replace, g_strsplit(string, search, -1));
-}
-
static sigfunc*
setup_signal(int signr, sigfunc *shandler) {
struct sigaction nh, oh;
@@ -180,19 +236,38 @@ scroll (GtkAdjustment* bar, const char *param) {
gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
}
+static void scroll_begin(WebKitWebView* page, const char *param) {
+ (void) page; (void) param;
+ gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
+}
+
+static void scroll_end(WebKitWebView* page, const char *param) {
+ (void) page; (void) param;
+ gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
+ gtk_adjustment_get_page_size(uzbl.gui.bar_v));
+}
+
static void scroll_vert(WebKitWebView* page, const char *param) {
(void) page;
-
scroll(uzbl.gui.bar_v, param);
}
static void scroll_horz(WebKitWebView* page, const char *param) {
(void) page;
-
scroll(uzbl.gui.bar_h, param);
}
static void
+cmd_set_status() {
+ if (!uzbl.behave.show_status) {
+ gtk_widget_hide(uzbl.gui.mainbar);
+ } else {
+ gtk_widget_show(uzbl.gui.mainbar);
+ }
+ update_title();
+}
+
+static void
toggle_status_cb (WebKitWebView* page, const char *param) {
(void)page;
(void)param;
@@ -239,12 +314,27 @@ progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
}
static void
+load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
+ (void) page;
+ (void) frame;
+ (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.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?
}
static void
@@ -291,6 +381,8 @@ static struct {char *name; Command command;} cmdlist[] =
{ "forward", view_go_forward },
{ "scroll_vert", scroll_vert },
{ "scroll_horz", scroll_horz },
+ { "scroll_begin", scroll_begin },
+ { "scroll_end", scroll_end },
{ "reload", view_reload, },
{ "reload_ign_cache", view_reload_bypass_cache},
{ "stop", view_stop_loading, },
@@ -302,7 +394,8 @@ static struct {char *name; Command command;} cmdlist[] =
{ "spawn", spawn },
{ "exit", close_uzbl },
{ "search", search_text },
- { "insert_mode", set_insert_mode }
+ { "insert_mode", set_insert_mode },
+ { "runcmd", runcmd }
};
static void
@@ -491,15 +584,14 @@ setup_scanner() {
}
static gchar *
-parse_status_template(const char *template) {
+expand_template(const char *template) {
+ if(!template) return NULL;
+
GTokenType token = G_TOKEN_NONE;
GString *ret = g_string_new("");
- gchar *buf=NULL;
+ char *buf=NULL;
int sym;
- if(!template)
- return NULL;
-
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);
@@ -513,7 +605,9 @@ parse_status_template(const char *template) {
g_markup_printf_escaped("%s", uzbl.state.uri):"");
break;
case SYM_LOADPRGS:
- g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
+ buf = itos(uzbl.gui.sbar.load_progress);
+ g_string_append(ret, buf);
+ free(buf);
break;
case SYM_LOADPRGSBAR:
buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
@@ -526,8 +620,10 @@ parse_status_template(const char *template) {
g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
break;
case SYM_NAME:
+ buf = itos(uzbl.xwin);
g_string_append(ret,
- uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin));
+ uzbl.state.instance_name?uzbl.state.instance_name:buf);
+ free(buf);
break;
case SYM_KEYCMD:
g_string_append(ret,
@@ -538,12 +634,60 @@ parse_status_template(const char *template) {
g_string_append(ret,
uzbl.behave.insert_mode?"[I]":"[C]");
break;
+ case SYM_MSG:
+ g_string_append(ret,
+ uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
+ break;
+ /* useragent syms */
+ case SYM_WK_MAJ:
+ buf = itos(WEBKIT_MAJOR_VERSION);
+ g_string_append(ret, buf);
+ free(buf);
+ break;
+ case SYM_WK_MIN:
+ buf = itos(WEBKIT_MINOR_VERSION);
+ g_string_append(ret, buf);
+ free(buf);
+ break;
+ case SYM_WK_MIC:
+ buf = itos(WEBKIT_MICRO_VERSION);
+ g_string_append(ret, buf);
+ free(buf);
+ break;
+ case SYM_SYSNAME:
+ g_string_append(ret, uzbl.state.unameinfo.sysname);
+ break;
+ case SYM_NODENAME:
+ g_string_append(ret, uzbl.state.unameinfo.nodename);
+ break;
+ case SYM_KERNREL:
+ g_string_append(ret, uzbl.state.unameinfo.release);
+ break;
+ case SYM_KERNVER:
+ g_string_append(ret, uzbl.state.unameinfo.version);
+ break;
+ case SYM_ARCHSYS:
+ g_string_append(ret, uzbl.state.unameinfo.machine);
+ break;
+ case SYM_ARCHUZBL:
+ g_string_append(ret, ARCH);
+ break;
+#ifdef _GNU_SOURCE
+ case SYM_DOMAINNAME:
+ g_string_append(ret, uzbl.state.unameinfo.domainname);
+ break;
+#endif
+ case SYM_COMMIT:
+ g_string_append(ret, COMMIT);
+ break;
default:
break;
}
}
else if(token == G_TOKEN_INT) {
- g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
+ buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
+ g_string_append(ret, buf);
+ free(buf);
}
else if(token == G_TOKEN_IDENTIFIER) {
g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
@@ -610,65 +754,259 @@ parse_command(const char *cmd, const char *param) {
fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
}
+/* command parser */
static void
-parse_line(char *line) {
- gchar **parts;
+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.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_strstrip(line);
+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)) {
+ printf("VAR: %s VALUE: %s\n", name, (char *)*p);
+ } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
+ }
+ return TRUE;
+}
- parts = g_strsplit(line, " ", 2);
+static void
+set_proxy_url() {
+ SoupURI *suri;
- if (!parts)
- return;
+ if(*uzbl.net.proxy_url == ' '
+ || uzbl.net.proxy_url == NULL) {
+ soup_session_remove_feature_by_type(uzbl.net.soup_session,
+ (GType) SOUP_SESSION_PROXY_URI);
+ }
+ else {
+ suri = soup_uri_new(uzbl.net.proxy_url);
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ SOUP_SESSION_PROXY_URI,
+ suri, NULL);
+ soup_uri_free(suri);
+ }
+ return;
+}
- parse_command(parts[0], parts[1]);
- g_strfreev(parts);
+static void
+move_statusbar() {
+ 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);
+
+ if(uzbl.behave.status_top) {
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
+ }
+ else {
+ 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);
+ }
+ gtk_widget_unref(uzbl.gui.scrolled_win);
+ gtk_widget_unref(uzbl.gui.mainbar);
+ gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
}
-void
-build_stream_name(int type) {
- char *xwin_str;
- State *s = &uzbl.state;
- Behaviour *b = &uzbl.behave;
+static gboolean
+var_is(const char *x, const char *y) {
+ return (strcmp(x, y) == 0 ? TRUE : FALSE );
+}
- xwin_str = itos((int)uzbl.xwin);
- switch(type) {
- case FIFO:
- if (b->fifo_dir) {
- sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s",
- b->fifo_dir,
- s->instance_name ? s->instance_name : xwin_str);
- } else {
- sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s",
- s->instance_name ? s->instance_name : xwin_str);
+static gboolean
+set_var_value(gchar *name, gchar *val) {
+ void **p = NULL;
+ char *endp = 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("load_finish_handler", name)
+ || var_is("history_handler", name)
+ || var_is("download_handler", name)
+ || var_is("cookie_handler", name)) {
+ if(*p)
+ 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);
+ set_proxy_url();
+ }
+ else if(var_is("fifo_dir", name)) {
+ if(*p) free(*p);
+ *p = init_fifo(g_strdup(val));
+ }
+ else if(var_is("socket_dir", name)) {
+ if(*p) free(*p);
+ *p = init_socket(g_strdup(val));
+ }
+ else if(var_is("modkey", name)) {
+ if(*p) free(*p);
+ int i;
+ *p = g_utf8_strup(val, -1);
+ uzbl.behave.modmask = 0;
+ for (i = 0; modkeys[i].key != NULL; i++) {
+ if (g_strrstr(*p, modkeys[i].key))
+ uzbl.behave.modmask |= modkeys[i].mask;
}
- break;
+ }
+ else if(var_is("useragent", name)) {
+ if(*p) free(*p);
+ *p = set_useragent(g_strdup(val));
+ }
+ /* variables that take int values */
+ else {
+ int *ip = (int *)p;
+ *ip = (int)strtoul(val, &endp, 10);
- case SOCKET:
- if (b->socket_dir) {
- sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s",
- b->socket_dir,
- s->instance_name ? s->instance_name : xwin_str);
- } else {
- sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s",
- s->instance_name ? s->instance_name : xwin_str);
+ if(var_is("show_status", name)) {
+ cmd_set_status();
}
- break;
- default:
- break;
+ else if(var_is("always_insert_mode", name)) {
+ uzbl.behave.insert_mode =
+ uzbl.behave.always_insert_mode ? TRUE : FALSE;
+ update_title();
+ }
+ else if (var_is("max_conns", name)) {
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
+ }
+ else if (var_is("max_conns_host", name)) {
+ g_object_set(G_OBJECT(uzbl.net.soup_session),
+ 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));
+ }
+ else if (var_is("status_top", name)) {
+ move_statusbar();
+ }
+ }
}
- g_free(xwin_str);
+ return TRUE;
}
static void
+runcmd(WebKitWebView* page, const char *param) {
+ (void) page;
+ parse_cmd_line(param);
+}
+
+static void
+parse_cmd_line(const char *ctl_line) {
+ gchar **tokens;
+
+ /* SET command */
+ if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
+ tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
+ if(tokens[0][0] == 0) {
+ set_var_value(tokens[1], tokens[2]);
+ g_strfreev(tokens);
+ }
+ else
+ printf("Error in command: %s\n", tokens[0]);
+ }
+ /* GET command */
+ else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
+ tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
+ if(tokens[0][0] == 0) {
+ get_var_value(tokens[1]);
+ g_strfreev(tokens);
+ }
+ 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);
+ if(tokens[0][0] == 0) {
+ add_binding(tokens[1], tokens[2]);
+ g_strfreev(tokens);
+ }
+ 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);
+ 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] == ' ')
+ || (ctl_line[0] == '\n'))
+ ; /* ignore these lines */
+ else
+ printf("Command not understood (%s)\n", ctl_line);
+
+ return;
+}
+
+static gchar*
+build_stream_name(int type, const gchar* dir) {
+ char *xwin_str;
+ State *s = &uzbl.state;
+ gchar *str;
+
+ xwin_str = itos((int)uzbl.xwin);
+ if (type == FIFO) {
+ str = g_strdup_printf
+ ("%s/uzbl_fifo_%s", dir,
+ s->instance_name ? s->instance_name : xwin_str);
+ } else if (type == SOCKET) {
+ str = g_strdup_printf
+ ("%s/uzbl_socket_%s", dir,
+ s->instance_name ? s->instance_name : xwin_str );
+ }
+ g_free(xwin_str);
+ return str;
+}
+
+static gboolean
control_fifo(GIOChannel *gio, GIOCondition condition) {
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)
@@ -678,41 +1016,90 @@ control_fifo(GIOChannel *gio, GIOCondition condition) {
if (ret == G_IO_STATUS_ERROR)
g_error ("Fifo: Error reading: %s\n", err->message);
- parse_line(ctl_line);
+ parse_cmd_line(ctl_line);
g_free(ctl_line);
- printf("...done\n");
- return;
+
+ return TRUE;
}
-static void
-create_fifo() {
+static 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)
+ g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
+ g_free(uzbl.comm.fifo_path);
+ uzbl.comm.fifo_path = 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.
+ 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);
+ uzbl.comm.fifo_path = path;
+ return dir;
+ } else g_warning ("init_fifo: could not add watch on %s\n", path);
+ } else g_warning ("init_fifo: can't open: %s\n", error->message);
+ } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
+ } else g_warning ("init_fifo: can't create %s: file exists\n", path);
+
+ /* if we got this far, there was an error; cleanup */
+ g_free(path);
+ g_free(dir);
+ return NULL;
+}
- build_stream_name(FIFO);
- if (file_exists(uzbl.comm.fifo_path)) {
- g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path);
- return;
+static gboolean
+control_stdin(GIOChannel *gio, GIOCondition 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;
}
- if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) {
- g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno));
- } else {
- // 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((gchar *) uzbl.comm.fifo_path, "r+", &error);
- if (chan) {
- if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
- g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path);
- } else {
- printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path);
- }
+
+ ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
+ if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
+ return FALSE;
+
+ parse_cmd_line(ctl_line);
+ g_free(ctl_line);
+
+ return TRUE;
+}
+
+static void
+create_stdin () {
+ GIOChannel *chan = NULL;
+ GError *error = NULL;
+
+ chan = g_io_channel_unix_new(fileno(stdin));
+ if (chan) {
+ 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 {
- g_error ("Fifo: Error while opening: %s\n", error->message);
+ printf ("Stdin: watch added successfully\n");
}
+ } else {
+ g_error ("Stdin: Error while opening: %s\n", error->message);
}
- return;
}
-static void
+static gboolean
control_socket(GIOChannel *chan) {
struct sockaddr_un remote;
char buffer[512], *ctl_line;
@@ -746,7 +1133,7 @@ control_socket(GIOChannel *chan) {
}
close (clientsock);
ctl_line = g_strdup(buffer);
- parse_line (ctl_line);
+ parse_cmd_line (ctl_line);
/*
TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
@@ -763,34 +1150,50 @@ control_socket(GIOChannel *chan) {
*/
g_free(ctl_line);
- return;
-}
+ return TRUE;
+}
+
+static 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)
+ g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
+ g_free(uzbl.comm.socket_path);
+ uzbl.comm.socket_path = NULL;
+ }
+
+ if (*dir == ' ') {
+ g_free(dir);
+ return NULL;
+ }
-static void
-create_socket() {
GIOChannel *chan = NULL;
int sock, len;
struct sockaddr_un local;
-
- build_stream_name(SOCKET);
+ gchar *path = build_stream_name(SOCKET, dir);
+
sock = socket (AF_UNIX, SOCK_STREAM, 0);
local.sun_family = AF_UNIX;
- strcpy (local.sun_path, uzbl.comm.socket_path);
+ strcpy (local.sun_path, path);
unlink (local.sun_path);
len = strlen (local.sun_path) + sizeof (local.sun_family);
- bind (sock, (struct sockaddr *) &local, len);
-
- if (errno == -1) {
- printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno));
- } else {
- printf ("Socket: Opened in %s\n", uzbl.comm.socket_path);
+ if (bind (sock, (struct sockaddr *) &local, len) != -1) {
+ printf ("init_socket: opened in %s\n", path);
listen (sock, 5);
- if( (chan = g_io_channel_unix_new(sock)) )
+ if( (chan = g_io_channel_unix_new(sock)) ) {
g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
- }
+ uzbl.comm.socket_path = path;
+ return dir;
+ }
+ } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
+
+ /* if we got this far, there was an error; cleanup */
+ g_free(path);
+ g_free(dir);
+ return NULL;
}
static void
@@ -832,7 +1235,7 @@ update_title (void) {
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 = parse_status_template(uzbl.behave.status_format);
+ statln = expand_template(uzbl.behave.status_format);
gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
if (b->status_background) {
GdkColor color;
@@ -858,7 +1261,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) */
@@ -868,7 +1271,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) {
@@ -896,49 +1299,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;
}
@@ -947,6 +1362,7 @@ 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 ());
@@ -956,6 +1372,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);
@@ -970,6 +1387,10 @@ create_mainbar () {
GUI *g = &uzbl.gui;
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 ("");
gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
@@ -1000,6 +1421,9 @@ add_binding (const gchar *key, const gchar *act) {
//Debug:
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_strfreev(parts);
@@ -1007,13 +1431,11 @@ add_binding (const gchar *key, const gchar *act) {
static void
settings_init () {
- GKeyFile* config = NULL;
- gboolean res = FALSE;
char *saveptr;
- gchar** keys = NULL;
State *s = &uzbl.state;
Network *n = &uzbl.net;
- Behaviour *b = &uzbl.behave;
+
+ uzbl.behave.reset_command_mode = 1;
if (!s->config_file) {
const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
@@ -1051,158 +1473,51 @@ settings_init () {
}
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);
- }
- } else {
- printf ("No configuration.\n");
- }
-
- if (res) {
- 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);
- b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
- 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->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)
- b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL);
- if (! b->socket_dir)
- b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL);
- keys = g_key_file_get_keys (config, "bindings", NULL, NULL);
- }
-
- printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled"));
- printf ("Download manager: %s\n", (b->download_handler ? b->download_handler : "disabled"));
- printf ("Cookie handler: %s\n", (b->cookie_handler ? b->cookie_handler : "disabled"));
- 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 ("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"));
-
- if (!b->modkey)
- b->modkey = "";
-
- //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
- gchar* modkeyup = g_utf8_strup (b->modkey, -1);
- if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key.
- if (g_strrstr (modkeyup,"LOCK") != NULL) b->modmask |= GDK_LOCK_MASK; //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock).
- if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key.
- if (g_strrstr (modkeyup,"MOD1") != NULL) b->modmask |= GDK_MOD1_MASK; //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key).
- if (g_strrstr (modkeyup,"MOD2") != NULL) b->modmask |= GDK_MOD2_MASK; //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
- if (g_strrstr (modkeyup,"MOD3") != NULL) b->modmask |= GDK_MOD3_MASK; //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
- if (g_strrstr (modkeyup,"MOD4") != NULL) b->modmask |= GDK_MOD4_MASK; //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
- if (g_strrstr (modkeyup,"MOD5") != NULL) b->modmask |= GDK_MOD5_MASK; //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
- if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button.
- if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button.
- if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button.
- if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button.
- if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button.
- if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10
- if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10
- if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */
- free (modkeyup);
-
- if (keys) {
- int i;
- for (i = 0; keys[i]; i++) {
- gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
-
- add_binding(g_strstrip(keys[i]), value);
- g_free(value);
- }
+ GIOChannel *chan = NULL;
+ GError *error = NULL;
+ gchar *readbuf = NULL;
+ gsize len;
- g_strfreev(keys);
- }
-
- /* networking options */
- if (res) {
- n->proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL);
- b->http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
- n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
- n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
- n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
- }
+ chan = g_io_channel_new_file(s->config_file, "r", &error);
- if(n->proxy_url){
- g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL);
- }
-
- if(!(b->http_debug <= 3)){
- b->http_debug = 0;
- fprintf(stderr, "Wrong http_debug level, ignoring.\n");
- } else if (b->http_debug > 0) {
- n->soup_logger = soup_logger_new(b->http_debug, -1);
- soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
- }
-
- if(n->useragent){
- char* newagent = malloc(1024);
-
- strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
- strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
- strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
+ if (chan) {
+ while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
+ == G_IO_STATUS_NORMAL) {
+ parse_cmd_line(readbuf);
+ g_free (readbuf);
+ }
- if (uname (&s->unameinfo) == -1) {
- printf("Error getting uname info. Not replacing system-related user agent variables.\n");
+ g_io_channel_unref (chan);
+ printf ("Config %s loaded\n", s->config_file);
} else {
- strcpy(newagent, str_replace("%sysname%", s->unameinfo.sysname, newagent));
- strcpy(newagent, str_replace("%nodename%", s->unameinfo.nodename, newagent));
- strcpy(newagent, str_replace("%kernrel%", s->unameinfo.release, newagent));
- strcpy(newagent, str_replace("%kernver%", s->unameinfo.version, newagent));
- strcpy(newagent, str_replace("%arch-system%", s->unameinfo.machine, newagent));
-
- #ifdef _GNU_SOURCE
- strcpy(newagent, str_replace("%domainname%", s->unameinfo.domainname, newagent));
- #endif
+ fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
}
-
- strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent));
- strcpy(newagent, str_replace("%commit%", COMMIT, newagent));
-
- n->useragent = malloc(1024);
- strcpy(n->useragent, newagent);
- g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
+ } else {
+ printf ("No configuration file loaded.\n");
}
+ if (!uzbl.behave.status_format)
+ uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
- if(n->max_conns >= 1){
- g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
- }
+ g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
+}
- if(n->max_conns_host >= 1){
- g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
+static gchar*
+set_useragent(gchar *val) {
+ if (*val == ' ') {
+ g_free(val);
+ return NULL;
}
-
- printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
- printf("HTTP logging level: %d\n", b->http_debug);
- printf("User-agent: %s\n", n->useragent? n->useragent : "default");
- printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
- printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
-
-
-
- if(b->cookie_handler){
- /* ck = soup_cookie_jar_new(); */
- /* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */
- /* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */
- g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
- }
-
+ gchar *ua = expand_template(val);
+ if (ua)
+ g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
+ return ua;
}
static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
(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 ("");
@@ -1232,6 +1547,7 @@ save_cookies (SoupMessage *msg, gpointer user_data){
g_slist_free(ck);
}
+
int
main (int argc, char* argv[]) {
gtk_init (&argc, &argv);
@@ -1252,26 +1568,34 @@ 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 ();
+ 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();
commands_hash ();
+ make_var_to_name_hash();
- if (uzbl.behave.always_insert_mode)
- uzbl.behave.insert_mode = TRUE;
- GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
- if (uzbl.behave.status_top)
- gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
- if (!uzbl.behave.status_top)
- gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
+ uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
+
+ uzbl.gui.scrolled_win = create_browser();
+ create_mainbar();
+ /* 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), vbox);
+ gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
- load_uri (uzbl.gui.web_view, uzbl.state.uri);
+ load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
gtk_widget_show_all (uzbl.gui.main_window);
@@ -1286,23 +1610,14 @@ 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");
-
- setup_scanner();
- if (!uzbl.behave.status_format)
- uzbl.behave.status_format = STATUS_DEFAULT;
if (!uzbl.behave.show_status)
gtk_widget_hide(uzbl.gui.mainbar);
else
update_title();
-
- if (uzbl.behave.fifo_dir)
- create_fifo ();
- if (uzbl.behave.socket_dir)
- create_socket();
+ create_stdin();
gtk_main ();
clean_up();
diff --git a/uzbl.h b/uzbl.h
index 71ec587..e23fa69 100644
--- a/uzbl.h
+++ b/uzbl.h
@@ -12,10 +12,19 @@
#define STATUS_DEFAULT "<span background=\"darkblue\" foreground=\"white\"> MODE </span> <span background=\"red\" foreground=\"white\">KEYCMD</span> (LOAD_PROGRESS%) <b>TITLE</b> - Uzbl browser"
-/* statusbar symbols */
-enum { SYM_TITLE, SYM_URI, SYM_NAME,
- SYM_LOADPRGS, SYM_LOADPRGSBAR,
- SYM_KEYCMD, SYM_MODE};
+enum {
+ /* statusbar symbols */
+ SYM_TITLE, SYM_URI, SYM_NAME,
+ SYM_LOADPRGS, SYM_LOADPRGSBAR,
+ SYM_KEYCMD, SYM_MODE, SYM_MSG,
+ /* useragent symbols */
+ SYM_WK_MAJ, SYM_WK_MIN, SYM_WK_MIC,
+ SYM_SYSNAME, SYM_NODENAME,
+ SYM_KERNREL, SYM_KERNVER,
+ SYM_ARCHSYS, SYM_ARCHUZBL,
+ SYM_DOMAINNAME, SYM_COMMIT
+};
+
const struct {
gchar *symbol_name;
guint symbol_token;
@@ -25,20 +34,36 @@ const struct {
{"TITLE", SYM_TITLE},
{"KEYCMD", SYM_KEYCMD},
{"MODE", SYM_MODE},
+ {"MSG", SYM_MSG},
{"LOAD_PROGRESS", SYM_LOADPRGS},
{"LOAD_PROGRESSBAR", SYM_LOADPRGSBAR},
+
+ {"WEBKIT_MAJOR", SYM_WK_MAJ},
+ {"WEBKIT_MINOR", SYM_WK_MIN},
+ {"WEBKIT_MICRO", SYM_WK_MIC},
+ {"SYSNAME", SYM_SYSNAME},
+ {"NODENAME", SYM_NODENAME},
+ {"KERNREL", SYM_KERNREL},
+ {"KERNVER", SYM_KERNVER},
+ {"ARCH_SYSTEM", SYM_ARCHSYS},
+ {"ARCH_UZBL", SYM_ARCHUZBL},
+ {"DOMAINNAME", SYM_DOMAINNAME},
+ {"COMMIT", SYM_COMMIT},
{NULL, 0}
}, *symp = symbols;
/* status bar elements */
typedef struct {
gint load_progress;
+ gchar *msg;
} StatusBar;
/* gui elements */
typedef struct {
GtkWidget* main_window;
+ GtkWidget* scrolled_win;
+ GtkWidget* vbox;
GtkWidget* mainbar;
GtkWidget* mainbar_label;
GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar
@@ -55,8 +80,15 @@ typedef struct {
/* external communication*/
enum { FIFO, SOCKET};
typedef struct {
- char fifo_path[64];
- char socket_path[108];
+ gchar *fifo_path;
+ gchar *socket_path;
+ /* stores (key)"variable name" -> (value)"pointer to this var*/
+ GHashTable *proto_var;
+ /* command parsing regexes */
+ GRegex *set_regex;
+ GRegex *cmd_regex;
+ GRegex *get_regex;
+ GRegex *bind_regex;
} Communication;
@@ -64,7 +96,7 @@ typedef struct {
typedef struct {
gchar *uri;
gchar *config_file;
- gchar *instance_name;
+ char *instance_name;
gchar config_file_path[500];
gchar selected_url[500];
char executable_path[500];
@@ -87,6 +119,7 @@ typedef struct {
/* behaviour */
typedef struct {
+ gchar* load_finish_handler;
gchar* status_format;
gchar* status_background;
gchar* history_handler;
@@ -98,6 +131,7 @@ typedef struct {
gboolean show_status;
gboolean insert_mode;
gboolean status_top;
+ gboolean reset_command_mode;
gchar* modkey;
guint modmask;
guint http_debug;
@@ -171,6 +205,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
@@ -213,23 +250,37 @@ static void
parse_command(const char *cmd, const char *param);
static void
-parse_line(char *line);
-
-void
-build_stream_name(int type);
+runcmd(WebKitWebView *page, const char *param);
static void
+parse_cmd_line(const char *ctl_line);
+
+static gchar*
+build_stream_name(int type, const gchar *dir);
+
+static gboolean
+var_is(const char *x, const char *y);
+
+static gchar*
+set_useragent(gchar *val);
+
+static gboolean
control_fifo(GIOChannel *gio, GIOCondition condition);
-static void
-create_fifo();
+static gchar*
+init_fifo(gchar *dir);
-static void
-create_socket();
+static gboolean
+control_stdin(GIOChannel *gio, GIOCondition condition);
static void
+create_stdin();
+
+static gchar*
+init_socket(gchar *dir);
+
+static gboolean
control_socket(GIOChannel *chan);
-
static void
update_title (void);
@@ -258,9 +309,6 @@ search_text (WebKitWebView *page, const char *param);
static void
run_js (WebKitWebView * web_view, const gchar *param);
-static char *
-str_replace (const char* search, const char* replace, const char* string);
-
static void handle_cookies (SoupSession *session,
SoupMessage *msg,
gpointer user_data);