diff options
-rwxr-xr-x | examples/data/uzbl/scripts/event_manager.py | 513 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/bind.py | 49 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/dump_config.py | 11 | ||||
-rw-r--r-- | examples/data/uzbl/scripts/plugins/echo_keys.py | 16 | ||||
-rw-r--r-- | uzbl-core.c | 155 | ||||
-rw-r--r-- | uzbl-core.h | 14 |
6 files changed, 630 insertions, 128 deletions
diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index d6f4a36..5145653 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -1,113 +1,498 @@ #!/usr/bin/env python -# Uzbl sample event manager +# Event Manager for Uzbl +# Copyright (c) 2009, Mason Larobina <mason.larobina@gmail.com> +# Copyright (c) 2009, Dieter Plaetinck <diterer@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 +# 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. +# (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 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. ''' -The Python Event Manager -======================== -Sample event manager written in python +E V E N T _ M A N A G E R . P Y +=============================== + +Event manager for uzbl written in python. Usage +===== + + uzbl | $XDG_DATA_HOME/uzbl/scripts/event_manager.py + +Todo ==== -uzbl | <path to event_manager.py> + + - Command line options including supplying a list of plugins to load or not + load (default is load all plugins in the plugin_dir). + - Spell checking. + ''' -import sys +import imp import os +import sys +import select +import re +import types +import socket +import pprint +from traceback import print_exc -# config dir. needed for bindings config -if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: - CONFIG_DIR = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/') -else: - CONFIG_DIR = os.path.join(os.environ['HOME'], '.config/uzbl/') +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ -# Default config -config = { - 'uzbl_fifo': '', - 'verbose': True, +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' -} # End of config dictionary. + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] -# buffer for building up commands -keycmd = '' + return os.path.join(os.environ['HOME'], default) +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +# Config dict (NOT the same as the uzbl.config). +config = { + 'verbose': True, + 'plugin_dir': "$XDG_DATA_HOME/uzbl/scripts/plugins/" +} + + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +# Define some globals. +_VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match _SCRIPTNAME = os.path.basename(sys.argv[0]) +_TYPECONVERT = {'int': int, 'float': float, 'str': str} + def echo(msg): '''Prints only if the verbose flag has been set.''' if config['verbose']: - sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + sys.stdout.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def counter(): + '''Generate unique object id's.''' + + i = 0 + while True: + i += 1 + yield i + + +class PluginManager(dict): + def __init__(self): + + plugin_dir = os.path.expandvars(config['plugin_dir']) + self.plugin_dir = os.path.realpath(plugin_dir) + if not os.path.exists(self.plugin_dir): + os.makedirs(self.plugin_dir) + + self.load_plugins() + + + def _find_plugins(self): + '''Find all python scripts in plugin dir and return a list of + locations and imp moduleinfo's.''' + + dirlist = os.listdir(self.plugin_dir) + pythonfiles = filter(lambda s: s.endswith('.py'), dirlist) + + plugins = [] + + for filename in pythonfiles: + plugins.append(filename[:-3]) + + return plugins + + + def _unload_plugin(self, plugin, remove_pyc=True): + '''Unload specific plugin and remove all waste in sys.modules + + Notice: manual manipulation of sys.modules is very un-pythonic but I + see no other way to make sure you have 100% unloaded the module. Also + this allows us to implement a reload plugins function.''' + + allmodules = sys.modules.keys() + allrefs = filter(lambda s: s.startswith("%s." % plugin), allmodules) + + for ref in allrefs: + del sys.modules[ref] + + if plugin in sys.modules.keys(): + del sys.modules[plugin] + + if plugin in self.keys(): + dict.__delitem__(self, plugin) + + if remove_pyc: + pyc = os.path.join(self.plugin_dir, '%s.pyc' % plugin) + if os.path.exists(pyc): + os.remove(pyc) + + + def load_plugins(self): + + pluginlist = self._find_plugins() + + for name in pluginlist: + try: + # Make sure the plugin isn't already loaded. + self._unload_plugin(name) + + except: + print_exc() + + try: + moduleinfo = imp.find_module(name, [self.plugin_dir,]) + plugin = imp.load_module(name, *moduleinfo) + dict.__setitem__(self, name, plugin) + + # Check it has the init function. + if not hasattr(plugin, 'init'): + raise ImportError('plugin missing main "init" function.') + + except: + print_exc() + self._unload_plugin(name) + + if len(self.keys()): + echo("loaded plugin(s): %s" % ', '.join(self.keys())) + + + def reload_plugins(self): + '''Unload all loaded plugins then run load_plugins() again. + + IMPORTANT: It is crucial that the event handler be deleted if you + are going to unload any modules because there is now way to track + which module created wich handler.''' + + for plugin in self.keys(): + self._unload_plugin(plugin) + + self.load_plugins() + + +def export_wrapper(uzbl, function): + '''Return an object that appends the uzbl meta-instance to the front of + the argument queue. I.e. (*args, **kargs) -> (uzbl, *args, **kargs)''' + + class Export(object): + def __init__(self, uzbl, function): + self.function = function + self.uzbl = uzbl + + def call(self, *args, **kargs): + return self.function(self.uzbl, *args, **kargs) + + return Export(uzbl, function).call + + +class UzblInstance(object): + '''Event manager for a uzbl instance.''' + + # Singleton plugin manager. + plugins = None + + def __init__(self): + '''Initialise event manager.''' + + # Hold functions exported by plugins. + self._exports = {} + + class ConfigDict(dict): + def __init__(self, setcmd): + self._setcmd = setcmd + + def __setitem__(self, key, value): + '''Updates the config dict and relays any changes back to the + uzbl instance via the set function.''' + + if type(value) == types.BooleanType: + value = int(value) + + if key in self.keys() and type(value) != type(self[key]): + raise TypeError("%r for %r" % (type(value), key)) + + else: + # All custom variables are strings. + value = "" if value is None else str(value) + + self._setcmd(key, value) + dict.__setitem__(self, key, value) + + self._config = ConfigDict(self.set) + self._running = None + + self._cmdbuffer = [] + self.keysheld = [] + self.metaheld = [] + self.mode = "command" + self.binds = {} + self.handlers = {} + self.nexthid = counter().next -def error(msg): - '''Prints error message and exits.''' + # Variables needed for fifo & socket communication with uzbl. + self.uzbl_fifo = None + self.uzbl_socket = None + self._fifo_cmd_queue = [] + self._socket_cmd_queue = [] + self._socket = None + self.send = self._send_socket - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - sys.exit(1) + if not self.plugins: + self.plugins = PluginManager() -def fifo(msg): - '''Writes commands to uzbl's fifo, if the fifo path is known''' + # Call the init() function in every plugin which then setup their + # respective hooks (event handlers, binds or timers). + self._init_plugins() - echo ('Fifo msg: ' + msg + '(fifo path: ' + config['uzbl_fifo'] + ')') - if config['uzbl_fifo']: - fd = os.open(config['uzbl_fifo'], os.O_WRONLY) - os.write(fd, msg) - os.close(fd) -def submit_keycmd(): - '''Sends the updated keycmd to uzbl, which can render it and stuff''' + def __getattribute__(self, name): + '''Expose any exported functions before class functions.''' - fifo ('set keycmd = ' + keycmd) + if not name.startswith('_'): + exports = object.__getattribute__(self, '_exports') + if name in exports: + return exports[name] + return object.__getattribute__(self, name) -def main(): - '''Main function.''' - echo ("Init eventhandler") + def _get_config(self): + '''Return the uzbl config dictionary.''' + + return self._config + + config = property(_get_config) + + + def _init_plugins(self): + '''Call the init() function in every plugin and expose all exposable + functions in the plugins root namespace.''' + + # Map all plugin exports + for (name, plugin) in self.plugins.items(): + for attr in dir(plugin): + if not attr.startswith('export_') or attr == 'export_': + continue + + obj = getattr(plugin, attr) + if type(obj) in [types.LambdaType, types.FunctionType]: + obj = export_wrapper(self, obj) + + self._exports[attr[7:]] = obj + + echo("exposed attribute(s): %s" % ', '.join(self._exports.keys())) + + # Now call the init function in all plugins. + for (name, plugin) in self.plugins.items(): + try: + plugin.init(self) + + except: + print_exc() + + + def _flush(self): + '''Flush messages from the outgoing queue to the uzbl instance.''' + + if len(self._fifo_cmd_queue) and self.uzbl_fifo: + if os.path.exists(self.uzbl_fifo): + h = open(self.uzbl_fifo, 'w') + while len(self._fifo_cmd_queue): + msg = self._fifo_cmd_queue.pop(0) + print "Sending via fifo: %r" % msg + h.write("%s\n" % msg) + h.close() + + if len(self._socket_cmd_queue) and self.uzbl_socket: + if not self._socket and os.path.exists(self.uzbl_socket): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.uzbl_socket) + self._socket = sock + + if self._socket: + while len(self._socket_cmd_queue): + msg = self._socket_cmd_queue.pop(0) + print "Sending via socket: %r" % msg + self._socket.send("%s\n" % msg) + + + def _send_fifo(self, msg): + '''Send a command to the uzbl instance via the fifo socket.''' + + self._fifo_cmd_queue.append(msg) + self._flush() + + + def _send_socket(self, msg): + '''Send a command to the uzbl instance via the socket file.''' + + self._socket_cmd_queue.append(msg) + self._flush() + + + def connect(self, event, handler, *args, **kargs): + '''Connect event with handler and return unique handler id. It goes + without saying that if you connect handlers with non-existent events + nothing will happen so be careful. + + If you choose the handler may be a uzbl command and upon receiving the + event the chosen command will be executed by the uzbl instance.''' + + if event not in self.handlers.keys(): + self.handlers[event] = {} + + id = self.nexthid() + d = {'handler': handler, 'args': args, 'kargs': kargs} + + self.handlers[event][id] = d + echo("added handler for %s: %r" % (event, d)) + + return id + + + def remove(self, id): + '''Remove connected event handler by unique handler id.''' + + for event in self.handlers.keys(): + if id in self.handlers[event].keys(): + echo("removed handler %d" % id) + del self.handlers[event][id] + + + def set(self, key, value): + '''Sets key "key" with value "value" in the uzbl instance.''' + + # TODO: Make a real escaping function. + escape = str + + if not _VALIDSETKEY(key): + raise KeyError("%r" % key) + + if '\n' in value: + raise ValueError("invalid character: \\n") + + self.send('set %s = %s' % (key, escape(value))) + + + def listen_from_fd(self, fd): + '''Main loop reading event messages from stdin.''' + + self._running = True + while self._running: + try: + if select.select([fd,], [], [], 1)[0]: + self.read_from_fd(fd) + continue + + self._flush() + + except KeyboardInterrupt: + self._running = False + print + + except: + print_exc() + + + def read_from_fd(self, fd): + '''Reads incoming event messages from fd.''' + + raw = fd.readline() + if not raw: + # Read null byte (i.e. uzbl closed). + self._running = False + return + + msg = raw.strip().split(' ', 3) + + if not msg or msg[0] != "EVENT": + # Not an event message + return + + event, args = msg[1], msg[3] + self.handle_event(event, args) + + + def handle_event(self, event, args): + '''Handle uzbl events internally before dispatch.''' + + print event, args + + if event == 'VARIABLE_SET': + l = args.split(' ', 2) + if len(l) == 2: + l.append("") + + key, type, value = l + dict.__setitem__(self._config, key, _TYPECONVERT[type](value)) + + elif event == 'FIFO_SET': + self.uzbl_fifo = args + self._flush() + + elif event == 'SOCKET_SET': + self.uzbl_socket = args + self._flush() + + elif event == 'SHUTDOWN': + for (name, plugin) in self.plugins.items(): + if hasattr(plugin, "cleanup"): + plugin.cleanup(uzbl) + + self.dispatch_event(event, args) + + + def dispatch_event(self, event, args): + '''Now send the event to any event handlers added with the connect + function. In other words: handle plugin's event hooks.''' + + if event in self.handlers.keys(): + for hid in self.handlers[event]: + try: + handler = self.handlers[event][hid] + print "Executing handler:", event, handler + self.exc_handler(handler, args) + + except: + print_exc() + + + def exc_handler(self, d, args): + '''Handle handler.''' + + if type(d['handler']) == types.FunctionType: + handler = d['handler'] + handler(self, args, *d['args'], **d['kargs']) - for line in sys.stdin: - line = line.strip() - data = line.partition('EVENT ') - if (data[0] == ""): - line = data[2] - echo ("Got event: " + line) - data = line.partition(' ') - event_name = data[0] - event_data = data[2] else: - echo ("Non-event: " + line) - continue - - if (event_name == 'FIFO_SET'): - config['uzbl_fifo'] = event_data.split()[-1] - elif (event_name == 'KEY_PRESS'): - # todo: keep a table of pressed modkeys. do we work with Mod[1-4] here or Alt_L and such? - key = event_data.split()[-1] - if (key == 'Escape'): - keycmd = '' - submit_keycmd - elif (event_name == 'KEY_RELEASE'): - #todo : update table of pressed modkeys - submit_keycmd + cmd = d['handler'] + self.send(cmd) + if __name__ == "__main__": - main() -
\ No newline at end of file + uzbl = UzblInstance().listen_from_fd(sys.stdin) diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py new file mode 100644 index 0000000..cf2a1ab --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -0,0 +1,49 @@ +'''Plugin provides support for classic uzbl binds. + +For example: + bind ZZ = exit -> bind('ZZ', 'exit') + bind o _ = uri %s -> bind('o _', 'uri %s') + bind fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") + bind fl* = -> bind('fl*') + +And it is also possible to execute a function on activation: + bind('DD', myhandler) +''' + +uzbls = {} + +def export_bind(uzbl, glob, cmd=None): + + if uzbl not in uzbls: + uzbls[uzbl] = {} + binds = uzbls[uzbl] + + if not cmd: + if glob in binds.keys(): + echo("deleted bind: %r" % self.binds[glob]) + del binds[glob] + + d = {'glob': glob, 'once': True, 'hasargs': True, 'cmd': cmd} + + if glob.endswith('*'): + d['pre'] = glob.rstrip('*') + d['once'] = False + + elif glob.endswith('_'): + d['pre'] = glob.rstrip('_') + + else: + d['pre'] = glob + d['hasargs'] = False + + binds[glob] = d + print "added bind: %r" % d + + +def init(uzbl): + + uzbl.bind("test", lambda _: True) + +def cleanup(uzbl): + if uzbl in uzbls: + del uzbl diff --git a/examples/data/uzbl/scripts/plugins/dump_config.py b/examples/data/uzbl/scripts/plugins/dump_config.py new file mode 100644 index 0000000..381dbf2 --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/dump_config.py @@ -0,0 +1,11 @@ +import pprint + +def dump_config(uzbl, args): + '''Dump the config every time the page finishes loading.''' + + print "%s\n" % pprint.pformat(uzbl.config) + + +def init(uzbl): + id = uzbl.connect('LOAD_FINISH', dump_config) + print "Dump config id:", id diff --git a/examples/data/uzbl/scripts/plugins/echo_keys.py b/examples/data/uzbl/scripts/plugins/echo_keys.py new file mode 100644 index 0000000..e1a1850 --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/echo_keys.py @@ -0,0 +1,16 @@ +def echo_keys(uzbl, key, print_meta=True): + '''Prints key-presses to the terminal.''' + + keys_pressed = int(uzbl.config['keys_pressed']) + 1 + print "You pressed:", key, "Total keys pressed:", keys_pressed + uzbl.config['keys_pressed'] = str(keys_pressed) + + +def init(uzbl): + '''In this function attach all your event hooks using uzbl.connect and + uzbl.bind functions.''' + + id = uzbl.connect('KEY_PRESS', echo_keys) + print "echo_keys hook id:", id + + uzbl.config['keys_pressed'] = str(0) diff --git a/uzbl-core.c b/uzbl-core.c index d8179df..5dd80a2 100644 --- a/uzbl-core.c +++ b/uzbl-core.c @@ -192,29 +192,29 @@ const struct var_name_to_ptr_t { }; /* Event id to name mapping - * Event names must be in the same + * Event names must be in the same * order as in 'enum event_type' * * TODO: Add more useful events */ const char *event_table[LAST_EVENT] = { - "LOAD_START" , - "LOAD_COMMIT" , - "LOAD_FINISH" , - "LOAD_ERROR" , + "LOAD_START" , + "LOAD_COMMIT" , + "LOAD_FINISH" , + "LOAD_ERROR" , "KEY_PRESS" , "KEY_RELEASE" , - "DOWNLOAD_REQUEST" , + "DOWNLOAD_REQUEST" , "COMMAND_EXECUTED" , "LINK_HOVER" , "TITLE_CHANGED" , "GEOMETRY_CHANGED" , "WEBINSPECTOR" , - "COOKIE" , "NEW_WINDOW" , "SELECTION_CHANGED", "VARIABLE_SET", - "FIFO_SET" + "FIFO_SET", + "SOCKET_SET" }; @@ -886,43 +886,44 @@ VIEWFUNC(go_forward) /* -- command to callback/function map for things we cannot attach to any signals */ struct {const char *key; CommandInfo value;} cmdlist[] = -{ /* key function no_split */ - { "back", {view_go_back, 0} }, - { "forward", {view_go_forward, 0} }, - { "scroll_vert", {scroll_vert, 0} }, - { "scroll_horz", {scroll_horz, 0} }, - { "scroll_begin", {scroll_begin, 0} }, - { "scroll_end", {scroll_end, 0} }, - { "reload", {view_reload, 0}, }, - { "reload_ign_cache", {view_reload_bypass_cache, 0} }, - { "stop", {view_stop_loading, 0}, }, - { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?). - { "zoom_out", {view_zoom_out, 0}, }, - { "toggle_zoom_type", {toggle_zoom_type, 0}, }, - { "uri", {load_uri, TRUE} }, - { "js", {run_js, TRUE} }, - { "script", {run_external_js, 0} }, - { "toggle_status", {toggle_status_cb, 0} }, - { "spawn", {spawn, 0} }, - { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler - { "sh", {spawn_sh, 0} }, - { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler - { "talk_to_socket", {talk_to_socket, 0} }, - { "exit", {close_uzbl, 0} }, - { "search", {search_forward_text, TRUE} }, - { "search_reverse", {search_reverse_text, TRUE} }, - { "dehilight", {dehilight, 0} }, - { "toggle_insert_mode", {toggle_insert_mode, 0} }, - { "set", {set_var, TRUE} }, - //{ "get", {get_var, TRUE} }, - { "bind", {act_bind, TRUE} }, - { "dump_config", {act_dump_config, 0} }, - { "keycmd", {keycmd, TRUE} }, - { "keycmd_nl", {keycmd_nl, TRUE} }, - { "keycmd_bs", {keycmd_bs, 0} }, - { "chain", {chain, 0} }, - { "print", {print, TRUE} }, - { "update_gui", {update_gui, TRUE} } +{ /* key function no_split */ + { "back", {view_go_back, 0} }, + { "forward", {view_go_forward, 0} }, + { "scroll_vert", {scroll_vert, 0} }, + { "scroll_horz", {scroll_horz, 0} }, + { "scroll_begin", {scroll_begin, 0} }, + { "scroll_end", {scroll_end, 0} }, + { "reload", {view_reload, 0}, }, + { "reload_ign_cache", {view_reload_bypass_cache, 0} }, + { "stop", {view_stop_loading, 0}, }, + { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?). + { "zoom_out", {view_zoom_out, 0}, }, + { "toggle_zoom_type", {toggle_zoom_type, 0}, }, + { "uri", {load_uri, TRUE} }, + { "js", {run_js, TRUE} }, + { "script", {run_external_js, 0} }, + { "toggle_status", {toggle_status_cb, 0} }, + { "spawn", {spawn, 0} }, + { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler + { "sh", {spawn_sh, 0} }, + { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler + { "talk_to_socket", {talk_to_socket, 0} }, + { "exit", {close_uzbl, 0} }, + { "search", {search_forward_text, TRUE} }, + { "search_reverse", {search_reverse_text, TRUE} }, + { "dehilight", {dehilight, 0} }, + { "toggle_insert_mode", {toggle_insert_mode, 0} }, + { "set", {set_var, TRUE} }, + //{ "get", {get_var, TRUE} }, + { "bind", {act_bind, TRUE} }, + { "dump_config", {act_dump_config, 0} }, + { "dump_config_as_events", {act_dump_config_as_events, 0} }, + { "keycmd", {keycmd, TRUE} }, + { "keycmd_nl", {keycmd_nl, TRUE} }, + { "keycmd_bs", {keycmd_bs, 0} }, + { "chain", {chain, 0} }, + { "print", {print, TRUE} }, + { "update_gui", {update_gui, TRUE} } }; void @@ -1010,6 +1011,11 @@ act_dump_config() { } void +act_dump_config_as_events() { + dump_config_as_events(); +} + +void set_keycmd() { run_keycmd(FALSE); update_title(); @@ -1966,25 +1972,31 @@ set_var_value(const gchar *name, gchar *val) { if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { if(!c->writeable) return FALSE; + msg = g_string_new(name); + /* check for the variable type */ if (c->type == TYPE_STR) { buf = expand(val, 0); g_free(*c->ptr.s); *c->ptr.s = buf; - msg = g_string_new(name); - g_string_append_printf(msg, " %s", buf); - send_event(VARIABLE_SET, msg->str); - g_string_free(msg,TRUE); + g_string_append_printf(msg, " str %s", buf); + } else if(c->type == TYPE_INT) { buf = expand(val, 0); *c->ptr.i = (int)strtoul(buf, &endp, 10); g_free(buf); + g_string_append_printf(msg, " int %d", *c->ptr.i); + } else if (c->type == TYPE_FLOAT) { buf = expand(val, 0); *c->ptr.f = strtod(buf, &endp); g_free(buf); + g_string_append_printf(msg, " float %f", *c->ptr.f); } + send_event(VARIABLE_SET, msg->str); + g_string_free(msg,TRUE); + /* invoke a command specific function */ if(c->func) c->func(); } else { @@ -2006,6 +2018,11 @@ set_var_value(const gchar *name, gchar *val) { *c->ptr.s = buf; g_hash_table_insert(uzbl.comm.proto_var, g_strdup(name), (gpointer) c); + + msg = g_string_new(name); + g_string_append_printf(msg, " str %s", buf); + send_event(VARIABLE_SET, msg->str); + g_string_free(msg,TRUE); } return TRUE; } @@ -2235,6 +2252,7 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL * if( (chan = g_io_channel_unix_new(sock)) ) { g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); uzbl.comm.socket_path = path; + send_event(SOCKET_SET, path); return dir; } } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno)); @@ -2292,7 +2310,7 @@ configure_event_cb(GtkWidget* window, GdkEventConfigure* event) { (void) event; retrieve_geometry(); - send_event(GEOMETRY_CHANGED, uzbl.gui.geometry); + send_event(GEOMETRY_CHANGED, uzbl.gui.geometry); return FALSE; } @@ -2341,7 +2359,7 @@ key_release_cb (GtkWidget* window, GdkEventKey* event) { void run_keycmd(const gboolean key_ret) { - + /* run the keycmd immediately if it isn't incremental and doesn't take args */ Action *act; gchar *tmp; @@ -2654,6 +2672,7 @@ void settings_init () { State *s = &uzbl.state; Network *n = &uzbl.net; + int i; for (i = 0; default_config[i].command != NULL; i++) { parse_cmd_line(default_config[i].command, NULL); @@ -2699,7 +2718,6 @@ void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data) g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path); if(uzbl.behave.cookie_handler) run_handler(uzbl.behave.cookie_handler, s->str); - send_event(COOKIE, s->str); if(uzbl.behave.cookie_handler && uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { @@ -2725,7 +2743,6 @@ save_cookies (SoupMessage *msg, gpointer user_data){ GString *s = g_string_new (""); g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie); run_handler(uzbl.behave.cookie_handler, s->str); - send_event(COOKIE, s->str); g_free (cookie); g_string_free(s, TRUE); } @@ -2844,18 +2861,36 @@ dump_var_hash(gpointer k, gpointer v, gpointer ud) { } void -dump_key_hash(gpointer k, gpointer v, gpointer ud) { +dump_config() { + g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL); +} + +void +dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) { (void) ud; - Action *a = v; + uzbl_cmdprop *c = v; + GString *msg; + + if(!c->dump) + return; + + /* check for the variable type */ + msg = g_string_new((char *)k); + if (c->type == TYPE_STR) { + g_string_append_printf(msg, " str %s", *c->ptr.s ? *c->ptr.s : " "); + } else if(c->type == TYPE_INT) { + g_string_append_printf(msg, " int %d", *c->ptr.i); + } else if (c->type == TYPE_FLOAT) { + g_string_append_printf(msg, " float %f", *c->ptr.f); + } - printf("bind %s = %s %s\n", (char *)k , - (char *)a->name, a->param?(char *)a->param:""); + send_event(VARIABLE_SET, msg->str); + g_string_free(msg, TRUE); } void -dump_config() { - g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL); - g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL); +dump_config_as_events() { + g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash_as_event, NULL); } void diff --git a/uzbl-core.h b/uzbl-core.h index 842d965..9d22eb0 100644 --- a/uzbl-core.h +++ b/uzbl-core.h @@ -188,10 +188,10 @@ typedef void sigfunc(int); enum event_type { LOAD_START, LOAD_COMMIT, LOAD_FINISH, LOAD_ERROR, KEY_PRESS, KEY_RELEASE, DOWNLOAD_REQ, COMMAND_EXECUTED, - LINK_HOVER, TITLE_CHANGED, GEOMETRY_CHANGED, - WEBINSPECTOR, COOKIE, NEW_WINDOW, SELECTION_CHANGED, - VARIABLE_SET, FIFO_SET, - + LINK_HOVER, TITLE_CHANGED, GEOMETRY_CHANGED, + WEBINSPECTOR, NEW_WINDOW, SELECTION_CHANGED, + VARIABLE_SET, FIFO_SET, SOCKET_SET, + /* must be last entry */ LAST_EVENT }; @@ -467,6 +467,9 @@ void act_dump_config(); void +act_dump_config_as_events(); + +void dump_var_hash(gpointer k, gpointer v, gpointer ud); void @@ -476,6 +479,9 @@ void dump_config(); void +dump_config_as_events(); + +void retrieve_geometry(); void |