aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar uranther <jwheaton@purdue.edu>2009-06-29 12:06:39 -0400
committerGravatar uranther <jwheaton@purdue.edu>2009-06-29 12:06:39 -0400
commitf679c8c008361962a330e062789ba6c77683e510 (patch)
treee4675fb2541de31bd9a4807f9928a37a2d37342b
parent6bb3be0480e029879b0f430416140ccfb446e4a1 (diff)
parent439824504f60d37f39d9b7bda8479dd1f18f17b9 (diff)
Merge from Dieterbe/experimental
-rw-r--r--AUTHORS8
-rw-r--r--Makefile18
-rw-r--r--README86
-rw-r--r--docs/CONTRIBUTING29
-rw-r--r--docs/FAQ22
-rw-r--r--docs/TODO7
-rw-r--r--examples/config/uzbl/config42
-rwxr-xr-xexamples/data/uzbl/scripts/cookies.py9
-rwxr-xr-xexamples/data/uzbl/scripts/cookies.sh5
-rwxr-xr-xexamples/data/uzbl/scripts/formfiller.pl2
-rwxr-xr-xexamples/data/uzbl/scripts/formfiller.sh5
-rwxr-xr-xexamples/data/uzbl/scripts/history.sh4
-rwxr-xr-xexamples/data/uzbl/scripts/insert_bookmark.sh5
-rwxr-xr-xexamples/data/uzbl/scripts/load_url_from_bookmarks.sh4
-rwxr-xr-xexamples/data/uzbl/scripts/load_url_from_history.sh3
-rwxr-xr-xexamples/data/uzbl/scripts/session.sh5
-rwxr-xr-xexamples/data/uzbl/scripts/uzbl_tabbed.py41
-rw-r--r--uzbl.c614
-rw-r--r--uzbl.h122
-rw-r--r--uzblctrl.c22
20 files changed, 752 insertions, 301 deletions
diff --git a/AUTHORS b/AUTHORS
index 83b87a1..2731d6c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,10 +21,16 @@ Contributors:
Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch
(uranther) - zoom level
(bobpaul) - session script patches
- Tom Adams (holizz) - few patches, cookies.py
+ Tom Adams (holizz) - few patches, cookies.py, gtkplugk/socket & uzbl_tabbed.py
neutralinsomniac - load_progress = 0 fix
Maximilian Gaß (mxey) - small patches
Abel Camarillo (00z) - make it compile on OpenBSD
+ (israellevin) - toggle_zoom_type
+ (kmeaw) - fix for multibyte utf8 characters segfault
+ (evocallaghan) - tiny patches
+ Aaron Griffin (phrakture) - Makefile patches to build on OSX
+ Mason Larobina - os.environ.keys() & os.path.join fix in cookies.py
+ (dequis) - Uzbl.run, birectional socket, javascript commands
Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c
Which is copyrighted:
diff --git a/Makefile b/Makefile
index a20e532..960ea20 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CFLAGS:=-std=c99 $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS)
-LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4) -pthread $(LDFLAGS)
+CFLAGS:=-std=c99 $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -lgthread-2.0 -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS)
+LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -pthread $(LDFLAGS)
all: uzbl uzblctrl
PREFIX?=$(DESTDIR)/usr
@@ -63,13 +63,13 @@ install:
install -d $(PREFIX)/bin
install -d $(PREFIX)/share/uzbl/docs
install -d $(PREFIX)/share/uzbl/examples
- install -D -m755 uzbl $(PREFIX)/bin/uzbl
- install -D -m755 uzblctrl $(PREFIX)/bin/uzblctrl
- cp -ax docs $(PREFIX)/share/uzbl/
- cp -ax config.h $(PREFIX)/share/uzbl/docs/
- cp -ax examples $(PREFIX)/share/uzbl/
- install -D -m644 AUTHORS $(PREFIX)/share/uzbl/docs
- install -D -m644 README $(PREFIX)/share/uzbl/docs
+ install -m755 uzbl $(PREFIX)/bin/uzbl
+ install -m755 uzblctrl $(PREFIX)/bin/uzblctrl
+ cp -rp docs $(PREFIX)/share/uzbl/
+ cp -rp config.h $(PREFIX)/share/uzbl/docs/
+ cp -rp examples $(PREFIX)/share/uzbl/
+ install -m644 AUTHORS $(PREFIX)/share/uzbl/docs
+ install -m644 README $(PREFIX)/share/uzbl/docs
uninstall:
diff --git a/README b/README
index 5c9dcd4..afef501 100644
--- a/README
+++ b/README
@@ -7,7 +7,7 @@
### TO NEW PEOPLE:
* please read the documentation in /usr/share/uzbl/docs
* invoke uzbl --help
-* to get you started: uzbl --uri 'http://www.archlinux.org' --config /usr/share/uzbl/examples/configs/sampleconfig
+* to get you started: `XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config uzbl --uri www.archlinux.org`
* study the sample config, have a look at all the bindings, and note how you can call the scripts to load new url from history and the bookmarks file
* note that there is no url bar. all url editing is supposed to happen _outside_ of uzbl.
For now, you can use the `load_from_*` dmenu based scripts to pick a url or type a new one or write commands into the fifo (see /usr/share/uzbl/docs/CHECKLIST)
@@ -95,8 +95,8 @@ The following commands are recognized:
- used for changing variables on the fly
- the changes are effective immediately; for example, setting the variable `uri` will make uzbl start loading, and changing `status_format` will make the status bar react immediately
- if you want to unset a string, use `set` with one space after the equals sign
-* `get <key>`
- - use this to print the value of a variable. (and TODO, get the value through the socket)
+* `print @<key>`
+ - use this to print the value of a variable.
* `bind <string> = <command>`
- sets the character sequence `<string>` to invoke `<command>` when typed interactively in uzbl
- there are a few tricks you can do:
@@ -161,6 +161,84 @@ The following commands are recognized:
- remember to quote the commands; one command must come as one parameter
- if you use `chain` with a handler script which must return some output (such as a cookie handler -- uzbl will wait for and use its output), use sync_spawn or sync_sh instead of spawn or sh in the command that should give the output
+### JAVASCRIPT HELPER OBJECT
+
+Javascript code run from uzbl is given a special object in the global namespace which gives special privileges to these scripts. This object is called `Uzbl`, and it is added and removed before and after the script execution so that it is hidden to web javascripts (There is no race condition, since all the javascript code runs in a single thread)
+
+Currently, the `Uzbl` object provides only one function:
+
+* `Uzbl.run( <command> )`
+ - command is any uzbl command as defined above
+ - return value: a string, either empty or containing the output of the command. Very few commands return their output currently, including js, script, and print.
+ - Examples:
+ * `Uzbl.run("spawn insert_bookmark.sh")`
+ * `uri = Uzbl.run("print @uri")` (see variable expansion below)
+
+### JAVASCRIPT SECURITY
+
+Since defined variables and functions are set in the global namespace (`window` object) as default, it is recommended to wrap your scripts like this:
+
+ (function(Uzbl) {
+ ...
+ })(Uzbl);
+
+This way, everything is kept private. It also turns Uzbl into a local variable, which can be accessed from callback functions defined inside. However for some situations, isolating everything isn't an option, for example, with binds. You can define them directly in the script body, and use `var Uzbl = window.Uzbl;` to make the Uzbl variable local, as in the following example:
+
+ function f() {
+ var Uzbl = window.Uzbl;
+ Uzbl.run(...);
+ setTimeout(function() {
+ Uzbl.run(...);
+ }, 500);
+ }
+
+Copying the Uzbl object and creating public functions should be taken with care to avoid creating security holes. Keep in mind that the "f" function above would be defined in the `window` object, and as such any javascript in the current page can call it.
+
+### VARIABLE EXPANSION AND COMMAND/JAVA SCRIPT SUBSTITUTION
+
+Variable expansion works pretty much as known from shell interpreters (sh, bash, etc.). This means you can
+construct strings with uzbl variables in them and have uzbl replace the variable name with its contents.
+
+In order to let uzbl know what to expand you'll need to prepend @ to the variable name:
+
+ print The variable \@show_status contains @show_status
+
+The above example demonstrates two things:
+
+ * '\' is treated as escape character and will use the character immediatelly following it literallily
+ this means '\@show_status' will not expand to the variable content but be rather printed as
+ '@show_status'
+
+ * prepending the variable with '@' will expand to its contents
+
+ * like in the shell you can use @{uzbl_var} to denote the beginning/end of the variable name in
+ cases where it is not obvious what belongs to the name and what not.
+ E.g.: print @{show_status}foobar
+
+
+Command substitution will launch any commands and substitute the call with the return value of the command.
+
+Uzbl will substitute any commands enclosed within @( )@:
+
+ print Command substitution: @(uname -a)@
+
+You can access any uzbl variable from within a command substitution:
+
+ print @(echo -n 'Accessing the show_status var from an external script, value: @show_status')@
+
+
+Java script substitution works in the exact same way as command substitution but you will need to enclose
+the java script in @< >@.
+
+ print The currently viewed document contains @<document.links.length>@ links
+
+Variable expansion also works within a java script substitution.
+
+
+NOTE: If you need to use literal @ or \ characters you will need to escape them:
+
+ print At sign: \@ and backslash: \\
+
### VARIABLE REPLACEMENT
Some of the variables are interpreted:
@@ -212,7 +290,7 @@ The script specific arguments are this:
* cookie handler
$8 GET/PUT
- $9 request address host (if current page url is www.foo.com/somepage, this could be something else then foo, eg advertising from another host)
+ $9 request address host (if current page url is www.foo.com/somepage, this could be something else than foo, eg advertising from another host)
$10 request address path
$11 cookie (only with PUT requests)
diff --git a/docs/CONTRIBUTING b/docs/CONTRIBUTING
index 74d1b36..c88be30 100644
--- a/docs/CONTRIBUTING
+++ b/docs/CONTRIBUTING
@@ -1,12 +1,11 @@
### Users
-Right now, the best way to contribute to Uzbl is to use it, hang around in
-our IRC channel, and tell us when things break. If you're feeling more
-adventerous, you can use one of the development branches and give bug
+Just use Uzbl, hang around in our IRC channel, try out different things and tell us when things break.
+If you're feeling more adventerous, you can use one of the development branches and give bug
reports and suggestions straight to the developer in charge of that, so the
-same problems don't occur when they get merged into the master branch. Have
-a look at the CHECKLIST file to see all the stuff that is supposed to work.
+same problems don't occur when they get merged into the master branch.
Play around with the configs and scripts and see if you can improve things.
+The wiki can be a good source of inspiration.
### Developers
@@ -29,16 +28,30 @@ Our convention is to develop in the *experimental* branch, and keep only stable,
So ideally, all contributors develop in their experimental, that gets merged into the mainline experimental, and after QA it gets merged into the main master.
-### VALGRIND PROFILING
+### Patch/branch requirements before merging:
+
+* patches/merges must be about one thing. If you want to work on multiple things, create new branches.
+ I allow exceptions for trivial typo fixes and such, but that's it.
+ This also implies that you also need to update your tree reguraly. Don't fall behind too much. (ie merge from Dieter)
+* any change in functionality that you want merged in must also be documented.
+ There is a readme and some files in the 'docs' directory who should correspond to the code base at all times.
+ Update them, not only for end users but also for your fellow hackers.
+* We recommend you finish your stuff first and then let Dieter know you want your stuff to be merged in, but
+ we know for bigger changes this is not always feasible. Just try to keep the merges about bigger "clean changesets".
+
+That said, you can always ask us to check on your stuff or ask for advice.
+
+
+### Valgrind profiling
$ add this to Makefile header: CFLAGS=-g
$ recompile
$ valgrind --tool=callgrind ./uzbl ....
$ kcachegrind callgrind.out.foo
-### MEMORY LEAK CHECKING
+### Memory leak checking
valgrind --tool=memcheck --leak-check=full ./uzbl
-### DEBUGGING / BACKTRACES
+### Debugging / backtraces
* compile with -ggdb (enabled by default on experimental tree)
* run: `gdb ./uzbl`
diff --git a/docs/FAQ b/docs/FAQ
index ef5df5f..a3c1254 100644
--- a/docs/FAQ
+++ b/docs/FAQ
@@ -4,11 +4,15 @@ FAQ
### I just installed uzbl but it doesn't do much. What now?
Uzbl includes very limited default settings (statusbar settings, but no keybinds, history/download handlers etc.)
Look at /usr/share/uzbl/docs/config.h to see the default settings.
-Neither does uzbl create a default config file on startup like some other programs do.
-Because we want to give you the freedom to place your config where you want, and to use a config or not.
-Have a look in /usr/share/uzbl/examples/configs to see what you can do. You will probably want to create your own config based on an example config
-so you can add keybinds and to use scripts.
-Use the --config parameter or save your config as $XDG\_CONFIG\_HOME/uzbl/config to have it auto-loaded.
+Neither does uzbl create a default config file on startup like some other programs do because we want to give you the freedom to place your config where you want, and to use a config or not.
+Have a look in /usr/share/uzbl/examples/configs to see what you can do.
+If you save a config as $XDG\_CONFIG\_HOME/uzbl/config it will be loaded automatically.
+Running with the `--verbose` flag on a command line can also be interesting.
+To get you started, try this:
+`XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config uzbl`
+It will temporarily override your $XDG\_CONFIG\_HOME and $XDG\_DATA\_HOME
+variables so you can try the sample stuff directly in /usr/share/uzbl/examples.
+If you like what you can do, you can copy the sample stuff into your ~ and edit to your liking.
### Where is the location bar? How do I change the URL ?
Uzbl has no location bar. All changes to the uri (editing of current uri, typing new uri, loading of uri from bookmarks/history/...) happens *outside* of uzbl.
@@ -90,6 +94,14 @@ They both have advantages and disadvantages:
So, when writing scripts, using fifo's is usually the fastest method (because you do not need to fork another process), so fifo is preferred unless you need a response.
+### What the hell is this 'XDG' stuff??
+You'll notice our example scripts and configs use variables such as `$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`.
+Most of us really like the [xdg basedir spec](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
+so our example material folows it. Basically it helps you keeping a clean `$HOME` and it separates config, data and cache.
+If these variables are not defined on your system, it could be that you need to install an xdg package.
+If you don't like this, no one is stopping you from changing the scripts and configs to point to a single `$HOME/.uzbl` directory or whatever you want.
+
+
### Does the world really need another browser?
We did try a lot of browsers, and we do not suffer [NIH](http://en.wikipedia.org/wiki/Not_Invented_Here).
We believe that the approach taken by way too many browsers is wrong. We do not want browsers that try to do everything,
diff --git a/docs/TODO b/docs/TODO
index 561757c..7f2d514 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -8,7 +8,6 @@ More or less in order of importance/urgency
* shortcuts to focus other instances (see docs/multiple-instances-management)
* recognize -h with GOption?
-* implement a vimperator-like link following scheme.
* implement getting feedback from socket
* scrolling: make page up and page down configurable.
* show % of location in statusbar/title if page doesn't fit entirely on view.
@@ -35,7 +34,7 @@ More or less in order of importance/urgency
* settings iterating "state generator" so we can "open in new window" again.
* handler for (broken) ssl certs.
* handlers for mailto: and maybe other thingies?
-* configure script
+* make sample scripts less depending on bash, but more posix sh.
* proxy_url is not a good var name. it's not a url.
* regex style page searching? so you can do 'or' and 'and' things. flags like case sensitive etc.
* check for real command name, not just the first letter.
@@ -45,14 +44,16 @@ More or less in order of importance/urgency
* document:
stylesheet overridding
formfiller
+ full duplex socket
+ ^X and such binds
link following
+ scrolling in %
webkit inspector usage
scroll commands can take %s, eg scroll 100% for pages
chaining of actions, print (and other actions that aren't documented yet)
overriding variables (such as -u)
variable expansion (@var, @{var}, where do they get expanded? can users have their own vars?, should we merge this with the replacement we do for useragent/window title etc?)
how %s works for the js command
-* consider switching to CMAKE. (someone already ported the makefile etc)
SOMEDAY:
diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config
index bbe3a75..e7c03dc 100644
--- a/examples/config/uzbl/config
+++ b/examples/config/uzbl/config
@@ -1,18 +1,22 @@
-
-# example uzbl config. in a real config, we should obey the xdg spec
+# example uzbl config.
# 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 commands -> 1 key). set
-# always_insert_mode to always be in insert mode and disable going out of it.
+# keyboard behavior is vimstyle by default, but you can change this
+# 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 commands
# from insert mode by combining them with the modkey
-# TODO: ability to attach misc things (spawn <foo>, script <bar>,.. to internal events)
# Usually you want to spawn a script to handle things, but any command (such as sh) can be used
set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh
set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh
set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py
+# You can bind whatever things (spawn <foo>, script <bar>,..) to some events TODO: make events system more generic
+set load_start_handler = set status_message = <span foreground="khaki">wait</span>
+set load_commit_handler = set status_message = <span foreground="green">recv</span>
+set load_finish_handler = set status_message = <span foreground="gold">done</span>
+
+
set minimum_font_size = 6
set font_size = 11
## monospace_size defaults to font_size, but you can alter it independently
@@ -61,7 +65,7 @@ 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 foreground="#606060">SELECTED_URI</span></span>
-set status_top = 0
+set status_top = 0
# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off)
set title_format_short = TITLE - Uzbl browser <NAME>
set title_format_long = KEYCMD MODE TITLE - Uzbl browser <NAME> > SELECTED_URI
@@ -99,11 +103,12 @@ bind << = scroll_begin
bind >> = scroll_end
bind b = back
bind m = forward
-bind s = stop
+bind S = stop
bind r = reload
bind R = reload_ign_cache
bind + = zoom_in
bind - = zoom_out
+bind T = toggle_zoom_type
bind 1 = sh "echo set zoom_level = 1.0 > $4"
bind 2 = sh "echo set zoom_level = 2.0 > $4"
bind t = toggle_status
@@ -115,9 +120,15 @@ bind ?* = search_reverse %s
bind n = search
bind N = search_reverse
bind gh = uri http://www.uzbl.org
-#TODO: set uri?
+
+# like this you can enter any command at runtime, interactively. prefixed by ':'
+bind :_ = chain '%s'
+
+# shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..'
bind o _ = uri %s
-bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go
+# shortcut to set variables
+bind s _ = set %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 = toggle_insert_mode
# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting
@@ -133,11 +144,13 @@ bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard
# does the same as yurl but without needing a script
bind y2url = sh 'echo -n $6 | xclip'
# go the page from primary selection
-bind p = sh "echo uri `xclip -selection primary -o` > $4"
+bind p = sh 'echo "uri `xclip -selection primary -o`" > $4'
# go to the page in clipboard
-bind P = sh "echo uri `xclip -selection clipboard -o` > $4"
+bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4'
+# start a new uzbl instance from the page in primary selection
+bind 'p = sh 'exec uzbl --uri $(xclip -o)'
bind ZZ = exit
-bind S = js alert("hi");
+bind Xs = js alert("hi");
# example showing how to use sh
# it sends a command to the fifo, whose path is told via a positional param
# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it
@@ -146,7 +159,10 @@ bind S = js alert("hi");
# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file
# path, fifo & socket dirs, etc.)
bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"'
-bind dump = sh "echo dump_config > $4"
+
+bind !dump = sh "echo dump_config > $4"
+bind !reload = sh 'cat $1 > $4'
+
# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically
bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh
bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit
diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py
index 3cc7eb0..4f80359 100755
--- a/examples/data/uzbl/scripts/cookies.py
+++ b/examples/data/uzbl/scripts/cookies.py
@@ -61,7 +61,12 @@ class FakeResponse:
return FakeHeaders(self.argv)
if __name__ == '__main__':
- jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt')
+ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']:
+ jar = cookielib.MozillaCookieJar(\
+ os.path.join(os.environ['XDG_DATA_HOME'],'/uzbl/cookies.txt'))
+ else:
+ jar = cookielib.MozillaCookieJar(\
+ os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt'))
try:
jar.load()
except:
@@ -79,4 +84,4 @@ if __name__ == '__main__':
res = FakeResponse(sys.argv)
jar.extract_cookies(res,req)
jar.save(ignore_discard=True) # save session cookies too
- #jar.save() # save everything but session cookies \ No newline at end of file
+ #jar.save() # save everything but session cookies
diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh
index 78139d6..56b9c79 100755
--- a/examples/data/uzbl/scripts/cookies.sh
+++ b/examples/data/uzbl/scripts/cookies.sh
@@ -24,10 +24,9 @@
# http://kb.mozillazine.org/Cookies.txt
# don't always append cookies, sometimes we need to overwrite
-cookie_config=$XDG_CONFIG_HOME/uzbl/cookies
+cookie_config=${XDG_CONFIG_HOME:-$HOME/.config}/uzbl/cookies
[ -z "$cookie_config" ] && exit 1
-[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1
-[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_data=$XDG_DATA_HOME/uzbl/cookies.txt
+[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/ ] && cookie_data=${XDG_DATA_HOME:-$home/.local/share}/uzbl/cookies.txt || exit 1
notifier=
diff --git a/examples/data/uzbl/scripts/formfiller.pl b/examples/data/uzbl/scripts/formfiller.pl
index c590836..9ac6959 100755
--- a/examples/data/uzbl/scripts/formfiller.pl
+++ b/examples/data/uzbl/scripts/formfiller.pl
@@ -3,7 +3,7 @@
# a slightly more advanced form filler
#
# uses settings file like: $keydir/<domain>
-
+#TODO: fallback to $HOME/.local/share
# user arg 1:
# edit: force editing of the file (fetches if file is missing)
# load: fill forms from file (fetches if file is missing)
diff --git a/examples/data/uzbl/scripts/formfiller.sh b/examples/data/uzbl/scripts/formfiller.sh
index d54c626..bbb9d1a 100755
--- a/examples/data/uzbl/scripts/formfiller.sh
+++ b/examples/data/uzbl/scripts/formfiller.sh
@@ -12,8 +12,9 @@
# something else (or empty): if file not available: new, otherwise load.
-keydir=$XDG_DATA_HOME/uzbl/forms
-[ -z "$keydir" ] && exit 1
+keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms
+[ -d "`dirname $keydir`" ] || exit 1
+[ -d "$keydir" ] || mkdir "$keydir"
#editor=gvim
editor='urxvt -e vim'
diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh
index 69f4034..ccc6b40 100755
--- a/examples/data/uzbl/scripts/history.sh
+++ b/examples/data/uzbl/scripts/history.sh
@@ -1,3 +1,5 @@
#!/bin/bash
#TODO: strip 'http://' part
-echo "$8 $6 $7" >> $XDG_DATA_HOME/uzbl/history
+file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history
+[ -d `dirname $file` ] || exit 1
+echo "$8 $6 $7" >> $file
diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh
index b3a7011..23c0d31 100755
--- a/examples/data/uzbl/scripts/insert_bookmark.sh
+++ b/examples/data/uzbl/scripts/insert_bookmark.sh
@@ -1,8 +1,7 @@
#!/bin/bash
-# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks)
-[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1
-file=$XDG_DATA_HOME/uzbl/bookmarks
+[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1
+file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks
which zenity &>/dev/null || exit 2
diff --git a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh
index eb04873..78ee726 100755
--- a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh
+++ b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh
@@ -2,8 +2,8 @@
#NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes.
-file=$XDG_DATA_HOME/uzbl/bookmarks
-[ -z "$file" ] && exit
+file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks
+[ -r "$file" ] || exit
COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030"
if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'
then
diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh
index 39ef302..57d634a 100755
--- a/examples/data/uzbl/scripts/load_url_from_history.sh
+++ b/examples/data/uzbl/scripts/load_url_from_history.sh
@@ -1,5 +1,6 @@
#!/bin/bash
-history_file=$XDG_DATA_HOME/uzbl/history
+history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history
+[ -r "$history_file" ] || exit 1
# choose from all entries, sorted and uniqued
# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i`
diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh
index e2642c7..4dbae55 100755
--- a/examples/data/uzbl/scripts/session.sh
+++ b/examples/data/uzbl/scripts/session.sh
@@ -8,9 +8,10 @@
# and doesn't need to be called manually at any point.
# Add a line like 'bind quit = /path/to/session.sh endsession' to your config
+[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1
scriptfile=$0 # this script
-sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored
-configfile=$XDG_DATA_HOME/uzbl/config # uzbl configuration file
+sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/session # the file in which the "session" (i.e. urls) are stored
+configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file
UZBL="uzbl -c $configfile" # add custom flags and whatever here.
fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere
diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py
new file mode 100755
index 0000000..4c3a934
--- /dev/null
+++ b/examples/data/uzbl/scripts/uzbl_tabbed.py
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+
+import string, pygtk, gtk, sys, subprocess
+pygtk.require('2.0')
+
+def new_tab(nothing):
+ socket = gtk.Socket()
+ socket.show()
+ notebook.append_page(socket, gtk.Label('title goes here'))
+ sid = socket.get_id()
+ subprocess.call(['sh', '-c', 'uzbl -s %s &'%sid])
+
+
+window = gtk.Window()
+window.show()
+
+vbox = gtk.VBox()
+vbox.show()
+window.add(vbox)
+
+button = gtk.Button(stock=gtk.STOCK_ADD)
+button.connect('clicked', new_tab)
+button.show()
+vbox.add(button)
+
+notebook = gtk.Notebook()
+vbox.add(notebook)
+notebook.show()
+
+window.connect("destroy", lambda w: gtk.main_quit())
+
+#def plugged_event(widget):
+# print "I (", widget, ") have just had a plug inserted!"
+
+#socket.connect("plug-added", plugged_event)
+#socket.connect("plug-removed", plugged_event)
+
+if len(sys.argv) == 2:
+ socket.add_id(long(sys.argv[1]))
+
+gtk.main() \ No newline at end of file
diff --git a/uzbl.c b/uzbl.c
index af0fbeb..d986a42 100644
--- a/uzbl.c
+++ b/uzbl.c
@@ -45,6 +45,7 @@
#include <sys/time.h>
#include <webkit/webkit.h>
#include <libsoup/soup.h>
+#include <JavaScriptCore/JavaScript.h>
#include <stdio.h>
#include <string.h>
@@ -57,9 +58,6 @@
#include "config.h"
Uzbl uzbl;
-typedef void (*Command)(WebKitWebView*, GArray *argv);
-
-
/* commandline arguments (set initial values for the state variables) */
const
@@ -73,6 +71,8 @@ GOptionEntry entries[] =
"Name of the current instance (defaults to Xorg window id)", "NAME" },
{ "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
"Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
+ { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
+ "Socket ID", "SOCKET" },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
@@ -191,12 +191,40 @@ make_var_to_name_hash() {
}
/* --- UTILITY FUNCTIONS --- */
-gchar *
-expand_vars(char *s) {
+enum {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS};
+static guint
+get_exp_type(gchar *s) {
+ /* variables */
+ if(*(s+1) == '(')
+ return EXP_EXPR;
+ else if(*(s+1) == '{')
+ return EXP_BRACED_VAR;
+ else if(*(s+1) == '<')
+ return EXP_JS;
+ else
+ return EXP_SIMPLE_VAR;
+
+return EXP_ERR;
+}
+
+/*
+ * recurse == 1: don't expand '@(command)@'
+ * recurse == 2: don't expand '@<java script>@'
+ */
+static gchar *
+expand(char *s, guint recurse) {
uzbl_cmdprop *c;
+ guint etype;
char upto = ' ';
- char ret[256], *vend;
+ char *end_simple_var = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½";
+ char str_end[2];
+ char ret[4096];
+ char *vend;
+ GError *err = NULL;
+ gchar *cmd_stdout = NULL;
+ gchar *mycmd = NULL;
GString *buf = g_string_new("");
+ GString *js_ret = g_string_new("");
while(*s) {
switch(*s) {
@@ -204,15 +232,51 @@ expand_vars(char *s) {
g_string_append_c(buf, *++s);
s++;
break;
+
case '@':
- if(*(s+1) == '{') {
- upto = '}'; s++;
- }
+ etype = get_exp_type(s);
s++;
- if( (vend = strchr(s, upto)) ||
- (vend = strchr(s, '\0')) ) {
- strncpy(ret, s, vend-s);
- ret[vend-s] = '\0';
+
+ switch(etype) {
+ case EXP_SIMPLE_VAR:
+ if( (vend = strpbrk(s, end_simple_var)) ||
+ (vend = strchr(s, '\0')) ) {
+ strncpy(ret, s, vend-s);
+ ret[vend-s] = '\0';
+ }
+ break;
+ case EXP_BRACED_VAR:
+ s++; upto = '}';
+ if( (vend = strchr(s, upto)) ||
+ (vend = strchr(s, '\0')) ) {
+ strncpy(ret, s, vend-s);
+ ret[vend-s] = '\0';
+ }
+ break;
+ case EXP_EXPR:
+ s++;
+ strcpy(str_end, ")@");
+ str_end[2] = '\0';
+ if( (vend = strstr(s, str_end)) ||
+ (vend = strchr(s, '\0')) ) {
+ strncpy(ret, s, vend-s);
+ ret[vend-s] = '\0';
+ }
+ break;
+ case EXP_JS:
+ s++;
+ strcpy(str_end, ">@");
+ str_end[2] = '\0';
+ if( (vend = strstr(s, str_end)) ||
+ (vend = strchr(s, '\0')) ) {
+ strncpy(ret, s, vend-s);
+ ret[vend-s] = '\0';
+ }
+ break;
+ }
+
+ if(etype == EXP_SIMPLE_VAR ||
+ etype == EXP_BRACED_VAR) {
if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
if(c->type == TYPE_STR)
g_string_append(buf, (gchar *)*c->ptr);
@@ -223,17 +287,49 @@ expand_vars(char *s) {
g_string_append_printf(buf, "%f", *(float *)c->ptr);
}
}
- if(upto == ' ') s = vend;
- else s = vend+1;
- upto = ' ';
+ if(etype == EXP_SIMPLE_VAR)
+ s = vend;
+ else
+ s = vend+1;
+ }
+ else if(recurse != 1 &&
+ etype == EXP_EXPR) {
+ mycmd = expand(ret, 1);
+ g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
+ g_free(mycmd);
+
+ if (err) {
+ g_printerr("error on running command: %s\n", err->message);
+ g_error_free (err);
+ }
+ else if (*cmd_stdout) {
+ g_string_append(buf, cmd_stdout);
+ g_free(cmd_stdout);
+ }
+ s = vend+2;
+ }
+ else if(recurse != 2 &&
+ etype == EXP_JS) {
+ mycmd = expand(ret, 2);
+ eval_js(uzbl.gui.web_view, mycmd, js_ret);
+ g_free(mycmd);
+
+ if(js_ret->str) {
+ g_string_append(buf, js_ret->str);
+ g_string_free(js_ret, TRUE);
+ js_ret = g_string_new("");
+ }
+ s = vend+2;
}
break;
+
default:
g_string_append_c(buf, *s);
s++;
break;
}
}
+ g_string_free(js_ret, TRUE);
return g_string_free(buf, FALSE);
}
@@ -447,36 +543,48 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
/* scroll a bar in a given direction */
void
scroll (GtkAdjustment* bar, GArray *argv) {
- gdouble amount;
gchar *end;
+ gdouble max_value;
+
+ gdouble page_size = gtk_adjustment_get_page_size(bar);
+ gdouble value = gtk_adjustment_get_value(bar);
+ gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
- amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
- if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
- gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
+ if (*end == '%')
+ value += page_size * amount * 0.01;
+ else
+ value += amount;
+
+ max_value = gtk_adjustment_get_upper(bar) - page_size;
+
+ if (value > max_value)
+ value = max_value; /* don't scroll past the end of the page */
+
+ gtk_adjustment_set_value (bar, value);
}
void
-scroll_begin(WebKitWebView* page, GArray *argv) {
- (void) page; (void) argv;
+scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
}
-void
-scroll_end(WebKitWebView* page, GArray *argv) {
- (void) page; (void) argv;
+static void
+scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
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));
}
-void
-scroll_vert(WebKitWebView* page, GArray *argv) {
- (void) page;
+static void
+scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
+ (void) page; (void) result;
scroll(uzbl.gui.bar_v, argv);
}
-void
-scroll_horz(WebKitWebView* page, GArray *argv) {
- (void) page;
+static void
+scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
+ (void) page; (void) result;
scroll(uzbl.gui.bar_h, argv);
}
@@ -490,10 +598,20 @@ cmd_set_status() {
update_title();
}
+static void
+toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
+ (void)page;
+ (void)argv;
+ (void)result;
+
+ webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
+}
+
void
-toggle_status_cb (WebKitWebView* page, GArray *argv) {
+toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
(void)page;
(void)argv;
+ (void)result;
if (uzbl.behave.show_status) {
gtk_widget_hide(uzbl.gui.mainbar);
@@ -596,7 +714,7 @@ log_history_cb () {
/* VIEW funcs (little webkit wrappers) */
-#define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
+#define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
VIEWFUNC(reload)
VIEWFUNC(reload_bypass_cache)
VIEWFUNC(stop_loading)
@@ -607,7 +725,7 @@ VIEWFUNC(go_forward)
#undef VIEWFUNC
/* -- command to callback/function map for things we cannot attach to any signals */
-struct {char *name; Command command[2];} cmdlist[] =
+static struct {char *key; CommandInfo value;} cmdlist[] =
{ /* key function no_split */
{ "back", {view_go_back, 0} },
{ "forward", {view_go_forward, 0} },
@@ -620,8 +738,9 @@ struct {char *name; Command command[2];} cmdlist[] =
{ "stop", {view_stop_loading, 0}, },
{ "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
{ "zoom_out", {view_zoom_out, 0}, },
- { "uri", {load_uri, NOSPLIT} },
- { "js", {run_js, NOSPLIT} },
+ { "toggle_zoom_type", {toggle_zoom_type, 0}, },
+ { "uri", {load_uri, TRUE} },
+ { "js", {run_js, TRUE} },
{ "script", {run_external_js, 0} },
{ "toggle_status", {toggle_status_cb, 0} },
{ "spawn", {spawn, 0} },
@@ -630,19 +749,19 @@ struct {char *name; Command command[2];} cmdlist[] =
{ "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
{ "exit", {close_uzbl, 0} },
{ "quit", {close_uzbl, 0} },
- { "search", {search_forward_text, NOSPLIT} },
- { "search_reverse", {search_reverse_text, NOSPLIT} },
+ { "search", {search_forward_text, TRUE} },
+ { "search_reverse", {search_reverse_text, TRUE} },
{ "dehilight", {dehilight, 0} },
{ "toggle_insert_mode", {toggle_insert_mode, 0} },
- { "set", {set_var, NOSPLIT} },
- //{ "get", {get_var, NOSPLIT} },
- { "bind", {act_bind, NOSPLIT} },
+ { "set", {set_var, TRUE} },
+ //{ "get", {get_var, TRUE} },
+ { "bind", {act_bind, TRUE} },
{ "dump_config", {act_dump_config, 0} },
- { "keycmd", {keycmd, NOSPLIT} },
- { "keycmd_nl", {keycmd_nl, NOSPLIT} },
+ { "keycmd", {keycmd, TRUE} },
+ { "keycmd_nl", {keycmd_nl, TRUE} },
{ "keycmd_bs", {keycmd_bs, 0} },
{ "chain", {chain, 0} },
- { "print", {print, NOSPLIT} }
+ { "print", {print, TRUE} }
};
void
@@ -652,7 +771,7 @@ commands_hash(void)
uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
for (i = 0; i < LENGTH(cmdlist); i++)
- g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
+ g_hash_table_insert(uzbl.behave.commands, cmdlist[i].key, &cmdlist[i].value);
}
/* -- CORE FUNCTIONS -- */
@@ -684,9 +803,9 @@ file_exists (const char * filename) {
return (access(filename, F_OK) == 0);
}
-void
-set_var(WebKitWebView *page, GArray *argv) {
- (void) page;
+static void
+set_var(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
set_var_value(g_strstrip(split[0]), value);
@@ -694,19 +813,19 @@ set_var(WebKitWebView *page, GArray *argv) {
g_strfreev(split);
}
-void
-print(WebKitWebView *page, GArray *argv) {
- (void) page;
+static void
+print(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
gchar* buf;
- buf = expand_vars(argv_idx(argv, 0));
- puts(buf);
+ buf = expand(argv_idx(argv, 0), 0);
+ g_string_assign(result, buf);
g_free(buf);
}
-void
-act_bind(WebKitWebView *page, GArray *argv) {
- (void) page;
+static void
+act_bind(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
add_binding(g_strstrip(split[0]), value);
@@ -720,9 +839,9 @@ act_dump_config() {
dump_config();
}
-void
-toggle_insert_mode(WebKitWebView *page, GArray *argv) {
- (void)page;
+static void
+toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
if (argv_idx(argv, 0)) {
if (strcmp (argv_idx(argv, 0), "0") == 0) {
@@ -737,12 +856,14 @@ toggle_insert_mode(WebKitWebView *page, GArray *argv) {
update_title();
}
-void
-load_uri (WebKitWebView *web_view, GArray *argv) {
+static void
+load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void) result;
+
if (argv_idx(argv, 0)) {
GString* newuri = g_string_new (argv_idx(argv, 0));
if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
- run_js(web_view, argv);
+ run_js(web_view, argv, NULL);
return;
}
if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
@@ -753,14 +874,109 @@ load_uri (WebKitWebView *web_view, GArray *argv) {
}
}
-void
-run_js (WebKitWebView * web_view, GArray *argv) {
+/* Javascript*/
+
+static JSValueRef
+js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
+ size_t argumentCount, const JSValueRef arguments[],
+ JSValueRef* exception) {
+ (void) function;
+ (void) thisObject;
+ (void) exception;
+
+ JSStringRef js_result_string;
+ GString *result = g_string_new("");
+
+ if (argumentCount >= 1) {
+ JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
+ size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
+ char ctl_line[arg_size];
+ JSStringGetUTF8CString(arg, ctl_line, arg_size);
+
+ parse_cmd_line(ctl_line, result);
+
+ JSStringRelease(arg);
+ }
+ js_result_string = JSStringCreateWithUTF8CString(result->str);
+
+ g_string_free(result, TRUE);
+
+ return JSValueMakeString(ctx, js_result_string);
+}
+
+static JSStaticFunction js_static_functions[] = {
+ {"run", js_run_command, kJSPropertyAttributeNone},
+};
+
+static void
+js_init() {
+ /* This function creates the class and its definition, only once */
+ if (!uzbl.js.initialized) {
+ /* it would be pretty cool to make this dynamic */
+ uzbl.js.classdef = kJSClassDefinitionEmpty;
+ uzbl.js.classdef.staticFunctions = js_static_functions;
+
+ uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
+ }
+}
+
+
+static void
+eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
+ WebKitWebFrame *frame;
+ JSGlobalContextRef context;
+ JSObjectRef globalobject;
+ JSStringRef var_name;
+
+ JSStringRef js_script;
+ JSValueRef js_result;
+ JSStringRef js_result_string;
+ size_t js_result_size;
+
+ js_init();
+
+ frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
+ context = webkit_web_frame_get_global_context(frame);
+ globalobject = JSContextGetGlobalObject(context);
+
+ /* uzbl javascript namespace */
+ var_name = JSStringCreateWithUTF8CString("Uzbl");
+ JSObjectSetProperty(context, globalobject, var_name,
+ JSObjectMake(context, uzbl.js.classref, NULL),
+ kJSClassAttributeNone, NULL);
+
+ /* evaluate the script and get return value*/
+ js_script = JSStringCreateWithUTF8CString(script);
+ js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
+ if (js_result && !JSValueIsUndefined(context, js_result)) {
+ js_result_string = JSValueToStringCopy(context, js_result, NULL);
+ js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
+
+ if (js_result_size) {
+ char js_result_utf8[js_result_size];
+ JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
+ g_string_assign(result, js_result_utf8);
+ }
+
+ JSStringRelease(js_result_string);
+ }
+
+ /* cleanup */
+ JSObjectDeleteProperty(context, globalobject, var_name, NULL);
+
+ JSStringRelease(var_name);
+ JSStringRelease(js_script);
+}
+
+static void
+run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
if (argv_idx(argv, 0))
- webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
+ eval_js(web_view, argv_idx(argv, 0), result);
}
-void
-run_external_js (WebKitWebView * web_view, GArray *argv) {
+static void
+run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
+ (void) result;
if (argv_idx(argv, 0)) {
GArray* lines = read_file_by_line (argv_idx (argv, 0));
gchar* js = NULL;
@@ -786,7 +1002,7 @@ run_external_js (WebKitWebView * web_view, GArray *argv) {
g_free (js);
js = newjs;
}
- webkit_web_view_execute_script (web_view, js);
+ eval_js (web_view, js, result);
g_free (js);
g_array_free (lines, TRUE);
}
@@ -810,19 +1026,21 @@ search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
}
}
-void
-search_forward_text (WebKitWebView *page, GArray *argv) {
+static void
+search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
+ (void) result;
search_text(page, argv, TRUE);
}
-void
-search_reverse_text (WebKitWebView *page, GArray *argv) {
+static void
+search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
+ (void) result;
search_text(page, argv, FALSE);
}
-void
-dehilight (WebKitWebView *page, GArray *argv) {
- (void) argv;
+static void
+dehilight (WebKitWebView *page, GArray *argv, GString *result) {
+ (void) argv; (void) result;
webkit_web_view_set_highlight_text_matches (page, FALSE);
}
@@ -846,54 +1064,56 @@ new_window_load_uri (const gchar * uri) {
g_string_free (to_execute, TRUE);
}
-void
-chain (WebKitWebView *page, GArray *argv) {
- (void)page;
+static void
+chain (WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) result;
gchar *a = NULL;
gchar **parts = NULL;
guint i = 0;
while ((a = argv_idx(argv, i++))) {
parts = g_strsplit (a, " ", 2);
- parse_command(parts[0], parts[1]);
+ parse_command(parts[0], parts[1], result);
g_strfreev (parts);
}
}
-void
-keycmd (WebKitWebView *page, GArray *argv) {
+static void
+keycmd (WebKitWebView *page, GArray *argv, GString *result) {
(void)page;
(void)argv;
+ (void)result;
g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
run_keycmd(FALSE);
update_title();
}
-void
-keycmd_nl (WebKitWebView *page, GArray *argv) {
+static void
+keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
(void)page;
(void)argv;
+ (void)result;
g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
run_keycmd(TRUE);
update_title();
}
-void
-keycmd_bs (WebKitWebView *page, GArray *argv) {
+static void
+keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
+ gchar *prev;
(void)page;
(void)argv;
- g_string_truncate(uzbl.state.keycmd,
- /* Calculate the number of bytes to truncate...
- * This is not simply (len-1) when dealing with UTF-8 string */
- g_utf8_offset_to_pointer(uzbl.state.keycmd->str,
- g_utf8_strlen(uzbl.state.keycmd->str, uzbl.state.keycmd->len) - 1)
- - uzbl.state.keycmd->str);
+ (void)result;
+ prev = g_utf8_find_prev_char(uzbl.state.keycmd->str, uzbl.state.keycmd->str + uzbl.state.keycmd->len);
+ if (prev)
+ g_string_truncate(uzbl.state.keycmd, prev - uzbl.state.keycmd->str);
update_title();
}
-void
-close_uzbl (WebKitWebView *page, GArray *argv) {
+static void
+close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
(void)page;
(void)argv;
+ (void)result;
gtk_main_quit ();
}
@@ -1225,26 +1445,26 @@ split_quoted(const gchar* src, const gboolean unquote) {
return ret;
}
-void
-spawn(WebKitWebView *web_view, GArray *argv) {
- (void)web_view;
+static void
+spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
//TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
if (argv_idx(argv, 0))
run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
}
-void
-spawn_sync(WebKitWebView *web_view, GArray *argv) {
- (void)web_view;
+static void
+spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
if (argv_idx(argv, 0))
run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
TRUE, &uzbl.comm.sync_stdout);
}
-void
-spawn_sh(WebKitWebView *web_view, GArray *argv) {
- (void)web_view;
+static void
+spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
if (!uzbl.behave.shell_cmd) {
g_printerr ("spawn_sh: shell_cmd is not set!\n");
return;
@@ -1263,9 +1483,9 @@ spawn_sh(WebKitWebView *web_view, GArray *argv) {
g_strfreev (cmd);
}
-void
-spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
- (void)web_view;
+static void
+spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
+ (void)web_view; (void)result;
if (!uzbl.behave.shell_cmd) {
g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
return;
@@ -1285,23 +1505,33 @@ spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
g_strfreev (cmd);
}
-void
-parse_command(const char *cmd, const char *param) {
- Command *c;
+static void
+parse_command(const char *cmd, const char *param, GString *result) {
+ CommandInfo *c;
if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
-
guint i;
gchar **par = split_quoted(param, TRUE);
GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
- if (c[1] == NOSPLIT) { /* don't split */
+ if (c->no_split) { /* don't split */
sharg_append(a, param);
} else if (par) {
for (i = 0; i < g_strv_length(par); i++)
sharg_append(a, par[i]);
}
- c[0](uzbl.gui.web_view, a);
+
+ if (result == NULL) {
+ GString *result_print = g_string_new("");
+
+ c->function(uzbl.gui.web_view, a, result_print);
+ if (result_print->len)
+ printf("%*s\n", result_print->len, result_print->str);
+
+ g_string_free(result_print, TRUE);
+ } else {
+ c->function(uzbl.gui.web_view, a, result);
+ }
g_strfreev (par);
g_array_free (a, TRUE);
@@ -1331,7 +1561,8 @@ set_proxy_url() {
void
set_icon() {
if(file_exists(uzbl.gui.icon)) {
- gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
+ if (uzbl.gui.main_window)
+ gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
} else {
g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
}
@@ -1341,7 +1572,7 @@ void
cmd_load_uri() {
GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
g_array_append_val (a, uzbl.state.uri);
- load_uri(uzbl.gui.web_view, a);
+ load_uri(uzbl.gui.web_view, a, NULL);
g_array_free (a, TRUE);
}
@@ -1574,17 +1805,17 @@ set_var_value(gchar *name, gchar *val) {
if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
/* check for the variable type */
if (c->type == TYPE_STR) {
- buf = expand_vars(val);
+ buf = expand(val, 0);
g_free(*c->ptr);
*c->ptr = buf;
} else if(c->type == TYPE_INT) {
int *ip = (int *)c->ptr;
- buf = expand_vars(val);
+ buf = expand(val, 0);
*ip = (int)strtoul(buf, &endp, 10);
g_free(buf);
} else if (c->type == TYPE_FLOAT) {
float *fp = (float *)c->ptr;
- buf = expand_vars(val);
+ buf = expand(val, 0);
*fp = strtod(buf, &endp);
g_free(buf);
}
@@ -1608,8 +1839,8 @@ render_html() {
}
enum {M_CMD, M_HTML};
-void
-parse_cmd_line(const char *ctl_line) {
+static void
+parse_cmd_line(const char *ctl_line, GString *result) {
Behaviour *b = &uzbl.behave;
size_t len=0;
@@ -1642,7 +1873,7 @@ parse_cmd_line(const char *ctl_line) {
else ctlstrip = g_strdup(ctl_line);
tokens = g_strsplit(ctlstrip, " ", 2);
- parse_command(tokens[0], tokens[1]);
+ parse_command(tokens[0], tokens[1], result);
g_free(ctlstrip);
g_strfreev(tokens);
}
@@ -1650,9 +1881,9 @@ parse_cmd_line(const char *ctl_line) {
gchar*
build_stream_name(int type, const gchar* dir) {
- char *xwin_str;
+ char *xwin_str = NULL;
State *s = &uzbl.state;
- gchar *str;
+ gchar *str = NULL;
xwin_str = itos((int)uzbl.xwin);
if (type == FIFO) {
@@ -1688,7 +1919,7 @@ control_fifo(GIOChannel *gio, GIOCondition condition) {
g_error_free (err);
}
- parse_cmd_line(ctl_line);
+ parse_cmd_line(ctl_line, NULL);
g_free(ctl_line);
return TRUE;
@@ -1732,7 +1963,7 @@ control_stdin(GIOChannel *gio, GIOCondition condition) {
if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
return FALSE;
- parse_cmd_line(ctl_line);
+ parse_cmd_line(ctl_line, NULL);
g_free(ctl_line);
return TRUE;
@@ -1760,53 +1991,53 @@ create_stdin () {
gboolean
control_socket(GIOChannel *chan) {
struct sockaddr_un remote;
- char buffer[512], *ctl_line;
- char temp[128];
- int sock, clientsock, n, done;
- unsigned int t;
-
- sock = g_io_channel_unix_get_fd(chan);
-
- memset (buffer, 0, sizeof (buffer));
+ unsigned int t = sizeof(remote);
+ int clientsock;
+ GIOChannel *clientchan;
- t = sizeof (remote);
- clientsock = accept (sock, (struct sockaddr *) &remote, &t);
-
- done = 0;
- do {
- memset (temp, 0, sizeof (temp));
- n = recv (clientsock, temp, 128, 0);
- if (n == 0) {
- buffer[strlen (buffer)] = '\0';
- done = 1;
- }
- if (!done)
- strcat (buffer, temp);
- } while (!done);
-
- if (strcmp (buffer, "\n") < 0) {
- buffer[strlen (buffer) - 1] = '\0';
- } else {
- buffer[strlen (buffer)] = '\0';
+ clientsock = accept (g_io_channel_unix_get_fd(chan),
+ (struct sockaddr *) &remote, &t);
+
+ if ((clientchan = g_io_channel_unix_new(clientsock))) {
+ g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
+ (GIOFunc) control_client_socket, clientchan);
}
- close (clientsock);
- ctl_line = g_strdup(buffer);
- parse_cmd_line (ctl_line);
-/*
- TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
+ return TRUE;
+}
+
+static gboolean
+control_client_socket(GIOChannel *clientchan) {
+ char *ctl_line;
+ GString *result = g_string_new("");
GError *error = NULL;
- gsize len;
GIOStatus ret;
- ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
- if (ret == G_IO_STATUS_ERROR)
- g_error ("Error reading: %s\n", error->message);
+ gsize len;
- printf("Got line %s (%u bytes) \n",ctl_line, len);
- if(ctl_line) {
- parse_line(ctl_line);
-*/
+ ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_warning ("Error reading: %s\n", error->message);
+ g_io_channel_shutdown(clientchan, TRUE, &error);
+ return FALSE;
+ } else if (ret == G_IO_STATUS_EOF) {
+ /* shutdown and remove channel watch from main loop */
+ g_io_channel_shutdown(clientchan, TRUE, &error);
+ return FALSE;
+ }
+ if (ctl_line) {
+ parse_cmd_line (ctl_line, result);
+ g_string_append_c(result, '\n');
+ ret = g_io_channel_write_chars (clientchan, result->str, result->len,
+ &len, &error);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_warning ("Error writing: %s", error->message);
+ }
+ g_io_channel_flush(clientchan, &error);
+ }
+
+ if (error) g_error_free (error);
+ g_string_free(result, TRUE);
g_free(ctl_line);
return TRUE;
}
@@ -1868,7 +2099,8 @@ update_title (void) {
if (b->show_status) {
if (b->title_format_short) {
parsed = expand_template(b->title_format_short, FALSE);
- gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+ if (uzbl.gui.main_window)
+ gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
g_free(parsed);
}
if (b->status_format) {
@@ -1880,12 +2112,14 @@ update_title (void) {
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);
+ if (uzbl.gui.main_window)
+ gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
}
} else {
if (b->title_format_long) {
parsed = expand_template(b->title_format_long, FALSE);
- gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+ if (uzbl.gui.main_window)
+ gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
g_free(parsed);
}
}
@@ -1915,7 +2149,7 @@ key_press_cb (GtkWidget* window, GdkEventKey* event)
if (event->keyval == GDK_Escape) {
g_string_truncate(uzbl.state.keycmd, 0);
update_title();
- dehilight(uzbl.gui.web_view, NULL);
+ dehilight(uzbl.gui.web_view, NULL, NULL);
return TRUE;
}
@@ -1936,7 +2170,7 @@ key_press_cb (GtkWidget* window, GdkEventKey* event)
}
if (event->keyval == GDK_BackSpace)
- keycmd_bs(NULL, NULL);
+ keycmd_bs(NULL, NULL, NULL);
gboolean key_ret = FALSE;
if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
@@ -1955,7 +2189,7 @@ run_keycmd(const gboolean key_ret) {
Action *act;
if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
g_string_truncate(uzbl.state.keycmd, 0);
- parse_command(act->name, act->param);
+ parse_command(act->name, act->param, NULL);
return;
}
@@ -1997,7 +2231,7 @@ exec_paramcmd(const Action *act, const guint i) {
g_string_printf (actionname, act->name, parampart->str);
if (act->param)
g_string_printf (actionparam, act->param, parampart->str);
- parse_command(actionname->str, actionparam->str);
+ parse_command(actionname->str, actionparam->str, NULL);
g_string_free(actionname, TRUE);
g_string_free(actionparam, TRUE);
g_string_free(parampart, TRUE);
@@ -2060,7 +2294,17 @@ create_window () {
return window;
}
-gchar**
+static
+GtkPlug* create_plug () {
+ GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
+ g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
+ g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
+
+ return plug;
+}
+
+
+static gchar**
inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
/*
If actname is one that calls an external command, this function will inject
@@ -2149,13 +2393,13 @@ run_handler (const gchar *act, const gchar *args) {
cp++;
}
- parse_command(parts[0], &(newargs->str[1]));
+ parse_command(parts[0], &(newargs->str[1]), NULL);
g_string_free(newargs, TRUE);
g_strfreev(chainparts);
} else {
gchar **inparts = inject_handler_args(parts[0], parts[1], args);
- parse_command(inparts[0], inparts[1]);
+ parse_command(inparts[0], inparts[1], NULL);
g_free(inparts[0]);
g_free(inparts[1]);
}
@@ -2239,7 +2483,7 @@ settings_init () {
Network *n = &uzbl.net;
int i;
for (i = 0; default_config[i].command != NULL; i++) {
- parse_cmd_line(default_config[i].command);
+ parse_cmd_line(default_config[i].command, NULL);
}
if (!s->config_file) {
@@ -2252,7 +2496,7 @@ settings_init () {
gchar* line;
while ((line = g_array_index(lines, gchar*, i))) {
- parse_cmd_line (line);
+ parse_cmd_line (line, NULL);
i ++;
g_free (line);
}
@@ -2492,17 +2736,25 @@ main (int argc, char* argv[]) {
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);
-
+ if (uzbl.state.socket_id) {
+ uzbl.gui.plug = create_plug ();
+ gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
+ gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
+ } else {
+ uzbl.gui.main_window = create_window ();
+ gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
+ gtk_widget_show_all (uzbl.gui.main_window);
+ uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
+ }
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);
if (uzbl.state.verbose) {
printf("Uzbl start location: %s\n", argv[0]);
- printf("window_id %i\n",(int) uzbl.xwin);
+ if (uzbl.state.socket_id)
+ printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
+ else
+ printf("window_id %i\n",(int) uzbl.xwin);
printf("pid %i\n", getpid ());
printf("name: %s\n", uzbl.state.instance_name);
}
diff --git a/uzbl.h b/uzbl.h
index 9c5db85..5ae8ca5 100644
--- a/uzbl.h
+++ b/uzbl.h
@@ -11,8 +11,6 @@
*
*/
-#define NOSPLIT ((void*)1)
-
enum {
/* statusbar symbols */
SYM_TITLE, SYM_URI, SYM_NAME,
@@ -67,6 +65,7 @@ typedef struct {
/* gui elements */
typedef struct {
GtkWidget* main_window;
+ GtkPlug* plug;
GtkWidget* scrolled_win;
GtkWidget* vbox;
GtkWidget* mainbar;
@@ -102,7 +101,8 @@ typedef struct {
typedef struct {
gchar *uri;
gchar *config_file;
- char *instance_name;
+ int socket_id;
+ char *instance_name;
gchar *selected_url;
gchar *executable_path;
GString* keycmd;
@@ -176,6 +176,12 @@ typedef struct {
GHashTable* commands;
} Behaviour;
+/* javascript */
+typedef struct {
+ gboolean initialized;
+ JSClassDefinition classdef;
+ JSClassRef classref;
+} Javascript;
/* main uzbl data structure */
typedef struct {
@@ -184,6 +190,7 @@ typedef struct {
Network net;
Behaviour behave;
Communication comm;
+ Javascript js;
Window xwin;
GScanner *scan;
@@ -247,8 +254,8 @@ setup_signal(int signe, sigfunc *shandler);
gboolean
set_var_value(gchar *name, gchar *val);
-void
-print(WebKitWebView *page, GArray *argv);
+static void
+print(WebKitWebView *page, GArray *argv, GString *result);
gboolean
new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data);
@@ -262,8 +269,11 @@ create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer us
gboolean
download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data);
-void
-toggle_status_cb (WebKitWebView* page, GArray *argv);
+static void
+toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result);
+
+static void
+toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result);
void
link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data);
@@ -301,51 +311,51 @@ new_action(const gchar *name, const gchar *param);
bool
file_exists (const char * filename);
-void
-toggle_insert_mode(WebKitWebView *page, GArray *argv);
+static void
+toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result);
-void
-load_uri (WebKitWebView * web_view, GArray *argv);
+static void
+load_uri (WebKitWebView * web_view, GArray *argv, GString *result);
void
new_window_load_uri (const gchar * uri);
-void
-chain (WebKitWebView *page, GArray *argv);
+static void
+chain (WebKitWebView *page, GArray *argv, GString *result);
-void
-keycmd (WebKitWebView *page, GArray *argv);
+static void
+keycmd (WebKitWebView *page, GArray *argv, GString *result);
-void
-keycmd_nl (WebKitWebView *page, GArray *argv);
+static void
+keycmd_nl (WebKitWebView *page, GArray *argv, GString *result);
-void
-keycmd_bs (WebKitWebView *page, GArray *argv);
+static void
+keycmd_bs (WebKitWebView *page, GArray *argv, GString *result);
-void
-close_uzbl (WebKitWebView *page, GArray *argv);
+static void
+close_uzbl (WebKitWebView *page, GArray *argv, GString *result);
gboolean
run_command(const gchar *command, const guint npre,
const gchar **args, const gboolean sync, char **output_stdout);
-void
-spawn(WebKitWebView *web_view, GArray *argv);
+static void
+spawn(WebKitWebView *web_view, GArray *argv, GString *result);
-void
-spawn_sh(WebKitWebView *web_view, GArray *argv);
+static void
+spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result);
-void
-spawn_sync(WebKitWebView *web_view, GArray *argv);
+static void
+spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-void
-spawn_sh_sync(WebKitWebView *web_view, GArray *argv);
+static void
+spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-void
-parse_command(const char *cmd, const char *param);
+static void
+parse_command(const char *cmd, const char *param, GString *result);
-void
-parse_cmd_line(const char *ctl_line);
+static void
+parse_cmd_line(const char *ctl_line, GString *result);
gchar*
build_stream_name(int type, const gchar *dir);
@@ -368,7 +378,10 @@ init_socket(gchar *dir);
gboolean
control_socket(GIOChannel *chan);
-void
+static gboolean
+control_client_socket(GIOChannel *chan);
+
+static void
update_title (void);
gboolean
@@ -389,7 +402,10 @@ create_mainbar ();
GtkWidget*
create_window ();
-void
+static
+GtkPlug* create_plug ();
+
+static void
run_handler (const gchar *act, const gchar *args);
void
@@ -407,20 +423,23 @@ settings_init ();
void
search_text (WebKitWebView *page, GArray *argv, const gboolean forward);
-void
-search_forward_text (WebKitWebView *page, GArray *argv);
+static void
+search_forward_text (WebKitWebView *page, GArray *argv, GString *result);
-void
-search_reverse_text (WebKitWebView *page, GArray *argv);
+static void
+search_reverse_text (WebKitWebView *page, GArray *argv, GString *result);
-void
-dehilight (WebKitWebView *page, GArray *argv);
+static void
+dehilight (WebKitWebView *page, GArray *argv, GString *result);
-void
-run_js (WebKitWebView * web_view, GArray *argv);
+static void
+run_js (WebKitWebView * web_view, GArray *argv, GString *result);
-void
-run_external_js (WebKitWebView * web_view, GArray *argv);
+static void
+run_external_js (WebKitWebView * web_view, GArray *argv, GString *result);
+
+static void
+eval_js(WebKitWebView * web_view, gchar *script, GString *result);
void handle_cookies (SoupSession *session,
SoupMessage *msg,
@@ -429,11 +448,11 @@ void
save_cookies (SoupMessage *msg,
gpointer user_data);
-void
-set_var(WebKitWebView *page, GArray *argv);
+static void
+set_var(WebKitWebView *page, GArray *argv, GString *result);
-void
-act_bind(WebKitWebView *page, GArray *argv);
+static void
+act_bind(WebKitWebView *page, GArray *argv, GString *result);
void
act_dump_config();
@@ -453,6 +472,11 @@ dump_key_hash(gpointer k, gpointer v, gpointer ud);
void
dump_config();
+typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
+typedef struct {
+ Command function;
+ gboolean no_split;
+} CommandInfo;
/* Command callbacks */
void
diff --git a/uzblctrl.c b/uzblctrl.c
index f0fe732..93584bc 100644
--- a/uzblctrl.c
+++ b/uzblctrl.c
@@ -2,17 +2,9 @@
/* Socket code more or less completely copied from here: http://www.ecst.csuchico.edu/~beej/guide/ipc/usock.html */
#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
-#include <webkit/webkit.h>
-#include <pthread.h>
#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
-#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -31,7 +23,7 @@ static GOptionEntry entries[] =
int
main(int argc, char* argv[]) {
GError *error = NULL;
- GOptionContext* context = g_option_context_new ("- utility for controlling and interacting with uzbl through its socket file"); //TODO: get stuff back from uzbl
+ GOptionContext* context = g_option_context_new ("- utility for controlling and interacting with uzbl through its socket file"); /* TODO: get stuff back from uzbl */
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);
@@ -40,6 +32,7 @@ main(int argc, char* argv[]) {
if (sockpath && command) {
int s, len;
struct sockaddr_un remote;
+ char tmp;
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror ("socket");
@@ -55,16 +48,23 @@ main(int argc, char* argv[]) {
exit (1);
}
- if (send (s, command, strlen (command), 0) == -1) {
+ if ((send (s, command, strlen (command), 0) == -1) ||
+ (send (s, "\n", 1, 0) == -1)) {
perror ("send");
exit (1);
}
+ while ((len = recv (s, &tmp, 1, 0))) {
+ putchar(tmp);
+ if (tmp == '\n')
+ break;
+ }
+
close(s);
return 0;
} else {
- puts ("Usage: uzblctrl -s /path/to/socket -c \"command\"");
+ fprintf(stderr, "Usage: uzblctrl -s /path/to/socket -c \"command\"");
return 1;
}
}