aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/config/config47
-rw-r--r--examples/config/style.css (renamed from examples/data/style.css)15
-rw-r--r--examples/data/plugins/bind.py8
-rw-r--r--examples/data/plugins/history.py2
-rw-r--r--examples/data/plugins/keycmd.py218
-rwxr-xr-xexamples/data/scripts/auth.py2
-rwxr-xr-xexamples/data/scripts/download.sh60
-rw-r--r--examples/data/scripts/follow.js15
-rwxr-xr-xexamples/data/scripts/follow.sh14
-rwxr-xr-xexamples/data/scripts/formfiller.sh12
-rwxr-xr-xexamples/data/scripts/go_input.sh6
-rwxr-xr-xexamples/data/scripts/history.sh6
-rwxr-xr-xexamples/data/scripts/insert_bookmark.sh11
-rwxr-xr-xexamples/data/scripts/insert_temp.sh7
-rwxr-xr-xexamples/data/scripts/instance-select-wmii.sh25
-rwxr-xr-xexamples/data/scripts/load_cookies.sh17
-rwxr-xr-xexamples/data/scripts/load_url_from_bookmarks.sh10
-rwxr-xr-xexamples/data/scripts/load_url_from_history.sh13
-rwxr-xr-xexamples/data/scripts/load_url_from_temps.sh22
-rwxr-xr-xexamples/data/scripts/session.sh28
-rw-r--r--examples/data/scripts/util/dmenu.sh9
-rw-r--r--examples/data/scripts/util/uzbl-dir.sh19
-rw-r--r--examples/data/scripts/util/uzbl-window.sh16
-rwxr-xr-xexamples/data/scripts/uzbl-event-manager991
-rwxr-xr-xexamples/data/scripts/uzbl-tabbed1404
25 files changed, 293 insertions, 2684 deletions
diff --git a/examples/config/config b/examples/config/config
index bcd6d3e..8c706df 100644
--- a/examples/config/config
+++ b/examples/config/config
@@ -4,9 +4,10 @@
# === Core settings ==========================================================
# common directory locations
-set prefix = @(echo $PREFIX)@
-set data_home = @(echo $XDG_DATA_HOME)@
-set cache_home = @(echo $XDG_CACHE_HOME)@
+set prefix = @(echo $PREFIX)@
+set data_home = @(echo $XDG_DATA_HOME)@
+set cache_home = @(echo $XDG_CACHE_HOME)@
+set config_home = @(echo $XDG_CONFIG_HOME)@
# Interface paths.
set fifo_dir = /tmp
@@ -90,12 +91,12 @@ 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 p='--';if(%3!=%2){p=(%1/(%3-%4));p=Math.round(10000*p)/100;};return p+'%';})()>\@
+@on_event SCROLL_VERT set scroll_message = \@<(function(){var p='--';if(%3<=%4){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 stylesheet_uri = file://@config_home/uzbl/style.css
set show_status = 1
set status_top = 0
@@ -153,15 +154,11 @@ set useragent = Uzbl (Webkit @{WEBKIT_MAJOR}.@{WEBKIT_MINOR}) (@(+uname
@modmap <space> <Space>
@modmap <KP_Enter> <Enter>
-#modkey_addition <Key1> <Key2> <Result>
-@modkey_addition <Shift> <Ctrl> <Meta>
-@modkey_addition <Shift> <Tab> <Shift-Tab>
-@modkey_addition <Shift> <Insert> <Shift-Insert>
-
#ignore_key <glob>
@ignore_key <ISO_*>
@ignore_key <Shift>
@ignore_key <Multi_key>
+@ignore_key <Mod2>
# --- Bind aliases -----------------------------------------------------------
@@ -185,6 +182,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
+@on_event ESCAPE js uzbl.follow.clearHints()
@bind <Escape> = event ESCAPE
@bind <Ctrl>[ = event ESCAPE
@@ -198,7 +196,7 @@ set ebind = @mode_bind global,-insert
@ebind <Delete> = event KEYCMD_DELETE
@ebind <Tab> = event START_COMPLETION
# Readline-ish bindings.
-@ebind <Ctrl>w = event KEYCMD_STRIP_WORD
+@ebind <Ctrl>w = event KEYCMD_STRIP_WORD \ -./&?=
@ebind <Ctrl>u = event SET_KEYCMD
@ebind <Ctrl>a = event SET_CURSOR_POS 0
@ebind <Ctrl>e = event SET_CURSOR_POS -1
@@ -267,6 +265,9 @@ set ebind = @mode_bind global,-insert
@cbind n = search
@cbind N = search_reverse
+# Print pages to a printer
+@cbind  <Ctrl>p = hardcopy
+
# Web searching binds
@cbind gg<Google:>_ = uri http://www.google.com/search?q=\@<encodeURIComponent(%r)>\@
@cbind ddg<DuckDuckGo:>_ = uri http://duckduckgo.com/?q=%s
@@ -285,8 +286,8 @@ set ebind = @mode_bind global,-insert
# Use socat to directly inject commands into uzbl-core and view events
# raised by uzbl-core:
-@cbind <Ctrl><Alt>t = sh 'xterm -e "socat unix-connect:\"$UZBL_SOCKET\" -"'
-#@cbind <Ctrl><Alt>t = sh 'urxvt -e socat unix-connect:"$UZBL_SOCKET" -'
+@cbind <Ctrl><Mod1>t = sh 'xterm -e "socat unix-connect:\"$UZBL_SOCKET\" -"'
+#@cbind <Ctrl><Mod1>t = sh 'urxvt -e socat unix-connect:"$UZBL_SOCKET" -'
# Uri opening prompts
@cbind o<uri:>_ = uri %s
@@ -300,6 +301,13 @@ set ebind = @mode_bind global,-insert
# Hard-bound bookmarks
@cbind gh = uri http://www.uzbl.org
+# New window binds
+@cbind gw = event REQ_NEW_WINDOW
+
+# SSL-ify bindings
+@cbind zs = uri \@(echo "$UZBL_URI" | sed -e 's/^http:/https:/')\@
+@cbind zS = event REQ_NEW_WINDOW \@(echo "$UZBL_URI" | sed -e 's/^http:/https:/')\@
+
# Yanking & pasting binds
@cbind yu = sh 'echo -n "$UZBL_URI" | xclip'
@cbind yU = sh 'echo -n "$1" | xclip' \@SELECTED_URI
@@ -314,7 +322,7 @@ set ebind = @mode_bind global,-insert
# Start a new uzbl instance from the page in primary selection
@cbind 'p = sh 'echo "event REQ_NEW_WINDOW $(xclip -o)" > "$UZBL_FIFO"'
# paste primary selection into keycmd at the cursor position
-@bind <Shift-Insert> = sh 'echo "event INJECT_KEYCMD $(xclip -o | sed s/\\\@/%40/g)" > "$UZBL_FIFO"'
+@bind <Shift><Insert> = sh 'echo "event INJECT_KEYCMD $(xclip -o | sed s/\\\@/%40/g)" > "$UZBL_FIFO"'
# Bookmark inserting binds
@cbind <Ctrl>b<tags:>_ = sh 'echo `printf "$UZBL_URI %s"` >> "$XDG_DATA_HOME"/uzbl/bookmarks'
@@ -325,6 +333,10 @@ set ebind = @mode_bind global,-insert
@cbind U = spawn @scripts_dir/load_url_from_history.sh
@cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh
+# Temporary bookmarks
+@cbind <Ctrl>d = spawn @scripts_dir/insert_temp.sh
+@cbind D = spawn @scripts_dir/load_url_from_temps.sh
+
# Link following (similar to vimperator and konqueror)
# Set custom keys you wish to use for navigation. Some common examples:
set follow_hint_keys = 0123456789
@@ -333,7 +345,7 @@ set follow_hint_keys = 0123456789
#set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234
@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
+@cbind fi = spawn @scripts_dir/go_input.sh
# Form filler binds
# This script allows you to configure (per domain) values to fill in form
@@ -341,10 +353,10 @@ set follow_hint_keys = 0123456789
# This implementation allows you to save multiple profiles for each form
# (think about multiple accounts on some website).
set formfiller = spawn @scripts_dir/formfiller.sh
-@cbind za = @formfiller add
@cbind ze = @formfiller edit
@cbind zn = @formfiller new
@cbind zl = @formfiller load
+@cbind zo = @formfiller once
# --- Uzbl tabbed binds ------------------------------------------------------
@@ -370,7 +382,8 @@ set preset = event PRESET_TABS
@cbind gs<preset save:>_ = @preset save %s
@cbind glo<preset load:>_ = @preset load %s
@cbind gd<preset del:>_ = @preset del %s
-@cbind gli = @preset list
+# This doesn't work right now.
+#@cbind gli = @preset list
# === Context menu items =====================================================
diff --git a/examples/data/style.css b/examples/config/style.css
index ff055d1..a368aa0 100644
--- a/examples/data/style.css
+++ b/examples/config/style.css
@@ -1,12 +1,11 @@
#uzbl_link_hints > span {
z-index: 1000 !important;
- background-color: #aaff00 !important;
- border: 2px solid #556600 !important;
- margin: 0 !important;
- padding: 1px !important;
+ background-color: #333 !important;
+ margin: 0 !important;
+ padding: 3px !important;
- color: black !important;
+ color: #ccc !important;
font-size: 9px !important;
line-height: 9px !important;
font-weight: bold !important;
@@ -14,12 +13,16 @@
text-decoration: none !important;
-webkit-transform: translate(-5px,-5px);
- /* opacity: 0.7; */
+ opacity: 0.8;
+ -webkit-border-radius: 6px !important;
+ /* Play around with this, pretty fun things to do :) */
+ /* -webkit-transform: scale(1) rotate(0deg) translate(-6px,-5px) !important; */
}
/* we can have different colours for different types of hints! */
#uzbl_link_hints.new-window > span {
background-color: #ffff00 !important;
+ color: black !important;
}
/* vim:set et ts=4: */
diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py
index 69fd863..fc8b392 100644
--- a/examples/data/plugins/bind.py
+++ b/examples/data/plugins/bind.py
@@ -372,11 +372,11 @@ def mode_changed(uzbl, mode):
uzbl.bindlet.reset()
-def match_and_exec(uzbl, bind, depth, keylet, bindlet):
+def match_and_exec(uzbl, bind, depth, modstate, keylet, bindlet):
(on_exec, has_args, mod_cmd, glob, more) = bind[depth]
cmd = keylet.modcmd if mod_cmd else keylet.keycmd
- if mod_cmd and keylet.held != mod_cmd:
+ if mod_cmd and modstate != mod_cmd:
return False
if has_args:
@@ -415,7 +415,7 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet):
return True
-def key_event(uzbl, keylet, mod_cmd=False, on_exec=False):
+def key_event(uzbl, modstate, keylet, mod_cmd=False, on_exec=False):
bindlet = uzbl.bindlet
depth = bindlet.depth
for bind in bindlet.get_binds():
@@ -423,7 +423,7 @@ def key_event(uzbl, keylet, mod_cmd=False, on_exec=False):
if (bool(t[MOD_CMD]) != mod_cmd) or (t[ON_EXEC] != on_exec):
continue
- if match_and_exec(uzbl, bind, depth, keylet, bindlet):
+ if match_and_exec(uzbl, bind, depth, modstate, keylet, bindlet):
return
bindlet.after()
diff --git a/examples/data/plugins/history.py b/examples/data/plugins/history.py
index 5e9e4e1..f42f86f 100644
--- a/examples/data/plugins/history.py
+++ b/examples/data/plugins/history.py
@@ -83,7 +83,7 @@ class History(object):
def __str__(self):
return "(History %s, %s)" % (self.cursor, self.prompt)
-def keycmd_exec(uzbl, keylet):
+def keycmd_exec(uzbl, modstate, keylet):
cmd = keylet.get_keycmd()
if cmd:
uzbl.history.add(cmd)
diff --git a/examples/data/plugins/keycmd.py b/examples/data/plugins/keycmd.py
index 928c597..1bb70e3 100644
--- a/examples/data/plugins/keycmd.py
+++ b/examples/data/plugins/keycmd.py
@@ -17,13 +17,10 @@ def uzbl_escape(str):
class Keylet(object):
- '''Small per-instance object that tracks all the keys held and characters
- typed.'''
+ '''Small per-instance object that tracks characters typed.'''
def __init__(self):
# Modcmd tracking
- self.held = set()
- self.ignored = set()
self.modcmd = ''
self.is_modcmd = False
@@ -33,7 +30,6 @@ class Keylet(object):
self.modmaps = {}
self.ignores = {}
- self.additions = {}
def get_keycmd(self):
@@ -48,7 +44,7 @@ class Keylet(object):
if not self.is_modcmd:
return ''
- return ''.join(self.held) + self.modcmd
+ return self.modcmd
def modmap_key(self, key):
@@ -65,28 +61,6 @@ class Keylet(object):
return key
- def find_addition(self, modkey):
- '''Key has just been pressed, check if this key + the held list
- results in a modkey addition. Return that addition and remove all
- modkeys that created it.'''
-
- # Intersection of (held list + modkey) and additions.
- added = (self.held | set([modkey])) & set(self.additions.keys())
- for key in added:
- if key == modkey or modkey in self.additions[key]:
- self.held -= self.additions[key]
- return key
-
- # Held list + ignored list + modkey.
- modkeys = self.held | self.ignored | set([modkey])
- for (key, value) in self.additions.items():
- if modkeys.issuperset(value):
- self.held -= value
- return key
-
- return modkey
-
-
def key_ignored(self, key):
'''Check if the given key is ignored by any ignore rules.'''
@@ -104,9 +78,6 @@ class Keylet(object):
if self.is_modcmd:
l.append('modcmd=%r' % self.get_modcmd())
- elif self.held:
- l.append('held=%r' % ''.join(sorted(self.held)))
-
if self.keycmd:
l.append('keycmd=%r' % self.get_keycmd())
@@ -132,10 +103,7 @@ def add_modmap(uzbl, key, map):
assert len(key)
modmaps = uzbl.keylet.modmaps
- if key[0] == "<" and key[-1] == ">":
- key = key[1:-1]
-
- modmaps[key] = map
+ modmaps[key.strip('<>')] = map.strip('<>')
uzbl.event("NEW_MODMAP", key, map)
@@ -171,45 +139,6 @@ def add_key_ignore(uzbl, glob):
uzbl.event('NEW_KEY_IGNORE', glob)
-def add_modkey_addition(uzbl, modkeys, result):
- '''Add a modkey addition definition.
-
- Examples:
- set mod_addition = request MODKEY_ADDITION
- @mod_addition <Shift> <Control> <Meta>
- @mod_addition <Left> <Up> <Left-Up>
- @mod_addition <Right> <Up> <Right-Up>
- ...
-
- Then:
- @bind <Right-Up> = <command1>
- @bind <Meta>o = <command2>
- ...
- '''
-
- additions = uzbl.keylet.additions
- modkeys = set(modkeys)
-
- assert len(modkeys) and result and result not in modkeys
-
- for (existing_result, existing_modkeys) in additions.items():
- if existing_result != result:
- assert modkeys != existing_modkeys
-
- additions[result] = modkeys
- uzbl.event('NEW_MODKEY_ADDITION', modkeys, result)
-
-
-def modkey_addition_parse(uzbl, modkeys):
- '''Parse modkey addition definition.'''
-
- keys = filter(None, map(unicode.strip, modkeys.split(" ")))
- keys = ['<%s>' % key.strip("<>") for key in keys if key.strip("<>")]
-
- assert len(keys) > 1
- add_modkey_addition(uzbl, keys[:-1], keys[-1])
-
-
def clear_keycmd(uzbl, *args):
'''Clear the keycmd for this uzbl instance.'''
@@ -220,15 +149,12 @@ def clear_keycmd(uzbl, *args):
uzbl.event('KEYCMD_CLEARED')
-def clear_modcmd(uzbl, clear_held=False):
+def clear_modcmd(uzbl):
'''Clear the modcmd for this uzbl instance.'''
k = uzbl.keylet
k.modcmd = ''
k.is_modcmd = False
- if clear_held:
- k.ignored = set()
- k.held = set()
del uzbl.config['modcmd']
uzbl.event('MODCMD_CLEARED')
@@ -244,28 +170,22 @@ def clear_current(uzbl):
clear_keycmd(uzbl)
-def focus_changed(uzbl, *args):
- '''Focus to the uzbl instance has now been lost which means all currently
- held keys in the held list will not get a KEY_RELEASE event so clear the
- entire held list.'''
-
- clear_modcmd(uzbl, clear_held=True)
-
-
-def update_event(uzbl, k, execute=True):
+def update_event(uzbl, modstate, k, execute=True):
'''Raise keycmd & modcmd update events.'''
- keycmd, modcmd = k.get_keycmd(), k.get_modcmd()
+ keycmd, modcmd = k.get_keycmd(), ''.join(modstate) + k.get_modcmd()
if k.is_modcmd:
- uzbl.event('MODCMD_UPDATE', k)
+ logger.debug('modcmd_update, %s' % modcmd)
+ uzbl.event('MODCMD_UPDATE', modstate, k)
else:
- uzbl.event('KEYCMD_UPDATE', k)
+ logger.debug('keycmd_update, %s' % keycmd)
+ uzbl.event('KEYCMD_UPDATE', modstate, k)
if uzbl.config.get('modcmd_updates', '1') == '1':
- new_modcmd = k.get_modcmd()
- if not new_modcmd:
+ new_modcmd = ''.join(modstate) + k.get_modcmd()
+ if not new_modcmd or not k.is_modcmd:
del uzbl.config['modcmd']
elif new_modcmd == modcmd:
@@ -293,54 +213,38 @@ def inject_str(str, index, inj):
return "%s%s%s" % (str[:index], inj, str[index:])
-def get_keylet_and_key(uzbl, key, add=True):
- '''Return the keylet and apply any transformations to the key as defined
- by the modmapping or modkey addition rules. Return None if the key is
- ignored.'''
-
+def parse_key_event(uzbl, key):
+ ''' Build a set from the modstate part of the event, and pass all keys through modmap '''
keylet = uzbl.keylet
- key = keylet.modmap_key(key)
- if len(key) == 1:
- return (keylet, key)
-
- modkey = "<%s>" % key.strip("<>")
-
- if keylet.key_ignored(modkey):
- if add:
- keylet.ignored.add(modkey)
-
- elif modkey in keylet.ignored:
- keylet.ignored.remove(modkey)
- modkey = keylet.find_addition(modkey)
-
- if keylet.key_ignored(modkey):
- return (keylet, None)
-
- return (keylet, modkey)
+ modstate, key = splitquoted(key)
+ modstate = set(['<%s>' % keylet.modmap_key(k) for k in modstate.split('|') if k])
+
+ key = keylet.modmap_key(key)
+ return modstate, key
def key_press(uzbl, key):
'''Handle KEY_PRESS events. Things done by this function include:
1. Ignore all shift key presses (shift can be detected by capital chars)
- 3. In non-modcmd mode:
+ 2. In non-modcmd mode:
a. append char to keycmd
- 4. If not in modcmd mode and a modkey was pressed set modcmd mode.
- 5. If in modcmd mode the pressed key is added to the held keys list.
- 6. Keycmd is updated and events raised if anything is changed.'''
+ 3. If not in modcmd mode and a modkey was pressed set modcmd mode.
+ 4. Keycmd is updated and events raised if anything is changed.'''
- (k, key) = get_keylet_and_key(uzbl, key.strip())
- if not key:
- return
+ k = uzbl.keylet
+ modstate, key = parse_key_event(uzbl, key)
+ k.is_modcmd = any(not k.key_ignored(m) for m in modstate)
- if key.lower() == '<space>' and not k.held and k.keycmd:
+ logger.debug('key press modstate=%s' % str(modstate))
+ if key.lower() == 'space' and not k.is_modcmd and k.keycmd:
k.keycmd = inject_str(k.keycmd, k.cursor, ' ')
k.cursor += 1
- elif not k.held and len(key) == 1:
-
+ elif not k.is_modcmd and len(key) == 1:
if uzbl.config.get('keycmd_events', '1') != '1':
+ # TODO, make a note on what's going on here
k.keycmd = ''
k.cursor = 0
del uzbl.config['keycmd']
@@ -349,33 +253,29 @@ def key_press(uzbl, key):
k.keycmd = inject_str(k.keycmd, k.cursor, key)
k.cursor += 1
- elif len(key) > 1:
- k.is_modcmd = True
- if key not in k.held:
- k.held.add(key)
+ elif len(key) == 1:
+ k.modcmd += key
else:
- k.is_modcmd = True
- k.modcmd += key
+ if not k.key_ignored('<%s>' % key):
+ modstate.add('<%s>' % key)
+ k.is_modcmd = True
- update_event(uzbl, k)
+ update_event(uzbl, modstate, k)
def key_release(uzbl, key):
'''Respond to KEY_RELEASE event. Things done by this function include:
- 1. Remove the key from the keylet held list.
- 2. If in a mod-command then raise a MODCMD_EXEC.
- 3. Check if any modkey is held, if so set modcmd mode.
- 4. Update the keycmd uzbl variable if anything changed.'''
-
- (k, key) = get_keylet_and_key(uzbl, key.strip(), add=False)
+ 1. If in a mod-command then raise a MODCMD_EXEC.
+ 2. Update the keycmd uzbl variable if anything changed.'''
+ k = uzbl.keylet
+ modstate, key = parse_key_event(uzbl, key)
- if key in k.held:
+ if len(key) > 1:
if k.is_modcmd:
- uzbl.event('MODCMD_EXEC', k)
+ uzbl.event('MODCMD_EXEC', modstate, k)
- k.held.remove(key)
clear_modcmd(uzbl)
@@ -385,7 +285,7 @@ def set_keycmd(uzbl, keycmd):
k = uzbl.keylet
k.keycmd = keycmd
k.cursor = len(keycmd)
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
def inject_keycmd(uzbl, keycmd):
@@ -394,7 +294,7 @@ def inject_keycmd(uzbl, keycmd):
k = uzbl.keylet
k.keycmd = inject_str(k.keycmd, k.cursor, keycmd)
k.cursor += len(keycmd)
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
def append_keycmd(uzbl, keycmd):
@@ -403,23 +303,29 @@ def append_keycmd(uzbl, keycmd):
k = uzbl.keylet
k.keycmd += keycmd
k.cursor = len(k.keycmd)
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
-def keycmd_strip_word(uzbl, sep):
+def keycmd_strip_word(uzbl, seps):
''' Removes the last word from the keycmd, similar to readline ^W '''
- sep = sep or ' '
+ seps = seps or ' '
k = uzbl.keylet
if not k.keycmd:
return
- head, tail = k.keycmd[:k.cursor].rstrip(sep), k.keycmd[k.cursor:]
- rfind = head.rfind(sep)
+ head, tail = k.keycmd[:k.cursor].rstrip(seps), k.keycmd[k.cursor:]
+ rfind = -1
+ for sep in seps:
+ p = head.rfind(sep)
+ if p >= 0 and rfind < p + 1:
+ rfind = p + 1
+ if rfind == len(head) and head[-1] in seps:
+ rfind -= 1
head = head[:rfind] if rfind + 1 else ''
k.keycmd = head + tail
k.cursor = len(head)
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
def keycmd_backspace(uzbl, *args):
@@ -431,7 +337,7 @@ def keycmd_backspace(uzbl, *args):
k.keycmd = k.keycmd[:k.cursor-1] + k.keycmd[k.cursor:]
k.cursor -= 1
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
def keycmd_delete(uzbl, *args):
@@ -442,14 +348,14 @@ def keycmd_delete(uzbl, *args):
return
k.keycmd = k.keycmd[:k.cursor] + k.keycmd[k.cursor+1:]
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
def keycmd_exec_current(uzbl, *args):
'''Raise a KEYCMD_EXEC with the current keylet and then clear the
keycmd.'''
- uzbl.event('KEYCMD_EXEC', uzbl.keylet)
+ uzbl.event('KEYCMD_EXEC', set(), uzbl.keylet)
clear_keycmd(uzbl)
@@ -476,7 +382,7 @@ def set_cursor_pos(uzbl, index):
cursor = len(k.keycmd)
k.cursor = cursor
- update_event(uzbl, k, False)
+ update_event(uzbl, set(), k, False)
# plugin init hook
@@ -485,8 +391,6 @@ def init(uzbl):
connect_dict(uzbl, {
'APPEND_KEYCMD': append_keycmd,
- 'FOCUS_GAINED': focus_changed,
- 'FOCUS_LOST': focus_changed,
'IGNORE_KEY': add_key_ignore,
'INJECT_KEYCMD': inject_keycmd,
'KEYCMD_BACKSPACE': keycmd_backspace,
@@ -496,7 +400,8 @@ def init(uzbl):
'KEYCMD_CLEAR': clear_keycmd,
'KEY_PRESS': key_press,
'KEY_RELEASE': key_release,
- 'MODKEY_ADDITION': modkey_addition_parse,
+ 'MOD_PRESS': key_press,
+ 'MOD_RELEASE': key_release,
'MODMAP': modmap_parse,
'SET_CURSOR_POS': set_cursor_pos,
'SET_KEYCMD': set_keycmd,
@@ -504,7 +409,6 @@ def init(uzbl):
export_dict(uzbl, {
'add_key_ignore': add_key_ignore,
- 'add_modkey_addition': add_modkey_addition,
'add_modmap': add_modmap,
'append_keycmd': append_keycmd,
'clear_current': clear_current,
diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py
index 592a2c6..49fa41e 100755
--- a/examples/data/scripts/auth.py
+++ b/examples/data/scripts/auth.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
import gtk
import sys
diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh
index c410ad2..dbc9caf 100755
--- a/examples/data/scripts/download.sh
+++ b/examples/data/scripts/download.sh
@@ -1,25 +1,63 @@
#!/bin/sh
-#
# uzbl's example configuration sets this script up as its download_handler.
-# when uzbl starts a download it runs this script.
+# this script is run when uzbl encounters a URL that it can't display, and when
+# a download is requested using the 'download' command.
+#
# if the script prints a file path to stdout, uzbl will save the download to
-# that path.
-# if nothing is printed to stdout, the download will be cancelled.
+# that path using it's internal downloader.
+#
+# if nothing is printed to stdout, the internal download will be cancelled.
+# you could do your own download handling in your script that way.
-. $UZBL_UTIL_DIR/uzbl-dir.sh
+# if $5 is set, it is the path that was passed to uzbl's "download" command.
+# we want to use that if it's available.
+[ -n "$5" ] && echo "$5" && exit
+
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
# the URL that is being downloaded
-uri=$1
+uri="$1"
+shift
+
+safe_uri="$( echo "$uri" | sed -e 's/\W/-/g' )"
# a filename suggested by the server or based on the URL
-suggested_filename=${2:-$(echo "$uri" | sed 's/\W/-/g')}
+suggested_filename="${1:-$safe_uri}"
+shift
# the mimetype of the file being downloaded
-content_type=$3
+content_type="$1"
+shift
# the size of the downloaded file in bytes. this is not always accurate, since
# the server might not have sent a size with its response headers.
-total_size=$4
+total_size="$1"
+shift
+
+case "$suggested_filename" in
+ # example: save torrents to a separate directory
+ #*.torrent)
+ # path="$UZBL_DOWNLOAD_DIR/torrents/$suggested_filename"
+ # ;;
+ # Default case
+ *)
+ path="$UZBL_DOWNLOAD_DIR/$suggested_filename"
+ ;;
+esac
+
+# Do nothing if we don't want to save the file
+[ -z "$path" ] && exit 0
+
+# Check if the file exists
+if [ ! -e "$path" ]; then
+ echo "$path"
+ exit 0
+fi
+
+# Try to make a unique filename
+count=1
+while [ -e "$path.$count" ]; do
+ count=$(( $count + 1 ))
+done
-# just save the file to the default directory with the suggested name
-echo $UZBL_DOWNLOAD_DIR/$suggested_filename
+echo "$path.$count"
diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js
index 536256b..b7b0d82 100644
--- a/examples/data/scripts/follow.js
+++ b/examples/data/scripts/follow.js
@@ -98,12 +98,17 @@ uzbl.follow.elementInViewport = function(el) {
}
// Removes all hints/leftovers that might be generated
-// by this script.
-uzbl.follow.removeAllHints = function(doc) {
+// by this script in the given document.
+uzbl.follow.removeHints = function(doc) {
var elements = doc.getElementById(uzbldivid);
if (elements) elements.parentNode.removeChild(elements);
}
+// Clears all hints in every document
+uzbl.follow.clearHints = function() {
+ this.documents().forEach(uzbl.follow.removeHints);
+}
+
// 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) {
@@ -153,7 +158,7 @@ uzbl.follow.reDrawHints = function(elems, chars) {
var positions = elements.map(uzbl.follow.elementPosition);
this.documents().forEach(function(doc) {
- uzbl.follow.removeAllHints(doc);
+ uzbl.follow.removeHints(doc);
if (!doc.body) return;
doc.hintdiv = doc.createElement('div');
doc.hintdiv.id = uzbldivid;
@@ -211,7 +216,7 @@ uzbl.follow.followLinks = function(follow) {
var s = follow.split('');
var linknr = this.labelToInt(follow);
- var followable = 'a, area, textarea, select, input:not([type=hidden]), button';
+ var followable = 'a, area, textarea, select, input:not([type=hidden]), button, *[onclick]';
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]';
@@ -230,7 +235,7 @@ uzbl.follow.followLinks = function(follow) {
var el = elems[linknr];
// clear all of our hints
- this.documents().forEach(uzbl.follow.removeAllHints);
+ this.clearHints();
if (newwindow) {
// we're opening a new window using the URL attached to this element
diff --git a/examples/data/scripts/follow.sh b/examples/data/scripts/follow.sh
index 1f8947d..014793e 100755
--- a/examples/data/scripts/follow.sh
+++ b/examples/data/scripts/follow.sh
@@ -2,10 +2,12 @@
# This scripts acts on the return value of followLinks in follow.js
case "$1" in
- XXXEMIT_FORM_ACTIVEXXX)
- # a form element was selected
- printf 'event FORM_ACTIVE\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO" ;;
- XXXRESET_MODEXXX)
- # a link was selected, reset uzbl's input mode
- printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO" ;;
+ XXXEMIT_FORM_ACTIVEXXX)
+ # a form element was selected
+ printf 'event FORM_ACTIVE\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
+ ;;
+ XXXRESET_MODEXXX)
+ # a link was selected, reset uzbl's input mode
+ printf 'set mode=\nevent KEYCMD_CLEAR\n' > "$UZBL_FIFO"
+ ;;
esac
diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh
index 3dc9dc4..c1171a0 100755
--- a/examples/data/scripts/formfiller.sh
+++ b/examples/data/scripts/formfiller.sh
@@ -66,22 +66,22 @@ ParseFields ()
field = $0
sub ( /[^:]*:/, "", field )
- if ( parts[2] ~ /(text|password|search)/ )
+ 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)/ )
+ 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" ) {
+ else if ( parts[2] ~ /^textarea$/ ) {
field = ""
while (getline) {
if ( /^%/ ) break
sub ( /^\\/, "" )
gsub ( /"/, "\\\"" )
gsub ( /\\/, "\\\\" )
- field = field $0 "\\n"
+ field = field $0 "\\\\n"
}
printf( "js uzbl.formfiller.insert(\"%s\",\"%s\",\"%s\",0);\n",
parts[1], parts[2], field )
@@ -116,7 +116,7 @@ Load ()
ParseProfile $option < "$file" \
| ParseFields \
- | sed 's/@/\\@/' \
+ | sed 's/@/\\@/g' \
> "$UZBL_FIFO"
}
@@ -132,7 +132,7 @@ Once ()
test -e "$tmpfile" &&
ParseFields < "$tmpfile" \
- | sed 's/@/\\@' \
+ | sed 's/@/\\@/g' \
> "$UZBL_FIFO"
}
diff --git a/examples/data/scripts/go_input.sh b/examples/data/scripts/go_input.sh
index ace0e79..9797788 100755
--- a/examples/data/scripts/go_input.sh
+++ b/examples/data/scripts/go_input.sh
@@ -1,5 +1,7 @@
#!/bin/sh
-case $(echo 'script @scripts_dir/go_input.js' | socat - unix-connect:"$UZBL_SOCKET") in
- *XXXEMIT_FORM_ACTIVEXXX*) echo 'event FORM_ACTIVE' > "$UZBL_FIFO" ;;
+case "$( echo "script @scripts_dir/go_input.js" | socat - "unix-connect:$UZBL_SOCKET" )" in
+ *XXXEMIT_FORM_ACTIVEXXX*)
+ echo "event FORM_ACTIVE" > "$UZBL_FIFO"
+ ;;
esac
diff --git a/examples/data/scripts/history.sh b/examples/data/scripts/history.sh
index 266d65d..0709b5e 100755
--- a/examples/data/scripts/history.sh
+++ b/examples/data/scripts/history.sh
@@ -1,7 +1,7 @@
#!/bin/sh
-. $UZBL_UTIL_DIR/uzbl-dir.sh
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
-[ -w "$UZBL_HISTORY_FILE" ] || [ ! -a "$UZBL_HISTORY_FILE" ] || exit 1
+>> "$UZBL_HISTORY_FILE" || exit 1
-echo $(date +'%Y-%m-%d %H:%M:%S')" $UZBL_URI $UZBL_TITLE" >> $UZBL_HISTORY_FILE
+echo "$( date +'%Y-%m-%d %H:%M:%S' ) $UZBL_URI $UZBL_TITLE" >> "$UZBL_HISTORY_FILE"
diff --git a/examples/data/scripts/insert_bookmark.sh b/examples/data/scripts/insert_bookmark.sh
index f67e67a..f310e49 100755
--- a/examples/data/scripts/insert_bookmark.sh
+++ b/examples/data/scripts/insert_bookmark.sh
@@ -1,15 +1,14 @@
#!/bin/sh
-. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
-[ -d "$UZBL_DATA_DIR" ] || exit 1
-[ -w "$UZBL_BOOKMARKS_FILE" ] || [ ! -a "$UZBL_BOOKMARKS_FILE" ] || exit 1
+>> "$UZBL_BOOKMARKS_FILE" || exit 1
which zenity >/dev/null 2>&1 || exit 2
-tags=$(zenity --entry --text="Enter space-separated tags for bookmark $UZBL_URI:")
-exitstatus=$?
-[ $exitstatus -eq 0 ] || exit $exitstatus
+tags="$( zenity --entry --text="Enter space-separated tags for bookmark $UZBL_URI:" )"
+exitstatus="$?"
+[ "$exitstatus" -eq 0 ] || exit "$exitstatus"
# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags
echo "$UZBL_URI $tags" >> "$UZBL_BOOKMARKS_FILE"
diff --git a/examples/data/scripts/insert_temp.sh b/examples/data/scripts/insert_temp.sh
new file mode 100755
index 0000000..7ed8d22
--- /dev/null
+++ b/examples/data/scripts/insert_temp.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
+
+>> "$UZBL_TEMPS_FILE" || exit 1
+
+echo "$UZBL_URI $UZBL_TITLE" >> "$UZBL_TEMPS_FILE"
diff --git a/examples/data/scripts/instance-select-wmii.sh b/examples/data/scripts/instance-select-wmii.sh
index 19d04e8..b2aadbb 100755
--- a/examples/data/scripts/instance-select-wmii.sh
+++ b/examples/data/scripts/instance-select-wmii.sh
@@ -1,6 +1,5 @@
#!/bin/sh
-
# This script allows you to focus another uzbl window
# It considers all uzbl windows in the current tag
# you can select one from a list, or go to the next/previous one
@@ -13,30 +12,30 @@
DMENU_SCHEME="wmii"
-. $UZBL_UTIL_DIR/dmenu.sh
+. "$UZBL_UTIL_DIR/dmenu.sh"
case "$1" in
- "list" )
- list=
+ "list")
+ list=""
# get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky
- for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2); do
- label=$(wmiir read /client/$i/label)
+ for i in $( wmiir read /tag/sel/index | grep uzbl | cut -d ' ' -f 2 ); do
+ label="$( wmiir read /client/$i/label )"
list="$list$i : $label\n"
done
- window=$(printf "$list\n" | $DMENU | cut -d ' ' -f1)
+ window="$( echo "$list" | $DMENU | cut -d ' ' -f 1 )"
wmiir xwrite /tag/sel/ctl "select client $window"
;;
- "next" )
- current=$(wmiir read /client/sel/ctl | head -n 1)
+ "next")
+ current="$( wmiir read /client/sel/ctl | head -n 1 )"
# find the next uzbl window and focus it
- next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2)
+ next="$( wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f 2 )"
if [ -n "$next" ]; then
wmiir xwrite /tag/sel/ctl "select client $next"
fi
;;
- "prev" )
- current=$(wmiir read /client/sel/ctl | head -n 1)
- prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2)
+ "prev")
+ current="$( wmiir read /client/sel/ctl | head -n 1 )"
+ prev="$( wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f 2 )"
if [ -n "$prev" ]; then
wmiir xwrite /tag/sel/ctl "select client $prev"
fi
diff --git a/examples/data/scripts/load_cookies.sh b/examples/data/scripts/load_cookies.sh
index 17ec2ad..c7fcc58 100755
--- a/examples/data/scripts/load_cookies.sh
+++ b/examples/data/scripts/load_cookies.sh
@@ -1,20 +1,21 @@
#!/bin/sh
-if [ "$1" != "" ]; then
- cookie_file=$1
+if [ -n "$1" ]; then
+ cookie_file="$1"
+ shift
else
- cookie_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/cookies.txt
+ cookie_file="${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/cookies.txt"
fi
awk -F \\t '
BEGIN {
- scheme["TRUE"] = "https";
- scheme["FALSE"] = "http";
+ scheme["TRUE"] = "https";
+ scheme["FALSE"] = "http";
}
$0 ~ /^#HttpOnly_/ {
-printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", substr($1,length("#HttpOnly_"),length($1)), $3, $6, $7, scheme[$4], $5)
+ printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", substr($1,length("#HttpOnly_"),length($1)), $3, $6, $7, scheme[$4], $5)
}
$0 !~ /^#/ {
-printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", $1, $3, $6, $7, scheme[$4], $5)
+ printf("add_cookie \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", $1, $3, $6, $7, scheme[$4], $5)
}
-' $cookie_file
+' "$cookie_file"
diff --git a/examples/data/scripts/load_url_from_bookmarks.sh b/examples/data/scripts/load_url_from_bookmarks.sh
index a5d9586..a03db4b 100755
--- a/examples/data/scripts/load_url_from_bookmarks.sh
+++ b/examples/data/scripts/load_url_from_bookmarks.sh
@@ -5,18 +5,18 @@
DMENU_SCHEME="bookmarks"
DMENU_OPTIONS="xmms vertical resize"
-. "$UZBL_UTIL_DIR"/dmenu.sh
-. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+. "$UZBL_UTIL_DIR/dmenu.sh"
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
[ -r "$UZBL_BOOKMARKS_FILE" ] || exit 1
if [ -z "$DMENU_HAS_VERTICAL" ]; then
# because they are all after each other, just show the url, not their tags.
- goto=$(awk '{print $1}' "$UZBL_BOOKMARKS_FILE" | $DMENU)
+ goto="$( awk '{ print $1 }' "$UZBL_BOOKMARKS_FILE" | $DMENU )"
else
# show tags as well
- goto=$($DMENU < "$UZBL_BOOKMARKS_FILE" | awk '{print $1}')
+ goto="$( $DMENU < "$UZBL_BOOKMARKS_FILE" | cut -d ' ' -f 1 )"
fi
[ -n "$goto" ] && echo "uri $goto" > "$UZBL_FIFO"
-#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:"$UZBL_SOCKET"
+#[ -n "$goto" ] && echo "uri $goto" | socat - "unix-connect:$UZBL_SOCKET"
diff --git a/examples/data/scripts/load_url_from_history.sh b/examples/data/scripts/load_url_from_history.sh
index 59ad492..24bfdce 100755
--- a/examples/data/scripts/load_url_from_history.sh
+++ b/examples/data/scripts/load_url_from_history.sh
@@ -3,21 +3,20 @@
DMENU_SCHEME="history"
DMENU_OPTIONS="xmms vertical resize"
-. "$UZBL_UTIL_DIR"/dmenu.sh
-. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+. "$UZBL_UTIL_DIR/dmenu.sh"
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
[ -r "$UZBL_HISTORY_FILE" ] || exit 1
# choose from all entries, sorted and uniqued
-# goto=$(awk '{print $3}' $history_file | sort -u | dmenu -i)
if [ -z "$DMENU_HAS_VERTICAL" ]; then
- current=$(tail -n 1 "$UZBL_HISTORY_FILE" | awk '{print $3}');
- goto=$( (echo $current; awk '{print $3}' "$UZBL_HISTORY_FILE" | grep -v "^$current\$" | sort -u) | $DMENU)
+ current="$( tail -n 1 "$UZBL_HISTORY_FILE" | cut -d ' ' -f 3 )"
+ goto="$( ( echo "$current"; awk '{ print $3 }' "$UZBL_HISTORY_FILE" | grep -v "^$current\$" | sort -u ) | $DMENU )"
else
# choose an item in reverse order, showing also the date and page titles
# pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url.
- goto=$(tac "$UZBL_HISTORY_FILE" | $DMENU | cut -d ' ' -f -3 | awk '{print $NF}')
+ goto="$( tac "$UZBL_HISTORY_FILE" | $DMENU | cut -d ' ' -f -3 | awk '{ print $NF }' )"
fi
[ -n "$goto" ] && echo "uri $goto" > "$UZBL_FIFO"
-#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:"$UZBL_SOCKET"
+#[ -n "$goto" ] && echo "uri $goto" | socat - "unix-connect:$UZBL_SOCKET"
diff --git a/examples/data/scripts/load_url_from_temps.sh b/examples/data/scripts/load_url_from_temps.sh
new file mode 100755
index 0000000..b46687b
--- /dev/null
+++ b/examples/data/scripts/load_url_from_temps.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+DMENU_SCHEME="temps"
+DMENU_OPTIONS="xmms vertical resize"
+
+. "$UZBL_UTIL_DIR/dmenu.sh"
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
+
+[ -r "$UZBL_TEMPS_FILE" ] || exit 1
+
+if [ -z "$DMENU_HAS_VERTICAL" ]; then
+ # because they are all after each other, just show the url, not their titles.
+ goto=$( awk '{ print $1 }' "$UZBL_TEMPS_FILE" | $DMENU )
+else
+ # show titles
+ goto=$( $DMENU < "$UZBL_TEMPS_FILE" | cut -d ' ' -f 1 )
+fi
+
+sed -i -e "\<^$goto <d" $UZBL_TEMPS_FILE
+
+[ -n "$goto" ] && echo "uri $goto" > "$UZBL_FIFO"
+#[ -n "$goto" ] && echo "uri $goto" | socat - "unix-connect:$UZBL_SOCKET"
diff --git a/examples/data/scripts/session.sh b/examples/data/scripts/session.sh
index ee09cf2..4e7bfd1 100755
--- a/examples/data/scripts/session.sh
+++ b/examples/data/scripts/session.sh
@@ -18,28 +18,30 @@
if [ -z "$UZBL_UTIL_DIR" ]; then
# we're being run standalone, we have to figure out where $UZBL_UTIL_DIR is
# using the same logic as uzbl-browser does.
- UZBL_UTIL_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/scripts/util
+ UZBL_UTIL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/scripts/util"
if ! [ -d "$UZBL_UTIL_DIR" ]; then
- PREFIX=$(grep '^PREFIX' "$(which uzbl-browser)" | sed 's/.*=//')
- UZBL_UTIL_DIR=$PREFIX/share/uzbl/examples/data/scripts/util
+ PREFIX="$( grep '^PREFIX' "$( which uzbl-browser )" | sed -e 's/.*=//' )"
+ UZBL_UTIL_DIR="$PREFIX/share/uzbl/examples/data/scripts/util"
fi
fi
-. "$UZBL_UTIL_DIR"/uzbl-dir.sh
+. "$UZBL_UTIL_DIR/uzbl-dir.sh"
+
[ -d "$UZBL_DATA_DIR" ] || exit 1
-UZBL="uzbl-browser -c $UZBL_CONFIG_FILE" # add custom flags and whatever here.
+UZBL="uzbl-browser -c \"$UZBL_CONFIG_FILE\"" # add custom flags and whatever here.
-scriptfile=$(readlink -f $0) # this script
+scriptfile="$( readlink -f "$0" )" # this script
act="$1"
+shift
if [ -z "$act" ]; then
[ -f "$UZBL_SESSION_FILE" ] && act="launch" || act="endsession"
fi
case $act in
- "launch" )
- urls=$(cat "$UZBL_SESSION_FILE")
+ "launch")
+ urls="$( cat "$UZBL_SESSION_FILE" )"
if [ -z "$urls" ]; then
$UZBL
else
@@ -50,17 +52,17 @@ case $act in
fi
;;
- "endinstance" )
+ "endinstance")
if [ -z "$UZBL_FIFO" ]; then
echo "session manager: endinstance must be called from uzbl"
exit 1
fi
[ "$UZBL_URI" != "(null)" ] && echo "$UZBL_URI" >> "$UZBL_SESSION_FILE"
- echo exit > "$UZBL_FIFO"
+ echo "exit" > "$UZBL_FIFO"
;;
- "endsession" )
- for fifo in "$UZBL_FIFO_DIR"/uzbl_fifo_*; do
+ "endsession")
+ for fifo in "$UZBL_FIFO_DIR/uzbl_fifo_*"; do
if [ "$fifo" != "$UZBL_FIFO" ]; then
echo "spawn $scriptfile endinstance" > "$fifo"
fi
@@ -68,7 +70,7 @@ case $act in
[ -z "$UZBL_FIFO" ] || echo "spawn $scriptfile endinstance" > "$UZBL_FIFO"
;;
- * )
+ *)
echo "session manager: bad action"
echo "Usage: $scriptfile [COMMAND] where commands are:"
echo " launch - Restore a saved session or start a new one"
diff --git a/examples/data/scripts/util/dmenu.sh b/examples/data/scripts/util/dmenu.sh
index 354d7d1..0b7272e 100644
--- a/examples/data/scripts/util/dmenu.sh
+++ b/examples/data/scripts/util/dmenu.sh
@@ -30,6 +30,13 @@ case "$DMENU_SCHEME" in
SB="#ccffaa"
SF="#303030"
;;
+ # Temps
+ "temps" )
+ NB="#303030"
+ NF="khaki"
+ SB="#ccffaa"
+ SF="#303030"
+ ;;
# Default
* )
NB="#303030"
@@ -98,7 +105,7 @@ if dmenu --help 2>&1 | grep -q '\[-l <\?lines>\?\]'; then
fi
# Detect placement patch
-if dmenu --help 2>&1 | grep -q '\[-x <xoffset>\]'; then
+if dmenu --help 2>&1 | grep -q '\[-x <\?xoffset>\?\]'; then
DMENU_PLACE_X="-x"
DMENU_PLACE_Y="-y"
DMENU_PLACE_WIDTH="-w"
diff --git a/examples/data/scripts/util/uzbl-dir.sh b/examples/data/scripts/util/uzbl-dir.sh
index bb56954..82510d8 100644
--- a/examples/data/scripts/util/uzbl-dir.sh
+++ b/examples/data/scripts/util/uzbl-dir.sh
@@ -2,18 +2,19 @@
# Common directories and files used in scripts
# Common things first
-UZBL_DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl
-UZBL_CONFIG_DIR=${XDG_CONFIG_DIR:-$HOME/.config}/uzbl
+UZBL_DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/uzbl"
+UZBL_CONFIG_DIR="${XDG_CONFIG_DIR:-$HOME/.config}/uzbl"
UZBL_FIFO_DIR=/tmp
UZBL_SOCKET_DIR=/tmp
# Directories
-UZBL_DOWNLOAD_DIR=${XDG_DOWNLOAD_DIR:-$HOME}
-UZBL_FORMS_DIR=$UZBL_DATA_DIR/dforms
+UZBL_DOWNLOAD_DIR="${XDG_DOWNLOAD_DIR:-$HOME}"
+UZBL_FORMS_DIR="$UZBL_DATA_DIR/dforms"
# Data files
-UZBL_CONFIG_FILE=$UZBL_CONFIG_DIR/config
-UZBL_COOKIE_FILE=$UZBL_DATA_DIR/cookies.txt
-UZBL_BOOKMARKS_FILE=$UZBL_DATA_DIR/bookmarks
-UZBL_HISTORY_FILE=$UZBL_DATA_DIR/history
-UZBL_SESSION_FILE=$UZBL_DATA_DIR/browser-session
+UZBL_CONFIG_FILE="$UZBL_CONFIG_DIR/config"
+UZBL_COOKIE_FILE="$UZBL_DATA_DIR/cookies.txt"
+UZBL_BOOKMARKS_FILE="$UZBL_DATA_DIR/bookmarks"
+UZBL_TEMPS_FILE="$UZBL_DATA_DIR/temps"
+UZBL_HISTORY_FILE="$UZBL_DATA_DIR/history"
+UZBL_SESSION_FILE="$UZBL_DATA_DIR/browser-session"
diff --git a/examples/data/scripts/util/uzbl-window.sh b/examples/data/scripts/util/uzbl-window.sh
index a7e92eb..4b96372 100644
--- a/examples/data/scripts/util/uzbl-window.sh
+++ b/examples/data/scripts/util/uzbl-window.sh
@@ -1,11 +1,11 @@
#!/bin/sh
# uzbl window detection
-UZBL_WIN_POS=$(xwininfo -id $UZBL_XID | \
- sed -ne 's/Corners:[ ]*[+-]\([0-9]*\)[+-]\([0-9]*\).*$/\1 \2/p')
-UZBL_WIN_SIZE=$(xwininfo -id $UZBL_XID | \
- sed -ne 's/-geometry[ ]*\([0-9]*\)x\([0-9]*\).*$/\1 \2/p')
-UZBL_WIN_POS_X=$(echo $UZBL_WIN_POS | cut -d\ -f1)
-UZBL_WIN_POS_Y=$(echo $UZBL_WIN_POS | cut -d\ -f2)
-UZBL_WIN_WIDTH=$(echo $UZBL_WIN_SIZE | cut -d\ -f1)
-UZBL_WIN_HEIGHT=$(echo $UZBL_WIN_SIZE | cut -d\ -f2)
+UZBL_WIN_POS="$( xwininfo -id "$UZBL_XID" | \
+ sed -n -e '[ ]*s/Corners:[ ]*[+-]\([0-9]*\)[+-]\([0-9]*\).*$/\1 \2/p' )"
+UZBL_WIN_SIZE="$( xwininfo -id "$UZBL_XID" | \
+ sed -n -e '[ ]*s/-geometry[ ]*\([0-9]*\)x\([0-9]*\).*$/\1 \2/p' )"
+UZBL_WIN_POS_X="$( echo "$UZBL_WIN_POS" | cut -d ' ' -f 1 )"
+UZBL_WIN_POS_Y="$( echo "$UZBL_WIN_POS" | cut -d ' ' -f 2 )"
+UZBL_WIN_WIDTH="$( echo "$UZBL_WIN_SIZE" | cut -d ' ' -f 1 )"
+UZBL_WIN_HEIGHT="$( echo "$UZBL_WIN_SIZE" | cut -d ' ' -f 2 )"
diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager
deleted file mode 100755
index cb462c7..0000000
--- a/examples/data/scripts/uzbl-event-manager
+++ /dev/null
@@ -1,991 +0,0 @@
-#!/usr/bin/env python
-
-# Event Manager for Uzbl
-# Copyright (c) 2009-2010, Mason Larobina <mason.larobina@gmail.com>
-# Copyright (c) 2009, Dieter Plaetinck <dieter@plaetinck.be>
-#
-# 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/>.
-
-'''
-
-E V E N T _ M A N A G E R . P Y
-===============================
-
-Event manager for uzbl written in python.
-
-'''
-
-import atexit
-import imp
-import logging
-import os
-import socket
-import sys
-import time
-import weakref
-import re
-from collections import defaultdict
-from functools import partial
-from glob import glob
-from itertools import count
-from optparse import OptionParser
-from select import select
-from signal import signal, SIGTERM, SIGINT
-from socket import socket, AF_UNIX, SOCK_STREAM
-from traceback import format_exc
-
-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 os.path.join(os.environ['HOME'], default)
-
-# `make install` will put the correct value here for your system
-PREFIX = '/usr/local/'
-
-# Setup xdg paths.
-DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/')
-CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/')
-
-# Define some globals.
-SCRIPTNAME = os.path.basename(sys.argv[0])
-
-def get_exc():
- '''Format `format_exc` for logging.'''
- return "\n%s" % format_exc().rstrip()
-
-def expandpath(path):
- '''Expand and realpath paths.'''
- return os.path.realpath(os.path.expandvars(path))
-
-def ascii(u):
- '''Convert unicode strings into ascii for transmission over
- ascii-only streams/sockets/devices.'''
- return u.encode('utf-8')
-
-
-def daemonize():
- '''Daemonize the process using the Stevens' double-fork magic.'''
-
- logger.info('entering daemon mode')
-
- try:
- if os.fork():
- os._exit(0)
-
- except OSError:
- logger.critical(get_exc())
- sys.exit(1)
-
- os.chdir('/')
- os.setsid()
- os.umask(0)
-
- try:
- if os.fork():
- os._exit(0)
-
- except OSError:
- logger.critical(get_exc())
- 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())
-
- logger.info('entered daemon mode')
-
-
-def make_dirs(path):
- '''Make all basedirs recursively as required.'''
-
- try:
- dirname = os.path.dirname(path)
- if not os.path.isdir(dirname):
- logger.debug('creating directories %r' % dirname)
- os.makedirs(dirname)
-
- except OSError:
- logger.error(get_exc())
-
-
-class EventHandler(object):
- '''Event handler class. Used to store args and kwargs which are merged
- come time to call the callback with the event args and kwargs.'''
-
- nextid = count().next
-
- def __init__(self, plugin, event, callback, args, kwargs):
- self.id = self.nextid()
- self.plugin = plugin
- self.event = event
- self.callback = callback
- self.args = args
- self.kwargs = kwargs
-
-
- def __repr__(self):
- elems = ['id=%d' % self.id, 'event=%s' % self.event,
- 'callback=%r' % self.callback]
-
- if self.args:
- elems.append('args=%s' % repr(self.args))
-
- if self.kwargs:
- elems.append('kwargs=%s' % repr(self.kwargs))
-
- elems.append('plugin=%s' % self.plugin.name)
- return u'<handler(%s)>' % ', '.join(elems)
-
-
- def call(self, uzbl, *args, **kwargs):
- '''Execute the handler function and merge argument lists.'''
-
- args = args + self.args
- kwargs = dict(self.kwargs.items() + kwargs.items())
- 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', 'unquote', 'splitquoted']
-
-
- def __init__(self, parent, name, path, plugin):
- self.parent = parent
- self.name = name
- self.path = path
- self.plugin = plugin
- self.logger = get_logger('plugin.%s' % name)
-
- # Weakrefs to all handlers created by this plugin
- self.handlers = set([])
-
- # Plugins init hook
- init = getattr(plugin, 'init', None)
- self.init = init if callable(init) else None
-
- # Plugins optional after hook
- after = getattr(plugin, 'after', None)
- self.after = after if callable(after) else None
-
- # Plugins optional cleanup hook
- cleanup = getattr(plugin, 'cleanup', None)
- self.cleanup = cleanup if callable(cleanup) else None
-
- assert init or after or cleanup, "missing hooks in plugin"
-
- # Export plugin's instance methods to plugin namespace
- for attr in self.special_functions:
- plugin.__dict__[attr] = getattr(self, attr)
-
-
- def __repr__(self):
- return u'<plugin(%r)>' % self.plugin
-
-
- def export(self, uzbl, attr, object, prepend=True):
- '''Attach `object` to `uzbl` instance. This is the preferred method
- of sharing functionality, functions, data and objects between
- plugins.
-
- If the object is callable you may wish to turn the callable object
- in to a meta-instance-method by prepending `uzbl` to the call stack.
- You can change this behaviour with the `prepend` argument.
- '''
-
- assert attr not in uzbl.exports, "attr %r already exported by %r" %\
- (attr, uzbl.exports[attr][0])
-
- prepend = True if prepend and callable(object) else False
- uzbl.__dict__[attr] = partial(object, uzbl) if prepend else object
- uzbl.exports[attr] = (self, object, prepend)
- uzbl.logger.info('exported %r to %r by plugin %r, prepended %r'
- % (object, 'uzbl.%s' % attr, self.name, prepend))
-
-
- def export_dict(self, uzbl, exports):
- for (attr, object) in exports.items():
- self.export(uzbl, attr, object)
-
-
- def find_handler(self, event, callback, args, kwargs):
- '''Check if a handler with the identical callback and arguments
- exists and return it.'''
-
- # Remove dead refs
- self.handlers -= set(filter(lambda ref: not ref(), self.handlers))
-
- # Find existing identical handler
- for handler in [ref() for ref in self.handlers]:
- if handler.event == event and handler.callback == callback \
- and handler.args == args and handler.kwargs == kwargs:
- return handler
-
-
- def connect(self, uzbl, event, callback, *args, **kwargs):
- '''Create an event handler object which handles `event` events.
-
- Arguments passed to the connect function (`args` and `kwargs`) are
- stored in the handler object and merged with the event arguments
- come handler execution.
-
- All handler functions must behave like a `uzbl` instance-method (that
- means `uzbl` is prepended to the callback call arguments).'''
-
- # Sanitise and check event name
- event = event.upper().strip()
- assert event and ' ' not in event
-
- assert callable(callback), 'callback must be callable'
-
- # Check if an identical handler already exists
- handler = self.find_handler(event, callback, args, kwargs)
- if not handler:
- # Create a new handler
- handler = EventHandler(self, event, callback, args, kwargs)
- self.handlers.add(weakref.ref(handler))
- self.logger.info('new %r' % handler)
-
- uzbl.handlers[event].append(handler)
- uzbl.logger.info('connected %r' % handler)
- return handler
-
-
- def connect_dict(self, uzbl, connects):
- for (event, callback) in connects.items():
- self.connect(uzbl, event, callback)
-
-
- def require(self, plugin):
- '''Check that plugin with name `plugin` has been loaded. Use this to
- ensure that your plugins dependencies have been met.'''
-
- 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):
- self.opts = opts
- self.parent = parent
- self.child_socket = child_socket
- self.time = time.time()
- self.pid = None
- self.name = None
-
- # Flag if the instance has raised the INSTANCE_START event.
- self.instance_start = False
-
- # Use name "unknown" until name is discovered.
- self.logger = get_logger('uzbl-instance[]')
-
- # Track plugin event handlers and exported functions.
- self.exports = {}
- self.handlers = defaultdict(list)
-
- # Internal vars
- self._depth = 0
- self._buffer = ''
-
-
- def __repr__(self):
- return '<uzbl(%s)>' % ', '.join([
- 'pid=%s' % (self.pid if self.pid else "Unknown"),
- 'name=%s' % ('%r' % self.name if self.name else "Unknown"),
- 'uptime=%f' % (time.time()-self.time),
- '%d exports' % len(self.exports.keys()),
- '%d handlers' % sum([len(l) for l in self.handlers.values()])])
-
-
- def init_plugins(self):
- '''Call the init and after hooks in all loaded plugins for this
- instance.'''
-
- # Initialise each plugin with the current uzbl instance.
- for plugin in self.parent.plugins.values():
- if plugin.init:
- self.logger.debug('calling %r plugin init hook' % plugin.name)
- plugin.init(self)
-
- # Allow plugins to use exported features of other plugins by calling an
- # optional `after` function in the plugins namespace.
- for plugin in self.parent.plugins.values():
- if plugin.after:
- self.logger.debug('calling %r plugin after hook'%plugin.name)
- plugin.after(self)
-
-
- def send(self, msg):
- '''Send a command to the uzbl instance via the child socket
- instance.'''
-
- msg = msg.strip()
- assert self.child_socket, "socket inactive"
-
- if opts.print_events:
- print ascii(u'%s<-- %s' % (' ' * self._depth, msg))
-
- self.child_socket.send(ascii("%s\n" % msg))
-
-
- def read(self):
- '''Read data from the child socket and pass lines to the parse_msg
- function.'''
-
- try:
- raw = unicode(self.child_socket.recv(8192), 'utf-8', 'ignore')
- if not raw:
- self.logger.debug('read null byte')
- return self.close()
-
- except:
- self.logger.error(get_exc())
- return self.close()
-
- lines = (self._buffer + raw).split('\n')
- self._buffer = lines.pop()
-
- for line in filter(None, map(unicode.strip, lines)):
- try:
- self.parse_msg(line.strip())
-
- except:
- self.logger.error(get_exc())
- self.logger.error('erroneous event: %r' % line)
-
-
- def parse_msg(self, line):
- '''Parse an incoming message from a uzbl instance. Event strings
- will be parsed into `self.event(event, args)`.'''
-
- # Split by spaces (and fill missing with nulls)
- elems = (line.split(' ', 3) + ['',]*3)[:4]
-
- # Ignore non-event messages.
- if elems[0] != 'EVENT':
- logger.info('non-event message: %r' % line)
- if opts.print_events:
- print '--- %s' % ascii(line)
- return
-
- # Check event string elements
- (name, event, args) = elems[1:]
- assert name and event, 'event string missing elements'
- if not self.name:
- self.name = name
- self.logger = get_logger('uzbl-instance%s' % name)
- self.logger.info('found instance name %r' % name)
-
- assert self.name == name, 'instance name mismatch'
-
- # Handle the event with the event handlers through the event method
- self.event(event, args)
-
-
- def event(self, event, *args, **kargs):
- '''Raise an event.'''
-
- event = event.upper()
-
- if not opts.daemon_mode and opts.print_events:
- elems = [event,]
- if args: elems.append(unicode(args))
- if kargs: elems.append(unicode(kargs))
- print ascii(u'%s--> %s' % (' ' * self._depth, ' '.join(elems)))
-
- if event == "INSTANCE_START" and args:
- assert not self.instance_start, 'instance already started'
-
- self.pid = int(args[0])
- self.logger.info('found instance pid %r' % self.pid)
-
- self.init_plugins()
-
- elif event == "INSTANCE_EXIT":
- self.logger.info('uzbl instance exit')
- self.close()
-
- if event not in self.handlers:
- return
-
- for handler in self.handlers[event]:
- self._depth += 1
- try:
- handler.call(self, *args, **kargs)
-
- except:
- self.logger.error(get_exc())
-
- self._depth -= 1
-
-
- def close_connection(self, child_socket):
- '''Close child socket and delete the uzbl instance created for that
- child socket connection.'''
-
-
- def close(self):
- '''Close the client socket and call the plugin cleanup hooks.'''
-
- self.logger.debug('called close method')
-
- # Remove self from parent uzbls dict.
- if self.child_socket in self.parent.uzbls:
- self.logger.debug('removing self from uzbls list')
- del self.parent.uzbls[self.child_socket]
-
- try:
- if self.child_socket:
- self.logger.debug('closing child socket')
- self.child_socket.close()
-
- except:
- self.logger.error(get_exc())
-
- finally:
- self.child_socket = None
-
- # Call plugins cleanup hooks.
- for plugin in self.parent.plugins.values():
- if plugin.cleanup:
- self.logger.debug('calling %r plugin cleanup hook'
- % plugin.name)
- plugin.cleanup(self)
-
- logger.info('removed %r' % self)
-
-
-class UzblEventDaemon(object):
- def __init__(self):
- self.opts = opts
- self.server_socket = None
- self._quit = False
-
- # Hold uzbl instances
- # {child socket: Uzbl instance, ..}
- self.uzbls = {}
-
- # Hold plugins
- # {plugin name: Plugin instance, ..}
- self.plugins = {}
-
- # Register that the event daemon server has started by creating the
- # pid file.
- make_pid_file(opts.pid_file)
-
- # Register a function to clean up the socket and pid file on exit.
- atexit.register(self.quit)
-
- # Add signal handlers.
- for sigint in [SIGTERM, SIGINT]:
- signal(sigint, self.quit)
-
- # Load plugins into self.plugins
- self.load_plugins(opts.plugins)
-
-
- def load_plugins(self, plugins):
- '''Load event manager plugins.'''
-
- for path in plugins:
- logger.debug('loading plugin %r' % path)
- (dir, file) = os.path.split(path)
- name = file[:-3] if file.lower().endswith('.py') else file
-
- info = imp.find_module(name, [dir,])
- module = imp.load_module(name, *info)
-
- # Check if the plugin has a callable hook.
- hooks = filter(callable, [getattr(module, attr, None) \
- for attr in ['init', 'after', 'cleanup']])
- assert hooks, "no hooks in plugin %r" % module
-
- logger.debug('creating plugin instance for %r plugin' % name)
- plugin = Plugin(self, name, path, module)
- self.plugins[name] = plugin
- logger.info('new %r' % plugin)
-
-
- def create_server_socket(self):
- '''Create the event manager daemon socket for uzbl instance duplex
- communication.'''
-
- # Close old socket.
- self.close_server_socket()
-
- sock = socket(AF_UNIX, SOCK_STREAM)
- sock.bind(opts.server_socket)
- sock.listen(5)
-
- self.server_socket = sock
- logger.debug('bound server socket to %r' % opts.server_socket)
-
-
- def run(self):
- '''Main event daemon loop.'''
-
- logger.debug('entering main loop')
-
- # Create and listen on the server socket
- self.create_server_socket()
-
- if opts.daemon_mode:
- # Daemonize the process
- daemonize()
-
- # Update the pid file
- make_pid_file(opts.pid_file)
-
- try:
- # Accept incoming connections and listen for incoming data
- self.listen()
-
- except:
- if not self._quit:
- logger.critical(get_exc())
-
- # Clean up and exit
- self.quit()
-
- logger.debug('exiting main loop')
-
-
- def listen(self):
- '''Accept incoming connections and constantly poll instance sockets
- for incoming data.'''
-
- logger.info('listening on %r' % opts.server_socket)
-
- # Count accepted connections
- connections = 0
-
- while (self.uzbls or not connections) or (not opts.auto_close):
- socks = [self.server_socket] + self.uzbls.keys()
- reads, _, errors = select(socks, [], socks, 1)
-
- if self.server_socket in reads:
- reads.remove(self.server_socket)
-
- # Accept connection and create uzbl instance.
- child_socket = self.server_socket.accept()[0]
- self.uzbls[child_socket] = Uzbl(self, child_socket)
- connections += 1
-
- for uzbl in [self.uzbls[s] for s in reads]:
- uzbl.read()
-
- for uzbl in [self.uzbls[s] for s in errors]:
- uzbl.logger.error('socket read error')
- uzbl.close()
-
- logger.info('auto closing')
-
-
- def close_server_socket(self):
- '''Close and delete the server socket.'''
-
- try:
- if self.server_socket:
- logger.debug('closing server socket')
- self.server_socket.close()
- self.server_socket = None
-
- if os.path.exists(opts.server_socket):
- logger.info('unlinking %r' % opts.server_socket)
- os.unlink(opts.server_socket)
-
- except:
- logger.error(get_exc())
-
-
- def quit(self, sigint=None, *args):
- '''Close all instance socket objects, server socket and delete the
- pid file.'''
-
- if sigint == SIGTERM:
- logger.critical('caught SIGTERM, exiting')
-
- elif sigint == SIGINT:
- logger.critical('caught SIGINT, exiting')
-
- elif not self._quit:
- logger.debug('shutting down event manager')
-
- self.close_server_socket()
-
- for uzbl in self.uzbls.values():
- uzbl.close()
-
- del_pid_file(opts.pid_file)
-
- if not self._quit:
- logger.info('event manager shut down')
- self._quit = True
-
-
-def make_pid_file(pid_file):
- '''Creates a pid file at `pid_file`, fails silently.'''
-
- try:
- logger.debug('creating pid file %r' % pid_file)
- make_dirs(pid_file)
- pid = os.getpid()
- fileobj = open(pid_file, 'w')
- fileobj.write('%d' % pid)
- fileobj.close()
- logger.info('created pid file %r with pid %d' % (pid_file, pid))
-
- except:
- logger.error(get_exc())
-
-
-def del_pid_file(pid_file):
- '''Deletes a pid file at `pid_file`, fails silently.'''
-
- if os.path.isfile(pid_file):
- try:
- logger.debug('deleting pid file %r' % pid_file)
- os.remove(pid_file)
- logger.info('deleted pid file %r' % pid_file)
-
- except:
- logger.error(get_exc())
-
-
-def get_pid(pid_file):
- '''Reads a pid from pid file `pid_file`, fails None.'''
-
- try:
- logger.debug('reading pid file %r' % pid_file)
- fileobj = open(pid_file, 'r')
- pid = int(fileobj.read())
- fileobj.close()
- logger.info('read pid %d from pid file %r' % (pid, pid_file))
- return pid
-
- except (IOError, ValueError):
- logger.error(get_exc())
- return None
-
-
-def pid_running(pid):
- '''Checks if a process with a pid `pid` is running.'''
-
- try:
- os.kill(pid, 0)
- except OSError:
- return False
- else:
- return True
-
-
-def term_process(pid):
- '''Asks nicely then forces process with pid `pid` to exit.'''
-
- try:
- logger.info('sending SIGTERM to process with pid %r' % pid)
- os.kill(pid, SIGTERM)
-
- except OSError:
- logger.error(get_exc())
-
- logger.debug('waiting for process with pid %r to exit' % pid)
- start = time.time()
- while True:
- if not pid_running(pid):
- logger.debug('process with pid %d exit' % pid)
- return True
-
- if (time.time()-start) > 5:
- logger.warning('process with pid %d failed to exit' % pid)
- logger.info('sending SIGKILL to process with pid %d' % pid)
- try:
- os.kill(pid, SIGKILL)
- except:
- logger.critical(get_exc())
- raise
-
- if (time.time()-start) > 10:
- logger.critical('unable to kill process with pid %d' % pid)
- raise OSError
-
- time.sleep(0.25)
-
-
-def stop_action():
- '''Stop the event manager daemon.'''
-
- pid_file = opts.pid_file
- if not os.path.isfile(pid_file):
- logger.error('could not find running event manager with pid file %r'
- % opts.pid_file)
- return
-
- pid = get_pid(pid_file)
- if not pid_running(pid):
- logger.debug('no process with pid %r' % pid)
- del_pid_file(pid_file)
- return
-
- logger.debug('terminating process with pid %r' % pid)
- term_process(pid)
- del_pid_file(pid_file)
- logger.info('stopped event manager process with pid %d' % pid)
-
-
-def start_action():
- '''Start the event manager daemon.'''
-
- pid_file = opts.pid_file
- if os.path.isfile(pid_file):
- pid = get_pid(pid_file)
- if pid_running(pid):
- logger.error('event manager already started with pid %d' % pid)
- return
-
- logger.info('no process with pid %d' % pid)
- del_pid_file(pid_file)
-
- UzblEventDaemon().run()
-
-
-def restart_action():
- '''Restart the event manager daemon.'''
-
- stop_action()
- start_action()
-
-
-def list_action():
- '''List all the plugins that would be loaded in the current search
- dirs.'''
-
- names = {}
- for plugin in opts.plugins:
- (head, tail) = os.path.split(plugin)
- if tail not in names:
- names[tail] = plugin
-
- for plugin in sorted(names.values()):
- print plugin
-
-
-if __name__ == "__main__":
- parser = OptionParser('usage: %prog [options] {start|stop|restart|list}')
- add = parser.add_option
-
- add('-v', '--verbose',
- dest='verbose', default=2, action='count',
- help='increase verbosity')
-
- add('-d', '--plugin-dir',
- dest='plugin_dirs', action='append', metavar="DIR", default=[],
- help='add extra plugin search dir, same as `-l "DIR/*.py"`')
-
- add('-l', '--load-plugin',
- dest='load_plugins', action='append', metavar="PLUGIN", default=[],
- help='load plugin, loads before plugins in search dirs')
-
- socket_location = os.path.join(CACHE_DIR, 'event_daemon')
- add('-s', '--server-socket',
- dest='server_socket', metavar="SOCKET", default=socket_location,
- help='server AF_UNIX socket location')
-
- add('-p', '--pid-file',
- metavar="FILE", dest='pid_file',
- help='pid file location, defaults to server socket + .pid')
-
- add('-n', '--no-daemon',
- dest='daemon_mode', action='store_false', default=True,
- help='do not daemonize the process')
-
- add('-a', '--auto-close',
- dest='auto_close', action='store_true', default=False,
- help='auto close after all instances disconnect')
-
- add('-i', '--no-default-dirs',
- dest='default_dirs', action='store_false', default=True,
- help='ignore the default plugin search dirs')
-
- add('-o', '--log-file',
- dest='log_file', metavar='FILE',
- help='write logging output to a file, defaults to server socket +'
- ' .log')
-
- add('-q', '--quiet-events',
- dest='print_events', action="store_false", default=True,
- help="silence the printing of events to stdout")
-
- (opts, args) = parser.parse_args()
-
- opts.server_socket = expandpath(opts.server_socket)
-
- # Set default pid file location
- if not opts.pid_file:
- opts.pid_file = "%s.pid" % opts.server_socket
-
- else:
- opts.pid_file = expandpath(opts.pid_file)
-
- # Set default log file location
- if not opts.log_file:
- opts.log_file = "%s.log" % opts.server_socket
-
- else:
- opts.log_file = expandpath(opts.log_file)
-
- # Logging setup
- log_level = logging.CRITICAL - opts.verbose*10
-
- # Console logging handler
- ch = logging.StreamHandler()
- ch.setLevel(max(log_level+10, 10))
- ch.setFormatter(logging.Formatter(
- '%(name)s: %(levelname)s: %(message)s'))
-
- # File logging handler
- fh = logging.FileHandler(opts.log_file, 'w', 'utf-8', 1)
- fh.setLevel(max(log_level, 10))
- fh.setFormatter(logging.Formatter(
- '[%(created)f] %(name)s: %(levelname)s: %(message)s'))
-
- # logging.getLogger wrapper which sets the levels and adds the
- # file and console handlers automagically
- def get_logger(name):
- handlers = [ch, fh]
- level = [max(log_level, 10),]
- logger = logging.getLogger(name)
- logger.setLevel(level[0])
- for handler in handlers:
- logger.addHandler(handler)
-
- return logger
-
- # Get main logger
- logger = get_logger(SCRIPTNAME)
- logger.info('logging to %r' % opts.log_file)
-
- plugins = {}
-
- # Load all `opts.load_plugins` into the plugins list
- for path in opts.load_plugins:
- path = expandpath(path)
- matches = glob(path)
- if not matches:
- parser.error('cannot find plugin(s): %r' % path)
-
- for plugin in matches:
- (head, tail) = os.path.split(plugin)
- if tail not in plugins:
- logger.debug('found plugin: %r' % plugin)
- plugins[tail] = plugin
-
- else:
- logger.debug('ignoring plugin: %r' % plugin)
-
- # Add default plugin locations
- if opts.default_dirs:
- logger.debug('adding default plugin dirs to plugin dirs list')
- opts.plugin_dirs += [os.path.join(DATA_DIR, 'plugins/'),
- os.path.join(PREFIX, 'share/uzbl/examples/data/plugins/')]
-
- else:
- logger.debug('ignoring default plugin dirs')
-
- # Load all plugins in `opts.plugin_dirs` into the plugins list
- for dir in opts.plugin_dirs:
- dir = expandpath(dir)
- logger.debug('searching plugin dir: %r' % dir)
- for plugin in glob(os.path.join(dir, '*.py')):
- (head, tail) = os.path.split(plugin)
- if tail not in plugins:
- logger.debug('found plugin: %r' % plugin)
- plugins[tail] = plugin
-
- else:
- logger.debug('ignoring plugin: %r' % plugin)
-
- plugins = plugins.values()
-
- # Check all the paths in the plugins list are files
- for plugin in plugins:
- if not os.path.isfile(plugin):
- parser.error('plugin not a file: %r' % plugin)
-
- if opts.auto_close: logger.debug('will auto close')
- else: logger.debug('will not auto close')
-
- if opts.daemon_mode: logger.debug('will daemonize')
- else: logger.debug('will not daemonize')
-
- opts.plugins = plugins
-
- # init like {start|stop|..} daemon actions
- daemon_actions = {'start': start_action, 'stop': stop_action,
- 'restart': restart_action, 'list': list_action}
-
- if len(args) == 1:
- action = args[0]
- if action not in daemon_actions:
- parser.error('invalid action: %r' % action)
-
- elif not args:
- logger.warning('no daemon action given, assuming %r' % 'start')
- action = 'start'
-
- else:
- parser.error('invalid action argument: %r' % args)
-
- logger.info('daemon action %r' % action)
- # Do action
- 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
deleted file mode 100755
index de71c2c..0000000
--- a/examples/data/scripts/uzbl-tabbed
+++ /dev/null
@@ -1,1404 +0,0 @@
-#!/usr/bin/env python
-
-# Uzbl tabbing wrapper using a fifo socket interface
-# Copyright (c) 2009, Tom Adams <tom@holizz.com>
-# Copyright (c) 2009, Chris van Dijk <cn.vandijk@hotmail.com>
-# Copyright (c) 2009, Mason Larobina <mason.larobina@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/>.
-
-
-# Author(s):
-# Tom Adams <tom@holizz.com>
-# Wrote the original uzbl_tabbed.py as a proof of concept.
-#
-# Chris van Dijk (quigybo) <cn.vandijk@hotmail.com>
-# Made signifigant headway on the old uzbl_tabbing.py script on the
-# uzbl wiki <http://www.uzbl.org/wiki/uzbl_tabbed>
-#
-# Mason Larobina <mason.larobina@gmail.com>
-# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface
-# and inherit configuration options from the user's uzbl config.
-#
-# Contributor(s):
-# mxey <mxey@ghosthacking.net>
-# uzbl_config path now honors XDG_CONFIG_HOME if it exists.
-#
-# Romain Bignon <romain@peerfuse.org>
-# Fix for session restoration code.
-#
-# Jake Probst <jake.probst@gmail.com>
-# Wrote a patch that overflows tabs in the tablist on to new lines when
-# running of room.
-#
-# Devon Jones <devon.jones@gmail.com>
-# Fifo command bring_to_front which brings the gtk window to focus.
-#
-# Simon Lipp (sloonz)
-# Various
-
-
-# Dependencies:
-# pygtk - python bindings for gtk.
-# pango - python bindings needed for text rendering & layout in gtk widgets.
-# pygobject - GLib's GObject bindings for python.
-#
-# Note: I haven't included version numbers with this dependency list because
-# I've only ever tested uzbl_tabbed.py on the latest stable versions of these
-# packages in Gentoo's portage. Package names may vary on different systems.
-
-
-# Configuration:
-# Because this version of uzbl_tabbed is able to inherit options from your main
-# uzbl configuration file you may wish to configure uzbl tabbed from there.
-# Here is a list of configuration options that can be customised and some
-# example values for each:
-#
-# General tabbing options:
-# show_tablist = 1
-# show_gtk_tabs = 0
-# tablist_top = 1
-# gtk_tab_pos = (top|left|bottom|right)
-# gtk_refresh = 1000
-# switch_to_new_tabs = 1
-# capture_new_windows = 1
-# multiline_tabs = 1
-#
-# Tab title options:
-# tab_titles = 1
-# tab_indexes = 1
-# new_tab_title = Loading
-# max_title_len = 50
-# show_ellipsis = 1
-#
-# Session options:
-# save_session = 1
-# json_session = 0
-# session_file = $HOME/.local/share/uzbl/session
-#
-# Inherited uzbl options:
-# fifo_dir = /tmp
-# socket_dir = /tmp
-# icon_path = $HOME/.local/share/uzbl/uzbl.png
-# status_background = #303030
-#
-# Misc options:
-# window_size = 800,800
-# verbose = 0
-#
-# And uzbl_tabbed.py takes care of the actual binding of the commands via each
-# instances fifo socket.
-#
-# Custom tab styling:
-# tab_colours = foreground = "#888" background = "#303030"
-# tab_text_colours = foreground = "#bbb"
-# selected_tab = foreground = "#fff"
-# selected_tab_text = foreground = "green"
-# tab_indicate_https = 1
-# https_colours = foreground = "#888"
-# https_text_colours = foreground = "#9c8e2d"
-# selected_https = foreground = "#fff"
-# selected_https_text = foreground = "gold"
-#
-# How these styling values are used are soley defined by the syling policy
-# handler below (the function in the config section). So you can for example
-# turn the tab text colour Firetruck-Red in the event "error" appears in the
-# tab title or some other arbitrary event. You may wish to make a trusted
-# hosts file and turn tab titles of tabs visiting trusted hosts purple.
-
-
-# Issues:
-# - new windows are not caught and opened in a new tab.
-# - when uzbl_tabbed.py crashes it takes all the children with it.
-# - when a new tab is opened when using gtk tabs the tab button itself
-# grabs focus from its child for a few seconds.
-# - when switch_to_new_tabs is not selected the notebook page is
-# maintained but the new window grabs focus (try as I might to stop it).
-
-
-# Todo:
-# - add command line options to use a different session file, not use a
-# session file and or open a uri on starup.
-# - ellipsize individual tab titles when the tab-list becomes over-crowded
-# - add "<" & ">" arrows to tablist to indicate that only a subset of the
-# currently open tabs are being displayed on the tablist.
-# - add the small tab-list display when both gtk tabs and text vim-like
-# tablist are hidden (I.e. [ 1 2 3 4 5 ])
-# - check spelling.
-# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into
-# the collective. Resistance is futile!
-
-
-import pygtk
-import gtk
-import subprocess
-import os
-import re
-import time
-import getopt
-import pango
-import select
-import sys
-import gobject
-import socket
-import random
-import hashlib
-import atexit
-import types
-
-from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP
-from signal import signal, SIGTERM, SIGINT
-from optparse import OptionParser, OptionGroup
-from traceback import print_exc
-
-
-pygtk.require('2.0')
-
-_SCRIPTNAME = os.path.basename(sys.argv[0])
-def error(msg):
- sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg))
-
-# ============================================================================
-# ::: 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 os.path.join(os.environ['HOME'], default)
-
-# Setup xdg paths.
-DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/')
-
-# Ensure uzbl xdg paths exist
-if not os.path.exists(DATA_DIR):
- os.makedirs(DATA_DIR)
-
-# All of these settings can be inherited from your uzbl config file.
-config = {
- # Tab options
- 'show_tablist': True, # Show text uzbl like statusbar tab-list
- 'show_gtk_tabs': False, # Show gtk notebook tabs
- 'tablist_top': True, # Display tab-list at top of window
- 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right)
- 'gtk_refresh': 1000, # Tablist refresh millisecond interval
- 'switch_to_new_tabs': True, # Upon opening a new tab switch to it
- 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows
- 'multiline_tabs': True, # Tabs overflow onto new tablist lines.
-
- # Tab title options
- 'tab_titles': True, # Display tab titles (else only tab-nums)
- 'tab_indexes': True, # Display tab nums (else only tab titles)
- 'new_tab_title': 'Loading', # New tab title
- 'max_title_len': 50, # Truncate title at n characters
- 'show_ellipsis': True, # Show ellipsis when truncating titles
-
- # Session options
- 'save_session': True, # Save session in file when quit
- 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'),
- 'session_file': os.path.join(DATA_DIR, 'session'),
-
- # Inherited uzbl options
- 'fifo_dir': '/tmp', # Path to look for uzbl fifo.
- 'socket_dir': '/tmp', # Path to look for uzbl socket.
- 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'),
- 'status_background': "#303030", # Default background for all panels.
-
- # Misc options
- 'window_size': "800,800", # width,height in pixels.
- 'verbose': False, # Print verbose output.
-
- # Add custom tab style definitions to be used by the tab colour policy
- # handler here. Because these are added to the config dictionary like
- # any other uzbl_tabbed configuration option remember that they can
- # be superseeded from your main uzbl config file.
- 'tab_colours': 'foreground = "#888" background = "#303030"',
- 'tab_text_colours': 'foreground = "#bbb"',
- 'selected_tab': 'foreground = "#fff"',
- 'selected_tab_text': 'foreground = "green"',
- 'tab_indicate_https': True,
- 'https_colours': 'foreground = "#888"',
- 'https_text_colours': 'foreground = "#9c8e2d"',
- 'selected_https': 'foreground = "#fff"',
- 'selected_https_text': 'foreground = "gold"',
-
-} # End of config dict.
-
-UZBL_TABBED_VARS = config.keys()
-
-# This is the tab style policy handler. Every time the tablist is updated
-# this function is called to determine how to colourise that specific tab
-# according the simple/complex rules as defined here. You may even wish to
-# move this function into another python script and import it using:
-# from mycustomtabbingconfig import colour_selector
-# Remember to rename, delete or comment out this function if you do that.
-
-def colour_selector(tabindex, currentpage, uzbl):
- '''Tablist styling policy handler. This function must return a tuple of
- the form (tab style, text style).'''
-
- # Just as an example:
- # if 'error' in uzbl.title:
- # if tabindex == currentpage:
- # return ('foreground="#fff"', 'foreground="red"')
- # return ('foreground="#888"', 'foreground="red"')
-
- # Style tabs to indicate connected via https.
- if config['tab_indicate_https'] and uzbl.uri.startswith("https://"):
- if tabindex == currentpage:
- return (config['selected_https'], config['selected_https_text'])
- return (config['https_colours'], config['https_text_colours'])
-
- # Style to indicate selected.
- if tabindex == currentpage:
- return (config['selected_tab'], config['selected_tab_text'])
-
- # Default tab style.
- return (config['tab_colours'], config['tab_text_colours'])
-
-# ============================================================================
-# ::: End of configuration section :::::::::::::::::::::::::::::::::::::::::::
-# ============================================================================
-
-def echo(msg):
- if config['verbose']:
- sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg))
-
-
-def counter():
- '''To infinity and beyond!'''
-
- i = 0
- while True:
- i += 1
- yield i
-
-
-def escape(s):
- '''Replaces html markup in tab titles that screw around with pango.'''
-
- for (split, glue) in [('&','&amp;'), ('<', '&lt;'), ('>', '&gt;')]:
- s = s.replace(split, glue)
- return s
-
-
-class SocketClient:
- '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance'''
-
- # List of UzblInstance objects not already linked with a SocketClient
- instances_queue = {}
-
- def __init__(self, socket):
- self._buffer = ""
- self._socket = socket
- self._watchers = [io_add_watch(socket, IO_IN, self._socket_recv),\
- io_add_watch(socket, IO_HUP, self._socket_closed)]
- self.uzbl = None
-
-
- def _socket_recv(self, fd, condition):
- '''Data available on socket, process it'''
-
- self._feed(self._socket.recv(1024)) #TODO: is io_add_watch edge or level-triggered ?
- return True
-
-
- def _socket_closed(self, fd, condition):
- '''Remote client exited'''
- self.uzbl.close()
- return False
-
-
- def _feed(self, data):
- '''An Uzbl instance sent some data, parse it'''
-
- self._buffer += data
- if self.uzbl:
- if "\n" in self._buffer:
- cmds = self._buffer.split("\n")
-
- if cmds[-1]: # Last command has been received incomplete, don't process it
- self._buffer, cmds = cmds[-1], cmds[:-1]
- else:
- self._buffer = ""
-
- for cmd in cmds:
- if cmd:
- self.uzbl.parse_command(cmd)
- else:
- name = re.findall('^EVENT \[(\d+-\d+)\] INSTANCE_START \d+$', self._buffer, re.M)
- uzbl = self.instances_queue.get(name[0])
- if uzbl:
- del self.instances_queue[name[0]]
- self.uzbl = uzbl
- self.uzbl.got_socket(self)
- self._feed("")
-
- def send(self, data):
- '''Child socket send function.'''
-
- self._socket.send(data + "\n")
-
- def close(self):
- '''Close the connection'''
-
- if self._socket:
- self._socket.close()
- self._socket = None
- map(source_remove, self._watchers)
- self._watchers = []
-
-
-class UzblInstance:
- '''Uzbl instance meta-data/meta-action object.'''
-
- def __init__(self, parent, tab, name, uri, title, switch):
-
- self.parent = parent
- self.tab = tab
- self.name = name
- self.title = title
- self.tabtitle = ""
- self.uri = uri
- self._client = None
- self._switch = switch # Switch to tab after loading ?
- self.title_changed()
-
-
- def got_socket(self, client):
- '''Uzbl instance is now connected'''
-
- self._client = client
- self.parent.config_uzbl(self)
- if self._switch:
- tabid = self.parent.notebook.page_num(self.tab)
- self.parent.goto_tab(tabid)
-
-
- def title_changed(self, gtk_only = True): # GTK-only is for indexes
- '''self.title has changed, update the tabs list'''
-
- tab_titles = config['tab_titles']
- tab_indexes = config['tab_indexes']
- show_ellipsis = config['show_ellipsis']
- max_title_len = config['max_title_len']
-
- # Unicode heavy strings do not like being truncated/sliced so by
- # re-encoding the string sliced of limbs are removed.
- self.tabtitle = self.title[:max_title_len + int(show_ellipsis)]
- if type(self.tabtitle) != types.UnicodeType:
- self.tabtitle = unicode(self.tabtitle, 'utf-8', 'ignore')
-
- self.tabtitle = self.tabtitle.encode('utf-8', 'ignore').strip()
-
- if show_ellipsis and len(self.tabtitle) != len(self.title):
- self.tabtitle += "\xe2\x80\xa6"
-
- gtk_tab_format = "%d %s"
- index = self.parent.notebook.page_num(self.tab)
- if tab_titles and tab_indexes:
- self.parent.notebook.set_tab_label_text(self.tab,
- gtk_tab_format % (index, self.tabtitle))
- elif tab_titles:
- self.parent.notebook.set_tab_label_text(self.tab, self.tabtitle)
- else:
- self.parent.notebook.set_tab_label_text(self.tab, str(index))
-
- # If instance is current tab, update window title
- if index == self.parent.notebook.get_current_page():
- title_format = "%s - Uzbl Browser"
- self.parent.window.set_title(title_format % self.title)
-
- # Non-GTK tabs
- if not gtk_only:
- self.parent.update_tablist()
-
-
- def set(self, key, val):
- ''' Send the SET command to Uzbl '''
-
- if self._client:
- self._client.send('set %s = %s') #TODO: escape chars ?
-
-
- def exit(self):
- ''' Ask the Uzbl instance to close '''
-
- if self._client:
- self._client.send('exit')
-
-
- def parse_command(self, cmd):
- ''' Parse event givent by the Uzbl instance '''
-
- type, _, args = cmd.split(" ", 2)
- if type == "EVENT":
- type, args = args.split(" ", 1)
- if type == "TITLE_CHANGED":
- self.title = args.strip()
- self.title_changed(False)
- elif type == "VARIABLE_SET":
- var, _, val = args.split(" ", 2)
-
- try:
- val = int(val)
- except:
- pass
-
- if var in UZBL_TABBED_VARS:
- if config[var] != val:
- config[var] = val
- if var == "show_gtk_tabs":
- self.parent.notebook.set_show_tabs(bool(val))
- elif var == "show_tablist" or var == "tablist_top":
- self.parent.update_tablist_display()
- elif var == "gtk_tab_pos":
- self.parent.update_gtk_tab_pos()
- elif var == "status_background":
- if config['status_background'].strip():
- 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)
-
- self.parent.update_tablist()
- else:
- config[var] = val
-
- if var == "uri":
- self.uri = val.strip()
- self.parent.update_tablist()
- elif type == "LOAD_COMMIT":
- self.uri = args
- elif type == "NEW_TAB":
- self.parent.new_tab(args)
- elif type == "NEW_BG_TAB":
- self.parent.new_tab(args, '', 0)
- elif type == "NEW_TAB_NEXT":
- self.parent.new_tab(args, next=True)
- elif type == "NEW_BG_TAB_NEXT":
- self.parent.new_tab(args, '', 0, next=True)
-
- elif type == "NEXT_TAB":
- if args:
- self.parent.next_tab(int(args))
- else:
- self.parent.next_tab()
- elif type == "PREV_TAB":
- if args:
- self.parent.prev_tab(int(args))
- else:
- self.parent.prev_tab()
- elif type == "GOTO_TAB":
- self.parent.goto_tab(int(args))
- elif type == "FIRST_TAB":
- self.parent.goto_tab(0)
- elif type == "LAST_TAB":
- self.parent.goto_tab(-1)
- elif type == "PRESET_TABS":
- self.parent.parse_command(["preset"] + args.split())
- elif type == "BRING_TO_FRONT":
- self.parent.window.present()
- elif type == "CLEAN_TABS":
- self.parent.clean_slate()
- elif type == "EXIT_ALL_TABS":
- self.parent.quitrequest()
-
-
- def close(self):
- '''The remote instance exited'''
-
- if self._client:
- self._client.close()
- self._client = None
-
-
-class UzblTabbed:
- '''A tabbed version of uzbl using gtk.Notebook'''
-
- def __init__(self):
- '''Create tablist, window and notebook.'''
-
- self._timers = {}
- self._buffer = ""
- self._killed = False
-
- # A list of the recently closed tabs
- self._closed = []
-
- # Holds metadata on the uzbl childen open.
- self.tabs = {}
-
- # Uzbl sockets (socket => SocketClient)
- self.clients = {}
-
- # Generates a unique id for uzbl socket filenames.
- self.next_pid = counter().next
-
- # Create main window
- self.window = gtk.Window()
- try:
- window_size = map(int, config['window_size'].split(','))
- self.window.set_default_size(*window_size)
-
- except:
- print_exc()
- error("Invalid value for default_size in config file.")
-
- self.window.set_title("Uzbl Browser")
- self.window.set_border_width(0)
-
- # Set main window icon
- icon_path = config['icon_path']
- if os.path.exists(icon_path):
- self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path))
-
- else:
- icon_path = '/usr/share/uzbl/examples/data/uzbl.png'
- if os.path.exists(icon_path):
- self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path))
-
- # Attach main window event handlers
- self.window.connect("delete-event", self.quitrequest)
-
- # Create tab list
- vbox = gtk.VBox()
- self.vbox = vbox
- self.window.add(vbox)
- ebox = gtk.EventBox()
- self.ebox = ebox
- self.tablist = gtk.Label()
-
- self.tablist.set_use_markup(True)
- self.tablist.set_justify(gtk.JUSTIFY_LEFT)
- self.tablist.set_line_wrap(False)
- self.tablist.set_selectable(False)
- self.tablist.set_padding(2,2)
- self.tablist.set_alignment(0,0)
- self.tablist.set_ellipsize(pango.ELLIPSIZE_END)
- self.tablist.set_text(" ")
- self.tablist.show()
- ebox.add(self.tablist)
- ebox.show()
- bgcolor = gtk.gdk.color_parse(config['status_background'])
- ebox.modify_bg(gtk.STATE_NORMAL, bgcolor)
-
- # Create notebook
- self.notebook = gtk.Notebook()
- self.notebook.set_show_tabs(config['show_gtk_tabs'])
-
- # Set tab position
- self.update_gtk_tab_pos()
-
- self.notebook.set_show_border(False)
- self.notebook.set_scrollable(True)
- self.notebook.set_border_width(0)
-
- self.notebook.connect("page-removed", self.tab_closed)
- self.notebook.connect("switch-page", self.tab_changed)
- self.notebook.connect("page-added", self.tab_opened)
- self.notebook.connect("page-reordered", self.tab_reordered)
-
- self.notebook.show()
- vbox.pack_start(self.notebook, True, True, 0)
- vbox.reorder_child(self.notebook, 1)
- self.update_tablist_display()
-
- self.vbox.show()
- self.window.show()
- self.wid = self.notebook.window.xid
-
- # Store information about the applications fifo and socket.
- fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid()
- socket_filename = 'uzbltabbed_%d.socket' % os.getpid()
- self._fifo = None
- self._socket = None
- self.fifo_path = os.path.join(config['fifo_dir'], fifo_filename)
- self.socket_path = os.path.join(config['socket_dir'], socket_filename)
-
- # Now initialise the fifo and the socket
- self.init_fifo()
- self.init_socket()
-
- # If we are using sessions then load the last one if it exists.
- if config['save_session']:
- self.load_session()
-
-
- def run(self):
- '''UzblTabbed main function that calls the gtk loop.'''
-
- if not self.clients and not SocketClient.instances_queue and not self.tabs:
- self.new_tab()
-
- gtk_refresh = int(config['gtk_refresh'])
- if gtk_refresh < 100:
- gtk_refresh = 100
-
- # Make SIGTERM act orderly.
- signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM))
-
- # Catch keyboard interrupts
- signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT))
-
- try:
- gtk.main()
-
- except:
- print_exc()
- error("encounted error %r" % sys.exc_info()[1])
-
- # Unlink fifo socket
- self.unlink_fifo()
- self.close_socket()
-
- # Attempt to close all uzbl instances nicely.
- self.quitrequest()
-
- # Allow time for all the uzbl instances to quit.
- time.sleep(1)
-
- raise
-
- def terminate(self, termsig=None):
- '''Handle termination signals and exit safely and cleanly.'''
-
- # Not required but at least it lets the user know what killed his
- # browsing session.
- if termsig == SIGTERM:
- error("caught SIGTERM signal")
-
- elif termsig == SIGINT:
- error("caught keyboard interrupt")
-
- else:
- error("caught unknown signal")
-
- error("commencing infanticide!")
-
- # Sends the exit signal to all uzbl instances.
- self.quitrequest()
-
-
- def init_socket(self):
- '''Create interprocess communication socket.'''
-
- def accept(sock, condition):
- '''A new uzbl instance was created'''
-
- client, _ = sock.accept()
- self.clients[client] = SocketClient(client)
-
- return True
-
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- sock.bind(self.socket_path)
- sock.listen(1)
-
- # Add event handler for IO_IN event.
- self._socket = (sock, io_add_watch(sock, IO_IN, accept))
-
- echo("[socket] listening at %r" % self.socket_path)
-
- # Add atexit register to destroy the socket on program termination.
- atexit.register(self.close_socket)
-
-
- def close_socket(self):
- '''Close the socket when closing the application'''
-
- if self._socket:
- (fd, watcher) = self._socket
- source_remove(watcher)
- fd.close()
- os.unlink(self.socket_path)
- self._socket = None
-
-
- def init_fifo(self):
- '''Create interprocess communication fifo.'''
-
- if os.path.exists(self.fifo_path):
- if not os.access(self.fifo_path, os.F_OK | os.R_OK | os.W_OK):
- os.mkfifo(self.fifo_path)
-
- else:
- basedir = os.path.dirname(self.fifo_path)
- if not os.path.exists(basedir):
- os.makedirs(basedir)
-
- os.mkfifo(self.fifo_path)
-
- # Add event handlers for IO_IN & IO_HUP events.
- self.setup_fifo_watchers()
-
- echo("[fifo] listening at %r" % self.fifo_path)
-
- # Add atexit register to destroy the fifo on program termination.
- atexit.register(self.unlink_fifo)
-
-
- def unlink_fifo(self):
- '''Unlink the fifo socket. Note: This function is called automatically
- on exit by an atexit register.'''
-
- # Make sure the fifo fd is closed.
- self.close_fifo()
-
- # And unlink if the real fifo exists.
- if os.path.exists(self.fifo_path):
- os.unlink(self.fifo_path)
- echo("unlinked %r" % self.fifo_path)
-
-
- def close_fifo(self):
- '''Remove all event handlers watching the fifo and close the fd.'''
-
- # Already closed
- if self._fifo is None: return
-
- (fd, watchers) = self._fifo
- os.close(fd)
-
- # Stop all gobject io watchers watching the fifo.
- for gid in watchers:
- source_remove(gid)
-
- self._fifo = None
-
-
- def setup_fifo_watchers(self):
- '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event
- handlers.'''
-
- # Close currently open fifo fd and kill all watchers
- self.close_fifo()
-
- fd = os.open(self.fifo_path, os.O_RDONLY | os.O_NONBLOCK)
-
- # Add gobject io event handlers to the fifo socket.
- watchers = [io_add_watch(fd, IO_IN, self.main_fifo_read),\
- io_add_watch(fd, IO_HUP, self.main_fifo_hangup)]
-
- self._fifo = (fd, watchers)
-
-
- def main_fifo_hangup(self, fd, cb_condition):
- '''Handle main fifo socket hangups.'''
-
- # Close old fd, open new fifo socket and add io event handlers.
- self.setup_fifo_watchers()
-
- # Kill the gobject event handler calling this handler function.
- return False
-
-
- def main_fifo_read(self, fd, cb_condition):
- '''Read from main fifo socket.'''
-
- self._buffer = os.read(fd, 1024)
- temp = self._buffer.split("\n")
- self._buffer = temp.pop()
- cmds = [s.strip().split() for s in temp if len(s.strip())]
-
- for cmd in cmds:
- try:
- #print cmd
- self.parse_command(cmd)
-
- except:
- print_exc()
- error("parse_command: invalid command %s" % ' '.join(cmd))
- raise
-
- return True
-
-
- def parse_command(self, cmd):
- '''Parse instructions from uzbl child processes.'''
-
- # Commands ( [] = optional, {} = required )
- # new [uri]
- # open new tab and head to optional uri.
- # newbg [uri]
- # open a new tab in the background
- # close [tab-num]
- # close current tab or close via tab id.
- # next [n-tabs]
- # open next tab or n tabs down. Supports negative indexing.
- # prev [n-tabs]
- # open prev tab or n tabs down. Supports negative indexing.
- # goto {tab-n}
- # goto tab n.
- # first
- # goto first tab.
- # last
- # goto last tab.
- # title {pid} {document-title}
- # updates tablist title.
- # uri {pid} {document-location}
- # updates tablist uri
- # bring_to_front
- # brings the gtk window to focus.
- # exit
- # exits uzbl_tabbed.py
-
- if cmd[0] == "new":
- if len(cmd) == 2:
- self.new_tab(cmd[1])
-
- else:
- self.new_tab()
-
- elif cmd[0] == "newbg":
- if len(cmd) == 2:
- self.new_tab(cmd[1], switch=False)
- else:
- self.new_tab(switch=False)
-
- elif cmd[0] == "newfromclip":
- uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\
- stdout=subprocess.PIPE).communicate()[0]
- if uri:
- self.new_tab(uri)
-
- elif cmd[0] == "close":
- if len(cmd) == 2:
- self.close_tab(int(cmd[1]))
-
- else:
- self.close_tab()
-
- elif cmd[0] == "next":
- if len(cmd) == 2:
- self.next_tab(int(cmd[1]))
-
- else:
- self.next_tab()
-
- elif cmd[0] == "prev":
- if len(cmd) == 2:
- self.prev_tab(int(cmd[1]))
-
- else:
- self.prev_tab()
-
- elif cmd[0] == "goto":
- self.goto_tab(int(cmd[1]))
-
- elif cmd[0] == "first":
- self.goto_tab(0)
-
- elif cmd[0] == "last":
- self.goto_tab(-1)
-
- elif cmd[0] in ["title", "uri"]:
- if len(cmd) > 2:
- uzbl = self.get_tab_by_name(int(cmd[1]))
- if uzbl:
- old = getattr(uzbl, cmd[0])
- new = ' '.join(cmd[2:])
- setattr(uzbl, cmd[0], new)
- if old != new:
- self.update_tablist()
-
- else:
- error("parse_command: no uzbl with name %r" % int(cmd[1]))
-
- elif cmd[0] == "preset":
- if len(cmd) < 3:
- error("parse_command: invalid preset command")
-
- elif cmd[1] == "save":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- self.save_session(path)
-
- elif cmd[1] == "load":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- self.load_session(path)
-
- elif cmd[1] == "del":
- path = os.path.join(config['saved_sessions_dir'], cmd[2])
- if os.path.isfile(path):
- os.remove(path)
-
- else:
- error("parse_command: preset %r does not exist." % path)
-
- elif cmd[1] == "list":
- uzbl = self.get_tab_by_name(int(cmd[2]))
- if uzbl:
- if not os.path.isdir(config['saved_sessions_dir']):
- js = "js alert('No saved presets.');"
- uzbl._client.send(js)
-
- else:
- listdir = os.listdir(config['saved_sessions_dir'])
- listdir = "\\n".join(listdir)
- js = "js alert('Session presets:\\n\\n%s');" % listdir
- uzbl._client.send(js)
-
- else:
- error("parse_command: unknown tab name.")
-
- else:
- error("parse_command: unknown parse command %r"\
- % ' '.join(cmd))
-
- elif cmd[0] == "bring_to_front":
- self.window.present()
-
- elif cmd[0] == "clean":
- self.clean_slate()
-
- elif cmd[0] == "exit":
- self.quitrequest()
-
- else:
- error("parse_command: unknown command %r" % ' '.join(cmd))
-
-
- def get_tab_by_name(self, name):
- '''Return uzbl instance by name.'''
-
- for (tab, uzbl) in self.tabs.items():
- if uzbl.name == name:
- return uzbl
-
- return False
-
-
- def new_tab(self, uri='', title='', switch=None, next=False):
- '''Add a new tab to the notebook and start a new instance of uzbl.
- Use the switch option to negate config['switch_to_new_tabs'] option
- when you need to load multiple tabs at a time (I.e. like when
- restoring a session from a file).'''
-
- tab = gtk.Socket()
- tab.show()
- self.notebook.insert_page(tab, position=next and self.notebook.get_current_page() + 1 or -1)
- self.notebook.set_tab_reorderable(tab, True)
- sid = tab.get_id()
- uri = uri.strip()
- name = "%d-%d" % (os.getpid(), self.next_pid())
-
- if switch is None:
- switch = config['switch_to_new_tabs']
-
- if not title:
- title = config['new_tab_title']
-
- cmd = ['uzbl-browser', '-n', name, '-s', str(sid),
- '--connect-socket', self.socket_path, '--uri', uri]
- gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
-
- uzbl = UzblInstance(self, tab, name, uri, title, switch)
- SocketClient.instances_queue[name] = uzbl
- self.tabs[tab] = uzbl
-
-
- def clean_slate(self):
- '''Close all open tabs and open a fresh brand new one.'''
-
- self.new_tab()
- tabs = self.tabs.keys()
- for tab in list(self.notebook)[:-1]:
- if tab not in tabs: continue
- uzbl = self.tabs[tab]
- uzbl.exit()
-
-
- def config_uzbl(self, uzbl):
- '''Send bind commands for tab new/close/next/prev to a uzbl
- instance.'''
-
- # Set definitions here
- # set(key, command back to fifo)
- if config['capture_new_windows']:
- uzbl.set("new_window", r'new $8')
-
-
- def goto_tab(self, index):
- '''Goto tab n (supports negative indexing).'''
-
- title_format = "%s - Uzbl Browser"
-
- tabs = list(self.notebook)
- if 0 <= index < len(tabs):
- self.notebook.set_current_page(index)
- uzbl = self.tabs[self.notebook.get_nth_page(index)]
- self.window.set_title(title_format % uzbl.title)
- self.update_tablist()
- return None
-
- try:
- tab = tabs[index]
- # Update index because index might have previously been a
- # negative index.
- index = tabs.index(tab)
- self.notebook.set_current_page(index)
- uzbl = self.tabs[self.notebook.get_nth_page(index)]
- self.window.set_title(title_format % uzbl.title)
- self.update_tablist()
-
- except IndexError:
- pass
-
-
- def next_tab(self, step=1):
- '''Switch to next tab or n tabs right.'''
-
- if step < 1:
- error("next_tab: invalid step %r" % step)
- return None
-
- ntabs = self.notebook.get_n_pages()
- tabn = (self.notebook.get_current_page() + step) % ntabs
- self.goto_tab(tabn)
-
-
- def prev_tab(self, step=1):
- '''Switch to prev tab or n tabs left.'''
-
- if step < 1:
- error("prev_tab: invalid step %r" % step)
- return None
-
- ntabs = self.notebook.get_n_pages()
- tabn = self.notebook.get_current_page() - step
- while tabn < 0: tabn += ntabs
- self.goto_tab(tabn)
-
-
- def close_tab(self, tabn=None):
- '''Closes current tab. Supports negative indexing.'''
-
- if tabn is None:
- tabn = self.notebook.get_current_page()
-
- else:
- try:
- tab = list(self.notebook)[tabn]
-
- except IndexError:
- error("close_tab: invalid index %r" % tabn)
- return None
-
- self.notebook.remove_page(tabn)
-
-
- def tab_opened(self, notebook, tab, index):
- '''Called upon tab creation. Called by page-added signal.'''
-
- if config['switch_to_new_tabs']:
- self.notebook.set_focus_child(tab)
-
- else:
- oldindex = self.notebook.get_current_page()
- oldtab = self.notebook.get_nth_page(oldindex)
- self.notebook.set_focus_child(oldtab)
-
-
- def tab_closed(self, notebook, tab, index):
- '''Close the window if no tabs are left. Called by page-removed
- signal.'''
-
- if tab in self.tabs.keys():
- uzbl = self.tabs[tab]
- uzbl.close()
-
- self._closed.append((uzbl.uri, uzbl.title))
- self._closed = self._closed[-10:]
- del self.tabs[tab]
-
- if self.notebook.get_n_pages() == 0:
- if not self._killed and config['save_session']:
- if os.path.exists(config['session_file']):
- os.remove(config['session_file'])
-
- self.quit()
-
- for tab in self.notebook:
- self.tabs[tab].title_changed(True)
- self.update_tablist()
-
- return True
-
-
- def tab_changed(self, notebook, page, index):
- '''Refresh tab list. Called by switch-page signal.'''
-
- tab = self.notebook.get_nth_page(index)
- self.notebook.set_focus_child(tab)
- self.update_tablist(index)
- return True
-
-
- def tab_reordered(self, notebook, page, index):
- '''Refresh tab titles. Called by page-reordered signal.'''
-
- for tab in self.notebook:
- self.tabs[tab].title_changed(True)
- return True
-
-
- def update_tablist_display(self):
- '''Called when show_tablist or tablist_top has changed'''
-
- if self.ebox in self.vbox.get_children():
- self.vbox.remove(self.ebox)
-
- if config['show_tablist']:
- self.vbox.pack_start(self.ebox, False, False, 0)
- if config['tablist_top']:
- self.vbox.reorder_child(self.ebox, 0)
- else:
- self.vbox.reorder_child(self.ebox, 2)
-
- def update_gtk_tab_pos(self):
- ''' Called when gtk_tab_pos has changed '''
-
- allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT,
- 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM}
- if config['gtk_tab_pos'] in allposes.keys():
- self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']])
-
-
- def update_tablist(self, curpage=None):
- '''Upate tablist status bar.'''
-
- if not config['show_tablist']:
- return True
-
- tab_titles = config['tab_titles']
- tab_indexes = config['tab_indexes']
- multiline_tabs = config['multiline_tabs']
-
- if multiline_tabs:
- multiline = []
-
- tabs = self.tabs.keys()
- if curpage is None:
- curpage = self.notebook.get_current_page()
-
- pango = ""
- normal = (config['tab_colours'], config['tab_text_colours'])
- selected = (config['selected_tab'], config['selected_tab_text'])
-
- if tab_titles and tab_indexes:
- tab_format = "<span %(tabc)s> [ %(index)d <span %(textc)s> %(title)s</span> ] </span>"
- elif tab_titles:
- tab_format = "<span %(tabc)s> [ <span %(textc)s>%(title)s</span> ] </span>"
- else:
- tab_format = "<span %(tabc)s> [ <span %(textc)s>%(index)d</span> ] </span>"
-
- for index, tab in enumerate(self.notebook):
- if tab not in tabs: continue
- uzbl = self.tabs[tab]
- title = escape(uzbl.tabtitle)
-
- style = colour_selector(index, curpage, uzbl)
- (tabc, textc) = style
-
- if multiline_tabs:
- opango = pango
-
- pango += tab_format % locals()
-
- self.tablist.set_markup(pango)
- listwidth = self.tablist.get_layout().get_pixel_size()[0]
- winwidth = self.window.get_size()[0]
-
- if listwidth > (winwidth - 20):
- multiline.append(opango)
- pango = tab_format % locals()
- else:
- pango += tab_format % locals()
-
- if multiline_tabs:
- multiline.append(pango)
- self.tablist.set_markup('&#10;'.join(multiline))
-
- else:
- self.tablist.set_markup(pango)
-
- return True
-
-
- def save_session(self, session_file=None):
- '''Save the current session to file for restoration on next load.'''
-
- if session_file is None:
- session_file = config['session_file']
-
- tabs = self.tabs.keys()
- lines = "curtab = %d\n" % self.notebook.get_current_page()
- for tab in list(self.notebook):
- if tab not in tabs:
- continue
-
- uzbl = self.tabs[tab]
- if not uzbl.uri:
- continue
-
- lines += "%s %s\n" % (uzbl.uri, uzbl.title)
-
- if not os.path.isfile(session_file):
- dirname = os.path.dirname(session_file)
- if not os.path.isdir(dirname):
- os.makedirs(dirname)
-
- fh = open(session_file, 'w')
- fh.write(lines)
- fh.close()
-
-
- def load_session(self, session_file=None):
- '''Load a saved session from file.'''
-
- default_path = False
- delete_loaded = False
-
- if session_file is None:
- default_path = True
- delete_loaded = True
- session_file = config['session_file']
-
- if not os.path.isfile(session_file):
- return False
-
- fh = open(session_file, 'r')
- raw = fh.read()
- fh.close()
-
- tabs = []
- curtab = 0
-
- lines = filter(None, map(str.strip, raw.split('\n')))
- if len(lines) < 2:
- error("Error: The session file %r looks invalid." % session_file)
- if delete_loaded and os.path.exists(session_file):
- os.remove(session_file)
-
- return None
-
- try:
- for line in lines:
- if line.startswith("curtab"):
- curtab = int(line.split()[-1])
-
- else:
- uri, title = map(str.strip, line.split(" ", 1))
- tabs += [(uri, title),]
-
- except:
- print_exc()
- error("Warning: failed to load session file %r" % session_file)
- return None
-
- # Now populate notebook with the loaded session.
- for (index, (uri, title)) in enumerate(tabs):
- self.new_tab(uri=uri, title=title, switch=(curtab==index))
-
- # A saved session has been loaded now delete it.
- if delete_loaded and os.path.exists(session_file):
- os.remove(session_file)
-
-
- def quitrequest(self, *args):
- '''Attempt to close all uzbl instances nicely and exit.'''
-
- self._killed = True
-
- if config['save_session']:
- if len(list(self.notebook)) > 1:
- self.save_session()
-
- else:
- # Notebook has one page open so delete the session file.
- if os.path.isfile(config['session_file']):
- os.remove(config['session_file'])
-
- for (tab, uzbl) in self.tabs.items():
- uzbl.exit()
-
- # Add a gobject timer to make sure the application force-quits after a
- # reasonable period. Calling quit when all the tabs haven't had time to
- # close should be a last resort.
- timer = "force-quit"
- timerid = timeout_add(5000, self.quit, timer)
- self._timers[timer] = timerid
-
-
- def quit(self, *args):
- '''Cleanup and quit. Called by delete-event signal.'''
-
- # Close the fifo socket, remove any gobject io event handlers and
- # delete socket.
- self.unlink_fifo()
- self.close_socket()
-
- # Remove all gobject timers that are still ticking.
- for (timerid, gid) in self._timers.items():
- source_remove(gid)
- del self._timers[timerid]
-
- try:
- gtk.main_quit()
-
- except:
- pass
-
-
-if __name__ == "__main__":
-
- # Build command line parser
- usage = "usage: %prog [OPTIONS] {URIS}..."
- parser = OptionParser(usage=usage)
- parser.add_option('-n', '--no-session', dest='nosession',
- action='store_true', help="ignore session saving a loading.")
- parser.add_option('-v', '--verbose', dest='verbose',
- action='store_true', help='print verbose output.')
-
- # Parse command line options
- (options, uris) = parser.parse_args()
-
- if options.nosession:
- config['save_session'] = False
-
- if options.verbose:
- config['verbose'] = True
-
- if config['verbose']:
- import pprint
- sys.stderr.write("%s\n" % pprint.pformat(config))
-
- uzbl = UzblTabbed()
-
- # All extra arguments given to uzbl_tabbed.py are interpreted as
- # web-locations to opened in new tabs.
- lasturi = len(uris)-1
- for (index,uri) in enumerate(uris):
- uzbl.new_tab(uri, switch=(index==lasturi))
-
- uzbl.run()