aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brendan Taylor <whateley@gmail.com>2011-03-13 21:17:43 -0600
committerGravatar Brendan Taylor <whateley@gmail.com>2011-03-13 21:17:43 -0600
commit5ec505fdb007d22bcfb5631e88e67038b06d778a (patch)
tree9b467f9fce2266114bcfe12cf7c1db0596b1f50b
parent6b2a973e17a0cf4d3cdc88e71973624929018c78 (diff)
parent0d9073aa31d7592ae3e7b321ac71c4b480750e08 (diff)
Merge branch 'experimental' into dev/fix-shell-scripts
Conflicts: examples/config/config examples/data/scripts/follow.sh examples/data/scripts/formfiller.sh
-rw-r--r--AUTHORS3
-rw-r--r--Makefile23
-rw-r--r--README12
-rw-r--r--docs/README.cookies63
-rw-r--r--docs/README.uzbl-event-manager39
-rw-r--r--docs/formfiller-data-format35
-rw-r--r--examples/config/config29
-rw-r--r--examples/data/per-site-settings2
-rw-r--r--examples/data/plugins/bind.py13
-rw-r--r--examples/data/plugins/config.py7
-rw-r--r--examples/data/plugins/cookies.py60
-rw-r--r--examples/data/plugins/downloads.py18
-rw-r--r--examples/data/plugins/history.py129
-rw-r--r--examples/data/plugins/keycmd.py5
-rw-r--r--examples/data/plugins/on_event.py6
-rw-r--r--examples/data/scripts/follow.js416
-rwxr-xr-xexamples/data/scripts/follow.sh30
-rw-r--r--examples/data/scripts/formfiller.js67
-rwxr-xr-xexamples/data/scripts/formfiller.sh320
-rwxr-xr-xexamples/data/scripts/uzbl-cookie-daemon677
-rwxr-xr-xexamples/data/scripts/uzbl-event-manager22
-rwxr-xr-xexamples/data/scripts/uzbl-tabbed7
-rw-r--r--examples/data/style.css38
-rw-r--r--examples/uzbl-cookie-manager.c381
-rw-r--r--extras/vim/syntax/uzbl.vim15
-rw-r--r--src/callbacks.c258
-rw-r--r--src/callbacks.h9
-rw-r--r--src/cookie-jar.c300
-rw-r--r--src/cookie-jar.h12
-rw-r--r--src/events.c88
-rw-r--r--src/events.h14
-rw-r--r--src/inspector.c4
-rw-r--r--src/io.c346
-rw-r--r--src/io.h23
-rw-r--r--src/menu.c192
-rw-r--r--src/menu.h18
-rw-r--r--src/util.c166
-rw-r--r--src/util.h23
-rwxr-xr-xsrc/uzbl-browser7
-rw-r--r--src/uzbl-core.c1496
-rw-r--r--src/uzbl-core.h478
-rw-r--r--tests/test-command.c60
-rw-r--r--tests/test-expand.c33
43 files changed, 2399 insertions, 3545 deletions
diff --git a/AUTHORS b/AUTHORS
index f5144a1..ff31818 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -35,7 +35,7 @@ In alphabetical order:
Daiki Ueno (ueno) - fix for crash when opening image in new window
Damien Leon - misc
Daniel M. Hackney - documentation cleanups
- David Keijser (keis) - the add_cookie/delete_cookie + distributor system, various C and python patches.
+ David Keijser (keis) - the add_cookie/delete_cookie + distributor system, consistent event syntax, various C and python patches.
Devon Jones <devon.jones@gmail.com> - uzbl_tabbed: bring_to_front
Dieter Plaetinck (Dieter@be) <dieter AT plaetinck.be> - several contributions
Dmytro Milinevskyy - uzbl-tabbed useability patches
@@ -75,6 +75,7 @@ In alphabetical order:
Simon Lipp (sloonz) - various patches, EM contributions
Sylvester Johansson (scj) - form filler script & different take on link follower
Tassilo Horn (tsdh) - $VISUAL patch
+ Taylan Ulrich Bayırlı (taylanub) - updated form filler
Thorsten Wilms - logo design
Tom Adams (holizz) - few patches, cookies.py, gtkplug/socket & proof of concept uzbl_tabbed.py, scheme_handler
Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch
diff --git a/Makefile b/Makefile
index f33a626..62bc9b5 100644
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ HEAD = $(wildcard src/*.h)
OBJ = $(foreach obj, $(SRC:.c=.o), $(notdir $(obj)))
LOBJ = $(foreach obj, $(SRC:.c=.lo), $(notdir $(obj)))
-all: uzbl-browser uzbl-cookie-manager
+all: uzbl-browser
VPATH:=src
@@ -49,11 +49,7 @@ ${OBJ}: ${HEAD}
uzbl-core: ${OBJ}
-uzbl-cookie-manager: examples/uzbl-cookie-manager.o util.o
- @echo -e "\n${CC} -o $@ examples/uzbl-cookie-manager.o util.o ${shell pkg-config --libs glib-2.0 libsoup-2.4}"
- @${CC} -o $@ examples/uzbl-cookie-manager.o util.o $(shell pkg-config --libs glib-2.0 libsoup-2.4)
-
-uzbl-browser: uzbl-core uzbl-cookie-manager
+uzbl-browser: uzbl-core
# the 'tests' target can never be up to date
.PHONY: tests
@@ -87,10 +83,8 @@ test-uzbl-browser-sandbox: uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
cp -np ./misc/env.sh ./sandbox/env.sh
- -source ./sandbox/env.sh && uzbl-cookie-manager -v
-source ./sandbox/env.sh && uzbl-event-manager restart -avv
source ./sandbox/env.sh && uzbl-browser --uri http://www.uzbl.org --verbose
- kill `cat ./sandbox/home/.cache/uzbl/cookie_daemon_socket.pid`
source ./sandbox/env.sh && uzbl-event-manager stop -ivv
make DESTDIR=./sandbox uninstall
rm -rf ./sandbox/usr
@@ -100,18 +94,20 @@ test-uzbl-tabbed-sandbox: uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser
make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data
cp -np ./misc/env.sh ./sandbox/env.sh
- -source ./sandbox/env.sh && uzbl-cookie-manager -v
-source ./sandbox/env.sh && uzbl-event-manager restart -avv
source ./sandbox/env.sh && ./sandbox/home/.local/share/uzbl/scripts/uzbl-tabbed
- kill `cat ./sandbox/home/.cache/uzbl/cookie_daemon_socket.pid`
source ./sandbox/env.sh && uzbl-event-manager stop -ivv
make DESTDIR=./sandbox uninstall
rm -rf ./sandbox/usr
clean:
rm -f uzbl-core
- rm -f uzbl-cookie-manager
- rm -f *.o *.lo
+ rm -f uzbl-core.o
+ rm -f events.o
+ rm -f callbacks.o
+ rm -f inspector.o
+ rm -f cookie-jar.o
+ rm -f util.o
find ./examples/ -name "*.pyc" -delete
cd ./tests/; $(MAKE) clean
rm -rf ./sandbox/
@@ -137,9 +133,8 @@ install-uzbl-core: all install-dirs
chmod 755 $(INSTALLDIR)/share/uzbl/examples/data/scripts/*
install -m755 uzbl-core $(INSTALLDIR)/bin/uzbl-core
-install-uzbl-browser: uzbl-cookie-manager install-dirs
+install-uzbl-browser: install-dirs
install -m755 src/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser
- install -m755 uzbl-cookie-manager $(INSTALLDIR)/bin/uzbl-cookie-manager
install -m755 examples/data/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager
mv $(INSTALLDIR)/bin/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser.bak
sed 's#^PREFIX=.*#PREFIX=$(RUN_PREFIX)#' < $(INSTALLDIR)/bin/uzbl-browser.bak > $(INSTALLDIR)/bin/uzbl-browser
diff --git a/README b/README
index d1f2357..6709bf5 100644
--- a/README
+++ b/README
@@ -183,11 +183,6 @@ The following commands are recognized:
the end, so the argument numbers will be higher.
* `sync_sh <command>`
- Synchronous version of `sh`, See `sync_spawn`.
-* `talk_to_socket <socketfile> <tokens>`
- - Send a message to `<socketfile>` and wait for a response. `<tokens>` are
- concatenated and separated by ASCII NUL bytes.
- - Expects the socket type to be `SOCK_SEQPACKET` (see `connect(2)`).
- - Waits for 500ms for a response.
* `exit`
- Closes `uzbl`.
* `search <string>`
@@ -265,6 +260,8 @@ The following commands are recognized:
* 'delete_cookie <domain> <path> <name> <value> [<scheme> <expires>]`
- Deletes a matching cookie from the cookie jar. scheme and expire time
is currently not considered when matching.
+* 'clear_cookies`
+ - Clears all cookies from the cookie jar
### VARIABLES AND CONSTANTS
@@ -361,6 +358,7 @@ file).
stylesheet.
* `resizable_text_areas`: Whether text areas can be resized (default 0).
* `default_encoding`: The default text encoding (default "iso-8859-1").
+* `current_encoding`: This can be set to force a text encoding.
* `enforce_96_dpi`: Enforce a resolution of 96 DPI (default 1).
* `caret_browsing`: Whether the caret is enabled in the text portion of pages
(default 0).
@@ -775,12 +773,12 @@ Events/requests which the EM and its plugins listens for
move the cursor back by one character.
* `START_COMPLETION`: TODO explain completion
* `BLACKLIST_COOKIE`: add a rule for blacklisting cookies
- - `request BLACKLIST_COOKIE <component> <regexp>`: Blacklist cookies where
+ - `request BLACKLIST_COOKIE [<component> <regexp>]*`: Blacklist cookies where
`<component>` matches `<regexp>`. `<component>` is one of `domain`,
`path`, `name`, `value`, `scheme` or `expires`.
* `WHITELIST_COOKIE`: add a rule for whitelisting cookies (if any whitelist is
set then only cookies that are whitelisted cookies will be used)
- - `request WHITELIST_COOKIE <component> <regexp>`: Whitelist cookies where
+ - `request WHITELIST_COOKIE [<component> <regexp>]*`: Whitelist cookies where
`<component>` matches `<regexp>`. `<component>` is one of `domain`,
`path`, `name`, `value`, `scheme` or `expires`.
diff --git a/docs/README.cookies b/docs/README.cookies
deleted file mode 100644
index 148603f..0000000
--- a/docs/README.cookies
+++ /dev/null
@@ -1,63 +0,0 @@
-# Cookies and Uzbl #
-
-The speed of cookie lookups is important, since a single page load can involve
-dozens of HTTP requests, each of which needs a separate cookie lookup (since
-another instance of uzbl may have obtained new cookies for a site).
-
-It is possible handle cookie lookup (and storage) using a `spawn_async` cookie
-handler, but spawning new processes is inherently slow so a `talk_to_socket`
-cookie daemon (like the default uzbl-cookie-manager) is recommended.
-
-## uzbl-cookie-manager ##
-
-uzbl-cookie-manager is a cookie daemon based on libsoup's SoupCookieJar. Cookies
-are stored in a file in the Mozilla cookies.txt format (default location
-$XDG_DATA_HOME/.local/share/cookies.txt).
-
-### uzbl-cookie-manager Whitelist ###
-
-If a whitelist file is present (default location
-$XDG_CONFIG_HOME/uzbl/cookie_whitelist), then website attempts to set cookies
-will be ignored unless the site's domain is present in the whitelist.
-
-The whitelist can contain comment lines beginning with `#`, and domain lines. A
-domain line beginning with . will whitelist the given domain name and any
-subdomain of it. Otherwise only exact matches of the domain are whitelisted.
-
-For instance, given this whitelist file:
-
- example.com
- .uzbl.org
-
-uzbl-cookie-manager would accept cookies for example.com, uzbl.org and
-www.uzbl.org, but ignore cookies set for www.example.com (and any other
-domain that is not a subdomain of uzbl.org).
-
-## uzbl-cookie-daemon ##
-
-uzbl-cookie-daemon is a Python cookie daemon based on Python's cookielib.
-Cookielib's lookup algorithm isn't very efficient for our needs, so
-uzbl-cookie-daemon is noticeably slow.
-
-## Cookie Daemon Protocol ##
-
-When uzbl's `cookie_handler` variable is set to `talk_to_socket path`, uzbl
-connects to the Unix domain socket located at `path`. uzbl will send a cookie
-lookup request on this socket every time it makes an HTTP request. The format of
-this lookup request is:
-
- GET\0scheme\0host\0path\0
-
-where `\0` is the null character, `scheme` is the URL scheme (http or https),
-`host` is the hostname from the URL and `path` is the requested path. The cookie
-daemon should respond with the names and values of cookies that match the
-request, in the format used by the `Cookie` header, terminated with a `\0`.
-
-When a website adds, deletes or changes a cookie, uzbl notifies the cookie
-daemon with a request in the format:
-
- PUT\0scheme\0host\0path\0name=value\0
-
-where `scheme`, `host` and `path` are (approximately) as above, and `name=value`
-is the cookie name-value pair to store. The cookie daemon should respond by
-writing `\0` to the socket.
diff --git a/docs/README.uzbl-event-manager b/docs/README.uzbl-event-manager
index 074811e..23e185c 100644
--- a/docs/README.uzbl-event-manager
+++ b/docs/README.uzbl-event-manager
@@ -83,17 +83,36 @@ events. If any whitelist is set, then any cookie that is not whitelisted will
be rejected. Otherwise, only cookies that have been blacklisted will be
rejected.
-BLACKLIST_COOKIE <part> <re>
- Adds a new blacklist filter. cookies where the component specified by
- `part` matches the regular expression `re` will be filtered. part can be
- either 0-5 or any of the symbolic names domain, path, name, value, scheme,
- expires
+BLACKLIST_COOKIE [<component> <re>]*
+ Adds a new blacklist filter. cookies where the components specified by
+ `component` matches the regular expression `re` will be filtered. component
+ may be either 0-5 or any of the symbolic names domain, path, name, value,
+ scheme, expires
- for example to block all cookies which name is "__utm" followed by a single
+ for example to block all cookies which name is "__utm" followed by a single
character (google analytics cookies) do.
request BLACKLIST_COOKIE name '^__utm.$'
-WHITELIST_COOKIE <part> <re>
- Adds a new whitelist filter. cookies where the component specified by
- `part` matches the regular expression `re` will be allowed. part can be any
- of the parts allowed for the BLACKLIST_COOKIE event
+WHITELIST_COOKIE [<component> <re>]*
+ Adds a new whitelist filter. cookies where the components specified by
+ `component` matches the regular expression `re` will be allowed. component
+ may be any of the components allowed for the BLACKLIST_COOKIE event
+
+### history.py ###
+- Status bar command history
+- Connects To: (KEYCMD_EXEC, HISTORY_PREV, HISTORY_NEXT, HISTORY_SEARCH)
+
+Records commands that are typed into the status bar so that they can be
+recalled. The same history is shared by all uzbl instances connected to the
+same event manager.
+
+HISTORY_PREV
+ Iterates backwards through commands that have been issued (filtered by the
+ last HISTORY_SEARCH if applicable).
+
+HISTORY_NEXT
+ Iterates forwards through commands that have been issued (filtered by the
+ last HISTORY_SEARCH if applicable).
+
+HISTORY_SEARCH <string>
+ Searches backwards through command history for an exact string.
diff --git a/docs/formfiller-data-format b/docs/formfiller-data-format
new file mode 100644
index 0000000..f42114c
--- /dev/null
+++ b/docs/formfiller-data-format
@@ -0,0 +1,35 @@
+FORMFILLER FILE FORMAT
+
+lines starting with '>' are ignored
+
+a file consists of profile definitions
+lines between profile definitions are ignored
+
+a line starting with '!profile=' introduces a profile definition
+the rest of that line is taken as the profile name
+profile names must match the RE /^[a-zA-Z0-9_-]*$/
+a line starting with '!' terminates the profile definition
+the rest of that line is ignored
+
+a profile definition consists of field definitions
+lines between field definitions are ignored
+
+a line starting with '%' introduces a field definition
+(details depend on the field type)
+the rest of that line shall be in the format ...
+ 'name(type){value}:checked' for checkbox/radio
+ 'name(type):value' for text/password/search
+ 'name(type):' for textarea
+where name/type/value/checked are the input field's HTML attribute values,
+ 'name' always being percent encoded, 'checked' being a JS boolean,
+ and 'value' being percent encoded if type is checkbox/radio
+for all types but textarea, the field definition ends with that single line
+for textarea, all lines up to (but excluding) one starting with '%' make up the 'value'
+the rest of that line starting with '%' is ignored
+
+for all lines, a leading '\', if present, is removed
+
+--
+
+a once-edit temporary file consists only of field definitions,
+ and lines starting with '!' or '>' are not special
diff --git a/examples/config/config b/examples/config/config
index b5421da..bcd6d3e 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -69,6 +69,11 @@ set download_handler = sync_spawn @scripts_dir/download.sh
# Load commit handlers
@on_event LOAD_COMMIT @set_status <span foreground="green">recv</span>
+ # add some javascript to the page for other 'js' and 'script' commands to access later.
+@on_event LOAD_COMMIT js uzbl = {};
+@on_event LOAD_COMMIT script @scripts_dir/formfiller.js
+@on_event LOAD_COMMIT script @scripts_dir/follow.js
+
# Userscripts/per-site-settings. See the script and the example configuration for details
#@on_event LOAD_COMMIT spawn @scripts_dir/per-site-settings.py @data_home/uzbl/per-site-settings
@@ -85,10 +90,13 @@ set download_handler = sync_spawn @scripts_dir/download.sh
#@on_event CONFIG_CHANGED print Config changed: %1 = %2
# Scroll percentage calculation
-@on_event SCROLL_VERT set scroll_message = \@<(function(){var a='%1'.split(' ');var p='--';if(a[2]!=a[1]){p=(a[0]/(a[2]-a[3]));p=Math.round(10000*p)/100;};return p+'%';})()>\@
+@on_event SCROLL_VERT set scroll_message = \@<(function(){var p='--';if(%3!=%2){p=(%1/(%3-%4));p=Math.round(10000*p)/100;};return p+'%';})()>\@
# === Behaviour and appearance ===============================================
+# Custom CSS can be defined here, including link follower hint styles
+set stylesheet_uri = file://@data_home/uzbl/style.css
+
set show_status = 1
set status_top = 0
set status_background = #303030
@@ -129,7 +137,11 @@ set progress.pending =
set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}) (@(+uname -sm)@ [@ARCH_UZBL])
# === Configure cookie blacklist ========================================================
-# Drop google analytics tracking cookies
+
+# Accept 'session cookies' from uzbl.org (when you have a whitelist all other cookies are dropped)
+#request WHITELIST_COOKIE domain 'uzbl.org$' expires '^$'
+
+# Drop google analytics tracking cookies (applied after whitelists if any)
#request BLACKLIST_COOKIE name '^__utm.$'
# === Key binding configuration ==============================================
@@ -172,6 +184,7 @@ set ebind = @mode_bind global,-insert
# Resets keycmd and returns to default mode.
@on_event ESCAPE @set_mode
+@on_event ESCAPE event KEYCMD_CLEAR
@bind <Escape> = event ESCAPE
@bind <Ctrl>[ = event ESCAPE
@@ -190,6 +203,15 @@ set ebind = @mode_bind global,-insert
@ebind <Ctrl>a = event SET_CURSOR_POS 0
@ebind <Ctrl>e = event SET_CURSOR_POS -1
+@ebind <Up> = event HISTORY_PREV
+@ebind <Down> = event HISTORY_NEXT
+@ebind <Ctrl>r<search:>_ = event HISTORY_SEARCH %s
+# Keycmd injection/append examples.
+#@ebind <Ctrl>su = event INJECT_KEYCMD \@uri
+#@ebind <Ctrl>st = event INJECT_KEYCMD \@title
+#@ebind <Ctrl>du = event APPEND_KEYCMD \@uri
+#@ebind <Ctrl>dt = event APPEND_KEYCMD \@title
+
# --- Mouse bindings ---------------------------------------------------------
# Middle click open in new window
@@ -309,7 +331,8 @@ set follow_hint_keys = 0123456789
#set follow_hint_keys = qwerty
#set follow_hint_keys = asdfghjkl;
#set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234
-@cbind fl* = spawn @scripts_dir/follow.sh follow_hint_keys "%s"
+@cbind fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 0) >\@
+@cbind Fl* = spawn @scripts_dir/follow.sh \@< uzbl.follow("\@follow_hint_keys", "%s", 1) >\@
@cbind gi = spawn @scripts_dir/go_input.sh
# Form filler binds
diff --git a/examples/data/per-site-settings b/examples/data/per-site-settings
index 78bade4..d02d7a7 100644
--- a/examples/data/per-site-settings
+++ b/examples/data/per-site-settings
@@ -1,3 +1,3 @@
.*
.*/\d+-\w+/(thread|subject|author|date).html
- script @data_home/uzbl/scripts/pipermail.js
+ script @scripts_dir/pipermail.js
diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py
index 5b13476..69fd863 100644
--- a/examples/data/plugins/bind.py
+++ b/examples/data/plugins/bind.py
@@ -164,15 +164,6 @@ def split_glob(glob):
return (mods, glob)
-def unquote(str):
- '''Remove quotation marks around string.'''
-
- if str and str[0] == str[-1] and str[0] in ['"', "'"]:
- str = str[1:-1]
-
- return str
-
-
class Bind(object):
# Class attribute to hold the number of Bind classes created.
@@ -379,7 +370,6 @@ def mode_changed(uzbl, mode):
if mode != 'stack':
uzbl.bindlet.reset()
- uzbl.clear_keycmd()
def match_and_exec(uzbl, bind, depth, keylet, bindlet):
@@ -421,7 +411,6 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet):
if not has_args or on_exec:
del uzbl.config['mode']
bindlet.reset()
- uzbl.clear_current()
return True
@@ -469,3 +458,5 @@ def init(uzbl):
'mode_bind': mode_bind,
'bindlet': Bindlet(uzbl),
})
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/config.py b/examples/data/plugins/config.py
index ed2d761..c9bdf67 100644
--- a/examples/data/plugins/config.py
+++ b/examples/data/plugins/config.py
@@ -3,8 +3,6 @@ from types import BooleanType
from UserDict import DictMixin
valid_key = compile('^[A-Za-z0-9_\.]+$').match
-types = {'int': int, 'float': float, 'str': unicode}
-escape = lambda s: unicode(s).replace('\n', '\\n')
class Config(DictMixin):
def __init__(self, uzbl):
@@ -49,7 +47,8 @@ class Config(DictMixin):
value = int(value)
else:
- value = escape(value)
+ value = unicode(value)
+ assert '\n' not in value
if not force and key in self and self[key] == value:
return
@@ -82,6 +81,8 @@ def parse_set_event(uzbl, args):
# plugin init hook
def init(uzbl):
+ global types
+ types = {'int': int, 'float': float, 'str': unquote}
export(uzbl, 'config', Config(uzbl))
connect(uzbl, 'VARIABLE_SET', parse_set_event)
diff --git a/examples/data/plugins/cookies.py b/examples/data/plugins/cookies.py
index c9fe2c3..e29ee36 100644
--- a/examples/data/plugins/cookies.py
+++ b/examples/data/plugins/cookies.py
@@ -7,10 +7,6 @@ import os, re
# these are symbolic names for the components of the cookie tuple
symbolic = {'domain': 0, 'path':1, 'name':2, 'value':3, 'scheme':4, 'expires':5}
-_splitquoted = re.compile("( |\\\".*?\\\"|'.*?')")
-def splitquoted(text):
- return [str(p.strip('\'"')) for p in _splitquoted.split(text) if p.strip()]
-
# allows for partial cookies
# ? allow wildcard in key
def match(key, cookie):
@@ -38,24 +34,38 @@ class TextStore(object):
self.filename = filename
def as_event(self, cookie):
+ """Convert cookie.txt row to uzbls cookie event format"""
+ scheme = {
+ 'TRUE' : 'https',
+ 'FALSE' : 'http'
+ }
if cookie[0].startswith("#HttpOnly_"):
domain = cookie[0][len("#HttpOnly_"):]
elif cookie[0].startswith('#'):
return None
else:
domain = cookie[0]
- return (domain,
- cookie[2],
- cookie[5],
- cookie[6],
- 'https' if cookie[3] == 'TRUE' else 'http',
- cookie[4])
+ try:
+ return (domain,
+ cookie[2],
+ cookie[5],
+ cookie[6],
+ scheme[cookie[3]],
+ cookie[4])
+ except (KeyError,IndexError):
+ # Let malformed rows pass through like comments
+ return None
def as_file(self, cookie):
+ """Convert cookie event to cookie.txt row"""
+ secure = {
+ 'https' : 'TRUE',
+ 'http' : 'FALSE'
+ }
return (cookie[0],
'TRUE' if cookie[0].startswith('.') else 'FALSE',
cookie[1],
- 'TRUE' if cookie[4] == 'https' else 'FALSE',
+ secure[cookie[4]],
cookie[5],
cookie[2],
cookie[3])
@@ -92,8 +102,11 @@ DefaultStore = TextStore(os.path.join(xdg_data_home, 'uzbl/cookies.txt'))
SessionStore = TextStore(os.path.join(xdg_data_home, 'uzbl/session-cookies.txt'))
def match_list(_list, cookie):
- for component, match in _list:
- if match(cookie[component]) is not None:
+ for matcher in _list:
+ for component, match in matcher:
+ if match(cookie[component]) is None:
+ break
+ else:
return True
return False
@@ -144,18 +157,21 @@ def delete_cookie(uzbl, cookie):
store.delete_cookie(cookie, splitted)
# add a cookie matcher to a whitelist or a blacklist.
-# a matcher is a (component, re) tuple that matches a cookie when the
+# a matcher is a list of (component, re) tuples that matches a cookie when the
# "component" part of the cookie matches the regular expression "re".
# "component" is one of the keys defined in the variable "symbolic" above,
# or the index of a component of a cookie tuple.
def add_cookie_matcher(_list, arg):
- component, regexp = splitquoted(arg)
- try:
- component = symbolic[component]
- except KeyError:
- component = int(component)
- assert component <= 5
- _list.append((component, re.compile(regexp).search))
+ args = splitquoted(arg)
+ mlist = []
+ for (component, regexp) in zip(args[0::2], args[1::2]):
+ try:
+ component = symbolic[component]
+ except KeyError:
+ component = int(component)
+ assert component <= 5
+ mlist.append((component, re.compile(regexp).search))
+ _list.append(mlist)
def blacklist(uzbl, arg):
add_cookie_matcher(uzbl.cookie_blacklist, arg)
@@ -174,3 +190,5 @@ def init(uzbl):
'cookie_blacklist' : [],
'cookie_whitelist' : []
})
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/downloads.py b/examples/data/plugins/downloads.py
index 7bf32d7..8d796ce 100644
--- a/examples/data/plugins/downloads.py
+++ b/examples/data/plugins/downloads.py
@@ -31,7 +31,11 @@ def update_download_section(uzbl):
if uzbl.config.get('downloads', '') != result:
uzbl.config['downloads'] = result
-def download_started(uzbl, destination_path):
+def download_started(uzbl, args):
+ # parse the arguments
+ args = splitquoted(args)
+ destination_path = args[0]
+
# add to the list of active downloads
global ACTIVE_DOWNLOADS
ACTIVE_DOWNLOADS[destination_path] = (0.0,)
@@ -41,9 +45,9 @@ def download_started(uzbl, destination_path):
def download_progress(uzbl, args):
# parse the arguments
- s = args.rindex(' ')
- destination_path = args[:s]
- progress = float(args[s+1:])
+ args = splitquoted(args)
+ destination_path = args[0]
+ progress = float(args[1])
# update the progress
global ACTIVE_DOWNLOADS
@@ -52,7 +56,11 @@ def download_progress(uzbl, args):
# update the status bar variable
update_download_section(uzbl)
-def download_complete(uzbl, destination_path):
+def download_complete(uzbl, args):
+ # parse the arguments
+ args = splitquoted(args)
+ destination_path = args[0]
+
# remove from the list of active downloads
global ACTIVE_DOWNLOADS
del ACTIVE_DOWNLOADS[destination_path]
diff --git a/examples/data/plugins/history.py b/examples/data/plugins/history.py
new file mode 100644
index 0000000..5e9e4e1
--- /dev/null
+++ b/examples/data/plugins/history.py
@@ -0,0 +1,129 @@
+import random
+
+shared_history = {'':[]}
+
+class History(object):
+ def __init__(self, uzbl):
+ self.uzbl = uzbl
+ self._temporary = []
+ self.prompt = ''
+ self.cursor = None
+ self.__temp_tail = False
+ self.search_key = None
+
+ def prev(self):
+ if self.cursor is None:
+ self.cursor = len(self) - 1
+ else:
+ self.cursor -= 1
+
+ if self.search_key:
+ while self.cursor >= 0 and self.search_key not in self[self.cursor]:
+ self.cursor -= 1
+
+ if self.cursor < 0 or len(self) == 0:
+ self.cursor = -1
+ return random.choice(end_messages)
+
+ return self[self.cursor]
+
+ def next(self):
+ if self.cursor is None:
+ return ''
+
+ self.cursor += 1
+
+ if self.search_key:
+ while self.cursor < len(self) and self.search_key not in self[self.cursor]:
+ self.cursor += 1
+
+ if self.cursor >= len(shared_history[self.prompt]):
+ self.cursor = None
+ self.search_key = None
+
+ if self._temporary:
+ return self._temporary.pop()
+ return ''
+
+ return self[self.cursor]
+
+ def change_prompt(self, prompt):
+ self.prompt = prompt
+ self._temporary = []
+ self.__temp_tail = False
+ if prompt not in shared_history:
+ shared_history[prompt] = []
+
+ def search(self, key):
+ self.search_key = key
+ self.cursor = None
+
+ def add(self, cmd):
+ if self._temporary:
+ self._temporary.pop()
+
+ shared_history[self.prompt].append(cmd)
+ self.cursor = None
+ self.search_key = None
+
+ def add_temporary(self, cmd):
+ assert not self._temporary
+
+ self._temporary.append(cmd)
+ self.cursor = len(self) - 1
+
+ def __getitem__(self, i):
+ if i < len(shared_history[self.prompt]):
+ return shared_history[self.prompt][i]
+ return self._temporary[i-len(shared_history)+1]
+
+ def __len__(self):
+ return len(shared_history[self.prompt]) + len(self._temporary)
+
+ def __str__(self):
+ return "(History %s, %s)" % (self.cursor, self.prompt)
+
+def keycmd_exec(uzbl, keylet):
+ cmd = keylet.get_keycmd()
+ if cmd:
+ uzbl.history.add(cmd)
+
+def history_prev(uzbl, _x):
+ cmd = uzbl.keylet.get_keycmd()
+ if uzbl.history.cursor is None and cmd:
+ uzbl.history.add_temporary(cmd)
+
+ uzbl.set_keycmd(uzbl.history.prev())
+ uzbl.logger.debug('PREV %s' % uzbl.history)
+
+def history_next(uzbl, _x):
+ cmd = uzbl.keylet.get_keycmd()
+
+ uzbl.set_keycmd(uzbl.history.next())
+ uzbl.logger.debug('NEXT %s' % uzbl.history)
+
+def history_search(uzbl, key):
+ uzbl.history.search(key)
+ uzbl.send('event HISTORY_PREV')
+ uzbl.logger.debug('SEARCH %s %s' % (key, uzbl.history))
+
+end_messages = ('Look behind you, A three-headed monkey!', 'error #4: static from nylon underwear.', 'error #5: static from plastic slide rules.', 'error #6: global warming.', 'error #9: doppler effect.', 'error #16: somebody was calculating pi on the server.', 'error #19: floating point processor overflow.', 'error #21: POSIX compliance problem.', 'error #25: Decreasing electron flux.', 'error #26: first Saturday after first full moon in Winter.', 'error #64: CPU needs recalibration.', 'error #116: the real ttys became pseudo ttys and vice-versa.', 'error #229: wrong polarity of neutron flow.', 'error #330: quantum decoherence.', 'error #388: Bad user karma.', 'error #407: Route flapping at the NAP.', 'error #435: Internet shut down due to maintenance.')
+
+# plugin init hook
+def init(uzbl):
+ connect_dict(uzbl, {
+ 'KEYCMD_EXEC': keycmd_exec,
+ 'HISTORY_PREV': history_prev,
+ 'HISTORY_NEXT': history_next,
+ 'HISTORY_SEARCH': history_search
+ })
+
+ export_dict(uzbl, {
+ 'history' : History(uzbl)
+ })
+
+# plugin after hook
+def after(uzbl):
+ uzbl.on_set('keycmd_prompt', lambda uzbl, k, v: uzbl.history.change_prompt(v))
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/keycmd.py b/examples/data/plugins/keycmd.py
index 2fb2283..928c597 100644
--- a/examples/data/plugins/keycmd.py
+++ b/examples/data/plugins/keycmd.py
@@ -210,7 +210,7 @@ def modkey_addition_parse(uzbl, modkeys):
add_modkey_addition(uzbl, keys[:-1], keys[-1])
-def clear_keycmd(uzbl):
+def clear_keycmd(uzbl, *args):
'''Clear the keycmd for this uzbl instance.'''
k = uzbl.keylet
@@ -493,6 +493,7 @@ def init(uzbl):
'KEYCMD_DELETE': keycmd_delete,
'KEYCMD_EXEC_CURRENT': keycmd_exec_current,
'KEYCMD_STRIP_WORD': keycmd_strip_word,
+ 'KEYCMD_CLEAR': clear_keycmd,
'KEY_PRESS': key_press,
'KEY_RELEASE': key_release,
'MODKEY_ADDITION': modkey_addition_parse,
@@ -514,3 +515,5 @@ def init(uzbl):
'set_cursor_pos': set_cursor_pos,
'set_keycmd': set_keycmd,
})
+
+# vi: set et ts=4:
diff --git a/examples/data/plugins/on_event.py b/examples/data/plugins/on_event.py
index 5142275..32f09e2 100644
--- a/examples/data/plugins/on_event.py
+++ b/examples/data/plugins/on_event.py
@@ -24,6 +24,10 @@ def event_handler(uzbl, *args, **kargs):
'''This function handles all the events being watched by various
on_event definitions and responds accordingly.'''
+ # Could be connected to a EM internal event that can use anything as args
+ if len(args) == 1 and isinstance(args[0], basestring):
+ args = splitquoted(args[0])
+
events = uzbl.on_events
event = kargs['on_event']
if event not in events:
@@ -80,3 +84,5 @@ def cleanup(uzbl):
del handlers[:]
uzbl.on_events.clear()
+
+# vi: set et ts=4:
diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js
index d995696..536256b 100644
--- a/examples/data/scripts/follow.js
+++ b/examples/data/scripts/follow.js
@@ -1,219 +1,192 @@
/* This is the basic linkfollowing script.
- * Its pretty stable, and you configure which keys to use for hinting
*
- * TODO: Some pages mess around a lot with the zIndex which
- * lets some hints in the background.
- * TODO: Some positions are not calculated correctly (mostly
- * because of uber-fancy-designed-webpages. Basic HTML and CSS
- * works good
- * TODO: Still some links can't be followed/unexpected things
- * happen. Blame some freaky webdesigners ;)
+ * TODO:
+ * Some pages mess around a lot with the zIndex which
+ * lets some hints in the background.
+ * Some positions are not calculated correctly (mostly
+ * because of uber-fancy-designed-webpages. Basic HTML and CSS
+ * works good
+ * Still some links can't be followed/unexpected things
+ * happen. Blame some freaky webdesigners ;)
*/
-//Just some shortcuts and globals
-var uzblid = 'uzbl_link_hint';
-var uzbldivid = uzblid + '_div_container';
-var doc = document;
-var win = window;
-var links = document.links;
-var forms = document.forms;
-//Make onlick-links "clickable"
-try {
- HTMLElement.prototype.click = function() {
- if (typeof this.onclick == 'function') {
- this.onclick({
- type: 'click'
- });
- }
- };
-} catch(e) {}
-//Catch the ESC keypress to stop linkfollowing
-function keyPressHandler(e) {
- var kC = window.event ? event.keyCode: e.keyCode;
- var Esc = window.event ? 27 : e.DOM_VK_ESCAPE;
- if (kC == Esc) {
- removeAllHints();
- }
+// Globals
+uzbldivid = 'uzbl_link_hints';
+
+uzbl.follow = function() {
+ // Export
+ charset = arguments[0];
+ newwindow = arguments[2];
+
+ var keypress = arguments[1];
+ return arguments.callee.followLinks(keypress);
+}
+
+uzbl.follow.isFrame = function(el) {
+ return (el.tagName == "FRAME" || el.tagName == "IFRAME");
+}
+
+// find the document that the given element belongs to
+uzbl.follow.getDocument = function(el) {
+ if (this.isFrame(el))
+ return el.contentDocument;
+
+ var doc = el;
+ while (doc.parentNode !== null)
+ doc = doc.parentNode;
+ return doc;
+}
+
+// find all documents in the display, searching frames recursively
+uzbl.follow.documents = function() {
+ return this.windows().map(function(w) { return w.document; }).filter(function(d) { return d != null; });
+}
+
+// find all windows in the display, searching for frames recursively
+uzbl.follow.windows = function(w) {
+  w = (typeof w == 'undefined') ? window.top : w;
+
+ var wins = [w];
+ var frames = w.frames;
+ for(var i = 0; i < frames.length; i++)
+ wins = wins.concat(uzbl.follow.windows(frames[i]));
+ return wins;
+}
+
+// search all frames for elements matching the given CSS selector
+uzbl.follow.query = function(selector) {
+ var res = [];
+ this.documents().forEach(function (doc) {
+ var set = doc.body.querySelectorAll(selector);
+ // convert the NodeList to an Array
+ set = Array.prototype.slice.call(set);
+ res = res.concat(set);
+ });
+ return res;
}
-//Calculate element position to draw the hint
-//Pretty accurate but on fails in some very fancy cases
-function elementPosition(el) {
- var up = el.offsetTop;
- var left = el.offsetLeft;
- var width = el.offsetWidth;
+
+// Calculate element position to draw the hint
+uzbl.follow.elementPosition = function(el) {
+ // el.getBoundingClientRect is another way to do this, but when a link is
+ // line-wrapped we want our hint at the left end of the link, not its
+ // bounding rectangle
+ var up = el.offsetTop;
+ var left = el.offsetLeft;
+ var width = el.offsetWidth;
var height = el.offsetHeight;
+
while (el.offsetParent) {
el = el.offsetParent;
up += el.offsetTop;
left += el.offsetLeft;
}
+
return [up, left, width, height];
}
-//Calculate if an element is visible
-function isVisible(el) {
- if (el == doc) {
- return true;
- }
- if (!el) {
- return false;
- }
- if (!el.parentNode) {
- return false;
- }
- if (el.style) {
- if (el.style.display == 'none') {
- return false;
- }
- if (el.style.visibility == 'hidden') {
- return false;
- }
- }
- return isVisible(el.parentNode);
-}
-//Calculate if an element is on the viewport.
-function elementInViewport(el) {
- offset = elementPosition(el);
- var up = offset[0];
- var left = offset[1];
- var width = offset[2];
+
+// Calculate if an element is on the viewport.
+uzbl.follow.elementInViewport = function(el) {
+ offset = uzbl.follow.elementPosition(el);
+ var up = offset[0];
+ var left = offset[1];
+ var width = offset[2];
var height = offset[3];
- return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset;
+ return up < window.pageYOffset + window.innerHeight &&
+ left < window.pageXOffset + window.innerWidth &&
+ (up + height) > window.pageYOffset &&
+ (left + width) > window.pageXOffset;
}
-//Removes all hints/leftovers that might be generated
-//by this script.
-function removeAllHints() {
+
+// Removes all hints/leftovers that might be generated
+// by this script.
+uzbl.follow.removeAllHints = function(doc) {
var elements = doc.getElementById(uzbldivid);
- if (elements) {
- elements.parentNode.removeChild(elements);
- }
+ if (elements) elements.parentNode.removeChild(elements);
}
-//Generate a hint for an element with the given label
-//Here you can play around with the style of the hints!
-function generateHint(el, label) {
- var pos = elementPosition(el);
- var hint = doc.createElement('div');
- hint.setAttribute('name', uzblid);
+
+// Generate a hint for an element with the given label
+// Here you can play around with the style of the hints!
+uzbl.follow.generateHint = function(doc, el, label, top, left) {
+ var hint = doc.createElement('span');
hint.innerText = label;
- hint.style.display = 'inline';
- hint.style.backgroundColor = '#B9FF00';
- hint.style.border = '2px solid #4A6600';
- hint.style.color = 'black';
- hint.style.fontSize = '9px';
- hint.style.fontWeight = 'bold';
- hint.style.lineHeight = '9px';
- hint.style.margin = '0px';
- hint.style.width = 'auto'; // fix broken rendering on w3schools.com
- hint.style.padding = '1px';
hint.style.position = 'absolute';
- hint.style.zIndex = '1000';
- // hint.style.textTransform = 'uppercase';
- hint.style.left = pos[1] + 'px';
- hint.style.top = pos[0] + 'px';
- // var img = el.getElementsByTagName('img');
- // if (img.length > 0) {
- // hint.style.top = pos[1] + img[0].height / 2 - 6 + 'px';
- // }
- hint.style.textDecoration = 'none';
- // hint.style.webkitBorderRadius = '6px'; // slow
- // Play around with this, pretty funny things to do :)
- // hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)';
+ hint.style.top = top + 'px';
+ hint.style.left = left + 'px';
return hint;
}
-// Here we choose what to do with an element that the user has selected.
-// Form elements get selected and/or focussed, and links and buttons are
-// clicked. This function returns "XXXRESET_MODEXXX" to indicate that uzbl
-// should be reset to command mode with an empty keycmd, or
-// "XXX_EMIT_FORM_ACTIVEXXX" to indicate that uzbl should be set to insert mode.
-function clickElem(item) {
- removeAllHints();
- if (item) {
- var name = item.tagName;
- if (name == 'BUTTON') {
- item.click();
- return "XXXRESET_MODEXXX";
- } else if (name == 'INPUT') {
- var type = item.type.toUpperCase();
- if (type == 'TEXT' || type == 'SEARCH' || type == 'PASSWORD') {
- item.focus();
- item.select();
- return "XXXEMIT_FORM_ACTIVEXXX";
- } else {
- item.click();
- return "XXXRESET_MODEXXX";
- }
- } else if (name == 'TEXTAREA' || name == 'SELECT') {
+// Here we choose what to do with an element if we
+// want to "follow" it. On form elements we "select"
+// or pass the focus, on links we try to perform a click,
+// but at least set the href of the link. (needs some improvements)
+uzbl.follow.clickElem = function(item) {
+ if(!item) return;
+ var name = item.tagName;
+
+ if (name == 'INPUT') {
+ var type = item.getAttribute('type').toUpperCase();
+ if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') {
item.focus();
item.select();
return "XXXEMIT_FORM_ACTIVEXXX";
- } else {
- item.click();
- window.location = item.href;
- return "XXXRESET_MODEXXX";
}
+ // otherwise fall through to a simulated mouseclick.
+ } else if (name == 'TEXTAREA' || name == 'SELECT') {
+ item.focus();
+ item.select();
+ return "XXXEMIT_FORM_ACTIVEXXX";
}
+
+ // simulate a mouseclick to activate the element
+ var mouseEvent = document.createEvent("MouseEvent");
+ mouseEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ item.dispatchEvent(mouseEvent);
+ return "XXXRESET_MODEXXX";
}
-//Returns a list of all links (in this version
-//just the elements itself, but in other versions, we
-//add the label here.
-function addLinks() {
- res = [[], []];
- for (var l = 0; l < links.length; l++) {
- var li = links[l];
- if (isVisible(li) && elementInViewport(li)) {
- res[0].push(li);
- }
- }
- return res;
-}
-//Same as above, just for the form elements
-function addFormElems() {
- res = [[], []];
- for (var f = 0; f < forms.length; f++) {
- for (var e = 0; e < forms[f].elements.length; e++) {
- var el = forms[f].elements[e];
- if (el && ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) {
- res[0].push(el);
- }
- }
- }
- return res;
-}
-//Draw all hints for all elements passed. "len" is for
-//the number of chars we should use to avoid collisions
-function reDrawHints(elems, chars) {
- removeAllHints();
- var hintdiv = doc.createElement('div');
- hintdiv.setAttribute('id', uzbldivid);
- for (var i = 0; i < elems[0].length; i++) {
- if (elems[0][i]) {
- var label = elems[1][i].substring(chars);
- var h = generateHint(elems[0][i], label);
- hintdiv.appendChild(h);
- }
- }
- if (document.body) {
- document.body.appendChild(hintdiv);
- }
+
+// Draw all hints for all elements passed.
+uzbl.follow.reDrawHints = function(elems, chars) {
+ var elements = elems.map(function(pair) { return pair[0] });
+ var labels = elems.map(function(pair) { return pair[1].substring(chars) });
+ // we have to calculate element positions before we modify the DOM
+ // otherwise the elementPosition call slows way down.
+ var positions = elements.map(uzbl.follow.elementPosition);
+
+ this.documents().forEach(function(doc) {
+ uzbl.follow.removeAllHints(doc);
+ if (!doc.body) return;
+ doc.hintdiv = doc.createElement('div');
+ doc.hintdiv.id = uzbldivid;
+ if(newwindow) doc.hintdiv.className = "new-window";
+ doc.body.appendChild(doc.hintdiv);
+ });
+
+ elements.forEach(function(el, i) {
+ var label = labels[i];
+ var pos = positions[i];
+ var doc = uzbl.follow.getDocument(el);
+ var h = uzbl.follow.generateHint(doc, el, label, pos[0], pos[1]);
+ doc.hintdiv.appendChild(h);
+ });
}
+
// pass: number of keys
// returns: key length
-function labelLength(n) {
+uzbl.follow.labelLength = function(n) {
var oldn = n;
var keylen = 0;
- if(n < 2) {
- return 1;
- }
- n -= 1; // our highest key will be n-1
+ if(n < 2) return 1;
+ n -= 1; // Our highest key will be n-1
while(n) {
keylen += 1;
n = Math.floor(n / charset.length);
}
return keylen;
}
+
// pass: number
// returns: label
-function intToLabel(n) {
+uzbl.follow.intToLabel = function(n) {
var label = '';
do {
label = charset.charAt(n % charset.length) + label;
@@ -221,55 +194,68 @@ function intToLabel(n) {
} while(n);
return label;
}
+
// pass: label
// returns: number
-function labelToInt(label) {
+uzbl.follow.labelToInt = function(label) {
var n = 0;
- var i;
- for(i = 0; i < label.length; ++i) {
+ for(var i = 0; i < label.length; ++i) {
n *= charset.length;
n += charset.indexOf(label[i]);
}
return n;
}
-//Put it all together
-function followLinks(follow) {
- // if(follow.charAt(0) == 'l') {
- // follow = follow.substr(1);
- // charset = 'thsnlrcgfdbmwvz-/';
- // }
+
+// Put it all together
+uzbl.follow.followLinks = function(follow) {
var s = follow.split('');
- var linknr = labelToInt(follow);
- if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)');
- var linkelems = addLinks();
- var formelems = addFormElems();
- var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])];
- var len = labelLength(elems[0].length);
- var oldDiv = doc.getElementById(uzbldivid);
- var leftover = [[], []];
- if (s.length == len && linknr < elems[0].length && linknr >= 0) {
- return clickElem(elems[0][linknr]);
- } else {
- for (var j = 0; j < elems[0].length; j++) {
- var b = true;
- var label = intToLabel(j);
- var n = label.length;
- for (n; n < len; n++) {
- label = charset.charAt(0) + label;
- }
- for (var k = 0; k < s.length; k++) {
- b = b && label.charAt(k) == s[k];
- }
- if (b) {
- leftover[0].push(elems[0][j]);
- leftover[1].push(label);
- }
+ var linknr = this.labelToInt(follow);
+
+ var followable = 'a, area, textarea, select, input:not([type=hidden]), button';
+ var uri = 'a, area, frame, iframe';
+ //var focusable = 'a, area, textarea, select, input:not([type=hidden]), button, frame, iframe, applet, object';
+ //var desc = '*[title], img[alt], applet[alt], area[alt], input[alt]';
+ //var image = 'img, input[type=image]';
+
+ if(newwindow)
+ var res = this.query(uri);
+ else
+ var res = this.query(followable);
+
+ var elems = res.filter(uzbl.follow.elementInViewport);
+ var len = this.labelLength(elems.length);
+
+ if (s.length == len && linknr < elems.length && linknr >= 0) {
+ // an element has been selected!
+ var el = elems[linknr];
+
+ // clear all of our hints
+ this.documents().forEach(uzbl.follow.removeAllHints);
+
+ if (newwindow) {
+ // we're opening a new window using the URL attached to this element
+ var uri = el.src || el.href;
+ if(uri.match(/javascript:/)) return;
+ window.open(uri);
+ return "XXXRESET_MODEXXX"
}
- reDrawHints(leftover, s.length);
+
+ // we're just going to click the element
+ return this.clickElem(el);
}
-}
-//Parse input: first argument is follow keys, second is user input.
-var args = '%s'.split(' ');
-var charset = args[0];
-followLinks(args[1]);
+ var leftover = [];
+ for (var j = 0; j < elems.length; j++) {
+ var b = true;
+ var label = this.intToLabel(j);
+ var n = label.length;
+ for (n; n < len; n++)
+ label = charset.charAt(0) + label;
+ for (var k = 0; k < s.length; k++)
+ b = b && label.charAt(k) == s[k];
+ if (b)
+ leftover.push([elems[j], label]);
+ }
+
+ this.reDrawHints(leftover, s.length);
+}
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index 6401188..014793e 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -1,31 +1,13 @@
#!/bin/sh
+# This scripts acts on the return value of followLinks in follow.js
-# This script is just a wrapper around follow.js that lets us change uzbl's mode
-# after a link is selected.
-
-. "$UZBL_UTIL_DIR/uzbl-util.sh"
-
-key_variable="$1"
-shift
-
-keys="$1"
-shift
-
-# if socat is installed then we can change Uzbl's input mode once a link is
-# selected; otherwise we just select a link.
-if ! which socat >/dev/null 2>&1; then
- print "script @scripts_dir/follow.js \"@{$key_variable} $keys\"\n" > "$UZBL_FIFO"
- exit 0
-fi
-
-result="$( print "script @scripts_dir/follow.js \"@{$key_variable} $keys\"\n" | socat - "unix-connect:$UZBL_SOCKET" )"
-case $result in
- *XXXEMIT_FORM_ACTIVEXXX*)
+case "$1" in
+ XXXEMIT_FORM_ACTIVEXXX)
# a form element was selected
- print "event FORM_ACTIVE\n" > "$UZBL_FIFO"
+ printf 'event FORM_ACTIVE\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
;;
- *XXXRESET_MODEXXX*)
+ XXXRESET_MODEXXX)
# a link was selected, reset uzbl's input mode
- print "set mode=\n" > "$UZBL_FIFO"
+ printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
;;
esac
diff --git a/examples/data/scripts/formfiller.js b/examples/data/scripts/formfiller.js
new file mode 100644
index 0000000..abf0162
--- /dev/null
+++ b/examples/data/scripts/formfiller.js
@@ -0,0 +1,67 @@
+uzbl.formfiller = {
+
+ dump: function() {
+ var rv = '';
+ var allFrames = new Array(window);
+ for ( f=0; f<window.frames.length; ++f ) {
+ allFrames.push(window.frames[f]);
+ }
+ for ( j=0; j<allFrames.length; ++j ) {
+ try {
+ var xp_res = allFrames[j].document.evaluate(
+ '//input', allFrames[j].document.documentElement, null, XPathResult.ANY_TYPE,null
+ );
+ var input;
+ while ( input = xp_res.iterateNext() ) {
+ var type = (input.type?input.type:text);
+ if ( type == 'text' || type == 'password' || type == 'search' ) {
+ rv += '%' + escape(input.name) + '(' + type + '):' + input.value + '\n';
+ }
+ else if ( type == 'checkbox' || type == 'radio' ) {
+ rv += '%' + escape(input.name) + '(' + type + '){' + escape(input.value) + '}:' + (input.checked?'1':'0') + '\n';
+ }
+ }
+ xp_res = allFrames[j].document.evaluate(
+ '//textarea', allFrames[j].document.documentElement, null, XPathResult.ANY_TYPE,null
+ );
+ var input;
+ while ( input = xp_res.iterateNext() ) {
+ rv += '%' + escape(input.name) + '(textarea):\n' + input.value.replace(/\n%/g,"\n\\%") + '\n%\n';
+ }
+ }
+ catch (err) { }
+ }
+ return 'formfillerstart\n' + rv + '%!end';
+ }
+
+ ,
+
+ insert: function(fname, ftype, fvalue, fchecked) {
+ fname = unescape(fname);
+ var allFrames = new Array(window);
+ for ( f=0; f<window.frames.length; ++f ) {
+ allFrames.push(window.frames[f]);
+ }
+ for ( j=0; j<allFrames.length; ++j ) {
+ try {
+ if ( ftype == 'text' || ftype == 'password' || ftype == 'search' || ftype == 'textarea' ) {
+ allFrames[j].document.getElementsByName(fname)[0].value = fvalue;
+ }
+ else if ( ftype == 'checkbox' ) {
+ allFrames[j].document.getElementsByName(fname)[0].checked = fchecked;
+ }
+ else if ( ftype == 'radio' ) {
+ fvalue = unescape(fvalue);
+ var radios = allFrames[j].document.getElementsByName(fname);
+ for ( r=0; r<radios.length; ++r ) {
+ if ( radios[r].value == fvalue ) {
+ radios[r].checked = fchecked;
+ }
+ }
+ }
+ }
+ catch (err) { }
+ }
+ }
+
+}
diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh
index 17634e2..3dc9dc4 100755
--- a/examples/data/scripts/formfiller.sh
+++ b/examples/data/scripts/formfiller.sh
@@ -1,198 +1,146 @@
#!/bin/sh
#
-# Enhanced html form (eg for logins) filler (and manager) for uzbl.
-#
-# uses settings files like: $UZBL_FORMS_DIR/<domain>
-# files contain lines like: !profile=<profile_name>
-# <fieldname>(fieldtype): <value>
-# profile_name should be replaced with a name that will tell sth about that
-# profile
-# fieldtype can be checkbox, text or password, textarea - only for information
-# pupropse (auto-generated) - don't change that
-#
-# Texteares: for textareas edited text can be now splitted into more lines.
-# If there will be text, that doesn't match key line:
-# <fieldname>(fieldtype):<value>
-# then it will be considered as a multiline for the first field above it
-# Keep in mind, that if you make more than one line for fileds like input
-# text fields, then all lines will be inserted into as one line
-#
-# Checkboxes/radio-buttons: to uncheck it type on of the following after the
-# colon:
-# no
-# off
-# 0
-# unchecked
-# false
-# or leave it blank, even without spaces
-# otherwise it will be considered as checked
-#
-# user arg 1:
-# edit: force editing the file (falls back to new if not found)
-# new: start with a new file.
-# load: try to load from file into form
-# add: try to add another profile to an existing file
-# once: edit form using external editor
-#
-# something else (or empty): if file not available: new, otherwise load.
+# action
+# new: add new profile template (creates file if not found), then edit
+# edit: edit file (fall back to 'new' if file not found)
+# load: load from file
+# once: use temporary file to edit form once
+# (empty): if file not available, new; otherwise, load
#
-DMENU_ARGS="-i"
-DMENU_SCHEMA="formfiller"
-DMENU_LINES="3"
-DMENU_PROMPT="Choose profile"
-DMENU_OPTIONS="vertical resize"
+action=$1
-. "$UZBL_UTIL_DIR/dmenu.sh"
-. "$UZBL_UTIL_DIR/editor.sh"
. "$UZBL_UTIL_DIR/uzbl-dir.sh"
+. "$UZBL_UTIL_DIR/editor.sh"
+
+mkdir -p "$UZBL_FORMS_DIR" || exit
+
+domain=${UZBL_URI#*://}
+domain=${domain%%/*}
-RAND="$( dd if=/dev/urandom count=1 2>/dev/null | cksum | cut -c 1-5 )"
-MODELINE="> vim:ft=formfiller"
-
-[ -d "$( dirname "$UZBL_FORMS_DIR" )" ] || exit 1
-[ -d "$UZBL_FORMS_DIR" ] || mkdir "$UZBL_FORMS_DIR" || exit 1
-
-action="$1"
-shift
-
-domain="$( print "$UZBL_URI\n" | sed -e 's/\(http\|https\):\/\/\([^\/]\+\)\/.*/\2/' )"
-form_file="$UZBL_FORMS_DIR/$domain"
-
-if [ "$action" != 'edit' ] && [ "$action" != 'new' ] && [ "$action" != 'load' ] && [ "$action" != 'add' ] && [ "$action" != 'once' ]; then
- action="new"
- [ -e "$form_file" ] && action="load"
-elif [ "$action" = 'edit' ] && [ ! -e "$form_file" ]; then
- action="new"
-fi
-
-dumpFunction="function dump() { \
- var rv=''; \
- var allFrames = new Array(window); \
- for(f=0;f<window.frames.length;f=f+1) { \
- allFrames.push(window.frames[f]); \
- } \
- for(j=0;j<allFrames.length;j=j+1) { \
- try { \
- var xp_res=allFrames[j].document.evaluate('//input', allFrames[j].document.documentElement, null, XPathResult.ANY_TYPE,null); \
- var input; \
- while(input=xp_res.iterateNext()) { \
- var type=(input.type?input.type:text); \
- if(type == 'text' || type == 'password' || type == 'search') { \
- rv += input.name + '(' + type + '):' + input.value + '\\\\n'; \
- } \
- else if(type == 'checkbox' || type == 'radio') { \
- rv += input.name + '{' + input.value + '}(' + type + '):' + (input.checked?'ON':'OFF') + '\\\\n'; \
- } \
- } \
- xp_res=allFrames[j].document.evaluate('//textarea', allFrames[j].document.documentElement, null, XPathResult.ANY_TYPE,null); \
- var input; \
- while(input=xp_res.iterateNext()) { \
- rv += input.name + '(textarea):' + input.value + '\\\\n'; \
- } \
- } \
- catch(err) { } \
- } \
- return rv; \
-};"
-
-insertFunction="function insert(fname, ftype, fvalue, fchecked) { \
- var allFrames = new Array(window); \
- for(f=0;f<window.frames.length;f=f+1) { \
- allFrames.push(window.frames[f]); \
- } \
- for(j=0;j<allFrames.length;j=j+1) { \
- try { \
- if(ftype == 'text' || ftype == 'password' || ftype == 'search' || ftype == 'textarea') { \
- allFrames[j].document.getElementsByName(fname)[0].value = fvalue; \
- } \
- else if(ftype == 'checkbox') { \
- allFrames[j].document.getElementsByName(fname)[0].checked = fchecked;\
- } \
- else if(ftype == 'radio') { \
- var radios = allFrames[j].document.getElementsByName(fname); \
- for(r=0;r<radios.length;r+=1) { \
- if(radios[r].value == fvalue) { \
- radios[r].checked = fchecked; \
- } \
- } \
- } \
- } \
- catch(err) { } \
- } \
-};"
-
-if [ "$action" = 'load' ]; then
- [ -e "$form_file" ] || exit 2
- if [ "$( grep "!profile" "$form_file" | wc -l )" -gt 1 ]; then
- menu="$( sed -n -e 's/^!profile=\([^[:blank:]]\+\)/\1/p' "$form_file" )"
- option="$( print "$menu" | $DMENU )"
+test "$domain" || exit
+
+file=$UZBL_FORMS_DIR/$domain
+
+GenForm ()
+{
+ echo 'js uzbl.formfiller.dump();' \
+ | socat - unix-connect:"$UZBL_SOCKET" \
+ | awk '
+ /^formfillerstart$/ {
+ while (getline) {
+ if ( /^%!end/ ) exit
+ print
+ }
+ }
+ '
+}
+
+GetOption ()
+{
+ DMENU_SCHEME=formfiller
+ DMENU_PROMPT="choose profile"
+ DMENU_LINES=4
+
+ . "$UZBL_UTIL_DIR/dmenu.sh"
+
+ if [ $(grep -c '^!profile' "$1") -gt 1 ]
+ then sed -n 's/^!profile=//p' "$1" | $DMENU
+ else sed -n 's/^!profile=//p' "$1"
fi
+}
- sed -i -e 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' "$form_file"
- fields="$( sed -n -e "/^!profile=${option}/,/^!profile=/p" "$form_file" | \
- sed -e '/^!profile=/d' | \
- sed -e 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' | \
- sed -e 's/^\(.\+\)$/<{br}>\1/' | \
- tr -d '\n' | \
- sed -e 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g' )"
- printf "%s\n" "${fields}" | \
- sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \
- sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - "unix-connect:$UZBL_SOCKET"
- printf "%s\n" "${fields}" | \
- sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \
- sed -e 's/@/\\@/g' | socat - "unix-connect:$UZBL_SOCKET"
-elif [ "$action" = "once" ]; then
- tmpfile="$( mktemp )"
- printf "js %s dump();\n" "$dumpFunction" | \
- socat - "unix-connect:$UZBL_SOCKET" | \
- sed -n -e '/^[^(]\+([^)]\+):/p' > "$tmpfile"
- printf "$MODELINE\n" >> "$tmpfile"
- $UZBL_EDITOR "$tmpfile"
+ParseProfile ()
+{
+ sed "/^>/d; /^!profile=$1$/,/^!/!d; /^!/d"
+}
+
+ParseFields ()
+{
+ awk '/^%/ {
+
+ sub ( /%/, "" )
- [ -e "$tmpfile" ] || exit 2
-
- # Remove comments
- sed -i -e '/^>/d' "$tmpfile"
-
- sed -i -e 's/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):\(off\|no\|false\|unchecked\|0\|$\)/\1{\2}(\3):0/I;s/^\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[^0]\+/\1{\2}(\3):1/I' "$tmpfile"
- fields="$( sed -e 's/^\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):/%{>\1\2):<}%/' "$tmpfile" | \
- sed -e 's/^\(.\+\)$/<{br}>\1/' | \
- tr -d '\n' | \
- sed -e 's/<{br}>%{>\([^(]\+(\)\(radio\|checkbox\|text\|search\|textarea\|password\)):<}%/\\n\1\2):/g' )"
- printf "%s\n" "${fields}" | \
- sed -n -e "s/\([^(]\+\)(\(password\|text\|search\|textarea\)\+):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\2', '\3', 0);/p" | \
- sed -e 's/@/\\@/g;s/<{br}>/\\\\n/g' | socat - "unix-connect:$UZBL_SOCKET"
- printf "%s\n" "${fields}" | \
- sed -n -e "s/\([^{]\+\){\([^}]*\)}(\(radio\|checkbox\)):[ ]*\(.\+\)/js $insertFunction; insert('\1', '\3', '\2', \4);/p" | \
- sed -e 's/@/\\@/g' | socat - "unix-connect:$UZBL_SOCKET"
- rm -f "$tmpfile"
-else
- if [ "$action" = 'new' -o "$action" = 'add' ]; then
- [ "$action" = 'new' ] && echo "$MODELINE" > "$form_file"
- print "!profile=NAME_THIS_PROFILE$RAND\n" >> "$form_file"
- #
- # 2. and 3. line (tr -d and sed) are because, on gmail login for example,
- # <input > tag is splited into lines
- # ex:
- # <input name="Email"
- # type="text"
- # value="">
- # So, tr removes all new lines, and sed inserts new line after each >
- # Next sed selects only <input> tags and only with type = "text" or = "password"
- # If type is first and name is second, then another sed will change their order
- # so the last sed will make output
- # text_from_the_name_attr(text or password):
- #
- # login(text):
- # passwd(password):
- #
- printf "js %s dump();\n" "$dumpFunction" | \
- socat - "unix-connect:$UZBL_SOCKET" | \
- sed -n -e '/^[^(]\+([^)]\+):/p' >> "$form_file"
+ split( $0, parts, /\(|\)|\{|\}/ )
+
+ field = $0
+ sub ( /[^:]*:/, "", field )
+
+ if ( parts[2] ~ /(text|password|search)/ )
+ printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",0);\n",
+ parts[1], parts[2], field )
+
+ else if ( parts[2] ~ /(checkbox|radio)/ )
+ printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",%s);\n",
+ parts[1], parts[2], parts[3], field )
+
+ else if ( parts[2] == "textarea" ) {
+ field = ""
+ while (getline) {
+ if ( /^%/ ) break
+ sub ( /^\\/, "" )
+ gsub ( /"/, "\\\"" )
+ gsub ( /\\/, "\\\\" )
+ field = field $0 "\\n"
+ }
+ printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",0);\n",
+ parts[1], parts[2], field )
+ }
+
+ }'
+}
+
+New ()
+{
+ { echo '!profile=NAME_THIS_PROFILE'
+ GenForm | sed 's/^!/\\!/'
+ echo '!'
+ } >> "$file"
+ chmod 600 "$file"
+ $UZBL_EDITOR "$file"
+}
+
+Edit ()
+ if [ -e "$file" ]
+ then $UZBL_EDITOR "$file"
+ else New
fi
- [ -e "$form_file" ] || exit 3 #this should never happen, but you never know.
- $UZBL_EDITOR "$form_file" #TODO: if user aborts save in editor, the file is already overwritten
-fi
-# vim:fileencoding=utf-8:sw=4
+Load ()
+{
+ test -e "$file" || exit
+
+ option=$(GetOption "$file")
+
+ case $option in *[!a-zA-Z0-9_-]*) exit 1; esac
+
+ ParseProfile $option < "$file" \
+ | ParseFields \
+ | sed 's/@/\\@/' \
+ > "$UZBL_FIFO"
+}
+
+Once ()
+{
+ tmpfile=/tmp/${0##*/}-$$-tmpfile
+ trap 'rm -f "$tmpfile"' EXIT
+
+ GenForm > "$tmpfile"
+ chmod 600 "$tmpfile"
+
+ $UZBL_EDITOR "$tmpfile"
+
+ test -e "$tmpfile" &&
+ ParseFields < "$tmpfile" \
+ | sed 's/@/\\@' \
+ > "$UZBL_FIFO"
+}
+
+case $action in
+ new) New; Load ;;
+ edit) Edit; Load ;;
+ load) Load ;;
+ once) Once ;;
+ '') if [ -e "$file" ]; then Load; else New; Load; fi ;;
+ *) exit 1
+esac
diff --git a/examples/data/scripts/uzbl-cookie-daemon b/examples/data/scripts/uzbl-cookie-daemon
deleted file mode 100755
index 0b9bef9..0000000
--- a/examples/data/scripts/uzbl-cookie-daemon
+++ /dev/null
@@ -1,677 +0,0 @@
-#!/usr/bin/env python
-
-# The Python Cookie Daemon for Uzbl.
-# Copyright (c) 2009, Tom Adams <tom@holizz.com>
-# Copyright (c) 2009, Dieter Plaetinck <dieter@plaetinck.be>
-# Copyright (c) 2009, Mason Larobina <mason.larobina@gmail.com>
-# Copyright (c) 2009, Michael Fiano <axionix@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-'''
-The Python Cookie Daemon
-========================
-
-This daemon is a re-write of the original cookies.py script found in uzbl's
-master branch. This script provides more functionality than the original
-cookies.py by adding numerous command line options to specify different cookie
-jar locations, socket locations, verbose output, etc. This functionality is
-very useful as it allows you to run multiple daemons at once serving cookies
-to different groups of uzbl instances as required.
-
-Keeping up to date
-==================
-
-Check the cookie daemon uzbl-wiki page for more information on where to
-find the latest version of the cookie_daemon.py
-
- http://www.uzbl.org/wiki/cookie_daemon.py
-
-Command line options
-====================
-
-Use the following command to get a full list of the cookie_daemon.py command
-line options:
-
- ./cookie_daemon.py --help
-
-Talking with uzbl
-=================
-
-In order to get uzbl to talk to a running cookie daemon you add the following
-to your uzbl config:
-
- set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket
-
-Or if you prefer using the $HOME variable:
-
- set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket
-
-Todo list
-=========
-
- - Use a pid file to make force killing a running daemon possible.
-
-Reporting bugs / getting help
-=============================
-
-The best way to report bugs and or get help with the cookie daemon is to
-contact the maintainers it the #uzbl irc channel found on the Freenode IRC
-network (irc.freenode.org).
-'''
-
-import cookielib
-import os
-import sys
-import urllib2
-import select
-import socket
-import time
-import atexit
-from traceback import print_exc
-from signal import signal, SIGTERM
-from optparse import OptionParser
-from os.path import join
-
-try:
- import cStringIO as StringIO
-
-except ImportError:
- import StringIO
-
-
-# ============================================================================
-# ::: Default configuration section ::::::::::::::::::::::::::::::::::::::::::
-# ============================================================================
-
-def xdghome(key, default):
- '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise
- use $HOME and the default path.'''
-
- xdgkey = "XDG_%s_HOME" % key
- if xdgkey in os.environ.keys() and os.environ[xdgkey]:
- return os.environ[xdgkey]
-
- return join(os.environ['HOME'], default)
-
-# Setup xdg paths.
-CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/')
-DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/')
-CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/')
-
-# Ensure data paths exist.
-for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]:
- if not os.path.exists(path):
- os.makedirs(path)
-
-# Default config
-config = {
-
- # Default cookie jar, whitelist, and daemon socket locations.
- 'cookie_jar': join(DATA_DIR, 'cookies.txt'),
- 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'),
- 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'),
-
- # Don't use a cookie whitelist policy by default.
- 'use_whitelist': False,
-
- # Time out after x seconds of inactivity (set to 0 for never time out).
- # WARNING: Do not use this option if you are manually launching the daemon.
- 'daemon_timeout': 0,
-
- # Daemonise by default.
- 'daemon_mode': True,
-
- # Optionally print helpful debugging messages to the terminal.
- 'verbose': False,
-
-} # End of config dictionary.
-
-
-# ============================================================================
-# ::: End of configuration section :::::::::::::::::::::::::::::::::::::::::::
-# ============================================================================
-
-
-_SCRIPTNAME = os.path.basename(sys.argv[0])
-def echo(msg):
- '''Prints only if the verbose flag has been set.'''
-
- if config['verbose']:
- sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg))
-
-
-def error(msg):
- '''Prints error message and exits.'''
-
- sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg))
- sys.exit(1)
-
-
-def mkbasedir(filepath):
- '''Create the base directories of the file in the file-path if the dirs
- don't exist.'''
-
- dirname = os.path.dirname(filepath)
- if not os.path.exists(dirname):
- echo("creating dirs: %r" % dirname)
- os.makedirs(dirname)
-
-
-def daemon_running(cookie_socket):
- '''Check if another process (hopefully a cookie_daemon.py) is listening
- on the cookie daemon socket. If another process is found to be
- listening on the socket exit the daemon immediately and leave the
- socket alone. If the connect fails assume the socket has been abandoned
- and delete it (to be re-created in the create socket function).'''
-
- if not os.path.exists(cookie_socket):
- return False
-
- if os.path.isfile(cookie_socket):
- raise Exception("regular file at %r is not a socket" % cookie_socket)
-
-
- if os.path.isdir(cookie_socket):
- raise Exception("directory at %r is not a socket" % cookie_socket)
-
- try:
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
- sock.connect(cookie_socket)
- sock.close()
- echo("detected daemon listening on %r" % cookie_socket)
- return True
-
- except socket.error:
- # Failed to connect to cookie_socket so assume it has been
- # abandoned by another cookie daemon process.
- if os.path.exists(cookie_socket):
- echo("deleting abandoned socket at %r" % cookie_socket)
- os.remove(cookie_socket)
-
- return False
-
-
-def send_command(cookie_socket, cmd):
- '''Send a command to a running cookie daemon.'''
-
- if not daemon_running(cookie_socket):
- return False
-
- try:
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
- sock.connect(cookie_socket)
- sock.send(cmd)
- sock.close()
- echo("sent command %r to %r" % (cmd, cookie_socket))
- return True
-
- except socket.error:
- print_exc()
- error("failed to send message %r to %r" % (cmd, cookie_socket))
- return False
-
-
-def kill_daemon(cookie_socket):
- '''Send the "EXIT" command to running cookie_daemon.'''
-
- if send_command(cookie_socket, "EXIT"):
- # Now ensure the cookie_socket is cleaned up.
- start = time.time()
- while os.path.exists(cookie_socket):
- time.sleep(0.1)
- if (time.time() - start) > 5:
- error("force deleting socket %r" % cookie_socket)
- os.remove(cookie_socket)
- return
-
- echo("stopped daemon listening on %r"% cookie_socket)
-
- else:
- if os.path.exists(cookie_socket):
- os.remove(cookie_socket)
- echo("removed abandoned/broken socket %r" % cookie_socket)
-
-
-def daemonize():
- '''Daemonize the process using the Stevens' double-fork magic.'''
-
- try:
- if os.fork():
- os._exit(0)
-
- except OSError:
- print_exc()
- sys.stderr.write("fork #1 failed")
- sys.exit(1)
-
- os.chdir('/')
- os.setsid()
- os.umask(0)
-
- try:
- if os.fork():
- os._exit(0)
-
- except OSError:
- print_exc()
- sys.stderr.write("fork #2 failed")
- sys.exit(1)
-
- if sys.stdout.isatty():
- sys.stdout.flush()
- sys.stderr.flush()
-
- devnull = '/dev/null'
- stdin = file(devnull, 'r')
- stdout = file(devnull, 'a+')
- stderr = file(devnull, 'a+', 0)
-
- os.dup2(stdin.fileno(), sys.stdin.fileno())
- os.dup2(stdout.fileno(), sys.stdout.fileno())
- os.dup2(stderr.fileno(), sys.stderr.fileno())
-
-
-class CookieMonster:
- '''The uzbl cookie daemon class.'''
-
- def __init__(self):
- '''Initialise class variables.'''
-
- self.server_socket = None
- self.jar = None
- self.last_request = time.time()
- self._running = False
-
-
- def run(self):
- '''Start the daemon.'''
-
- # The check healthy function will exit if another daemon is detected
- # listening on the cookie socket and remove the abandoned socket if
- # there isnt.
- if os.path.exists(config['cookie_socket']):
- if daemon_running(config['cookie_socket']):
- sys.exit(1)
-
- # Create cookie daemon socket.
- self.create_socket()
-
- # Daemonize process.
- if config['daemon_mode']:
- echo("entering daemon mode")
- daemonize()
-
- # Register a function to cleanup on exit.
- atexit.register(self.quit)
-
- # Make SIGTERM act orderly.
- signal(SIGTERM, lambda signum, stack_frame: sys.exit(1))
-
- # Create cookie jar object from file.
- self.open_cookie_jar()
-
- # Create a way to exit nested loops by setting a running flag.
- self._running = True
-
- while self._running:
- try:
- # Enter main listen loop.
- self.listen()
-
- except KeyboardInterrupt:
- self._running = False
- print
-
- except socket.error:
- print_exc()
-
- except:
- # Clean up
- self.del_socket()
-
- # Raise exception
- raise
-
- # Always delete the socket before calling create again.
- self.del_socket()
- # Create cookie daemon socket.
- self.create_socket()
-
-
- def load_whitelist(self):
- '''Load the cookie jar whitelist policy.'''
-
- cookie_whitelist = config['cookie_whitelist']
-
- if cookie_whitelist:
- mkbasedir(cookie_whitelist)
-
- # Create cookie whitelist file if it does not exist.
- if not os.path.exists(cookie_whitelist):
- open(cookie_whitelist, 'w').close()
-
- # Read cookie whitelist file into list.
- file = open(cookie_whitelist,'r')
- domain_list = [line.rstrip('\n') for line in file]
- file.close()
-
- # Define policy of allowed domains
- policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list)
- self.jar.set_policy(policy)
-
- # Save the last modified time of the whitelist.
- self._whitelistmtime = os.stat(cookie_whitelist).st_mtime
-
-
- def open_cookie_jar(self):
- '''Open the cookie jar.'''
-
- cookie_jar = config['cookie_jar']
- cookie_whitelist = config['cookie_whitelist']
-
- if cookie_jar:
- mkbasedir(cookie_jar)
-
- # Create cookie jar object from file.
- self.jar = cookielib.MozillaCookieJar(cookie_jar)
-
- # Load cookie whitelist policy.
- if config['use_whitelist']:
- self.load_whitelist()
-
- if cookie_jar:
- try:
- # Attempt to load cookies from the cookie jar.
- self.jar.load(ignore_discard=True)
-
- # Ensure restrictive permissions are set on the cookie jar
- # to prevent other users on the system from hi-jacking your
- # authenticated sessions simply by copying your cookie jar.
- os.chmod(cookie_jar, 0600)
-
- except:
- pass
-
-
- def reload_whitelist(self):
- '''Reload the cookie whitelist.'''
-
- cookie_whitelist = config['cookie_whitelist']
- if os.path.exists(cookie_whitelist):
- echo("reloading whitelist %r" % cookie_whitelist)
- self.open_cookie_jar()
-
-
- def create_socket(self):
- '''Create AF_UNIX socket for communication with uzbl instances.'''
-
- cookie_socket = config['cookie_socket']
- mkbasedir(cookie_socket)
-
- self.server_socket = socket.socket(socket.AF_UNIX,
- socket.SOCK_SEQPACKET)
-
- self.server_socket.bind(cookie_socket)
-
- # Set restrictive permissions on the cookie socket to prevent other
- # users on the system from data-mining your cookies.
- os.chmod(cookie_socket, 0600)
-
-
- def listen(self):
- '''Listen for incoming cookie PUT and GET requests.'''
-
- daemon_timeout = config['daemon_timeout']
- echo("listening on %r" % config['cookie_socket'])
-
- connections = []
-
- while self._running:
- # This line tells the socket how many pending incoming connections
- # to enqueue at once. Raising this number may or may not increase
- # performance.
- self.server_socket.listen(1)
-
- r, w, x = select.select([self.server_socket]+connections, [], [], 1)
-
- for socket in r:
- if self.server_socket == socket:
- client_socket, _ = socket.accept()
- connections.append(client_socket)
- else:
- if not self.handle_request(socket):
- # connection was closed, forget about the client socket
- connections.remove(socket)
-
- self.last_request = time.time()
-
- if daemon_timeout:
- # Checks if the daemon has been idling for too long.
- idle = time.time() - self.last_request
- if idle > daemon_timeout:
- self._running = False
-
-
- def handle_request(self, client_socket):
- '''Connection made, now to serve a cookie PUT or GET request.'''
-
- # Receive cookie request from client.
- data = client_socket.recv(8192)
- if not data:
- return False
-
- # Cookie argument list in packet is null separated.
- argv = data.split("\0")
- action = argv[0].upper().strip()
-
- # Catch the EXIT command sent to kill running daemons.
- if action == "EXIT":
- self._running = False
- return False
-
- # Catch whitelist RELOAD command.
- elif action == "RELOAD":
- self.reload_whitelist()
- return True
-
- # Return if command unknown.
- elif action not in ['GET', 'PUT']:
- error("unknown command %r." % argv)
- return True
-
- # Determine whether or not to print cookie data to terminal.
- print_cookie = (config['verbose'] and not config['daemon_mode'])
- if print_cookie:
- print ' '.join(argv[:4])
-
- uri = urllib2.urlparse.ParseResult(
- scheme=argv[1],
- netloc=argv[2],
- path=argv[3],
- params='',
- query='',
- fragment='').geturl()
-
- req = urllib2.Request(uri)
-
- if action == "GET":
- self.jar._policy._now = self._now = int(time.time())
- cookies = self.jar._cookies_for_request(req)
- attrs = self.jar._cookie_attrs(cookies)
- if attrs:
- cookie = "; ".join(attrs)
- client_socket.send(cookie)
- if print_cookie:
- print cookie
- else:
- client_socket.send("\0")
-
- elif action == "PUT":
- cookie = argv[4] if len(argv) > 3 else None
- if print_cookie:
- print cookie
-
- self.put_cookie(req, cookie)
- client_socket.send("\0")
-
- if print_cookie:
- print
-
- return True
-
-
- def put_cookie(self, req, cookie=None):
- '''Put a cookie in the cookie jar.'''
-
- hdr = urllib2.httplib.HTTPMessage(\
- StringIO.StringIO('Set-Cookie: %s' % cookie))
- res = urllib2.addinfourl(StringIO.StringIO(), hdr,
- req.get_full_url())
- self.jar.extract_cookies(res, req)
- if config['cookie_jar']:
- self.jar.save(ignore_discard=True)
-
-
- def del_socket(self):
- '''Remove the cookie_socket file on exit. In a way the cookie_socket
- is the daemons pid file equivalent.'''
-
- if self.server_socket:
- try:
- self.server_socket.close()
-
- except:
- pass
-
- self.server_socket = None
-
- cookie_socket = config['cookie_socket']
- if os.path.exists(cookie_socket):
- echo("deleting socket %r" % cookie_socket)
- os.remove(cookie_socket)
-
-
- def quit(self):
- '''Called on exit to make sure all loose ends are tied up.'''
-
- self.del_socket()
- sys.exit(0)
-
-
-def main():
- '''Main function.'''
-
- # Define command line parameters.
- usage = "usage: %prog [options] {start|stop|restart|reload}"
- parser = OptionParser(usage=usage)
- parser.add_option('-n', '--no-daemon', dest='no_daemon',
- action='store_true', help="don't daemonise the process.")
-
- parser.add_option('-v', '--verbose', dest="verbose",
- action='store_true', help="print verbose output.")
-
- parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout',
- action="store", metavar="SECONDS", help="shutdown the daemon after x "\
- "seconds inactivity. WARNING: Do not use this when launching the "\
- "cookie daemon manually.")
-
- parser.add_option('-s', '--cookie-socket', dest="cookie_socket",
- metavar="SOCKET", help="manually specify the socket location.")
-
- parser.add_option('-j', '--cookie-jar', dest='cookie_jar',
- metavar="FILE", help="manually specify the cookie jar location.")
-
- parser.add_option('-m', '--memory', dest='memory', action='store_true',
- help="store cookies in memory only - do not write to disk")
-
- parser.add_option('-u', '--use-whitelist', dest='usewhitelist',
- action='store_true', help="use cookie whitelist policy")
-
- parser.add_option('-w', '--cookie-whitelist', dest='whitelist',
- action='store', help="manually specify whitelist location",
- metavar='FILE')
-
- # Parse the command line arguments.
- (options, args) = parser.parse_args()
-
- expand = lambda p: os.path.realpath(os.path.expandvars(p))
-
- initcommands = ['start', 'stop', 'restart', 'reload']
- for arg in args:
- if arg not in initcommands:
- error("unknown argument %r" % args[0])
- sys.exit(1)
-
- if len(args) > 1:
- error("the daemon only accepts one {%s} action at a time."
- % '|'.join(initcommands))
- sys.exit(1)
-
- if len(args):
- action = args[0]
-
- else:
- action = "start"
-
- if options.no_daemon:
- config['daemon_mode'] = False
-
- if options.cookie_socket:
- config['cookie_socket'] = expand(options.cookie_socket)
-
- if options.cookie_jar:
- config['cookie_jar'] = expand(options.cookie_jar)
-
- if options.memory:
- config['cookie_jar'] = None
-
- if options.whitelist:
- config['cookie_whitelist'] = expand(options.whitelist)
-
- if options.whitelist or options.usewhitelist:
- config['use_whitelist'] = True
-
- if options.daemon_timeout:
- try:
- config['daemon_timeout'] = int(options.daemon_timeout)
-
- except ValueError:
- error("expected int argument for -t, --daemon-timeout")
-
- # Expand $VAR's in config keys that relate to paths.
- for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']:
- if config[key]:
- config[key] = os.path.expandvars(config[key])
-
- if options.verbose:
- config['verbose'] = True
- import pprint
- sys.stderr.write("%s\n" % pprint.pformat(config))
-
- # It would be better if we didn't need to start this python process just
- # to send a command to the socket, but unfortunately socat doesn't seem
- # to support SEQPACKET.
- if action == "reload":
- send_command(config['cookie_socket'], "RELOAD")
-
- if action in ['stop', 'restart']:
- kill_daemon(config['cookie_socket'])
-
- if action in ['start', 'restart']:
- CookieMonster().run()
-
-
-if __name__ == "__main__":
- main()
diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager
index 8ad3af7..cb462c7 100755
--- a/examples/data/scripts/uzbl-event-manager
+++ b/examples/data/scripts/uzbl-event-manager
@@ -34,6 +34,7 @@ import socket
import sys
import time
import weakref
+import re
from collections import defaultdict
from functools import partial
from glob import glob
@@ -169,13 +170,16 @@ class EventHandler(object):
self.callback(uzbl, *args, **kwargs)
+
+
+
class Plugin(object):
'''Plugin module wrapper object.'''
# Special functions exported from the Plugin instance to the
# plugin namespace.
special_functions = ['require', 'export', 'export_dict', 'connect',
- 'connect_dict', 'logger']
+ 'connect_dict', 'logger', 'unquote', 'splitquoted']
def __init__(self, parent, name, path, plugin):
@@ -291,6 +295,20 @@ class Plugin(object):
assert plugin in self.parent.plugins, self.logger.critical(
'plugin %r required by plugin %r' (plugin, self.name))
+ @classmethod
+ def unquote(cls, s):
+ '''Removes quotation marks around strings if any and interprets
+ \\-escape sequences using `string_escape`'''
+ if s and s[0] == s[-1] and s[0] in ['"', "'"]:
+ s = s[1:-1]
+ return s.encode('utf-8').decode('string_escape').decode('utf-8')
+
+ _splitquoted = re.compile("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
+ @classmethod
+ def splitquoted(cls, text):
+ '''Splits string on whitespace while respecting quotations'''
+ return [cls.unquote(p) for p in cls._splitquoted.split(text) if p.strip()]
+
class Uzbl(object):
def __init__(self, parent, child_socket):
@@ -969,3 +987,5 @@ if __name__ == "__main__":
daemon_actions[action]()
logger.debug('process CPU time: %f' % time.clock())
+
+# vi: set et ts=4:
diff --git a/examples/data/scripts/uzbl-tabbed b/examples/data/scripts/uzbl-tabbed
index 1d64436..de71c2c 100755
--- a/examples/data/scripts/uzbl-tabbed
+++ b/examples/data/scripts/uzbl-tabbed
@@ -472,8 +472,11 @@ class UzblInstance:
self.parent.update_gtk_tab_pos()
elif var == "status_background":
if config['status_background'].strip():
- col = gtk.gdk.color_parse(config['status_background'])
- self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col)
+ try:
+ col = gtk.gdk.color_parse(config['status_background'])
+ self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col)
+ except ValueError:
+ pass # got an invalid colour, just ignore it
elif var == "tab_titles" or var == "tab_indexes":
for tab in self.parent.notebook:
self.parent.tabs[tab].title_changed(True)
diff --git a/examples/data/style.css b/examples/data/style.css
index f9b111e..ff055d1 100644
--- a/examples/data/style.css
+++ b/examples/data/style.css
@@ -1,25 +1,25 @@
-.uzbl_highlight { background-color: yellow;}
-.uzbl_h_first { background-color: lightgreen;}
+#uzbl_link_hints > span {
+ z-index: 1000 !important;
-.uzbl_follow { border-style: dotted;
- border-width: thin;
+ background-color: #aaff00 !important;
+ border: 2px solid #556600 !important;
+ margin: 0 !important;
+ padding: 1px !important;
+
+ color: black !important;
+ font-size: 9px !important;
+ line-height: 9px !important;
+ font-weight: bold !important;
+ font-variant: normal !important;
+ text-decoration: none !important;
+
+ -webkit-transform: translate(-5px,-5px);
+ /* opacity: 0.7; */
}
-#uzbl_hint > div {
- display: inline;
- border: 2px solid #4a6600;
- background-color: #b9ff00;
- color: black;
- font-size: 9px;
- font-weight: bold;
- line-height: 9px;
- margin: 0px;
- padding: 0px;
- position: absolute;
- z-index: 1000;
- -webkit-border-radius: 6px;
- text-decoration: none;
- -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px);
+/* we can have different colours for different types of hints! */
+#uzbl_link_hints.new-window > span {
+ background-color: #ffff00 !important;
}
/* vim:set et ts=4: */
diff --git a/examples/uzbl-cookie-manager.c b/examples/uzbl-cookie-manager.c
deleted file mode 100644
index 70addf3..0000000
--- a/examples/uzbl-cookie-manager.c
+++ /dev/null
@@ -1,381 +0,0 @@
-#define _POSIX_SOURCE
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-#include <signal.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <sys/unistd.h>
-
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#include <libsoup/soup-cookie.h>
-#include <libsoup/soup-cookie-jar-text.h>
-#include <libsoup/soup-uri.h>
-
-#include "../src/util.h"
-
-extern const XDG_Var XDG[];
-
-int verbose = 0;
-
-#define SOCK_BACKLOG 10
-#define MAX_COOKIE_LENGTH 4096
-
-char cookie_buffer[MAX_COOKIE_LENGTH];
-
-int setup_socket(const char *cookied_socket_path) {
- /* delete the cookie socket if it was left behind on a previous run */
- unlink(cookied_socket_path);
-
- int socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
-
- if(socket_fd < 0) {
- fprintf(stderr, "socket failed (%s)\n", strerror(errno));
- return -1;
- }
-
- struct sockaddr_un sa;
- sa.sun_family = AF_UNIX;
- strcpy(sa.sun_path, cookied_socket_path);
-
- if(bind(socket_fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
- fprintf(stderr, "bind failed (%s)\n", strerror(errno));
- return -1;
- }
-
- if(listen(socket_fd, SOCK_BACKLOG) < 0) {
- fprintf(stderr, "listen failed (%s)\n", strerror(errno));
- return -1;
- }
-
- return socket_fd;
-}
-
-const char *whitelist_path = NULL;
-GPtrArray *whitelisted_hosts = NULL;
-time_t whitelist_update_time = 0;
-
-void whitelist_line_cb(const gchar* line, void *user_data) {
- (void) user_data;
-
- gchar *norm_host;
-
- const gchar *p = line;
- while(isspace(*p))
- p++;
-
- if(p[0] == '#' || !p[0]) /* ignore comments and blank lines */
- return;
-
- if(p[0] == '.')
- norm_host = g_strdup(p);
- else
- norm_host = g_strconcat(".", p, NULL);
-
- g_ptr_array_add(whitelisted_hosts, g_strchomp(norm_host));
-}
-
-gboolean load_whitelist(const char *whitelist_path) {
- if(!file_exists(whitelist_path))
- return FALSE;
-
- /* check if the whitelist file was updated */
- struct stat f;
- if(stat(whitelist_path, &f) < 0)
- return FALSE;
-
- if(whitelisted_hosts == NULL)
- whitelisted_hosts = g_ptr_array_new();
-
- if(f.st_mtime > whitelist_update_time) {
- /* the file was updated, reload the whitelist */
- if(verbose) puts("reloading whitelist");
- while(whitelisted_hosts->len > 0) {
- g_free(g_ptr_array_index(whitelisted_hosts, 0));
- g_ptr_array_remove_index_fast(whitelisted_hosts, 0);
- }
- for_each_line_in_file(whitelist_path, whitelist_line_cb, NULL);
- whitelist_update_time = f.st_mtime;
- }
-
- return TRUE;
-}
-
-gboolean should_save_cookie(const char *host) {
- if(!load_whitelist(whitelist_path))
- return TRUE; /* some error with the file, assume no whitelist */
-
- /* we normalize the hostname so it has a . in front like the whitelist entries */
- gchar *test_host = (host[0] == '.') ? g_strdup(host) : g_strconcat(".", host, NULL);
- int hl = strlen(test_host);
-
- /* test against each entry in the whitelist */
- gboolean result = FALSE;
- guint i;
- for(i = 0; i < whitelisted_hosts->len; i++) {
- /* a match means the host ends with (or is equal to) the whitelist entry */
- const gchar *entry = g_ptr_array_index(whitelisted_hosts, i);
- int el = strlen(entry);
- result = (el <= hl) && !strcmp(test_host + (hl - el), entry);
-
- if(result)
- break;
- }
-
- g_free(test_host);
-
- return result;
-}
-
-void handle_request(SoupCookieJar *j, const char *buff, int len, int fd) {
- const char *command = buff;
-
- const char *scheme = command + strlen(command) + 1;
- if((scheme - buff) > len) {
- fprintf(stderr, "got malformed or partial request\n");
- return;
- }
-
- const char *host = scheme + strlen(scheme) + 1;
- if((host - buff) > len) {
- fprintf(stderr, "got malformed or partial request\n");
- return;
- }
-
- const char *path = host + strlen(host) + 1;
- if((path - buff) > len) {
- fprintf(stderr, "got malformed or partial request\n");
- return;
- }
-
- /* glue the parts back together into a SoupURI */
- char *u = g_strconcat(scheme, "://", host, path, NULL);
- if(verbose) printf("%s %s\n", command, u);
- SoupURI *uri = soup_uri_new(u);
- g_free(u);
-
- if(!strcmp(command, "GET")) {
- char *result = soup_cookie_jar_get_cookies(j, uri, TRUE);
- if(result) {
- if(verbose) puts(result);
- if(write(fd, result, strlen(result)+1) < 0)
- fprintf(stderr, "write failed (%s)", strerror(errno));
-
- g_free(result);
- } else {
- if(verbose) puts("-");
- if(write(fd, "", 1) < 0)
- fprintf(stderr, "write failed (%s)", strerror(errno));
- }
- } else if(!strcmp(command, "PUT")) {
- const char *name_and_val = path + strlen(path) + 1;
- if((name_and_val - buff) > len) {
- fprintf(stderr, "got malformed or partial request\n");
- return;
- }
-
- if(verbose) puts(name_and_val);
-
- if(should_save_cookie(host)) {
- char *eql = strchr(name_and_val, '=');
- eql[0] = 0;
-
- const char *name = name_and_val;
- const char *value = eql + 1;
-
- SoupCookie *cookie = soup_cookie_new(name, value, host, path, SOUP_COOKIE_MAX_AGE_ONE_YEAR);
-
- soup_cookie_jar_add_cookie(j, cookie);
- } else if(verbose)
- puts("no, blacklisted.");
-
- if(write(fd, "", 1) < 0)
- fprintf(stderr, "write failed (%s)", strerror(errno));
- }
-
- soup_uri_free(uri);
-}
-
-void
-wait_for_things_to_happen_and_then_do_things(SoupCookieJar* j, int cookie_socket) {
- GArray *connections = g_array_new (FALSE, FALSE, sizeof (int));
-
- while(1) {
- unsigned int i;
- int r;
- fd_set fs;
-
- int maxfd = cookie_socket;
- FD_ZERO(&fs);
- FD_SET(maxfd, &fs);
-
- for(i = 0; i < connections->len; i++) {
- int fd = g_array_index(connections, int, i);
- if(fd > maxfd) maxfd = fd;
- FD_SET(fd, &fs);
- }
-
- r = select(maxfd+1, &fs, NULL, NULL, NULL);
- if(r < 0) {
- fprintf(stderr, "select failed (%s)\n", strerror(errno));
- continue;
- }
-
- if(FD_ISSET(cookie_socket, &fs)) {
- /* handle new connection */
- int fd = accept(cookie_socket, NULL, NULL);
- g_array_append_val(connections, fd);
- if(verbose) puts("got connection.");
- }
-
- for(i = 0; i < connections->len; i++) {
- /* handle activity on a connection */
- int fd = g_array_index(connections, int, i);
- if(FD_ISSET(fd, &fs)) {
- r = read(fd, cookie_buffer, MAX_COOKIE_LENGTH);
- if(r < 0) {
- fprintf(stderr, "read failed (%s)\n", strerror(errno));
- continue;
- } else if(r == 0) {
- if(verbose) puts("client hung up.");
- g_array_remove_index(connections, i);
- i--; /* other elements in the array are moved down to fill the gap */
- continue;
- }
- cookie_buffer[r] = 0;
-
- handle_request(j, cookie_buffer, r, fd);
- }
- }
- }
-}
-
-void usage(const char *progname) {
- printf("%s [-s socket-path] [-f cookies.txt] [-w whitelist-file] [-n] [-v]\n", progname);
- puts("\t-n\tdon't daemonise the process");
- puts("\t-v\tbe verbose");
-}
-
-void daemonise() {
- int r = fork();
-
- if(r < 0) {
- fprintf(stderr, "fork failed (%s)", strerror(errno));
- exit(1);
- } else if (r > 0) {
- /* this is the parent, which has done its job */
- exit(0);
- }
-
- if(setsid() < 0) {
- fprintf(stderr, "setsid failed (%s)", strerror(errno));
- exit(1);
- }
-}
-
-const char *pid_file_path = NULL;
-const char *cookied_socket_path = NULL;
-
-void cleanup_after_signal(int signal) {
- (void) signal;
- unlink(pid_file_path);
- unlink(cookied_socket_path);
- exit(0);
-}
-
-int main(int argc, char *argv[]) {
- int i;
-
- const char *cookies_txt_path = NULL;
- gboolean foreground = FALSE;
-
- for(i = 1; i < argc && argv[i][0] == '-'; i++) {
- switch(argv[i][1]) {
- case 's':
- cookied_socket_path = argv[++i];
- break;
- case 'f':
- cookies_txt_path = argv[++i];
- break;
- case 'w':
- whitelist_path = argv[++i];
- break;
- case 'n':
- foreground = TRUE;
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- usage(argv[0]);
- return 1;
- }
- }
-
- if(!foreground)
- daemonise();
-
- if(!cookies_txt_path)
- cookies_txt_path = g_strconcat(get_xdg_var(XDG[1]), "/uzbl/cookies.txt", NULL);
-
- if(!cookied_socket_path)
- cookied_socket_path = g_strconcat(get_xdg_var(XDG[2]), "/uzbl/cookie_daemon_socket", NULL);
-
- if(!whitelist_path)
- whitelist_path = g_strconcat(get_xdg_var(XDG[0]), "/uzbl/cookie_whitelist", NULL);
-
- /* write out and lock the pid file.
- * this ensures that only one uzbl-cookie-manager is running per-socket.
- * (we should probably also lock the cookies.txt to prevent accidents...) */
- pid_file_path = g_strconcat(cookied_socket_path, ".pid", NULL);
- int lockfd = open(pid_file_path, O_RDWR|O_CREAT, 0600);
- if(lockfd < 0) {
- fprintf(stderr, "couldn't open pid file %s (%s)\n", pid_file_path, strerror(errno));
- return 1;
- }
-
- if(flock(lockfd, LOCK_EX|LOCK_NB) < 0) {
- fprintf(stderr, "couldn't lock pid file %s (%s)\n", pid_file_path, strerror(errno));
- fprintf(stderr, "uzbl-cookie-manager is probably already running\n");
- return 1;
- }
-
- gchar* pids = g_strdup_printf("%d\n", getpid());
- write(lockfd, pids, strlen(pids));
- g_free(pids);
-
- struct sigaction sa;
- sa.sa_handler = cleanup_after_signal;
- if(sigaction(SIGINT, &sa, NULL) || sigaction(SIGTERM, &sa, NULL)) {
- fprintf(stderr, "sigaction failed (%s)\n", strerror(errno));
- return 1;
- }
-
- if(!foreground) {
- /* close STDIO */
- close(0);
- close(1);
- close(2);
- }
-
- g_type_init();
-
- SoupCookieJar *j = soup_cookie_jar_text_new(cookies_txt_path, FALSE);
-
- int cookie_socket = setup_socket(cookied_socket_path);
- if(cookie_socket < 0)
- return 1;
-
- wait_for_things_to_happen_and_then_do_things(j, cookie_socket);
-
- return 0;
-}
diff --git a/extras/vim/syntax/uzbl.vim b/extras/vim/syntax/uzbl.vim
index b8572c9..1a4172b 100644
--- a/extras/vim/syntax/uzbl.vim
+++ b/extras/vim/syntax/uzbl.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Uzbl config syntax
-" Maintainer: Mason Larobina <mason.larobina@gmail.com>
-" Contributors: Gregor Uhlenheuer (kongo2002)
+" Maintainer: Gregor Uhlenheuer (kongo2002) <kongo2002@gmail.com>
+" Contributors: Mason Larobina <mason.larobina@gmail.com>
" Pawel Tomak (grodzik) <pawel.tomak@gmail.com>
" Version: 0.1
"
@@ -25,19 +25,20 @@ elseif exists("b:current_syntax")
finish
endif
-" Don't match keywords inside strings
-setl iskeyword=!-~,192-255
-
syn keyword uzblKeyword back forward scroll reload reload_ign_cache stop
syn keyword uzblKeyword zoom_in zoom_out toggle_zoom_type uri script
-syn keyword uzblKeyword toggle_status spawn sync_spawn sync_sh talk_to_socket
+syn keyword uzblKeyword toggle_status spawn sync_spawn sync_sh sync_spawn_exec
syn keyword uzblKeyword exit search search_reverse search_clear dehilight set
syn keyword uzblKeyword dump_config dump_config_as_events chain print event
syn keyword uzblKeyword request menu_add menu_link_add menu_image_add
syn keyword uzblKeyword menu_editable_add menu_separator menu_link_separator
syn keyword uzblKeyword menu_image_separator menu_editable_separator
syn keyword uzblKeyword menu_remove menu_link_remove menu_image_remove
-syn keyword uzblKeyword menu_editable_remove hardcopy include js sh
+syn keyword uzblKeyword menu_editable_remove hardcopy include
+
+" Match 'js' and 'sh' only without a dot in front
+syn match uzblKeyword /\.\@<!sh\s\+/
+syn match uzblKeyword /\.\@<!js\s\+/
" Comments
syn match uzblTodo /TODO:/ contained
diff --git a/src/callbacks.c b/src/callbacks.c
index fa2ed1f..deda426 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -7,12 +7,14 @@
#include "callbacks.h"
#include "events.h"
#include "util.h"
+#include "io.h"
+
void
set_proxy_url() {
SoupURI *suri;
- if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
+ if (uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
soup_session_remove_feature_by_type(uzbl.net.soup_session,
(GType) SOUP_SESSION_PROXY_URI);
}
@@ -23,9 +25,11 @@ set_proxy_url() {
suri, NULL);
soup_uri_free(suri);
}
+
return;
}
+
void
set_authentication_handler() {
/* Check if WEBKIT_TYPE_SOUP_AUTH_DIALOG feature is set */
@@ -45,19 +49,26 @@ set_authentication_handler() {
return;
}
+
void
set_status_background() {
- GdkColor color;
- gdk_color_parse (uzbl.behave.status_background, &color);
/* labels and hboxes do not draw their own background. applying this
* on the vbox/main_window is ok as the statusbar is the only affected
* widget. (if not, we could also use GtkEventBox) */
- if (uzbl.gui.main_window)
- gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
- else if (uzbl.gui.plug)
- gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
+ GtkWidget* widget = uzbl.gui.main_window ? uzbl.gui.main_window : GTK_WIDGET (uzbl.gui.plug);
+
+#if GTK_CHECK_VERSION(2,91,0)
+ GdkRGBA color;
+ gdk_rgba_parse (&color, uzbl.behave.status_background);
+ gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &color);
+#else
+ GdkColor color;
+ gdk_color_parse (uzbl.behave.status_background, &color);
+ gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color);
+#endif
}
+
void
set_icon() {
if(file_exists(uzbl.gui.icon)) {
@@ -105,7 +116,7 @@ cmd_set_status() {
void
cmd_load_uri() {
- load_uri_imp (uzbl.state.uri);
+ load_uri_imp (uzbl.state.uri);
}
void
@@ -280,6 +291,13 @@ cmd_caret_browsing() {
}
void
+set_current_encoding() {
+ webkit_web_view_set_custom_encoding(uzbl.gui.web_view,
+ uzbl.behave.current_encoding);
+}
+
+
+void
cmd_fifo_dir() {
uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
}
@@ -402,12 +420,12 @@ link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpoin
if(s->last_selected_url &&
g_strcmp0(s->selected_url, s->last_selected_url))
- send_event(LINK_UNHOVER, s->last_selected_url, NULL);
+ send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
- send_event(LINK_HOVER, s->selected_url, NULL);
+ send_event(LINK_HOVER, NULL, TYPE_STR, s->selected_url, NULL);
}
else if(s->last_selected_url) {
- send_event(LINK_UNHOVER, s->last_selected_url, NULL);
+ send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
}
update_title();
@@ -422,7 +440,7 @@ title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
g_free (uzbl.gui.main_title);
uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
update_title();
- send_event(TITLE_CHANGED, uzbl.gui.main_title, NULL);
+ send_event(TITLE_CHANGED, NULL, TYPE_STR, uzbl.gui.main_title, NULL);
g_setenv("UZBL_TITLE", uzbl.gui.main_title, TRUE);
}
@@ -430,38 +448,52 @@ void
progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
(void) param_spec;
int progress = webkit_web_view_get_progress(web_view) * 100;
- gchar *prg_str = itos(progress);
- send_event(LOAD_PROGRESS, prg_str, NULL);
- g_free(prg_str);
+ send_event(LOAD_PROGRESS, NULL, TYPE_INT, progress, NULL);
}
void
load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
(void) param_spec;
- WebKitWebFrame *frame = webkit_web_view_get_main_frame(web_view);
+ WebKitWebFrame *frame;
WebKitLoadStatus status = webkit_web_view_get_load_status(web_view);
switch(status) {
case WEBKIT_LOAD_PROVISIONAL:
- send_event(LOAD_START, uzbl.state.uri, NULL);
+ send_event(LOAD_START, NULL, TYPE_STR, uzbl.state.uri ? uzbl.state.uri : "", NULL);
break;
case WEBKIT_LOAD_COMMITTED:
- g_free (uzbl.state.uri);
- GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
- uzbl.state.uri = g_string_free (newuri, FALSE);
- g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
-
- send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame), NULL);
+ frame = webkit_web_view_get_main_frame(web_view);
+ send_event(LOAD_COMMIT, NULL, TYPE_STR, webkit_web_frame_get_uri (frame), NULL);
break;
case WEBKIT_LOAD_FINISHED:
- send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame), NULL);
+ send_event(LOAD_FINISH, NULL, TYPE_STR, uzbl.state.uri, NULL);
break;
case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
break; /* we don't do anything with this (yet) */
case WEBKIT_LOAD_FAILED:
break; /* load_error_cb will handle this case */
}
+}
+void
+load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) {
+ (void) page; (void) frame; (void) ud;
+ GError *err = web_err;
+
+ send_event (LOAD_ERROR, NULL,
+ TYPE_STR, uri,
+ TYPE_INT, err->code,
+ TYPE_STR, err->message,
+ NULL);
+}
+
+void
+uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec) {
+ (void) param_spec;
+
+ g_free (uzbl.state.uri);
+ g_object_get (web_view, "uri", &uzbl.state.uri, NULL);
+ g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
}
void
@@ -471,24 +503,11 @@ selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) {
webkit_web_view_copy_clipboard(webkitwebview);
tmp = gtk_clipboard_wait_for_text(gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
- send_event(SELECTION_CHANGED, tmp, NULL);
+ send_event(SELECTION_CHANGED, NULL, TYPE_STR, tmp ? tmp : "", NULL);
g_free(tmp);
}
void
-load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) {
- (void) page;
- (void) frame;
- (void) ud;
- GError *err = web_err;
- gchar *details;
-
- details = g_strdup_printf("%s %d:%s", uri, err->code, err->message);
- send_event(LOAD_ERROR, details, NULL);
- g_free(details);
-}
-
-void
destroy_cb (GtkWidget* widget, gpointer data) {
(void) widget;
(void) data;
@@ -505,7 +524,7 @@ configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
retrieve_geometry();
if(strcmp(lastgeo, uzbl.gui.geometry))
- send_event(GEOMETRY_CHANGED, uzbl.gui.geometry, NULL);
+ send_event(GEOMETRY_CHANGED, NULL, TYPE_STR, uzbl.gui.geometry, NULL);
g_free(lastgeo);
return FALSE;
@@ -517,10 +536,7 @@ focus_cb(GtkWidget* window, GdkEventFocus* event, void *ud) {
(void) event;
(void) ud;
- if(event->in)
- send_event(FOCUS_GAINED, "", NULL);
- else
- send_event(FOCUS_LOST, "", NULL);
+ send_event (event->in?FOCUS_GAINED:FOCUS_LOST, NULL, NULL);
return FALSE;
}
@@ -562,9 +578,9 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) {
/* left click */
if(event->button == 1) {
if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE))
- send_event(FORM_ACTIVE, "button1", NULL);
+ send_event(FORM_ACTIVE, NULL, TYPE_NAME, "button1", NULL);
else if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
- send_event(ROOT_ACTIVE, "button1", NULL);
+ send_event(ROOT_ACTIVE, NULL, TYPE_NAME, "button1", NULL);
}
else if(event->button == 2 && !(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) {
sendev = TRUE;
@@ -577,8 +593,8 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) {
if(sendev) {
details = g_strdup_printf("Button%d", event->button);
- send_event(KEY_PRESS, details, NULL);
- g_free(details);
+ send_event(KEY_PRESS, NULL, TYPE_NAME, details, NULL);
+ g_free (details);
}
}
@@ -606,8 +622,8 @@ button_release_cb (GtkWidget* window, GdkEventButton* event) {
if(sendev) {
details = g_strdup_printf("Button%d", event->button);
- send_event(KEY_RELEASE, details, NULL);
- g_free(details);
+ send_event(KEY_RELEASE, NULL, TYPE_NAME, details, NULL);
+ g_free (details);
}
}
@@ -620,9 +636,11 @@ motion_notify_cb(GtkWidget* window, GdkEventMotion* event, gpointer user_data) {
(void) event;
(void) user_data;
- gchar *details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state);
- send_event(PTR_MOVE, details, NULL);
- g_free(details);
+ send_event (PTR_MOVE, NULL,
+ TYPE_FLOAT, event->x,
+ TYPE_FLOAT, event->y,
+ TYPE_INT, event->state,
+ NULL);
return FALSE;
}
@@ -641,23 +659,26 @@ navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNe
printf("Navigation requested -> %s\n", uri);
if (uzbl.behave.scheme_handler) {
- GString *s = g_string_new ("");
- g_string_printf(s, "'%s'", uri);
+ GString *result = g_string_new ("");
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(uzbl.behave.scheme_handler, a);
- run_handler(uzbl.behave.scheme_handler, s->str);
+ if(c) {
+ g_array_append_val(a, uri);
+ run_parsed_command(c, a, result);
+ }
+ g_array_free(a, TRUE);
- if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
- char *p = strchr(uzbl.comm.sync_stdout, '\n' );
+ if(result->len > 0) {
+ char *p = strchr(result->str, '\n' );
if ( p != NULL ) *p = '\0';
- if (!strcmp(uzbl.comm.sync_stdout, "USED")) {
+ if (!strcmp(result->str, "USED")) {
webkit_web_policy_decision_ignore(policy_decision);
decision_made = TRUE;
}
}
- if (uzbl.comm.sync_stdout)
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
- g_string_free(s, TRUE);
+ g_string_free(result, TRUE);
}
if (!decision_made)
webkit_web_policy_decision_use(policy_decision);
@@ -676,7 +697,7 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame,
(void) user_data;
if (uzbl.state.verbose)
- printf("New window requested -> %s \n", webkit_network_request_get_uri (request));
+ printf ("New window requested -> %s \n", webkit_network_request_get_uri (request));
/* This event function causes troubles with `target="_blank"` anchors.
* Either we:
@@ -690,9 +711,9 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame,
* We are leaving this uncommented as we would rather links open twice
* than not at all.
*/
- send_event(NEW_WINDOW, webkit_network_request_get_uri (request), NULL);
+ send_event (NEW_WINDOW, NULL, TYPE_STR, webkit_network_request_get_uri (request), NULL);
- webkit_web_policy_decision_ignore(policy_decision);
+ webkit_web_policy_decision_ignore (policy_decision);
return TRUE;
}
@@ -722,7 +743,7 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes
(void) response;
(void) user_data;
- send_event(REQUEST_STARTING, webkit_network_request_get_uri(request), NULL);
+ send_event (REQUEST_STARTING, NULL, TYPE_STR, webkit_network_request_get_uri(request), NULL);
}
void
@@ -737,7 +758,7 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) {
gtk_widget_destroy(GTK_WIDGET(web_view));
}
else
- send_event(NEW_WINDOW, uri, NULL);
+ send_event(NEW_WINDOW, NULL, TYPE_STR, uri, NULL);
}
@@ -778,9 +799,10 @@ download_progress_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_
const gchar *dest_uri = webkit_download_get_destination_uri(download);
const gchar *dest_path = dest_uri + strlen("file://");
- gchar *details = g_strdup_printf("%s %.2lf", dest_path, progress);
- send_event(DOWNLOAD_PROGRESS, details, NULL);
- g_free(details);
+ send_event(DOWNLOAD_PROGRESS, NULL,
+ TYPE_STR, dest_path,
+ TYPE_FLOAT, progress,
+ NULL);
}
void
@@ -800,7 +822,7 @@ download_status_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_da
{
const gchar *dest_uri = webkit_download_get_destination_uri(download);
const gchar *dest_path = dest_uri + strlen("file://");
- send_event(DOWNLOAD_COMPLETE, dest_path, NULL);
+ send_event(DOWNLOAD_COMPLETE, NULL, TYPE_STR, dest_path, NULL);
}
}
}
@@ -844,27 +866,35 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat
(this may be inaccurate, there's nothing we can do about that.) */
unsigned int total_size = webkit_download_get_total_size(download);
- gchar *ev = g_strdup_printf("'%s' '%s' '%s' %d", uri, suggested_filename,
- content_type, total_size);
- run_handler(uzbl.behave.download_handler, ev);
- g_free(ev);
-
- /* no response, cancel the download */
- if(!uzbl.comm.sync_stdout) {
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(uzbl.behave.download_handler, a);
+ if(!c) {
webkit_download_cancel(download);
+ g_array_free(a, TRUE);
return FALSE;
}
+ g_array_append_val(a, uri);
+ g_array_append_val(a, suggested_filename);
+ g_array_append_val(a, content_type);
+ gchar *total_size_s = g_strdup_printf("%d", total_size);
+ g_array_append_val(a, total_size_s);
+
+ GString *result = g_string_new ("");
+ run_parsed_command(c, a, result);
+
+ g_free(total_size_s);
+ g_array_free(a, TRUE);
+
/* no response, cancel the download */
- if(uzbl.comm.sync_stdout[0] == 0) {
+ if(result->len == 0) {
webkit_download_cancel(download);
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
return FALSE;
}
/* we got a response, it's the path we should download the file to */
- gchar *destination_path = uzbl.comm.sync_stdout;
- uzbl.comm.sync_stdout = NULL;
+ gchar *destination_path = result->str;
+ g_string_free(result, FALSE);
/* presumably people don't need newlines in their filenames. */
char *p = strchr(destination_path, '\n');
@@ -883,7 +913,7 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat
g_free(rel_path);
}
- send_event(DOWNLOAD_STARTED, destination_path, NULL);
+ send_event(DOWNLOAD_STARTED, NULL, TYPE_STR, destination_path, NULL);
/* convert absolute path to file:// URI */
gchar *destination_uri = g_strconcat("file://", destination_path, NULL);
@@ -904,12 +934,13 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w)
gdouble min = gtk_adjustment_get_lower(adjust);
gdouble max = gtk_adjustment_get_upper(adjust);
gdouble page = gtk_adjustment_get_page_size(adjust);
- gchar* details;
- details = g_strdup_printf("%g %g %g %g", value, min, max, page);
- send_event(SCROLL_VERT, details, NULL);
-
- g_free(details);
+ send_event (SCROLL_VERT, NULL,
+ TYPE_FLOAT, value,
+ TYPE_FLOAT, min,
+ TYPE_FLOAT, max,
+ TYPE_FLOAT, page,
+ NULL);
return (FALSE);
}
@@ -923,27 +954,40 @@ scroll_horiz_cb(GtkAdjustment *adjust, void *w)
gdouble min = gtk_adjustment_get_lower(adjust);
gdouble max = gtk_adjustment_get_upper(adjust);
gdouble page = gtk_adjustment_get_page_size(adjust);
- gchar* details;
- details = g_strdup_printf("%g %g %g %g", value, min, max, page);
-
- send_event(SCROLL_HORIZ, details, NULL);
- g_free(details);
+ send_event (SCROLL_HORIZ, NULL,
+ TYPE_FLOAT, value,
+ TYPE_FLOAT, min,
+ TYPE_FLOAT, max,
+ TYPE_FLOAT, page,
+ NULL);
return (FALSE);
}
void
-run_menu_command(GtkWidget *menu, const char *line) {
+run_menu_command(GtkWidget *menu, MenuItem *mi) {
(void) menu;
- parse_cmd_line(line, NULL);
+ if (mi->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
+ gchar* uri;
+ g_object_get(mi->hittest, "image-uri", &uri, NULL);
+ gchar* cmd = g_strdup_printf("%s %s", mi->cmd, uri);
+
+ parse_cmd_line(cmd, NULL);
+
+ g_free(cmd);
+ g_free(uri);
+ g_object_unref(mi->hittest);
+ }
+ else {
+ parse_cmd_line(mi->cmd, NULL);
+ }
}
void
populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
- (void) v;
(void) c;
GUI *g = &uzbl.gui;
GtkWidget *item;
@@ -958,11 +1002,19 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
if((context = get_click_context(NULL)) == -1)
return;
-
for(i=0; i < uzbl.gui.menu_items->len; i++) {
hit = 0;
mi = g_ptr_array_index(uzbl.gui.menu_items, i);
+ if (mi->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) {
+ GdkEventButton ev;
+ gint x, y;
+ gdk_window_get_pointer(gtk_widget_get_window(GTK_WIDGET(v)), &x, &y, NULL);
+ ev.x = x;
+ ev.y = y;
+ mi->hittest = webkit_web_view_get_hit_test_result(v, &ev);
+ }
+
if((mi->context > WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT) &&
(context & mi->context)) {
if(mi->issep) {
@@ -973,7 +1025,7 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
else {
item = gtk_menu_item_new_with_label(mi->name);
g_signal_connect(item, "activate",
- G_CALLBACK(run_menu_command), mi->cmd);
+ G_CALLBACK(run_menu_command), mi);
gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
@@ -991,7 +1043,7 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
else {
item = gtk_menu_item_new_with_label(mi->name);
g_signal_connect(item, "activate",
- G_CALLBACK(run_menu_command), mi->cmd);
+ G_CALLBACK(run_menu_command), mi);
gtk_menu_shell_append(GTK_MENU_SHELL(m), item);
gtk_widget_show(item);
}
@@ -999,12 +1051,4 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
}
}
-void
-cmd_set_cookie_handler() {
- if(uzbl.behave.cookie_handler[0] == 0) {
- g_free(uzbl.behave.cookie_handler);
- uzbl.behave.cookie_handler = NULL;
- }
-
- uzbl_cookie_jar_set_handler(uzbl.net.soup_cookie_jar, uzbl.behave.cookie_handler);
-}
+/* vi: set et ts=4: */
diff --git a/src/callbacks.h b/src/callbacks.h
index 899e959..d34b9fa 100644
--- a/src/callbacks.h
+++ b/src/callbacks.h
@@ -110,6 +110,9 @@ void
cmd_default_encoding();
void
+set_current_encoding();
+
+void
cmd_enforce_96dpi();
void
@@ -158,6 +161,9 @@ void
load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud);
void
+uri_change_cb (WebKitWebView *web_view, GParamSpec param_spec);
+
+void
selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud);
void
@@ -216,6 +222,3 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w);
gboolean
scroll_horiz_cb(GtkAdjustment *adjust, void *w);
-
-void
-cmd_set_cookie_handler();
diff --git a/src/cookie-jar.c b/src/cookie-jar.c
index 626e454..bc7d022 100644
--- a/src/cookie-jar.c
+++ b/src/cookie-jar.c
@@ -1,51 +1,20 @@
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <poll.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <string.h>
-#include <errno.h>
-
-#include <libsoup/soup-uri.h>
#include <libsoup/soup-cookie.h>
#include "cookie-jar.h"
#include "uzbl-core.h"
#include "events.h"
-static void
-uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data);
-
-G_DEFINE_TYPE_WITH_CODE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR,
- G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, uzbl_cookie_jar_session_feature_init))
+G_DEFINE_TYPE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR)
-static void request_started (SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg, SoupSocket *socket);
static void changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie);
-static void setup_handler(UzblCookieJar *jar);
-
-static void connect_cookie_socket(UzblCookieJar *jar);
-static void disconnect_cookie_socket(UzblCookieJar *jar);
-
-static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_len);
-
-static bool has_socket_handler(UzblCookieJar *jar) {
- return jar->socket_path != NULL;
-}
-
static void
soup_cookie_jar_socket_init(UzblCookieJar *jar) {
- jar->handler = NULL;
- jar->socket_path = NULL;
- jar->connection_fd = -1;
- jar->in_get_callback = 0;
jar->in_manual_add = 0;
}
static void
finalize(GObject *object) {
- disconnect_cookie_socket(UZBL_COOKIE_JAR(object));
G_OBJECT_CLASS(soup_cookie_jar_socket_parent_class)->finalize(object);
}
@@ -55,272 +24,37 @@ soup_cookie_jar_socket_class_init(UzblCookieJarClass *socket_class) {
SOUP_COOKIE_JAR_CLASS(socket_class)->changed = changed;
}
-/* override SoupCookieJar's request_started handler */
-static void
-uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data) {
- (void) user_data;
- iface->request_started = request_started;
-}
-
UzblCookieJar *uzbl_cookie_jar_new() {
return g_object_new(UZBL_TYPE_COOKIE_JAR, NULL);
}
-void
-uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar* handler) {
- jar->handler = handler;
- setup_handler(jar);
-}
-
-char *get_cookies(UzblCookieJar *jar, SoupURI *uri) {
- gchar *result, *path;
- GString *s = g_string_new ("GET");
-
- path = uri->path[0] ? uri->path : "/";
-
- if(has_socket_handler(jar)) {
- g_string_append_c(s, 0); /* null-terminate the GET */
- g_string_append_len(s, uri->scheme, strlen(uri->scheme)+1);
- g_string_append_len(s, uri->host, strlen(uri->host)+1 );
- g_string_append_len(s, path, strlen(path)+1 );
-
- result = do_socket_request(jar, s->str, s->len);
- /* try it again; older cookie daemons closed the connection after each request */
- if(result == NULL)
- result = do_socket_request(jar, s->str, s->len);
- } else {
- g_string_append_printf(s, " '%s' '%s' '%s'", uri->scheme, uri->host, uri->path);
-
- run_handler(jar->handler, s->str);
- result = g_strdup(uzbl.comm.sync_stdout);
- }
- g_string_free(s, TRUE);
- return result;
-}
-
-/* this is a duplicate of SoupCookieJar's request_started that uses our get_cookies instead */
-static void
-request_started(SoupSessionFeature *feature, SoupSession *session,
- SoupMessage *msg, SoupSocket *socket) {
- (void) session; (void) socket;
- gchar *cookies;
-
- UzblCookieJar *jar = UZBL_COOKIE_JAR (feature);
- SoupURI *uri = soup_message_get_uri(msg);
- gboolean add_to_internal_jar = false;
-
- if(jar->handler) {
- cookies = get_cookies(jar, uri);
- } else {
- /* no handler is set, fall back to the internal soup cookie jar */
- cookies = soup_cookie_jar_get_cookies(SOUP_COOKIE_JAR(jar), soup_message_get_uri (msg), TRUE);
- }
-
- if (cookies && cookies[0] != 0) {
- const gchar *next_cookie_start = cookies;
-
- if (add_to_internal_jar) {
- /* add the cookie data that we just obtained from the cookie handler
- to the cookie jar so that javascript has access to them.
- we set this flag so that we don't trigger the PUT handler. */
- jar->in_get_callback = true;
- do {
- SoupCookie *soup_cookie = soup_cookie_parse(next_cookie_start, uri);
- if(soup_cookie)
- soup_cookie_jar_add_cookie(SOUP_COOKIE_JAR(uzbl.net.soup_cookie_jar), soup_cookie);
- next_cookie_start = strchr(next_cookie_start, ';');
- } while(next_cookie_start++ != NULL);
- jar->in_get_callback = false;
- }
-
- soup_message_headers_replace (msg->request_headers, "Cookie", cookies);
- } else {
- soup_message_headers_remove (msg->request_headers, "Cookie");
- }
-
- if(cookies)
- g_free (cookies);
-}
-
static void
changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
- SoupCookie * cookie = new_cookie ? new_cookie : old_cookie;
+ SoupCookie *cookie = new_cookie ? new_cookie : old_cookie;
UzblCookieJar *uzbl_jar = UZBL_COOKIE_JAR(jar);
- /* when Uzbl begins an HTTP request, it GETs cookies from the handler
- and then adds them to the cookie jar so that javascript can access
- these cookies. this causes a 'changed' callback, which we don't want
- to do anything, so we just return.
-
- (if SoupCookieJar let us override soup_cookie_jar_get_cookies we
- wouldn't have to do this.) */
- if(uzbl_jar->in_get_callback)
- return;
-
- gchar *scheme = cookie->secure ? "https" : "http";
-
- /* send a ADD or DELETE -_COOKIE event depending on what have changed */
+ /* send a ADD or DELETE -_COOKIE event depending on what has changed. these
+ * events aren't sent when a cookie changes due to an add/delete_cookie
+ * command because otherwise a loop would occur when a cookie change is
+ * propagated to other uzbl instances using add/delete_cookie. */
if(!uzbl_jar->in_manual_add) {
+ gchar *scheme = cookie->secure ? "https" : "http";
+
gchar *expires = NULL;
if(cookie->expires)
expires = g_strdup_printf ("%d", soup_date_to_time_t (cookie->expires));
- gchar * eventstr = g_strdup_printf ("'%s' '%s' '%s' '%s' '%s' '%s'",
- cookie->domain, cookie->path, cookie->name, cookie->value, scheme, expires?expires:"");
- if(new_cookie)
- send_event(ADD_COOKIE, eventstr, NULL);
- else
- send_event(DELETE_COOKIE, eventstr, NULL);
- g_free(eventstr);
+ send_event (new_cookie ? ADD_COOKIE : DELETE_COOKIE, NULL,
+ TYPE_STR, cookie->domain,
+ TYPE_STR, cookie->path,
+ TYPE_STR, cookie->name,
+ TYPE_STR, cookie->value,
+ TYPE_STR, scheme,
+ TYPE_STR, expires ? expires : "",
+ NULL);
+
if(expires)
g_free(expires);
}
-
- /* the cookie daemon is only interested in new cookies and changed
- ones, it can take care of deleting expired cookies on its own. */
- if(!new_cookie)
- return;
-
- GString *s = g_string_new ("PUT");
-
- if(has_socket_handler(uzbl_jar)) {
- g_string_append_c(s, 0); /* null-terminate the PUT */
- g_string_append_len(s, scheme, strlen(scheme)+1);
- g_string_append_len(s, new_cookie->domain, strlen(new_cookie->domain)+1 );
- g_string_append_len(s, new_cookie->path, strlen(new_cookie->path)+1 );
- g_string_append_printf(s, "%s=%s", new_cookie->name, new_cookie->value);
-
- gchar *result = do_socket_request(uzbl_jar, s->str, s->len+1);
- /* try it again; older cookie daemons closed the connection after each request */
- if(!result)
- result = do_socket_request(uzbl_jar, s->str, s->len+1);
-
- g_free(result);
- } else {
- g_string_append_printf(s, " '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value);
-
- run_handler(uzbl_jar->handler, s->str);
- }
-
- g_string_free(s, TRUE);
-}
-
-static void
-setup_handler(UzblCookieJar *jar) {
- if(jar->handler && strncmp(jar->handler, "talk_to_socket", strlen("talk_to_socket")) == 0) {
- /* extract the socket path from the handler. */
- jar->socket_path = jar->handler + strlen("talk_to_socket");
- while(isspace(*jar->socket_path))
- jar->socket_path++;
- if(*jar->socket_path == 0)
- return; /* there was no path specified. */
- disconnect_cookie_socket(jar);
- connect_cookie_socket(jar);
- } else {
- jar->socket_path = NULL;
- }
-}
-
-static void
-connect_cookie_socket(UzblCookieJar *jar) {
- struct sockaddr_un sa;
- int fd;
-
- g_strlcpy(sa.sun_path, jar->socket_path, sizeof(sa.sun_path));
- sa.sun_family = AF_UNIX;
-
- /* create socket file descriptor and connect it to path */
- fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
- if(fd == -1) {
- g_printerr("connect_cookie_socket: creating socket failed (%s)\n", strerror(errno));
- return;
- }
-
- if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
- g_printerr("connect_cookie_socket: connect failed (%s)\n", strerror(errno));
- close(fd);
- return;
- }
-
- /* successful connection! */
- jar->connection_fd = fd;
-}
-
-static void
-disconnect_cookie_socket(UzblCookieJar *jar) {
- if(jar->connection_fd > 0) {
- close(jar->connection_fd);
- jar->connection_fd = -1;
- }
-}
-
-static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_length) {
- int len;
- ssize_t ret;
- struct pollfd pfd;
- gchar *result = NULL;
-
- if(jar->connection_fd < 0)
- connect_cookie_socket(jar); /* connection was lost, reconnect */
-
- /* write request */
- ret = write(jar->connection_fd, request, request_length);
- if(ret == -1) {
- g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
- disconnect_cookie_socket(jar);
- return NULL;
- }
-
- /* wait for a response, with a 500ms timeout */
- pfd.fd = jar->connection_fd;
- pfd.events = POLLIN;
- while(1) {
- ret = poll(&pfd, 1, 500);
- if(ret == 1) break;
- if(ret == 0) errno = ETIMEDOUT;
- if(errno == EINTR) continue;
- g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
- strerror(errno));
- if(errno != ETIMEDOUT)
- disconnect_cookie_socket(jar);
- return NULL;
- }
-
- /* get length of response */
- if(ioctl(jar->connection_fd, FIONREAD, &len) == -1) {
- g_printerr("talk_to_socket: cannot find daemon response length, "
- "ioctl failed (%s)\n", strerror(errno));
- disconnect_cookie_socket(jar);
- return NULL;
- }
-
- /* there was an empty response. */
- if(len == 0)
- return g_strdup("");
-
- /* there is a response, read it */
- result = g_malloc(len + 1);
- if(!result) {
- g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
- return NULL;
- }
- result[len] = 0; /* ensure result is null terminated */
-
- gchar *p = result;
- while(len > 0) {
- ret = read(jar->connection_fd, p, len);
- if(ret == -1) {
- g_printerr("talk_to_socket: failed to read from socket (%s)\n",
- strerror(errno));
- disconnect_cookie_socket(jar);
- g_free(result);
- return NULL;
- } else {
- len -= ret;
- p += ret;
- }
- }
-
- return result;
}
diff --git a/src/cookie-jar.h b/src/cookie-jar.h
index f3e3733..05f4a6f 100644
--- a/src/cookie-jar.h
+++ b/src/cookie-jar.h
@@ -10,12 +10,6 @@
typedef struct {
SoupCookieJar parent;
- const gchar *handler;
-
- const gchar *socket_path;
- int connection_fd;
-
- gboolean in_get_callback;
gboolean in_manual_add;
} UzblCookieJar;
@@ -25,10 +19,4 @@ typedef struct {
UzblCookieJar *uzbl_cookie_jar_new();
-void
-uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar *handler);
-
-char
-*get_cookies(UzblCookieJar *jar, SoupURI *uri);
-
#endif
diff --git a/src/events.c b/src/events.c
index 31a95d5..58dddfc 100644
--- a/src/events.c
+++ b/src/events.c
@@ -5,6 +5,7 @@
#include "uzbl-core.h"
#include "events.h"
+#include "util.h"
UzblCore uzbl;
@@ -91,7 +92,7 @@ send_event_sockets(GPtrArray *sockets, GString *msg) {
}
}
-static void
+void
replay_buffered_events() {
guint i = 0;
@@ -137,32 +138,66 @@ send_event_stdout(GString *msg) {
fflush(stdout);
}
+void
+vsend_event(int type, const gchar *custom_event, va_list vargs) {
+ GString *event_message = g_string_sized_new (512);
+
+ if (type >= LAST_EVENT)
+ return;
+ const gchar *event = custom_event ? custom_event : event_table[type];
+ char* str;
+
+ int next;
+ g_string_printf (event_message, "EVENT [%s] %s",
+ uzbl.state.instance_name, event);
+
+ while ((next = va_arg (vargs, int)) != 0) {
+ g_string_append_c(event_message, ' ');
+ switch(next) {
+ case TYPE_INT:
+ g_string_append_printf (event_message, "%d", va_arg (vargs, int));
+ break;
+ case TYPE_STR:
+ g_string_append_c (event_message, '\'');
+ append_escaped (event_message, va_arg (vargs, char*));
+ g_string_append_c (event_message, '\'');
+ break;
+ case TYPE_FORMATTEDSTR:
+ g_string_append (event_message, va_arg (vargs, char*));
+ break;
+ case TYPE_NAME:
+ str = va_arg (vargs, char*);
+ g_assert (valid_name (str));
+ g_string_append (event_message, str);
+ break;
+ case TYPE_FLOAT:
+ // ‘float’ is promoted to ‘double’ when passed through ‘...’
+ g_string_append_printf (event_message, "%.2f", va_arg (vargs, double));
+ break;
+ }
+ }
+
+ g_string_append_c(event_message, '\n');
+
+ if (uzbl.state.events_stdout)
+ send_event_stdout (event_message);
+ send_event_socket (event_message);
+
+ g_string_free (event_message, TRUE);
+}
+
/*
* build event string and send over the supported interfaces
* custom_event == NULL indicates an internal event
*/
void
-send_event(int type, const gchar *details, const gchar *custom_event) {
- GString *event_message = g_string_new("");
-
- /* check for custom events */
- if(custom_event) {
- g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, custom_event, details);
- }
- /* check wether we support the internal event */
- else if(type < LAST_EVENT) {
- g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, event_table[type], details);
- }
-
- if(event_message->str) {
- if(uzbl.state.events_stdout)
- send_event_stdout(event_message);
- send_event_socket(event_message);
-
- g_string_free(event_message, TRUE);
- }
+send_event(int type, const gchar *custom_event, ...) {
+ va_list vargs, vacopy;
+ va_start (vargs, custom_event);
+ va_copy (vacopy, vargs);
+ vsend_event (type, custom_event, vacopy);
+ va_end (vacopy);
+ va_end (vargs);
}
/* Transform gdk key events to our own events */
@@ -170,6 +205,7 @@ void
key_to_event(guint keyval, gint mode) {
gchar ucs[7];
gint ulen;
+ gchar *keyname;
guint32 ukval = gdk_keyval_to_unicode(keyval);
/* check for printable unicode char */
@@ -181,12 +217,14 @@ key_to_event(guint keyval, gint mode) {
ucs[ulen] = 0;
send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE,
- ucs, NULL);
+ NULL, TYPE_FORMATTEDSTR, ucs, NULL);
}
/* send keysym for non-printable chars */
- else {
+ else if((keyname = gdk_keyval_name(keyval))){
send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE,
- gdk_keyval_name(keyval), NULL);
+ NULL, TYPE_NAME, keyname , NULL);
}
}
+
+/* vi: set et ts=4: */
diff --git a/src/events.h b/src/events.h
index 3c7b933..bd519a6 100644
--- a/src/events.h
+++ b/src/events.h
@@ -3,6 +3,12 @@
** (c) 2009 by Robert Manea
*/
+#ifndef __EVENTS__
+#define __EVENTS__
+
+#include <glib.h>
+#include <stdarg.h>
+
/* Event system */
enum event_type {
LOAD_START, LOAD_COMMIT, LOAD_FINISH, LOAD_ERROR,
@@ -27,13 +33,15 @@ void
event_buffer_timeout(guint sec);
void
-send_event_socket(GString *msg);
+replay_buffered_events();
void
-send_event_stdout(GString *msg);
+vsend_event(int type, const gchar *custom_event, va_list vargs);
void
-send_event(int type, const gchar *details, const gchar *custom_event);
+send_event(int type, const gchar *custom_event, ...) G_GNUC_NULL_TERMINATED;
void
key_to_event(guint keyval, gint mode);
+
+#endif
diff --git a/src/inspector.c b/src/inspector.c
index de3dbcd..4c8c890 100644
--- a/src/inspector.c
+++ b/src/inspector.c
@@ -49,7 +49,7 @@ inspector_show_window_cb (WebKitWebInspector* inspector){
(void) inspector;
gtk_widget_show(uzbl.gui.inspector_window);
- send_event(WEBINSPECTOR, "open", NULL);
+ send_event(WEBINSPECTOR, NULL, TYPE_NAME, "open", NULL);
return TRUE;
}
@@ -57,7 +57,7 @@ inspector_show_window_cb (WebKitWebInspector* inspector){
gboolean
inspector_close_window_cb (WebKitWebInspector* inspector){
(void) inspector;
- send_event(WEBINSPECTOR, "close", NULL);
+ send_event(WEBINSPECTOR, NULL, TYPE_NAME, "close", NULL);
return TRUE;
}
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..3f8fa2f
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,346 @@
+#define _POSIX_SOURCE
+
+#include <stdio.h>
+
+#include "events.h"
+#include "io.h"
+#include "util.h"
+#include "uzbl-core.h"
+
+/*@null@*/ gchar*
+build_stream_name(int type, const gchar* dir) {
+ State *s = &uzbl.state;
+ gchar *str = NULL;
+
+ if (type == FIFO) {
+ str = g_strdup_printf
+ ("%s/uzbl_fifo_%s", dir, s->instance_name);
+ } else if (type == SOCKET) {
+ str = g_strdup_printf
+ ("%s/uzbl_socket_%s", dir, s->instance_name);
+ }
+ return str;
+}
+
+
+gboolean
+control_fifo(GIOChannel *gio, GIOCondition condition) {
+ if (uzbl.state.verbose)
+ printf("triggered\n");
+ gchar *ctl_line;
+ GIOStatus ret;
+ GError *err = NULL;
+
+ if (condition & G_IO_HUP)
+ g_error ("Fifo: Read end of pipe died!\n");
+
+ if(!gio)
+ g_error ("Fifo: GIOChannel broke\n");
+
+ ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_error ("Fifo: Error reading: %s\n", err->message);
+ g_error_free (err);
+ }
+
+ parse_cmd_line(ctl_line, NULL);
+ g_free(ctl_line);
+
+ return TRUE;
+}
+
+
+gboolean
+attach_fifo(gchar *path) {
+ GError *error = NULL;
+ /* 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. */
+ GIOChannel *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)) {
+ if (uzbl.state.verbose)
+ printf ("attach_fifo: created successfully as %s\n", path);
+ send_event(FIFO_SET, NULL, TYPE_STR, path, NULL);
+ uzbl.comm.fifo_path = path;
+ g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE);
+ return TRUE;
+ } else g_warning ("attach_fifo: could not add watch on %s\n", path);
+ } else g_warning ("attach_fifo: can't open: %s\n", error->message);
+
+ if (error) g_error_free (error);
+ return FALSE;
+}
+
+
+/*@null@*/ gchar*
+init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
+ if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
+ if (unlink(uzbl.comm.fifo_path) == -1)
+ 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;
+ }
+
+ gchar *path = build_stream_name(FIFO, dir);
+
+ if (!file_exists(path)) {
+ if (mkfifo (path, 0666) == 0 && attach_fifo(path)) {
+ return dir;
+ } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
+ } else {
+ /* the fifo exists. but is anybody home? */
+ int fd = open(path, O_WRONLY|O_NONBLOCK);
+ if(fd < 0) {
+ /* some error occurred, presumably nobody's on the read end.
+ * we can attach ourselves to it. */
+ if(attach_fifo(path))
+ return dir;
+ else
+ g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno));
+ } else {
+ /* somebody's there, we can't use that fifo. */
+ close(fd);
+ /* whatever, this instance can live without a fifo. */
+ g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path);
+ }
+ }
+
+ /* if we got this far, there was an error; cleanup */
+ g_free(dir);
+ g_free(path);
+ return NULL;
+}
+
+
+gboolean
+control_stdin(GIOChannel *gio, GIOCondition condition) {
+ (void) condition;
+ gchar *ctl_line = NULL;
+ GIOStatus ret;
+
+ ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
+ if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
+ return FALSE;
+
+ GString *result = g_string_new("");
+
+ parse_cmd_line(ctl_line, result);
+ g_free(ctl_line);
+
+ puts(result->str);
+ g_string_free(result, TRUE);
+
+ return TRUE;
+}
+
+void
+create_stdin() {
+ GIOChannel *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 ("create_stdin: could not add watch\n");
+ } else if (uzbl.state.verbose) {
+ printf ("create_stdin: watch added successfully\n");
+ }
+ } else {
+ g_error ("create_stdin: error while opening stdin\n");
+ }
+}
+
+gboolean
+remove_socket_from_array(GIOChannel *chan) {
+ gboolean ret = 0;
+
+ ret = g_ptr_array_remove_fast(uzbl.comm.connect_chan, chan);
+ if(!ret)
+ ret = g_ptr_array_remove_fast(uzbl.comm.client_chan, chan);
+
+ if(ret)
+ g_io_channel_unref (chan);
+ return ret;
+}
+
+gboolean
+control_socket(GIOChannel *chan) {
+ struct sockaddr_un remote;
+ unsigned int t = sizeof(remote);
+ GIOChannel *iochan;
+ int clientsock;
+
+ clientsock = accept (g_io_channel_unix_get_fd(chan),
+ (struct sockaddr *) &remote, &t);
+
+ if(!uzbl.comm.client_chan)
+ uzbl.comm.client_chan = g_ptr_array_new();
+
+ if ((iochan = g_io_channel_unix_new(clientsock))) {
+ g_io_channel_set_encoding(iochan, NULL, NULL);
+ g_io_add_watch(iochan, G_IO_IN|G_IO_HUP,
+ (GIOFunc) control_client_socket, iochan);
+ g_ptr_array_add(uzbl.comm.client_chan, (gpointer)iochan);
+ }
+ return TRUE;
+}
+
+
+void
+init_connect_socket() {
+ int sockfd, replay = 0;
+ struct sockaddr_un local;
+ GIOChannel *chan;
+ gchar **name = NULL;
+
+ if(!uzbl.comm.connect_chan)
+ uzbl.comm.connect_chan = g_ptr_array_new();
+
+ name = uzbl.state.connect_socket_names;
+
+ while(name && *name) {
+ sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
+ local.sun_family = AF_UNIX;
+ strcpy (local.sun_path, *name);
+
+ if(!connect(sockfd, (struct sockaddr *) &local, sizeof(local))) {
+ if ((chan = g_io_channel_unix_new(sockfd))) {
+ g_io_channel_set_encoding(chan, NULL, NULL);
+ g_io_add_watch(chan, G_IO_IN|G_IO_HUP,
+ (GIOFunc) control_client_socket, chan);
+ g_ptr_array_add(uzbl.comm.connect_chan, (gpointer)chan);
+ replay++;
+ }
+ }
+ else
+ g_warning("Error connecting to socket: %s\n", *name);
+ name++;
+ }
+
+ /* replay buffered events */
+ if(replay && uzbl.state.event_buffer)
+ replay_buffered_events();
+}
+
+
+gboolean
+control_client_socket(GIOChannel *clientchan) {
+ char *ctl_line;
+ GString *result = g_string_new("");
+ GError *error = NULL;
+ GIOStatus ret;
+ gsize len;
+
+ ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_warning ("Error reading: %s", error->message);
+ g_clear_error (&error);
+ ret = g_io_channel_shutdown (clientchan, TRUE, &error);
+ remove_socket_from_array (clientchan);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_warning ("Error closing: %s", error->message);
+ g_clear_error (&error);
+ }
+ return FALSE;
+ } else if (ret == G_IO_STATUS_EOF) {
+ /* shutdown and remove channel watch from main loop */
+ ret = g_io_channel_shutdown (clientchan, TRUE, &error);
+ remove_socket_from_array (clientchan);
+ if (ret == G_IO_STATUS_ERROR) {
+ g_warning ("Error closing: %s", error->message);
+ g_clear_error (&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_clear_error (&error);
+ }
+ if (g_io_channel_flush(clientchan, &error) == G_IO_STATUS_ERROR) {
+ g_warning ("Error flushing: %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ g_string_free(result, TRUE);
+ g_free(ctl_line);
+ return TRUE;
+}
+
+
+gboolean
+attach_socket(gchar *path, struct sockaddr_un *local) {
+ GIOChannel *chan = NULL;
+ int sock = socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) {
+ if (uzbl.state.verbose)
+ printf ("init_socket: opened in %s\n", path);
+
+ if(listen (sock, 5) < 0)
+ g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno));
+
+ 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;
+ send_event(SOCKET_SET, NULL, TYPE_STR, path, NULL);
+ g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE);
+ return TRUE;
+ }
+ } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno));
+
+ return FALSE;
+}
+
+
+/*@null@*/ gchar*
+init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
+ if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
+ if (unlink(uzbl.comm.socket_path) == -1)
+ 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;
+ }
+
+ struct sockaddr_un local;
+ gchar *path = build_stream_name(SOCKET, dir);
+
+ local.sun_family = AF_UNIX;
+ strcpy (local.sun_path, path);
+
+ if(!file_exists(path) && attach_socket(path, &local)) {
+ /* it's free for the taking. */
+ return dir;
+ } else {
+ /* see if anybody's listening on the socket path we want. */
+ int sock = socket (AF_UNIX, SOCK_STREAM, 0);
+ if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ /* some error occurred, presumably nobody's listening.
+ * we can attach ourselves to it. */
+ unlink(path);
+ if(attach_socket(path, &local))
+ return dir;
+ else
+ g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno));
+ } else {
+ /* somebody's there, we can't use that socket path. */
+ close(sock);
+ /* whatever, this instance can live without a socket. */
+ g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path);
+ }
+ }
+
+ /* if we got this far, there was an error; cleanup */
+ g_free(path);
+ g_free(dir);
+ return NULL;
+}
diff --git a/src/io.h b/src/io.h
new file mode 100644
index 0000000..a6ea0a1
--- /dev/null
+++ b/src/io.h
@@ -0,0 +1,23 @@
+#ifndef __IO__
+#define __IO__
+
+#include <glib/gstdio.h>
+
+/*@null@*/ gchar*
+build_stream_name(int type, const gchar *dir);
+
+gboolean control_fifo(GIOChannel *gio, GIOCondition condition);
+
+/*@null@*/ gchar*
+init_fifo(gchar *dir);
+
+gboolean control_stdin(GIOChannel *gio, GIOCondition condition);
+void create_stdin();
+
+/*@null@*/ gchar*
+init_socket(gchar *dir);
+
+gboolean control_socket(GIOChannel *chan);
+gboolean control_client_socket(GIOChannel *chan);
+
+#endif
diff --git a/src/menu.c b/src/menu.c
new file mode 100644
index 0000000..451b35a
--- /dev/null
+++ b/src/menu.c
@@ -0,0 +1,192 @@
+#include "menu.h"
+#include "util.h"
+#include "uzbl-core.h"
+
+void
+add_to_menu(GArray *argv, guint context) {
+ GUI *g = &uzbl.gui;
+ MenuItem *m;
+ gchar *item_cmd = NULL;
+
+ if(!argv_idx(argv, 0))
+ return;
+
+ gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
+ if(!g->menu_items)
+ g->menu_items = g_ptr_array_new();
+
+ if(split[1])
+ item_cmd = split[1];
+
+ if(split[0]) {
+ m = malloc(sizeof(MenuItem));
+ m->name = g_strdup(split[0]);
+ m->cmd = g_strdup(item_cmd?item_cmd:"");
+ m->context = context;
+ m->issep = FALSE;
+ g_ptr_array_add(g->menu_items, m);
+ }
+
+ g_strfreev(split);
+}
+
+
+void
+menu_add(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
+
+}
+
+
+void
+menu_add_link(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
+}
+
+
+void
+menu_add_image(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
+}
+
+
+void
+menu_add_edit(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
+}
+
+
+void
+add_separator_to_menu(GArray *argv, guint context) {
+ GUI *g = &uzbl.gui;
+ MenuItem *m;
+ gchar *sep_name;
+
+ if(!g->menu_items)
+ g->menu_items = g_ptr_array_new();
+
+ if(!argv_idx(argv, 0))
+ return;
+ else
+ sep_name = argv_idx(argv, 0);
+
+ m = malloc(sizeof(MenuItem));
+ m->name = g_strdup(sep_name);
+ m->cmd = NULL;
+ m->context = context;
+ m->issep = TRUE;
+ g_ptr_array_add(g->menu_items, m);
+}
+
+
+void
+menu_add_separator(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
+}
+
+
+void
+menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
+}
+
+
+void
+menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
+}
+
+
+void
+menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
+}
+
+
+void
+remove_from_menu(GArray *argv, guint context) {
+ GUI *g = &uzbl.gui;
+ MenuItem *mi;
+ gchar *name = NULL;
+ guint i=0;
+
+ if(!g->menu_items)
+ return;
+
+ if(!argv_idx(argv, 0))
+ return;
+ else
+ name = argv_idx(argv, 0);
+
+ for(i=0; i < g->menu_items->len; i++) {
+ mi = g_ptr_array_index(g->menu_items, i);
+
+ if((context == mi->context) && !strcmp(name, mi->name)) {
+ g_free(mi->name);
+ g_free(mi->cmd);
+ g_free(mi);
+ g_ptr_array_remove_index(g->menu_items, i);
+ }
+ }
+}
+
+
+void
+menu_remove(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
+}
+
+
+void
+menu_remove_link(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
+}
+
+
+void
+menu_remove_image(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
+}
+
+
+void
+menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
+ (void) result;
+
+ remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
+}
+
diff --git a/src/menu.h b/src/menu.h
new file mode 100644
index 0000000..8b89f2f
--- /dev/null
+++ b/src/menu.h
@@ -0,0 +1,18 @@
+#ifndef __MENU__
+#define __MENU__
+
+#include <webkit/webkit.h>
+
+void menu_add(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_link(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_image(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_edit(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_separator(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result);
+void menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result);
+void menu_remove(WebKitWebView *page, GArray *argv, GString *result);
+void menu_remove_link(WebKitWebView *page, GArray *argv, GString *result);
+void menu_remove_image(WebKitWebView *page, GArray *argv, GString *result);
+void menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result);
+#endif
diff --git a/src/util.c b/src/util.c
index c9c728e..8f6c349 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,8 +6,9 @@
#include "util.h"
-const XDG_Var XDG[] =
-{
+gchar* find_existing_file2(gchar *, const gchar *);
+
+const XDG_Var XDG[] = {
{ "XDG_CONFIG_HOME", "~/.config" },
{ "XDG_DATA_HOME", "~/.local/share" },
{ "XDG_CACHE_HOME", "~/.cache" },
@@ -17,56 +18,41 @@ const XDG_Var XDG[] =
/*@null@*/ gchar*
get_xdg_var (XDG_Var xdg) {
- const gchar* actual_value = getenv (xdg.environmental);
- const gchar* home = getenv ("HOME");
- gchar* return_value;
-
- if (! actual_value || strcmp (actual_value, "") == 0) {
- if (xdg.default_value) {
- return_value = str_replace ("~", home, xdg.default_value);
- } else {
- return_value = NULL;
- }
- } else {
- return_value = str_replace("~", home, actual_value);
- }
+ const gchar *actual_value = getenv(xdg.environmental);
+ const gchar *home = getenv("HOME");
- return return_value;
+ if (!actual_value || !actual_value[0])
+ actual_value = xdg.default_value;
+
+ if (!actual_value)
+ return NULL;
+
+ return str_replace("~", home, actual_value);
}
/*@null@*/ gchar*
-find_xdg_file (int xdg_type, const char* filename) {
+find_xdg_file (int xdg_type, const char* basename) {
/* xdg_type = 0 => config
xdg_type = 1 => data
- xdg_type = 2 => cache*/
+ xdg_type = 2 => cache */
- gchar* xdgv = get_xdg_var (XDG[xdg_type]);
- gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
+ gchar *xdgv = get_xdg_var(XDG[xdg_type]);
+ gchar *path = g_strconcat (xdgv, basename, NULL);
g_free (xdgv);
- gchar* temporary_string;
- char* saveptr;
- char* buf;
-
- if (! file_exists (temporary_file) && xdg_type != 2) {
- buf = get_xdg_var (XDG[3 + xdg_type]);
- temporary_string = (char *) strtok_r (buf, ":", &saveptr);
- g_free(buf);
+ if (file_exists(path))
+ return path;
- while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
- g_free (temporary_file);
- temporary_file = g_strconcat (temporary_string, filename, NULL);
- }
- }
+ if (xdg_type == 2)
+ return NULL;
- //g_free (temporary_string); - segfaults.
+ /* the file doesn't exist in the expected directory.
+ * check if it exists in one of the system-wide directories. */
+ char *system_dirs = get_xdg_var(XDG[3 + xdg_type]);
+ path = find_existing_file2(system_dirs, basename);
+ g_free(system_dirs);
- if (file_exists (temporary_file)) {
- return temporary_file;
- } else {
- g_free(temporary_file);
- return NULL;
- }
+ return path;
}
gboolean
@@ -96,15 +82,99 @@ for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *
GIOChannel *chan = g_io_channel_new_file(path, "r", NULL);
- if (chan) {
- while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
- callback(line, user_data);
- g_free(line);
- }
- g_io_channel_unref (chan);
+ if (!chan)
+ return FALSE;
- return TRUE;
+ while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
+ callback(line, user_data);
+ g_free(line);
}
- return FALSE;
+ g_io_channel_unref (chan);
+
+ return TRUE;
+}
+
+/* This function searches the directories in the : separated ($PATH style)
+ * string 'dirs' for a file named 'basename'. It returns the path of the first
+ * file found, or NULL if none could be found.
+ * NOTE: this function modifies the 'dirs' argument. */
+gchar*
+find_existing_file2(gchar *dirs, const gchar *basename) {
+ char *saveptr = NULL;
+
+ /* iterate through the : separated elements until we find our file. */
+ char *tok = strtok_r(dirs, ":", &saveptr);
+ char *path = g_strconcat (tok, "/", basename, NULL);
+
+ while (!file_exists(path)) {
+ g_free(path);
+
+ tok = strtok_r(NULL, ":", &saveptr);
+ if (!tok)
+ return NULL; /* we've hit the end of the string */
+
+ path = g_strconcat (tok, "/", basename, NULL);
+ }
+
+ return path;
+}
+
+/* search a PATH style string for an existing file+path combination.
+ * everything after the last ':' is assumed to be the name of the file.
+ * e.g. "/tmp:/home:a/file" will look for /tmp/a/file and /home/a/file.
+ *
+ * if there are no :s then the entire thing is taken to be the path. */
+gchar*
+find_existing_file(const gchar* path_list) {
+ if(!path_list)
+ return NULL;
+
+ char *path_list_dup = g_strdup(path_list);
+
+ char *basename = strrchr(path_list_dup, ':');
+ if(!basename)
+ return path_list_dup;
+
+ basename[0] = '\0';
+ basename++;
+
+ char *result = find_existing_file2(path_list_dup, basename);
+ g_free(path_list_dup);
+ return result;
+}
+
+gchar*
+argv_idx(const GArray *a, const guint idx) {
+ return g_array_index(a, gchar*, idx);
+}
+
+GString *
+append_escaped (GString *dest, const gchar *src) {
+ g_assert(dest);
+ g_assert(src);
+
+ // Hint that we are going to append another string.
+ int oldlen = dest->len;
+ g_string_set_size (dest, dest->len + strlen(src) * 2);
+ g_string_truncate (dest, oldlen);
+
+ // Append src char by char with baddies escaped
+ for (const gchar *p = src; *p; p++) {
+ switch (*p) {
+ case '\\':
+ g_string_append (dest, "\\\\");
+ break;
+ case '\'':
+ g_string_append (dest, "\\'");
+ break;
+ case '\n':
+ g_string_append (dest, "\\n");
+ break;
+ default:
+ g_string_append_c (dest, *p);
+ break;
+ }
+ }
+ return dest;
}
diff --git a/src/util.h b/src/util.h
index f03f13e..75a614b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,18 +1,19 @@
#include <glib.h>
+#include <stdio.h>
typedef struct {
gchar* environmental;
gchar* default_value;
} XDG_Var;
-gchar* get_xdg_var (XDG_Var xdg);
-
-gchar* find_xdg_file (int xdg_type, const char* filename);
-
-gboolean file_exists(const char* filename);
-
-char *
-str_replace (const char* search, const char* replace, const char* string);
-
-gboolean
-for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data);
+gchar* get_xdg_var(XDG_Var xdg);
+gchar* find_xdg_file(int xdg_type, const char* filename);
+gboolean file_exists(const char* filename);
+char* str_replace(const char* search, const char* replace, const char* string);
+gboolean for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data);
+gchar* find_existing_file(const gchar*);
+gchar* argv_idx(const GArray*, const guint);
+/**
+ * appends `src' to `dest' with backslash, single-quotes and newlines in
+ * `src' escaped */
+GString * append_escaped (GString *dest, const gchar *src);
diff --git a/src/uzbl-browser b/src/uzbl-browser
index faa2829..81645ca 100755
--- a/src/uzbl-browser
+++ b/src/uzbl-browser
@@ -64,13 +64,6 @@ then
export UZBL_UTIL_DIR
fi
-# uzbl-cookie-manager will exit if another instance is already running.
-# we could also check if its pid file exists to avoid having to spawn it.
-#if [ ! -f "$XDG_CACHE_HOME"/uzbl/cookie_daemon_socket.pid ]
-#then
-# ${UZBL_COOKIE_DAEMON:-uzbl-cookie-manager}
-#fi
-
# uzbl-event-manager will exit if one is already running.
# we could also check if its pid file exists to avoid having to spawn it.
DAEMON_SOCKET="$XDG_CACHE_HOME"/uzbl/event_daemon
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index 877dbda..c879602 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -35,13 +35,14 @@
#include "inspector.h"
#include "config.h"
#include "util.h"
+#include "menu.h"
+#include "io.h"
UzblCore uzbl;
/* commandline arguments (set initial values for the state variables) */
const
-GOptionEntry entries[] =
-{
+GOptionEntry entries[] = {
{ "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
"Uri to load at startup (equivalent to 'uzbl <uri>' or 'set uri = URI' after uzbl has launched)", "URI" },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
@@ -91,7 +92,6 @@ const struct var_name_to_ptr_t {
{ "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)},
{ "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
{ "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)},
- { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)},
{ "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)},
{ "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)},
{ "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
@@ -131,6 +131,7 @@ const struct var_name_to_ptr_t {
{ "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
{ "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
{ "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
+ { "current_encoding", PTR_V_STR(uzbl.behave.current_encoding, 1, set_current_encoding)},
{ "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
{ "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
{ "scrollbars_visible", PTR_V_INT(uzbl.gui.scrollbars_visible, 1, cmd_scrollbars_visibility)},
@@ -145,6 +146,7 @@ const struct var_name_to_ptr_t {
{ "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
{ "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
{ "PID", PTR_C_STR(uzbl.info.pid_str, NULL)},
+ { "_", PTR_C_STR(uzbl.state.last_result, NULL)},
{ NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
};
@@ -164,43 +166,39 @@ create_var_to_name_hash() {
/* --- UTILITY FUNCTIONS --- */
-enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
+enum exp_type {
+ EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE
+};
+
enum exp_type
get_exp_type(const gchar *s) {
- /* variables */
- if(*(s+1) == '(')
- return EXP_EXPR;
- else if(*(s+1) == '{')
- return EXP_BRACED_VAR;
- else if(*(s+1) == '<')
- return EXP_JS;
- else if(*(s+1) == '[')
- return EXP_ESCAPE;
- else
- return EXP_SIMPLE_VAR;
-
- /*@notreached@*/
-return EXP_ERR;
+ switch(*(s+1)) {
+ case '(': return EXP_EXPR;
+ case '{': return EXP_BRACED_VAR;
+ case '<': return EXP_JS;
+ case '[': return EXP_ESCAPE;
+ default: return EXP_SIMPLE_VAR;
+ }
}
/*
* recurse == 1: don't expand '@(command)@'
* recurse == 2: don't expand '@<java script>@'
*/
-gchar *
-expand(const char *s, guint recurse) {
- uzbl_cmdprop *c;
+gchar*
+expand(const char* s, guint recurse) {
+ uzbl_cmdprop* c;
enum exp_type etype;
- char *end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
- char *ret = NULL;
- char *vend = NULL;
- GError *err = NULL;
- gchar *cmd_stdout = NULL;
- gchar *mycmd = NULL;
- GString *buf = g_string_new("");
- GString *js_ret = g_string_new("");
-
- while(s && *s) {
+ char* end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
+ char* ret = NULL;
+ char* vend = NULL;
+ GError* err = NULL;
+ gchar* cmd_stdout = NULL;
+ gchar* mycmd = NULL;
+ GString* buf = g_string_new("");
+ GString* js_ret = g_string_new("");
+
+ while (s && *s) {
switch(*s) {
case '\\':
g_string_append_c(buf, *++s);
@@ -351,81 +349,15 @@ expand(const char *s, guint recurse) {
return g_string_free(buf, FALSE);
}
-char *
-itos(int val) {
- char tmp[20];
-
- snprintf(tmp, sizeof(tmp), "%i", val);
- return g_strdup(tmp);
-}
-
-gchar*
-strfree(gchar *str) {
- g_free(str);
- return NULL;
-}
-
-gchar*
-argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
-
-/* search a PATH style string for an existing file+path combination */
-gchar*
-find_existing_file(gchar* path_list) {
- int i=0;
- int cnt;
- gchar **split;
- gchar *tmp = NULL;
- gchar *executable;
-
- if(!path_list)
- return NULL;
-
- split = g_strsplit(path_list, ":", 0);
- while(split[i])
- i++;
-
- if(i<=1) {
- tmp = g_strdup(split[0]);
- g_strfreev(split);
- return tmp;
- }
- else
- cnt = i-1;
-
- i=0;
- tmp = g_strdup(split[cnt]);
- g_strstrip(tmp);
- if(tmp[0] == '/')
- executable = g_strdup_printf("%s", tmp+1);
- else
- executable = g_strdup(tmp);
- g_free(tmp);
-
- while(i<cnt) {
- tmp = g_strconcat(g_strstrip(split[i]), "/", executable, NULL);
- if(g_file_test(tmp, G_FILE_TEST_EXISTS)) {
- g_strfreev(split);
- return tmp;
- }
- else
- g_free(tmp);
- i++;
- }
-
- g_free(executable);
- g_strfreev(split);
- return NULL;
-}
-
void
clean_up(void) {
- if(uzbl.info.pid_str) {
- send_event(INSTANCE_EXIT, uzbl.info.pid_str, NULL);
+ if (uzbl.info.pid_str) {
+ send_event (INSTANCE_EXIT, NULL, TYPE_INT, getpid(), NULL);
g_free(uzbl.info.pid_str);
uzbl.info.pid_str = NULL;
}
- if(uzbl.state.executable_path) {
+ if (uzbl.state.executable_path) {
g_free(uzbl.state.executable_path);
uzbl.state.executable_path = NULL;
}
@@ -435,7 +367,7 @@ clean_up(void) {
uzbl.behave.commands = NULL;
}
- if(uzbl.state.event_buffer) {
+ if (uzbl.state.event_buffer) {
g_ptr_array_free(uzbl.state.event_buffer, TRUE);
uzbl.state.event_buffer = NULL;
}
@@ -495,7 +427,7 @@ empty_event_buffer(int s) {
/* scroll a bar in a given direction */
void
-scroll (GtkAdjustment* bar, gchar *amount_str) {
+scroll(GtkAdjustment* bar, gchar *amount_str) {
gchar *end;
gdouble max_value;
@@ -571,79 +503,80 @@ VIEWFUNC(go_forward)
#undef VIEWFUNC
/* -- command to callback/function map for things we cannot attach to any signals */
-struct {const char *key; CommandInfo value;} cmdlist[] =
+CommandInfo cmdlist[] =
{ /* key function no_split */
- { "back", {view_go_back, 0} },
- { "forward", {view_go_forward, 0} },
- { "scroll", {scroll_cmd, 0} },
- { "reload", {view_reload, 0}, },
- { "reload_ign_cache", {view_reload_bypass_cache, 0} },
- { "stop", {view_stop_loading, 0}, },
- { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
- { "zoom_out", {view_zoom_out, 0}, },
- { "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_async, 0} },
- { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
- { "sync_spawn_exec", {spawn_sync_exec, 0} }, // needed for load_cookies.sh :(
- { "sh", {spawn_sh_async, 0} },
- { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
- { "exit", {close_uzbl, 0} },
- { "search", {search_forward_text, TRUE} },
- { "search_reverse", {search_reverse_text, TRUE} },
- { "search_clear", {search_clear, TRUE} },
- { "dehilight", {dehilight, 0} },
- { "set", {set_var, TRUE} },
- { "dump_config", {act_dump_config, 0} },
- { "dump_config_as_events", {act_dump_config_as_events, 0} },
- { "chain", {chain, 0} },
- { "print", {print, TRUE} },
- { "event", {event, TRUE} },
- { "request", {event, TRUE} },
- { "menu_add", {menu_add, TRUE} },
- { "menu_link_add", {menu_add_link, TRUE} },
- { "menu_image_add", {menu_add_image, TRUE} },
- { "menu_editable_add", {menu_add_edit, TRUE} },
- { "menu_separator", {menu_add_separator, TRUE} },
- { "menu_link_separator", {menu_add_separator_link, TRUE} },
- { "menu_image_separator", {menu_add_separator_image, TRUE}},
- { "menu_editable_separator", {menu_add_separator_edit, TRUE} },
- { "menu_remove", {menu_remove, TRUE} },
- { "menu_link_remove", {menu_remove_link, TRUE} },
- { "menu_image_remove", {menu_remove_image, TRUE} },
- { "menu_editable_remove", {menu_remove_edit, TRUE} },
- { "hardcopy", {hardcopy, TRUE} },
- { "include", {include, TRUE} },
- { "show_inspector", {show_inspector, 0} },
- { "add_cookie", {add_cookie, 0} },
- { "delete_cookie", {delete_cookie, 0} }
+ { "back", view_go_back, 0 },
+ { "forward", view_go_forward, 0 },
+ { "scroll", scroll_cmd, 0 },
+ { "reload", view_reload, 0 },
+ { "reload_ign_cache", view_reload_bypass_cache, 0 },
+ { "stop", view_stop_loading, 0 },
+ { "zoom_in", view_zoom_in, 0 }, //Can crash (when max zoom reached?).
+ { "zoom_out", view_zoom_out, 0 },
+ { "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_async, 0 },
+ { "sync_spawn", spawn_sync, 0 },
+ { "sync_spawn_exec", spawn_sync_exec, 0 }, // needed for load_cookies.sh :(
+ { "sh", spawn_sh_async, 0 },
+ { "sync_sh", spawn_sh_sync, 0 },
+ { "exit", close_uzbl, 0 },
+ { "search", search_forward_text, TRUE },
+ { "search_reverse", search_reverse_text, TRUE },
+ { "search_clear", search_clear, TRUE },
+ { "dehilight", dehilight, 0 },
+ { "set", set_var, TRUE },
+ { "dump_config", act_dump_config, 0 },
+ { "dump_config_as_events", act_dump_config_as_events, 0 },
+ { "chain", chain, 0 },
+ { "print", print, TRUE },
+ { "event", event, TRUE },
+ { "request", event, TRUE },
+ { "menu_add", menu_add, TRUE },
+ { "menu_link_add", menu_add_link, TRUE },
+ { "menu_image_add", menu_add_image, TRUE },
+ { "menu_editable_add", menu_add_edit, TRUE },
+ { "menu_separator", menu_add_separator, TRUE },
+ { "menu_link_separator", menu_add_separator_link, TRUE },
+ { "menu_image_separator", menu_add_separator_image, TRUE },
+ { "menu_editable_separator", menu_add_separator_edit, TRUE },
+ { "menu_remove", menu_remove, TRUE },
+ { "menu_link_remove", menu_remove_link, TRUE },
+ { "menu_image_remove", menu_remove_image, TRUE },
+ { "menu_editable_remove", menu_remove_edit, TRUE },
+ { "hardcopy", hardcopy, TRUE },
+ { "include", include, TRUE },
+ { "show_inspector", show_inspector, 0 },
+ { "add_cookie", add_cookie, 0 },
+ { "delete_cookie", delete_cookie, 0 },
+ { "clear_cookies", clear_cookies, 0 }
};
void
-commands_hash(void)
-{
+commands_hash(void) {
unsigned int i;
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, (gpointer) cmdlist[i].key, &cmdlist[i].value);
+ g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i]);
}
+
void
builtins() {
- unsigned int i,
- len = LENGTH(cmdlist);
- GString *command_list = g_string_new("");
+ unsigned int i;
+ unsigned int len = LENGTH(cmdlist);
+ GString* command_list = g_string_new("");
for (i = 0; i < len; i++) {
g_string_append(command_list, cmdlist[i].key);
g_string_append_c(command_list, ' ');
}
- send_event(BUILTINS, command_list->str, NULL);
+ send_event(BUILTINS, NULL, TYPE_STR, command_list->str, NULL);
g_string_free(command_list, TRUE);
}
@@ -664,178 +597,6 @@ set_var(WebKitWebView *page, GArray *argv, GString *result) {
g_strfreev(split);
}
-void
-add_to_menu(GArray *argv, guint context) {
- GUI *g = &uzbl.gui;
- MenuItem *m;
- gchar *item_cmd = NULL;
-
- if(!argv_idx(argv, 0))
- return;
-
- gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
- if(!g->menu_items)
- g->menu_items = g_ptr_array_new();
-
- if(split[1])
- item_cmd = split[1];
-
- if(split[0]) {
- m = malloc(sizeof(MenuItem));
- m->name = g_strdup(split[0]);
- m->cmd = g_strdup(item_cmd?item_cmd:"");
- m->context = context;
- m->issep = FALSE;
- g_ptr_array_add(g->menu_items, m);
- }
-
- g_strfreev(split);
-}
-
-void
-menu_add(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
-
-}
-
-void
-menu_add_link(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
-}
-
-void
-menu_add_image(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
-}
-
-void
-menu_add_edit(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
-}
-
-void
-add_separator_to_menu(GArray *argv, guint context) {
- GUI *g = &uzbl.gui;
- MenuItem *m;
- gchar *sep_name;
-
- if(!g->menu_items)
- g->menu_items = g_ptr_array_new();
-
- if(!argv_idx(argv, 0))
- return;
- else
- sep_name = argv_idx(argv, 0);
-
- m = malloc(sizeof(MenuItem));
- m->name = g_strdup(sep_name);
- m->cmd = NULL;
- m->context = context;
- m->issep = TRUE;
- g_ptr_array_add(g->menu_items, m);
-}
-
-void
-menu_add_separator(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
-}
-
-void
-menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
-}
-void
-menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
-}
-
-void
-menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
-}
-
-void
-remove_from_menu(GArray *argv, guint context) {
- GUI *g = &uzbl.gui;
- MenuItem *mi;
- gchar *name = NULL;
- guint i=0;
-
- if(!g->menu_items)
- return;
-
- if(!argv_idx(argv, 0))
- return;
- else
- name = argv_idx(argv, 0);
-
- for(i=0; i < g->menu_items->len; i++) {
- mi = g_ptr_array_index(g->menu_items, i);
-
- if((context == mi->context) && !strcmp(name, mi->name)) {
- g_free(mi->name);
- g_free(mi->cmd);
- g_free(mi);
- g_ptr_array_remove_index(g->menu_items, i);
- }
- }
-}
-
-void
-menu_remove(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT);
-}
-
-void
-menu_remove_link(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK);
-}
-
-void
-menu_remove_image(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE);
-}
-
-void
-menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result) {
- (void) page;
- (void) result;
-
- remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE);
-}
void
event(WebKitWebView *page, GArray *argv, GString *result) {
@@ -852,7 +613,7 @@ event(WebKitWebView *page, GArray *argv, GString *result) {
else
return;
- send_event(0, split[1]?split[1]:"", event_name->str);
+ send_event(0, event_name->str, TYPE_FORMATTEDSTR, split[1] ? split[1] : "", NULL);
g_string_free(event_name, TRUE);
g_strfreev(split);
@@ -863,6 +624,9 @@ print(WebKitWebView *page, GArray *argv, GString *result) {
(void) page; (void) result;
gchar* buf;
+ if(!result)
+ return;
+
buf = expand(argv_idx(argv, 0), 0);
g_string_assign(result, buf);
g_free(buf);
@@ -895,11 +659,11 @@ include(WebKitWebView *page, GArray *argv, GString *result) {
if((path = find_existing_file(path))) {
if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) {
gchar *tmp = g_strdup_printf("File %s can not be read.", path);
- send_event(COMMAND_ERROR, tmp, NULL);
+ send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
g_free(tmp);
}
- send_event(FILE_INCLUDED, path, NULL);
+ send_event(FILE_INCLUDED, NULL, TYPE_STR, path, NULL);
g_free(path);
}
}
@@ -962,6 +726,18 @@ delete_cookie(WebKitWebView *page, GArray *argv, GString *result) {
uzbl.net.soup_cookie_jar->in_manual_add = 0;
}
+
+void
+clear_cookies(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page; (void) argv; (void) result;
+
+ // Replace the current cookie jar with a new empty jar
+ soup_session_remove_feature (uzbl.net.soup_session, uzbl.net.soup_cookie_jar);
+ g_object_unref (G_OBJECT (uzbl.net.soup_cookie_jar));
+ uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new ();
+ soup_session_add_feature(uzbl.net.soup_session, uzbl.net.soup_cookie_jar);
+}
+
void
act_dump_config() {
dump_config();
@@ -973,9 +749,10 @@ act_dump_config_as_events() {
}
void
-load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
+load_uri(WebKitWebView *web_view, GArray *argv, GString *result) {
(void) web_view; (void) result;
- set_var_value("uri", argv_idx(argv, 0));
+ gchar * uri = argv_idx(argv, 0);
+ set_var_value("uri", uri ? uri : "");
}
/* Javascript*/
@@ -999,7 +776,7 @@ eval_js(WebKitWebView * web_view, gchar *script, GString *result, const char *fi
js_script = JSStringCreateWithUTF8CString(script);
js_file = JSStringCreateWithUTF8CString(file);
js_result = JSEvaluateScript(context, js_script, globalobject, js_file, 0, &js_exc);
- if (js_result && !JSValueIsUndefined(context, js_result)) {
+ if (result && js_result && !JSValueIsUndefined(context, js_result)) {
js_result_string = JSValueToStringCopy(context, js_result, NULL);
js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
@@ -1118,7 +895,8 @@ search_clear(WebKitWebView *page, GArray *argv, GString *result) {
(void) result;
webkit_web_view_unmark_text_matches (page);
- uzbl.state.searchtx = strfree (uzbl.state.searchtx);
+ g_free(uzbl.state.searchtx);
+ uzbl.state.searchtx = NULL;
}
void
@@ -1128,29 +906,34 @@ search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
}
void
-search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
+search_reverse_text(WebKitWebView *page, GArray *argv, GString *result) {
(void) result;
search_text(page, argv, FALSE);
}
void
-dehilight (WebKitWebView *page, GArray *argv, GString *result) {
+dehilight(WebKitWebView *page, GArray *argv, GString *result) {
(void) argv; (void) result;
webkit_web_view_set_highlight_text_matches (page, FALSE);
}
void
-chain (WebKitWebView *page, GArray *argv, GString *result) {
- (void) page; (void) result;
- gchar *a = NULL;
- gchar **parts = NULL;
+chain(WebKitWebView *page, GArray *argv, GString *result) {
+ (void) page;
guint i = 0;
- while ((a = argv_idx(argv, i++))) {
- parts = g_strsplit (a, " ", 2);
- if (parts[0])
- parse_command(parts[0], parts[1], result);
- g_strfreev (parts);
+ const gchar *cmd;
+ GString *r = g_string_new ("");
+ while ((cmd = argv_idx(argv, i++))) {
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(cmd, a);
+ if (c)
+ run_parsed_command(c, a, r);
+ g_array_free (a, TRUE);
}
+ if(result)
+ g_string_assign (result, r->str);
+
+ g_string_free(r, TRUE);
}
void
@@ -1184,7 +967,8 @@ run_command (const gchar *command, const gchar **args, const gboolean sync,
gboolean result;
if (sync) {
- if (*output_stdout) *output_stdout = strfree(*output_stdout);
+ if (*output_stdout)
+ g_free(*output_stdout);
result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, output_stdout, NULL, NULL, &err);
@@ -1252,25 +1036,28 @@ split_quoted(const gchar* src, const gboolean unquote) {
}
void
-spawn(GArray *argv, gboolean sync, gboolean exec) {
+spawn(GArray *argv, GString *result, gboolean exec) {
gchar *path = NULL;
gchar *arg_car = argv_idx(argv, 0);
const gchar **arg_cdr = &g_array_index(argv, const gchar *, 1);
if (arg_car && (path = find_existing_file(arg_car))) {
- if (uzbl.comm.sync_stdout)
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
- run_command(path, arg_cdr, sync, sync?&uzbl.comm.sync_stdout:NULL);
- // run each line of output from the program as a command
- if (sync && exec && uzbl.comm.sync_stdout) {
- gchar *head = uzbl.comm.sync_stdout;
- gchar *tail;
- while ((tail = strchr (head, '\n'))) {
- *tail = '\0';
- parse_cmd_line(head, NULL);
- head = tail + 1;
+ gchar *r = NULL;
+ run_command(path, arg_cdr, result != NULL, result ? &r : NULL);
+ if(result) {
+ g_string_assign(result, r);
+ // run each line of output from the program as a command
+ if (exec && r) {
+ gchar *head = r;
+ gchar *tail;
+ while ((tail = strchr (head, '\n'))) {
+ *tail = '\0';
+ parse_cmd_line(head, NULL);
+ head = tail + 1;
+ }
}
}
+ g_free(r);
g_free(path);
}
}
@@ -1278,23 +1065,28 @@ spawn(GArray *argv, gboolean sync, gboolean exec) {
void
spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
- spawn(argv, FALSE, FALSE);
+ spawn(argv, NULL, FALSE);
}
void
spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
- spawn(argv, TRUE, FALSE);
+ (void)web_view;
+ spawn(argv, result, FALSE);
}
void
spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) {
- (void)web_view; (void)result;
- spawn(argv, TRUE, TRUE);
+ (void)web_view;
+ if(!result) {
+ GString *force_result = g_string_new("");
+ spawn(argv, force_result, TRUE);
+ g_string_free (force_result, TRUE);
+ } else
+ spawn(argv, result, TRUE);
}
void
-spawn_sh(GArray *argv, gboolean sync) {
+spawn_sh(GArray *argv, GString *result) {
if (!uzbl.behave.shell_cmd) {
g_printerr ("spawn_sh: shell_cmd is not set!\n");
return;
@@ -1302,19 +1094,23 @@ spawn_sh(GArray *argv, gboolean sync) {
guint i;
gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
+ if(!cmd)
+ return;
+
gchar *cmdname = g_strdup(cmd[0]);
g_array_insert_val(argv, 1, cmdname);
for (i = 1; i < g_strv_length(cmd); i++)
g_array_prepend_val(argv, cmd[i]);
- if (cmd) {
- if (uzbl.comm.sync_stdout)
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+ if (result) {
+ gchar *r = NULL;
+ run_command(cmd[0], (const gchar **) argv->data, TRUE, &r);
+ g_string_assign(result, r);
+ g_free(r);
+ } else
+ run_command(cmd[0], (const gchar **) argv->data, FALSE, NULL);
- run_command(cmd[0], (const gchar **) argv->data,
- sync, sync?&uzbl.comm.sync_stdout:NULL);
- }
g_free (cmdname);
g_strfreev (cmd);
}
@@ -1322,58 +1118,110 @@ spawn_sh(GArray *argv, gboolean sync) {
void
spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
- spawn_sh(argv, FALSE);
+ spawn_sh(argv, NULL);
}
void
spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
(void)web_view; (void)result;
- spawn_sh(argv, TRUE);
+ spawn_sh(argv, result);
}
void
-parse_command(const char *cmd, const char *param, GString *result) {
- CommandInfo *c;
- GString *tmp = g_string_new("");
+run_parsed_command(const CommandInfo *c, GArray *a, GString *result) {
+ c->function(uzbl.gui.web_view, a, result);
- 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*));
+ /* send the COMMAND_EXECUTED event, except for set and event/request commands */
+ if(strcmp("set", c->key) &&
+ strcmp("event", c->key) &&
+ strcmp("request", c->key)) {
+ // FIXME, build string inside send_event
+ GString *param = g_string_new("");
+ const gchar *p;
+ guint i = 0;
+ while ((p = argv_idx(a, i++)))
+ g_string_append_printf(param, " '%s'", p);
+ send_event(COMMAND_EXECUTED, NULL,
+ TYPE_NAME, c->key,
+ TYPE_FORMATTEDSTR, param->str,
+ NULL);
+ g_string_free(param, TRUE);
+ }
- 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]);
- }
+ if(result) {
+ g_free(uzbl.state.last_result);
+ uzbl.state.last_result = g_strdup(result->str);
+ }
+}
- if (result == NULL) {
- GString *result_print = g_string_new("");
+void
+parse_command_arguments(const gchar *p, GArray *a, gboolean no_split) {
+ if (no_split && p) { /* pass the parameters through in one chunk */
+ sharg_append(a, g_strdup(p));
+ return;
+ }
- c->function(uzbl.gui.web_view, a, result_print);
- if (result_print->len)
- printf("%*s\n", (int)result_print->len, result_print->str);
+ gchar **par = split_quoted(p, TRUE);
+ if (par) {
+ guint i;
+ for (i = 0; i < g_strv_length(par); i++)
+ sharg_append(a, g_strdup(par[i]));
+ g_strfreev (par);
+ }
+}
- g_string_free(result_print, TRUE);
- } else {
- c->function(uzbl.gui.web_view, a, result);
- }
- g_strfreev (par);
- g_array_free (a, TRUE);
+const CommandInfo *
+parse_command_parts(const gchar *line, GArray *a) {
+ CommandInfo *c = NULL;
- if(strcmp("set", cmd) &&
- strcmp("event", cmd) &&
- strcmp("request", cmd)) {
- g_string_printf(tmp, "%s %s", cmd, param?param:"");
- send_event(COMMAND_EXECUTED, tmp->str, NULL);
- }
+ gchar *exp_line = expand(line, 0);
+ if(exp_line[0] == '\0') {
+ g_free(exp_line);
+ return NULL;
}
- else {
- g_string_printf (tmp, "%s %s", cmd, param?param:"");
- send_event(COMMAND_ERROR, tmp->str, NULL);
+
+ /* separate the line into the command and its parameters */
+ gchar **tokens = g_strsplit(exp_line, " ", 2);
+
+ /* look up the command */
+ c = g_hash_table_lookup(uzbl.behave.commands, tokens[0]);
+
+ if(!c) {
+ send_event(COMMAND_ERROR, NULL,
+ TYPE_STR, exp_line,
+ NULL);
+ g_free(exp_line);
+ g_strfreev(tokens);
+ return NULL;
+ }
+
+ gchar *p = g_strdup(tokens[1]);
+ g_free(exp_line);
+ g_strfreev(tokens);
+
+ /* parse the arguments */
+ parse_command_arguments(p, a, c->no_split);
+ g_free(p);
+
+ return c;
+}
+
+void
+parse_command(const char *cmd, const char *params, GString *result) {
+ CommandInfo *c = g_hash_table_lookup(uzbl.behave.commands, cmd);
+ if(c) {
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+
+ parse_command_arguments(params, a, c->no_split);
+ run_parsed_command(c, a, result);
+
+ g_array_free (a, TRUE);
+ } else {
+ send_event(COMMAND_ERROR, NULL,
+ TYPE_NAME, cmd,
+ TYPE_STR, params ? params : "",
+ NULL);
}
- g_string_free(tmp, TRUE);
}
@@ -1398,47 +1246,81 @@ move_statusbar() {
}
g_object_unref(uzbl.gui.scrolled_win);
g_object_unref(uzbl.gui.mainbar);
- gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
+ if (!uzbl.state.plug_mode)
+ gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
return;
}
gboolean
+valid_name(const gchar* name) {
+ char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
+ return strpbrk(name, invalid_chars) == NULL;
+}
+
+void
+send_set_var_event(const char *name, const uzbl_cmdprop *c) {
+ /* check for the variable type */
+ switch(c->type) {
+ case TYPE_STR:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, *c->ptr.s ? *c->ptr.s : " ",
+ NULL);
+ break;
+ case TYPE_INT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "int",
+ TYPE_INT, *c->ptr.i,
+ NULL);
+ break;
+ case TYPE_FLOAT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "float",
+ TYPE_FLOAT, *c->ptr.f,
+ NULL);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+gboolean
set_var_value(const gchar *name, gchar *val) {
uzbl_cmdprop *c = NULL;
char *endp = NULL;
char *buf = NULL;
- char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
- GString *msg;
+
+ g_assert(val != NULL);
if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
if(!c->writeable) return FALSE;
- msg = g_string_new(name);
-
- /* check for the variable type */
- if (c->type == TYPE_STR) {
+ switch(c->type) {
+ case TYPE_STR:
buf = g_strdup(val);
g_free(*c->ptr.s);
*c->ptr.s = buf;
- g_string_append_printf(msg, " str %s", buf);
-
- } else if(c->type == TYPE_INT) {
+ break;
+ case TYPE_INT:
*c->ptr.i = (int)strtoul(val, &endp, 10);
- g_string_append_printf(msg, " int %d", *c->ptr.i);
-
- } else if (c->type == TYPE_FLOAT) {
+ break;
+ case TYPE_FLOAT:
*c->ptr.f = strtod(val, &endp);
- g_string_append_printf(msg, " float %f", *c->ptr.f);
+ break;
+ default:
+ g_assert_not_reached();
}
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg,TRUE);
+ send_set_var_event(name, c);
/* invoke a command specific function */
if(c->func) c->func();
} else {
/* check wether name violates our naming scheme */
- if(strpbrk(name, invalid_chars)) {
+ if(!valid_name(name)) {
if (uzbl.state.verbose)
printf("Invalid variable name: %s\n", name);
return FALSE;
@@ -1456,10 +1338,11 @@ set_var_value(const gchar *name, gchar *val) {
g_hash_table_insert(uzbl.comm.proto_var,
g_strdup(name), (gpointer) c);
- msg = g_string_new(name);
- g_string_append_printf(msg, " str %s", buf);
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg,TRUE);
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, buf,
+ NULL);
}
update_title();
return TRUE;
@@ -1467,376 +1350,26 @@ set_var_value(const gchar *name, gchar *val) {
void
parse_cmd_line(const char *ctl_line, GString *result) {
- size_t len=0;
- gchar *ctlstrip = NULL;
- gchar *exp_line = NULL;
- gchar *work_string = NULL;
-
- work_string = g_strdup(ctl_line);
-
- /* strip trailing newline */
- len = strlen(ctl_line);
- if (work_string[len - 1] == '\n')
- ctlstrip = g_strndup(work_string, len - 1);
- else
- ctlstrip = g_strdup(work_string);
- g_free(work_string);
-
- if( strcmp(g_strchug(ctlstrip), "") &&
- strcmp(exp_line = expand(ctlstrip, 0), "")
- ) {
- /* ignore comments */
- if((exp_line[0] == '#'))
- ;
-
- /* parse a command */
- else {
- gchar **tokens = NULL;
-
- tokens = g_strsplit(exp_line, " ", 2);
- parse_command(tokens[0], tokens[1], result);
- g_strfreev(tokens);
- }
- g_free(exp_line);
- }
-
- g_free(ctlstrip);
-}
-
-/*@null@*/ gchar*
-build_stream_name(int type, const gchar* dir) {
- State *s = &uzbl.state;
- gchar *str = NULL;
-
- if (type == FIFO) {
- str = g_strdup_printf
- ("%s/uzbl_fifo_%s", dir, s->instance_name);
- } else if (type == SOCKET) {
- str = g_strdup_printf
- ("%s/uzbl_socket_%s", dir, s->instance_name);
- }
- return str;
-}
-
-gboolean
-control_fifo(GIOChannel *gio, GIOCondition condition) {
- if (uzbl.state.verbose)
- printf("triggered\n");
- gchar *ctl_line;
- GIOStatus ret;
- GError *err = NULL;
-
- if (condition & G_IO_HUP)
- g_error ("Fifo: Read end of pipe died!\n");
-
- if(!gio)
- g_error ("Fifo: GIOChannel broke\n");
-
- ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
- if (ret == G_IO_STATUS_ERROR) {
- g_error ("Fifo: Error reading: %s\n", err->message);
- g_error_free (err);
- }
-
- parse_cmd_line(ctl_line, NULL);
- g_free(ctl_line);
-
- return TRUE;
-}
-
-gboolean
-attach_fifo(gchar *path) {
- GError *error = NULL;
- /* 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. */
- GIOChannel *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)) {
- if (uzbl.state.verbose)
- printf ("attach_fifo: created successfully as %s\n", path);
- send_event(FIFO_SET, path, NULL);
- uzbl.comm.fifo_path = path;
- g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE);
- return TRUE;
- } else g_warning ("attach_fifo: could not add watch on %s\n", path);
- } else g_warning ("attach_fifo: can't open: %s\n", error->message);
-
- if (error) g_error_free (error);
- return FALSE;
-}
-
-/*@null@*/ gchar*
-init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
- if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
- if (unlink(uzbl.comm.fifo_path) == -1)
- 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;
- }
-
- gchar *path = build_stream_name(FIFO, dir);
-
- if (!file_exists(path)) {
- if (mkfifo (path, 0666) == 0 && attach_fifo(path)) {
- return dir;
- } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
- } else {
- /* the fifo exists. but is anybody home? */
- int fd = open(path, O_WRONLY|O_NONBLOCK);
- if(fd < 0) {
- /* some error occurred, presumably nobody's on the read end.
- * we can attach ourselves to it. */
- if(attach_fifo(path))
- return dir;
- else
- g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno));
- } else {
- /* somebody's there, we can't use that fifo. */
- close(fd);
- /* whatever, this instance can live without a fifo. */
- g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path);
- }
- }
-
- /* if we got this far, there was an error; cleanup */
- g_free(dir);
- g_free(path);
- return NULL;
-}
-
-gboolean
-control_stdin(GIOChannel *gio, GIOCondition condition) {
- (void) condition;
- gchar *ctl_line = NULL;
- GIOStatus ret;
-
- ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
- if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
- return FALSE;
-
- parse_cmd_line(ctl_line, NULL);
- g_free(ctl_line);
-
- return TRUE;
-}
+ gchar *work_string = g_strdup(ctl_line);
-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 {
- if (uzbl.state.verbose)
- printf ("Stdin: watch added successfully\n");
- }
- } else {
- g_error ("Stdin: Error while opening: %s\n", error->message);
- }
- if (error) g_error_free (error);
-}
-
-gboolean
-remove_socket_from_array(GIOChannel *chan) {
- gboolean ret = 0;
-
- ret = g_ptr_array_remove_fast(uzbl.comm.connect_chan, chan);
- if(!ret)
- ret = g_ptr_array_remove_fast(uzbl.comm.client_chan, chan);
+ /* strip trailing newline, and any other whitespace in front */
+ g_strstrip(work_string);
- if(ret)
- g_io_channel_unref (chan);
- return ret;
-}
-
-gboolean
-control_socket(GIOChannel *chan) {
- struct sockaddr_un remote;
- unsigned int t = sizeof(remote);
- GIOChannel *iochan;
- int clientsock;
-
- clientsock = accept (g_io_channel_unix_get_fd(chan),
- (struct sockaddr *) &remote, &t);
-
- if(!uzbl.comm.client_chan)
- uzbl.comm.client_chan = g_ptr_array_new();
-
- if ((iochan = g_io_channel_unix_new(clientsock))) {
- g_io_channel_set_encoding(iochan, NULL, NULL);
- g_io_add_watch(iochan, G_IO_IN|G_IO_HUP,
- (GIOFunc) control_client_socket, iochan);
- g_ptr_array_add(uzbl.comm.client_chan, (gpointer)iochan);
- }
- return TRUE;
-}
-
-void
-init_connect_socket() {
- int sockfd, replay = 0;
- struct sockaddr_un local;
- GIOChannel *chan;
- gchar **name = NULL;
-
- if(!uzbl.comm.connect_chan)
- uzbl.comm.connect_chan = g_ptr_array_new();
-
- name = uzbl.state.connect_socket_names;
-
- while(name && *name) {
- sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
- local.sun_family = AF_UNIX;
- strcpy (local.sun_path, *name);
-
- if(!connect(sockfd, (struct sockaddr *) &local, sizeof(local))) {
- if ((chan = g_io_channel_unix_new(sockfd))) {
- g_io_channel_set_encoding(chan, NULL, NULL);
- g_io_add_watch(chan, G_IO_IN|G_IO_HUP,
- (GIOFunc) control_client_socket, chan);
- g_ptr_array_add(uzbl.comm.connect_chan, (gpointer)chan);
- replay++;
- }
- }
- else
- g_warning("Error connecting to socket: %s\n", *name);
- name++;
- }
-
- /* replay buffered events */
- if(replay)
- send_event_socket(NULL);
-}
-
-gboolean
-control_client_socket(GIOChannel *clientchan) {
- char *ctl_line;
- GString *result = g_string_new("");
- GError *error = NULL;
- GIOStatus ret;
- gsize len;
-
- ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
- if (ret == G_IO_STATUS_ERROR) {
- g_warning ("Error reading: %s", error->message);
- g_clear_error (&error);
- ret = g_io_channel_shutdown (clientchan, TRUE, &error);
- remove_socket_from_array (clientchan);
- if (ret == G_IO_STATUS_ERROR) {
- g_warning ("Error closing: %s", error->message);
- g_clear_error (&error);
- }
- return FALSE;
- } else if (ret == G_IO_STATUS_EOF) {
- /* shutdown and remove channel watch from main loop */
- ret = g_io_channel_shutdown (clientchan, TRUE, &error);
- remove_socket_from_array (clientchan);
- if (ret == G_IO_STATUS_ERROR) {
- g_warning ("Error closing: %s", error->message);
- g_clear_error (&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_clear_error (&error);
- }
- if (g_io_channel_flush(clientchan, &error) == G_IO_STATUS_ERROR) {
- g_warning ("Error flushing: %s", error->message);
- g_clear_error (&error);
- }
- }
-
- g_string_free(result, TRUE);
- g_free(ctl_line);
- return TRUE;
-}
-
-
-gboolean
-attach_socket(gchar *path, struct sockaddr_un *local) {
- GIOChannel *chan = NULL;
- int sock = socket (AF_UNIX, SOCK_STREAM, 0);
-
- if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) {
- if (uzbl.state.verbose)
- printf ("init_socket: opened in %s\n", path);
-
- if(listen (sock, 5) < 0)
- g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno));
-
- 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;
- send_event(SOCKET_SET, path, NULL);
- g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE);
- return TRUE;
- }
- } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno));
-
- return FALSE;
-}
-
-
-/*@null@*/ gchar*
-init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
- if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
- if (unlink(uzbl.comm.socket_path) == -1)
- 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;
- }
-
- struct sockaddr_un local;
- gchar *path = build_stream_name(SOCKET, dir);
-
- local.sun_family = AF_UNIX;
- strcpy (local.sun_path, path);
-
- if(!file_exists(path) && attach_socket(path, &local)) {
- /* it's free for the taking. */
- return dir;
- } else {
- /* see if anybody's listening on the socket path we want. */
- int sock = socket (AF_UNIX, SOCK_STREAM, 0);
- if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
- /* some error occurred, presumably nobody's listening.
- * we can attach ourselves to it. */
- unlink(path);
- if(attach_socket(path, &local))
- return dir;
- else
- g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno));
- } else {
- /* somebody's there, we can't use that socket path. */
- close(sock);
- /* whatever, this instance can live without a socket. */
- g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path);
+ if( strcmp(work_string, "") ) {
+ if((work_string[0] != '#')) { /* ignore comments */
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(work_string, a);
+ if(c)
+ run_parsed_command(c, a, result);
+ g_array_free (a, TRUE);
}
}
- /* if we got this far, there was an error; cleanup */
- g_free(path);
- g_free(dir);
- return NULL;
+ g_free(work_string);
}
void
-update_title (void) {
+update_title(void) {
Behaviour *b = &uzbl.behave;
const gchar *title_format = b->title_format_long;
@@ -1875,10 +1408,22 @@ update_title (void) {
}
void
-create_browser () {
- GUI *g = &uzbl.gui;
+create_scrolled_win() {
+ GUI* g = &uzbl.gui;
+
+ g->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ g->scrolled_win = gtk_scrolled_window_new(NULL, NULL);
- g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
+ gtk_scrolled_window_set_policy(
+ GTK_SCROLLED_WINDOW(g->scrolled_win),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_NEVER
+ );
+
+ gtk_container_add(
+ GTK_CONTAINER(g->scrolled_win),
+ GTK_WIDGET(g->web_view)
+ );
g_object_connect((GObject*)g->web_view,
"signal::key-press-event", (GCallback)key_press_cb, NULL,
@@ -1890,6 +1435,7 @@ create_browser () {
"signal::selection-changed", (GCallback)selection_changed_cb, NULL,
"signal::notify::progress", (GCallback)progress_change_cb, NULL,
"signal::notify::load-status", (GCallback)load_status_change_cb, NULL,
+ "signal::notify::uri", (GCallback)uri_change_cb, NULL,
"signal::load-error", (GCallback)load_error_cb, NULL,
"signal::hovering-over-link", (GCallback)link_hover_cb, NULL,
"signal::navigation-policy-decision-requested", (GCallback)navigation_decision_cb, NULL,
@@ -1904,8 +1450,9 @@ create_browser () {
NULL);
}
+
GtkWidget*
-create_mainbar () {
+create_mainbar() {
GUI *g = &uzbl.gui;
g->mainbar = gtk_hbox_new (FALSE, 0);
@@ -1937,11 +1484,16 @@ create_mainbar () {
GtkWidget*
-create_window () {
+create_window() {
GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
gtk_widget_set_name (window, "Uzbl browser");
+ gtk_window_set_title(GTK_WINDOW(window), "Uzbl browser");
+
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_window_set_has_resize_grip (window, FALSE);
+#endif
/* if the window has been made small, it shouldn't try to resize itself due
* to a long statusbar. */
@@ -1956,8 +1508,9 @@ create_window () {
return window;
}
+
GtkPlug*
-create_plug () {
+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);
@@ -1966,132 +1519,13 @@ create_plug () {
return plug;
}
-
-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
- newargs in front of the user-provided args in that command line. They will
- come become after the body of the script (in sh) or after the name of
- the command to execute (in spawn).
- i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
- spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
-
- The return value consist of two strings: the action (sh, ...) and its args.
-
- If act is not one that calls an external command, then the given action merely
- gets duplicated.
- */
- GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
- /* Arrr! Here be memory leaks */
- gchar *actdup = g_strdup(actname);
- g_array_append_val(rets, actdup);
-
- if ((g_strcmp0(actname, "spawn") == 0) ||
- (g_strcmp0(actname, "sh") == 0) ||
- (g_strcmp0(actname, "sync_spawn") == 0) ||
- (g_strcmp0(actname, "sync_sh") == 0)) {
- guint i;
- GString *a = g_string_new("");
- gchar **spawnparts = split_quoted(origargs, FALSE);
- g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
- if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
-
- for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
- if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
-
- g_array_append_val(rets, a->str);
- g_string_free(a, FALSE);
- g_strfreev(spawnparts);
- } else {
- gchar *origdup = g_strdup(origargs);
- g_array_append_val(rets, origdup);
- }
- return (gchar**)g_array_free(rets, FALSE);
-}
-
-void
-run_handler (const gchar *act, const gchar *args) {
- /* Consider this code a temporary hack to make the handlers usable.
- In practice, all this splicing, injection, and reconstruction is
- inefficient, annoying and hard to manage. Potential pitfalls arise
- when the handler specific args 1) are not quoted (the handler
- callbacks should take care of this) 2) are quoted but interfere
- with the users' own quotation. A more ideal solution is
- to refactor parse_command so that it doesn't just take a string
- and execute it; rather than that, we should have a function which
- returns the argument vector parsed from the string. This vector
- could be modified (e.g. insert additional args into it) before
- passing it to the next function that actually executes it. Though
- it still isn't perfect for chain actions.. will reconsider & re-
- factor when I have the time. -duc */
-
- if (!act) return;
- char **parts = g_strsplit(act, " ", 2);
- if (!parts || !parts[0]) return;
- if (g_strcmp0(parts[0], "chain") == 0) {
- GString *newargs = g_string_new("");
- gchar **chainparts = split_quoted(parts[1], FALSE);
-
- /* for every argument in the chain, inject the handler args
- and make sure the new parts are wrapped in quotes */
- gchar **cp = chainparts;
- gchar quot = '\'';
- gchar *quotless = NULL;
- gchar **spliced_quotless = NULL; // sigh -_-;
- gchar **inpart = NULL;
-
- while (*cp) {
- if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
- quot = **cp;
- quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
- } else quotless = g_strdup(*cp);
-
- spliced_quotless = g_strsplit(quotless, " ", 2);
- inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
- g_strfreev(spliced_quotless);
-
- g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
- g_free(quotless);
- g_strfreev(inpart);
- cp++;
- }
-
- parse_command(parts[0], &(newargs->str[1]), NULL);
- g_string_free(newargs, TRUE);
- g_strfreev(chainparts);
-
- } else {
- gchar **inparts;
- gchar *inparts_[2];
- if (parts[1]) {
- /* expand the user-specified arguments */
- gchar* expanded = expand(parts[1], 0);
- inparts = inject_handler_args(parts[0], expanded, args);
- g_free(expanded);
- } else {
- inparts_[0] = parts[0];
- inparts_[1] = g_strdup(args);
- inparts = inparts_;
- }
-
- parse_command(inparts[0], inparts[1], NULL);
-
- if (inparts != inparts_) {
- g_free(inparts[0]);
- g_free(inparts[1]);
- } else
- g_free(inparts[1]);
- }
- g_strfreev(parts);
-}
-
void
settings_init () {
- State *s = &uzbl.state;
- Network *n = &uzbl.net;
-
- int i;
+ State* s = &uzbl.state;
+ Network* n = &uzbl.net;
+ int i;
+
+ /* Load default config */
for (i = 0; default_config[i].command != NULL; i++) {
parse_cmd_line(default_config[i].command, NULL);
}
@@ -2102,56 +1536,59 @@ settings_init () {
}
else if (!s->config_file) {
- s->config_file = find_xdg_file (0, "/uzbl/config");
+ s->config_file = find_xdg_file(0, "/uzbl/config");
}
+ /* Load config file, if any */
if (s->config_file) {
- if(!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) {
+ if (!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) {
gchar *tmp = g_strdup_printf("File %s can not be read.", s->config_file);
- send_event(COMMAND_ERROR, tmp, NULL);
+ send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
g_free(tmp);
}
g_setenv("UZBL_CONFIG", s->config_file, TRUE);
} else if (uzbl.state.verbose)
printf ("No configuration file loaded.\n");
- if(s->connect_socket_names)
+ if (s->connect_socket_names)
init_connect_socket();
g_signal_connect(n->soup_session, "authenticate", G_CALLBACK(handle_authentication), NULL);
}
-void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data) {
+void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data) {
(void) user_data;
- if(uzbl.behave.authentication_handler && *uzbl.behave.authentication_handler != 0) {
- gchar *info, *host, *realm;
- gchar *p;
-
+ if (uzbl.behave.authentication_handler && *uzbl.behave.authentication_handler != 0) {
soup_session_pause_message(session, msg);
- /* Sanitize strings */
- info = g_strdup(soup_auth_get_info(auth));
- host = g_strdup(soup_auth_get_host(auth));
- realm = g_strdup(soup_auth_get_realm(auth));
- for (p = info; *p; p++) if (*p == '\'') *p = '\"';
- for (p = host; *p; p++) if (*p == '\'') *p = '\"';
- for (p = realm; *p; p++) if (*p == '\'') *p = '\"';
+ GString *result = g_string_new ("");
- GString *s = g_string_new ("");
- g_string_printf(s, "'%s' '%s' '%s' '%s'",
- info, host, realm, retrying?"TRUE":"FALSE");
+ gchar *info = g_strdup(soup_auth_get_info(auth));
+ gchar *host = g_strdup(soup_auth_get_host(auth));
+ gchar *realm = g_strdup(soup_auth_get_realm(auth));
- run_handler(uzbl.behave.authentication_handler, s->str);
+ GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
+ const CommandInfo *c = parse_command_parts(uzbl.behave.authentication_handler, a);
+ if(c) {
+ sharg_append(a, info);
+ sharg_append(a, host);
+ sharg_append(a, realm);
+ sharg_append(a, retrying ? "TRUE" : "FALSE");
+
+ run_parsed_command(c, a, result);
+ }
+ g_array_free(a, TRUE);
- if (uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
+ if (result->len > 0) {
char *username, *password;
int number_of_endls=0;
- username = uzbl.comm.sync_stdout;
+ username = result->str;
- for (p = uzbl.comm.sync_stdout; *p; p++) {
+ gchar *p;
+ for (p = result->str; *p; p++) {
if (*p == '\n') {
*p = '\0';
if (++number_of_endls == 1)
@@ -2165,12 +1602,9 @@ void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *au
soup_auth_authenticate(auth, username, password);
}
- if (uzbl.comm.sync_stdout)
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
-
soup_session_unpause_message(session, msg);
- g_string_free(s, TRUE);
+ g_string_free(result, TRUE);
g_free(info);
g_free(host);
g_free(realm);
@@ -2202,23 +1636,9 @@ void
dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) {
(void) ud;
uzbl_cmdprop *c = v;
- GString *msg;
- if(!c->dump)
- return;
-
- /* check for the variable type */
- msg = g_string_new((char *)k);
- if (c->type == TYPE_STR) {
- g_string_append_printf(msg, " str %s", *c->ptr.s ? *c->ptr.s : " ");
- } else if(c->type == TYPE_INT) {
- g_string_append_printf(msg, " int %d", *c->ptr.i);
- } else if (c->type == TYPE_FLOAT) {
- g_string_append_printf(msg, " float %f", *c->ptr.f);
- }
-
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg, TRUE);
+ if(c->dump)
+ send_set_var_event(k, c);
}
void
@@ -2262,62 +1682,76 @@ set_webview_scroll_adjustments() {
NULL);
}
-/* set up gtk, gobject, variable defaults and other things that tests and other
+
+/* Set up gtk, gobject, variable defaults and other things that tests and other
* external applications need to do anyhow */
void
-initialize(int argc, char *argv[]) {
- int i;
+initialize(int argc, char** argv) {
+ /* Initialize variables */
+ uzbl.state.socket_id = 0;
+ uzbl.state.plug_mode = FALSE;
- for(i=0; i<argc; ++i) {
- if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--socket")) {
- uzbl.state.plug_mode = TRUE;
- break;
- }
- }
+ uzbl.state.executable_path = g_strdup(argv[0]);
+ uzbl.state.selected_url = NULL;
+ uzbl.state.searchtx = NULL;
- if (!g_thread_supported ())
- g_thread_init (NULL);
- gtk_init (&argc, &argv);
+ uzbl.info.webkit_major = webkit_major_version();
+ uzbl.info.webkit_minor = webkit_minor_version();
+ uzbl.info.webkit_micro = webkit_micro_version();
+ uzbl.info.arch = ARCH;
+ uzbl.info.commit = COMMIT;
- uzbl.state.executable_path = g_strdup(argv[0]);
- uzbl.state.selected_url = NULL;
- uzbl.state.searchtx = NULL;
+ uzbl.state.last_result = NULL;
+ /* Parse commandline arguments */
GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
- 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, NULL);
+ 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, NULL);
g_option_context_free(context);
+ /* Only print version */
if (uzbl.behave.print_version) {
printf("Commit: %s\n", COMMIT);
exit(EXIT_SUCCESS);
}
- uzbl.net.soup_session = webkit_get_default_session();
+ /* Embedded mode */
+ if (uzbl.state.socket_id)
+ uzbl.state.plug_mode = TRUE;
+
+ if (!g_thread_supported())
+ g_thread_init(NULL);
- uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new();
- soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar));
/* TODO: move the handler setup to event_buffer_timeout and disarm the
* handler in empty_event_buffer? */
- if(setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR)
+ if (setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR)
fprintf(stderr, "uzbl: error hooking %d: %s\n", SIGALRM, strerror(errno));
event_buffer_timeout(10);
- uzbl.info.webkit_major = webkit_major_version();
- uzbl.info.webkit_minor = webkit_minor_version();
- uzbl.info.webkit_micro = webkit_micro_version();
- uzbl.info.arch = ARCH;
- uzbl.info.commit = COMMIT;
+
+ /* HTTP client */
+ uzbl.net.soup_session = webkit_get_default_session();
+ uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new();
+
+ soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar));
+
- commands_hash ();
+ commands_hash();
create_var_to_name_hash();
+ /* GUI */
+ gtk_init(&argc, &argv);
create_mainbar();
- create_browser();
+ create_scrolled_win();
+
+ uzbl.gui.vbox = gtk_vbox_new(FALSE, 0);
+ 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);
}
+
void
load_uri_imp(gchar *uri) {
GString* newuri;
@@ -2367,21 +1801,9 @@ int
main (int argc, char* argv[]) {
initialize(argc, argv);
- uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
- GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-
- gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
- GTK_WIDGET (uzbl.gui.web_view));
-
- uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
-
- /* 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);
-
+ /* Embedded mode */
if (uzbl.state.plug_mode) {
- uzbl.gui.plug = create_plug ();
+ 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));
/* in xembed mode the window has no unique id and thus
@@ -2392,13 +1814,20 @@ main (int argc, char* argv[]) {
gettimeofday(&tv, NULL);
srand((unsigned int)tv.tv_sec*tv.tv_usec);
uzbl.xwin = rand();
- } else {
- uzbl.gui.main_window = create_window ();
+ }
+
+ /* Windowed mode */
+ 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_get_window (GTK_WIDGET (uzbl.gui.main_window)));
+
+ gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
}
+ /* Scrolling */
uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
@@ -2416,34 +1845,18 @@ main (int argc, char* argv[]) {
uzbl.info.pid_str = g_strdup_printf("%d", getpid());
g_setenv("UZBL_PID", uzbl.info.pid_str, TRUE);
- send_event(INSTANCE_START, uzbl.info.pid_str, NULL);
+ send_event(INSTANCE_START, NULL, TYPE_INT, getpid(), NULL);
- if(uzbl.state.plug_mode) {
- char *t = itos(gtk_plug_get_id(uzbl.gui.plug));
- send_event(PLUG_CREATED, t, NULL);
- g_free(t);
+ if (uzbl.state.plug_mode) {
+ send_event(PLUG_CREATED, NULL, TYPE_INT, gtk_plug_get_id (uzbl.gui.plug), NULL);
}
- /* generate an event with a list of built in commands */
+ /* Generate an event with a list of built in commands */
builtins();
- if (!uzbl.state.plug_mode)
- gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
-
- if (uzbl.state.verbose) {
- printf("Uzbl start location: %s\n", argv[0]);
- 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);
- printf("commit: %s\n", uzbl.info.commit);
- }
-
/* Check uzbl is in window mode before getting/setting geometry */
if (uzbl.gui.main_window) {
- if(uzbl.gui.geometry)
+ if (uzbl.gui.geometry)
cmd_set_geometry();
else
retrieve_geometry();
@@ -2452,10 +1865,13 @@ main (int argc, char* argv[]) {
gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
if (argc > 1 && !uzbl.state.uri)
uri_override = g_strdup(argv[1]);
+
gboolean verbose_override = uzbl.state.verbose;
- settings_init ();
+ /* Read configuration file */
+ settings_init();
+ /* Update status bar */
if (!uzbl.behave.show_status)
gtk_widget_hide(uzbl.gui.mainbar);
else
@@ -2464,6 +1880,7 @@ main (int argc, char* argv[]) {
/* WebInspector */
set_up_inspector();
+ /* Options overriding */
if (verbose_override > uzbl.state.verbose)
uzbl.state.verbose = verbose_override;
@@ -2472,7 +1889,22 @@ main (int argc, char* argv[]) {
g_free(uri_override);
}
- gtk_main ();
+ /* Verbose feedback */
+ if (uzbl.state.verbose) {
+ printf("Uzbl start location: %s\n", argv[0]);
+ 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);
+ printf("commit: %s\n", uzbl.info.commit);
+ }
+
+
+ gtk_main();
+
+ /* Cleanup and exit*/
clean_up();
return EXIT_SUCCESS;
diff --git a/src/uzbl-core.h b/src/uzbl-core.h
index f81722d..affd334 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -10,6 +10,9 @@
*
*/
+#ifndef __UZBL_CORE__
+#define __UZBL_CORE__
+
#define _POSIX_SOURCE
#include <glib/gstdio.h>
@@ -40,12 +43,18 @@
#include <sys/ioctl.h>
#include <assert.h>
+#if GTK_CHECK_VERSION(2,91,0)
+ #include <gtk/gtkx.h>
+#endif
+
#include "cookie-jar.h"
#define LENGTH(x) (sizeof x / sizeof x[0])
-/* gui elements */
+
+/* GUI elements */
typedef struct {
+ /* Window */
GtkWidget* main_window;
gchar* geometry;
GtkPlug* plug;
@@ -57,100 +66,109 @@ typedef struct {
GtkWidget* mainbar_label_left;
GtkWidget* mainbar_label_right;
- GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar
- GtkScrollbar* scbar_h; // (These are still hidden)
- GtkAdjustment* bar_v; // Information about document length
- GtkAdjustment* bar_h; // and scrolling position
+ /* Scrolling */
+ GtkScrollbar* scbar_v; /* Horizontal and Vertical Scrollbar */
+ GtkScrollbar* scbar_h; /* (These are still hidden) */
+ GtkAdjustment* bar_v; /* Information about document length */
+ GtkAdjustment* bar_h; /* and scrolling position */
int scrollbars_visible;
+
+ /* Web page */
WebKitWebView* web_view;
gchar* main_title;
gchar* icon;
/* WebInspector */
- GtkWidget *inspector_window;
- WebKitWebInspector *inspector;
+ GtkWidget* inspector_window;
+ WebKitWebInspector* inspector;
- /* custom context menu item */
- GPtrArray *menu_items;
+ /* Custom context menu item */
+ GPtrArray* menu_items;
} GUI;
-/* external communication*/
+/* External communication */
enum { FIFO, SOCKET};
typedef struct {
gchar *fifo_path;
gchar *socket_path;
- /* stores (key)"variable name" -> (value)"pointer to var*/
- GHashTable *proto_var;
+ GHashTable *proto_var; /* stores (key)"variable name" -> (value)"pointer to var */
- gchar *sync_stdout;
GPtrArray *connect_chan;
GPtrArray *client_chan;
} Communication;
-/* internal state */
+/* Internal state */
typedef struct {
- gchar *uri;
- gchar *config_file;
- int socket_id;
- char *instance_name;
- gchar *selected_url;
- gchar *last_selected_url;
- gchar *executable_path;
- gchar* searchtx;
- gboolean verbose;
- gboolean events_stdout;
- GPtrArray *event_buffer;
- gchar** connect_socket_names;
- GdkEventButton *last_button;
- gboolean plug_mode;
+ gchar* uri;
+ gchar* config_file;
+ char* instance_name;
+ gchar* selected_url;
+ gchar* last_selected_url;
+ gchar* executable_path;
+ gchar* searchtx;
+ gboolean verbose;
+ GdkEventButton* last_button;
+ gchar* last_result;
+ gboolean plug_mode;
+
+ /* Events */
+ int socket_id;
+ gboolean events_stdout;
+ GPtrArray* event_buffer;
+ gchar** connect_socket_names;
} State;
-/* networking */
+/* Networking */
typedef struct {
- SoupSession *soup_session;
- UzblCookieJar *soup_cookie_jar;
- SoupLogger *soup_logger;
- char *proxy_url;
- char *useragent;
- char *accept_languages;
- gint max_conns;
- gint max_conns_host;
+ SoupSession* soup_session;
+ UzblCookieJar* soup_cookie_jar;
+ SoupLogger* soup_logger;
+ char* proxy_url;
+ char* useragent;
+ char* accept_languages;
+ gint max_conns;
+ gint max_conns_host;
} Network;
-/* behaviour */
+/* Behaviour */
typedef struct {
/* Status bar */
gchar* status_format;
gchar* status_format_right;
gchar* status_background;
+ gboolean show_status;
+ gboolean status_top;
/* Window title */
gchar* title_format_short;
gchar* title_format_long;
+ /* Communication */
gchar* fifo_dir;
gchar* socket_dir;
- gchar* cookie_handler;
+
+ /* Handlers */
gchar* authentication_handler;
+ gchar* scheme_handler;
+ gchar* download_handler;
+
+ /* Fonts */
gchar* default_font_family;
gchar* monospace_font_family;
gchar* sans_serif_font_family;
gchar* serif_font_family;
gchar* fantasy_font_family;
gchar* cursive_font_family;
- gchar* scheme_handler;
- gchar* download_handler;
- gboolean show_status;
+
gboolean forward_keys;
- gboolean status_top;
- guint modmask;
guint http_debug;
gchar* shell_cmd;
guint view_source;
+
/* WebKitWebSettings exports */
guint font_size;
guint monospace_size;
@@ -168,58 +186,53 @@ typedef struct {
gchar* style_uri;
guint resizable_txt;
gchar* default_encoding;
+ gchar* current_encoding;
guint enforce_96dpi;
gchar *inject_html;
guint caret_browsing;
guint javascript_windows;
- guint mode;
- gchar* base_url;
gboolean print_version;
/* command list: (key)name -> (value)Command */
- /* command list: (key)name -> (value)Command */
GHashTable* commands;
+
/* event lookup: (key)event_id -> (value)event_name */
GHashTable *event_lookup;
} Behaviour;
-/* javascript */
-typedef struct {
- gboolean initialized;
- JSClassDefinition classdef;
- JSClassRef classref;
-} Javascript;
-/* static information */
+/* Static information */
typedef struct {
- int webkit_major;
- int webkit_minor;
- int webkit_micro;
- gchar *arch;
- gchar *commit;
- gchar *pid_str;
+ int webkit_major;
+ int webkit_minor;
+ int webkit_micro;
+ gchar* arch;
+ gchar* commit;
+ gchar* pid_str;
} Info;
-/* main uzbl data structure */
+
+/* Main uzbl data structure */
typedef struct {
GUI gui;
State state;
Network net;
Behaviour behave;
Communication comm;
- Javascript js;
Info info;
Window xwin;
} UzblCore;
-/* Main Uzbl object */
-extern UzblCore uzbl;
+extern UzblCore uzbl; /* Main Uzbl object */
+
typedef void sigfunc(int);
-/* uzbl variables */
-enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT};
+/* Uzbl variables */
+enum ptr_type {TYPE_INT = 1, TYPE_STR, TYPE_FLOAT,
+ TYPE_NAME, TYPE_FORMATTEDSTR // used by send_event
+};
typedef struct {
enum ptr_type type;
union {
@@ -233,262 +246,111 @@ typedef struct {
} uzbl_cmdprop;
/* Functions */
-char *
-itos(int val);
-
-gchar*
-strfree(gchar *str);
-
-void
-clean_up(void);
-
-void
-catch_sigterm(int s);
-
-sigfunc *
-setup_signal(int signe, sigfunc *shandler);
-
-gboolean
-set_var_value(const gchar *name, gchar *val);
-
-void
-load_uri_imp(gchar *uri);
-
-void
-print(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-commands_hash(void);
-
-void
-load_uri (WebKitWebView * web_view, GArray *argv, GString *result);
-
-void
-chain (WebKitWebView *page, GArray *argv, GString *result);
-
-void
-close_uzbl (WebKitWebView *page, GArray *argv, GString *result);
-
-gboolean
-run_command(const gchar *command, const gchar **args, const gboolean sync,
- char **output_stdout);
-
-void
-spawn_async(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
-spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
-spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
-spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
-spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result);
-
-void
-parse_command(const char *cmd, const char *param, GString *result);
-
-void
-parse_cmd_line(const char *ctl_line, GString *result);
-
-/*@null@*/ gchar*
-build_stream_name(int type, const gchar *dir);
-
-gboolean
-control_fifo(GIOChannel *gio, GIOCondition condition);
-
-/*@null@*/ gchar*
-init_fifo(gchar *dir);
-
-gboolean
-control_stdin(GIOChannel *gio, GIOCondition condition);
-
-void
-create_stdin();
-
-/*@null@*/ gchar*
-init_socket(gchar *dir);
-
-gboolean
-control_socket(GIOChannel *chan);
-
-gboolean
-control_client_socket(GIOChannel *chan);
-
-void
-update_title (void);
-
-gboolean
-key_press_cb (GtkWidget* window, GdkEventKey* event);
-
-gboolean
-key_release_cb (GtkWidget* window, GdkEventKey* event);
-
-void
-initialize (int argc, char *argv[]);
-
-void
-create_browser ();
-
-GtkWidget*
-create_mainbar ();
-
-GtkWidget*
-create_window ();
-
-GtkPlug*
-create_plug ();
-
-void
-run_handler (const gchar *act, const gchar *args);
-
-void
-settings_init ();
-
-void
-search_text (WebKitWebView *page, GArray *argv, const gboolean forward);
-
-void
-search_forward_text (WebKitWebView *page, GArray *argv, GString *result);
-
-void
-search_reverse_text (WebKitWebView *page, GArray *argv, GString *result);
-
-void
-search_clear(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-dehilight (WebKitWebView *page, GArray *argv, GString *result);
-
-void
-run_js (WebKitWebView * web_view, GArray *argv, GString *result);
-
-void
-run_external_js (WebKitWebView * web_view, GArray *argv, GString *result);
-
-void
-eval_js(WebKitWebView * web_view, gchar *script, GString *result, const gchar *script_file);
-
-void
-handle_authentication (SoupSession *session,
+void clean_up(void);
+void update_title(void);
+
+/* Signal management functions */
+void catch_sigterm(int s);
+sigfunc* setup_signal(int signe, sigfunc *shandler);
+
+gboolean set_var_value(const gchar *name, gchar *val);
+void load_uri_imp(gchar *uri);
+void print(WebKitWebView *page, GArray *argv, GString *result);
+void commands_hash(void);
+void load_uri(WebKitWebView * web_view, GArray *argv, GString *result);
+void chain(WebKitWebView *page, GArray *argv, GString *result);
+void close_uzbl(WebKitWebView *page, GArray *argv, GString *result);
+
+/* Running commands */
+gboolean run_command(const gchar *command, const gchar **args, const gboolean sync,
+ char **output_stdout);
+void spawn_async(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result);
+void spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result);
+void parse_command(const char *cmd, const char *param, GString *result);
+void parse_cmd_line(const char *ctl_line, GString *result);
+
+/* Keyboard events functions */
+gboolean key_press_cb(GtkWidget* window, GdkEventKey* event);
+gboolean key_release_cb(GtkWidget* window, GdkEventKey* event);
+
+/* Initialization functions */
+void initialize(int argc, char *argv[]);
+void create_scrolled_win();
+GtkWidget* create_mainbar();
+GtkWidget* create_window();
+GtkPlug* create_plug();
+void run_handler(const gchar *act, const gchar *args);
+void settings_init();
+
+/* Search functions */
+void search_text (WebKitWebView *page, GArray *argv, const gboolean forward);
+void search_forward_text (WebKitWebView *page, GArray *argv, GString *result);
+void search_reverse_text (WebKitWebView *page, GArray *argv, GString *result);
+void search_clear(WebKitWebView *page, GArray *argv, GString *result);
+void dehilight (WebKitWebView *page, GArray *argv, GString *result);
+
+/* Javascript functions */
+void run_js (WebKitWebView * web_view, GArray *argv, GString *result);
+void run_external_js (WebKitWebView * web_view, GArray *argv, GString *result);
+void eval_js(WebKitWebView * web_view, gchar *script, GString *result, const gchar *script_file);
+
+/* Network functions */
+void handle_authentication (SoupSession *session,
SoupMessage *msg,
SoupAuth *auth,
gboolean retrying,
gpointer user_data);
+gboolean valid_name(const gchar* name);
+void set_var(WebKitWebView *page, GArray *argv, GString *result);
+void act_dump_config();
+void act_dump_config_as_events();
+void dump_var_hash(gpointer k, gpointer v, gpointer ud);
+void dump_key_hash(gpointer k, gpointer v, gpointer ud);
+void dump_config();
+void dump_config_as_events();
+
+void retrieve_geometry();
+void set_webview_scroll_adjustments();
+void event(WebKitWebView *page, GArray *argv, GString *result);
+void init_connect_socket();
+gboolean remove_socket_from_array(GIOChannel *chan);
+
+gint get_click_context();
+void hardcopy(WebKitWebView *page, GArray *argv, GString *result);
+void include(WebKitWebView *page, GArray *argv, GString *result);
+void show_inspector(WebKitWebView *page, GArray *argv, GString *result);
+void add_cookie(WebKitWebView *page, GArray *argv, GString *result);
+void delete_cookie(WebKitWebView *page, GArray *argv, GString *result);
+void clear_cookies(WebKitWebView *pag, GArray *argv, GString *result);
+void builtins();
-void handle_cookies (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data);
-
-void
-set_var(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-act_dump_config();
-
-void
-act_dump_config_as_events();
-
-void
-dump_var_hash(gpointer k, gpointer v, gpointer ud);
-
-void
-dump_key_hash(gpointer k, gpointer v, gpointer ud);
-
-void
-dump_config();
-
-void
-dump_config_as_events();
-
-void
-retrieve_geometry();
-
-void
-set_webview_scroll_adjustments();
-
-void
-event(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-init_connect_socket();
-
-gboolean
-remove_socket_from_array(GIOChannel *chan);
-
-void
-menu_add(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_link(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_image(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_edit(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_separator(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_remove(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_remove_link(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_remove_image(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result);
-
-gint
-get_click_context();
-
-void
-hardcopy(WebKitWebView *page, GArray *argv, GString *result);
-
-void
-include(WebKitWebView *page, GArray *argv, GString *result);
+typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
-void
-show_inspector(WebKitWebView *page, GArray *argv, GString *result);
+typedef struct {
+ const gchar *key;
+ Command function;
+ gboolean no_split;
+} CommandInfo;
-void
-add_cookie(WebKitWebView *page, GArray *argv, GString *result);
+const CommandInfo *
+parse_command_parts(const gchar *line, GArray *a);
void
-delete_cookie(WebKitWebView *page, GArray *argv, GString *result);
+parse_command_arguments(const gchar *p, GArray *a, gboolean no_split);
void
-builtins();
-
-typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result);
+run_parsed_command(const CommandInfo *c, GArray *a, GString *result);
typedef struct {
- Command function;
- gboolean no_split;
-} CommandInfo;
-
-typedef struct {
- gchar *name;
- gchar *cmd;
+ gchar* name;
+ gchar* cmd;
gboolean issep;
- guint context;
+ guint context;
+ WebKitHitTestResult* hittest;
} MenuItem;
-
+#endif
/* vi: set et ts=4: */
diff --git a/tests/test-command.c b/tests/test-command.c
index 7b33405..6b55fb3 100644
--- a/tests/test-command.c
+++ b/tests/test-command.c
@@ -152,7 +152,7 @@ test_set_variable (struct EventFixture *ef, const void *data) {
/* set a string */
parse_cmd_line("set useragent = Uzbl browser kthxbye!", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET useragent str Uzbl browser kthxbye!");
+ ASSERT_EVENT(ef, "VARIABLE_SET useragent str 'Uzbl browser kthxbye!'");
g_assert_cmpstr("Uzbl browser kthxbye!", ==, uzbl.net.useragent);
/* set an int */
@@ -168,7 +168,7 @@ test_set_variable (struct EventFixture *ef, const void *data) {
parse_cmd_line(g_string_free(cmd, FALSE), NULL);
ev = g_string_new("EVENT [" INSTANCE_NAME "] VARIABLE_SET zoom_level float ");
- g_string_append_printf(ev, "%f\n", 0.25);
+ g_string_append_printf(ev, "%.2f\n", 0.25);
read_event(ef);
g_assert_cmpstr(g_string_free(ev, FALSE), ==, ef->event_buffer);
@@ -188,13 +188,13 @@ test_set_variable (struct EventFixture *ef, const void *data) {
/* set a custom variable */
parse_cmd_line("set nonexistant_variable = Some Value", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET nonexistant_variable str Some Value");
+ ASSERT_EVENT(ef, "VARIABLE_SET nonexistant_variable str 'Some Value'");
uzbl_cmdprop *c = g_hash_table_lookup(uzbl.comm.proto_var, "nonexistant_variable");
g_assert_cmpstr("Some Value", ==, *c->ptr.s);
/* set a custom variable with expansion */
parse_cmd_line("set an_expanded_variable = Test @(echo expansion)@", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET an_expanded_variable str Test expansion");
+ ASSERT_EVENT(ef, "VARIABLE_SET an_expanded_variable str 'Test expansion'");
c = g_hash_table_lookup(uzbl.comm.proto_var, "an_expanded_variable");
g_assert_cmpstr("Test expansion", ==, *c->ptr.s);
}
@@ -263,11 +263,12 @@ test_toggle_status (void) {
void
test_sync_sh (void) {
- parse_cmd_line("sync_sh 'echo Test echo.'", NULL);
- g_assert_cmpstr("Test echo.\n", ==, uzbl.comm.sync_stdout);
+ GString *result = g_string_new("");
+
+ parse_cmd_line("sync_sh 'echo Test echo.'", result);
+ g_assert_cmpstr("Test echo.\n", ==, result->str);
- /* clean up after ourselves */
- uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
+ g_string_free(result, TRUE);
}
void
@@ -281,27 +282,30 @@ test_js (void) {
g_string_free(result, TRUE);
}
+void test_uri(void) {
+ /* Testing for a crash, not crashing is a pass */
+ parse_cmd_line("uri", NULL);
+}
+
void
-test_run_handler_arg_order (void) {
- run_handler("sync_spawn echo uvw xyz", "abc def");
+test_last_result (void) {
+ GString *result = g_string_new("");
- assert(uzbl.comm.sync_stdout);
+ /* the last result gets set */
+ parse_cmd_line("js -1", result);
+ g_assert_cmpstr("-1", ==, uzbl.state.last_result);
- /* the rest of the result should be the arguments passed to run_handler. */
- /* the arguments in the second argument to run_handler should be placed before any
- * included in the first argument to run handler. */
- g_assert_cmpstr("abc def uvw xyz\n", ==, uzbl.comm.sync_stdout);
+ /* the last result can be used in a chain */
+ parse_cmd_line("chain 'js 1' 'js \\@_ + 1'", result);
+ g_assert_cmpstr("2", ==, uzbl.state.last_result);
+
+ g_string_free(result, TRUE);
}
void
-test_run_handler_expand (void) {
- uzbl.net.useragent = "Test uzbl uzr agent";
- run_handler("sync_spawn echo @useragent", "result:");
-
- assert(uzbl.comm.sync_stdout);
-
- /* the user-specified arguments to the handler should have been expanded */
- g_assert_cmpstr("result: Test uzbl uzr agent\n", ==, uzbl.comm.sync_stdout);
+test_no_such_command (void) {
+ parse_cmd_line("no-such-command", NULL);
+ /* if we didn't crash then we're ok! */
}
int
@@ -314,16 +318,16 @@ main (int argc, char *argv[]) {
g_test_add("/test-command/event", struct EventFixture, NULL, event_fixture_setup, test_event, event_fixture_teardown);
g_test_add_func("/test-command/print", test_print);
+ g_test_add_func("/test-command/uri", test_uri);
g_test_add_func("/test-command/scroll", test_scroll);
g_test_add_func("/test-command/toggle-status", test_toggle_status);
g_test_add_func("/test-command/sync-sh", test_sync_sh);
g_test_add_func("/test-command/js", test_js);
- /* the following aren't really "command" tests, but they're not worth
- * splitting into a separate file yet */
- g_test_add_func("/test-command/run_handler/arg-order", test_run_handler_arg_order);
- g_test_add_func("/test-command/run_handler/expand", test_run_handler_expand);
+ g_test_add_func("/test-command/last-result", test_last_result);
+
+ g_test_add_func("/test-command/no-such-command", test_no_such_command);
/* set up uzbl */
initialize(argc, argv);
@@ -331,7 +335,7 @@ main (int argc, char *argv[]) {
uzbl.state.config_file = "/tmp/uzbl-config";
uzbl.comm.fifo_path = "/tmp/some-nonexistant-fifo";
uzbl.comm.socket_path = "/tmp/some-nonexistant-socket";
- uzbl.state.uri = "http://example.org/";
+ uzbl.state.uri = g_strdup("http://example.org/");
uzbl.gui.main_title = "Example.Org";
uzbl.state.instance_name = INSTANCE_NAME;
diff --git a/tests/test-expand.c b/tests/test-expand.c
index 06e1619..d823cfa 100644
--- a/tests/test-expand.c
+++ b/tests/test-expand.c
@@ -23,6 +23,7 @@
#include <signal.h>
#include <src/uzbl-core.h>
+#include <src/util.h>
#include <src/config.h>
extern UzblCore uzbl;
@@ -65,14 +66,12 @@ test_useragent (void) {
void
test_WEBKIT_VERSION (void) {
- GString* expected = g_string_new("");
- g_string_append(expected, itos(webkit_major_version()));
- g_string_append(expected, " ");
- g_string_append(expected, itos(webkit_minor_version()));
- g_string_append(expected, " ");
- g_string_append(expected, itos(webkit_micro_version()));
+ gchar *expected = g_strdup_printf("%d %d %d", webkit_major_version(),
+ webkit_minor_version(),
+ webkit_micro_version());
- g_assert_cmpstr(expand("@WEBKIT_MAJOR @WEBKIT_MINOR @WEBKIT_MICRO", 0), ==, g_string_free(expected, FALSE));
+ g_assert_cmpstr(expand("@WEBKIT_MAJOR @WEBKIT_MINOR @WEBKIT_MICRO", 0), ==, expected);
+ g_free(expected);
}
void
@@ -86,26 +85,13 @@ test_COMMIT (void) {
}
void
-test_cmd_useragent_simple (void) {
- GString* expected = g_string_new("Uzbl (Webkit ");
- g_string_append(expected, itos(WEBKIT_MAJOR_VERSION));
- g_string_append(expected, ".");
- g_string_append(expected, itos(WEBKIT_MINOR_VERSION));
- g_string_append(expected, ".");
- g_string_append(expected, itos(WEBKIT_MICRO_VERSION));
- g_string_append(expected, ")");
-
- g_assert_cmpstr(expand("Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}.@{WEBKIT_MICRO})", 0), ==, g_string_free(expected, FALSE));
-}
-
-void
test_cmd_useragent_full (void) {
GString* expected = g_string_new("Uzbl (Webkit ");
- g_string_append(expected, itos(WEBKIT_MAJOR_VERSION));
+ g_string_append(expected, g_strdup_printf("%d", WEBKIT_MAJOR_VERSION));
g_string_append(expected, ".");
- g_string_append(expected, itos(WEBKIT_MINOR_VERSION));
+ g_string_append(expected, g_strdup_printf("%d", WEBKIT_MINOR_VERSION));
g_string_append(expected, ".");
- g_string_append(expected, itos(WEBKIT_MICRO_VERSION));
+ g_string_append(expected, g_strdup_printf("%d", WEBKIT_MICRO_VERSION));
g_string_append(expected, ") (");
struct utsname unameinfo;
@@ -187,7 +173,6 @@ main (int argc, char *argv[]) {
g_test_add_func("/test-expand/@ARCH_UZBL", test_ARCH_UZBL);
g_test_add_func("/test-expand/@COMMIT", test_COMMIT);
- g_test_add_func("/test-expand/cmd_useragent_simple", test_cmd_useragent_simple);
g_test_add_func("/test-expand/cmd_useragent_full", test_cmd_useragent_full);
g_test_add_func("/test-expand/escape_markup", test_escape_markup);