aboutsummaryrefslogtreecommitdiffhomepage
path: root/bin
diff options
context:
space:
mode:
authorGravatar keis <keijser@gmail.com>2011-07-28 22:31:30 +0200
committerGravatar keis <keijser@gmail.com>2011-07-28 22:31:30 +0200
commitdb61f092140205e71f40fb14dc98a1e650c7e527 (patch)
tree6a2459ae08c6baa4875b1db226dc7eb615a3cd3c /bin
parent1e20430333aee952f55f6caec4d55238a0160bf9 (diff)
parente035f6f991fdbe9862a72fba6e8d348dcc25532f (diff)
Merge branch 'experimental' of git://github.com/Dieterbe/uzbl into mouse-events
Diffstat (limited to 'bin')
-rwxr-xr-xbin/uzbl-event-manager300
-rwxr-xr-xbin/uzbl-tabbed564
2 files changed, 351 insertions, 513 deletions
diff --git a/bin/uzbl-event-manager b/bin/uzbl-event-manager
index cb462c7..64a1354 100755
--- a/bin/uzbl-event-manager
+++ b/bin/uzbl-event-manager
@@ -30,21 +30,22 @@ import atexit
import imp
import logging
import os
-import socket
import sys
import time
import weakref
import re
+import errno
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 signal import signal, SIGTERM, SIGINT, SIGKILL
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.'''
@@ -65,14 +66,19 @@ CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/')
# Define some globals.
SCRIPTNAME = os.path.basename(sys.argv[0])
+logger = logging.getLogger(SCRIPTNAME)
+
+
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.'''
@@ -89,7 +95,7 @@ def daemonize():
os._exit(0)
except OSError:
- logger.critical(get_exc())
+ logger.critical('failed to daemonize', exc_info=True)
sys.exit(1)
os.chdir('/')
@@ -101,7 +107,7 @@ def daemonize():
os._exit(0)
except OSError:
- logger.critical(get_exc())
+ logger.critical('failed to daemonize', exc_info=True)
sys.exit(1)
if sys.stdout.isatty():
@@ -126,11 +132,11 @@ def make_dirs(path):
try:
dirname = os.path.dirname(path)
if not os.path.isdir(dirname):
- logger.debug('creating directories %r' % dirname)
+ logger.debug('creating directories %r', dirname)
os.makedirs(dirname)
except OSError:
- logger.error(get_exc())
+ logger.error('failed to create directories', exc_info=True)
class EventHandler(object):
@@ -147,7 +153,6 @@ class EventHandler(object):
self.args = args
self.kwargs = kwargs
-
def __repr__(self):
elems = ['id=%d' % self.id, 'event=%s' % self.event,
'callback=%r' % self.callback]
@@ -161,7 +166,6 @@ class EventHandler(object):
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.'''
@@ -170,9 +174,6 @@ class EventHandler(object):
self.callback(uzbl, *args, **kwargs)
-
-
-
class Plugin(object):
'''Plugin module wrapper object.'''
@@ -181,13 +182,12 @@ class Plugin(object):
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)
+ self.logger = logging.getLogger('plugin.%s' % name)
# Weakrefs to all handlers created by this plugin
self.handlers = set([])
@@ -210,13 +210,11 @@ class Plugin(object):
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
+ def export(self, uzbl, attr, obj, prepend=True):
+ '''Attach `obj` to `uzbl` instance. This is the preferred method
of sharing functionality, functions, data and objects between
plugins.
@@ -228,18 +226,16 @@ class Plugin(object):
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))
-
+ prepend = True if prepend and callable(obj) else False
+ uzbl.__dict__[attr] = partial(obj, uzbl) if prepend else obj
+ uzbl.exports[attr] = (self, obj, prepend)
+ uzbl.logger.info('exported %r to %r by plugin %r, prepended %r',
+ obj, '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.'''
@@ -253,7 +249,6 @@ class Plugin(object):
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.
@@ -276,24 +271,22 @@ class Plugin(object):
# Create a new handler
handler = EventHandler(self, event, callback, args, kwargs)
self.handlers.add(weakref.ref(handler))
- self.logger.info('new %r' % handler)
+ self.logger.info('new %r', handler)
uzbl.handlers[event].append(handler)
- uzbl.logger.info('connected %r' % 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))
+ 'plugin %r required by plugin %r', plugin, self.name)
@classmethod
def unquote(cls, s):
@@ -304,10 +297,12 @@ class Plugin(object):
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()]
+ parts = cls._splitquoted.split(text)
+ return [cls.unquote(p) for p in parts if p.strip()]
class Uzbl(object):
@@ -315,6 +310,7 @@ class Uzbl(object):
self.opts = opts
self.parent = parent
self.child_socket = child_socket
+ self.child_buffer = []
self.time = time.time()
self.pid = None
self.name = None
@@ -323,7 +319,7 @@ class Uzbl(object):
self.instance_start = False
# Use name "unknown" until name is discovered.
- self.logger = get_logger('uzbl-instance[]')
+ self.logger = logging.getLogger('uzbl-instance[]')
# Track plugin event handlers and exported functions.
self.exports = {}
@@ -333,16 +329,14 @@ class Uzbl(object):
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),
+ '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.'''
@@ -350,17 +344,16 @@ class Uzbl(object):
# 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)
+ 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)
+ 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.'''
@@ -371,8 +364,27 @@ class Uzbl(object):
if opts.print_events:
print ascii(u'%s<-- %s' % (' ' * self._depth, msg))
- self.child_socket.send(ascii("%s\n" % msg))
+ self.child_buffer.append(ascii("%s\n" % msg))
+ def do_send(self):
+ data = ''.join(self.child_buffer)
+ try:
+ bsent = self.child_socket.send(data)
+ except socket.error as e:
+ if e.errno in (errno.EAGAIN, errno.EINTR):
+ self.child_buffer = [data]
+ return
+ else:
+ self.logger.error('failed to send', exc_info=True)
+ return self.close()
+ else:
+ if bsent == 0:
+ self.logger.debug('write end of connection closed')
+ self.close()
+ elif bsent < len(data):
+ self.child_buffer = [data[bsent:]]
+ else:
+ del self.child_buffer[:]
def read(self):
'''Read data from the child socket and pass lines to the parse_msg
@@ -385,7 +397,7 @@ class Uzbl(object):
return self.close()
except:
- self.logger.error(get_exc())
+ self.logger.error('failed to read', exc_info=True)
return self.close()
lines = (self._buffer + raw).split('\n')
@@ -399,17 +411,16 @@ class Uzbl(object):
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]
+ elems = (line.split(' ', 3) + [''] * 3)[:4]
# Ignore non-event messages.
if elems[0] != 'EVENT':
- logger.info('non-event message: %r' % line)
+ logger.info('non-event message: %r', line)
if opts.print_events:
print '--- %s' % ascii(line)
return
@@ -419,31 +430,32 @@ class Uzbl(object):
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)
+ self.logger = logging.getLogger('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))
+ 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.logger.info('found instance pid %r', self.pid)
self.init_plugins()
@@ -460,16 +472,14 @@ class Uzbl(object):
handler.call(self, *args, **kargs)
except:
- self.logger.error(get_exc())
+ self.logger.error('error in handler', exc_info=True)
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.'''
@@ -486,7 +496,7 @@ class Uzbl(object):
self.child_socket.close()
except:
- self.logger.error(get_exc())
+ self.logger.error('failed to close socket', exc_info=True)
finally:
self.child_socket = None
@@ -494,11 +504,11 @@ class Uzbl(object):
# Call plugins cleanup hooks.
for plugin in self.parent.plugins.values():
if plugin.cleanup:
- self.logger.debug('calling %r plugin cleanup hook'
- % plugin.name)
+ self.logger.debug('calling %r plugin cleanup hook',
+ plugin.name)
plugin.cleanup(self)
- logger.info('removed %r' % self)
+ logger.info('removed %r', self)
class UzblEventDaemon(object):
@@ -529,16 +539,15 @@ class UzblEventDaemon(object):
# 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)
+ 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,])
+ info = imp.find_module(name, [dir])
module = imp.load_module(name, *info)
# Check if the plugin has a callable hook.
@@ -546,11 +555,10 @@ class UzblEventDaemon(object):
for attr in ['init', 'after', 'cleanup']])
assert hooks, "no hooks in plugin %r" % module
- logger.debug('creating plugin instance for %r plugin' % name)
+ logger.debug('creating plugin instance for %r plugin', name)
plugin = Plugin(self, name, path, module)
self.plugins[name] = plugin
- logger.info('new %r' % plugin)
-
+ logger.info('new %r', plugin)
def create_server_socket(self):
'''Create the event manager daemon socket for uzbl instance duplex
@@ -564,8 +572,7 @@ class UzblEventDaemon(object):
sock.listen(5)
self.server_socket = sock
- logger.debug('bound server socket to %r' % opts.server_socket)
-
+ logger.debug('bound server socket to %r', opts.server_socket)
def run(self):
'''Main event daemon loop.'''
@@ -588,35 +595,39 @@ class UzblEventDaemon(object):
except:
if not self._quit:
- logger.critical(get_exc())
+ logger.critical('failed to listen', exc_info=True)
# 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)
+ 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)
+ wsocks = [k for k, v in self.uzbls.items() if v.child_buffer]
+ reads, writes, errors = select(socks, wsocks, 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]
+ child_socket.setblocking(False)
self.uzbls[child_socket] = Uzbl(self, child_socket)
connections += 1
+ for uzbl in [self.uzbls[s] for s in writes]:
+ uzbl.do_send()
+
for uzbl in [self.uzbls[s] for s in reads]:
uzbl.read()
@@ -626,7 +637,6 @@ class UzblEventDaemon(object):
logger.info('auto closing')
-
def close_server_socket(self):
'''Close and delete the server socket.'''
@@ -637,12 +647,11 @@ class UzblEventDaemon(object):
self.server_socket = None
if os.path.exists(opts.server_socket):
- logger.info('unlinking %r' % opts.server_socket)
+ logger.info('unlinking %r', opts.server_socket)
os.unlink(opts.server_socket)
except:
- logger.error(get_exc())
-
+ logger.error('failed to close server socket', exc_info=True)
def quit(self, sigint=None, *args):
'''Close all instance socket objects, server socket and delete the
@@ -673,16 +682,16 @@ def make_pid_file(pid_file):
'''Creates a pid file at `pid_file`, fails silently.'''
try:
- logger.debug('creating pid file %r' % pid_file)
+ 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))
+ logger.info('created pid file %r with pid %d', pid_file, pid)
except:
- logger.error(get_exc())
+ logger.error('failed to create pid file', exc_info=True)
def del_pid_file(pid_file):
@@ -690,27 +699,27 @@ def del_pid_file(pid_file):
if os.path.isfile(pid_file):
try:
- logger.debug('deleting pid file %r' % pid_file)
+ logger.debug('deleting pid file %r', pid_file)
os.remove(pid_file)
- logger.info('deleted pid file %r' % pid_file)
+ logger.info('deleted pid file %r', pid_file)
except:
- logger.error(get_exc())
+ logger.error('failed to delete pid file', exc_info=True)
def get_pid(pid_file):
'''Reads a pid from pid file `pid_file`, fails None.'''
try:
- logger.debug('reading pid file %r' % pid_file)
+ 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))
+ logger.info('read pid %d from pid file %r', pid, pid_file)
return pid
except (IOError, ValueError):
- logger.error(get_exc())
+ logger.error('failed to read pid', exc_info=True)
return None
@@ -729,30 +738,30 @@ 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)
+ 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)
+ 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)
+ 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)
+ 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())
+ logger.critical('failed to kill %d', pid, exc_info=True)
raise
- if (time.time()-start) > 10:
- logger.critical('unable to kill process with pid %d' % pid)
+ if (time.time() - start) > 10:
+ logger.critical('unable to kill process with pid %d', pid)
raise OSError
time.sleep(0.25)
@@ -763,20 +772,20 @@ def stop_action():
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)
+ logger.error('could not find running event manager with pid file %r',
+ pid_file)
return
pid = get_pid(pid_file)
if not pid_running(pid):
- logger.debug('no process with pid %r' % pid)
+ logger.debug('no process with pid %r', pid)
del_pid_file(pid_file)
return
- logger.debug('terminating process with pid %r' % pid)
+ 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)
+ logger.info('stopped event manager process with pid %d', pid)
def start_action():
@@ -786,10 +795,10 @@ def start_action():
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)
+ logger.error('event manager already started with pid %d', pid)
return
- logger.info('no process with pid %d' % pid)
+ logger.info('no process with pid %d', pid)
del_pid_file(pid_file)
UzblEventDaemon().run()
@@ -816,7 +825,7 @@ def list_action():
print plugin
-if __name__ == "__main__":
+def make_parser():
parser = OptionParser('usage: %prog [options] {start|stop|restart|list}')
add = parser.add_option
@@ -833,6 +842,7 @@ if __name__ == "__main__":
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')
@@ -862,6 +872,34 @@ if __name__ == "__main__":
dest='print_events', action="store_false", default=True,
help="silence the printing of events to stdout")
+ return parser
+
+
+def init_logger():
+ log_level = logging.CRITICAL - opts.verbose * 10
+ logger = logging.getLogger()
+ logger.setLevel(max(log_level, 10))
+
+ # Console
+ handler = logging.StreamHandler()
+ handler.setLevel(max(log_level + 10, 10))
+ handler.setFormatter(logging.Formatter(
+ '%(name)s: %(levelname)s: %(message)s'))
+ logger.addHandler(handler)
+
+ # Logfile
+ handler = logging.FileHandler(opts.log_file, 'w', 'utf-8', 1)
+ handler.setLevel(max(log_level, 10))
+ handler.setFormatter(logging.Formatter(
+ '[%(created)f] %(name)s: %(levelname)s: %(message)s'))
+ logger.addHandler(handler)
+
+
+def main():
+ global opts
+
+ parser = make_parser()
+
(opts, args) = parser.parse_args()
opts.server_socket = expandpath(opts.server_socket)
@@ -881,35 +919,8 @@ if __name__ == "__main__":
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)
+ init_logger()
+ logger.info('logging to %r', opts.log_file)
plugins = {}
@@ -923,11 +934,11 @@ if __name__ == "__main__":
for plugin in matches:
(head, tail) = os.path.split(plugin)
if tail not in plugins:
- logger.debug('found plugin: %r' % plugin)
+ logger.debug('found plugin: %r', plugin)
plugins[tail] = plugin
else:
- logger.debug('ignoring plugin: %r' % plugin)
+ logger.debug('ignoring plugin: %r', plugin)
# Add default plugin locations
if opts.default_dirs:
@@ -941,15 +952,15 @@ if __name__ == "__main__":
# 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)
+ 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)
+ logger.debug('found plugin: %r', plugin)
plugins[tail] = plugin
else:
- logger.debug('ignoring plugin: %r' % plugin)
+ logger.debug('ignoring plugin: %r', plugin)
plugins = plugins.values()
@@ -958,11 +969,15 @@ if __name__ == "__main__":
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.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')
+ if opts.daemon_mode:
+ logger.debug('will daemonize')
+ else:
+ logger.debug('will not daemonize')
opts.plugins = plugins
@@ -976,16 +991,21 @@ if __name__ == "__main__":
parser.error('invalid action: %r' % action)
elif not args:
- logger.warning('no daemon action given, assuming %r' % 'start')
action = 'start'
+ logger.warning('no daemon action given, assuming %r', action)
else:
parser.error('invalid action argument: %r' % args)
- logger.info('daemon action %r' % action)
+ logger.info('daemon action %r', action)
# Do action
daemon_actions[action]()
- logger.debug('process CPU time: %f' % time.clock())
+ logger.debug('process CPU time: %f', time.clock())
+
+
+if __name__ == "__main__":
+ main()
+
# vi: set et ts=4:
diff --git a/bin/uzbl-tabbed b/bin/uzbl-tabbed
index a15967a..1a65788 100755
--- a/bin/uzbl-tabbed
+++ b/bin/uzbl-tabbed
@@ -72,7 +72,6 @@
# 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:
@@ -88,8 +87,6 @@
# 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
#
@@ -199,7 +196,6 @@ config = {
'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
@@ -215,8 +211,6 @@ config = {
'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.
@@ -298,17 +292,20 @@ def escape(s):
return s
class SocketClient:
- '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance'''
+ '''Represents a connection to the uzbl-tabbed socket.'''
# List of UzblInstance objects not already linked with a SocketClient
instances_queue = {}
- def __init__(self, socket):
+ def __init__(self, socket, uzbl_tabbed):
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
+ self.uzbl_tabbed = uzbl_tabbed
+ self.dispatcher = GlobalEventDispatcher(uzbl_tabbed)
def _socket_recv(self, fd, condition):
@@ -328,26 +325,44 @@ class SocketClient:
'''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 = ""
+ if "\n" in self._buffer:
+ cmds = self._buffer.split("\n")
- 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 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.handle_event(cmd)
+
+ def handle_event(self, cmd):
+ cmd = parse_event(cmd)
+ message, instance_name, message_type = cmd[0:3]
+ args = cmd[3:]
+
+ if not message == "EVENT":
+ return
+
+ # strip the surrounding []
+ instance_name = instance_name[1:-1]
+
+ if self.uzbl:
+ if not self.dispatcher.dispatch(message_type, args):
+ self.uzbl.dispatcher.dispatch(message_type, args)
+ elif message_type == 'INSTANCE_START':
+ uzbl = self.instances_queue.get(instance_name)
if uzbl:
- del self.instances_queue[name[0]]
- self.uzbl = uzbl
- self.uzbl.got_socket(self)
- self._feed("")
+ # we've found the uzbl we were waiting for
+ del self.instances_queue[instance_name]
+ else:
+ # an unsolicited uzbl has connected, how exciting!
+ uzbl = UzblInstance(self.uzbl_tabbed, None, '', '', False)
+ self.uzbl = uzbl
+ self.uzbl.got_socket(self)
+ self._feed("")
def send(self, data):
'''Child socket send function.'''
@@ -363,18 +378,84 @@ class SocketClient:
map(source_remove, self._watchers)
self._watchers = []
-class EventDispatcher:
- def __init__(self, uzbl):
- self.uzbl = uzbl
- self.parent = self.uzbl.parent
+def unquote(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("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
+def parse_event(text):
+ '''Splits string on whitespace while respecting quotations'''
+ return [unquote(p) for p in _splitquoted.split(text) if p.strip()]
+
+class EventDispatcher:
def dispatch(self, message_type, args):
+ '''Returns True if the message was handled, False otherwise.'''
+
method = getattr(self, message_type.lower(), None)
if method is None:
- return
+ return False
+
+ method(*args)
+ return True
+
+class GlobalEventDispatcher(EventDispatcher):
+ def __init__(self, uzbl_tabbed):
+ self.uzbl_tabbed = uzbl_tabbed
+
+ def new_tab(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri)
+
+ def new_tab_bg(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, switch = False)
- return method(*args)
+ def new_tab_next(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, next=True)
+
+ def new_bg_tab_next(self, uri = ''):
+ self.uzbl_tabbed.new_tab(uri, switch = False, next = True)
+
+ def next_tab(self, step = 1):
+ self.uzbl_tabbed.next_tab(int(step))
+
+ def prev_tab(self, step = 1):
+ self.uzbl_tabbed.prev_tab(int(step))
+
+ def goto_tab(self, index):
+ self.uzbl_tabbed.goto_tab(int(index))
+
+ def first_tab(self):
+ self.uzbl_tabbed.goto_tab(0)
+
+ def last_tab(self):
+ self.uzbl_tabbed.goto_tab(-1)
+
+ def preset_tabs(self, *args):
+ self.uzbl_tabbed.run_preset_command(*args)
+
+ def bring_to_front(self):
+ self.uzbl_tabbed.window.present()
+
+ def clean_tabs(self):
+ self.uzbl_tabbed.clean_slate()
+
+ def exit_all_tabs(self):
+ self.uzbl_tabbed.quitrequest()
+
+class InstanceEventDispatcher(EventDispatcher):
+ def __init__(self, uzbl):
+ self.uzbl = uzbl
+ self.parent = self.uzbl.parent
+
+ def plug_created(self, plug_id):
+ if not self.uzbl.tab:
+ tab = self.parent.create_tab()
+ tab.add_id(int(plug_id))
+ self.uzbl.set_tab(tab)
def title_changed(self, title):
self.uzbl.title = title.strip()
@@ -417,71 +498,14 @@ class EventDispatcher:
def load_commit(self, uri):
self.uzbl.uri = uri
- def new_tab(self, uri = None):
- if uri:
- self.parent.new_tab(uri)
- else:
- self.parent.new_tab()
-
- def new_tab_bg(self, uri = None):
- if uri:
- self.parent.new_tab(uri, switch = False)
- else:
- self.parent.new_tab(switch = False)
-
- def new_tab_next(self, uri = None):
- if uri:
- self.parent.new_tab(uri, next=True)
- else:
- self.parent.new_tab(next=True)
-
- def new_bg_tab_next(self, uri = None):
- if uri:
- self.parent.new_tab(uri, switch = False, next = True)
- else:
- self.parent.new_tab(switch = False, next = True)
-
- def next_tab(self, step = None):
- if step:
- self.parent.next_tab(int(step))
- else:
- self.parent.next_tab()
-
- def prev_tab(self, step = None):
- if step:
- self.parent.prev_tab(int(step))
- else:
- self.parent.prev_tab()
-
- def goto_tab(self, index):
- self.parent.goto_tab(int(index))
-
- def first_tab(self):
- self.parent.goto_tab(0)
-
- def last_tab(self):
- self.parent.goto_tab(-1)
-
- def preset_tabs(self, *args):
- self.parent.parse_command(["preset"] + [ a for a in args ])
-
- def bring_to_front(self):
- self.parent.window.present()
-
- def clean_tabs(self):
- self.parent.clean_slate()
-
- def exit_all_tabs(self):
- self.parent.quitrequest()
-
class UzblInstance:
'''Uzbl instance meta-data/meta-action object.'''
- def __init__(self, parent, tab, name, uri, title, switch):
+ def __init__(self, parent, name, uri, title, switch):
self.parent = parent
- self.tab = tab
- self.dispatcher = EventDispatcher(self)
+ self.tab = None
+ self.dispatcher = InstanceEventDispatcher(self)
self.name = name
self.title = title
@@ -490,8 +514,11 @@ class UzblInstance:
self._client = None
self._switch = switch # Switch to tab after loading ?
- self.title_changed()
+ def set_tab(self, tab):
+ self.tab = tab
+ self.title_changed()
+ self.parent.tabs[self.tab] = self
def got_socket(self, client):
'''Uzbl instance is now connected'''
@@ -506,6 +533,9 @@ class UzblInstance:
def title_changed(self, gtk_only = True): # GTK-only is for indexes
'''self.title has changed, update the tabs list'''
+ if not self.tab:
+ return
+
tab_titles = config['tab_titles']
tab_indexes = config['tab_indexes']
show_ellipsis = config['show_ellipsis']
@@ -546,7 +576,8 @@ class UzblInstance:
''' Send the SET command to Uzbl '''
if self._client:
- self._client.send('set %s = %s') #TODO: escape chars ?
+ line = 'set %s = %s' % (key, val) #TODO: escape chars ?
+ self._client.send(line)
def exit(self):
@@ -555,27 +586,6 @@ class UzblInstance:
if self._client:
self._client.send('exit')
- def unquote(self, 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("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
- def parse_event(self, text):
- '''Splits string on whitespace while respecting quotations'''
- return [self.unquote(p) for p in self._splitquoted.split(text) if p.strip()]
-
- def parse_command(self, cmd):
- ''' Parse event givent by the Uzbl instance '''
-
- cmd = self.parse_event(cmd)
- message, message_type, args = cmd[0], cmd[2], cmd[3:]
-
- if message == "EVENT":
- self.dispatcher.dispatch(message_type, args)
-
def close(self):
'''The remote instance exited'''
@@ -606,6 +616,13 @@ class UzblTabbed:
# Generates a unique id for uzbl socket filenames.
self.next_pid = counter().next
+ # Whether to reconfigure new uzbl instances
+ self.force_socket_dir = False
+ self.force_fifo_dir = False
+
+ self.fifo_dir = '/tmp' # Path to look for uzbl fifo.
+ self.socket_dir = '/tmp' # Path to look for uzbl socket.
+
# Create main window
self.window = gtk.Window()
try:
@@ -684,16 +701,12 @@ class UzblTabbed:
self.window.show()
self.wid = self.notebook.window.xid
- # Store information about the applications fifo and socket.
- fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid()
+ # Store information about the application's socket.
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)
+ self.socket_path = os.path.join(self.socket_dir, socket_filename)
- # Now initialise the fifo and the socket
- self.init_fifo()
+ # Now initialise the the socket
self.init_socket()
# If we are using sessions then load the last one if it exists.
@@ -724,8 +737,7 @@ class UzblTabbed:
print_exc()
error("encounted error %r" % sys.exc_info()[1])
- # Unlink fifo socket
- self.unlink_fifo()
+ # Unlink socket
self.close_socket()
# Attempt to close all uzbl instances nicely.
@@ -763,7 +775,7 @@ class UzblTabbed:
'''A new uzbl instance was created'''
client, _ = sock.accept()
- self.clients[client] = SocketClient(client)
+ self.clients[client] = SocketClient(client, self)
return True
@@ -791,249 +803,45 @@ class UzblTabbed:
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)
+ def run_preset_command(self, cmd, *args):
+ if len(args) < 1:
+ error("parse_command: invalid preset command")
- 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 == "save":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ self.save_session(path)
- elif cmd[0] == "prev":
- if len(cmd) == 2:
- self.prev_tab(int(cmd[1]))
+ elif cmd == "load":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ self.load_session(path)
+ elif cmd == "del":
+ path = os.path.join(config['saved_sessions_dir'], args[0])
+ if os.path.isfile(path):
+ os.remove(path)
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)
+ error("parse_command: preset %r does not exist." % path)
- else:
- error("parse_command: preset %r does not exist." % path)
-
- elif cmd[1] == "list":
- # FIXME: what argument is this supposed to be passed,
- # and why?
- 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)
+ elif cmd == "list":
+ # FIXME: what argument is this supposed to be passed,
+ # and why?
+ uzbl = self.get_tab_by_name(int(args[0]))
+ if uzbl:
+ if not os.path.isdir(config['saved_sessions_dir']):
+ js = "js alert('No saved presets.');"
+ uzbl._client.send(js)
else:
- error("parse_command: unknown tab name.")
+ 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 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()
+ error("parse_command: unknown tab name.")
else:
- error("parse_command: unknown command %r" % ' '.join(cmd))
+ error("parse_command: unknown parse command %r" % cmd)
def get_tab_by_name(self, name):
@@ -1045,6 +853,18 @@ class UzblTabbed:
return False
+ def create_tab(self, beside = False):
+ tab = gtk.Socket()
+ tab.show()
+
+ if beside:
+ pos = self.notebook.get_current_page() + 1
+ self.notebook.insert_page(tab, position=pos)
+ else:
+ self.notebook.append_page(tab)
+
+ self.notebook.set_tab_reorderable(tab, True)
+ return tab
def new_tab(self, uri='', title='', switch=None, next=False):
'''Add a new tab to the notebook and start a new instance of uzbl.
@@ -1052,10 +872,7 @@ class UzblTabbed:
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)
+ tab = self.create_tab(next)
sid = tab.get_id()
uri = uri.strip()
name = "%d-%d" % (os.getpid(), self.next_pid())
@@ -1070,9 +887,10 @@ class UzblTabbed:
'--connect-socket', self.socket_path, '--uri', str(uri)]
gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
- uzbl = UzblInstance(self, tab, name, uri, title, switch)
+ uzbl = UzblInstance(self, name, uri, title, switch)
+ uzbl.set_tab(tab)
+
SocketClient.instances_queue[name] = uzbl
- self.tabs[tab] = uzbl
def clean_slate(self):
@@ -1085,16 +903,15 @@ class UzblTabbed:
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')
+ if self.force_socket_dir:
+ uzbl.set("socket_dir", self.socket_dir)
+ if self.force_fifo_dir:
+ uzbl.set("fifo_dir", self.fifo_dir)
def goto_tab(self, index):
'''Goto tab n (supports negative indexing).'''
@@ -1411,9 +1228,8 @@ class UzblTabbed:
def quit(self, *args):
'''Cleanup and quit. Called by delete-event signal.'''
- # Close the fifo socket, remove any gobject io event handlers and
+ # Close the socket, remove any gobject io event handlers and
# delete socket.
- self.unlink_fifo()
self.close_socket()
# Remove all gobject timers that are still ticking.
@@ -1455,13 +1271,15 @@ if __name__ == "__main__":
import pprint
sys.stderr.write("%s\n" % pprint.pformat(config))
+ uzbl = UzblTabbed()
+
if options.socketdir:
- config['socket_dir'] = options.socketdir
+ uzbl.socket_dir = options.socketdir
+ uzbl.force_socket_dir = True
if options.fifodir:
- config['fifo_dir'] = options.fifodir
-
- uzbl = UzblTabbed()
+ uzbl.fifo_dir = options.fifodir
+ uzbl.force_fifo_dir = True
# All extra arguments given to uzbl_tabbed.py are interpreted as
# web-locations to opened in new tabs.