aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brendan Taylor <whateley@gmail.com>2011-02-17 13:09:50 -0700
committerGravatar Brendan Taylor <whateley@gmail.com>2011-02-17 13:09:50 -0700
commit67af28c8d147e35c91ea91b0ddf51680d9feb475 (patch)
tree697e96acc530fefdc6ab6189d95e23127cc127cc
parentb7a47b3f58e6fa05d56577ea6425d353a41ddb86 (diff)
parente3b04d3ae9fb6dfeff5e6099784586b54591814e (diff)
Merge branch 'escaped_events' into experimental
Conflicts: src/util.c
-rw-r--r--examples/data/plugins/bind.py9
-rw-r--r--examples/data/plugins/config.py7
-rw-r--r--examples/data/plugins/cookies.py4
-rw-r--r--examples/data/plugins/downloads.py18
-rw-r--r--examples/data/plugins/on_event.py6
-rwxr-xr-xexamples/data/scripts/uzbl-event-manager22
-rw-r--r--src/callbacks.c103
-rw-r--r--src/cookie-jar.c16
-rw-r--r--src/events.c83
-rw-r--r--src/events.h6
-rw-r--r--src/util.c30
-rw-r--r--src/util.h4
-rw-r--r--src/uzbl-core.c131
-rw-r--r--src/uzbl-core.h5
-rw-r--r--tests/test-command.c8
15 files changed, 290 insertions, 162 deletions
diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py
index 41f96c5..69fd863 100644
--- a/examples/data/plugins/bind.py
+++ b/examples/data/plugins/bind.py
@@ -164,15 +164,6 @@ def split_glob(glob):
return (mods, glob)
-def unquote(str):
- '''Remove quotation marks around string.'''
-
- if str and str[0] == str[-1] and str[0] in ['"', "'"]:
- str = str[1:-1]
-
- return str
-
-
class Bind(object):
# Class attribute to hold the number of Bind classes created.
diff --git a/examples/data/plugins/config.py b/examples/data/plugins/config.py
index ed2d761..c9bdf67 100644
--- a/examples/data/plugins/config.py
+++ b/examples/data/plugins/config.py
@@ -3,8 +3,6 @@ from types import BooleanType
from UserDict import DictMixin
valid_key = compile('^[A-Za-z0-9_\.]+$').match
-types = {'int': int, 'float': float, 'str': unicode}
-escape = lambda s: unicode(s).replace('\n', '\\n')
class Config(DictMixin):
def __init__(self, uzbl):
@@ -49,7 +47,8 @@ class Config(DictMixin):
value = int(value)
else:
- value = escape(value)
+ value = unicode(value)
+ assert '\n' not in value
if not force and key in self and self[key] == value:
return
@@ -82,6 +81,8 @@ def parse_set_event(uzbl, args):
# plugin init hook
def init(uzbl):
+ global types
+ types = {'int': int, 'float': float, 'str': unquote}
export(uzbl, 'config', Config(uzbl))
connect(uzbl, 'VARIABLE_SET', parse_set_event)
diff --git a/examples/data/plugins/cookies.py b/examples/data/plugins/cookies.py
index 6ee8798..e29ee36 100644
--- a/examples/data/plugins/cookies.py
+++ b/examples/data/plugins/cookies.py
@@ -7,10 +7,6 @@ import os, re
# these are symbolic names for the components of the cookie tuple
symbolic = {'domain': 0, 'path':1, 'name':2, 'value':3, 'scheme':4, 'expires':5}
-_splitquoted = re.compile("( |\\\".*?\\\"|'.*?')")
-def splitquoted(text):
- return [str(p.strip('\'"')) for p in _splitquoted.split(text) if p.strip()]
-
# allows for partial cookies
# ? allow wildcard in key
def match(key, cookie):
diff --git a/examples/data/plugins/downloads.py b/examples/data/plugins/downloads.py
index 7bf32d7..8d796ce 100644
--- a/examples/data/plugins/downloads.py
+++ b/examples/data/plugins/downloads.py
@@ -31,7 +31,11 @@ def update_download_section(uzbl):
if uzbl.config.get('downloads', '') != result:
uzbl.config['downloads'] = result
-def download_started(uzbl, destination_path):
+def download_started(uzbl, args):
+ # parse the arguments
+ args = splitquoted(args)
+ destination_path = args[0]
+
# add to the list of active downloads
global ACTIVE_DOWNLOADS
ACTIVE_DOWNLOADS[destination_path] = (0.0,)
@@ -41,9 +45,9 @@ def download_started(uzbl, destination_path):
def download_progress(uzbl, args):
# parse the arguments
- s = args.rindex(' ')
- destination_path = args[:s]
- progress = float(args[s+1:])
+ args = splitquoted(args)
+ destination_path = args[0]
+ progress = float(args[1])
# update the progress
global ACTIVE_DOWNLOADS
@@ -52,7 +56,11 @@ def download_progress(uzbl, args):
# update the status bar variable
update_download_section(uzbl)
-def download_complete(uzbl, destination_path):
+def download_complete(uzbl, args):
+ # parse the arguments
+ args = splitquoted(args)
+ destination_path = args[0]
+
# remove from the list of active downloads
global ACTIVE_DOWNLOADS
del ACTIVE_DOWNLOADS[destination_path]
diff --git a/examples/data/plugins/on_event.py b/examples/data/plugins/on_event.py
index 5142275..32f09e2 100644
--- a/examples/data/plugins/on_event.py
+++ b/examples/data/plugins/on_event.py
@@ -24,6 +24,10 @@ def event_handler(uzbl, *args, **kargs):
'''This function handles all the events being watched by various
on_event definitions and responds accordingly.'''
+ # Could be connected to a EM internal event that can use anything as args
+ if len(args) == 1 and isinstance(args[0], basestring):
+ args = splitquoted(args[0])
+
events = uzbl.on_events
event = kargs['on_event']
if event not in events:
@@ -80,3 +84,5 @@ def cleanup(uzbl):
del handlers[:]
uzbl.on_events.clear()
+
+# vi: set et ts=4:
diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager
index 8ad3af7..cb462c7 100755
--- a/examples/data/scripts/uzbl-event-manager
+++ b/examples/data/scripts/uzbl-event-manager
@@ -34,6 +34,7 @@ import socket
import sys
import time
import weakref
+import re
from collections import defaultdict
from functools import partial
from glob import glob
@@ -169,13 +170,16 @@ class EventHandler(object):
self.callback(uzbl, *args, **kwargs)
+
+
+
class Plugin(object):
'''Plugin module wrapper object.'''
# Special functions exported from the Plugin instance to the
# plugin namespace.
special_functions = ['require', 'export', 'export_dict', 'connect',
- 'connect_dict', 'logger']
+ 'connect_dict', 'logger', 'unquote', 'splitquoted']
def __init__(self, parent, name, path, plugin):
@@ -291,6 +295,20 @@ class Plugin(object):
assert plugin in self.parent.plugins, self.logger.critical(
'plugin %r required by plugin %r' (plugin, self.name))
+ @classmethod
+ def unquote(cls, s):
+ '''Removes quotation marks around strings if any and interprets
+ \\-escape sequences using `string_escape`'''
+ if s and s[0] == s[-1] and s[0] in ['"', "'"]:
+ s = s[1:-1]
+ return s.encode('utf-8').decode('string_escape').decode('utf-8')
+
+ _splitquoted = re.compile("( |\"(?:\\\\.|[^\"])*?\"|'(?:\\\\.|[^'])*?')")
+ @classmethod
+ def splitquoted(cls, text):
+ '''Splits string on whitespace while respecting quotations'''
+ return [cls.unquote(p) for p in cls._splitquoted.split(text) if p.strip()]
+
class Uzbl(object):
def __init__(self, parent, child_socket):
@@ -969,3 +987,5 @@ if __name__ == "__main__":
daemon_actions[action]()
logger.debug('process CPU time: %f' % time.clock())
+
+# vi: set et ts=4:
diff --git a/src/callbacks.c b/src/callbacks.c
index 9bc5c28..a40057c 100644
--- a/src/callbacks.c
+++ b/src/callbacks.c
@@ -116,7 +116,7 @@ cmd_set_status() {
void
cmd_load_uri() {
- load_uri_imp (uzbl.state.uri);
+ load_uri_imp (uzbl.state.uri);
}
void
@@ -413,12 +413,12 @@ link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpoin
if(s->last_selected_url &&
g_strcmp0(s->selected_url, s->last_selected_url))
- send_event(LINK_UNHOVER, s->last_selected_url, NULL);
+ send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
- send_event(LINK_HOVER, s->selected_url, NULL);
+ send_event(LINK_HOVER, NULL, TYPE_STR, s->selected_url, NULL);
}
else if(s->last_selected_url) {
- send_event(LINK_UNHOVER, s->last_selected_url, NULL);
+ send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL);
}
update_title();
@@ -433,7 +433,7 @@ title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
g_free (uzbl.gui.main_title);
uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
update_title();
- send_event(TITLE_CHANGED, uzbl.gui.main_title, NULL);
+ send_event(TITLE_CHANGED, NULL, TYPE_STR, uzbl.gui.main_title, NULL);
g_setenv("UZBL_TITLE", uzbl.gui.main_title, TRUE);
}
@@ -441,9 +441,7 @@ void
progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
(void) param_spec;
int progress = webkit_web_view_get_progress(web_view) * 100;
- gchar *prg_str = g_strdup_printf("%d", progress);
- send_event(LOAD_PROGRESS, prg_str, NULL);
- g_free(prg_str);
+ send_event(LOAD_PROGRESS, NULL, TYPE_INT, progress, NULL);
}
void
@@ -454,7 +452,7 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
WebKitLoadStatus status = webkit_web_view_get_load_status(web_view);
switch(status) {
case WEBKIT_LOAD_PROVISIONAL:
- send_event(LOAD_START, uzbl.state.uri, NULL);
+ send_event(LOAD_START, NULL, TYPE_STR, uzbl.state.uri ? uzbl.state.uri : "", NULL);
break;
case WEBKIT_LOAD_COMMITTED:
g_free (uzbl.state.uri);
@@ -462,10 +460,10 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
uzbl.state.uri = g_string_free (newuri, FALSE);
g_setenv("UZBL_URI", uzbl.state.uri, TRUE);
- send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame), NULL);
+ send_event(LOAD_COMMIT, NULL, TYPE_STR, webkit_web_frame_get_uri (frame), NULL);
break;
case WEBKIT_LOAD_FINISHED:
- send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame), NULL);
+ send_event(LOAD_FINISH, NULL, TYPE_STR, webkit_web_frame_get_uri(frame), NULL);
break;
case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
break; /* we don't do anything with this (yet) */
@@ -482,7 +480,7 @@ selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) {
webkit_web_view_copy_clipboard(webkitwebview);
tmp = gtk_clipboard_wait_for_text(gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
- send_event(SELECTION_CHANGED, tmp, NULL);
+ send_event(SELECTION_CHANGED, NULL, TYPE_STR, tmp ? tmp : "", NULL);
g_free(tmp);
}
@@ -492,11 +490,12 @@ load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer
(void) frame;
(void) ud;
GError *err = web_err;
- gchar *details;
- details = g_strdup_printf("%s %d:%s", uri, err->code, err->message);
- send_event(LOAD_ERROR, details, NULL);
- g_free(details);
+ send_event (LOAD_ERROR, NULL,
+ TYPE_STR, uri,
+ TYPE_INT, err->code,
+ TYPE_STR, err->message,
+ NULL);
}
void
@@ -516,7 +515,7 @@ configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
retrieve_geometry();
if(strcmp(lastgeo, uzbl.gui.geometry))
- send_event(GEOMETRY_CHANGED, uzbl.gui.geometry, NULL);
+ send_event(GEOMETRY_CHANGED, NULL, TYPE_STR, uzbl.gui.geometry, NULL);
g_free(lastgeo);
return FALSE;
@@ -528,10 +527,7 @@ focus_cb(GtkWidget* window, GdkEventFocus* event, void *ud) {
(void) event;
(void) ud;
- if(event->in)
- send_event(FOCUS_GAINED, "", NULL);
- else
- send_event(FOCUS_LOST, "", NULL);
+ send_event (event->in?FOCUS_GAINED:FOCUS_LOST, NULL, NULL);
return FALSE;
}
@@ -573,9 +569,9 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) {
/* left click */
if(event->button == 1) {
if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE))
- send_event(FORM_ACTIVE, "button1", NULL);
+ send_event(FORM_ACTIVE, NULL, TYPE_NAME, "button1", NULL);
else if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
- send_event(ROOT_ACTIVE, "button1", NULL);
+ send_event(ROOT_ACTIVE, NULL, TYPE_NAME, "button1", NULL);
}
else if(event->button == 2 && !(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) {
sendev = TRUE;
@@ -588,8 +584,8 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) {
if(sendev) {
details = g_strdup_printf("Button%d", event->button);
- send_event(KEY_PRESS, details, NULL);
- g_free(details);
+ send_event(KEY_PRESS, NULL, TYPE_NAME, details, NULL);
+ g_free (details);
}
}
@@ -617,8 +613,8 @@ button_release_cb (GtkWidget* window, GdkEventButton* event) {
if(sendev) {
details = g_strdup_printf("Button%d", event->button);
- send_event(KEY_RELEASE, details, NULL);
- g_free(details);
+ send_event(KEY_RELEASE, NULL, TYPE_NAME, details, NULL);
+ g_free (details);
}
}
@@ -631,9 +627,11 @@ motion_notify_cb(GtkWidget* window, GdkEventMotion* event, gpointer user_data) {
(void) event;
(void) user_data;
- gchar *details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state);
- send_event(PTR_MOVE, details, NULL);
- g_free(details);
+ send_event (PTR_MOVE, NULL,
+ TYPE_FLOAT, event->x,
+ TYPE_FLOAT, event->y,
+ TYPE_INT, event->state,
+ NULL);
return FALSE;
}
@@ -690,7 +688,7 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame,
(void) user_data;
if (uzbl.state.verbose)
- printf("New window requested -> %s \n", webkit_network_request_get_uri (request));
+ printf ("New window requested -> %s \n", webkit_network_request_get_uri (request));
/* This event function causes troubles with `target="_blank"` anchors.
* Either we:
@@ -704,9 +702,9 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame,
* We are leaving this uncommented as we would rather links open twice
* than not at all.
*/
- send_event(NEW_WINDOW, webkit_network_request_get_uri (request), NULL);
+ send_event (NEW_WINDOW, NULL, TYPE_STR, webkit_network_request_get_uri (request), NULL);
- webkit_web_policy_decision_ignore(policy_decision);
+ webkit_web_policy_decision_ignore (policy_decision);
return TRUE;
}
@@ -736,7 +734,7 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes
(void) response;
(void) user_data;
- send_event(REQUEST_STARTING, webkit_network_request_get_uri(request), NULL);
+ send_event (REQUEST_STARTING, NULL, TYPE_STR, webkit_network_request_get_uri(request), NULL);
}
void
@@ -751,7 +749,7 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) {
gtk_widget_destroy(GTK_WIDGET(web_view));
}
else
- send_event(NEW_WINDOW, uri, NULL);
+ send_event(NEW_WINDOW, NULL, TYPE_STR, uri, NULL);
}
@@ -792,9 +790,10 @@ download_progress_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_
const gchar *dest_uri = webkit_download_get_destination_uri(download);
const gchar *dest_path = dest_uri + strlen("file://");
- gchar *details = g_strdup_printf("%s %.2lf", dest_path, progress);
- send_event(DOWNLOAD_PROGRESS, details, NULL);
- g_free(details);
+ send_event(DOWNLOAD_PROGRESS, NULL,
+ TYPE_STR, dest_path,
+ TYPE_FLOAT, progress,
+ NULL);
}
void
@@ -814,7 +813,7 @@ download_status_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_da
{
const gchar *dest_uri = webkit_download_get_destination_uri(download);
const gchar *dest_path = dest_uri + strlen("file://");
- send_event(DOWNLOAD_COMPLETE, dest_path, NULL);
+ send_event(DOWNLOAD_COMPLETE, NULL, TYPE_STR, dest_path, NULL);
}
}
}
@@ -905,7 +904,7 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat
g_free(rel_path);
}
- send_event(DOWNLOAD_STARTED, destination_path, NULL);
+ send_event(DOWNLOAD_STARTED, NULL, TYPE_STR, destination_path, NULL);
/* convert absolute path to file:// URI */
gchar *destination_uri = g_strconcat("file://", destination_path, NULL);
@@ -926,12 +925,13 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w)
gdouble min = gtk_adjustment_get_lower(adjust);
gdouble max = gtk_adjustment_get_upper(adjust);
gdouble page = gtk_adjustment_get_page_size(adjust);
- gchar* details;
- details = g_strdup_printf("%g %g %g %g", value, min, max, page);
-
- send_event(SCROLL_VERT, details, NULL);
- g_free(details);
+ send_event (SCROLL_VERT, NULL,
+ TYPE_FLOAT, value,
+ TYPE_FLOAT, min,
+ TYPE_FLOAT, max,
+ TYPE_FLOAT, page,
+ NULL);
return (FALSE);
}
@@ -945,12 +945,13 @@ scroll_horiz_cb(GtkAdjustment *adjust, void *w)
gdouble min = gtk_adjustment_get_lower(adjust);
gdouble max = gtk_adjustment_get_upper(adjust);
gdouble page = gtk_adjustment_get_page_size(adjust);
- gchar* details;
- details = g_strdup_printf("%g %g %g %g", value, min, max, page);
- send_event(SCROLL_HORIZ, details, NULL);
-
- g_free(details);
+ send_event (SCROLL_HORIZ, NULL,
+ TYPE_FLOAT, value,
+ TYPE_FLOAT, min,
+ TYPE_FLOAT, max,
+ TYPE_FLOAT, page,
+ NULL);
return (FALSE);
}
@@ -1020,3 +1021,5 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) {
}
}
}
+
+/* vi: set et ts=4: */
diff --git a/src/cookie-jar.c b/src/cookie-jar.c
index 82a5269..bc7d022 100644
--- a/src/cookie-jar.c
+++ b/src/cookie-jar.c
@@ -45,13 +45,15 @@ changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) {
if(cookie->expires)
expires = g_strdup_printf ("%d", soup_date_to_time_t (cookie->expires));
- gchar * eventstr = g_strdup_printf ("'%s' '%s' '%s' '%s' '%s' '%s'",
- cookie->domain, cookie->path, cookie->name, cookie->value, scheme, expires?expires:"");
- if(new_cookie)
- send_event(ADD_COOKIE, eventstr, NULL);
- else
- send_event(DELETE_COOKIE, eventstr, NULL);
- g_free(eventstr);
+ send_event (new_cookie ? ADD_COOKIE : DELETE_COOKIE, NULL,
+ TYPE_STR, cookie->domain,
+ TYPE_STR, cookie->path,
+ TYPE_STR, cookie->name,
+ TYPE_STR, cookie->value,
+ TYPE_STR, scheme,
+ TYPE_STR, expires ? expires : "",
+ NULL);
+
if(expires)
g_free(expires);
}
diff --git a/src/events.c b/src/events.c
index 31a95d5..174ff75 100644
--- a/src/events.c
+++ b/src/events.c
@@ -5,6 +5,7 @@
#include "uzbl-core.h"
#include "events.h"
+#include "util.h"
UzblCore uzbl;
@@ -137,32 +138,66 @@ send_event_stdout(GString *msg) {
fflush(stdout);
}
+void
+vsend_event(int type, const gchar *custom_event, va_list vargs) {
+ GString *event_message = g_string_sized_new (512);
+
+ if (type >= LAST_EVENT)
+ return;
+ const gchar *event = custom_event ? custom_event : event_table[type];
+ char* str;
+
+ int next;
+ g_string_printf (event_message, "EVENT [%s] %s",
+ uzbl.state.instance_name, event);
+
+ while ((next = va_arg (vargs, int)) != 0) {
+ g_string_append_c(event_message, ' ');
+ switch(next) {
+ case TYPE_INT:
+ g_string_append_printf (event_message, "%d", va_arg (vargs, int));
+ break;
+ case TYPE_STR:
+ g_string_append_c (event_message, '\'');
+ append_escaped (event_message, va_arg (vargs, char*));
+ g_string_append_c (event_message, '\'');
+ break;
+ case TYPE_FORMATTEDSTR:
+ g_string_append (event_message, va_arg (vargs, char*));
+ break;
+ case TYPE_NAME:
+ str = va_arg (vargs, char*);
+ g_assert (valid_name (str));
+ g_string_append (event_message, str);
+ break;
+ case TYPE_FLOAT:
+ // ‘float’ is promoted to ‘double’ when passed through ‘...’
+ g_string_append_printf (event_message, "%.2f", va_arg (vargs, double));
+ break;
+ }
+ }
+
+ g_string_append_c(event_message, '\n');
+
+ if (uzbl.state.events_stdout)
+ send_event_stdout (event_message);
+ send_event_socket (event_message);
+
+ g_string_free (event_message, TRUE);
+}
+
/*
* build event string and send over the supported interfaces
* custom_event == NULL indicates an internal event
*/
void
-send_event(int type, const gchar *details, const gchar *custom_event) {
- GString *event_message = g_string_new("");
-
- /* check for custom events */
- if(custom_event) {
- g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, custom_event, details);
- }
- /* check wether we support the internal event */
- else if(type < LAST_EVENT) {
- g_string_printf(event_message, "EVENT [%s] %s %s\n",
- uzbl.state.instance_name, event_table[type], details);
- }
-
- if(event_message->str) {
- if(uzbl.state.events_stdout)
- send_event_stdout(event_message);
- send_event_socket(event_message);
-
- g_string_free(event_message, TRUE);
- }
+send_event(int type, const gchar *custom_event, ...) {
+ va_list vargs, vacopy;
+ va_start (vargs, custom_event);
+ va_copy (vacopy, vargs);
+ vsend_event (type, custom_event, vacopy);
+ va_end (vacopy);
+ va_end (vargs);
}
/* Transform gdk key events to our own events */
@@ -181,12 +216,14 @@ key_to_event(guint keyval, gint mode) {
ucs[ulen] = 0;
send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE,
- ucs, NULL);
+ NULL, TYPE_FORMATTEDSTR, ucs, NULL);
}
/* send keysym for non-printable chars */
else {
send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE,
- gdk_keyval_name(keyval), NULL);
+ NULL, TYPE_NAME, gdk_keyval_name(keyval), NULL);
}
}
+
+/* vi: set et ts=4: */
diff --git a/src/events.h b/src/events.h
index 4edc5ab..8e75097 100644
--- a/src/events.h
+++ b/src/events.h
@@ -7,6 +7,7 @@
#define __EVENTS__
#include <glib.h>
+#include <stdarg.h>
/* Event system */
enum event_type {
@@ -38,7 +39,10 @@ void
send_event_stdout(GString *msg);
void
-send_event(int type, const gchar *details, const gchar *custom_event);
+vsend_event(int type, const gchar *custom_event, va_list vargs);
+
+void
+send_event(int type, const gchar *custom_event, ...) G_GNUC_NULL_TERMINATED;
void
key_to_event(guint keyval, gint mode);
diff --git a/src/util.c b/src/util.c
index cc51048..8f6c349 100644
--- a/src/util.c
+++ b/src/util.c
@@ -148,3 +148,33 @@ gchar*
argv_idx(const GArray *a, const guint idx) {
return g_array_index(a, gchar*, idx);
}
+
+GString *
+append_escaped (GString *dest, const gchar *src) {
+ g_assert(dest);
+ g_assert(src);
+
+ // Hint that we are going to append another string.
+ int oldlen = dest->len;
+ g_string_set_size (dest, dest->len + strlen(src) * 2);
+ g_string_truncate (dest, oldlen);
+
+ // Append src char by char with baddies escaped
+ for (const gchar *p = src; *p; p++) {
+ switch (*p) {
+ case '\\':
+ g_string_append (dest, "\\\\");
+ break;
+ case '\'':
+ g_string_append (dest, "\\'");
+ break;
+ case '\n':
+ g_string_append (dest, "\\n");
+ break;
+ default:
+ g_string_append_c (dest, *p);
+ break;
+ }
+ }
+ return dest;
+}
diff --git a/src/util.h b/src/util.h
index 126166b..75a614b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -13,3 +13,7 @@ char* str_replace(const char* search, const char* replace, const char* str
gboolean for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data);
gchar* find_existing_file(const gchar*);
gchar* argv_idx(const GArray*, const guint);
+/**
+ * appends `src' to `dest' with backslash, single-quotes and newlines in
+ * `src' escaped */
+GString * append_escaped (GString *dest, const gchar *src);
diff --git a/src/uzbl-core.c b/src/uzbl-core.c
index 936dbdc..b2e7a7a 100644
--- a/src/uzbl-core.c
+++ b/src/uzbl-core.c
@@ -351,7 +351,7 @@ expand(const char* s, guint recurse) {
void
clean_up(void) {
if (uzbl.info.pid_str) {
- send_event(INSTANCE_EXIT, uzbl.info.pid_str, NULL);
+ send_event (INSTANCE_EXIT, NULL, TYPE_INT, getpid(), NULL);
g_free(uzbl.info.pid_str);
uzbl.info.pid_str = NULL;
}
@@ -574,7 +574,7 @@ builtins() {
g_string_append_c(command_list, ' ');
}
- send_event(BUILTINS, command_list->str, NULL);
+ send_event(BUILTINS, NULL, TYPE_STR, command_list->str, NULL);
g_string_free(command_list, TRUE);
}
@@ -611,7 +611,7 @@ event(WebKitWebView *page, GArray *argv, GString *result) {
else
return;
- send_event(0, split[1]?split[1]:"", event_name->str);
+ send_event(0, event_name->str, TYPE_FORMATTEDSTR, split[1] ? split[1] : "", NULL);
g_string_free(event_name, TRUE);
g_strfreev(split);
@@ -657,11 +657,11 @@ include(WebKitWebView *page, GArray *argv, GString *result) {
if((path = find_existing_file(path))) {
if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) {
gchar *tmp = g_strdup_printf("File %s can not be read.", path);
- send_event(COMMAND_ERROR, tmp, NULL);
+ send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
g_free(tmp);
}
- send_event(FILE_INCLUDED, path, NULL);
+ send_event(FILE_INCLUDED, NULL, TYPE_STR, path, NULL);
g_free(path);
}
}
@@ -1120,13 +1120,17 @@ run_parsed_command(const CommandInfo *c, GArray *a, GString *result) {
if(strcmp("set", c->key) &&
strcmp("event", c->key) &&
strcmp("request", c->key)) {
- GString *tmp = g_string_new(c->key);
+ // FIXME, build string inside send_event
+ GString *param = g_string_new("");
const gchar *p;
guint i = 0;
while ((p = argv_idx(a, i++)))
- g_string_append_printf(tmp, " '%s'", p);
- send_event(COMMAND_EXECUTED, tmp->str, NULL);
- g_string_free(tmp, TRUE);
+ g_string_append_printf(param, " '%s'", p);
+ send_event(COMMAND_EXECUTED, NULL,
+ TYPE_NAME, c->key,
+ TYPE_FORMATTEDSTR, param->str,
+ NULL);
+ g_string_free(param, TRUE);
}
if(result) {
@@ -1166,7 +1170,9 @@ parse_command_parts(const gchar *line, GArray *a) {
c = g_hash_table_lookup(uzbl.behave.commands, tokens[0]);
if(!c) {
- send_event(COMMAND_ERROR, exp_line, NULL);
+ send_event(COMMAND_ERROR, NULL,
+ TYPE_STR, exp_line,
+ NULL);
g_free(exp_line);
g_strfreev(tokens);
return NULL;
@@ -1194,9 +1200,10 @@ parse_command(const char *cmd, const char *params, GString *result) {
g_array_free (a, TRUE);
} else {
- gchar *tmp = g_strconcat(cmd, " ", params, NULL);
- send_event(COMMAND_ERROR, tmp, NULL);
- g_free(tmp);
+ send_event(COMMAND_ERROR, NULL,
+ TYPE_NAME, cmd,
+ TYPE_STR, params ? params : "",
+ NULL);
}
}
@@ -1227,42 +1234,73 @@ move_statusbar() {
}
gboolean
+valid_name(const gchar* name) {
+ char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
+ return strpbrk(name, invalid_chars) == NULL;
+}
+
+void
+send_set_var_event(const char *name, const uzbl_cmdprop *c) {
+ /* check for the variable type */
+ switch(c->type) {
+ case TYPE_STR:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, *c->ptr.s ? *c->ptr.s : " ",
+ NULL);
+ break;
+ case TYPE_INT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "int",
+ TYPE_INT, *c->ptr.i,
+ NULL);
+ break;
+ case TYPE_FLOAT:
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "float",
+ TYPE_FLOAT, *c->ptr.f,
+ NULL);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+gboolean
set_var_value(const gchar *name, gchar *val) {
uzbl_cmdprop *c = NULL;
char *endp = NULL;
char *buf = NULL;
- char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½";
- GString *msg;
if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
if(!c->writeable) return FALSE;
- msg = g_string_new(name);
-
- /* check for the variable type */
- if (c->type == TYPE_STR) {
+ switch(c->type) {
+ case TYPE_STR:
buf = g_strdup(val);
g_free(*c->ptr.s);
*c->ptr.s = buf;
- g_string_append_printf(msg, " str %s", buf);
-
- } else if(c->type == TYPE_INT) {
+ break;
+ case TYPE_INT:
*c->ptr.i = (int)strtoul(val, &endp, 10);
- g_string_append_printf(msg, " int %d", *c->ptr.i);
-
- } else if (c->type == TYPE_FLOAT) {
+ break;
+ case TYPE_FLOAT:
*c->ptr.f = strtod(val, &endp);
- g_string_append_printf(msg, " float %f", *c->ptr.f);
+ break;
+ default:
+ g_assert_not_reached();
}
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg,TRUE);
+ send_set_var_event(name, c);
/* invoke a command specific function */
if(c->func) c->func();
} else {
/* check wether name violates our naming scheme */
- if(strpbrk(name, invalid_chars)) {
+ if(!valid_name(name)) {
if (uzbl.state.verbose)
printf("Invalid variable name: %s\n", name);
return FALSE;
@@ -1280,10 +1318,11 @@ set_var_value(const gchar *name, gchar *val) {
g_hash_table_insert(uzbl.comm.proto_var,
g_strdup(name), (gpointer) c);
- msg = g_string_new(name);
- g_string_append_printf(msg, " str %s", buf);
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg,TRUE);
+ send_event (VARIABLE_SET, NULL,
+ TYPE_NAME, name,
+ TYPE_NAME, "str",
+ TYPE_STR, buf,
+ NULL);
}
update_title();
return TRUE;
@@ -1480,7 +1519,7 @@ settings_init () {
if (s->config_file) {
if (!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) {
gchar *tmp = g_strdup_printf("File %s can not be read.", s->config_file);
- send_event(COMMAND_ERROR, tmp, NULL);
+ send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL);
g_free(tmp);
}
g_setenv("UZBL_CONFIG", s->config_file, TRUE);
@@ -1573,23 +1612,9 @@ void
dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) {
(void) ud;
uzbl_cmdprop *c = v;
- GString *msg;
-
- if(!c->dump)
- return;
-
- /* check for the variable type */
- msg = g_string_new((char *)k);
- if (c->type == TYPE_STR) {
- g_string_append_printf(msg, " str %s", *c->ptr.s ? *c->ptr.s : " ");
- } else if(c->type == TYPE_INT) {
- g_string_append_printf(msg, " int %d", *c->ptr.i);
- } else if (c->type == TYPE_FLOAT) {
- g_string_append_printf(msg, " float %f", *c->ptr.f);
- }
- send_event(VARIABLE_SET, msg->str, NULL);
- g_string_free(msg, TRUE);
+ if(c->dump)
+ send_set_var_event(k, c);
}
void
@@ -1796,12 +1821,10 @@ main (int argc, char* argv[]) {
uzbl.info.pid_str = g_strdup_printf("%d", getpid());
g_setenv("UZBL_PID", uzbl.info.pid_str, TRUE);
- send_event(INSTANCE_START, uzbl.info.pid_str, NULL);
+ send_event(INSTANCE_START, NULL, TYPE_INT, getpid(), NULL);
if (uzbl.state.plug_mode) {
- char *t = g_strdup_printf("%d", gtk_plug_get_id(uzbl.gui.plug));
- send_event(PLUG_CREATED, t, NULL);
- g_free(t);
+ send_event(PLUG_CREATED, NULL, TYPE_INT, gtk_plug_get_id (uzbl.gui.plug), NULL);
}
/* Generate an event with a list of built in commands */
diff --git a/src/uzbl-core.h b/src/uzbl-core.h
index a10c0ce..3240fc6 100644
--- a/src/uzbl-core.h
+++ b/src/uzbl-core.h
@@ -241,7 +241,9 @@ extern UzblCore uzbl; /* Main Uzbl object */
typedef void sigfunc(int);
/* Uzbl variables */
-enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT};
+enum ptr_type {TYPE_INT = 1, TYPE_STR, TYPE_FLOAT,
+ TYPE_NAME, TYPE_FORMATTEDSTR // used by send_event
+};
typedef struct {
enum ptr_type type;
union {
@@ -315,6 +317,7 @@ void handle_authentication (SoupSession *session,
void handle_cookies (SoupSession *session,
SoupMessage *msg,
gpointer user_data);
+gboolean valid_name(const gchar* name);
void set_var(WebKitWebView *page, GArray *argv, GString *result);
void act_dump_config();
void act_dump_config_as_events();
diff --git a/tests/test-command.c b/tests/test-command.c
index 6d3d81e..55bf316 100644
--- a/tests/test-command.c
+++ b/tests/test-command.c
@@ -152,7 +152,7 @@ test_set_variable (struct EventFixture *ef, const void *data) {
/* set a string */
parse_cmd_line("set useragent = Uzbl browser kthxbye!", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET useragent str Uzbl browser kthxbye!");
+ ASSERT_EVENT(ef, "VARIABLE_SET useragent str 'Uzbl browser kthxbye!'");
g_assert_cmpstr("Uzbl browser kthxbye!", ==, uzbl.net.useragent);
/* set an int */
@@ -168,7 +168,7 @@ test_set_variable (struct EventFixture *ef, const void *data) {
parse_cmd_line(g_string_free(cmd, FALSE), NULL);
ev = g_string_new("EVENT [" INSTANCE_NAME "] VARIABLE_SET zoom_level float ");
- g_string_append_printf(ev, "%f\n", 0.25);
+ g_string_append_printf(ev, "%.2f\n", 0.25);
read_event(ef);
g_assert_cmpstr(g_string_free(ev, FALSE), ==, ef->event_buffer);
@@ -188,13 +188,13 @@ test_set_variable (struct EventFixture *ef, const void *data) {
/* set a custom variable */
parse_cmd_line("set nonexistant_variable = Some Value", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET nonexistant_variable str Some Value");
+ ASSERT_EVENT(ef, "VARIABLE_SET nonexistant_variable str 'Some Value'");
uzbl_cmdprop *c = g_hash_table_lookup(uzbl.comm.proto_var, "nonexistant_variable");
g_assert_cmpstr("Some Value", ==, *c->ptr.s);
/* set a custom variable with expansion */
parse_cmd_line("set an_expanded_variable = Test @(echo expansion)@", NULL);
- ASSERT_EVENT(ef, "VARIABLE_SET an_expanded_variable str Test expansion");
+ ASSERT_EVENT(ef, "VARIABLE_SET an_expanded_variable str 'Test expansion'");
c = g_hash_table_lookup(uzbl.comm.proto_var, "an_expanded_variable");
g_assert_cmpstr("Test expansion", ==, *c->ptr.s);
}