From e04b4d1628000f185e4499c0bdd9d5a5a610fd15 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 27 Apr 2009 21:25:35 +0200 Subject: reorganize/refactor example scripts/config / bookmark file etc so that its easier for new users + separate config for development --- examples/bookmarks | 4 +++ examples/configs/sampleconfig | 41 +++++++++++++++++++++++++++++ examples/configs/sampleconfig-dev | 41 +++++++++++++++++++++++++++++ examples/scripts/download.sh | 2 ++ examples/scripts/history.sh | 4 +++ examples/scripts/insert_bookmark.sh | 15 +++++++++++ examples/scripts/load_url_from_bookmarks.sh | 12 +++++++++ examples/scripts/load_url_from_history.sh | 6 +++++ 8 files changed, 125 insertions(+) create mode 100644 examples/bookmarks create mode 100644 examples/configs/sampleconfig create mode 100644 examples/configs/sampleconfig-dev create mode 100755 examples/scripts/download.sh create mode 100755 examples/scripts/history.sh create mode 100755 examples/scripts/insert_bookmark.sh create mode 100755 examples/scripts/load_url_from_bookmarks.sh create mode 100755 examples/scripts/load_url_from_history.sh (limited to 'examples') diff --git a/examples/bookmarks b/examples/bookmarks new file mode 100644 index 0000000..13fcd48 --- /dev/null +++ b/examples/bookmarks @@ -0,0 +1,4 @@ +http://www.archlinux.org linux arch +http://www.uzbl.org uzbl browser +http://dieter.plaetinck.be uzbl +http://www.icanhascheezburger.com lolcats fun diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig new file mode 100644 index 0000000..b92acc2 --- /dev/null +++ b/examples/configs/sampleconfig @@ -0,0 +1,41 @@ + +# example uzbl config. in a real config, we should obey the xdg spec + +# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. +# bindings_internal denote keys to trigger actions internally in uzbl +# bindings_external denote keys to trigger scripts outside uzbl + +# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the actions +# from insert mode by combining them with the modkey + +[behavior] +history_handler = /bin/bash /usr/share/uzbl/examples/scripts/history.sh +download_handler = /bin/bash /usr/share/uzbl/examples/scripts/download.sh +fifo_dir = /tmp +always_insert_mode = 0 +modkey = Mod1 +show_status = 1 +status_top = 0 + +[bindings_internal] +back = b +forward = m +stop = s +refresh = r +reload = R +home = h +follow_link_here = f +follow_link_new_tab = F +follow_link_new_window = w +zoom_in = + +zoom_out = - +toggle_status = t + +[bindings_external] +/bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh = B +/bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh = u +/bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh = U + +[network] diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev new file mode 100644 index 0000000..f7f3bb7 --- /dev/null +++ b/examples/configs/sampleconfig-dev @@ -0,0 +1,41 @@ + +# example uzbl config. in a real config, we should obey the xdg spec + +# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. +# bindings_internal denote keys to trigger actions internally in uzbl +# bindings_external denote keys to trigger scripts outside uzbl + +# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the actions +# from insert mode by combining them with the modkey + +[behavior] +history_handler = /bin/bash ./examples/scripts/history.sh +download_handler = /bin/bash ./examples/scripts/download.sh +fifo_dir = /tmp +always_insert_mode = 0 +modkey = Mod1 +show_status = 1 +status_top = 0 + +[bindings_internal] +back = b +forward = m +stop = s +refresh = r +reload = R +home = h +follow_link_here = f +follow_link_new_tab = F +follow_link_new_window = w +zoom_in = + +zoom_out = - +toggle_status = t + +[bindings_external] +/bin/bash ./examples/scripts/insert_bookmark.sh = B +/bin/bash ./examples/scripts/load_url_from_history.sh = u +/bin/bash ./examples/scripts/load_url_from_bookmarks.sh = U + +[network] diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh new file mode 100755 index 0000000..ff3d8db --- /dev/null +++ b/examples/scripts/download.sh @@ -0,0 +1,2 @@ +#!/bin/bash +wget $5 diff --git a/examples/scripts/history.sh b/examples/scripts/history.sh new file mode 100755 index 0000000..03c568a --- /dev/null +++ b/examples/scripts/history.sh @@ -0,0 +1,4 @@ +#!/bin/bash +#TODO: strip 'http://' part +# you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) +echo "$7 $5" >> /tmp/uzbl.history diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh new file mode 100755 index 0000000..af6ca8a --- /dev/null +++ b/examples/scripts/insert_bookmark.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) +if [ -f /usr/share/uzbl/examples/bookmarks ] +then + file=/usr/share/uzbl/examples/bookmarks +else + file=./examples/bookmarks #useful when developing +fi + +which zenity &>/dev/null || exit 2 + +entry=`zenity --entry --text="Add bookmark. add tags at the end, separated by commas" --entry-text="$5"` +url=`awk '{print $1}' <<< $entry` +# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags +echo "$entry" >> $file diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh new file mode 100755 index 0000000..fd9179e --- /dev/null +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) +if [ -f /usr/share/uzbl/examples/bookmarks ] +then + file=/usr/share/uzbl/examples/bookmarks +else + file=./examples/bookmarks #useful when developing +fi + +goto=`awk '{print $1}' $history_file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. +[ -n "$goto" ] && echo "uri $goto" > $4 diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh new file mode 100755 index 0000000..366aedf --- /dev/null +++ b/examples/scripts/load_url_from_history.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) +history_file=/tmp/uzbl.history + +goto=`awk '{print $3}' $history_file | sort | uniq | dmenu` +[ -n "$goto" ] && echo "uri $goto" > $4 -- cgit v1.2.3 From 9350236d497be03e9df441fe98f30bbc161ae6ab Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 27 Apr 2009 21:48:11 +0200 Subject: insert_bookmark related stuff --- README | 3 ++- TODO | 1 + examples/scripts/insert_bookmark.sh | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/README b/README index 962bb31..3dedb25 100644 --- a/README +++ b/README @@ -2,7 +2,8 @@ TO NEW PEOPLE: - please read the README in /usr/share/uzbl/docs - invoke uzbl --help - to get you started: uzbl --uri 'http://www.archlinux.org' --config /usr/share/uzbl/examples/configs/sampleconfig - - study the sample config, have a look at all the bindings, and note how you can call the scripts to insert a bookmark, and load new url from history and the bookmarks file + - study the sample config, have a look at all the bindings, and note how you can call the scripts to load new url from history and the bookmarks file + - inserting new bookmarks is not working yet. it will be soon. - note that there is no url bar. all url editing is supposed to happen _outside_ of uzbl. right now you cannot just change the url as you please (we are working on that) for now, you can use the load_from scripts and write commands into the fifo (see /usr/share/uzbl/docs/CHECKLIST) diff --git a/TODO b/TODO index 8a0cb91..5b300e3 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,5 @@ ASAP +* do a clean implementation of bindings that need arguments (eg insert_bookmark needs the uri.) * implement all the ideas from README * get a logo diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh index af6ca8a..be17c05 100755 --- a/examples/scripts/insert_bookmark.sh +++ b/examples/scripts/insert_bookmark.sh @@ -1,8 +1,9 @@ #!/bin/bash # you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) + if [ -f /usr/share/uzbl/examples/bookmarks ] then - file=/usr/share/uzbl/examples/bookmarks + file=/usr/share/uzbl/examples/bookmarks # you will probably get permission denied errors here. pick a file in your ~ else file=./examples/bookmarks #useful when developing fi -- cgit v1.2.3 From 4272975c6bd04915c7cd74d53604efdc1dd83aab Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 27 Apr 2009 21:50:12 +0200 Subject: typo fix should fix bookmark loading --- examples/scripts/load_url_from_bookmarks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index fd9179e..ca512eb 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -8,5 +8,5 @@ else file=./examples/bookmarks #useful when developing fi -goto=`awk '{print $1}' $history_file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. +goto=`awk '{print $1}' $file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. [ -n "$goto" ] && echo "uri $goto" > $4 -- cgit v1.2.3 From 19db1dd05caf52db5d8d5c5187f1406fd99a9627 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Tue, 28 Apr 2009 08:12:16 +0100 Subject: Added 'exit' command (bound to 'k' by default). --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 1 + uzbl.c | 12 +++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index b92acc2..94cbbb8 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -32,6 +32,7 @@ follow_link_new_window = w zoom_in = + zoom_out = - toggle_status = t +exit = k [bindings_external] /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh = B diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index f7f3bb7..4281ab8 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -32,6 +32,7 @@ follow_link_new_window = w zoom_in = + zoom_out = - toggle_status = t +exit = k [bindings_external] /bin/bash ./examples/scripts/insert_bookmark.sh = B diff --git a/uzbl.c b/uzbl.c index 438dae3..422607f 100644 --- a/uzbl.c +++ b/uzbl.c @@ -110,6 +110,9 @@ update_title (GtkWindow* window); static void load_uri ( WebKitWebView * web_view, const gchar * uri); +static void +close_uzbl ( WebKitWebView * web_view); + static gboolean run_command(const char *command, const char *args); @@ -245,7 +248,8 @@ static Command commands[] = { "zoom_in", &webkit_web_view_zoom_in, NULL }, //Can crash (when max zoom reached?). { "zoom_out", &webkit_web_view_zoom_out, NULL }, { "uri", (void *) NULL, &load_uri }, - { "toggle_status", &toggle_status_cb, NULL } + { "toggle_status", &toggle_status_cb, NULL }, + { "exit" , &close_uzbl, NULL }, //{ "get uri", &webkit_web_view_get_uri}, }; @@ -273,6 +277,12 @@ load_uri (WebKitWebView * web_view, const gchar * uri) { } +static void +close_uzbl (WebKitWebView * web_view) { + (void) web_view; + gtk_main_quit (); +} + // make sure to put '' around args, so that if there is whitespace we can still keep arguments together. static gboolean run_command(const char *command, const char *args) { -- cgit v1.2.3 From 7446b36ea6a2067186cf5a25ccd99e16ecc95dcc Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Tue, 28 Apr 2009 17:29:25 +0100 Subject: Tidied up settings loading code. Added home_page parameter to config, and added go_home function. --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 1 + uzbl.c | 69 ++++++++++++++++++--------------------- 3 files changed, 33 insertions(+), 38 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 94cbbb8..03f963d 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -18,6 +18,7 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 +home_page = http://www.uzbl.org [bindings_internal] back = b diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 4281ab8..9d890b60 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -18,6 +18,7 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 +home_page = http://www.uzbl.org [bindings_internal] back = b diff --git a/uzbl.c b/uzbl.c index a2c6931..dc38794 100644 --- a/uzbl.c +++ b/uzbl.c @@ -69,6 +69,7 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; +static gchar* home_page = NULL; typedef struct { const char *binding; @@ -110,6 +111,9 @@ update_title (GtkWindow* window); static void load_uri ( WebKitWebView * web_view, const gchar * uri); +static void +go_home ( WebKitWebView * web_view); + static void close_uzbl ( WebKitWebView * web_view); @@ -249,6 +253,7 @@ static Command commands[] = { "zoom_out", &webkit_web_view_zoom_out, NULL }, { "uri", (void *) NULL, &load_uri }, { "toggle_status", &toggle_status_cb, NULL }, + { "home" , &go_home, NULL }, { "exit" , &close_uzbl, NULL }, //{ "get uri", &webkit_web_view_get_uri}, }; @@ -276,6 +281,11 @@ load_uri (WebKitWebView * web_view, const gchar * uri) { } } +static void +go_home (WebKitWebView * web_view) { + if (home_page) + webkit_web_view_load_uri (web_view, home_page); +} static void close_uzbl (WebKitWebView * web_view) { @@ -414,7 +424,7 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) (void) page; int i; gboolean result=FALSE; //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. - if (event->type != GDK_KEY_PRESS) + if (event->type != GDK_KEY_PRESS) return result; //TURN OFF/ON INSERT MODE @@ -558,48 +568,31 @@ settings_init () { } if (res) { - history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); - download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); + history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); + download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); - show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); - modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); - keysi = g_key_file_get_keys (config, "bindings_internal", NULL, NULL); - keyse = g_key_file_get_keys (config, "bindings_external", NULL, NULL); - status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); + show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); + modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); + keysi = g_key_file_get_keys (config, "bindings_internal", NULL, NULL); + keyse = g_key_file_get_keys (config, "bindings_external", NULL, NULL); + status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); + home_page = g_key_file_get_value (config, "behavior", "home_page", NULL); if (! fifodir) - fifodir = g_key_file_get_value (config, "behavior", "fifodir", NULL); + fifodir = g_key_file_get_value (config, "behavior", "fifodir", NULL); } - if (history_handler) { - printf ("History handler: %s\n", history_handler); - } else { - printf ("History handler disabled\n"); - } - - if (download_handler) { - printf ("Download manager: %s\n", download_handler); - } else { - printf ("Download manager disabled\n"); - } + printf ("History handler: %s\n", (history_handler ? history_handler : "disabled")); + printf ("Download manager: %s\n", (download_handler ? download_handler : "disabled")); + printf ("FIFO directory: %s\n", (fifodir ? fifodir : "/tmp")); + printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); + printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); + printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); + printf ("Modkey: %s\n", (modkey ? modkey : "disabled")); + printf ("Home page: %s\n", (home_page ? home_page : "disabled")); + + if (! modkey) + modkey = ""; - if (fifodir) { - printf ("Fifo directory: %s\n", fifodir); - } else { - printf ("Fifo directory: /tmp\n"); - } - - printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); - - printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); - - printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); - - if (modkey) { - printf ("Modkey: %s\n", modkey); - } else { - printf ("Modkey disabled\n"); - modkey = ""; - } //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED) gchar* modkeyup = g_utf8_strup (modkey, -1); if (g_strrstr (modkeyup,"SHIFT") != NULL) modmask |= GDK_SHIFT_MASK; //the Shift key. -- cgit v1.2.3 From b3b92d1fa68aaca611acc434338f602f25d5e44c Mon Sep 17 00:00:00 2001 From: prema Date: Tue, 28 Apr 2009 21:08:12 +0200 Subject: Merge bindings, new command merges external and internal binding, create new command spawn. in fifo and config file, separate command name and parameter via space. Now, there's only one command func. proto. --- examples/configs/sampleconfig | 34 +++--- examples/configs/sampleconfig-dev | 34 +++--- uzbl.c | 243 +++++++++++++++++++------------------- 3 files changed, 153 insertions(+), 158 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index b92acc2..d2991af 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -19,23 +19,21 @@ modkey = Mod1 show_status = 1 status_top = 0 -[bindings_internal] -back = b -forward = m -stop = s -refresh = r -reload = R -home = h -follow_link_here = f -follow_link_new_tab = F -follow_link_new_window = w -zoom_in = + -zoom_out = - -toggle_status = t - -[bindings_external] -/bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh = B -/bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh = u -/bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh = U +[bindings] +b = back +m = forward +s = stop +r = refresh +R = reload +h = home +f = follow_link_here +F = follow_link_new_tab +w = follow_link_new_window ++ = zoom_in +- = zoom_out +t = toggle_status +B = spawn /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh +u = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh +U = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh [network] diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index f7f3bb7..4caa9ff 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -19,23 +19,21 @@ modkey = Mod1 show_status = 1 status_top = 0 -[bindings_internal] -back = b -forward = m -stop = s -refresh = r -reload = R -home = h -follow_link_here = f -follow_link_new_tab = F -follow_link_new_window = w -zoom_in = + -zoom_out = - -toggle_status = t - -[bindings_external] -/bin/bash ./examples/scripts/insert_bookmark.sh = B -/bin/bash ./examples/scripts/load_url_from_history.sh = u -/bin/bash ./examples/scripts/load_url_from_bookmarks.sh = U +[bindings] +b = back +m = forward +s = stop +r = refresh +R = reload +h = home +f = follow_link_here +F = follow_link_new_tab +w = follow_link_new_window ++ = zoom_in +- = zoom_out +t = toggle_status +B = spawn /bin/bash ./examples/scripts/insert_bookmark.sh +u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh +U = spawn /bin/bash ./examples/scripts/load_url_from_bookmarks.sh [network] diff --git a/uzbl.c b/uzbl.c index ee10237..2e2c3a8 100644 --- a/uzbl.c +++ b/uzbl.c @@ -30,6 +30,7 @@ #define LENGTH(x) (sizeof x / sizeof x[0]) +#define MAX_BINDINGS 256 #include #include @@ -71,17 +72,14 @@ static gchar* modkey = NULL; static guint modmask = 0; typedef struct { - const char *binding; - const char *action; + char *binding; + char *action; + char *param; } Binding; /* settings from config: group bindings_internal */ -static Binding internal_bindings[256]; -static int num_internal_bindings = 0; - -/* settings from config: group bindings_external */ -static Binding external_bindings[256]; -static int num_external_bindings = 0; +static Binding bindings[MAX_BINDINGS]; +static int num_bindings = 0; /* commandline arguments (set initial values for the state variables) */ static GOptionEntry entries[] = @@ -96,13 +94,12 @@ static GOptionEntry entries[] = typedef struct { const char *command; - void (*func_1_param)(WebKitWebView*); - void (*func_2_params)(WebKitWebView*, const gchar *); + void (*func)(WebKitWebView*, const char *); } Command; /* XDG stuff */ -char *XDG_CONFIG_HOME_default[256]; -char *XDG_CONFIG_DIRS_default = "/etc/xdg"; +static char *XDG_CONFIG_HOME_default[256]; +static char *XDG_CONFIG_DIRS_default = "/etc/xdg"; static void update_title (GtkWindow* window); @@ -113,6 +110,10 @@ load_uri ( WebKitWebView * web_view, const gchar * uri); static gboolean run_command(const char *command, const char *args); +static void +spawn(WebKitWebView *web_view, const char *param); + + /* --- CALLBACKS --- */ static gboolean @@ -147,20 +148,9 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { } static void -go_back_cb (WebKitWebView* page) { - (void) page; - webkit_web_view_go_back (web_view); -} - -static void -go_forward_cb (WebKitWebView* page) { - (void) page; - webkit_web_view_go_forward (web_view); -} - -static void -toggle_status_cb (WebKitWebView* page) { - (void) page; +toggle_status_cb (WebKitWebView* page, const char *param) { + (void)page; + (void)param; if (show_status) { gtk_widget_hide(mainbar); } else { @@ -234,22 +224,35 @@ log_history_cb () { } } +/* VIEW funcs (little webkit wrappers) */ + +#define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);} +VIEWFUNC(reload) +VIEWFUNC(stop_loading) +VIEWFUNC(zoom_in) +VIEWFUNC(zoom_out) +VIEWFUNC(go_back) +VIEWFUNC(go_forward) +#undef VIEWFUNC + /* -- command to callback/function map for things we cannot attach to any signals */ // TODO: reload, home, quit static Command commands[] = { - { "back", &go_back_cb, NULL }, - { "forward", &go_forward_cb, NULL }, - { "refresh", &webkit_web_view_reload, NULL }, //Buggy - { "stop", &webkit_web_view_stop_loading, NULL }, - { "zoom_in", &webkit_web_view_zoom_in, NULL }, //Can crash (when max zoom reached?). - { "zoom_out", &webkit_web_view_zoom_out, NULL }, - { "uri", NULL, &load_uri }, - { "toggle_status", &toggle_status_cb, NULL } + { "back", view_go_back }, + { "forward", view_go_forward }, + { "reload", view_reload, }, //Buggy + { "stop", view_stop_loading, }, + { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). + { "zoom_out", view_zoom_out, }, + { "uri", load_uri }, + { "toggle_status", toggle_status_cb }, + { "spawn", spawn }, //{ "get uri", &webkit_web_view_get_uri}, }; /* -- CORE FUNCTIONS -- */ + static bool file_exists (const char * filename) { @@ -262,10 +265,10 @@ file_exists (const char * filename) { } static void -load_uri (WebKitWebView * web_view, const gchar * uri) { - if (uri != NULL) { - GString* newuri = g_string_new (uri); - if (g_strrstr (uri, "://") == NULL) +load_uri (WebKitWebView * web_view, const gchar *param) { + if (param) { + GString* newuri = g_string_new (param); + if (g_strrstr (param, "://") == NULL) g_string_prepend (newuri, "http://"); webkit_web_view_load_uri (web_view, newuri->str); g_string_free (newuri, TRUE); @@ -290,41 +293,24 @@ run_command(const char *command, const char *args) { } static void -parse_command(const char *cmd) { +spawn(WebKitWebView *web_view, const char *param) { + (void)web_view; + run_command(param, NULL); +} + +static void +parse_command(const char *action, const char *param) { unsigned int i; - Command *c = NULL; - char buffer[512]; - strcpy (buffer, cmd); - const gchar * command_name = strtok (buffer, " "); - const gchar * command_param = strtok (NULL, " ,"); - - Command *c_tmp = NULL; - for (i = 0; i < LENGTH (commands); i++) { - c_tmp = &commands[i]; - if (strncmp (command_name, c_tmp->command, strlen (c_tmp->command)) == 0) { - c = c_tmp; - } - } - if (c != NULL) { - if (c->func_2_params != NULL) { - if (command_param != NULL) { - printf ("command executing: \"%s %s\"\n", command_name, command_param); - c->func_2_params (web_view, command_param); - } else { - if (c->func_1_param != NULL) { - printf ("command executing: \"%s\"\n", command_name); - c->func_1_param (web_view); - } else { - fprintf (stderr, "command needs a parameter. \"%s\" is not complete\n", command_name); - } - } - } else if (c->func_1_param != NULL) { - printf ("command executing: \"%s\"\n", command_name); - c->func_1_param (web_view); - } - } else { - fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd); - } + int parsed = 0; + + for (i = 0; i < LENGTH (commands); i++) + if (strcmp(action, commands[i].command) == 0) { + commands[i].func(web_view, param); + parsed = 1; + } + + if (!parsed) + fprintf (stderr, "command \"%s\" not understood. ignoring.\n", action); } static void @@ -351,10 +337,18 @@ static void char buffer[256]; memset (buffer, 0, sizeof (buffer)); while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo)) { - if (strcmp (buffer, "\n")) { - buffer[strlen (buffer) - 1] = '\0'; // Remove newline - parse_command (buffer); - } + gchar **parts; + + g_strstrip(buffer); + + parts = g_strsplit(buffer, " ", 2); + + if (!parts) + continue; + + parse_command(parts[0], parts[1]); + + g_strfreev(parts); } } @@ -373,8 +367,10 @@ update_title (GtkWindow* window) { GString* string_short = g_string_new (""); if (!always_insert_mode) g_string_append (string_long, (insert_mode ? "[I] " : "[C] ")); - g_string_append (string_long, main_title); - g_string_append (string_short, main_title); + if (main_title) { + g_string_append (string_long, main_title); + g_string_append (string_short, main_title); + } g_string_append (string_long, " - Uzbl browser"); g_string_append (string_short, " - Uzbl browser"); if (load_progress < 100) @@ -414,21 +410,10 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) return TRUE; } - //INTERNAL BINDINGS - for (i = 0; i < num_internal_bindings; i++) { - if (strcmp(event->string, internal_bindings[i].binding) == 0) { + for (i = 0; i < num_bindings; i++) { + if (strcmp(event->string, bindings[i].binding) == 0) { if (!insert_mode || (event->state == modmask)) { - parse_command (internal_bindings[i].action); - result = TRUE; - } - } - } - - //EXTERNAL BINDINGS - for (i = 0; i < num_external_bindings; i++) { - if (strcmp(event->string, external_bindings[i].binding) == 0) { - if (!insert_mode || (event->state == modmask)) { - run_command(external_bindings[i].action, NULL); + parse_command(bindings[i].action, bindings[i].param); result = TRUE; } } @@ -481,29 +466,39 @@ GtkWidget* create_window () { } static void -add_binding (char *binding, char *action, bool internal) { - Binding bind = {binding, action}; - if (internal) { - internal_bindings[num_internal_bindings] = bind; - num_internal_bindings ++; - } else { - external_bindings[num_external_bindings] = bind; - num_external_bindings ++; - } +add_binding (const gchar *key, const gchar *action) { + char **parts = g_strsplit(action, " ", 2); + + printf("add_binding, key '%s', action '%s'", key, action); + + if (!parts) + return; + + if (MAX_BINDINGS == num_bindings) { + fprintf(stderr, "Maximum number number bindings reached, ignoring\n"); + return; + } + + bindings[num_bindings].binding = g_strdup(key); + bindings[num_bindings].action = g_strdup(parts[0]); /* parts[0] is always defined */ + bindings[num_bindings].param = (parts[1] ? g_strdup(parts[1]) : NULL); + + num_bindings++; + + g_strfreev(parts); } static void settings_init () { GKeyFile* config; gboolean res = FALSE; - gchar** keysi = NULL; - gchar** keyse = NULL; + gchar** keys = NULL; if (! config_file) { const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME"); char conf[256]; if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) { - XDG_CONFIG_HOME = (char *)XDG_CONFIG_HOME_default; + XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default; } printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME); @@ -553,11 +548,10 @@ settings_init () { always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); - keysi = g_key_file_get_keys (config, "bindings_internal", NULL, NULL); - keyse = g_key_file_get_keys (config, "bindings_external", NULL, NULL); status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); if (! fifodir) fifodir = g_key_file_get_value (config, "behavior", "fifodir", NULL); + keys = g_key_file_get_keys (config, "bindings", NULL, NULL); } if (history_handler) { @@ -610,32 +604,29 @@ settings_init () { if (g_strrstr (modkeyup,"META") != NULL) modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */ free (modkeyup); - if (keysi) { - int i = 0; - for (i = 0; keysi[i]; i++) { - gchar *binding = g_key_file_get_string (config, "bindings_internal", keysi[i], NULL); - printf ("Action: %s, Binding: %s (internal)\n", g_strdup (keysi[i]), binding); - add_binding (binding, g_strdup (keysi[i]), true); - } - } - if (keyse) { - int i = 0; - for (i = 0; keyse[i]; i++) { - gchar *binding = g_key_file_get_string (config, "bindings_external", keyse[i], NULL); - printf ("Action: %s, Binding: %s (external)\n", g_strdup (keyse[i]), binding); - add_binding (binding, g_strdup (keyse[i]), false); + if (keys) { + int i; + for (i = 0; keys[i]; i++) { + gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL); + + add_binding(g_strstrip(keys[i]), value); + g_free(value); } + + g_strfreev(keys); } } int main (int argc, char* argv[]) { + int i; + gtk_init (&argc, &argv); if (!g_thread_supported ()) g_thread_init (NULL); - strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME")); - strcat ((char *) XDG_CONFIG_HOME_default, "/.config"); + strcat ((char*)XDG_CONFIG_HOME_default, getenv ("HOME")); + strcat ((char*)XDG_CONFIG_HOME_default, "/.config"); GError *error = NULL; GOptionContext* context = g_option_context_new ("- some stuff here maybe someday"); @@ -672,6 +663,14 @@ main (int argc, char* argv[]) { gtk_main (); + for (i = 0; i < num_bindings; i++) { + g_free(bindings[i].binding); + g_free(bindings[i].action); + if (bindings[i].param) + g_free(bindings[i].param); + } + unlink (fifopath); + return 0; } -- cgit v1.2.3 From 3893863e204466b73939fcbeae1a714679a04aad Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 29 Apr 2009 19:51:15 +0200 Subject: dmenu -i in example scripts --- examples/scripts/load_url_from_bookmarks.sh | 2 +- examples/scripts/load_url_from_history.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index ca512eb..9b991c8 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -8,5 +8,5 @@ else file=./examples/bookmarks #useful when developing fi -goto=`awk '{print $1}' $file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. +goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. [ -n "$goto" ] && echo "uri $goto" > $4 diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 366aedf..8978daa 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -2,5 +2,5 @@ # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) history_file=/tmp/uzbl.history -goto=`awk '{print $3}' $history_file | sort | uniq | dmenu` +goto=`awk '{print $3}' $history_file | sort | uniq | dmenu -i` [ -n "$goto" ] && echo "uri $goto" > $4 -- cgit v1.2.3 From 353aefa427b0153fe1db25781771bf1c52fab4d6 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Wed, 29 Apr 2009 19:01:48 +0100 Subject: Replaced FIFO interface with socket. --- .gitignore | 3 +- Makefile | 4 +- TODO | 2 +- examples/scripts/load_url_from_bookmarks.sh | 2 +- examples/scripts/load_url_from_history.sh | 2 +- uzbl.c | 92 +++++++++++++++++++---------- uzblctrl.c | 63 ++++++++++++++++++++ 7 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 uzblctrl.c (limited to 'examples') diff --git a/.gitignore b/.gitignore index 5dc9796..471b6f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -uzbl \ No newline at end of file +uzbl +uzblctrl \ No newline at end of file diff --git a/Makefile b/Makefile index a70ca9a..fa68594 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CPPFLAGS=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -Wall -W LDFLAGS=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) -all: uzbl +all: uzbl uzblctrl test: ./uzbl --uri http://www.uzbl.org @@ -13,12 +13,14 @@ test-config-real: clean: rm -f uzbl + rm -f uzblctrl install: install -d $(DESTDIR)/usr/bin install -d $(DESTDIR)/usr/share/uzbl/docs install -d $(DESTDIR)/usr/share/uzbl/examples install -D -m755 uzbl $(DESTDIR)/usr/bin/uzbl + install -D -m755 uzblctrl $(DESTDIR)/usr/bin/uzblctrl cp -ax examples $(DESTDIR)/usr/share/uzbl/ install -D -m644 CHECKLIST $(DESTDIR)/usr/share/uzbl/docs install -D -m644 README $(DESTDIR)/usr/share/uzbl/docs diff --git a/TODO b/TODO index 8f5a7f2..fbedb5a 100644 --- a/TODO +++ b/TODO @@ -11,7 +11,7 @@ ASAP * implement a vimperator-like link following scheme. but let user pick his favorite characters to construct the "link identifiers" with. * add a keybind to hand the current url to an external scrips, so you can edit it and/or store it in the primary and secondary clipboards * use http://library.gnome.org/devel/glib/stable/glib-Hash-Tables.html#g-hash-table-insert for tracking bindings and wherever we use structs and ugly loops -* fifo -> socket. so you can do question-response. socket is slightly more complicated so we'll need to create a uzblctrl +* fifo -> socket. so you can do question-response. socket is slightly more complicated so we'll need to create a uzblctrl (half done - commands can't yet send data back) * select/fork based instead of the pthread stuff -> drops dependency, more lightweight. * on website, see if we can
the documentation inside the uzbl project itself, so we need to maintain the stuff on only 1 place * see if we can use the github bugtracker (anonymous posting allowed?) diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index ca512eb..7dffafe 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -9,4 +9,4 @@ else fi goto=`awk '{print $1}' $file | dmenu` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $4 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 366aedf..08cf413 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -3,4 +3,4 @@ history_file=/tmp/uzbl.history goto=`awk '{print $3}' $history_file | sort | uniq | dmenu` -[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $4 -c "uri $goto" diff --git a/uzbl.c b/uzbl.c index dcf5fe5..cf46f25 100644 --- a/uzbl.c +++ b/uzbl.c @@ -42,6 +42,11 @@ #include #include #include +#include +#include +#include +#include +#include /* housekeeping / internal variables */ static GtkWidget* main_window; @@ -52,18 +57,17 @@ static gchar* main_title; static gchar selected_url[500] = "\0"; static gint load_progress; static Window xwin = 0; -static char fifopath[64]; +static char socket_path[108]; /* state variables (initial values coming from command line arguments but may be changed later) */ static gchar* uri = NULL; static gchar* config_file = NULL; static gchar config_file_path[500]; - static gboolean verbose = FALSE; /* settings from config: group behaviour */ static gchar* history_handler = NULL; -static gchar* fifodir = NULL; +static gchar* socket_dir = NULL; static gchar* download_handler = NULL; static gboolean always_insert_mode = FALSE; static gboolean show_status = FALSE; @@ -331,10 +335,10 @@ close_uzbl (WebKitWebView * web_view) { // make sure to put '' around args, so that if there is whitespace we can still keep arguments together. static gboolean run_command(const char *command, const char *args) { - //command [args] + //command [args] GString* to_execute = g_string_new (""); gboolean result; - g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s'", command, config_file, (int) getpid() , (int) xwin, fifopath); + g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s'", command, config_file, (int) getpid() , (int) xwin, socket_path); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -383,34 +387,60 @@ parse_command(const char *cmd) { } static void -*control_fifo() { - if (fifodir) { - sprintf (fifopath, "%s/uzbl_%d", fifodir, (int) xwin); +*control_socket() { + if (socket_dir) { + sprintf (socket_path, "%s/uzbl_%d", socket_dir, (int) xwin); } else { - sprintf (fifopath, "/tmp/uzbl_%d", (int) xwin); + sprintf (socket_path, "/tmp/uzbl_%d", (int) xwin); } - if (mkfifo (fifopath, 0666) == -1) { - printf ("Possible error creating fifo\n"); + int sock, clientsock, len; + unsigned int t; + struct sockaddr_un local, remote; + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strcpy (local.sun_path, socket_path); + unlink (local.sun_path); + + len = strlen (local.sun_path) + sizeof (local.sun_family); + bind (sock, (struct sockaddr *) &local, len); + + if (errno == -1) { + printf ("A problem occurred when opening a socket in %s\n", socket_path); + } else { + printf ("Control socket opened in %s\n", socket_path); } + + listen (sock, 5); - printf ("Control fifo opened in %s\n", fifopath); - - while (true) { - FILE *fifo = fopen (fifopath, "r"); - if (!fifo) { - printf ("Could not open %s for reading\n", fifopath); - return NULL; - } - - char buffer[256]; + for(;;) { + int done, n; + char buffer[512]; + char temp[128]; + memset (buffer, 0, sizeof (buffer)); - while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo)) { - if (strcmp (buffer, "\n")) { - buffer[strlen (buffer) - 1] = '\0'; // Remove newline - parse_command (buffer); - } + + t = sizeof (remote); + clientsock = accept (sock, (struct sockaddr *) &remote, &t); + printf ("Connected to client\n"); + + done = 0; + do { + n = recv (clientsock, temp, 128, 0); + if (n == 0) + done = 1; + + if (!done) + strcat (buffer, temp); + } while (!done); + + if (strcmp (buffer, "\n")) { + buffer[strlen (buffer) - 1] = '\0'; + parse_command (buffer); } + close(clientsock); } return NULL; @@ -419,7 +449,7 @@ static void static void setup_threading () { pthread_t control_thread; - pthread_create(&control_thread, NULL, control_fifo, NULL); + pthread_create(&control_thread, NULL, control_socket, NULL); } static void @@ -613,13 +643,13 @@ settings_init () { keyse = g_key_file_get_keys (config, "bindings_external", NULL, NULL); status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); home_page = g_key_file_get_value (config, "behavior", "home_page", NULL); - if (! fifodir) - fifodir = g_key_file_get_value (config, "behavior", "fifodir", NULL); + if (! socket_dir) + socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); } printf ("History handler: %s\n", (history_handler ? history_handler : "disabled")); printf ("Download manager: %s\n", (download_handler ? download_handler : "disabled")); - printf ("FIFO directory: %s\n", (fifodir ? fifodir : "/tmp")); + printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "/tmp")); printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); @@ -713,7 +743,7 @@ main (int argc, char* argv[]) { gtk_main (); - unlink (fifopath); + unlink (socket_path); return 0; } diff --git a/uzblctrl.c b/uzblctrl.c new file mode 100644 index 0000000..5415247 --- /dev/null +++ b/uzblctrl.c @@ -0,0 +1,63 @@ +/* Socket code more or less completely copied from here: http://www.ecst.csuchico.edu/~beej/guide/ipc/usock.html */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static gchar* sockpath; +static gchar* command; + +static GOptionEntry entries[] = +{ + { "socket", 's', 0, G_OPTION_ARG_STRING, &sockpath, "Socket path of the client uzbl", NULL }, + { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "The uzbl command to execute", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +int +main(int argc, char* argv[]) { + GError *error = NULL; + GOptionContext* context = g_option_context_new ("- some stuff here maybe someday"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_parse (context, &argc, &argv, &error); + + int s, len; + struct sockaddr_un remote; + + if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror ("socket"); + exit (1); + } + + remote.sun_family = AF_UNIX; + strcpy (remote.sun_path, (char *) sockpath); + len = strlen (remote.sun_path) + sizeof (remote.sun_family); + + if (connect (s, (struct sockaddr *) &remote, len) == -1) { + perror ("connect"); + exit (1); + } + + if (send (s, command, strlen (command), 0) == -1) { + perror ("send"); + exit (1); + } + + close(s); + + return 0; +} -- cgit v1.2.3 From f152a16f2bf659c1b17cbb005f5faa770131fb7e Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Wed, 29 Apr 2009 20:39:48 +0100 Subject: Changed fifo_dir to socket_dir --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 03f963d..9fba5b7 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -13,7 +13,7 @@ [behavior] history_handler = /bin/bash /usr/share/uzbl/examples/scripts/history.sh download_handler = /bin/bash /usr/share/uzbl/examples/scripts/download.sh -fifo_dir = /tmp +socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 show_status = 1 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9d890b60..0d8bdd3 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,7 +13,7 @@ [behavior] history_handler = /bin/bash ./examples/scripts/history.sh download_handler = /bin/bash ./examples/scripts/download.sh -fifo_dir = /tmp +socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 show_status = 1 -- cgit v1.2.3 From 092201fa92e498a8bcc6fc824fcf179adc8c43fa Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 29 Apr 2009 22:46:08 +0200 Subject: merging fifo support back in :/ experimental! (doesnt work) --- README | 13 ++++---- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 1 + examples/scripts/download.sh | 2 +- examples/scripts/history.sh | 2 +- examples/scripts/load_url_from_bookmarks.sh | 2 +- examples/scripts/load_url_from_history.sh | 2 +- uzbl.c | 52 ++++++++++++++++++++++++++--- 8 files changed, 60 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/README b/README index 02062f1..31f307a 100644 --- a/README +++ b/README @@ -105,18 +105,19 @@ $1 uzbl-config-file $2 uzbl-pid $3 uzbl-x-window-id $4 uzbl_fifo-filename +$5 uzbl_socket-filename .. [ script specific ] (optional) The script specific arguments are this: * history: - $5 page url - $6 page title - $7 date of visit (Y-m-d H:i:s localtime) + $6 page url + $7 page title + $8 date of visit (Y-m-d H:i:s localtime) * add bookmark: - $5 page url - $6 page title + $6 page url + $7 page title * download: - $5 url + $6 url KNOWN BUGS - Segfaults when using zoom commands (happens when max zoom already reached?). diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 9fba5b7..9796859 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -13,6 +13,7 @@ [behavior] history_handler = /bin/bash /usr/share/uzbl/examples/scripts/history.sh download_handler = /bin/bash /usr/share/uzbl/examples/scripts/download.sh +fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 0d8bdd3..d742147 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,6 +13,7 @@ [behavior] history_handler = /bin/bash ./examples/scripts/history.sh download_handler = /bin/bash ./examples/scripts/download.sh +fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 modkey = Mod1 diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh index ff3d8db..41c408e 100755 --- a/examples/scripts/download.sh +++ b/examples/scripts/download.sh @@ -1,2 +1,2 @@ #!/bin/bash -wget $5 +wget $6 diff --git a/examples/scripts/history.sh b/examples/scripts/history.sh index 03c568a..b6671fe 100755 --- a/examples/scripts/history.sh +++ b/examples/scripts/history.sh @@ -1,4 +1,4 @@ #!/bin/bash #TODO: strip 'http://' part # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) -echo "$7 $5" >> /tmp/uzbl.history +echo "$8 $6" >> /tmp/uzbl.history diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index d13b990..2a893bf 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -10,4 +10,4 @@ fi goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. #[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $4 -c "uri $goto" +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index cab4529..81a220a 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -4,4 +4,4 @@ history_file=/tmp/uzbl.history goto=`awk '{print $3}' $history_file | sort | uniq | dmenu -i` #[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $4 -c "uri $goto" +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/uzbl.c b/uzbl.c index 2eeb9e3..75616af 100644 --- a/uzbl.c +++ b/uzbl.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ static gchar* main_title; static gchar selected_url[500] = "\0"; static gint load_progress; static Window xwin = 0; +static char fifo_path[64]; static char socket_path[108]; /* state variables (initial values coming from command line arguments but may be changed later) */ @@ -67,6 +69,7 @@ static gboolean verbose = FALSE; /* settings from config: group behaviour */ static gchar* history_handler = NULL; +static gchar* fifo_dir = NULL; static gchar* socket_dir = NULL; static gchar* download_handler = NULL; static gboolean always_insert_mode = FALSE; @@ -345,10 +348,10 @@ close_uzbl (WebKitWebView * web_view) { // make sure to put '' around args, so that if there is whitespace we can still keep arguments together. static gboolean run_command(const char *command, const char *args) { - //command [args] + //command [args] GString* to_execute = g_string_new (""); gboolean result; - g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s'", command, config_file, (int) getpid() , (int) xwin, socket_path); + g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -387,12 +390,46 @@ parse_command(const char *cmd) { fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd); } +static void +control_fifo(GIOChannel *fd) { + gchar *ctl_line; + gsize ctl_line_length, term_pos; + + if(!fd) + return; + + g_io_channel_read_line(fd, &ctl_line, &ctl_line_length, &term_pos, NULL); //TODO: support partial writes + ctl_line[term_pos] ='\0'; + parse_command(ctl_line); + + return; +} + +static void +create_fifo() { + GIOChannel *chan = NULL; + + if (fifo_dir) { + sprintf (fifo_path, "%s/uzbl_fifo_%d", fifo_dir, (int) xwin); + } else { + sprintf (fifo_path, "/tmp/uzbl_fifo_%d", (int) xwin); + } + printf ("Control fifo opened in %s\n", fifo_path); + if (mkfifo (fifo_path, 0666) == -1) { + printf ("Possible error creating fifo\n"); + } + + if( (chan = g_io_channel_new_file((gchar *) fifo_path, "r+", NULL)) ) + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, chan); + return; +} + static void *control_socket() { if (socket_dir) { - sprintf (socket_path, "%s/uzbl_%d", socket_dir, (int) xwin); + sprintf (socket_path, "%s/uzbl_socket_%d", socket_dir, (int) xwin); } else { - sprintf (socket_path, "/tmp/uzbl_%d", (int) xwin); + sprintf (socket_path, "/tmp/uzbl_socket_%d", (int) xwin); } int sock, clientsock, len; @@ -638,12 +675,15 @@ settings_init () { keyse = g_key_file_get_keys (config, "bindings_external", NULL, NULL); status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); home_page = g_key_file_get_value (config, "behavior", "home_page", NULL); + if (! fifo_dir) + fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); if (! socket_dir) - socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); + socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); } printf ("History handler: %s\n", (history_handler ? history_handler : "disabled")); printf ("Download manager: %s\n", (download_handler ? download_handler : "disabled")); + printf ("Fifo directory: %s\n", (fifo_dir ? fifo_dir : "/tmp")); printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "/tmp")); printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); @@ -740,10 +780,12 @@ main (int argc, char* argv[]) { gtk_widget_hide(mainbar); setup_threading (); + create_fifo (); gtk_main (); unlink (socket_path); + unlink (fifo_path); return 0; } -- cgit v1.2.3 From 6ebde132877402c8634d1058677ed8216e7e682b Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Thu, 30 Apr 2009 20:57:58 +0200 Subject: Homepage function remove, it is substitued by uri "yourhomepagehere" --- examples/configs/sampleconfig | 3 +-- examples/configs/sampleconfig-dev | 3 +-- uzbl.c | 17 +---------------- 3 files changed, 3 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 4cba098..f6e8688 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -19,7 +19,6 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -home_page = http://www.uzbl.org [bindings] b = back @@ -27,7 +26,7 @@ m = forward s = stop r = refresh R = reload -h = home +h = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9413732..f6390b8 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -19,7 +19,6 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -home_page = http://www.uzbl.org [bindings] b = back @@ -27,7 +26,7 @@ m = forward s = stop r = refresh R = reload -h = home +h = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window diff --git a/uzbl.c b/uzbl.c index 967b3f1..a48849c 100644 --- a/uzbl.c +++ b/uzbl.c @@ -79,7 +79,6 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; -static gchar* home_page = NULL; /* settings from config: group bindings, key -> action */ static GHashTable *bindings; @@ -116,9 +115,6 @@ load_uri ( WebKitWebView * web_view, const gchar * uri); static void new_window_load_uri (const gchar * uri); -static void -go_home (WebKitWebView *page, const char *param); - static void close_uzbl (WebKitWebView *page, const char *param); @@ -266,7 +262,7 @@ VIEWFUNC(go_forward) #undef VIEWFUNC /* -- command to callback/function map for things we cannot attach to any signals */ -// TODO: reload, home, quit +// TODO: reload static struct {char *name; Command command;} cmdlist[] = { @@ -280,7 +276,6 @@ static struct {char *name; Command command;} cmdlist[] = { "uri", load_uri }, { "toggle_status", toggle_status_cb }, { "spawn", spawn }, - { "home", go_home }, { "exit", close_uzbl }, }; @@ -360,14 +355,6 @@ new_window_load_uri (const gchar * uri) { g_string_free (to_execute, TRUE); } -static void -go_home (WebKitWebView *page, const char *param) { - (void)param; - - if (home_page) - webkit_web_view_load_uri (page, home_page); -} - static void close_uzbl (WebKitWebView *page, const char *param) { (void)page; @@ -707,7 +694,6 @@ settings_init () { show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); - home_page = g_key_file_get_value (config, "behavior", "home_page", NULL); if (! fifo_dir) fifo_dir = g_key_file_get_value (config, "behavior", "fifodir", NULL); if (! socket_dir) @@ -723,7 +709,6 @@ settings_init () { printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); printf ("Modkey: %s\n", (modkey ? modkey : "disabled")); - printf ("Home page: %s\n", (home_page ? home_page : "disabled")); if (! modkey) modkey = ""; -- cgit v1.2.3 From 0c6ca060eef33bae6c2de50ce9918c43f17172f8 Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Thu, 30 Apr 2009 23:31:02 +0200 Subject: multiple character bindings --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index f6e8688..b5d598a 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -26,7 +26,7 @@ m = forward s = stop r = refresh R = reload -h = uri http://www.uzbl.org +gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index f6390b8..3953d79 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -26,7 +26,7 @@ m = forward s = stop r = refresh R = reload -h = uri http://www.uzbl.org +gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window diff --git a/uzbl.c b/uzbl.c index a48849c..ec16590 100644 --- a/uzbl.c +++ b/uzbl.c @@ -61,6 +61,7 @@ static gint load_progress; static Window xwin = 0; static char fifo_path[64]; static char socket_path[108]; +static GString *keycmd; /* state variables (initial values coming from command line arguments but may be changed later) */ static gchar* uri = NULL; @@ -522,6 +523,8 @@ static void update_title (GtkWindow* window) { GString* string_long = g_string_new (""); GString* string_short = g_string_new (""); + + g_string_append_printf(string_long, "%s ", keycmd->str); if (!always_insert_mode) g_string_append (string_long, (insert_mode ? "[I] " : "[C] ")); if (main_title) { @@ -564,18 +567,35 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) return FALSE; //TURN OFF/ON INSERT MODE - if ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i'))) { + if ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i') && !keycmd->len)) { insert_mode = !insert_mode || always_insert_mode; update_title (GTK_WINDOW (main_window)); return TRUE; } - if ((!insert_mode || (event->state == modmask)) && (action = g_hash_table_lookup(bindings, event->string))) { - parse_command(action->name, action->param); + if (insert_mode && event->state != modmask) + return FALSE; + + + if (event->keyval == GDK_Escape) { + g_string_truncate(keycmd, 0); + + update_title (GTK_WINDOW (main_window)); + return TRUE; } - return !insert_mode; + g_string_append(keycmd, event->string); + + if ((action = g_hash_table_lookup(bindings, keycmd->str))) { + g_string_truncate(keycmd, 0); + + parse_command(action->name, action->param); + } + + update_title (GTK_WINDOW (main_window)); + + return TRUE; } static GtkWidget* @@ -765,6 +785,8 @@ main (int argc, char* argv[]) { /* initialize hash table */ bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); + keycmd = g_string_new(""); + settings_init (); commands_hash (); @@ -797,6 +819,8 @@ main (int argc, char* argv[]) { gtk_main (); + g_string_free(keycmd, TRUE); + unlink (socket_path); unlink (fifo_path); -- cgit v1.2.3 From 5130922e2024218321c8b49386e20615a8767002 Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Thu, 30 Apr 2009 23:58:56 +0200 Subject: Entering insert mode is now function --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 1 + uzbl.c | 17 +++++++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index b5d598a..230ef30 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -34,6 +34,7 @@ w = follow_link_new_window - = zoom_out t = toggle_status k = exit +i = insert_mode B = spawn /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh u = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh U = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3953d79..35e7746 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -34,6 +34,7 @@ w = follow_link_new_window - = zoom_out t = toggle_status k = exit +i = insert_mode B = spawn /bin/bash ./examples/scripts/insert_bookmark.sh u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh U = spawn /bin/bash ./examples/scripts/load_url_from_bookmarks.sh diff --git a/uzbl.c b/uzbl.c index ec16590..f3c6588 100644 --- a/uzbl.c +++ b/uzbl.c @@ -131,6 +131,9 @@ free_action(gpointer action); static Action* new_action(const gchar *name, const gchar *param); +static void +set_insert_mode(WebKitWebView *page, const gchar *param); + /* --- CALLBACKS --- */ @@ -278,6 +281,7 @@ static struct {char *name; Command command;} cmdlist[] = { "toggle_status", toggle_status_cb }, { "spawn", spawn }, { "exit", close_uzbl }, + { "insert_mode", set_insert_mode } }; static void @@ -324,6 +328,15 @@ file_exists (const char * filename) { return false; } +void +set_insert_mode(WebKitWebView *page, const gchar *param) { + (void)page; + (void)param; + + insert_mode = TRUE; + update_title (GTK_WINDOW (main_window)); +} + static void load_uri (WebKitWebView * web_view, const gchar *param) { if (param) { @@ -566,8 +579,8 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right) return FALSE; - //TURN OFF/ON INSERT MODE - if ((insert_mode && (event->keyval == GDK_Escape)) || (!insert_mode && (event->string[0] == 'i') && !keycmd->len)) { + /* turn of insert mode */ + if (insert_mode && (event->keyval == GDK_Escape)) { insert_mode = !insert_mode || always_insert_mode; update_title (GTK_WINDOW (main_window)); return TRUE; -- cgit v1.2.3 From b73df48c2c4c48c97bdce954669f4f82897da7ec Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Fri, 1 May 2009 14:35:32 +0200 Subject: scroll stuff, thx to jouz, with slight changes --- examples/configs/sampleconfig | 7 +++++- examples/configs/sampleconfig-dev | 6 ++++- uzbl.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 230ef30..2f9df6f 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -21,6 +21,10 @@ show_status = 1 status_top = 0 [bindings] +j = scroll_down +k = scroll_up +h = scroll_left +l = scroll_right b = back m = forward s = stop @@ -33,10 +37,11 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -k = exit +ZZ = exit i = insert_mode B = spawn /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh u = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh U = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh + [network] diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 35e7746..9fcc906 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -21,6 +21,10 @@ show_status = 1 status_top = 0 [bindings] +j = scroll_down +k = scroll_up +h = scroll_left +l = scroll_right b = back m = forward s = stop @@ -33,7 +37,7 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -k = exit +ZZ = exit i = insert_mode B = spawn /bin/bash ./examples/scripts/insert_bookmark.sh u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh diff --git a/uzbl.c b/uzbl.c index b767f4d..ca6c6ae 100644 --- a/uzbl.c +++ b/uzbl.c @@ -54,6 +54,10 @@ static GtkWidget* main_window; static GtkWidget* mainbar; static GtkWidget* mainbar_label; +static GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar +static GtkScrollbar* scbar_h; // (These are still hidden) +static GtkAdjustment* bar_v; // Information about document length +static GtkAdjustment* bar_h; // and scrolling position static WebKitWebView* web_view; static gchar* main_title; static gchar selected_url[500] = "\0"; @@ -80,6 +84,8 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; +static gdouble hscroll = 20; +static gdouble vscroll = 20; /* settings from config: group bindings, key -> action */ static GHashTable *bindings; @@ -177,10 +183,45 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { return (FALSE); } +/* scroll a bar in a given direction */ +static void +scroll (double i, GtkAdjustment* bar) { + gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+i); +} + +static void scroll_up (WebKitWebView* page, const char *param) { + (void) page; + (void) param; + + scroll (-vscroll, bar_v); +} + +static void scroll_left (WebKitWebView* page, const char *param) { + (void) page; + (void) param; + + scroll (-hscroll, bar_h); +} + +static void scroll_down (WebKitWebView* page, const char *param) { + (void) page; + (void) param; + + scroll (vscroll, bar_v); +} + +static void scroll_right (WebKitWebView* page, const char *param) { + (void) page; + (void) param; + + scroll (hscroll, bar_h); +} + static void toggle_status_cb (WebKitWebView* page, const char *param) { (void)page; (void)param; + if (show_status) { gtk_widget_hide(mainbar); } else { @@ -272,6 +313,10 @@ static struct {char *name; Command command;} cmdlist[] = { { "back", view_go_back }, { "forward", view_go_forward }, + { "scroll_down", scroll_down }, + { "scroll_up", scroll_up }, + { "scroll_left", scroll_left }, + { "scroll_right", scroll_right }, { "reload", view_reload, }, //Buggy { "refresh", view_reload, }, /* for convenience, will change */ { "stop", view_stop_loading, }, @@ -825,6 +870,12 @@ main (int argc, char* argv[]) { printf("window_id %i\n",(int) xwin); printf("pid %i\n", getpid ()); + scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); + bar_v = gtk_range_get_adjustment((GtkRange*) scbar_v); + scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); + bar_h = gtk_range_get_adjustment((GtkRange*) scbar_h); + gtk_widget_set_scroll_adjustments ((GtkWidget*) web_view, bar_h, bar_v); + if (!show_status) gtk_widget_hide(mainbar); -- cgit v1.2.3 From 97348882c8eeac6919ada99bdc5b55b86f99ee1f Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Fri, 1 May 2009 15:07:06 +0200 Subject: Use only 2 scrolling function --- examples/configs/sampleconfig | 9 +++++---- examples/configs/sampleconfig-dev | 9 +++++---- uzbl.c | 38 +++++++++++++------------------------- 3 files changed, 23 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 2f9df6f..1e4d3ee 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -21,10 +21,11 @@ show_status = 1 status_top = 0 [bindings] -j = scroll_down -k = scroll_up -h = scroll_left -l = scroll_right +# scroll down/up/left/right +j = scroll_vert 20 +k = scroll_vert -20 +h = scroll_horz -20 +l = scroll_horz 20 b = back m = forward s = stop diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9fcc906..bcba2df 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -21,10 +21,11 @@ show_status = 1 status_top = 0 [bindings] -j = scroll_down -k = scroll_up -h = scroll_left -l = scroll_right +## scroll down/up/left/right +j = scroll_vert 20 +k = scroll_vert -20 +h = scroll_horz -20 +l = scroll_horz 20 b = back m = forward s = stop diff --git a/uzbl.c b/uzbl.c index ca6c6ae..6a17480 100644 --- a/uzbl.c +++ b/uzbl.c @@ -84,8 +84,6 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; -static gdouble hscroll = 20; -static gdouble vscroll = 20; /* settings from config: group bindings, key -> action */ static GHashTable *bindings; @@ -185,36 +183,28 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { /* scroll a bar in a given direction */ static void -scroll (double i, GtkAdjustment* bar) { - gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+i); -} +scroll (GtkAdjustment* bar, const char *param) { + gdouble amount; + gchar *end; -static void scroll_up (WebKitWebView* page, const char *param) { - (void) page; - (void) param; + amount = g_ascii_strtod(param, &end); - scroll (-vscroll, bar_v); -} - -static void scroll_left (WebKitWebView* page, const char *param) { - (void) page; - (void) param; + if (*end) + fprintf(stderr, "found something after double: %s\n", end); - scroll (-hscroll, bar_h); + gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount); } -static void scroll_down (WebKitWebView* page, const char *param) { +static void scroll_vert(WebKitWebView* page, const char *param) { (void) page; - (void) param; - scroll (vscroll, bar_v); + scroll(bar_v, param); } -static void scroll_right (WebKitWebView* page, const char *param) { +static void scroll_horz(WebKitWebView* page, const char *param) { (void) page; - (void) param; - scroll (hscroll, bar_h); + scroll(bar_h, param); } static void @@ -313,10 +303,8 @@ static struct {char *name; Command command;} cmdlist[] = { { "back", view_go_back }, { "forward", view_go_forward }, - { "scroll_down", scroll_down }, - { "scroll_up", scroll_up }, - { "scroll_left", scroll_left }, - { "scroll_right", scroll_right }, + { "scroll_vert", scroll_vert }, + { "scroll_horz", scroll_horz }, { "reload", view_reload, }, //Buggy { "refresh", view_reload, }, /* for convenience, will change */ { "stop", view_stop_loading, }, -- cgit v1.2.3 From 921b5985eb6c5c82ef68fda58cdfce1f3c2f18ce Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 1 May 2009 17:09:12 +0200 Subject: due to socket addition, url is now $6 --- examples/scripts/insert_bookmark.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh index be17c05..5d76c35 100755 --- a/examples/scripts/insert_bookmark.sh +++ b/examples/scripts/insert_bookmark.sh @@ -10,7 +10,7 @@ fi which zenity &>/dev/null || exit 2 -entry=`zenity --entry --text="Add bookmark. add tags at the end, separated by commas" --entry-text="$5"` +entry=`zenity --entry --text="Add bookmark. add tags at the end, separated by commas" --entry-text="$6"` url=`awk '{print $1}' <<< $entry` # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags echo "$entry" >> $file -- cgit v1.2.3 From 8e524576ecbcdb43c21507f2f11441338d117501 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 1 May 2009 17:14:48 +0200 Subject: no more need for /bin/shellname --- TODO | 1 - examples/configs/sampleconfig | 10 +++++----- examples/configs/sampleconfig-dev | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/TODO b/TODO index 80440a3..2c9f8d1 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,6 @@ ASAP * when launching new instance, don't just try 'uzbl' and then './uzbl', rather launch a new uzbl in the same way the current uzbl instance was started. (same command, same arguments, except --uri) * where to put proxy config? webkit support? depend on libsoup? * compare libsoup to curl backend. there are probably performance differences -* check configured commands if they end on .sh so users don't need to prepend /bin/ * implement a more advanced dmenu alike that behaves like FF's awesomebar and where you can search in url + window title * recognize -h with GOption? * implement a vimperator-like link following scheme. but let user pick his favorite characters to construct the "link identifiers" with. diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 2f9df6f..0f2fa5f 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -11,8 +11,8 @@ # from insert mode by combining them with the modkey [behavior] -history_handler = /bin/bash /usr/share/uzbl/examples/scripts/history.sh -download_handler = /bin/bash /usr/share/uzbl/examples/scripts/download.sh +history_handler = /usr/share/uzbl/examples/scripts/history.sh +download_handler = /usr/share/uzbl/examples/scripts/download.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 @@ -39,9 +39,9 @@ w = follow_link_new_window t = toggle_status ZZ = exit i = insert_mode -B = spawn /bin/bash /usr/share/uzbl/examples/scripts/insert_bookmark.sh -u = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_history.sh -U = spawn /bin/bash /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh +B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh +u = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh +U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh [network] diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9fcc906..7cbf8b4 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,8 +11,8 @@ # from insert mode by combining them with the modkey [behavior] -history_handler = /bin/bash ./examples/scripts/history.sh -download_handler = /bin/bash ./examples/scripts/download.sh +history_handler = ./examples/scripts/history.sh +download_handler = ./examples/scripts/download.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 @@ -39,8 +39,8 @@ w = follow_link_new_window t = toggle_status ZZ = exit i = insert_mode -B = spawn /bin/bash ./examples/scripts/insert_bookmark.sh -u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh -U = spawn /bin/bash ./examples/scripts/load_url_from_bookmarks.sh +B = spawn ./examples/scripts/insert_bookmark.sh +u = spawn ./examples/scripts/load_url_from_history.sh +U = spawn ./examples/scripts/load_url_from_bookmarks.sh [network] -- cgit v1.2.3 From f1abf36c4a8d2b05af81ca8d4f886090f5e01867 Mon Sep 17 00:00:00 2001 From: Evgeny Grablyk Date: Fri, 1 May 2009 20:44:13 +0300 Subject: Add support for network settings Proxy support. Sopport setting user-agent, max. connections number and such. --- examples/configs/sampleconfig-dev | 6 +++++ uzbl.c | 52 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index f6390b8..61ccec9 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -39,3 +39,9 @@ u = spawn /bin/bash ./examples/scripts/load_url_from_history.sh U = spawn /bin/bash ./examples/scripts/load_url_from_bookmarks.sh [network] +proxy_server = +#values 0-3 +http_debug = 0 +user-agent = uzbl +max_conns = +max_conns_per_host = diff --git a/uzbl.c b/uzbl.c index a48849c..e5483df 100644 --- a/uzbl.c +++ b/uzbl.c @@ -1,3 +1,4 @@ +/* -*- c-basic-offset: 4; */ // Original code taken from the example webkit-gtk+ application. see notice below. // Modified code is licensed under the GPL 3. See LICENSE file. @@ -49,6 +50,7 @@ #include #include #include +#include /* housekeeping / internal variables */ static GtkWidget* main_window; @@ -79,6 +81,7 @@ static gboolean insert_mode = FALSE; static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; +static guint http_debug = 0; /* settings from config: group bindings, key -> action */ static GHashTable *bindings; @@ -106,6 +109,14 @@ typedef void (*Command)(WebKitWebView*, const char *); static char *XDG_CONFIG_HOME_default[256]; static char *XDG_CONFIG_DIRS_default = "/etc/xdg"; +/* libsoup stuff - proxy and friends; networking aptions actually */ +static SoupSession *soup_session; +static SoupLogger *soup_logger; +static char *proxy_url = NULL; +static char *useragent = NULL; +static gint max_conns; +static gint max_conns_host; + static void update_title (GtkWindow* window); @@ -744,6 +755,44 @@ settings_init () { g_strfreev(keys); } + + /* networking options */ + proxy_url = g_key_file_get_value(config, "network", "proxy_server", NULL); + http_debug = g_key_file_get_integer(config, "network", "http_debug", NULL); + useragent = g_key_file_get_value(config, "network", "user-agent", NULL); + max_conns = g_key_file_get_integer(config, "network", "max_conns", NULL); + max_conns_host = g_key_file_get_integer(config, "network", "max_conns_per_host", NULL); + + if(proxy_url){ + g_object_set(G_OBJECT(soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(proxy_url), NULL); + printf("Proxy configured: %s\n", proxy_url ? proxy_url : "none"); + } + + if(!(http_debug <= 3)){ + http_debug = 0; + fprintf(stderr, "Wrong http_debug level, ignoring.\n"); + } else { + soup_logger = soup_logger_new(http_debug, -1); + soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(soup_logger)); + printf("HTTP logging level: %d\n", http_debug); + } + + if(useragent){ + g_object_set(G_OBJECT(soup_session), SOUP_SESSION_USER_AGENT, useragent, NULL); + printf("User-agent: %s\n", useragent); + } else { + printf("User-agent: webkit default\n"); + } + + if(max_conns >= 1){ + g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS, max_conns, NULL); + printf("Maximum connections set to: %d\n", max_conns); + } + if(max_conns_host >= 1){ + g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, max_conns_host, NULL); + printf("Maximum connections per host set to: %d\n", max_conns_host); + } + } int @@ -764,7 +813,8 @@ main (int argc, char* argv[]) { g_option_context_parse (context, &argc, &argv, &error); /* initialize hash table */ bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); - + + soup_session = webkit_get_default_session(); settings_init (); commands_hash (); -- cgit v1.2.3 From d9c1fbf27bcaa62acd0df7107254aa1652700ba9 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 1 May 2009 20:30:53 +0200 Subject: smarter history picking. first entry == current url --- examples/scripts/load_url_from_history.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 81a220a..3e2e2ee 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -2,6 +2,10 @@ # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) history_file=/tmp/uzbl.history -goto=`awk '{print $3}' $history_file | sort | uniq | dmenu -i` +# choose from all entries, sorted and uniqued +# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` + +# choose from all entries, the first one being current url, and after that all others, sorted and uniqued. +current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | dmenu -i` #[ -n "$goto" ] && echo "uri $goto" > $4 [ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" -- cgit v1.2.3 From 2730e98467ce79484b45251fc68d6d68872b4169 Mon Sep 17 00:00:00 2001 From: dusanx Date: Sat, 2 May 2009 16:02:07 +0200 Subject: Parameter commands and backspace handling --- CHECKLIST | 5 ++++- examples/configs/sampleconfig-dev | 4 ++++ uzbl.c | 42 +++++++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/CHECKLIST b/CHECKLIST index e88df08..26f733f 100644 --- a/CHECKLIST +++ b/CHECKLIST @@ -25,4 +25,7 @@ Also testers and interested people can use this list to see what uzbl is about, * vimlike command and insert modes behave as expected * always_insert_mode and modkey work too * status bar can be toggled on and off, if off, some info (mode) will be put in title bar. position of statusbar (top/bottom) also works - +* backspace erases last edit character +* commands with parameters: any key sequence that ends with underscore _ expects parameter. Undersore marks exact location where parameter begins. Command part can have %s that will be replaced with parameter. + :o _ = uri %s - user needs to type :o www.google.com + :O_ = uri %s - user needs to type :Owww.google.com diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index a1ba48d..e9c9cc1 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -43,6 +43,10 @@ i = insert_mode B = spawn ./examples/scripts/insert_bookmark.sh u = spawn ./examples/scripts/load_url_from_history.sh U = spawn ./examples/scripts/load_url_from_bookmarks.sh +#parameter command examples (all need space but can be removed from individual commands). underscore is important. +o _ = uri %s +:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +gg _ = uri http://www.google.com/search?q=%s [network] # to start a local socks server, do : ssh -fND localhost:8118 localhost diff --git a/uzbl.c b/uzbl.c index 15efaf9..bffd1ff 100644 --- a/uzbl.c +++ b/uzbl.c @@ -594,20 +594,52 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) if (insert_mode && event->state != modmask) return FALSE; - if (event->keyval == GDK_Escape) { g_string_truncate(keycmd, 0); - update_title(); + return TRUE; + } + if ((event->keyval == GDK_BackSpace) && (keycmd->len > 0)) { + g_string_truncate(keycmd, keycmd->len - 1); + update_title(); return TRUE; } - g_string_append(keycmd, event->string); + if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) { + GString* short_keys = g_string_new (""); + unsigned int i; + for (i=0; i<(keycmd->len); i++) { + g_string_append_c(short_keys, keycmd->str[i]); + g_string_append_c(short_keys, '_'); + + //printf("\nTesting string: @%s@\n", short_keys->str); + if ((action = g_hash_table_lookup(bindings, short_keys->str))) { + GString* parampart = g_string_new (keycmd->str); + g_string_erase (parampart, 0, i+1); + //printf("\nParameter: @%s@\n", parampart->str); + GString* actionname = g_string_new (""); + if (action->name) + g_string_printf (actionname, action->name, parampart->str); + GString* actionparam = g_string_new (""); + if (action->param) + g_string_printf (actionparam, action->param, parampart->str); + parse_command(actionname->str, actionparam->str); + g_string_free (actionname, TRUE); + g_string_free (actionparam, TRUE); + g_string_free (parampart, TRUE); + g_string_truncate(keycmd, 0); + } + + g_string_truncate(short_keys, short_keys->len - 1); + } + g_string_free (short_keys, TRUE); + return (!insert_mode); + } + g_string_append(keycmd, event->string); if ((action = g_hash_table_lookup(bindings, keycmd->str))) { g_string_truncate(keycmd, 0); - parse_command(action->name, action->param); } @@ -665,6 +697,8 @@ add_binding (const gchar *key, const gchar *act) { if (!parts) return; + //Debug: + printf ("@%s@ @%s@ @%s@\n", key, parts[0], parts[1]); action = new_action(parts[0], parts[1]); g_hash_table_insert(bindings, g_strdup(key), action); -- cgit v1.2.3 From c3a8768621d322da0472e4837ee4cafb9110f01a Mon Sep 17 00:00:00 2001 From: Premysl 'Anydot' Hruby Date: Sat, 2 May 2009 23:47:14 +0200 Subject: reload while ignoring cache function added --- examples/configs/sampleconfig | 4 ++-- examples/configs/sampleconfig-dev | 4 ++-- uzbl.c | 29 +++++++++++++++-------------- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 7b88682..3fddc89 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -29,8 +29,8 @@ l = scroll_horz 20 b = back m = forward s = stop -r = refresh -R = reload +r = reload +R = reload_ign_cache gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index e9c9cc1..b151e92 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -29,8 +29,8 @@ l = scroll_horz 20 b = back m = forward s = stop -r = refresh -R = reload +r = reload +R = reload_ign_cache gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab diff --git a/uzbl.c b/uzbl.c index a805ba3..847328a 100644 --- a/uzbl.c +++ b/uzbl.c @@ -280,6 +280,7 @@ log_history_cb () { #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);} VIEWFUNC(reload) +VIEWFUNC(reload_bypass_cache) VIEWFUNC(stop_loading) VIEWFUNC(zoom_in) VIEWFUNC(zoom_out) @@ -292,20 +293,20 @@ VIEWFUNC(go_forward) static struct {char *name; Command command;} cmdlist[] = { - { "back", view_go_back }, - { "forward", view_go_forward }, - { "scroll_vert", scroll_vert }, - { "scroll_horz", scroll_horz }, - { "reload", view_reload, }, //Buggy - { "refresh", view_reload, }, /* for convenience, will change */ - { "stop", view_stop_loading, }, - { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). - { "zoom_out", view_zoom_out, }, - { "uri", load_uri }, - { "toggle_status", toggle_status_cb }, - { "spawn", spawn }, - { "exit", close_uzbl }, - { "insert_mode", set_insert_mode } + { "back", view_go_back }, + { "forward", view_go_forward }, + { "scroll_vert", scroll_vert }, + { "scroll_horz", scroll_horz }, + { "reload", view_reload, }, + { "reload_ign_cache", view_reload_bypass_cache}, + { "stop", view_stop_loading, }, + { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). + { "zoom_out", view_zoom_out, }, + { "uri", load_uri }, + { "toggle_status", toggle_status_cb }, + { "spawn", spawn }, + { "exit", close_uzbl }, + { "insert_mode", set_insert_mode } }; static void -- cgit v1.2.3 From 1bf1244122e822695d14c31a2efc236fe7ede5e1 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 3 May 2009 15:13:02 +0200 Subject: cleanup configs --- examples/configs/sampleconfig | 17 ++++++++++------- examples/configs/sampleconfig-dev | 13 ++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 7b88682..2870cf7 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -22,33 +22,36 @@ status_top = 0 [bindings] # scroll down/up/left/right -j = scroll_vert 20 -k = scroll_vert -20 -h = scroll_horz -20 -l = scroll_horz 20 +j = scroll_vert 20 +k = scroll_vert -20 +h = scroll_horz -20 +l = scroll_horz 20 b = back m = forward s = stop r = refresh R = reload -gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -ZZ = exit +gh = uri http://www.uzbl.org +o _ = uri %s +:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +gg _ = uri http://www.google.com/search?q=%s i = insert_mode B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh u = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh +ZZ = exit [network] proxy_server = #values 0-3 -http_debug = 1 +http_debug = 0 user-agent = uzbl max_conns = max_conns_per_host = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index e9c9cc1..2948ff0 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -21,7 +21,7 @@ show_status = 1 status_top = 0 [bindings] -## scroll down/up/left/right +# scroll down/up/left/right j = scroll_vert 20 k = scroll_vert -20 h = scroll_horz -20 @@ -31,22 +31,21 @@ m = forward s = stop r = refresh R = reload -gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -ZZ = exit +gh = uri http://www.uzbl.org +o _ = uri %s +:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +gg _ = uri http://www.google.com/search?q=%s i = insert_mode B = spawn ./examples/scripts/insert_bookmark.sh u = spawn ./examples/scripts/load_url_from_history.sh U = spawn ./examples/scripts/load_url_from_bookmarks.sh -#parameter command examples (all need space but can be removed from individual commands). underscore is important. -o _ = uri %s -:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -gg _ = uri http://www.google.com/search?q=%s +ZZ = exit [network] # to start a local socks server, do : ssh -fND localhost:8118 localhost -- cgit v1.2.3 From 1825c5b18e7369cf63025ea13ebcf898135bc65b Mon Sep 17 00:00:00 2001 From: dusanx Date: Sun, 3 May 2009 16:58:11 +0200 Subject: Search --- examples/configs/sampleconfig-dev | 1 + uzbl.c | 17 +++++++++++++++++ uzbl.h | 3 +++ 3 files changed, 21 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index e9c9cc1..b486660 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -44,6 +44,7 @@ B = spawn ./examples/scripts/insert_bookmark.sh u = spawn ./examples/scripts/load_url_from_history.sh U = spawn ./examples/scripts/load_url_from_bookmarks.sh #parameter command examples (all need space but can be removed from individual commands). underscore is important. +/_ = search %s o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go gg _ = uri http://www.google.com/search?q=%s diff --git a/uzbl.c b/uzbl.c index ffae493..f8cb48f 100644 --- a/uzbl.c +++ b/uzbl.c @@ -70,6 +70,7 @@ static char fifo_path[64]; static char socket_path[108]; static char executable_path[500]; static GString* keycmd; +static gchar searchtx[500] = "\0"; /* state variables (initial values coming from command line arguments but may be changed later) */ static gchar* uri = NULL; @@ -320,6 +321,7 @@ static struct {char *name; Command command;} cmdlist[] = { "toggle_status", toggle_status_cb }, { "spawn", spawn }, { "exit", close_uzbl }, + { "search", search_text }, { "insert_mode", set_insert_mode } }; @@ -387,6 +389,20 @@ load_uri (WebKitWebView * web_view, const gchar *param) { } } +static void +search_text (WebKitWebView *page, const char *param) { + if ((param) && (param[0] != '\0')) { + printf("\nima param!!!\n"); + strcpy(searchtx, param); + } + if (searchtx[0] != '\0') { + printf ("\n\nsearching: %s\n\n", searchtx); + webkit_web_view_mark_text_matches (page, searchtx, FALSE, 0); + webkit_web_view_set_highlight_text_matches (page, TRUE); + webkit_web_view_search_text (page, searchtx, FALSE, TRUE, TRUE); + } +} + static void new_window_load_uri (const gchar * uri) { GString* to_execute = g_string_new (""); @@ -742,6 +758,7 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) g_string_free (actionparam, TRUE); g_string_free (parampart, TRUE); g_string_truncate(keycmd, 0); + update_title(); } g_string_truncate(short_keys, short_keys->len - 1); diff --git a/uzbl.h b/uzbl.h index d0d6ec7..f9e3053 100644 --- a/uzbl.h +++ b/uzbl.h @@ -116,4 +116,7 @@ add_binding (const gchar *key, const gchar *act); static void settings_init (); +static void +search_text (WebKitWebView *page, const char *param); + /* vi: set et ts=4: */ -- cgit v1.2.3 From 632c220597135962918747d2d4286dfc4f87eb76 Mon Sep 17 00:00:00 2001 From: dusanx Date: Sun, 3 May 2009 17:29:30 +0200 Subject: Latest config-dev --- examples/configs/sampleconfig-dev | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index b486660..bd58519 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -21,7 +21,7 @@ show_status = 1 status_top = 0 [bindings] -## scroll down/up/left/right +# scroll down/up/left/right j = scroll_vert 20 k = scroll_vert -20 h = scroll_horz -20 @@ -31,23 +31,21 @@ m = forward s = stop r = refresh R = reload -gh = uri http://www.uzbl.org f = follow_link_here F = follow_link_new_tab w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -ZZ = exit +gh = uri http://www.uzbl.org +o _ = uri %s +:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +gg _ = uri http://www.google.com/search?q=%s i = insert_mode B = spawn ./examples/scripts/insert_bookmark.sh u = spawn ./examples/scripts/load_url_from_history.sh U = spawn ./examples/scripts/load_url_from_bookmarks.sh -#parameter command examples (all need space but can be removed from individual commands). underscore is important. -/_ = search %s -o _ = uri %s -:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -gg _ = uri http://www.google.com/search?q=%s +ZZ = exit [network] # to start a local socks server, do : ssh -fND localhost:8118 localhost @@ -57,3 +55,4 @@ http_debug = 0 user-agent = uzbl max_conns = max_conns_per_host = + -- cgit v1.2.3 From 37b63dde6f8a0e446bc89858c7857fab3f2aaead Mon Sep 17 00:00:00 2001 From: dusanx Date: Sun, 3 May 2009 17:33:18 +0200 Subject: Merged Dieter branch --- examples/configs/sampleconfig-dev | 1 + 1 file changed, 1 insertion(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index bd58519..8ba580c 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -38,6 +38,7 @@ w = follow_link_new_window - = zoom_out t = toggle_status gh = uri http://www.uzbl.org +/_ = search %s o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go gg _ = uri http://www.google.com/search?q=%s -- cgit v1.2.3 From 6eaf20f58d381c94b4a06046766431eada975204 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 3 May 2009 17:43:39 +0200 Subject: cleanup config files after dusanx search stuff --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 2870cf7..ab44d47 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -37,6 +37,7 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status +/_ = search %s gh = uri http://www.uzbl.org o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 8ba580c..66b66bc 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -37,8 +37,8 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status -gh = uri http://www.uzbl.org /_ = search %s +gh = uri http://www.uzbl.org o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go gg _ = uri http://www.google.com/search?q=%s -- cgit v1.2.3 From 31fe93a77761eefa2de68c1273d825c93d922332 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 3 May 2009 17:46:55 +0200 Subject: better seach configs --- examples/configs/sampleconfig | 3 +++ examples/configs/sampleconfig-dev | 3 +++ 2 files changed, 6 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index ab44d47..6f4d8d9 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -37,7 +37,10 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status +#hilight matches /_ = search %s +#jump to next +; = search gh = uri http://www.uzbl.org o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 66b66bc..7e1e31d 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -37,7 +37,10 @@ w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status +#hilight matches /_ = search %s +#jump to next +; = search gh = uri http://www.uzbl.org o _ = uri %s :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -- cgit v1.2.3 From 01cfcffd7762edd4bed94e91b2013890680765a9 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Sun, 3 May 2009 19:32:49 +0100 Subject: Added command "script" to run javascript on the current page. --- CHECKLIST | 1 + examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 1 + uzbl.c | 7 +++++++ uzbl.h | 3 +++ 5 files changed, 13 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/CHECKLIST b/CHECKLIST index 9a9bfbf..66f7bf6 100644 --- a/CHECKLIST +++ b/CHECKLIST @@ -34,3 +34,4 @@ Also testers and interested people can use this list to see what uzbl is about, * searching: /_ = search %s <-- hilight all ; = search <-- jump over all hits +* run javascript on curent page through "script" command. \ No newline at end of file diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 6f4d8d9..e4fd3a6 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -50,7 +50,7 @@ B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh u = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh ZZ = exit - +S = script alert("hi"); [network] proxy_server = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 7e1e31d..7ce220f 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -50,6 +50,7 @@ B = spawn ./examples/scripts/insert_bookmark.sh u = spawn ./examples/scripts/load_url_from_history.sh U = spawn ./examples/scripts/load_url_from_bookmarks.sh ZZ = exit +S = script alert("hi"); [network] # to start a local socks server, do : ssh -fND localhost:8118 localhost diff --git a/uzbl.c b/uzbl.c index 2f24b56..edd0b38 100644 --- a/uzbl.c +++ b/uzbl.c @@ -303,6 +303,7 @@ static struct {char *name; Command command;} cmdlist[] = { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). { "zoom_out", view_zoom_out, }, { "uri", load_uri }, + { "script", run_js }, { "toggle_status", toggle_status_cb }, { "spawn", spawn }, { "exit", close_uzbl }, @@ -374,6 +375,12 @@ load_uri (WebKitWebView * web_view, const gchar *param) { } } +static void +run_js (WebKitWebView * web_view, const gchar *param) { + if (param) + webkit_web_view_execute_script (web_view, param); +} + static void search_text (WebKitWebView *page, const char *param) { if ((param) && (param[0] != '\0')) { diff --git a/uzbl.h b/uzbl.h index f9e3053..f81e3f6 100644 --- a/uzbl.h +++ b/uzbl.h @@ -119,4 +119,7 @@ settings_init (); static void search_text (WebKitWebView *page, const char *param); +static void +run_js (WebKitWebView * web_view, const gchar *param); + /* vi: set et ts=4: */ -- cgit v1.2.3 From b6a39ed3eba72d2c3fea3ae9ed28ff7510a05e1f Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Sun, 3 May 2009 23:13:34 +0100 Subject: Added hacky variable suppot (currently "%webkit-major%", "%webkit-minor%" and "%webkit-micro%", alas no "%kernver%" or "%commit%" yet) to user agent. I'm tired and it's late. I've probably done this in a very poor way which would be infinitely better. Now I am going to go and sleep. When I wake up and come on IRC, tell me how bad the code is :P --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index e4fd3a6..4fcdead 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -56,6 +56,6 @@ S = script alert("hi"); proxy_server = #values 0-3 http_debug = 0 -user-agent = uzbl +user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) max_conns = max_conns_per_host = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 7ce220f..9c4664e 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -57,7 +57,7 @@ S = script alert("hi"); #proxy_server = http://127.0.0.1:8118 #values 0-3 http_debug = 0 -user-agent = uzbl +user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) max_conns = max_conns_per_host = diff --git a/uzbl.c b/uzbl.c index af414ed..8e25903 100644 --- a/uzbl.c +++ b/uzbl.c @@ -134,20 +134,20 @@ itos(int val) { static char * str_replace (const char* search, const char* replace, const char* string) { - char newstring[512]; - char tempstring[512]; + char newstring[1024]; + char tempstring[1024]; unsigned int i = 0; memset (newstring, 0, sizeof (newstring)); for (i = 0; i < strlen (string) - strlen (search); i ++) { memset (tempstring, 0, sizeof (tempstring)); - strncpy (tempstring, string + i, sizeof (search) + 1); + strncpy (tempstring, string + i, strlen (search)); if (strcmp (tempstring, search) == 0) { strncpy (newstring, string, i); strcat (newstring, replace); - strcat (newstring, string + i + sizeof (search) + 1); + strcat (newstring, string + i + strlen (search)); } } @@ -981,6 +981,14 @@ settings_init () { } if(useragent){ + char* newagent = malloc(1024); + + strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), useragent)); + strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent)); + strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent)); + + useragent = malloc(1024); + strcpy(useragent, newagent); g_object_set(G_OBJECT(soup_session), SOUP_SESSION_USER_AGENT, useragent, NULL); } -- cgit v1.2.3 From d3dc638149202de26529abd97b39c1a287f72a54 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Mon, 4 May 2009 10:39:06 +0100 Subject: Now supports all values uname() can grab in the user agent. See sampleconfig for all variables. --- CHECKLIST | 3 ++- Makefile | 2 +- examples/configs/sampleconfig | 2 ++ examples/configs/sampleconfig-dev | 2 ++ uzbl.c | 22 ++++++++++++++++++++-- 5 files changed, 27 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/CHECKLIST b/CHECKLIST index 66f7bf6..292f9ab 100644 --- a/CHECKLIST +++ b/CHECKLIST @@ -34,4 +34,5 @@ Also testers and interested people can use this list to see what uzbl is about, * searching: /_ = search %s <-- hilight all ; = search <-- jump over all hits -* run javascript on curent page through "script" command. \ No newline at end of file +* run javascript on curent page through "script" command. +* variable replacement in user agent. \ No newline at end of file diff --git a/Makefile b/Makefile index 906436f..622a79a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CPPFLAGS=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -Wall -W -DKERNVER="\"$(shell uname -r)\"" -DARCH="\"$(shell uname -m)\"" -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" +CPPFLAGS=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) -Wall -W -DARCH="\"$(shell uname -m)\"" -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" LDFLAGS=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) all: uzbl uzblctrl diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 4fcdead..ef3f0a8 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -57,5 +57,7 @@ proxy_server = #values 0-3 http_debug = 0 user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +# Example user agent containing everything: +#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) max_conns = max_conns_per_host = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9c4664e..443dbb0 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -58,6 +58,8 @@ S = script alert("hi"); #values 0-3 http_debug = 0 user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +# Example user agent containing everything: +#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) max_conns = max_conns_per_host = diff --git a/uzbl.c b/uzbl.c index ae7c755..39417cf 100644 --- a/uzbl.c +++ b/uzbl.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -92,6 +93,9 @@ static gchar* modkey = NULL; static guint modmask = 0; static guint http_debug = 0; +/* System info */ +static struct utsname unameinfo; + /* settings from config: group bindings, key -> action */ static GHashTable* bindings; @@ -971,8 +975,22 @@ settings_init () { strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), useragent)); strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent)); strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent)); - strcpy(newagent, str_replace("%kernver%", KERNVER, newagent)); - strcpy(newagent, str_replace("%arch%", ARCH, newagent)); + + if (uname (&unameinfo) == -1) { + printf("Error getting uname info. Not replacing system-related user agent variables.\n"); + } else { + strcpy(newagent, str_replace("%sysname%", unameinfo.sysname, newagent)); + strcpy(newagent, str_replace("%nodename%", unameinfo.nodename, newagent)); + strcpy(newagent, str_replace("%kernrel%", unameinfo.release, newagent)); + strcpy(newagent, str_replace("%kernver%", unameinfo.version, newagent)); + strcpy(newagent, str_replace("%arch-system%", unameinfo.machine, newagent)); + + #ifdef _GNU_SOURCE + strcpy(newagent, str_replace("%domainname%", unameinfo.domainname, newagent)); + #endif + } + + strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent)); strcpy(newagent, str_replace("%commit%", COMMIT, newagent)); useragent = malloc(1024); -- cgit v1.2.3 From f6c8d8a2a226f3d256f8b2d53ed84897862208a6 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Mon, 4 May 2009 10:45:56 +0100 Subject: Added %commit% variable to sample config files, as I forgot to do it just now :p --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 5c8226d..9ef069c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -58,6 +58,6 @@ proxy_server = http_debug = 0 user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) # Example user agent containing everything: -#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) +#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) max_conns = max_conns_per_host = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 8749fe8..580234e 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -59,7 +59,7 @@ S = script alert("hi"); http_debug = 0 user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) # Example user agent containing everything: -#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) +#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) max_conns = max_conns_per_host = -- cgit v1.2.3 From da643e8b7f0de88fa6ee2e7f1181746cda57a8ff Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 19:59:33 +0200 Subject: move datafiles into own dir --- TODO | 10 +++++++++- examples/bookmarks | 4 ---- examples/data/bookmarks | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) delete mode 100644 examples/bookmarks create mode 100644 examples/data/bookmarks (limited to 'examples') diff --git a/TODO b/TODO index f44308b..73a8f21 100644 --- a/TODO +++ b/TODO @@ -32,9 +32,17 @@ * backspace key to pop characters from (multichar) command * optional logging of http requests&responses with ip/hostname and port. -> how to implement? handler? stdout? (through a socket so you know what corresponds to what?) * bench/optimize fifo vs socket performance. measure delays. minimize forks. does glib use a shell? how does it detect the shebang line? -* cookie support. how do we store and control usage? +* cookie support. * "remember account settings" support. but how? configure post data per site? regex match eg '^bbs.archlinux.org' ? * http_proxy env var not recognized. libproxy (used by libsoup) should handle this http://mail.gnome.org/archives/libsoup-list/2009-February/msg00018.html +* support ssl. do ssl certificate & exception management similar to how we do cookies +* improve DCOMMIT macro. what if WC is dirty? what if user downloaded tarball without .git? +* DARCH is not correct (should be at runtime) + +* variable replacing: +user agent -> str_replace(all vars) DONE +title bar -> str_replace(all vars) +status bar -> str_replace(all vars) -> pango markup thingie SOMEDAY: check if we can make the settings loading less hard coded. eg( keep a list of all settings, and for each one, try to load it) diff --git a/examples/bookmarks b/examples/bookmarks deleted file mode 100644 index 13fcd48..0000000 --- a/examples/bookmarks +++ /dev/null @@ -1,4 +0,0 @@ -http://www.archlinux.org linux arch -http://www.uzbl.org uzbl browser -http://dieter.plaetinck.be uzbl -http://www.icanhascheezburger.com lolcats fun diff --git a/examples/data/bookmarks b/examples/data/bookmarks new file mode 100644 index 0000000..13fcd48 --- /dev/null +++ b/examples/data/bookmarks @@ -0,0 +1,4 @@ +http://www.archlinux.org linux arch +http://www.uzbl.org uzbl browser +http://dieter.plaetinck.be uzbl +http://www.icanhascheezburger.com lolcats fun -- cgit v1.2.3 From 8776679111e15ae5522d42a5f92993a57d71832c Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 20:04:05 +0200 Subject: bookmarks location update + slight fixes re INSTALL file --- INSTALL | 50 +++++++++++++++++++++++++++++ INSTALLING | 50 ----------------------------- examples/scripts/insert_bookmark.sh | 4 +-- examples/scripts/load_url_from_bookmarks.sh | 4 +-- 4 files changed, 54 insertions(+), 54 deletions(-) create mode 100644 INSTALL delete mode 100644 INSTALLING (limited to 'examples') diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..decf316 --- /dev/null +++ b/INSTALL @@ -0,0 +1,50 @@ +Arch Linux +---------- +[Arch Linux](http://www.archlinux.org) is our distro of choice, and the distro we use for testing. + +You can find a [PKGBUILD](http://aur.archlinux.org/packages.php?ID=25972) on the AUR, which installs the latest +from the master branch. You can edit the PKGBUILD to change to any other +branch you want. + +From source +----------- + $ git clone git://github.com/Dieterbe/uzbl.git + [ $ git checkout master/experimental ] # master == fairly stable. experimental is more bleeding edge + $ cd uzbl + $ make + $ sudo make install + +Dependencies +------------ +* git (for downloading) +* pkgconfig (for Make/gcc) +* libwebkit 1.1.4 or higher +* libsoup 2.24 or higher (dep for webkit/gtk+) +* gtk 2 something something + +Optional/Recommended +-------------------- +The following tools are quite useful, and some of them are used in the +sample scripts: + +* dmenu +* zenity +* bash + +File locations +-------------- +After installing - using either method - you will find: + +* /usr/bin : uzbl [and uzblctrl] +* /usr/share/uzbl/docs/ : documentation files included with uzbl. (readme, checklist, .. ) +* /usr/share/uzbl/examples: sample scripts, config files and a sample data (boomarks, .. ) + +You will probably want to change the scripts to behave more like you want, so copy the scripts to your home dir. If you save your config as +$XDG\_CONFIG\_HOME/uzbl/config (this expands to ~/.config/uzbl/config on most systems) it will be recognized automatically. You can also pass the path to +the config file with the --config parameter. + +You're free to store your personal stuff where you want, but we think the [XDG basedir spec](http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html) +is very useful for keeping a clean home directory, so we recommend: + +* $XDG\_CONFIG\_HOME/uzbl/config* (~/.config/uzbl/config on most systems): config file +* $XDG\_DATA\_HOME/uzbl (~/.local/share/uzbl on most systems): bookmarks file, history file. and "scripts" directory with scripts \ No newline at end of file diff --git a/INSTALLING b/INSTALLING deleted file mode 100644 index e95f7a4..0000000 --- a/INSTALLING +++ /dev/null @@ -1,50 +0,0 @@ -Arch Linux ----------- -[Arch Linux](http://www.archlinux.org) is our distro of choice, and the distro we use for testing. - -You can find a [PKGBUILD](http://aur.archlinux.org/packages.php?ID=25972) on the AUR, which installs the latest -from the master branch. You can edit the PKGBUILD to change to any other -branch you want. - -From source ------------ - $ git clone git://github.com/Dieterbe/uzbl.git - [ $ git checkout master/experimental ] # master == fairly stable. experimental is more bleeding edge - $ cd uzbl - $ make - $ sudo make install - -Dependencies ------------- -* git (for building) -* pkgconfig (for Make/gcc) -* libwebkit 1.1.4 or higher -* libsoup 2.24 or higher (dep for webkit/gtk+) -* gtk 2 something something - -Optional/Recommended --------------------- -The following tools are quite useful, and some of them are used in the -sample scripts: - -* dmenu -* zenity -* bash - -File locations --------------- -After installing - using either method - you will find: - -* /usr/bin : uzbl [and uzblctrl] -* /usr/share/uzbl/docs/ : documentation files included with uzbl. (readme, checklist,..) -* /usr/share/uzbl/examples: sample scripts, config files and a sample bookmarks file. - -You will probably want to change the scripts to behave more like you want, so copy the scripts to your home dir. If you save your config as -$XDG\_CONFIG\_HOME/uzbl/config (this expands to ~/.config/uzbl/config on most systems) it will be recognized automatically. You can also pass the path to -the config file with the --config parameter. - -You're free to store your personal stuff where you want, but we think the [XDG basedir spec](http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html) -is very useful for keeping a clean home directory, so we recommend: - -* $XDG\_CONFIG\_HOME/uzbl/config* (~/.config/uzbl/config on most systems): config file -* $XDG\_DATA\_HOME/uzbl (~/.local/share/uzbl on most systems): bookmarks file, history file. and "scripts" directory with scripts \ No newline at end of file diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh index 5d76c35..98de4b0 100755 --- a/examples/scripts/insert_bookmark.sh +++ b/examples/scripts/insert_bookmark.sh @@ -1,9 +1,9 @@ #!/bin/bash # you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) -if [ -f /usr/share/uzbl/examples/bookmarks ] +if [ -f /usr/share/uzbl/examples/data/bookmarks ] then - file=/usr/share/uzbl/examples/bookmarks # you will probably get permission denied errors here. pick a file in your ~ + file=/usr/share/uzbl/examples/data/bookmarks # you will probably get permission denied errors here. pick a file in your ~ else file=./examples/bookmarks #useful when developing fi diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 2a893bf..f8e2b53 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -1,9 +1,9 @@ #!/bin/bash # you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) -if [ -f /usr/share/uzbl/examples/bookmarks ] +if [ -f /usr/share/uzbl/examples/data/bookmarks ] then - file=/usr/share/uzbl/examples/bookmarks + file=/usr/share/uzbl/examples/data/bookmarks else file=./examples/bookmarks #useful when developing fi -- cgit v1.2.3 From 1df72478dc583a4457821f020683616e08bbc0d9 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 20:18:08 +0200 Subject: bookmarks file location fix --- examples/scripts/insert_bookmark.sh | 2 +- examples/scripts/load_url_from_bookmarks.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh index 98de4b0..fe18328 100755 --- a/examples/scripts/insert_bookmark.sh +++ b/examples/scripts/insert_bookmark.sh @@ -5,7 +5,7 @@ if [ -f /usr/share/uzbl/examples/data/bookmarks ] then file=/usr/share/uzbl/examples/data/bookmarks # you will probably get permission denied errors here. pick a file in your ~ else - file=./examples/bookmarks #useful when developing + file=./examples/data/bookmarks #useful when developing fi which zenity &>/dev/null || exit 2 diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index f8e2b53..35c772c 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -5,7 +5,7 @@ if [ -f /usr/share/uzbl/examples/data/bookmarks ] then file=/usr/share/uzbl/examples/data/bookmarks else - file=./examples/bookmarks #useful when developing + file=./examples/data/bookmarks #useful when developing fi goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -- cgit v1.2.3 From 1ba4dfe07bce046854c4d9b29403aea7b0cc3c40 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 21:28:00 +0200 Subject: sample cookie handler and config file --- README | 2 ++ examples/configs/cookies | 22 ++++++++++++++++ examples/scripts/cookies.sh | 62 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 examples/configs/cookies create mode 100755 examples/scripts/cookies.sh (limited to 'examples') diff --git a/README b/README index 2087b2a..ad57566 100644 --- a/README +++ b/README @@ -117,6 +117,8 @@ The script specific arguments are this: none * download: $8 url of item to download +* cookie handler + $8 GET/PUT KNOWN BUGS - Segfaults when using zoom commands (happens when max zoom already reached?). diff --git a/examples/configs/cookies b/examples/configs/cookies new file mode 100644 index 0000000..9b7374a --- /dev/null +++ b/examples/configs/cookies @@ -0,0 +1,22 @@ +# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script. +# stick to this format. +# trusted -> always store what we get, send what we have (TODO: by default, or when requested?) +# deny -> deny storing + sending + +# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind... + + +TRUSTED +bbs.archlinux.org +archlinux.org +linux.com + + + + +DENY +www.icanhascheezburger.com + + + +# rest -> ask \ No newline at end of file diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh new file mode 100755 index 0000000..69b786f --- /dev/null +++ b/examples/scripts/cookies.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# this is an example script of how you could manage your cookies.. +# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) + +# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( +# TODO: different cookie paths per config (eg per group of uzbl instances) + +if [ -f /usr/share/uzbl/examples/configs/cookies ] +then + file=/usr/share/uzbl/examples/configs/cookies +else + file=./examples/configs/cookies #useful when developing +fi + +if [ -d $XDG_DATA_HOME/uzbl/cookies ] +then + cookie_dir=$XDG_DATA_HOME/uzbl/cookies +else + cookie_dir=./examples/data +fi + +which zenity &>/dev/null || exit 2 + +uri=$6 +action=$8 # GET/PUT +host=${uri/\/*/} + + + +# $1 = section (TRUSTED or DENY) +# $2 =url +function match () { + sed -n "/$1/,/^\$/p" $file 2>/dev/null | grep -q "^$host" +} + +function readcookie () { + cookie= + while read + do + cookie="$REPLY +" + done +} + +function fetch_cookie () { + cookie=`cat $cookie_dir/$host.cookie` +} + +function store_cookie () { + echo $cookie > $cookie_dir/$host.cookie +} + +if match TRUSTED $host +then + [ $action == PUT ] && readcookie && store_cookie $host + [ $action == GET ] && fetch_cookie && echo "$cookie" +elif ! match DENY $host +then + [ $action == PUT ] && readcookie && zenity --question --title 'Uzbl Cookie handler' --text "Accept cookie from $host ? Contents:\n$cookie" && store_cookie $host + [ $action == GET ] && fetch_cookie && zenity --question --title 'Uzbl Cookie handler' --text "Submit cookie to $host ? Contents:\n$cookie" && echo $cookie +fi +exit 0 -- cgit v1.2.3 From b8de166f5afac15635b98b66b45ce8dfc2d85582 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 21:29:32 +0200 Subject: enable cookie handler in configs --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 1 + 2 files changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 9ef069c..0606fd7 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -13,6 +13,7 @@ [behavior] history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh +cookie_handler = /usr/share/uzbl/examples/scripts/cookie.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 580234e..fee0abd 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,6 +13,7 @@ [behavior] history_handler = ./examples/scripts/history.sh download_handler = ./examples/scripts/download.sh +cookie_handler = ./examples/scripts/history.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 -- cgit v1.2.3 From 3338b740dd23d3e88fc1722b56c5b8fda187b627 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 4 May 2009 21:41:39 +0200 Subject: correct cookie handler script --- examples/configs/sampleconfig-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index fee0abd..0cb0699 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,7 +13,7 @@ [behavior] history_handler = ./examples/scripts/history.sh download_handler = ./examples/scripts/download.sh -cookie_handler = ./examples/scripts/history.sh +cookie_handler = ./examples/scripts/cookie.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 -- cgit v1.2.3 From 53ec9eb51cfc3b88fc2c1c7678d106040a65250d Mon Sep 17 00:00:00 2001 From: Jan Kolkmeier Date: Tue, 5 May 2009 23:02:08 +0200 Subject: basic linkfollowing --- examples/configs/sampleconfig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 0606fd7..a5c8611 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -32,9 +32,12 @@ m = forward s = stop r = reload R = reload_ign_cache -f = follow_link_here -F = follow_link_new_tab -w = follow_link_new_window +#Link Following preview... +#These scripts are going to be outsourced in future. +#Hit F to toggle the Hints (now in form of link numbering) +F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +#then type f, followed by the link number and RETURN to follow that link +f_ = script window.location = document.links[%s].href + = zoom_in - = zoom_out t = toggle_status -- cgit v1.2.3 From ffe28435ff741bce2856132d2d3168e659e1a44c Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 5 May 2009 23:13:07 +0200 Subject: link following from Jan Kolkmeier (jouz) --- AUTHORS | 2 +- CHECKLIST | 3 ++- examples/configs/sampleconfig | 9 ++++++--- examples/configs/sampleconfig-dev | 8 +++++--- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index fd0ec3e..ff39641 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,7 +9,7 @@ Contributors: Robert Manea - Various improvements Zane Ashby (HashBox) - Rewrote FIFO interface. Fixed various bugs. (sentientswitch) - Cleaned up code. Added some commands. - Jan Kolkmeier (jouz) - scrolling + Jan Kolkmeier (jouz) - scrolling, link following Evgeny Grablyk - libsoup settings Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c diff --git a/CHECKLIST b/CHECKLIST index 292f9ab..2ea1a74 100644 --- a/CHECKLIST +++ b/CHECKLIST @@ -35,4 +35,5 @@ Also testers and interested people can use this list to see what uzbl is about, /_ = search %s <-- hilight all ; = search <-- jump over all hits * run javascript on curent page through "script" command. -* variable replacement in user agent. \ No newline at end of file +* variable replacement in user agent. +* basic keyboard link hilighting (numbering) and following. will be improved more diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 0606fd7..f1c36e5 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -32,9 +32,6 @@ m = forward s = stop r = reload R = reload_ign_cache -f = follow_link_here -F = follow_link_new_tab -w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status @@ -53,6 +50,12 @@ U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh ZZ = exit S = script alert("hi"); +# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... +#hit f followed by linknumber and ENTER to follow that link +f_ = script window.location = document.links[%s].href; +#hit F to show the link numbers +F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} + [network] proxy_server = #values 0-3 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 0cb0699..e77ab7f 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -32,9 +32,6 @@ m = forward s = stop r = reload R = reload_ign_cache -f = follow_link_here -F = follow_link_new_tab -w = follow_link_new_window + = zoom_in - = zoom_out t = toggle_status @@ -53,6 +50,11 @@ U = spawn ./examples/scripts/load_url_from_bookmarks.sh ZZ = exit S = script alert("hi"); +# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... +#hit f followed by linknumber and ENTER to follow that link +f_ = script window.location = document.links[%s].href; +#hit F to show the link numbers +F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} [network] # to start a local socks server, do : ssh -fND localhost:8118 localhost #proxy_server = http://127.0.0.1:8118 -- cgit v1.2.3 From 130ce69dd0dda878f9186f98ab8a3e7f0f13b5a2 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 6 May 2009 22:41:14 +0200 Subject: storing cookies now works with handler --- README | 1 + TODO | 4 ++-- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- examples/scripts/cookies.sh | 27 +++++++++++++++------------ 5 files changed, 20 insertions(+), 16 deletions(-) (limited to 'examples') diff --git a/README b/README index ad57566..104a958 100644 --- a/README +++ b/README @@ -119,6 +119,7 @@ The script specific arguments are this: $8 url of item to download * cookie handler $8 GET/PUT + $9 cookie (only with PUT requests) KNOWN BUGS - Segfaults when using zoom commands (happens when max zoom already reached?). diff --git a/TODO b/TODO index 73a8f21..642aa5a 100644 --- a/TODO +++ b/TODO @@ -32,13 +32,13 @@ * backspace key to pop characters from (multichar) command * optional logging of http requests&responses with ip/hostname and port. -> how to implement? handler? stdout? (through a socket so you know what corresponds to what?) * bench/optimize fifo vs socket performance. measure delays. minimize forks. does glib use a shell? how does it detect the shebang line? -* cookie support. +* cookie support. storing seems to work, but not yet sending * "remember account settings" support. but how? configure post data per site? regex match eg '^bbs.archlinux.org' ? * http_proxy env var not recognized. libproxy (used by libsoup) should handle this http://mail.gnome.org/archives/libsoup-list/2009-February/msg00018.html * support ssl. do ssl certificate & exception management similar to how we do cookies * improve DCOMMIT macro. what if WC is dirty? what if user downloaded tarball without .git? * DARCH is not correct (should be at runtime) - +* when loading page foo.com, it can have img src=http://bar/..., uri in uzbl will be set to foo. we must pass bar to cookie handler * variable replacing: user agent -> str_replace(all vars) DONE title bar -> str_replace(all vars) diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 3a46142..4342389 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -13,7 +13,7 @@ [behavior] history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh -cookie_handler = /usr/share/uzbl/examples/scripts/cookie.sh +cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index b602c52..9ac8393 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,7 +13,7 @@ [behavior] history_handler = ./examples/scripts/history.sh download_handler = ./examples/scripts/download.sh -cookie_handler = ./examples/scripts/cookie.sh +cookie_handler = ./examples/scripts/cookies.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index 69b786f..55498a1 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -5,6 +5,16 @@ # MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( # TODO: different cookie paths per config (eg per group of uzbl instances) +# TODO: correct implementation. +# see http://curl.haxx.se/rfc/cookie_spec.html +# http://en.wikipedia.org/wiki/HTTP_cookie + +# TODO : check expires= before sending. +# write sample script that cleans up cookies dir based on expires attribute. +# TODO: check uri against domain attribute. and path also. +# implement secure attribute. + + if [ -f /usr/share/uzbl/examples/configs/cookies ] then file=/usr/share/uzbl/examples/configs/cookies @@ -22,7 +32,9 @@ fi which zenity &>/dev/null || exit 2 uri=$6 +uri=${uri/http:\/\/} # strip 'http://' part action=$8 # GET/PUT +cookie=$9 host=${uri/\/*/} @@ -33,15 +45,6 @@ function match () { sed -n "/$1/,/^\$/p" $file 2>/dev/null | grep -q "^$host" } -function readcookie () { - cookie= - while read - do - cookie="$REPLY -" - done -} - function fetch_cookie () { cookie=`cat $cookie_dir/$host.cookie` } @@ -52,11 +55,11 @@ function store_cookie () { if match TRUSTED $host then - [ $action == PUT ] && readcookie && store_cookie $host + [ $action == PUT ] && store_cookie $host [ $action == GET ] && fetch_cookie && echo "$cookie" elif ! match DENY $host then - [ $action == PUT ] && readcookie && zenity --question --title 'Uzbl Cookie handler' --text "Accept cookie from $host ? Contents:\n$cookie" && store_cookie $host - [ $action == GET ] && fetch_cookie && zenity --question --title 'Uzbl Cookie handler' --text "Submit cookie to $host ? Contents:\n$cookie" && echo $cookie + [ $action == PUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host + [ $action == GET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie fi exit 0 -- cgit v1.2.3 From 26d1fd8f8d2efdef5d3563a240852e54356e7dc1 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Thu, 7 May 2009 13:49:48 +0200 Subject: added status_format option to sampleconfig-dev file --- examples/configs/sampleconfig-dev | 1 + uzbl.c | 20 +++++++------------- uzbl.h | 1 + 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9ac8393..85b45b5 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,6 +20,7 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] [bindings] # scroll down/up/left/right diff --git a/uzbl.c b/uzbl.c index def7bc0..f2f176b 100644 --- a/uzbl.c +++ b/uzbl.c @@ -55,17 +55,6 @@ #include "uzbl.h" -/* status bar format - TODO: integrate with the config file -*/ -char *status_format = - " MODE " - " | Cmd: KEYCMD" - " | TITLE " - " | LOAD_PROGRESS% LOAD_PROGRESSBAR" - " | URI" - " | NAME | Uzbl browser "; - static Uzbl uzbl; @@ -503,7 +492,7 @@ parse_status_template(const char *template) { break; case SYM_NAME: g_string_append(ret, - uzbl.state.instance_name?uzbl.state.instance_name:""); + uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin)); break; case SYM_KEYCMD: g_string_append(ret, @@ -807,7 +796,7 @@ update_title (void) { if (b->show_status) { gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short); - statln = parse_status_template(status_format); + statln = parse_status_template(uzbl.behave.status_format); gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln); g_free(statln); } else { @@ -1038,6 +1027,7 @@ settings_init () { b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); + b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); if (! b->fifo_dir) b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); if (! b->socket_dir) @@ -1054,6 +1044,7 @@ settings_init () { printf ("Show status: %s\n", (b->show_status ? "TRUE" : "FALSE")); printf ("Status top: %s\n", (b->status_top ? "TRUE" : "FALSE")); printf ("Modkey: %s\n", (b->modkey ? b->modkey : "disabled")); + printf ("Status format: %s\n", (b->status_format ? b->status_format : "none")); if (!b->modkey) b->modkey = ""; @@ -1250,6 +1241,9 @@ main (int argc, char* argv[]) { if (!uzbl.behave.show_status) gtk_widget_hide(uzbl.gui.mainbar); + if (!uzbl.behave.status_format) + uzbl.behave.status_format = ""; + setup_scanner(); if (uzbl.behave.fifo_dir) diff --git a/uzbl.h b/uzbl.h index 13525d7..2fbd020 100644 --- a/uzbl.h +++ b/uzbl.h @@ -85,6 +85,7 @@ typedef struct { /* behaviour */ typedef struct { + gchar *status_format; gchar* history_handler; gchar* fifo_dir; gchar* socket_dir; -- cgit v1.2.3 From 28f3992dee59aa53f86c3909cb2cb6ddf7613bb4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 7 May 2009 20:22:27 +0200 Subject: cookie doc --- examples/scripts/cookies.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index 55498a1..02fb471 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -13,7 +13,8 @@ # write sample script that cleans up cookies dir based on expires attribute. # TODO: check uri against domain attribute. and path also. # implement secure attribute. - +# support blocking or not for 3rd parties +# http://kb.mozillazine.org/Cookies.txt if [ -f /usr/share/uzbl/examples/configs/cookies ] then -- cgit v1.2.3 From 1a9bc2950b4235276c25ce9ec4f5a6d2e8cc9ac0 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 7 May 2009 22:23:55 +0200 Subject: cookie support: correct invocations of script, various fixes. almost a basic working version --- README | 4 ++- examples/scripts/cookies.sh | 71 ++++++++++++++++++++++++++++++++++++++------- uzbl.c | 32 +++++++++++--------- 3 files changed, 81 insertions(+), 26 deletions(-) (limited to 'examples') diff --git a/README b/README index 8a2c48f..a16638d 100644 --- a/README +++ b/README @@ -118,7 +118,9 @@ The script specific arguments are this: $8 url of item to download * cookie handler $8 GET/PUT - $9 cookie (only with PUT requests) + $9 request address host (if current page url is www.foo.com/somepage, this could be something else then foo, eg advertising from another host) + $10 request address path + $11 cookie (only with PUT requests) KNOWN BUGS - Segfaults when using zoom commands (happens when max zoom already reached?). diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index 02fb471..9f6d202 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -1,5 +1,9 @@ #!/bin/bash # this is an example script of how you could manage your cookies.. +# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) +# This is one textfile with entries like this: +# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 +# domain alow-read-other-subdomains path http-required expiration name value # you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) # MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( @@ -23,23 +27,68 @@ else file=./examples/configs/cookies #useful when developing fi -if [ -d $XDG_DATA_HOME/uzbl/cookies ] -then - cookie_dir=$XDG_DATA_HOME/uzbl/cookies -else - cookie_dir=./examples/data -fi +#cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt +cookie_file=./examples/data/cookies.txt which zenity &>/dev/null || exit 2 -uri=$6 -uri=${uri/http:\/\/} # strip 'http://' part +# Example cookie: +# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net + +# uri=$6 +# uri=${uri/http:\/\/} # strip 'http://' part +# host=${uri/\/*/} action=$8 # GET/PUT +host=$9 +shift +path=$9 +shift cookie=$9 -host=${uri/\/*/} +field_domain=$host +field_path=$path +field_name= +field_value= +field_exp='end_session' + + +# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET +function parse_cookie () { + IFS=$';' + first_pair=1 + for pair in $cookie + do + if [ "$first_pair" == 1 ] + then + field_name=${i%%=*} + field_value=${i#*=} + first_pair=0 + else + read -r pair <<< "$pair" #strip leading/trailing wite space + key=${i%%=*} + val=${i#*=} + [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` + # TODO: domain + [ "$key" == path ] && field_path=$val + fi + done + unset IFS +} + +# match cookies in cookies.txt againsh hostname and path +function get_cookie () { + path_esc=${path//\//\\/} + cookie=`awk "/^[^\t]*$host\t[^\t]*\t$path_esc/" cookie_file 2>/dev/null | tail -n 1` + [ -n "$cookie" ] +} + +[ $action == PUT ] && parse_cookie && echo -e "$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" >> $cookie_file +[ $action == GET ] && get_cookie && echo "$cookie" + +exit +# TODO: implement this later. # $1 = section (TRUSTED or DENY) # $2 =url function match () { @@ -47,11 +96,11 @@ function match () { } function fetch_cookie () { - cookie=`cat $cookie_dir/$host.cookie` + cookie=`cat $cookie_file/$host.cookie` } function store_cookie () { - echo $cookie > $cookie_dir/$host.cookie + echo $cookie > $cookie_file/$host.cookie } if match TRUSTED $host diff --git a/uzbl.c b/uzbl.c index 66498f6..db23821 100644 --- a/uzbl.c +++ b/uzbl.c @@ -1058,17 +1058,17 @@ settings_init () { if (res) { b->history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); b->download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); - b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL); + b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL); b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); - b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); + b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); if (! b->fifo_dir) b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); if (! b->socket_dir) b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); - keys = g_key_file_get_keys (config, "bindings", NULL, NULL); + keys = g_key_file_get_keys (config, "bindings", NULL, NULL); } printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled")); @@ -1195,26 +1195,30 @@ settings_init () { static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ (void) session; (void) user_data; + gchar * stdout = NULL; soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); - - /* ask handler for cookies, if there are any, use - soup_message_headers_replace (msg->request_headers, - "Cookie", cookies); - to add them - */ + GString* args = g_string_new (""); + SoupURI * soup_uri = soup_message_get_uri(msg); + g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path); + run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout); + if(stdout) { + soup_message_headers_replace (msg->request_headers, "Cookie", stdout); + } + g_string_free(args, TRUE); } static void save_cookies (SoupMessage *msg, gpointer user_data){ (void) user_data; GSList *ck; - char *req, *cookie; + char *cookie; for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ cookie = soup_cookie_to_set_cookie_header(ck->data); - req = malloc(strlen(cookie) + 10); - sprintf(req, "PUT \"%s\"", cookie); - run_command_async(uzbl.behave.cookie_handler, req); - free(req); + GString* args = g_string_new (""); + SoupURI * soup_uri = soup_message_get_uri(msg); + g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie); + run_command_async(uzbl.behave.cookie_handler, args->str); + g_string_free(args, TRUE); free(cookie); } g_slist_free(ck); -- cgit v1.2.3 From 1c9ca71b1751a187ec79a29a648988032919e097 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Fri, 8 May 2009 18:27:28 +0200 Subject: made statusbar selectable, fix bug in parse status to not ignore # chars --- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 85b45b5..6bd458e 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,7 +20,7 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] [bindings] # scroll down/up/left/right diff --git a/uzbl.c b/uzbl.c index b4a5052..ff3ffa0 100644 --- a/uzbl.c +++ b/uzbl.c @@ -445,7 +445,7 @@ setup_scanner() { ) /* cset_skip_characters */, ( G_CSET_a_2_z - "_" + "_#" G_CSET_A_2_Z ) /* cset_identifier_first */, ( @@ -455,7 +455,7 @@ setup_scanner() { G_CSET_LATINS G_CSET_LATINC ) /* cset_identifier_nth */, - ( "#\n" ) /* cpair_comment_single */, + ( "" ) /* cpair_comment_single */, TRUE /* case_sensitive */, @@ -511,7 +511,8 @@ parse_status_template(const char *template) { switch(sym) { case SYM_URI: g_string_append(ret, - g_markup_printf_escaped("%s", uzbl.state.uri)); + uzbl.state.uri? + g_markup_printf_escaped("%s", uzbl.state.uri):""); break; case SYM_LOADPRGS: g_string_append(ret, itos(uzbl.gui.sbar.load_progress)); @@ -965,6 +966,7 @@ create_mainbar () { g->mainbar = gtk_hbox_new (FALSE, 0); g->mainbar_label = gtk_label_new (""); + gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE); gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END); gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0); gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2); @@ -1280,7 +1282,7 @@ main (int argc, char* argv[]) { setup_scanner(); if (!uzbl.behave.status_format) - uzbl.behave.status_format = STATUS_DEFAULT; + uzbl.behave.status_format = STATUS_DEFAULT; if (!uzbl.behave.show_status) gtk_widget_hide(uzbl.gui.mainbar); else -- cgit v1.2.3 From 3900127bbed6f1e99e279466a363a6f89803fdd5 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 8 May 2009 18:38:55 +0200 Subject: bit nicer default statusbar look --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 4342389..42597e1 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -14,6 +14,7 @@ history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 6bd458e..2e889ed 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,7 +20,7 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] [bindings] # scroll down/up/left/right -- cgit v1.2.3 From 9155f7537a5ac5409e4ecd291080eb537eb0ebee Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 8 May 2009 20:01:37 +0200 Subject: support for changing the background color of the statusbar correctly --- CHECKLIST | 1 + examples/configs/sampleconfig | 4 +++- examples/configs/sampleconfig-dev | 4 +++- uzbl.c | 12 ++++++++++-- uzbl.h | 3 ++- 5 files changed, 19 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/CHECKLIST b/CHECKLIST index 2ea1a74..b2c7065 100644 --- a/CHECKLIST +++ b/CHECKLIST @@ -37,3 +37,4 @@ Also testers and interested people can use this list to see what uzbl is about, * run javascript on curent page through "script" command. * variable replacement in user agent. * basic keyboard link hilighting (numbering) and following. will be improved more +* support overriding background color of statusbar and pango markup format to customize the statusbar in terms of which variables, separators, colors, fonts, etc diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 42597e1..2e54e4c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -14,7 +14,9 @@ history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +# you can optionally use this setting to override the background color of the statusbar from your GTK theme. +status_background = #99CCFF fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 2e889ed..f6ee9f2 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,7 +20,9 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +# you can optionally use this setting to override the background color of the statusbar from your GTK theme. +status_background = #99CCFF [bindings] # scroll down/up/left/right diff --git a/uzbl.c b/uzbl.c index 1e7ee49..975cf62 100644 --- a/uzbl.c +++ b/uzbl.c @@ -833,8 +833,15 @@ update_title (void) { if (b->show_status) { gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short); + // TODO: we should probably not do this every time we want to update the title..? statln = parse_status_template(uzbl.behave.status_format); gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln); + if (b->status_background) { + GdkColor color; + gdk_color_parse (b->status_background, &color); + //labels and hboxes do not draw their own background. applying this on the window is ok as we the statusbar is the only affected widget. (if not, we could also use GtkEventBox) + gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color); + } g_free(statln); } else { gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long); @@ -1065,9 +1072,10 @@ settings_init () { b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); - b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); + b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); + b->status_background = g_key_file_get_string (config, "behavior", "status_background", NULL); if (! b->fifo_dir) - b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); + b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); if (! b->socket_dir) b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); keys = g_key_file_get_keys (config, "bindings", NULL, NULL); diff --git a/uzbl.h b/uzbl.h index ea99003..71ec587 100644 --- a/uzbl.h +++ b/uzbl.h @@ -87,7 +87,8 @@ typedef struct { /* behaviour */ typedef struct { - gchar *status_format; + gchar* status_format; + gchar* status_background; gchar* history_handler; gchar* fifo_dir; gchar* socket_dir; -- cgit v1.2.3 From 19892427c5dafccb1ac6341dcb4c370e2a9134a8 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 8 May 2009 20:55:14 +0200 Subject: *sweet ass sample statusbar layout* --- examples/configs/sampleconfig | 4 ++-- examples/configs/sampleconfig-dev | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 2e54e4c..92a7cfc 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -14,9 +14,9 @@ history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME # you can optionally use this setting to override the background color of the statusbar from your GTK theme. -status_background = #99CCFF +status_background = #303030 fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index f6ee9f2..69c7362 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,9 +20,9 @@ always_insert_mode = 0 modkey = Mod1 show_status = 1 status_top = 0 -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR [URI] [NAME] +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME # you can optionally use this setting to override the background color of the statusbar from your GTK theme. -status_background = #99CCFF +status_background = #303030 [bindings] # scroll down/up/left/right -- cgit v1.2.3 From e4f0286360d99356e1951ade67f24e12ac36f452 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 8 May 2009 23:32:47 +0200 Subject: disable cookie handler in master branch --- examples/configs/sampleconfig | 1 - examples/configs/sampleconfig-dev | 1 - 2 files changed, 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 92a7cfc..7dd5195 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -13,7 +13,6 @@ [behavior] history_handler = /usr/share/uzbl/examples/scripts/history.sh download_handler = /usr/share/uzbl/examples/scripts/download.sh -cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME # you can optionally use this setting to override the background color of the statusbar from your GTK theme. status_background = #303030 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 69c7362..0c34667 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -13,7 +13,6 @@ [behavior] history_handler = ./examples/scripts/history.sh download_handler = ./examples/scripts/download.sh -cookie_handler = ./examples/scripts/cookies.sh fifo_dir = /tmp socket_dir = /tmp always_insert_mode = 0 -- cgit v1.2.3 From 8d714bb94fc900cee4fa91048e5c91a67e66a224 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 9 May 2009 16:03:44 +0200 Subject: first draft of new config spec --- Makefile | 4 +- docs/config-syntax | 38 ++++++++++++++++ examples/configs/sampleconfig | 70 ----------------------------- examples/configs/sampleconfig-dev | 92 +++++++++++++++++++-------------------- 4 files changed, 84 insertions(+), 120 deletions(-) create mode 100644 docs/config-syntax delete mode 100644 examples/configs/sampleconfig (limited to 'examples') diff --git a/Makefile b/Makefile index 622a79a..2d6b8c9 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ test: uzbl ./uzbl --uri http://www.uzbl.org test-config: uzbl - ./uzbl --uri http://www.uzbl.org --config examples/configs/sampleconfig-dev + ./uzbl --uri http://www.uzbl.org < examples/configs/sampleconfig-dev test-config-real: uzbl - ./uzbl --uri http://www.uzbl.org --config /usr/share/uzbl/examples/configs/sampleconfig + ./uzbl --uri http://www.uzbl.org < /usr/share/uzbl/examples/configs/sampleconfig clean: rm -f uzbl diff --git a/docs/config-syntax b/docs/config-syntax new file mode 100644 index 0000000..2315b6c --- /dev/null +++ b/docs/config-syntax @@ -0,0 +1,38 @@ +Configuration setting at startup and changing at runtime happens through one of these: +- stdin at startup (TODO: see if we can keep listening while running) (write command to it + "\n") +- fifo (write command to it + "\n") +- socket (uzblctrl -s -c + +Lines written to the above starting with '#' or being empty, are ignored. + +** Command syntax: +commands can have no, one or 2 arguments. + +[\t[\t]] + +The 'bind' command is a special command, where argument 1 is a keyboard character (combo) and argument 2 is a command as specified above. +You can also use a '_' in the part to denote where you pass on whatever you want, which will be replaced into the specififed command whereever %s is mentioned + +** commands +Commands where one of the arguments is "parameter" expect this arugment to be a valid variable identifier (eg uzbl.behave.status_format) + +set parameter value # make sure the value complies with the datatype. +toggle parameter # expects parameter to be a gboolean. (eg status, insert_mode, ..) +get parameter +bind +script +script_file +back +forward +scroll_vert +scroll_horz +reload +reload_ign_cache +stop +zoom_in +zoom_out +spawn +exit +search + +The 'set' command may do more then just set the variable. eg 'set uri' commands will also cause uzbl to navigate to the uri. \ No newline at end of file diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig deleted file mode 100644 index 92a7cfc..0000000 --- a/examples/configs/sampleconfig +++ /dev/null @@ -1,70 +0,0 @@ - -# example uzbl config. in a real config, we should obey the xdg spec - -# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. -# bindings_internal denote keys to trigger actions internally in uzbl -# bindings_external denote keys to trigger scripts outside uzbl - -# keyboard behavior is vimstyle by default (all actions -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the actions -# from insert mode by combining them with the modkey - -[behavior] -history_handler = /usr/share/uzbl/examples/scripts/history.sh -download_handler = /usr/share/uzbl/examples/scripts/download.sh -cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME -# you can optionally use this setting to override the background color of the statusbar from your GTK theme. -status_background = #303030 -fifo_dir = /tmp -socket_dir = /tmp -always_insert_mode = 0 -modkey = Mod1 -show_status = 1 -status_top = 0 - -[bindings] -# scroll down/up/left/right -j = scroll_vert 20 -k = scroll_vert -20 -h = scroll_horz -20 -l = scroll_horz 20 -b = back -m = forward -s = stop -r = reload -R = reload_ign_cache -+ = zoom_in -- = zoom_out -t = toggle_status -#hilight matches -/_ = search %s -#jump to next -; = search -gh = uri http://www.uzbl.org -o _ = uri %s -:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -gg _ = uri http://www.google.com/search?q=%s -i = insert_mode -B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh -u = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh -U = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh -ZZ = exit -S = script alert("hi"); - -# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... -#hit F to toggle the Hints (now in form of link numbering) -F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -#hit f followed by linknumber and ENTER to follow that link -f_ = script window.location = document.links[%s].href; - -[network] -proxy_server = -#values 0-3 -http_debug = 0 -user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) -# Example user agent containing everything: -#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -max_conns = -max_conns_per_host = diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 69c7362..119e3a0 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -10,63 +10,59 @@ # if you do this, make sure you've set a modkey so you can reach the actions # from insert mode by combining them with the modkey -[behavior] -history_handler = ./examples/scripts/history.sh -download_handler = ./examples/scripts/download.sh -cookie_handler = ./examples/scripts/cookies.sh -fifo_dir = /tmp -socket_dir = /tmp -always_insert_mode = 0 -modkey = Mod1 -show_status = 1 -status_top = 0 -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME +set uzbl.behave.history_handler ./examples/scripts/history.sh +set uzbl.behave.download_handler ./examples/scripts/download.sh +set uzbl.behave.cookie_handler ./examples/scripts/cookies.sh +set uzbl.behave.fifo_dir /tmp +set uzbl.behave.socket_dir /tmp +set uzbl.behave.always_insert_mode 0 +set uzbl.behave.modkey Mod1 +set uzbl.behave.show_status 1 +set uzbl.behave.status_top 0 +set uzbl.behave.status_format MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME # you can optionally use this setting to override the background color of the statusbar from your GTK theme. -status_background = #303030 +set uzbl.behave.status_background #303030 -[bindings] # scroll down/up/left/right -j = scroll_vert 20 -k = scroll_vert -20 -h = scroll_horz -20 -l = scroll_horz 20 -b = back -m = forward -s = stop -r = reload -R = reload_ign_cache -+ = zoom_in -- = zoom_out -t = toggle_status +bind j scroll_vert 20 +bind k scroll_vert -20 +bind h scroll_horz -20 +bind l scroll_horz 20 +bind b back +bind m forward +bind s stop +bind r reload +bind R reload_ign_cache +bind + zoom_in +bind - zoom_out +bind t toggle uzbl.behave.show_status #hilight matches -/_ = search %s +bind /_ search %s #jump to next -; = search -gh = uri http://www.uzbl.org -o _ = uri %s -:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -gg _ = uri http://www.google.com/search?q=%s -i = insert_mode -B = spawn ./examples/scripts/insert_bookmark.sh -u = spawn ./examples/scripts/load_url_from_history.sh -U = spawn ./examples/scripts/load_url_from_bookmarks.sh -ZZ = exit -S = script alert("hi"); - +bind ; search +bind gh set uzbl.state.uri http://www.uzbl.org +bind o _ set uzbl.state.uri %s +bind :wiki _ set uzbl.state.uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ set uzbl.state.uri http://www.google.com/search?q=%s +bind i toggle uzbl.behave.insert_mode +bind B spawn ./examples/scripts/insert_bookmark.sh +bind u spawn ./examples/scripts/load_url_from_history.sh +bind U spawn ./examples/scripts/load_url_from_bookmarks.sh +bind ZZ exit +bind S script alert("hi"); # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) -F = script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +bind F script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} #hit f followed by linknumber and ENTER to follow that link -f_ = script window.location = document.links[%s].href; +bind f_ script window.location = document.links[%s].href; + -[network] # to start a local socks server, do : ssh -fND localhost:8118 localhost -#proxy_server = http://127.0.0.1:8118 +set uzbl.net.proxy_url http://127.0.0.1:8118 #values 0-3 -http_debug = 0 -user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +set uzbl.behave.http_debug = 0 +set uzbl.net.useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) # Example user agent containing everything: -#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -max_conns = -max_conns_per_host = - +#set uzbl.net.useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +set uzbl.net.max_conns 0 +set uzbl.net.max_conns_host 0 -- cgit v1.2.3 From 94f2be465514937c12eb75a1a28d5a54649d0adb Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 11 May 2009 19:17:21 +0200 Subject: yank script WIP --- examples/scripts/yank.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 examples/scripts/yank.sh (limited to 'examples') diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh new file mode 100755 index 0000000..0429f19 --- /dev/null +++ b/examples/scripts/yank.sh @@ -0,0 +1,10 @@ +# use this script to pipe any variable to xclip, so you have it in your clipboard +exit +# this script is not done yet + +# can we make this universal? +# add xclip to optdeps + +which xclip &>/dev/null || exit 1 + +echo -n `eval "$3"` #| xclip \ No newline at end of file -- cgit v1.2.3 From c6c5e95d8f00f9cc1404b1dd49431a0ce464c239 Mon Sep 17 00:00:00 2001 From: DuClare Date: Mon, 11 May 2009 23:25:45 +0300 Subject: Use incremental search in sampleconfigs. --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 92a7cfc..aa681fe 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -39,7 +39,7 @@ R = reload_ign_cache - = zoom_out t = toggle_status #hilight matches -/_ = search %s +/* = search %s #jump to next ; = search gh = uri http://www.uzbl.org diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 69c7362..e512202 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -39,7 +39,7 @@ R = reload_ign_cache - = zoom_out t = toggle_status #hilight matches -/_ = search %s +/* = search %s #jump to next ; = search gh = uri http://www.uzbl.org -- cgit v1.2.3 From 87598a5098910fe1395d201a008fdd9ff4926f8f Mon Sep 17 00:00:00 2001 From: DuClare Date: Tue, 12 May 2009 15:46:14 +0300 Subject: Added my cfg, a simple session manager and a clipboard handler. --- examples/duclare/clipboard.sh | 13 ++++++++ examples/duclare/session.sh | 44 +++++++++++++++++++++++++ examples/duclare/uzbl.conf | 75 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100755 examples/duclare/clipboard.sh create mode 100755 examples/duclare/session.sh create mode 100644 examples/duclare/uzbl.conf (limited to 'examples') diff --git a/examples/duclare/clipboard.sh b/examples/duclare/clipboard.sh new file mode 100755 index 0000000..a2b3717 --- /dev/null +++ b/examples/duclare/clipboard.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +fifo="$5" +action="$1" +url="$7" +selection=$(xclip -o) + +case $action in + "yank" ) echo -n "$url" | xclip;; + "goto" ) echo "uri $selection" > "$fifo";; + * ) echo "clipboard.sh: invalid action";; +esac + diff --git a/examples/duclare/session.sh b/examples/duclare/session.sh new file mode 100755 index 0000000..4dd4a39 --- /dev/null +++ b/examples/duclare/session.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# Simple session manager for uzbl. When called with "endsession" as the +# argument, it'lla empty the sessionfile, look for fifos in $fifodir and +# instruct each of them to store their current url in $sessionfile and +# terminate themselves. Run with "launch" as the argument and an instance of +# uzbl will be launched for each stored url. "endinstance" is used internally +# and doesn't need to be called manually at any point. + + +scriptfile=~/.uzbl/session.sh # this script +sessionfile=~/.uzbl/session # the file in which the "session" (i.e. urls) are stored + +# a simple script that calls the executable with --config and args +launcher=~/.uzbl/launch + +fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere +thisfifo="$5" +act="$1" +url="$7" + +case $act in + "launch" ) + for url in $(cat $sessionfile); do + $launcher --uri "$url" & + done + exit 0;; + "endinstance" ) + if [ "$url" != "(null)" ]; then + echo "$url" >> $sessionfile; echo "exit" > "$thisfifo" + else + echo "exit" > "$thisfifo" + fi;; + "endsession" ) + echo -n "" > "$sessionfile" + for fifo in $fifodir/uzbl_fifo_*; do + if [ "$fifo" != "$thisfifo" ]; then + echo "spawn $scriptfile endinstance" > "$fifo" + fi + done + echo "spawn $scriptfile endinstance" > "$thisfifo";; + * ) echo "session manager: bad action";; +esac + diff --git a/examples/duclare/uzbl.conf b/examples/duclare/uzbl.conf new file mode 100644 index 0000000..1ce5944 --- /dev/null +++ b/examples/duclare/uzbl.conf @@ -0,0 +1,75 @@ + +# example uzbl config. in a real config, we should obey the xdg spec + +# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. +# bindings_internal denote keys to trigger actions internally in uzbl +# bindings_external denote keys to trigger scripts outside uzbl + +# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the actions +# from insert mode by combining them with the modkey + +[behavior] +history_handler = /home/duclare/.uzbl/history.sh +download_handler = ~/.uzbl/download.sh +cookie_handler = ~/.uzbl/cookie.sh +status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME +fifo_dir = /tmp +socket_dir = /tmp +always_insert_mode = 0 +modkey = Mod1 +show_status = 1 +status_top = 0 +never_reset_mode = 0 + +[bindings] +# scroll down/up/left/right +j = scroll_vert 40 +k = scroll_vert -40 +h = scroll_horz -20 +l = scroll_horz 20 +b = back +m = forward +s = stop +r = reload +R = reload_ign_cache +w = follow_link_new_window ++ = zoom_in +- = zoom_out +t = toggle_status +#hilight matches +/* = search %s +#jump to next +; = search +gh = uri http://www.uzbl.org +o_ = uri %s +:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +ew_ = uri http://en.wikipedia.org/w/index.php?title=Special%3ASearch&search=%s&go=Go + +g_ = uri http://www.google.com/search?q=%s +i = insert_mode +B = spawn /home/duclare/.uzbl/insert_bookmark.sh +u = spawn /home/duclare/.uzbl/load_url_from_history.sh +U = spawn /home/duclare/.uzbl/load_url_from_bookmarks.sh +y = spawn /home/duclare/.uzbl/clipboard.sh yank +p = spawn /home/duclare/.uzbl/clipboard.sh goto +W = spawn /home/duclare/.uzbl/launch +ZZ = exit +:q = spawn /home/duclare/.uzbl/session.sh endsession + +# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... +# Vimperator-like hints, except that you can't type text to narrow on targets. You can still the text of a link from the beginning, and it'll activate as soon as the word is unique +f* = script var uzblid = 'uzbl_link_hint'; var uzbldivid = uzblid+'_div_container'; var links = document.links; try { HTMLElement.prototype.click = function () {if (typeof this.onclick == 'function') this.onclick({type: 'click'}); } } catch (e) {} function removeOldHints() { var elements = document.getElementById(uzbldivid); if( elements) elements.parentNode.removeChild(elements); } function keyPressHandler(e) {var kC = (window.event) ? event.keyCode : e.keyCode; var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE; if(kC==Esc) removeOldHints();} function isVisible(obj) { if (obj == document) return true; if (!obj) return false; if (!obj.parentNode) return false; if (obj.style) { if (obj.style.display == 'none') return false; if (obj.style.visibility == 'hidden') return false; } return isVisible(obj.parentNode); } function elementPosition(el) { var up = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while(el.offsetParent) { el = el.offsetParent; up += el.offsetTop; left += el.offsetLeft; } return [up,left,width,height]; } function elementInViewport(el) { offset = elementPosition(el); var up = offset[0]; var left = offset[1]; var width = offset[2]; var height = offset[3]; return (up < (window.pageYOffset + window.innerHeight) && left < (window.pageXOffset + window.innerWidth) && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset); } function generateHints(items, l) { var hintdiv = document.createElement('div'); hintdiv.setAttribute('id', uzbldivid); for (var i=0; i < items.length; i++) { var nr = items[i]; var li = links[nr]; var pos = elementPosition(li); var hint = document.createElement('div'); hint.setAttribute('name',uzblid); var n = (nr+'').length; for (n; n0) { hint.style.left=pos[1]+(img[0].width/2)+'px'; } hint.style.textDecoration='none'; hint.style.webkitBorderRadius='6px'; hint.style.webkitTransform='scale(0.9) rotate(0deg) translate(-6px,-5px)'; hintdiv.appendChild(hint); } document.body.appendChild(hintdiv); } function clickLink(item) { removeOldHints(); if (item) { item.click(); window.location = item.href; } } function followLink(follow) { document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); var s = follow.split(''); var linktexts = [[],[]]; for (var i=0; i < links.length; i++) { var li = links[i]; if (isVisible(li) && elementInViewport(li)) { linktexts[0].push(i); linktexts[1].push(li.innerText); } } var leftovers = []; var nrlength = (linktexts[0][linktexts[0].length-1]+'').length; var linknr = parseInt(follow, 10); if (s.length == nrlength) { clickLink(links[linknr]); } else { for (var j=0; j < linktexts[0].length; j++) { var b = true; for (var k=0; k < s.length; k++) { b = (b && (linktexts[1][j].charAt(k)==s[k])); } if (b) { leftovers.push(linktexts[0][j]); } } if (leftovers.length == 1 && s.length >= nrlength) { clickLink(links[leftovers[0]]); } else if (!document.getElementById(uzbldivid)) { generateHints(linktexts[0], nrlength); } } } followLink('%s'); + +[network] +# to start a local socks server, do : ssh -fND localhost:8118 localhost +#proxy_server = http://127.0.0.1:8118 +#values 0-3 +http_debug = 0 +user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +# Example user agent containing everything: +#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +max_conns = +max_conns_per_host = + -- cgit v1.2.3 From 0131a31934ae5330ad2bee7db89ce642f158bf5e Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Tue, 12 May 2009 18:31:51 +0200 Subject: further enhancements to the cmd parser, added sampleconfig-pipe --- examples/configs/sampleconfig-pipe | 4 ++++ uzbl.c | 25 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 examples/configs/sampleconfig-pipe (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe new file mode 100644 index 0000000..305f57d --- /dev/null +++ b/examples/configs/sampleconfig-pipe @@ -0,0 +1,4 @@ +GET status_format +BIND xx = exit +BIND gG _ = uri http://www.google.com/search?q=%s +SET status_format = MODE KEYCMD URI diff --git a/uzbl.c b/uzbl.c index c652917..ccb2203 100644 --- a/uzbl.c +++ b/uzbl.c @@ -63,7 +63,7 @@ const struct { char *name; void **ptr; } var_name_to_ptr[] = { - { "name", (void *)&uzbl.state.instance_name }, + { "status_format", (void *)&uzbl.behave.status_format }, { "show_status", (void *)&uzbl.behave.show_status }, { "insert_mode", (void *)&uzbl.behave.insert_mode }, { NULL, NULL } @@ -212,6 +212,16 @@ static void scroll_horz(WebKitWebView* page, const char *param) { scroll(uzbl.gui.bar_h, param); } +static void +cmd_set_status() { + if (!uzbl.behave.show_status) { + gtk_widget_hide(uzbl.gui.mainbar); + } else { + gtk_widget_show(uzbl.gui.mainbar); + } + update_title(); +} + static void toggle_status_cb (WebKitWebView* page, const char *param) { (void)page; @@ -754,11 +764,18 @@ set_var_value(gchar *name, gchar *val) { char *endp = NULL; if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(!strcmp(name, "name")) { + if(!strcmp(name, "status_format")) { free(*p); *p = g_strdup(val); - } else { + update_title(); + } + /* variables that take int values */ + else { *p = (int)strtoul(val, &endp, 10); + + if(!strcmp(name, "show_status")) { + cmd_set_status(); + } } } return TRUE; @@ -770,7 +787,7 @@ setup_regex() { uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", 0, 0, &err); uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", 0, 0, &err); - uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.+[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err); + uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.*[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err); } static gboolean -- cgit v1.2.3 From 8379e623c118f7861ee52884556a8b201b441dc9 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 12 May 2009 22:44:53 +0200 Subject: 2 bugfixes in cookie handler --- examples/scripts/cookies.sh | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index 9f6d202..cd449dc 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -5,7 +5,7 @@ # kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 # domain alow-read-other-subdomains path http-required expiration name value # you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) - +# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" # MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( # TODO: different cookie paths per config (eg per group of uzbl instances) @@ -19,6 +19,7 @@ # implement secure attribute. # support blocking or not for 3rd parties # http://kb.mozillazine.org/Cookies.txt +# don't always append cookies, sometimes we need to overwrite if [ -f /usr/share/uzbl/examples/configs/cookies ] then @@ -60,13 +61,13 @@ function parse_cookie () { do if [ "$first_pair" == 1 ] then - field_name=${i%%=*} - field_value=${i#*=} + field_name=${pair%%=*} + field_value=${pair#*=} first_pair=0 else read -r pair <<< "$pair" #strip leading/trailing wite space - key=${i%%=*} - val=${i#*=} + key=${pair%%=*} + val=${pair#*=} [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` # TODO: domain [ "$key" == path ] && field_path=$val @@ -78,8 +79,16 @@ function parse_cookie () { # match cookies in cookies.txt againsh hostname and path function get_cookie () { path_esc=${path//\//\\/} - cookie=`awk "/^[^\t]*$host\t[^\t]*\t$path_esc/" cookie_file 2>/dev/null | tail -n 1` - [ -n "$cookie" ] + cookie=`awk "/^[^\t]*$host\t[^\t]*\t$path_esc/" $cookie_file 2>/dev/null | tail -n 1` + if [ -z "$cookie" ] + then + false + else + read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" + cookie="$name=$value" + #echo "COOKIE $cookie" >> $HOME/cookielog + true + fi } [ $action == PUT ] && parse_cookie && echo -e "$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" >> $cookie_file -- cgit v1.2.3 From 3532d7214d6a6e6c676f1b87e4ba8c851fcc8f2f Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 13 May 2009 00:26:16 +0200 Subject: stdin, fifo, socket support only the new command style, added uri variable --- examples/configs/sampleconfig-pipe | 7 +- uzbl.c | 202 ++++++++++++++++++++----------------- 2 files changed, 114 insertions(+), 95 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index 305f57d..45f3e08 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -1,4 +1,7 @@ GET status_format -BIND xx = exit +SET show_status = 1 +BIND x = exit BIND gG _ = uri http://www.google.com/search?q=%s -SET status_format = MODE KEYCMD URI +SET status_format = MSG URI +SET status_message = Wazz up dude? +BIND x = exit diff --git a/uzbl.c b/uzbl.c index 96bbf0f..84005df 100644 --- a/uzbl.c +++ b/uzbl.c @@ -63,10 +63,12 @@ const struct { char *name; void **ptr; } var_name_to_ptr[] = { - { "status_format", (void *)&uzbl.behave.status_format }, - { "status_message", (void *)&uzbl.gui.sbar.msg }, - { "show_status", (void *)&uzbl.behave.show_status }, - { "insert_mode", (void *)&uzbl.behave.insert_mode }, + { "uri", (void *)&uzbl.state.uri }, + { "status_format", (void *)&uzbl.behave.status_format }, + { "status_background", (void *)&uzbl.behave.status_background }, + { "status_message", (void *)&uzbl.gui.sbar.msg }, + { "show_status", (void *)&uzbl.behave.show_status }, + { "insert_mode", (void *)&uzbl.behave.insert_mode }, { NULL, NULL } }, *n2v_p = var_name_to_ptr; @@ -663,6 +665,103 @@ parse_line(char *line) { g_strfreev(parts); } +/* command parser */ +static void +setup_regex() { + GError *err=NULL; + + uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", 0, 0, &err); + uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", 0, 0, &err); + uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.*[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err); +} +static gboolean +get_var_value(gchar *name) { + void **p = NULL; + + if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { + if(!strcmp(name, "status_format")) { + printf("VAR: %s VALUE: %s\n", name, (char *)*p); + } else { + printf("VAR: %s VALUE: %d\n", name, (int)*p); + } + } + return TRUE; +} + +static gboolean +set_var_value(gchar *name, gchar *val) { + void **p = NULL; + char *endp = NULL; + + if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { + if(!strcmp(name, "status_message") + || !strcmp(name, "status_background") + || !strcmp(name, "status_format")) { + if(*p) + free(*p); + *p = g_strdup(val); + update_title(); + } + else if(!strcmp(name, "uri")) { + if(*p) + free(*p); + *p = g_strdup(val); + load_uri(uzbl.gui.web_view, (const gchar*)*p); + } + /* variables that take int values */ + else { + *p = (int)strtoul(val, &endp, 10); + + if(!strcmp(name, "show_status")) { + cmd_set_status(); + } + } + } + return TRUE; +} + + +static void +parse_cmd_line(char *ctl_line) { + gchar **tokens; + + /* SET command */ + if(ctl_line[0] == 'S') { + tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0); + if(tokens[0][0] == 0) { + set_var_value(tokens[1], tokens[2]); + g_strfreev(tokens); + } + else + printf("Error in command: %s\n", tokens[0]); + } + /* GET command */ + else if(ctl_line[0] == 'G') { + tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0); + if(tokens[0][0] == 0) { + get_var_value(tokens[1]); + g_strfreev(tokens); + } + else + printf("Error in command: %s\n", tokens[0]); + } + /* BIND command */ + else if(ctl_line[0] == 'B') { + tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0); + if(tokens[0][0] == 0) { + add_binding(tokens[1], tokens[2]); + g_strfreev(tokens); + } + else + printf("Error in command: %s\n", tokens[0]); + } + else + printf("Command not understood (%s)\n", ctl_line); + + return; +} + + void build_stream_name(int type) { char *xwin_str; @@ -715,9 +814,10 @@ control_fifo(GIOChannel *gio, GIOCondition condition) { if (ret == G_IO_STATUS_ERROR) g_error ("Fifo: Error reading: %s\n", err->message); - parse_line(ctl_line); + //parse_line(ctl_line); + parse_cmd_line(ctl_line); g_free(ctl_line); - printf("...done\n"); + return; } @@ -749,58 +849,6 @@ create_fifo() { return; } -static gboolean -get_var_value(gchar *name) { - void **p = NULL; - - if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(!strcmp(name, "status_format")) { - printf("VAR: %s VALUE: %s\n", name, (char *)*p); - } else { - printf("VAR: %s VALUE: %d\n", name, (int)*p); - } - } - return TRUE; -} - -static gboolean -set_var_value(gchar *name, gchar *val) { - void **p = NULL; - char *endp = NULL; - - if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(!strcmp(name, "status_format")) { - if(*p) - free(*p); - *p = g_strdup(val); - update_title(); - } - else if(!strcmp(name, "status_message")) { - if(*p) - free(*p); - *p = g_strdup(val); - update_title(); - } - /* variables that take int values */ - else { - *p = (int)strtoul(val, &endp, 10); - - if(!strcmp(name, "show_status")) { - cmd_set_status(); - } - } - } - return TRUE; -} - -static void -setup_regex() { - GError *err=NULL; - - uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", 0, 0, &err); - uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", 0, 0, &err); - uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.*[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err); -} static gboolean control_stdin(GIOChannel *gio, GIOCondition condition) { @@ -808,7 +856,6 @@ control_stdin(GIOChannel *gio, GIOCondition condition) { gsize ctl_line_len = 0; GIOStatus ret; GError *err = NULL; - gchar **tokens; if (condition & G_IO_HUP) { ret = g_io_channel_shutdown (gio, FALSE, &err); @@ -819,39 +866,7 @@ control_stdin(GIOChannel *gio, GIOCondition condition) { if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) return FALSE; - /* SET command */ - if(ctl_line[0] == 'S') { - tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - set_var_value(tokens[1], tokens[2]); - g_strfreev(tokens); - } - else - printf("Error in command: %s\n", tokens[0]); - } - /* GET command */ - else if(ctl_line[0] == 'G') { - tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - get_var_value(tokens[1]); - g_strfreev(tokens); - } - else - printf("Error in command: %s\n", tokens[0]); - } - /* BIND command */ - else if(ctl_line[0] == 'B') { - tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0); - if(tokens[0][0] == 0) { - add_binding(tokens[1], tokens[2]); - g_strfreev(tokens); - } - else - printf("Error in command: %s\n", tokens[0]); - } - else - printf("Command not understood (%s)\n", ctl_line); - + parse_cmd_line(ctl_line); g_free(ctl_line); return TRUE; @@ -908,7 +923,8 @@ control_socket(GIOChannel *chan) { } close (clientsock); ctl_line = g_strdup(buffer); - parse_line (ctl_line); + //parse_line (ctl_line); + parse_cmd_line (ctl_line); /* TODO: we should be able to do it with this. but glib errors out with "Invalid argument" -- cgit v1.2.3 From 76d8e267b0f64b7213c0cf5f8aa46b6c47ad77cb Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 13 May 2009 01:28:13 +0200 Subject: fixed BIND regex's greedyness, support to overwrite existing bindings --- examples/configs/sampleconfig-pipe | 36 +++++++++++++++++++++++++++++------- uzbl.c | 12 +++++++++--- 2 files changed, 38 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index 45f3e08..78a1b80 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -1,7 +1,29 @@ -GET status_format -SET show_status = 1 -BIND x = exit -BIND gG _ = uri http://www.google.com/search?q=%s -SET status_format = MSG URI -SET status_message = Wazz up dude? -BIND x = exit +SET show_status = 1 +SET status_background = #303030 +SET status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME +BIND j = scroll_vert 20 +BIND k = scroll_vert -20 +BIND h = scroll_horz -20 +BIND l = scroll_horz 20 +BIND b = back +BIND m = forward +BIND s = stop +BIND r = reload +BIND R = reload_ign_cache +BIND + = zoom_in +BIND - = zoom_out +BIND t = toggle uzbl.behave.show_status +BIND /_ = search %s +BIND ; = search +BIND gh = uri http://www.uzbl.org +BIND o _ = uri %s +BIND :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +BIND gg _ = uri http://www.google.com/search?q=%s +BIND i = insert_mode +BIND B = spawn ./examples/scripts/insert_bookmark.sh +BIND u = spawn ./examples/scripts/load_url_from_history.sh +BIND U = spawn ./examples/scripts/load_url_from_bookmarks.sh +BIND ZZ = exit +BIND S = script alert("hi"); +BIND F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +BIND f_ = script window.location = document.links[%s].href; diff --git a/uzbl.c b/uzbl.c index 84005df..612fd87 100644 --- a/uzbl.c +++ b/uzbl.c @@ -670,9 +670,12 @@ static void setup_regex() { GError *err=NULL; - uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", 0, 0, &err); - uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", 0, 0, &err); - uzbl.comm.bind_regex = g_regex_new("^BIND\\s+(.*[^ ])\\s*=\\s*([a-z][^\\n].+)$", 0, 0, &err); + uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", + G_REGEX_OPTIMIZE, 0, &err); + uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", + G_REGEX_OPTIMIZE, 0, &err); + uzbl.comm.bind_regex = g_regex_new("^BIND\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$", + G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err); } static gboolean get_var_value(gchar *name) { @@ -1178,6 +1181,9 @@ add_binding (const gchar *key, const gchar *act) { //Debug: printf ("Binding %-10s : %s\n", key, act); action = new_action(parts[0], parts[1]); + + if(g_hash_table_lookup(uzbl.bindings, key)) + g_hash_table_remove(uzbl.bindings, key); g_hash_table_insert(uzbl.bindings, g_strdup(key), action); g_strfreev(parts); -- cgit v1.2.3 From a135f3b6e6d03ca3d4ad15c8383047c659953f15 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 13 May 2009 01:35:21 +0200 Subject: typos in sampleconfig-pipe --- examples/configs/sampleconfig-pipe | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index 78a1b80..a23f6d9 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -1,10 +1,10 @@ SET show_status = 1 SET status_background = #303030 SET status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME -BIND j = scroll_vert 20 -BIND k = scroll_vert -20 -BIND h = scroll_horz -20 -BIND l = scroll_horz 20 +BIND j = scroll_vert 20 +BIND k = scroll_vert -20 +BIND h = scroll_horz -20 +BIND l = scroll_horz 20 BIND b = back BIND m = forward BIND s = stop @@ -12,7 +12,7 @@ BIND r = reload BIND R = reload_ign_cache BIND + = zoom_in BIND - = zoom_out -BIND t = toggle uzbl.behave.show_status +BIND t = toggle_status BIND /_ = search %s BIND ; = search BIND gh = uri http://www.uzbl.org -- cgit v1.2.3 From 90a7cebb6fbb37392bf626bfdf4274a764be2deb Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 13 May 2009 12:15:04 +0200 Subject: command files can contain comments and empty lines --- examples/configs/sampleconfig-pipe | 5 ++++- uzbl.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index a23f6d9..4db3f23 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -1,6 +1,9 @@ +# Behaviour and appearance SET show_status = 1 SET status_background = #303030 -SET status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME +SET status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG + +# Key bindings BIND j = scroll_vert 20 BIND k = scroll_vert -20 BIND h = scroll_horz -20 diff --git a/uzbl.c b/uzbl.c index 612fd87..dcb4706 100644 --- a/uzbl.c +++ b/uzbl.c @@ -758,6 +758,11 @@ parse_cmd_line(char *ctl_line) { else printf("Error in command: %s\n", tokens[0]); } + /* Comments */ + else if( (ctl_line[0] == '#') + || (ctl_line[0] == ' ') + || (ctl_line[0] == '\n')) + ; /* ignore these lines */ else printf("Command not understood (%s)\n", ctl_line); -- cgit v1.2.3 From 7ad67b457eb953810536a0844781cfcd95f38476 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 13 May 2009 13:16:05 +0200 Subject: initial command don't have to be uppercase any more --- examples/configs/sampleconfig-pipe | 58 +++++++++++++++++++------------------- uzbl.c | 12 ++++---- 2 files changed, 35 insertions(+), 35 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index 4db3f23..9fc4d52 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -1,32 +1,32 @@ # Behaviour and appearance -SET show_status = 1 -SET status_background = #303030 -SET status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG +set show_status = 1 +set status_background = #303030 +set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG # Key bindings -BIND j = scroll_vert 20 -BIND k = scroll_vert -20 -BIND h = scroll_horz -20 -BIND l = scroll_horz 20 -BIND b = back -BIND m = forward -BIND s = stop -BIND r = reload -BIND R = reload_ign_cache -BIND + = zoom_in -BIND - = zoom_out -BIND t = toggle_status -BIND /_ = search %s -BIND ; = search -BIND gh = uri http://www.uzbl.org -BIND o _ = uri %s -BIND :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -BIND gg _ = uri http://www.google.com/search?q=%s -BIND i = insert_mode -BIND B = spawn ./examples/scripts/insert_bookmark.sh -BIND u = spawn ./examples/scripts/load_url_from_history.sh -BIND U = spawn ./examples/scripts/load_url_from_bookmarks.sh -BIND ZZ = exit -BIND S = script alert("hi"); -BIND F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -BIND f_ = script window.location = document.links[%s].href; +bind j = scroll_vert 20 +bind k = scroll_vert -20 +bind h = scroll_horz -20 +bind l = scroll_horz 20 +bind b = back +bind m = forward +bind s = stop +bind r = reload +bind R = reload_ign_cache +bind + = zoom_in +bind - = zoom_out +bind t = toggle_status +bind /_ = search %s +bind ; = search +bind gh = uri http://www.uzbl.org +bind o _ = uri %s +bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ = uri http://www.google.com/search?q=%s +bind i = insert_mode +bind B = spawn ./examples/scripts/insert_bookmark.sh +bind u = spawn ./examples/scripts/load_url_from_history.sh +bind U = spawn ./examples/scripts/load_url_from_bookmarks.sh +bind ZZ = exit +bind S = script alert("hi"); +bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +bind f_ = script window.location = document.links[%s].href; diff --git a/uzbl.c b/uzbl.c index dcb4706..c55c572 100644 --- a/uzbl.c +++ b/uzbl.c @@ -670,11 +670,11 @@ static void setup_regex() { GError *err=NULL; - uzbl.comm.get_regex = g_regex_new("^GET\\s+([^ \\n]+)$", + uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$", G_REGEX_OPTIMIZE, 0, &err); - uzbl.comm.set_regex = g_regex_new("^SET\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", + uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$", G_REGEX_OPTIMIZE, 0, &err); - uzbl.comm.bind_regex = g_regex_new("^BIND\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$", + uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$", G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err); } static gboolean @@ -729,7 +729,7 @@ parse_cmd_line(char *ctl_line) { gchar **tokens; /* SET command */ - if(ctl_line[0] == 'S') { + if(ctl_line[0] == 's' || ctl_line[0] == 'S') { tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0); if(tokens[0][0] == 0) { set_var_value(tokens[1], tokens[2]); @@ -739,7 +739,7 @@ parse_cmd_line(char *ctl_line) { printf("Error in command: %s\n", tokens[0]); } /* GET command */ - else if(ctl_line[0] == 'G') { + else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') { tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0); if(tokens[0][0] == 0) { get_var_value(tokens[1]); @@ -749,7 +749,7 @@ parse_cmd_line(char *ctl_line) { printf("Error in command: %s\n", tokens[0]); } /* BIND command */ - else if(ctl_line[0] == 'B') { + else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') { tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0); if(tokens[0][0] == 0) { add_binding(tokens[1], tokens[2]); -- cgit v1.2.3 From 4482ee0af3813938b437e8b54c2a13267fc955cf Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 14 May 2009 23:11:51 +0200 Subject: import whats useful from duclares sample stuff --- examples/duclare/clipboard.sh | 13 -------- examples/duclare/session.sh | 44 ------------------------- examples/duclare/uzbl.conf | 75 ------------------------------------------- examples/scripts/clipboard.sh | 15 +++++++++ examples/scripts/session.sh | 42 ++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 132 deletions(-) delete mode 100755 examples/duclare/clipboard.sh delete mode 100755 examples/duclare/session.sh delete mode 100644 examples/duclare/uzbl.conf create mode 100755 examples/scripts/clipboard.sh create mode 100755 examples/scripts/session.sh (limited to 'examples') diff --git a/examples/duclare/clipboard.sh b/examples/duclare/clipboard.sh deleted file mode 100755 index a2b3717..0000000 --- a/examples/duclare/clipboard.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -fifo="$5" -action="$1" -url="$7" -selection=$(xclip -o) - -case $action in - "yank" ) echo -n "$url" | xclip;; - "goto" ) echo "uri $selection" > "$fifo";; - * ) echo "clipboard.sh: invalid action";; -esac - diff --git a/examples/duclare/session.sh b/examples/duclare/session.sh deleted file mode 100755 index 4dd4a39..0000000 --- a/examples/duclare/session.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# Simple session manager for uzbl. When called with "endsession" as the -# argument, it'lla empty the sessionfile, look for fifos in $fifodir and -# instruct each of them to store their current url in $sessionfile and -# terminate themselves. Run with "launch" as the argument and an instance of -# uzbl will be launched for each stored url. "endinstance" is used internally -# and doesn't need to be called manually at any point. - - -scriptfile=~/.uzbl/session.sh # this script -sessionfile=~/.uzbl/session # the file in which the "session" (i.e. urls) are stored - -# a simple script that calls the executable with --config and args -launcher=~/.uzbl/launch - -fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -thisfifo="$5" -act="$1" -url="$7" - -case $act in - "launch" ) - for url in $(cat $sessionfile); do - $launcher --uri "$url" & - done - exit 0;; - "endinstance" ) - if [ "$url" != "(null)" ]; then - echo "$url" >> $sessionfile; echo "exit" > "$thisfifo" - else - echo "exit" > "$thisfifo" - fi;; - "endsession" ) - echo -n "" > "$sessionfile" - for fifo in $fifodir/uzbl_fifo_*; do - if [ "$fifo" != "$thisfifo" ]; then - echo "spawn $scriptfile endinstance" > "$fifo" - fi - done - echo "spawn $scriptfile endinstance" > "$thisfifo";; - * ) echo "session manager: bad action";; -esac - diff --git a/examples/duclare/uzbl.conf b/examples/duclare/uzbl.conf deleted file mode 100644 index 1ce5944..0000000 --- a/examples/duclare/uzbl.conf +++ /dev/null @@ -1,75 +0,0 @@ - -# example uzbl config. in a real config, we should obey the xdg spec - -# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. -# bindings_internal denote keys to trigger actions internally in uzbl -# bindings_external denote keys to trigger scripts outside uzbl - -# keyboard behavior is vimstyle by default (all actions -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the actions -# from insert mode by combining them with the modkey - -[behavior] -history_handler = /home/duclare/.uzbl/history.sh -download_handler = ~/.uzbl/download.sh -cookie_handler = ~/.uzbl/cookie.sh -status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME -fifo_dir = /tmp -socket_dir = /tmp -always_insert_mode = 0 -modkey = Mod1 -show_status = 1 -status_top = 0 -never_reset_mode = 0 - -[bindings] -# scroll down/up/left/right -j = scroll_vert 40 -k = scroll_vert -40 -h = scroll_horz -20 -l = scroll_horz 20 -b = back -m = forward -s = stop -r = reload -R = reload_ign_cache -w = follow_link_new_window -+ = zoom_in -- = zoom_out -t = toggle_status -#hilight matches -/* = search %s -#jump to next -; = search -gh = uri http://www.uzbl.org -o_ = uri %s -:wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -ew_ = uri http://en.wikipedia.org/w/index.php?title=Special%3ASearch&search=%s&go=Go - -g_ = uri http://www.google.com/search?q=%s -i = insert_mode -B = spawn /home/duclare/.uzbl/insert_bookmark.sh -u = spawn /home/duclare/.uzbl/load_url_from_history.sh -U = spawn /home/duclare/.uzbl/load_url_from_bookmarks.sh -y = spawn /home/duclare/.uzbl/clipboard.sh yank -p = spawn /home/duclare/.uzbl/clipboard.sh goto -W = spawn /home/duclare/.uzbl/launch -ZZ = exit -:q = spawn /home/duclare/.uzbl/session.sh endsession - -# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... -# Vimperator-like hints, except that you can't type text to narrow on targets. You can still the text of a link from the beginning, and it'll activate as soon as the word is unique -f* = script var uzblid = 'uzbl_link_hint'; var uzbldivid = uzblid+'_div_container'; var links = document.links; try { HTMLElement.prototype.click = function () {if (typeof this.onclick == 'function') this.onclick({type: 'click'}); } } catch (e) {} function removeOldHints() { var elements = document.getElementById(uzbldivid); if( elements) elements.parentNode.removeChild(elements); } function keyPressHandler(e) {var kC = (window.event) ? event.keyCode : e.keyCode; var Esc = (window.event) ? 27 : e.DOM_VK_ESCAPE; if(kC==Esc) removeOldHints();} function isVisible(obj) { if (obj == document) return true; if (!obj) return false; if (!obj.parentNode) return false; if (obj.style) { if (obj.style.display == 'none') return false; if (obj.style.visibility == 'hidden') return false; } return isVisible(obj.parentNode); } function elementPosition(el) { var up = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; var height = el.offsetHeight; while(el.offsetParent) { el = el.offsetParent; up += el.offsetTop; left += el.offsetLeft; } return [up,left,width,height]; } function elementInViewport(el) { offset = elementPosition(el); var up = offset[0]; var left = offset[1]; var width = offset[2]; var height = offset[3]; return (up < (window.pageYOffset + window.innerHeight) && left < (window.pageXOffset + window.innerWidth) && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset); } function generateHints(items, l) { var hintdiv = document.createElement('div'); hintdiv.setAttribute('id', uzbldivid); for (var i=0; i < items.length; i++) { var nr = items[i]; var li = links[nr]; var pos = elementPosition(li); var hint = document.createElement('div'); hint.setAttribute('name',uzblid); var n = (nr+'').length; for (n; n0) { hint.style.left=pos[1]+(img[0].width/2)+'px'; } hint.style.textDecoration='none'; hint.style.webkitBorderRadius='6px'; hint.style.webkitTransform='scale(0.9) rotate(0deg) translate(-6px,-5px)'; hintdiv.appendChild(hint); } document.body.appendChild(hintdiv); } function clickLink(item) { removeOldHints(); if (item) { item.click(); window.location = item.href; } } function followLink(follow) { document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); var s = follow.split(''); var linktexts = [[],[]]; for (var i=0; i < links.length; i++) { var li = links[i]; if (isVisible(li) && elementInViewport(li)) { linktexts[0].push(i); linktexts[1].push(li.innerText); } } var leftovers = []; var nrlength = (linktexts[0][linktexts[0].length-1]+'').length; var linknr = parseInt(follow, 10); if (s.length == nrlength) { clickLink(links[linknr]); } else { for (var j=0; j < linktexts[0].length; j++) { var b = true; for (var k=0; k < s.length; k++) { b = (b && (linktexts[1][j].charAt(k)==s[k])); } if (b) { leftovers.push(linktexts[0][j]); } } if (leftovers.length == 1 && s.length >= nrlength) { clickLink(links[leftovers[0]]); } else if (!document.getElementById(uzbldivid)) { generateHints(linktexts[0], nrlength); } } } followLink('%s'); - -[network] -# to start a local socks server, do : ssh -fND localhost:8118 localhost -#proxy_server = http://127.0.0.1:8118 -#values 0-3 -http_debug = 0 -user-agent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) -# Example user agent containing everything: -#user-agent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -max_conns = -max_conns_per_host = - diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh new file mode 100755 index 0000000..c64b65c --- /dev/null +++ b/examples/scripts/clipboard.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard. + +fifo="$5" +action="$1" +url="$7" +selection=$(xclip -o) + +case $action in + "yank" ) echo -n "$url" | xclip;; + "goto" ) echo "uri $selection" > "$fifo";; + * ) echo "clipboard.sh: invalid action";; +esac + diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh new file mode 100755 index 0000000..5087af0 --- /dev/null +++ b/examples/scripts/session.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Very simple session manager for uzbl. When called with "endsession" as the +# argument, it'lla empty the sessionfile, look for fifos in $fifodir and +# instruct each of them to store their current url in $sessionfile and +# terminate themselves. Run with "launch" as the argument and an instance of +# uzbl will be launched for each stored url. "endinstance" is used internally +# and doesn't need to be called manually at any point. + + +scriptfile=$XDG_CONFIG_HOME/uzbl/session.sh # this script +sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored +UZBL="uzbl" # add custom flags and whatever here. + +fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere +thisfifo="$5" +act="$1" +url="$7" + +case $act in + "launch" ) + for url in $(cat $sessionfile); do + $UZBL --uri "$url" & + done + exit 0;; + "endinstance" ) + if [ "$url" != "(null)" ]; then + echo "$url" >> $sessionfile; + fi + echo "exit" > "$thisfifo" + ;; + "endsession" ) + echo -n "" > "$sessionfile" + for fifo in $fifodir/uzbl_fifo_*; do + if [ "$fifo" != "$thisfifo" ]; then + echo "spawn $scriptfile endinstance" > "$fifo" + fi + done + echo "spawn $scriptfile endinstance" > "$thisfifo";; + * ) echo "session manager: bad action";; +esac + -- cgit v1.2.3 From ec8973e07453baeee83fc7e8a229832acc872f47 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Fri, 15 May 2009 11:48:35 +0200 Subject: added modkey and always_insert to cmd parser --- examples/configs/sampleconfig-pipe | 4 ++ uzbl.c | 128 +++++++++++++------------------------ 2 files changed, 50 insertions(+), 82 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index 9fc4d52..c25db06 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -2,6 +2,10 @@ set show_status = 1 set status_background = #303030 set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG +set modkey = Mod1 +set always_insert = 0 +#set proxy_url = http://127.0.0.1:8118 +set fifo_dir = /tmp # Key bindings bind j = scroll_vert 20 diff --git a/uzbl.c b/uzbl.c index 5a93d37..8bd952a 100644 --- a/uzbl.c +++ b/uzbl.c @@ -70,6 +70,8 @@ const struct { { "status_message", (void *)&uzbl.gui.sbar.msg }, { "show_status", (void *)&uzbl.behave.show_status }, { "insert_mode", (void *)&uzbl.behave.insert_mode }, + { "modkey" , (void *)&uzbl.behave.modkey }, + { "always_insert" , (void *)&uzbl.behave.always_insert_mode }, { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler}, { "history_handler", (void *)&uzbl.behave.history_handler }, { "download_handler", (void *)&uzbl.behave.download_handler }, @@ -725,6 +727,34 @@ set_proxy_url() { return; } +static void +set_modkey() { + Behaviour *b = &uzbl.behave; + + if (!b->modkey) + b->modkey = ""; + + //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED) + gchar* modkeyup = g_utf8_strup (b->modkey, -1); + if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key. + if (g_strrstr (modkeyup,"LOCK") != NULL) b->modmask |= GDK_LOCK_MASK; //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock). + if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key. + if (g_strrstr (modkeyup,"MOD1") != NULL) b->modmask |= GDK_MOD1_MASK; //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key). + if (g_strrstr (modkeyup,"MOD2") != NULL) b->modmask |= GDK_MOD2_MASK; //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). + if (g_strrstr (modkeyup,"MOD3") != NULL) b->modmask |= GDK_MOD3_MASK; //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). + if (g_strrstr (modkeyup,"MOD4") != NULL) b->modmask |= GDK_MOD4_MASK; //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). + if (g_strrstr (modkeyup,"MOD5") != NULL) b->modmask |= GDK_MOD5_MASK; //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). + if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button. + if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button. + if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button. + if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button. + if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button. + if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10 + if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10 + if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */ + g_free (modkeyup); +} + static gboolean var_is(const char *x, const char *y) { gboolean ret = FALSE; @@ -754,14 +784,12 @@ set_var_value(gchar *name, gchar *val) { update_title(); } else if(var_is("uri", name)) { - if(*p) - free(*p); + if(*p) free(*p); *p = g_strdup(val); load_uri(uzbl.gui.web_view, (const gchar*)*p); } else if(var_is("proxy_url", name)) { - if(*p) - free(*p); + if(*p) free(*p); *p = g_strdup(val); set_proxy_url(); } @@ -773,6 +801,11 @@ set_var_value(gchar *name, gchar *val) { if(*p) free(*p); *p = init_socket(g_strdup(val)); } + else if(var_is("modkey", name)) { + if(*p) free(*p); + *p = g_strdup(val); + set_modkey(); + } /* variables that take int values */ else { int *ip = p; @@ -781,6 +814,12 @@ set_var_value(gchar *name, gchar *val) { if(var_is("show_status", name)) { cmd_set_status(); } + else if(var_is("always_insert", name)) { + + uzbl.behave.insert_mode = + uzbl.behave.always_insert_mode ? TRUE : FALSE; + update_title(); + } else if (var_is("max_conns", name)) { g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL); @@ -790,8 +829,10 @@ set_var_value(gchar *name, gchar *val) { SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL); } else if (var_is("http_debug", name)) { + //soup_session_remove_feature + // (uzbl.net.soup_session, uzbl.net.soup_logger); soup_session_remove_feature - (uzbl.net.soup_session, uzbl.net.soup_logger); + (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */ /*g_free(uzbl.net.soup_logger);*/ @@ -1309,7 +1350,6 @@ settings_init () { GKeyFile* config = NULL; gboolean res = FALSE; char *saveptr; - gchar** keys = NULL; State *s = &uzbl.state; Network *n = &uzbl.net; Behaviour *b = &uzbl.behave; @@ -1362,86 +1402,17 @@ settings_init () { } if (res) { - b->load_finish_handler= g_key_file_get_value (config, "behavior", "load_finish_handler",NULL); - b->history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); - b->download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); - b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL); - b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); - b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); - b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL); b->reset_command_mode = g_key_file_get_boolean (config, "behavior", "reset_command_mode", NULL); - b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL); - b->status_background = g_key_file_get_string (config, "behavior", "status_background", NULL); - if (! b->fifo_dir) - b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL); - if (! b->socket_dir) - b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); - keys = g_key_file_get_keys (config, "bindings", NULL, NULL); } - printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled")); - printf ("Download manager: %s\n", (b->download_handler ? b->download_handler : "disabled")); - printf ("Cookie handler: %s\n", (b->cookie_handler ? b->cookie_handler : "disabled")); - printf ("Fifo directory: %s\n", (b->fifo_dir ? b->fifo_dir : "disabled")); - printf ("Socket directory: %s\n", (b->socket_dir ? b->socket_dir : "disabled")); - printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE" : "FALSE")); printf ("Reset mode: %s\n" , (b->reset_command_mode ? "TRUE" : "FALSE")); - printf ("Show status: %s\n", (b->show_status ? "TRUE" : "FALSE")); - printf ("Status top: %s\n", (b->status_top ? "TRUE" : "FALSE")); - printf ("Modkey: %s\n", (b->modkey ? b->modkey : "disabled")); - printf ("Status format: %s\n", (b->status_format ? b->status_format : "none")); - - if (!b->modkey) - b->modkey = ""; - - //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED) - gchar* modkeyup = g_utf8_strup (b->modkey, -1); - if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key. - if (g_strrstr (modkeyup,"LOCK") != NULL) b->modmask |= GDK_LOCK_MASK; //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock). - if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key. - if (g_strrstr (modkeyup,"MOD1") != NULL) b->modmask |= GDK_MOD1_MASK; //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key). - if (g_strrstr (modkeyup,"MOD2") != NULL) b->modmask |= GDK_MOD2_MASK; //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). - if (g_strrstr (modkeyup,"MOD3") != NULL) b->modmask |= GDK_MOD3_MASK; //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). - if (g_strrstr (modkeyup,"MOD4") != NULL) b->modmask |= GDK_MOD4_MASK; //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). - if (g_strrstr (modkeyup,"MOD5") != NULL) b->modmask |= GDK_MOD5_MASK; //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier). - if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button. - if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button. - if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button. - if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button. - if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button. - if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10 - if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10 - if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */ - free (modkeyup); - - if (keys) { - int i; - for (i = 0; keys[i]; i++) { - gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL); - - add_binding(g_strstrip(keys[i]), value); - g_free(value); - } - - g_strfreev(keys); - } /* networking options */ if (res) { - b->http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL); n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL); } - - if(!(b->http_debug <= 3)){ - b->http_debug = 0; - fprintf(stderr, "Wrong http_debug level, ignoring.\n"); - } else if (b->http_debug > 0) { - n->soup_logger = soup_logger_new(b->http_debug, -1); - soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger)); - } - if(n->useragent){ char* newagent = malloc(1024); @@ -1471,12 +1442,7 @@ settings_init () { g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL); } - - printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none"); - printf("HTTP logging level: %d\n", b->http_debug); printf("User-agent: %s\n", n->useragent? n->useragent : "default"); - printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0); - printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0); g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL); } @@ -1541,8 +1507,6 @@ main (int argc, char* argv[]) { settings_init (); commands_hash (); - if (uzbl.behave.always_insert_mode) - uzbl.behave.insert_mode = TRUE; GtkWidget* vbox = gtk_vbox_new (FALSE, 0); if (uzbl.behave.status_top) -- cgit v1.2.3 From d6edddd27fd625e69b9b1091e19853b16aa12677 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Fri, 15 May 2009 13:33:45 +0200 Subject: added status_top to cmd parser --- examples/configs/sampleconfig-pipe | 1 + uzbl.c | 49 ++++++++++++++++++++++++++++++++------ uzbl.h | 2 ++ 3 files changed, 45 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe index c25db06..bc5fdca 100644 --- a/examples/configs/sampleconfig-pipe +++ b/examples/configs/sampleconfig-pipe @@ -6,6 +6,7 @@ set modkey = Mod1 set always_insert = 0 #set proxy_url = http://127.0.0.1:8118 set fifo_dir = /tmp +#set status_top = 1 # Key bindings bind j = scroll_vert 20 diff --git a/uzbl.c b/uzbl.c index 8bd952a..1c3bec4 100644 --- a/uzbl.c +++ b/uzbl.c @@ -69,6 +69,7 @@ const struct { { "status_background", (void *)&uzbl.behave.status_background }, { "status_message", (void *)&uzbl.gui.sbar.msg }, { "show_status", (void *)&uzbl.behave.show_status }, + { "status_top", (void *)&uzbl.behave.status_top }, { "insert_mode", (void *)&uzbl.behave.insert_mode }, { "modkey" , (void *)&uzbl.behave.modkey }, { "always_insert" , (void *)&uzbl.behave.always_insert_mode }, @@ -755,6 +756,29 @@ set_modkey() { g_free (modkeyup); } +static void +move_statusbar() { + /* TODO: investigate how to make gtk not warn */ + gtk_widget_ref(uzbl.gui.scrolled_win); + gtk_widget_ref(uzbl.gui.mainbar); + gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win); + gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar); + + if(uzbl.behave.status_top) { + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + } + else { + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + } + + gtk_container_add(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win); + gtk_container_add(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar); + gtk_widget_unref(uzbl.gui.scrolled_win); + gtk_widget_unref(uzbl.gui.mainbar); +} + static gboolean var_is(const char *x, const char *y) { gboolean ret = FALSE; @@ -840,6 +864,9 @@ set_var_value(gchar *name, gchar *val) { soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); } + else if (var_is("status_top", name)) { + move_statusbar(); + } } } return TRUE; @@ -1283,6 +1310,7 @@ create_browser () { GUI *g = &uzbl.gui; GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL); + //main_window_ref = g_object_ref(scrolled_window); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); @@ -1307,6 +1335,10 @@ create_mainbar () { GUI *g = &uzbl.gui; g->mainbar = gtk_hbox_new (FALSE, 0); + + /* keep a reference to the bar so we can re-pack it at runtime*/ + //sbar_ref = g_object_ref(g->mainbar); + g->mainbar_label = gtk_label_new (""); gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE); gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END); @@ -1481,6 +1513,7 @@ save_cookies (SoupMessage *msg, gpointer user_data){ g_slist_free(ck); } + int main (int argc, char* argv[]) { gtk_init (&argc, &argv); @@ -1508,15 +1541,17 @@ main (int argc, char* argv[]) { commands_hash (); - GtkWidget* vbox = gtk_vbox_new (FALSE, 0); - if (uzbl.behave.status_top) - gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0); - if (!uzbl.behave.status_top) - gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0); + uzbl.gui.vbox = gtk_vbox_new (FALSE, 0); + + uzbl.gui.scrolled_win = create_browser(); + create_mainbar(); + /* initial packing */ + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + uzbl.gui.main_window = create_window (); - gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox); + gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); load_uri (uzbl.gui.web_view, uzbl.state.uri); diff --git a/uzbl.h b/uzbl.h index 1da04cc..410d7b9 100644 --- a/uzbl.h +++ b/uzbl.h @@ -41,6 +41,8 @@ typedef struct { /* gui elements */ typedef struct { GtkWidget* main_window; + GtkWidget* scrolled_win; + GtkWidget* vbox; GtkWidget* mainbar; GtkWidget* mainbar_label; GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar -- cgit v1.2.3 From cb0ab53e5c503ec26a8da1a5c04706b43ca71978 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 15 May 2009 14:56:34 +0200 Subject: merge pipe config into dev config --- examples/configs/sampleconfig-dev | 109 +++++++++++++++++++------------------ examples/configs/sampleconfig-pipe | 37 ------------- 2 files changed, 56 insertions(+), 90 deletions(-) delete mode 100644 examples/configs/sampleconfig-pipe (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 119e3a0..40fc67a 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -1,68 +1,71 @@ # example uzbl config. in a real config, we should obey the xdg spec - -# all keys in the behavior group are optional. if not set, the corresponding behavior is disabed. -# bindings_internal denote keys to trigger actions internally in uzbl -# bindings_external denote keys to trigger scripts outside uzbl +# all settings are optional. you can use uzbl without any config at all (but it won't do much) # keyboard behavior is vimstyle by default (all actions -> 1 key). set # always_insert_mode to always be in insert mode and disable going out of it. # if you do this, make sure you've set a modkey so you can reach the actions # from insert mode by combining them with the modkey -set uzbl.behave.history_handler ./examples/scripts/history.sh -set uzbl.behave.download_handler ./examples/scripts/download.sh -set uzbl.behave.cookie_handler ./examples/scripts/cookies.sh -set uzbl.behave.fifo_dir /tmp -set uzbl.behave.socket_dir /tmp -set uzbl.behave.always_insert_mode 0 -set uzbl.behave.modkey Mod1 -set uzbl.behave.show_status 1 -set uzbl.behave.status_top 0 -set uzbl.behave.status_format MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME +# TODO: ability to attach misc things (spawn , script ,.. to internal events) +#set history_handler ./examples/scripts/history.sh +#set download_handler ./examples/scripts/download.sh +#set behave.cookie_handler ./examples/scripts/cookies.sh + + + +# Behaviour and appearance +set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. -set uzbl.behave.status_background #303030 +set status_background = #303030 +set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG +set modkey = Mod1 +set always_insert = 0 +# to start a local socks server, do : ssh -fND localhost:8118 localhost +#set proxy_url = http://127.0.0.1:8118 +#values 0-3 +#set http_debug = 0 +#set useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +# Example user agent containing everything: +#set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +#set max_conns 0 +#set .max_conns_host 0 -# scroll down/up/left/right -bind j scroll_vert 20 -bind k scroll_vert -20 -bind h scroll_horz -20 -bind l scroll_horz 20 -bind b back -bind m forward -bind s stop -bind r reload -bind R reload_ign_cache -bind + zoom_in -bind - zoom_out -bind t toggle uzbl.behave.show_status +set fifo_dir = /tmp +#TODO socket dir +#set status_top = 1 + +# Key bindings +bind j = scroll_vert 20 +bind k = scroll_vert -20 +bind h = scroll_horz -20 +bind l = scroll_horz 20 +bind b = back +bind m = forward +bind s = stop +bind r = reload +bind R = reload_ign_cache +bind + = zoom_in +bind - = zoom_out +bind t = toggle_status #hilight matches -bind /_ search %s +bind /_ = search %s #jump to next -bind ; search -bind gh set uzbl.state.uri http://www.uzbl.org -bind o _ set uzbl.state.uri %s -bind :wiki _ set uzbl.state.uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ set uzbl.state.uri http://www.google.com/search?q=%s -bind i toggle uzbl.behave.insert_mode -bind B spawn ./examples/scripts/insert_bookmark.sh -bind u spawn ./examples/scripts/load_url_from_history.sh -bind U spawn ./examples/scripts/load_url_from_bookmarks.sh -bind ZZ exit -bind S script alert("hi"); +bind ; = search +bind gh = uri http://www.uzbl.org +#TODO: set uri? +bind o _ = uri %s +bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ = uri http://www.google.com/search?q=%s +bind i = insert_mode +#TODO: no 'toggle' command? +bind B = spawn ./examples/scripts/insert_bookmark.sh +bind u = spawn ./examples/scripts/load_url_from_history.sh +bind U = spawn ./examples/scripts/load_url_from_bookmarks.sh +bind ZZ = exit +bind S = script alert("hi"); # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) -bind F script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} #hit f followed by linknumber and ENTER to follow that link -bind f_ script window.location = document.links[%s].href; - - -# to start a local socks server, do : ssh -fND localhost:8118 localhost -set uzbl.net.proxy_url http://127.0.0.1:8118 -#values 0-3 -set uzbl.behave.http_debug = 0 -set uzbl.net.useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) -# Example user agent containing everything: -#set uzbl.net.useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -set uzbl.net.max_conns 0 -set uzbl.net.max_conns_host 0 +bind f_ = script window.location = document.links[%s].href; diff --git a/examples/configs/sampleconfig-pipe b/examples/configs/sampleconfig-pipe deleted file mode 100644 index bc5fdca..0000000 --- a/examples/configs/sampleconfig-pipe +++ /dev/null @@ -1,37 +0,0 @@ -# Behaviour and appearance -set show_status = 1 -set status_background = #303030 -set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG -set modkey = Mod1 -set always_insert = 0 -#set proxy_url = http://127.0.0.1:8118 -set fifo_dir = /tmp -#set status_top = 1 - -# Key bindings -bind j = scroll_vert 20 -bind k = scroll_vert -20 -bind h = scroll_horz -20 -bind l = scroll_horz 20 -bind b = back -bind m = forward -bind s = stop -bind r = reload -bind R = reload_ign_cache -bind + = zoom_in -bind - = zoom_out -bind t = toggle_status -bind /_ = search %s -bind ; = search -bind gh = uri http://www.uzbl.org -bind o _ = uri %s -bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ = uri http://www.google.com/search?q=%s -bind i = insert_mode -bind B = spawn ./examples/scripts/insert_bookmark.sh -bind u = spawn ./examples/scripts/load_url_from_history.sh -bind U = spawn ./examples/scripts/load_url_from_bookmarks.sh -bind ZZ = exit -bind S = script alert("hi"); -bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -bind f_ = script window.location = document.links[%s].href; -- cgit v1.2.3 From 8bb034612bc8342dc50d2b5250793c7535ff2ce2 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 15 May 2009 15:15:14 +0200 Subject: fix for too many always_insert_mode stuff --- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 40fc67a..ae7dea8 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -20,7 +20,7 @@ set show_status = 1 set status_background = #303030 set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG set modkey = Mod1 -set always_insert = 0 +set always_insert_mode = 0 # to start a local socks server, do : ssh -fND localhost:8118 localhost #set proxy_url = http://127.0.0.1:8118 #values 0-3 diff --git a/uzbl.c b/uzbl.c index 67ee0ae..631f338 100644 --- a/uzbl.c +++ b/uzbl.c @@ -72,7 +72,6 @@ const struct { { "status_top", (void *)&uzbl.behave.status_top }, { "insert_mode", (void *)&uzbl.behave.insert_mode }, { "modkey" , (void *)&uzbl.behave.modkey }, - { "always_insert" , (void *)&uzbl.behave.always_insert_mode }, { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler}, { "history_handler", (void *)&uzbl.behave.history_handler }, { "download_handler", (void *)&uzbl.behave.download_handler }, @@ -832,8 +831,7 @@ set_var_value(gchar *name, gchar *val) { if(var_is("show_status", name)) { cmd_set_status(); } - else if(var_is("always_insert", name)) { - + else if(var_is("always_insert_mode", name)) { uzbl.behave.insert_mode = uzbl.behave.always_insert_mode ? TRUE : FALSE; update_title(); @@ -861,12 +859,6 @@ set_var_value(gchar *name, gchar *val) { else if (var_is("status_top", name)) { move_statusbar(); } - else if (var_is("always_insert_mode", name)) { - if (*ip) { - uzbl.behave.insert_mode = TRUE; - update_title(); - } - } } } return TRUE; -- cgit v1.2.3 From 263cb1a9da4030b2fe5e7f1b73721c28915bf002 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 15 May 2009 18:07:44 +0200 Subject: fixes in config --- examples/configs/sampleconfig-dev | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ae7dea8..38f1274 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -10,7 +10,7 @@ # TODO: ability to attach misc things (spawn , script ,.. to internal events) #set history_handler ./examples/scripts/history.sh #set download_handler ./examples/scripts/download.sh -#set behave.cookie_handler ./examples/scripts/cookies.sh +#set cookie_handler ./examples/scripts/cookies.sh @@ -29,7 +29,7 @@ set always_insert_mode = 0 # Example user agent containing everything: #set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) #set max_conns 0 -#set .max_conns_host 0 +#set max_conns_host 0 set fifo_dir = /tmp #TODO socket dir -- cgit v1.2.3 From a759f9ca068fa219d171fcc9d79a4a063818de2d Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 09:23:21 +0200 Subject: support dmenu vertical patch (with gracefull fallback to normal dmenu) --- examples/scripts/load_url_from_bookmarks.sh | 8 +++++++- examples/scripts/load_url_from_history.sh | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 35c772c..032c8fe 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -1,5 +1,11 @@ #!/bin/bash +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch +else + DMENU="dmenu -i" +fi # you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) if [ -f /usr/share/uzbl/examples/data/bookmarks ] then @@ -8,6 +14,6 @@ else file=./examples/data/bookmarks #useful when developing fi -goto=`awk '{print $1}' $file | dmenu -i` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. +goto=`awk '{print $1}' $file | $DMENU` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. #[ -n "$goto" ] && echo "uri $goto" > $4 [ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 3e2e2ee..aef7739 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -2,10 +2,17 @@ # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) history_file=/tmp/uzbl.history +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch +else + DMENU="dmenu -i" +fi + # choose from all entries, sorted and uniqued # goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` # choose from all entries, the first one being current url, and after that all others, sorted and uniqued. -current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | dmenu -i` +current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` #[ -n "$goto" ] && echo "uri $goto" > $4 [ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" -- cgit v1.2.3 From 7d6b9d5e9d61a75110708e002d7381c67bff0343 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 09:36:05 +0200 Subject: fix for handlers in sample config --- examples/configs/sampleconfig-dev | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 38f1274..d42957d 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -8,9 +8,9 @@ # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -#set history_handler ./examples/scripts/history.sh -#set download_handler ./examples/scripts/download.sh -#set cookie_handler ./examples/scripts/cookies.sh +set history_handler = ./examples/scripts/history.sh +set download_handler = ./examples/scripts/download.sh +set cookie_handler = ./examples/scripts/cookies.sh -- cgit v1.2.3 From 87ad07963cdc6caf4a96bcbc485b366536c157b8 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 09:44:44 +0200 Subject: regression fix: different command syntax for setting uris --- examples/scripts/load_url_from_bookmarks.sh | 4 ++-- examples/scripts/load_url_from_history.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 032c8fe..2d19067 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -15,5 +15,5 @@ else fi goto=`awk '{print $1}' $file | $DMENU` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -#[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" +#[ -n "$goto" ] && echo "cmd uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index aef7739..9dd56d2 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -14,5 +14,5 @@ fi # choose from all entries, the first one being current url, and after that all others, sorted and uniqued. current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` -#[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" +#[ -n "$goto" ] && echo "cmd uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" -- cgit v1.2.3 From 2eb9dae768134ee685ee81bb6c257147b552d210 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 09:49:21 +0200 Subject: reenable sockets --- examples/configs/sampleconfig-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index d42957d..cee74cd 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -32,7 +32,7 @@ set always_insert_mode = 0 #set max_conns_host 0 set fifo_dir = /tmp -#TODO socket dir +set socket_dir = /tmp #set status_top = 1 # Key bindings -- cgit v1.2.3 From 262ccb5f3e120f1d48a63dc46ad7e7689a46ad83 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 09:56:42 +0200 Subject: document reset_command_mode in config + reorder a bit --- examples/configs/sampleconfig-dev | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index cee74cd..761a4f9 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -19,7 +19,12 @@ set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG +set status_top = 0 + set modkey = Mod1 +# reset to command mode when new page is loaded +set reset_command_mode = 1 +# this var has precedence over reset_command_mode set always_insert_mode = 0 # to start a local socks server, do : ssh -fND localhost:8118 localhost #set proxy_url = http://127.0.0.1:8118 @@ -33,7 +38,6 @@ set always_insert_mode = 0 set fifo_dir = /tmp set socket_dir = /tmp -#set status_top = 1 # Key bindings bind j = scroll_vert 20 -- cgit v1.2.3 From 242051ada8f13f347ef467007cbcf1290b67f317 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 12:38:53 +0200 Subject: most peole bookmark>history --- examples/configs/sampleconfig-dev | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 761a4f9..fc8bf87 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -64,8 +64,8 @@ bind gg _ = uri http://www.google.com/search?q=%s bind i = insert_mode #TODO: no 'toggle' command? bind B = spawn ./examples/scripts/insert_bookmark.sh -bind u = spawn ./examples/scripts/load_url_from_history.sh -bind U = spawn ./examples/scripts/load_url_from_bookmarks.sh +bind U = spawn ./examples/scripts/load_url_from_history.sh +bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh bind ZZ = exit bind S = script alert("hi"); # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... -- cgit v1.2.3 From 67160e8918ddca8792db46be96e11ce45896df98 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 16 May 2009 14:11:33 +0200 Subject: make handlers working in sample config, pass correct page titles to scripts, in example scripts: save page titles, and if dmenu-vertical is found show more stuff (date, page title, bookmark tags,..) + small stuff --- examples/configs/sampleconfig-dev | 6 +++--- examples/scripts/history.sh | 2 +- examples/scripts/insert_bookmark.sh | 17 +++++++++-------- examples/scripts/load_url_from_bookmarks.sh | 19 +++++++++++-------- examples/scripts/load_url_from_history.sh | 13 ++++++++----- uzbl.c | 6 +++--- 6 files changed, 35 insertions(+), 28 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index fc8bf87..d196c92 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -8,9 +8,9 @@ # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -set history_handler = ./examples/scripts/history.sh -set download_handler = ./examples/scripts/download.sh -set cookie_handler = ./examples/scripts/cookies.sh +set history_handler = ./examples/scripts/history.sh +set download_handler = ./examples/scripts/download.sh +set cookie_handler = ./examples/scripts/cookies.sh diff --git a/examples/scripts/history.sh b/examples/scripts/history.sh index b6671fe..19b5218 100755 --- a/examples/scripts/history.sh +++ b/examples/scripts/history.sh @@ -1,4 +1,4 @@ #!/bin/bash #TODO: strip 'http://' part # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) -echo "$8 $6" >> /tmp/uzbl.history +echo "$8 $6 $7" >> /tmp/uzbl.history diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh index fe18328..180f4cd 100755 --- a/examples/scripts/insert_bookmark.sh +++ b/examples/scripts/insert_bookmark.sh @@ -1,16 +1,17 @@ #!/bin/bash # you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) -if [ -f /usr/share/uzbl/examples/data/bookmarks ] -then - file=/usr/share/uzbl/examples/data/bookmarks # you will probably get permission denied errors here. pick a file in your ~ -else - file=./examples/data/bookmarks #useful when developing -fi + +[ -f /usr/share/uzbl/examples/data/bookmarks ] && file=/usr/share/uzbl/examples/data/bookmarks # you will probably get permission denied errors here. +[ -f $XDG_DATA_HOME/uzbl/bookmarks ] && file=$XDG_DATA_HOME/uzbl/bookmarks +[ -f ./examples/data/bookmarks ] && file=./examples/data/bookmarks #useful when developing +[ -z "$file" ] && exit 1 which zenity &>/dev/null || exit 2 -entry=`zenity --entry --text="Add bookmark. add tags at the end, separated by commas" --entry-text="$6"` +entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` url=`awk '{print $1}' <<< $entry` # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags -echo "$entry" >> $file +echo "$entry" >/dev/null #for some reason we need this.. don't ask me why +echo -e "$entry" >> $file +true \ No newline at end of file diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 2d19067..5ceb52e 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -1,19 +1,22 @@ #!/bin/bash +#NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. + +[ -f /usr/share/uzbl/examples/data/bookmarks ] && file=/usr/share/uzbl/examples/data/bookmarks +[ -f $XDG_DATA_HOME/uzbl/bookmarks ] && file=$XDG_DATA_HOME/uzbl/bookmarks +[ -f ./examples/data/bookmarks ] && file=./examples/data/bookmarks #useful when developing +[ -z "$file" ] && exit 1 + if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # show tags as well + goto=`$DMENU < $file | awk '{print $1}'` else DMENU="dmenu -i" -fi -# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) -if [ -f /usr/share/uzbl/examples/data/bookmarks ] -then - file=/usr/share/uzbl/examples/data/bookmarks -else - file=./examples/data/bookmarks #useful when developing + # because they are all after each other, just show the url, not their tags. + goto=`awk '{print $1}' $file | $DMENU` fi -goto=`awk '{print $1}' $file | $DMENU` #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. #[ -n "$goto" ] && echo "cmd uri $goto" > $4 [ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 9dd56d2..f79a058 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -2,17 +2,20 @@ # you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) history_file=/tmp/uzbl.history +# choose from all entries, sorted and uniqued +# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` + + if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # choose an item in reverse order, showing also the date and page titles + goto=`tac $history_file | $DMENU | awk '{print $3}'` else DMENU="dmenu -i" + # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order + current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` fi -# choose from all entries, sorted and uniqued -# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` - -# choose from all entries, the first one being current url, and after that all others, sorted and uniqued. -current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` #[ -n "$goto" ] && echo "cmd uri $goto" > $4 [ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" diff --git a/uzbl.c b/uzbl.c index 4c65c39..7c0bb94 100644 --- a/uzbl.c +++ b/uzbl.c @@ -712,7 +712,7 @@ run_command_async(const char *command, const char *args) { command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path); g_string_append_printf (to_execute, " '%s' '%s'", - uzbl.state.uri, "TODO title here"); + uzbl.state.uri, uzbl.gui.main_title); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -728,7 +728,7 @@ run_command_sync(const char *command, const char *args, char **stdout) { GString* to_execute = g_string_new (""); gboolean result; g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path); - g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here"); + g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, uzbl.gui.main_title); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -1371,7 +1371,7 @@ create_browser () { g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view); -- cgit v1.2.3 From c738a2d91fd48c52b171f0fdb983e8b308d315f3 Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 16 May 2009 17:35:18 +0300 Subject: Adapt clipboard.sh for new cfg system --- examples/scripts/clipboard.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh index c64b65c..e13f053 100755 --- a/examples/scripts/clipboard.sh +++ b/examples/scripts/clipboard.sh @@ -9,7 +9,7 @@ selection=$(xclip -o) case $action in "yank" ) echo -n "$url" | xclip;; - "goto" ) echo "uri $selection" > "$fifo";; + "goto" ) echo "act uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac -- cgit v1.2.3 From ff86e511bda0313edbb6ead21415747b8eb88d29 Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 16 May 2009 17:58:18 +0300 Subject: Replace cmd with act in scripts --- examples/scripts/load_url_from_bookmarks.sh | 4 ++-- examples/scripts/load_url_from_history.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 5ceb52e..821b136 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -18,5 +18,5 @@ else goto=`awk '{print $1}' $file | $DMENU` fi -#[ -n "$goto" ] && echo "cmd uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" +#[ -n "$goto" ] && echo "act uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index f79a058..cf2ceb2 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -17,5 +17,5 @@ else current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` fi -#[ -n "$goto" ] && echo "cmd uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "cmd uri $goto" +#[ -n "$goto" ] && echo "act uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" -- cgit v1.2.3 From e4a23d55521aff58cd0c4b4b4db42f81f869b698 Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 16 May 2009 20:51:11 +0300 Subject: Added examples of some new features in sampleconfig-dev --- examples/configs/sampleconfig-dev | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index d196c92..7653407 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,6 +11,13 @@ set history_handler = ./examples/scripts/history.sh set download_handler = ./examples/scripts/download.sh set cookie_handler = ./examples/scripts/cookies.sh +set minimum_font_size = 6 +set default_font_size = 11 + +# use with bind ... = sh +# notice the '' - it's a spacer to keep bash and sh from shifting the positional parameters +# by one, so they will appear in the same position as with scripts invoked via spawn +set shell_cmd = sh -c %s '' @@ -44,6 +51,8 @@ bind j = scroll_vert 20 bind k = scroll_vert -20 bind h = scroll_horz -20 bind l = scroll_horz 20 +bind << = scroll_begin +bind >> = scroll_end bind b = back bind m = forward bind s = stop @@ -52,8 +61,9 @@ bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out bind t = toggle_status -#hilight matches -bind /_ = search %s +# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called +# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. +bind /* = search %s #jump to next bind ; = search bind gh = uri http://www.uzbl.org @@ -68,6 +78,10 @@ bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh bind ZZ = exit bind S = script alert("hi"); +# example showing how to use sh +# it sends a command to the fifo, whose path is told via a positional param +# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it +bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -- cgit v1.2.3 From 6396f7bb44754be1ca9570a641aa1b7f9808dce4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 09:35:15 +0200 Subject: fix for pick right field in load_from_history --- examples/scripts/load_url_from_history.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index cf2ceb2..ec54631 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -10,7 +10,8 @@ if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then DMENU="dmenu -i -xs -rs -l 10" # vertical patch # choose an item in reverse order, showing also the date and page titles - goto=`tac $history_file | $DMENU | awk '{print $3}'` + # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. + goto=`tac $history_file | $DMENU | cut -d ' ' -f -3 | awk '{print $NF}'` else DMENU="dmenu -i" # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order -- cgit v1.2.3 From ae20aa3c63ad47bcc24859a239ddb9aeed40a5a2 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 10:53:13 +0200 Subject: SELECTED_URI variable + allow variable replacing in window title in both states --- README | 2 +- docs/TODO | 2 +- examples/configs/sampleconfig-dev | 5 +++- uzbl.c | 60 ++++++++++++++------------------------- uzbl.h | 7 +++++ 5 files changed, 34 insertions(+), 42 deletions(-) (limited to 'examples') diff --git a/README b/README index bc5baca..bdc7fa1 100644 --- a/README +++ b/README @@ -77,7 +77,7 @@ TODO ### VARIABLE REPLACEMENT Some of the variables are interpreted: -* title bar: variable replacement (not yet actually) +* title bar: variable replacement (long and short version, depending if statusbar is visible or not) * user agent: variable replacement * statusbar: variable replacement + pango markup diff --git a/docs/TODO b/docs/TODO index 6258432..d501643 100644 --- a/docs/TODO +++ b/docs/TODO @@ -14,6 +14,7 @@ More or less in order of importance/urgency * implement getting feedback from socket * scrolling: make page up and page down configurable. * show % of location in statusbar/title if page doesn't fit entirely on view. +* conditionals in format strings: eg if(SELECTED_URI) { "-> SELECTED_URI" } or another smart way to achieve the same. * make default window size configurable, and optional * on uzbl.org commits overview: add date+time and repository * how to handle different content types? (text-plain, image/png, application/pdf,... maybe a map of content-type to uzbl/command @@ -34,7 +35,6 @@ More or less in order of importance/urgency * improve DCOMMIT macro. what if WC is dirty? what if user downloaded tarball without .git? * DARCH is not correct (should be at runtime) * keybinds to open "next" or "previous" by looking for next/prev links and/or looking for numbers in the uri we can inc/decrement -* variable replacing for title bar in "statusbar_visible" and statusbar_invisible states * settings iterating "state generator" so we can "open in new window" again. * handler for (broken) ssl certs. * handlers for mailto: and maybe other thingies? diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 7653407..71fc46e 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -25,8 +25,11 @@ set shell_cmd = sh -c %s '' set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSG +set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI set status_top = 0 +# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) +set title_format_short = TITLE - Uzbl browser +set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI set modkey = Mod1 # reset to command mode when new page is loaded diff --git a/uzbl.c b/uzbl.c index aa5e440..c2a6bd9 100644 --- a/uzbl.c +++ b/uzbl.c @@ -69,6 +69,8 @@ const struct { { "status_top", (void *)&uzbl.behave.status_top }, { "status_format", (void *)&uzbl.behave.status_format }, { "status_background", (void *)&uzbl.behave.status_background }, + { "title_format_long", (void *)&uzbl.behave.title_format_long }, + { "title_format_short", (void *)&uzbl.behave.title_format_short }, { "insert_mode", (void *)&uzbl.behave.insert_mode }, { "always_insert_mode", (void *)&uzbl.behave.always_insert_mode }, { "reset_command_mode", (void *)&uzbl.behave.reset_command_mode }, @@ -301,7 +303,7 @@ link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpoin (void) page; (void) title; (void) data; - //ADD HOVER URL TO WINDOW TITLE + //Set selected_url state variable uzbl.state.selected_url[0] = '\0'; if (link) { strcpy (uzbl.state.selected_url, link); @@ -632,6 +634,11 @@ expand_template(const char *template) { uzbl.gui.main_title? g_markup_printf_escaped("%s", uzbl.gui.main_title):""); break; + case SYM_SELECTED_URI: + g_string_append(ret, + uzbl.state.selected_url? + g_markup_printf_escaped("%s", uzbl.state.selected_url):""); + break; case SYM_NAME: buf = itos(uzbl.xwin); g_string_append(ret, @@ -795,7 +802,9 @@ get_var_value(gchar *name) { if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { if(var_is("status_format", name) - || var_is("useragent", name)) { + || var_is("useragent", name) + || var_is("title_format_short", name) + || var_is("title_format_long", name)) { printf("VAR: %s VALUE: %s\n", name, (char *)*p); } else printf("VAR: %s VALUE: %d\n", name, (int)*p); } @@ -856,6 +865,8 @@ set_var_value(gchar *name, gchar *val) { if(var_is("status_message", name) || var_is("status_background", name) || var_is("status_format", name) + || var_is("title_format_long", name) + || var_is("title_format_short", name) || var_is("load_finish_handler", name) || var_is("history_handler", name) || var_is("download_handler", name) @@ -1249,42 +1260,11 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL * static void update_title (void) { - GString* string_long = g_string_new (""); - GString* string_short = g_string_new (""); - char* iname = NULL; - gchar *statln; - int iname_len; - State *s = &uzbl.state; Behaviour *b = &uzbl.behave; - if(s->instance_name) { - iname_len = strlen(s->instance_name)+4; - iname = malloc(iname_len); - snprintf(iname, iname_len, "<%s> ", s->instance_name); - - g_string_prepend(string_long, iname); - g_string_prepend(string_short, iname); - free(iname); - } - - g_string_append_printf(string_long, "%s ", s->keycmd->str); - if (!b->always_insert_mode) - g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] ")); - if (uzbl.gui.main_title) { - g_string_append (string_long, uzbl.gui.main_title); - g_string_append (string_short, uzbl.gui.main_title); - } - g_string_append (string_long, " - Uzbl browser"); - g_string_append (string_short, " - Uzbl browser"); - if (s->selected_url[0]!=0) { - g_string_append_printf (string_long, " -> (%s)", s->selected_url); - } - - gchar* title_long = g_string_free (string_long, FALSE); - gchar* title_short = g_string_free (string_short, FALSE); - if (b->show_status) { - gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short); + gchar *statln; + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), expand_template(b->title_format_short)); // TODO: we should probably not do this every time we want to update the title..? statln = expand_template(uzbl.behave.status_format); gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln); @@ -1296,11 +1276,8 @@ update_title (void) { } g_free(statln); } else { - gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long); + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), expand_template(b->title_format_long)); } - - g_free (title_long); - g_free (title_short); } static gboolean @@ -1591,6 +1568,11 @@ settings_init () { } if (!uzbl.behave.status_format) uzbl.behave.status_format = g_strdup(STATUS_DEFAULT); + if (!uzbl.behave.title_format_long) + uzbl.behave.title_format_long = g_strdup(TITLE_LONG_DEFAULT); + if (!uzbl.behave.title_format_short) + uzbl.behave.title_format_short = g_strdup(TITLE_SHORT_DEFAULT); + g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL); } diff --git a/uzbl.h b/uzbl.h index 506f1d3..368ad46 100644 --- a/uzbl.h +++ b/uzbl.h @@ -12,12 +12,16 @@ */ #define STATUS_DEFAULT " MODE KEYCMD (LOAD_PROGRESS%) TITLE - Uzbl browser" +#define TITLE_LONG_DEFAULT "KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI" +#define TITLE_SHORT_DEFAULT "TITLE - Uzbl browser " + enum { /* statusbar symbols */ SYM_TITLE, SYM_URI, SYM_NAME, SYM_LOADPRGS, SYM_LOADPRGSBAR, SYM_KEYCMD, SYM_MODE, SYM_MSG, + SYM_SELECTED_URI, /* useragent symbols */ SYM_WK_MAJ, SYM_WK_MIN, SYM_WK_MIC, SYM_SYSNAME, SYM_NODENAME, @@ -33,6 +37,7 @@ const struct { {"NAME", SYM_NAME}, {"URI", SYM_URI}, {"TITLE", SYM_TITLE}, + {"SELECTED_URI", SYM_SELECTED_URI}, {"KEYCMD", SYM_KEYCMD}, {"MODE", SYM_MODE}, {"MSG", SYM_MSG}, @@ -124,6 +129,8 @@ typedef struct { typedef struct { gchar* load_finish_handler; gchar* status_format; + gchar* title_format_short; + gchar* title_format_long; gchar* status_background; gchar* history_handler; gchar* fifo_dir; -- cgit v1.2.3 From c66bf8d5ead4e1834c5427af90ea2776f66bd78e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 11:29:09 +0200 Subject: pretteh default colors --- examples/scripts/load_url_from_bookmarks.sh | 6 +++--- examples/scripts/load_url_from_history.sh | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 821b136..21ea33d 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -6,16 +6,16 @@ [ -f $XDG_DATA_HOME/uzbl/bookmarks ] && file=$XDG_DATA_HOME/uzbl/bookmarks [ -f ./examples/data/bookmarks ] && file=./examples/data/bookmarks #useful when developing [ -z "$file" ] && exit 1 - +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then DMENU="dmenu -i -xs -rs -l 10" # vertical patch # show tags as well - goto=`$DMENU < $file | awk '{print $1}'` + goto=`$DMENU $COLORS < $file | awk '{print $1}'` else DMENU="dmenu -i" # because they are all after each other, just show the url, not their tags. - goto=`awk '{print $1}' $file | $DMENU` + goto=`awk '{print $1}' $file | $DMENU $COLORS` fi #[ -n "$goto" ] && echo "act uri $goto" > $4 diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index ec54631..ea6e7aa 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -4,18 +4,17 @@ history_file=/tmp/uzbl.history # choose from all entries, sorted and uniqued # goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` - - +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then DMENU="dmenu -i -xs -rs -l 10" # vertical patch # choose an item in reverse order, showing also the date and page titles # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. - goto=`tac $history_file | $DMENU | cut -d ' ' -f -3 | awk '{print $NF}'` + goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` else DMENU="dmenu -i" # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU` + current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` fi #[ -n "$goto" ] && echo "act uri $goto" > $4 -- cgit v1.2.3 From ec40bc9cc14226a94a45c51e56bf70a5173fd379 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 11:48:05 +0200 Subject: load a page by default --- examples/configs/sampleconfig-dev | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 71fc46e..9196f4c 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -90,3 +90,6 @@ bind XS = sh 'echo "act script alert (\"This is sent by the shell via bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} #hit f followed by linknumber and ENTER to follow that link bind f_ = script window.location = document.links[%s].href; + +# "home" page if you will +set uri = uzbl.org -- cgit v1.2.3 From fbd34b5b157d1a847005ef7e0784ca25f4bb0aee Mon Sep 17 00:00:00 2001 From: Peter Suschlik Date: Sun, 17 May 2009 16:01:33 +0200 Subject: Search reverse. Use vim keys (n, N and /, ?). --- examples/configs/sampleconfig-dev | 4 +++- uzbl.c | 17 ++++++++++++++--- uzbl.h | 5 ++++- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 901421b..752a191 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -67,8 +67,10 @@ bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. bind /* = search %s +bind ?* = search_reverse %s #jump to next -bind ; = search +bind n = search +bind N = search_reverse bind gh = uri http://www.uzbl.org #TODO: set uri? bind o _ = uri %s diff --git a/uzbl.c b/uzbl.c index bbc2c27..ca37eab 100644 --- a/uzbl.c +++ b/uzbl.c @@ -411,7 +411,8 @@ static struct {char *name; Command command;} cmdlist[] = { "spawn", spawn }, { "sh", spawn_sh }, { "exit", close_uzbl }, - { "search", search_text }, + { "search", search_forward_text }, + { "search_reverse", search_reverse_text }, { "insert_mode", set_insert_mode }, { "runcmd", runcmd } }; @@ -483,7 +484,7 @@ run_js (WebKitWebView * web_view, const gchar *param) { } static void -search_text (WebKitWebView *page, const char *param) { +search_text (WebKitWebView *page, const char *param, const gboolean forward) { if ((param) && (param[0] != '\0')) { strcpy(uzbl.state.searchtx, param); } @@ -493,10 +494,20 @@ search_text (WebKitWebView *page, const char *param) { webkit_web_view_unmark_text_matches (page); webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0); webkit_web_view_set_highlight_text_matches (page, TRUE); - webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE); + webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE); } } +static void +search_forward_text (WebKitWebView *page, const char *param) { + search_text(page, param, TRUE); +} + +static void +search_reverse_text (WebKitWebView *page, const char *param) { + search_text(page, param, FALSE); +} + static void new_window_load_uri (const gchar * uri) { GString* to_execute = g_string_new (""); diff --git a/uzbl.h b/uzbl.h index 368ad46..11a4ad7 100644 --- a/uzbl.h +++ b/uzbl.h @@ -345,7 +345,10 @@ static void settings_init (); static void -search_text (WebKitWebView *page, const char *param); +search_forward_text (WebKitWebView *page, const char *param); + +static void +search_reverse_text (WebKitWebView *page, const char *param); static void run_js (WebKitWebView * web_view, const gchar *param); -- cgit v1.2.3 From 2a552a8707a84158d34f4fd4f28fee9aa07f2ff6 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 16:09:59 +0200 Subject: working yank script --- examples/configs/sampleconfig-dev | 3 +++ examples/scripts/yank.sh | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 9196f4c..faf0162 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -79,6 +79,9 @@ bind i = insert_mode bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh +# with the sample yank script, you can yank one of the arguments into clipboard/selection +bind yurl = spawn ./examples/scripts/yank.sh 8 primary +bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard bind ZZ = exit bind S = script alert("hi"); # example showing how to use sh diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh index 0429f19..d4926be 100755 --- a/examples/scripts/yank.sh +++ b/examples/scripts/yank.sh @@ -1,10 +1,11 @@ # use this script to pipe any variable to xclip, so you have it in your clipboard -exit -# this script is not done yet - -# can we make this universal? -# add xclip to optdeps +# in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) +# make the 2nd argument one of : primary, secondary, clipboard. +# examples: +# bind yurl = spawn ./examples/scripts/yank.sh 8 primary +# bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard which xclip &>/dev/null || exit 1 +[ "$2" == primary -o "$2" == secondary -o "$2" == clipboard ] || exit 2 -echo -n `eval "$3"` #| xclip \ No newline at end of file +echo -n "${!1}" | xclip -selection $2 \ No newline at end of file -- cgit v1.2.3 From 2ca1c57a3d8dcdfdc8b3ff0ed0f48fed8a0d5006 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 16:11:29 +0200 Subject: bring back non-dev sample config --- examples/configs/sampleconfig | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 examples/configs/sampleconfig (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig new file mode 100644 index 0000000..92253ab --- /dev/null +++ b/examples/configs/sampleconfig @@ -0,0 +1,98 @@ + +# example uzbl config. in a real config, we should obey the xdg spec +# all settings are optional. you can use uzbl without any config at all (but it won't do much) + +# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the actions +# from insert mode by combining them with the modkey + +# TODO: ability to attach misc things (spawn , script ,.. to internal events) +set history_handler = /usr/share/uzbl/examples/scripts/history.sh +set download_handler = /usr/share/uzbl/examples/scripts/download.sh +set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh +set minimum_font_size = 6 +set default_font_size = 11 + +# use with bind ... = sh +# notice the '' - it's a spacer to keep bash and sh from shifting the positional parameters +# by one, so they will appear in the same position as with scripts invoked via spawn +set shell_cmd = sh -c %s '' + + + +# Behaviour and appearance +set show_status = 1 +# you can optionally use this setting to override the background color of the statusbar from your GTK theme. +set status_background = #303030 +set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_top = 0 +# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) +set title_format_short = TITLE - Uzbl browser +set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI + +set modkey = Mod1 +# reset to command mode when new page is loaded +set reset_command_mode = 1 +# this var has precedence over reset_command_mode +set always_insert_mode = 0 +# to start a local socks server, do : ssh -fND localhost:8118 localhost +#set proxy_url = http://127.0.0.1:8118 +#values 0-3 +#set http_debug = 0 +#set useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +# Example user agent containing everything: +#set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +#set max_conns 0 +#set max_conns_host 0 + +set fifo_dir = /tmp +set socket_dir = /tmp + +# Key bindings +bind j = scroll_vert 20 +bind k = scroll_vert -20 +bind h = scroll_horz -20 +bind l = scroll_horz 20 +bind << = scroll_begin +bind >> = scroll_end +bind b = back +bind m = forward +bind s = stop +bind r = reload +bind R = reload_ign_cache +bind + = zoom_in +bind - = zoom_out +bind t = toggle_status +# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called +# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. +bind /* = search %s +#jump to next +bind ; = search +bind gh = uri http://www.uzbl.org +#TODO: set uri? +bind o _ = uri %s +bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ = uri http://www.google.com/search?q=%s +bind i = insert_mode +#TODO: no 'toggle' command? +bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh +bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh +bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh +# with the sample yank script, you can yank one of the arguments into clipboard/selection +bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 8 primary +bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard +bind ZZ = exit +bind S = script alert("hi"); +# example showing how to use sh +# it sends a command to the fifo, whose path is told via a positional param +# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it +bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' +# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... +#hit F to toggle the Hints (now in form of link numbering) +bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +#hit f followed by linknumber and ENTER to follow that link +bind f_ = script window.location = document.links[%s].href; + +# "home" page if you will +set uri = uzbl.org -- cgit v1.2.3 From 8c4c9681b72632356094beece7f844633a2f4922 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 16:14:35 +0200 Subject: syntax fixes --- examples/configs/sampleconfig | 12 ++++++------ examples/configs/sampleconfig-dev | 13 +++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 92253ab..f8fa7cb 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -37,14 +37,14 @@ set reset_command_mode = 1 # this var has precedence over reset_command_mode set always_insert_mode = 0 # to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 +#set proxy_url = http://127.0.0.1:8118 #values 0-3 -#set http_debug = 0 -#set useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +#set http_debug = 0 +#set useragent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) # Example user agent containing everything: -#set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -#set max_conns 0 -#set max_conns_host 0 +#set useragent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +#set max_conns = 0 +#set max_conns_host = 0 set fifo_dir = /tmp set socket_dir = /tmp diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index faf0162..36df808 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -36,15 +36,16 @@ set modkey = Mod1 set reset_command_mode = 1 # this var has precedence over reset_command_mode set always_insert_mode = 0 + # to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 +#set proxy_url = http://127.0.0.1:8118 #values 0-3 -#set http_debug = 0 -#set useragent uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +#set http_debug = 0 +#set useragent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) # Example user agent containing everything: -#set useragent Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) -#set max_conns 0 -#set max_conns_host 0 +#set useragent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +#set max_conns = 0 +#set max_conns_host = 0 set fifo_dir = /tmp set socket_dir = /tmp -- cgit v1.2.3 From 260b76c7c46e8260fd63fe84c917c390a7e18b2b Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 17:21:52 +0200 Subject: cleanup after merging in from splattael --- examples/configs/sampleconfig-dev | 2 +- uzbl.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 835a617..ec2dbbb 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -10,7 +10,7 @@ # TODO: ability to attach misc things (spawn , script ,.. to internal events) set history_handler = ./examples/scripts/history.sh set download_handler = ./examples/scripts/download.sh -#set cookie_handler = ./examples/scripts/cookies.sh not done yet.. +set cookie_handler = ./examples/scripts/cookies.sh set minimum_font_size = 6 set default_font_size = 11 diff --git a/uzbl.h b/uzbl.h index 11a4ad7..49a275d 100644 --- a/uzbl.h +++ b/uzbl.h @@ -344,6 +344,9 @@ find_xdg_file (int xdg_type, char* filename); static void settings_init (); +static void +search_text (WebKitWebView *page, const char *param, const gboolean forward); + static void search_forward_text (WebKitWebView *page, const char *param); -- cgit v1.2.3 From b0de6d517e337db87f04e2593ee484ea6c5f23f5 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 17:29:49 +0200 Subject: keep configs in sync --- examples/configs/sampleconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index f8fa7cb..e5ae9a2 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -67,8 +67,10 @@ bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. bind /* = search %s +bind ?* = search_reverse %s #jump to next -bind ; = search +bind n = search +bind N = search_reverse bind gh = uri http://www.uzbl.org #TODO: set uri? bind o _ = uri %s -- cgit v1.2.3 From ae5ccd70b0170418780509578587cbadbcf636bd Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 17:59:30 +0200 Subject: disable cookies again --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index e5ae9a2..7a94b19 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -10,7 +10,7 @@ # TODO: ability to attach misc things (spawn , script ,.. to internal events) set history_handler = /usr/share/uzbl/examples/scripts/history.sh set download_handler = /usr/share/uzbl/examples/scripts/download.sh -set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh +#set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh does not work yet set minimum_font_size = 6 set default_font_size = 11 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ec2dbbb..31b49ab 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -10,7 +10,7 @@ # TODO: ability to attach misc things (spawn , script ,.. to internal events) set history_handler = ./examples/scripts/history.sh set download_handler = ./examples/scripts/download.sh -set cookie_handler = ./examples/scripts/cookies.sh +#set cookie_handler = ./examples/scripts/cookies.sh does not work yet set minimum_font_size = 6 set default_font_size = 11 -- cgit v1.2.3 From 8516adf58ac158a3ad4fb66adf1df08c55c716a9 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 17 May 2009 19:26:03 +0200 Subject: more more fancy xclip related things in sample configs --- examples/configs/sampleconfig | 6 ++++++ examples/configs/sampleconfig-dev | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index e5ae9a2..ada1134 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -84,6 +84,12 @@ bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmar # with the sample yank script, you can yank one of the arguments into clipboard/selection bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 8 primary bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard +# does the same as yurl but without needing a script +bind y2url = sh 'echo -n $6 | xclip' +# go the page from primary selection +bind p = sh "echo act uri `xclip -selection primary -o` > $4" +# go to the page in clipboard +bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit bind S = script alert("hi"); # example showing how to use sh diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ec2dbbb..337da7b 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -85,6 +85,12 @@ bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection bind yurl = spawn ./examples/scripts/yank.sh 8 primary bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard +# does the same as yurl but without needing a script +bind y2url = sh 'echo -n $6 | xclip' +# go the page from primary selection +bind p = sh "echo act uri `xclip -selection primary -o` > $4" +# go to the page in clipboard +bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit bind S = script alert("hi"); # example showing how to use sh -- cgit v1.2.3 From 82cf9578d821a68d275f1ee13f182d85913acb04 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Sun, 17 May 2009 22:29:17 +0100 Subject: Changed insert_mode into toggle_insert_mode. --- README | 2 +- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 46 +++++++++++++++++++-------------------- uzbl.h | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/README b/README index e170e67..bdfb403 100644 --- a/README +++ b/README @@ -161,7 +161,7 @@ actions follows: * `exit` * `search ` * `search_reverse ` -* `insert_mode` +* `toggle_insert_mode` * `runcmd` - can be used for running a command such as SET or BIND diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index ada1134..3cca85c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -76,7 +76,7 @@ bind gh = uri http://www.uzbl.org bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s -bind i = insert_mode +bind i = toggle_insert_mode #TODO: no 'toggle' command? bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 337da7b..de60187 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -77,7 +77,7 @@ bind gh = uri http://www.uzbl.org bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s -bind i = insert_mode +bind i = toggle_insert_mode #TODO: no 'toggle' command? bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh diff --git a/uzbl.c b/uzbl.c index 1b8e8bc..2c3f8b3 100644 --- a/uzbl.c +++ b/uzbl.c @@ -394,27 +394,27 @@ VIEWFUNC(go_forward) static struct {char *name; Command command;} cmdlist[] = { - { "back", view_go_back }, - { "forward", view_go_forward }, - { "scroll_vert", scroll_vert }, - { "scroll_horz", scroll_horz }, - { "scroll_begin", scroll_begin }, - { "scroll_end", scroll_end }, - { "reload", view_reload, }, - { "reload_ign_cache", view_reload_bypass_cache}, - { "stop", view_stop_loading, }, - { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). - { "zoom_out", view_zoom_out, }, - { "uri", load_uri }, - { "script", run_js }, - { "toggle_status", toggle_status_cb }, - { "spawn", spawn }, - { "sh", spawn_sh }, - { "exit", close_uzbl }, - { "search", search_forward_text }, - { "search_reverse", search_reverse_text }, - { "insert_mode", set_insert_mode }, - { "runcmd", runcmd } + { "back", view_go_back }, + { "forward", view_go_forward }, + { "scroll_vert", scroll_vert }, + { "scroll_horz", scroll_horz }, + { "scroll_begin", scroll_begin }, + { "scroll_end", scroll_end }, + { "reload", view_reload, }, + { "reload_ign_cache", view_reload_bypass_cache}, + { "stop", view_stop_loading, }, + { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). + { "zoom_out", view_zoom_out, }, + { "uri", load_uri }, + { "script", run_js }, + { "toggle_status", toggle_status_cb }, + { "spawn", spawn }, + { "sh", spawn_sh }, + { "exit", close_uzbl }, + { "search", search_forward_text }, + { "search_reverse", search_reverse_text }, + { "toggle_insert_mode", toggle_insert_mode }, + { "runcmd", runcmd } }; static void @@ -457,11 +457,11 @@ file_exists (const char * filename) { } void -set_insert_mode(WebKitWebView *page, const gchar *param) { +toggle_insert_mode(WebKitWebView *page, const gchar *param) { (void)page; (void)param; - uzbl.behave.insert_mode = TRUE; + uzbl.behave.insert_mode = ! uzbl.behave.insert_mode; update_title(); } diff --git a/uzbl.h b/uzbl.h index 49a275d..251d270 100644 --- a/uzbl.h +++ b/uzbl.h @@ -258,7 +258,7 @@ static bool file_exists (const char * filename); void -set_insert_mode(WebKitWebView *page, const gchar *param); +toggle_insert_mode(WebKitWebView *page, const gchar *param); static void load_uri (WebKitWebView * web_view, const gchar *param); -- cgit v1.2.3 From c37edf6ed469e36d2e75f9a25dec3e656bb0c02e Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Sun, 17 May 2009 22:42:32 +0100 Subject: Added an optional param to toggle_insert_mode, which allows to specify whether to enable or disable it. --- README | 3 ++- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 11 ++++++++++- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/README b/README index bdfb403..733d4c8 100644 --- a/README +++ b/README @@ -161,7 +161,8 @@ actions follows: * `exit` * `search ` * `search_reverse ` -* `toggle_insert_mode` +* `toggle_insert_mode ` + - if the optional state is 0, disable insert mode. If 1, enable insert mode. * `runcmd` - can be used for running a command such as SET or BIND diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 3cca85c..bca4314 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -77,7 +77,7 @@ bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s bind i = toggle_insert_mode -#TODO: no 'toggle' command? +bind I = toggle_insert_mode 0 # disable insert mode (1 to enable) bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index de60187..ba916cc 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -78,7 +78,7 @@ bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s bind i = toggle_insert_mode -#TODO: no 'toggle' command? +bind I = toggle_insert_mode 0 # disable insert mode (1 to enable) bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh diff --git a/uzbl.c b/uzbl.c index 2c3f8b3..2b91be1 100644 --- a/uzbl.c +++ b/uzbl.c @@ -461,7 +461,16 @@ toggle_insert_mode(WebKitWebView *page, const gchar *param) { (void)page; (void)param; - uzbl.behave.insert_mode = ! uzbl.behave.insert_mode; + if (param != NULL) { + if (strcmp (param, "0") == 0) { + uzbl.behave.insert_mode = FALSE; + } else { + uzbl.behave.insert_mode = TRUE; + } + } else { + uzbl.behave.insert_mode = ! uzbl.behave.insert_mode; + } + update_title(); } -- cgit v1.2.3 From fe14095ad924b92232fad1f810fa2223e474fb75 Mon Sep 17 00:00:00 2001 From: DuClare Date: Mon, 18 May 2009 21:55:41 +0300 Subject: Document quotation & handlers in sampleconfig, fix leaks and breaks --- examples/configs/sampleconfig-dev | 19 ++++++++----- uzbl.c | 57 ++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ec2dbbb..a92d249 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -8,16 +8,17 @@ # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -set history_handler = ./examples/scripts/history.sh -set download_handler = ./examples/scripts/download.sh +# Usually you want to spawn a script to handle things, but any action (such as sh) can be used +set history_handler = spawn ./examples/scripts/history.sh +set download_handler = spawn ./examples/scripts/download.sh + +# TODO: you can't use actions in cookie handler yet. set cookie_handler = ./examples/scripts/cookies.sh set minimum_font_size = 6 set default_font_size = 11 # use with bind ... = sh -# notice the '' - it's a spacer to keep bash and sh from shifting the positional parameters -# by one, so they will appear in the same position as with scripts invoked via spawn -set shell_cmd = sh -c %s '' +set shell_cmd = sh -c @@ -79,6 +80,8 @@ bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?searc bind gg _ = uri http://www.google.com/search?q=%s bind i = insert_mode #TODO: no 'toggle' command? +# Enclose the executable in double quotes if it has spaces. Any additional parameters you use will +# appear AFTER the default parameters bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh @@ -90,7 +93,11 @@ bind S = script alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' +# The body of the shell command should be one parameter, so if it has spaces like here, +# you must enclose it in double quotes. Remember to escape (and double-escape) quotes and backslashes +# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file +# path, fifo & socket dirs, etc.) +bind XS = sh "echo \"act script alert (\\\"This is sent by the shell via a fifo\\\")\" > \"$4\"" # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} diff --git a/uzbl.c b/uzbl.c index cf27c13..5812256 100644 --- a/uzbl.c +++ b/uzbl.c @@ -234,7 +234,8 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download); if (uzbl.state.verbose) printf("Download -> %s\n",uri); - run_command(uzbl.behave.download_handler, 0, &uri, FALSE, NULL); + /* if urls not escaped, we may have to escape and quote uri before this call */ + run_handler(uzbl.behave.download_handler, uri); } return (FALSE); } @@ -368,7 +369,7 @@ log_history_cb () { char date [80]; time ( &rawtime ); timeinfo = localtime ( &rawtime ); - strftime (date, 80, " \"%Y-%m-%d %H:%M:%S\"", timeinfo); + strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo); run_handler(uzbl.behave.history_handler, date); } } @@ -756,9 +757,8 @@ run_command (const gchar *command, const guint npre, const gchar **args, sharg_append(a, uzbl.state.uri); sharg_append(a, uzbl.gui.main_title); - for (i = npre; i < g_strv_length(args); i++) + for (i = npre; i < g_strv_length((gchar**)args); i++) sharg_append(a, args[i]); - gboolean result; if (sync) result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, stdout, NULL, NULL, &err); @@ -766,9 +766,15 @@ run_command (const gchar *command, const guint npre, const gchar **args, NULL, NULL, NULL, &err); if (uzbl.state.verbose) { - gchar *cli = g_strjoinv(" ", (gchar **)a->data); - printf("Called %s. Result: %s\n", cli, (result ? "TRUE" : "FALSE" )); - g_free (cli); + GString *s = g_string_new("spawned:"); + for (i = 0; i < (a->len); i++) { + gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i)); + g_string_append_printf(s, " %s", qarg); + g_free (qarg); + } + g_string_append_printf(s, " -- result: %s", (result ? "true" : "false")); + printf("%s\n", s->str); + g_string_free(s, TRUE); } if (err) { g_printerr("error on run_command: %s\n", err->message); @@ -776,7 +782,7 @@ run_command (const gchar *command, const guint npre, const gchar **args, } g_free (pid); g_free (xwin); - g_array_free (a, FALSE); + g_array_free (a, TRUE); return result; } @@ -811,7 +817,7 @@ spawn(WebKitWebView *web_view, const char *param) { //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after gchar **cmd = split_quoted(param); if (cmd) run_command(cmd[0], 0, &cmd[1], FALSE, NULL); - g_strfreev (cmd); + g_strfreev ((gchar**)cmd); } static void @@ -1553,8 +1559,8 @@ run_handler (const gchar *act, const gchar *args) { char **spawnparts; spawnparts = split_quoted(parts[1]); g_string_append_printf(a, "\"%s\"", spawnparts[0]); - g_string_append(a, args); /* append handler args before user args */ - int i; + if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */ + guint i; for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ g_string_append_printf(a, " \"%s\"", spawnparts[i]); parse_command(parts[0], a->str); @@ -1699,15 +1705,19 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use gchar * stdout = NULL; soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); - GString* args = g_string_new (""); + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + gchar *action = g_strdup ("GET"); SoupURI * soup_uri = soup_message_get_uri(msg); - g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path); - run_command(uzbl.behave.cookie_handler, 0, args->str, TRUE, &stdout); - //run_handler(uzbl.behave.cookie_handler); + sharg_append(a, action); + sharg_append(a, soup_uri->host); + sharg_append(a, soup_uri->path); + run_command(uzbl.behave.cookie_handler, 0, a->data, TRUE, &stdout); /* TODO: use handler */ + //run_handler(uzbl.behave.cookie_handler); /* TODO: global stdout pointer, spawn_sync */ if(stdout) { soup_message_headers_replace (msg->request_headers, "Cookie", stdout); } - g_string_free(args, TRUE); + g_free (action); + g_array_free(a, TRUE); } static void @@ -1717,12 +1727,17 @@ save_cookies (SoupMessage *msg, gpointer user_data){ char *cookie; for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ cookie = soup_cookie_to_set_cookie_header(ck->data); - GString* args = g_string_new (""); + GArray *a = g_array_new(TRUE, FALSE, sizeof(gchar*)); SoupURI * soup_uri = soup_message_get_uri(msg); - g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie); - run_command(uzbl.behave.cookie_handler, 0, args->str, FALSE, NULL); - g_string_free(args, TRUE); - free(cookie); + gchar *action = strdup("PUT"); + sharg_append(a, action); + sharg_append(a, soup_uri->host); + sharg_append(a, soup_uri->path); + sharg_append(a, cookie); + run_command(uzbl.behave.cookie_handler, 0, a->data, FALSE, NULL); + g_free (cookie); + g_free (action); + g_array_free(a, TRUE); } g_slist_free(ck); } -- cgit v1.2.3 From 870b771adee7360b178648ba44534bda559d8168 Mon Sep 17 00:00:00 2001 From: DuClare Date: Mon, 18 May 2009 22:03:52 +0300 Subject: Update sampleconfig --- examples/configs/sampleconfig | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index ada1134..444a20a 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -8,16 +8,17 @@ # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -set history_handler = /usr/share/uzbl/examples/scripts/history.sh -set download_handler = /usr/share/uzbl/examples/scripts/download.sh +# You can use any action in place of spawn +set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh +set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh + +# TODO: cookie_handler can't take arbitrary actionsyet set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh set minimum_font_size = 6 set default_font_size = 11 # use with bind ... = sh -# notice the '' - it's a spacer to keep bash and sh from shifting the positional parameters -# by one, so they will appear in the same position as with scripts invoked via spawn -set shell_cmd = sh -c %s '' +set shell_cmd = sh -c @@ -85,7 +86,7 @@ bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmar bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 8 primary bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard # does the same as yurl but without needing a script -bind y2url = sh 'echo -n $6 | xclip' +bind y2url = sh "echo -n $6 | xclip" # go the page from primary selection bind p = sh "echo act uri `xclip -selection primary -o` > $4" # go to the page in clipboard @@ -95,7 +96,9 @@ bind S = script alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' +# Parameters are separated by spaces and the script body must be one parameter, so enclose it in +# DOUBLE quotes and escape any inner quotes using backslashes +bind XS = sh "echo \"act script alert (\\\"This is sent by the shell via a fifo\\\")\" > \"$4\"" # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -- cgit v1.2.3 From 8268ba59ef4347354aa7d4e20d9a0d5194170e4f Mon Sep 17 00:00:00 2001 From: DuClare Date: Mon, 18 May 2009 22:07:58 +0300 Subject: Update session.sh --- examples/scripts/session.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh index 5087af0..b8e2bd6 100755 --- a/examples/scripts/session.sh +++ b/examples/scripts/session.sh @@ -13,9 +13,9 @@ sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. UZBL="uzbl" # add custom flags and whatever here. fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -thisfifo="$5" -act="$1" -url="$7" +thisfifo="$4" +act="$8" +url="$6" case $act in "launch" ) -- cgit v1.2.3 From 1cfdb853c5296f5b510f35a90d5abc449eab6af6 Mon Sep 17 00:00:00 2001 From: Barrucadu Date: Mon, 18 May 2009 20:08:56 +0100 Subject: Renamed "script" to "js". Added "script" command which executes an external JS file. Moved hinting to an external JS file. I renamed "script" to "js" because we use "sh" for one-line *sh scripts, so "js" for one-line JS scripts is nice and consistent. --- README | 4 +++- examples/configs/sampleconfig | 6 +++--- examples/configs/sampleconfig-dev | 6 +++--- examples/scripts/hint.js | 26 ++++++++++++++++++++++++++ uzbl.c | 30 +++++++++++++++++++++++++++++- uzbl.h | 3 +++ 6 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 examples/scripts/hint.js (limited to 'examples') diff --git a/README b/README index 733d4c8..b46c236 100644 --- a/README +++ b/README @@ -147,9 +147,11 @@ actions follows: * `zoom_in` * `zoom_out` * `uri
` -* `script ` +* `js ` - execute the javascript in `` - remember that the commands, and thus actions, must not contain line breaks +* `script ` + - execute the javascript in `` * `toggle_status` * `spawn ` - runs a command; see EXTERNAL SCRIPTS for details diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index bca4314..db4abc2 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -91,16 +91,16 @@ bind p = sh "echo act uri `xclip -selection primary -o` > $4" # go to the page in clipboard bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit -bind S = script alert("hi"); +bind S = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) -bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +bind F= script /usr/share/uzbl/examples/scripts/hint.js #hit f followed by linknumber and ENTER to follow that link -bind f_ = script window.location = document.links[%s].href; +bind f_ = js window.location = document.links[%s].href; # "home" page if you will set uri = uzbl.org diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ba916cc..fb240dd 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -92,16 +92,16 @@ bind p = sh "echo act uri `xclip -selection primary -o` > $4" # go to the page in clipboard bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit -bind S = script alert("hi"); +bind S = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it bind XS = sh 'echo "act script alert (\"This is sent by the shell via a fifo\")" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) -bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} +bind F= script ./examples/scripts/hint.js #hit f followed by linknumber and ENTER to follow that link -bind f_ = script window.location = document.links[%s].href; +bind f_ = js window.location = document.links[%s].href; # "home" page if you will set uri = uzbl.org diff --git a/examples/scripts/hint.js b/examples/scripts/hint.js new file mode 100644 index 0000000..ec7f1e2 --- /dev/null +++ b/examples/scripts/hint.js @@ -0,0 +1,26 @@ +for (var i=0; i < document.links.length; i++) { + var uzblid = 'uzbl_link_hint_'; + var li = document.links[i]; + var pre = document.getElementById(uzblid+i); + + if (pre) { + li.removeChild(pre); + } else { + var hint = document.createElement('div'); + hint.setAttribute('id',uzblid+i); + hint.innerHTML = i; + hint.style.display='inline'; + hint.style.lineHeight='90%'; + hint.style.backgroundColor='red'; + hint.style.color='white'; + hint.style.fontSize='small-xx'; + hint.style.fontWeight='light'; + hint.style.margin='0px'; + hint.style.padding='2px'; + hint.style.position='absolute'; + hint.style.textDecoration='none'; + hint.style.left=li.style.left; + hint.style.top=li.style.top; + li.insertAdjacentElement('afterBegin',hint); + } +} diff --git a/uzbl.c b/uzbl.c index 4606130..d0a06b4 100644 --- a/uzbl.c +++ b/uzbl.c @@ -429,7 +429,8 @@ static struct {char *name; Command command;} cmdlist[] = { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). { "zoom_out", view_zoom_out, }, { "uri", load_uri }, - { "script", run_js }, + { "js", run_js }, + { "script", run_external_js }, { "toggle_status", toggle_status_cb }, { "spawn", spawn }, { "sh", spawn_sh }, @@ -515,6 +516,33 @@ run_js (WebKitWebView * web_view, const gchar *param) { webkit_web_view_execute_script (web_view, param); } +static void +run_external_js (WebKitWebView * web_view, const gchar *param) { + if (param) { + FILE* fp = fopen (param, "r"); + gchar* buffer = malloc(512); + gchar* js = NULL; + + if (fp != NULL) { + while (fgets (buffer, 512, fp) != NULL) { + if (js == NULL) { + js = g_strdup ((const gchar*) buffer); + } else { + gchar* newjs = g_strconcat (js, buffer, NULL); + js = newjs; + } + bzero (buffer, strlen (buffer)); + } + webkit_web_view_execute_script (web_view, js); + } else { + fprintf (stderr, "JavaScript file '%s' not be read.\n", param); + } + fclose (fp); + g_free (buffer); + g_free (js); + } +} + static void search_text (WebKitWebView *page, const char *param, const gboolean forward) { if ((param) && (param[0] != '\0')) { diff --git a/uzbl.h b/uzbl.h index 4ae42a6..0d8be65 100644 --- a/uzbl.h +++ b/uzbl.h @@ -360,6 +360,9 @@ search_reverse_text (WebKitWebView *page, const char *param); static void run_js (WebKitWebView * web_view, const gchar *param); +static void +run_external_js (WebKitWebView * web_view, const gchar *param); + static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data); -- cgit v1.2.3 From 2fdee627933de64c564688238f7bee93079a0238 Mon Sep 17 00:00:00 2001 From: DuClare Date: Tue, 19 May 2009 09:40:07 +0300 Subject: Update sampleconf* for single quotes --- examples/configs/sampleconfig | 4 ++-- examples/configs/sampleconfig-dev | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 444a20a..69156e2 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -97,8 +97,8 @@ bind S = script alert("hi"); # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it # Parameters are separated by spaces and the script body must be one parameter, so enclose it in -# DOUBLE quotes and escape any inner quotes using backslashes -bind XS = sh "echo \"act script alert (\\\"This is sent by the shell via a fifo\\\")\" > \"$4\"" +# quotes and escape any inner quotes using backslashes +bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index fa4be91..ea3ea6f 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -80,7 +80,7 @@ bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?searc bind gg _ = uri http://www.google.com/search?q=%s bind i = insert_mode #TODO: no 'toggle' command? -# Enclose the executable in double quotes if it has spaces. Any additional parameters you use will +# Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh @@ -100,10 +100,10 @@ bind S = script alert("hi"); # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it # The body of the shell command should be one parameter, so if it has spaces like here, -# you must enclose it in double quotes. Remember to escape (and double-escape) quotes and backslashes +# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -bind XS = sh "echo \"act script alert (\\\"This is sent by the shell via a fifo\\\")\" > \"$4\"" +bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} -- cgit v1.2.3 From d228014222c889eb61150a5aa9b2efaf5259b880 Mon Sep 17 00:00:00 2001 From: DuClare Date: Tue, 19 May 2009 10:25:21 +0300 Subject: Fix useragent syms in sampleconfig* --- examples/configs/sampleconfig | 4 ++-- examples/configs/sampleconfig-dev | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 69156e2..dfe99d6 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -41,9 +41,9 @@ set always_insert_mode = 0 #set proxy_url = http://127.0.0.1:8118 #values 0-3 #set http_debug = 0 -#set useragent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) # Example user agent containing everything: -#set useragent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) #set max_conns = 0 #set max_conns_host = 0 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ea3ea6f..2197fd9 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -42,9 +42,9 @@ set always_insert_mode = 0 #set proxy_url = http://127.0.0.1:8118 #values 0-3 #set http_debug = 0 -#set useragent = uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) +#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) # Example user agent containing everything: -#set useragent = Uzbl (Webkit %webkit-major%.%webkit-minor%.%webkit-micro%) (%sysname% %nodename% %kernrel% %kernver% %arch-system% [%arch-uzbl%]) (Commit %commit%) +set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) #set max_conns = 0 #set max_conns_host = 0 -- cgit v1.2.3 From 355fa7c0d712c2b7a15bf15d8b12c078d4310085 Mon Sep 17 00:00:00 2001 From: DuClare Date: Tue, 19 May 2009 14:24:05 +0300 Subject: Finish argv, fix sampleconfig-dev --- examples/configs/sampleconfig-dev | 5 +- uzbl.c | 101 +++++++++++++++++++++----------------- uzbl.h | 2 +- 3 files changed, 59 insertions(+), 49 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 2197fd9..d80b927 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -95,7 +95,7 @@ bind p = sh "echo act uri `xclip -selection primary -o` > $4" # go to the page in clipboard bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit -bind S = script alert("hi"); +bind S = script 'alert("hi");' # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -103,7 +103,8 @@ bind S = script alert("hi"); # you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' +bind XS = sh 'echo "act script \'alert (\\\"This is sent by the shell via a fifo\\\")\'" > "$4"' + # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) bind F= script for (var i=0; i < document.links.length; i++) {var uzblid = 'uzbl_link_hint_';var li = document.links[i];var pre = document.getElementById(uzblid+i);if (pre) {li.removeChild(pre);} else {var hint = document.createElement('div');hint.setAttribute('id',uzblid+i);hint.innerHTML = i;hint.style.display='inline';hint.style.lineHeight='90%';hint.style.backgroundColor='red';hint.style.color='white';hint.style.fontSize='small-xx';hint.style.fontWeight='light';hint.style.margin='0px';hint.style.padding='2px';hint.style.position='absolute';hint.style.textDecoration='none';hint.style.left=li.style.left;hint.style.top=li.style.top;li.insertAdjacentElement('afterBegin',hint);}} diff --git a/uzbl.c b/uzbl.c index 41d8cff..763004c 100644 --- a/uzbl.c +++ b/uzbl.c @@ -137,7 +137,7 @@ static GOptionEntry entries[] = { NULL, 0, 0, 0, NULL, NULL, NULL } }; -typedef void (*Command)(WebKitWebView*, const char *); +typedef void (*Command)(WebKitWebView*, GArray *argv); /* --- UTILITY FUNCTIONS --- */ @@ -149,6 +149,9 @@ itos(int val) { return g_strdup(tmp); } +static gchar* +argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } + static char * str_replace (const char* search, const char* replace, const char* string) { gchar **buf; @@ -293,9 +296,9 @@ cmd_set_status() { } static void -toggle_status_cb (WebKitWebView* page, const char *param) { +toggle_status_cb (WebKitWebView* page, GArray *argv) { (void)page; - (void)param; + (void)argv; if (uzbl.behave.show_status) { gtk_widget_hide(uzbl.gui.mainbar); @@ -395,7 +398,7 @@ log_history_cb () { /* VIEW funcs (little webkit wrappers) */ -#define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);} +#define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);} VIEWFUNC(reload) VIEWFUNC(reload_bypass_cache) VIEWFUNC(stop_loading) @@ -473,37 +476,42 @@ file_exists (const char * filename) { } static void -set_insert_mode(WebKitWebView *page, const gchar *param) { +set_insert_mode(WebKitWebView *page, GArray *argv) { (void)page; - (void)param; + (void)argv; uzbl.behave.insert_mode = TRUE; update_title(); } static void -load_uri (WebKitWebView * web_view, const gchar *param) { - if (param) { - GString* newuri = g_string_new (param); - if (g_strrstr (param, "://") == NULL) +load_uri (WebKitWebView * web_view, GArray *argv) { /* TODO: tell load_uri doesn't want splicing */ + if (argv_idx(argv, 0)) { + gchar *u = g_strjoinv(" ", (gchar**)argv->data); + GString* newuri = g_string_new (u); + if (g_strrstr (u, "://") == NULL) g_string_prepend (newuri, "http://"); /* if we do handle cookies, ask our handler for them */ webkit_web_view_load_uri (web_view, newuri->str); g_string_free (newuri, TRUE); + g_free (u); } } static void -run_js (WebKitWebView * web_view, const gchar *param) { - if (param) - webkit_web_view_execute_script (web_view, param); +run_js (WebKitWebView * web_view, GArray *argv) { /* TODO: tell run_js doesn't want splicing */ + if (argv_idx(argv, 0)) { + gchar *body = g_strjoinv(" ", (gchar**)argv->data); + webkit_web_view_execute_script (web_view, body); + g_free(body); + } } static void -search_text (WebKitWebView *page, const char *param, const gboolean forward) { - if ((param) && (param[0] != '\0')) { - uzbl.state.searchtx = g_strdup(param); - } +search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { /* TODO: "" */ + if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) + uzbl.state.searchtx = g_strjoinv(" ", (gchar**)argv->data); + if (uzbl.state.searchtx != NULL) { if (uzbl.state.verbose) printf ("Searching: %s\n", uzbl.state.searchtx); @@ -517,13 +525,13 @@ search_text (WebKitWebView *page, const char *param, const gboolean forward) { } static void -search_forward_text (WebKitWebView *page, const char *param) { - search_text(page, param, TRUE); +search_forward_text (WebKitWebView *page, GArray *argv) { + search_text(page, argv, TRUE); } static void -search_reverse_text (WebKitWebView *page, const char *param) { - search_text(page, param, FALSE); +search_reverse_text (WebKitWebView *page, GArray *argv) { + search_text(page, argv, FALSE); } static void @@ -546,9 +554,9 @@ new_window_load_uri (const gchar * uri) { } static void -close_uzbl (WebKitWebView *page, const char *param) { +close_uzbl (WebKitWebView *page, GArray *argv) { (void)page; - (void)param; + (void)argv; gtk_main_quit (); } @@ -819,6 +827,8 @@ static gchar** split_quoted(const gchar* src, const gboolean unquote) { /* split on unquoted space, return array of strings; remove a layer of quotes and backslashes if unquote */ + if (!src) return NULL; + gboolean dq = FALSE; gboolean sq = FALSE; GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); @@ -851,16 +861,14 @@ split_quoted(const gchar* src, const gboolean unquote) { } static void -spawn(WebKitWebView *web_view, const char *param) { +spawn(WebKitWebView *web_view, GArray *argv) { (void)web_view; //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after - gchar **cmd = split_quoted(param, TRUE); - if (cmd) run_command(cmd[0], 0, &cmd[1], FALSE, NULL); - g_strfreev ((gchar**)cmd); + if (argv_idx(argv, 0)) run_command(argv_idx(argv, 0), 0, argv->data + sizeof(gchar*), FALSE, NULL); } static void -spawn_sh(WebKitWebView *web_view, const char *param) { +spawn_sh(WebKitWebView *web_view, GArray *argv) { (void)web_view; if (!uzbl.behave.shell_cmd) { g_printerr ("spawn_sh: shell_cmd is not set!\n"); @@ -869,21 +877,15 @@ spawn_sh(WebKitWebView *web_view, const char *param) { guint i; gchar *spacer = g_strdup(""); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + g_array_insert_val(argv, 1, spacer); gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); - gchar **p = split_quoted(param, TRUE); + for (i = 1; i < g_strv_length(cmd); i++) - sharg_append(a, cmd[i]); - sharg_append(a, p[0]); /* the first param comes right after shell_cmd; - the rest come after default args */ - sharg_append(a, spacer); - for (i = 1; i < g_strv_length(p); i++) - sharg_append(a, p[i]); - if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, a->data, FALSE, NULL); + g_array_prepend_val(argv, cmd[i]); + + if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, argv->data, FALSE, NULL); g_free (spacer); g_strfreev (cmd); - g_strfreev (p); - g_array_free (a, FALSE); } static void @@ -891,7 +893,7 @@ parse_command(const char *cmd, const char *param) { Command c; if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) { - int i; + guint i; gchar **par = split_quoted(param, TRUE); GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); for (i = 0; i < g_strv_length(par); i++) @@ -900,7 +902,7 @@ parse_command(const char *cmd, const char *param) { g_strfreev (par); g_array_free (a, TRUE); } else - fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd); + g_printerr ("command \"%s\" not understood. ignoring.\n", cmd); } /* command parser */ @@ -1019,7 +1021,10 @@ set_var_value(gchar *name, gchar *val) { else if(var_is("uri", name)) { if(*p) free(*p); *p = g_strdup(val); - load_uri(uzbl.gui.web_view, (const gchar*)*p); + GArray *a = g_array_new(TRUE, FALSE, sizeof(gchar*)); + g_array_append_val(a, *p); + load_uri(uzbl.gui.web_view, a); + g_array_free(a, TRUE); } else if(var_is("proxy_url", name)) { if(*p) free(*p); @@ -1103,9 +1108,13 @@ set_var_value(gchar *name, gchar *val) { } static void -runcmd(WebKitWebView* page, const char *param) { +runcmd(WebKitWebView* page, GArray *argv) { /* TODO: tell runcmd doesn't want args spliced + or just wait 'till actions and commands are + merged :] */ (void) page; - parse_cmd_line(param); + gchar *ctl_line = g_strjoinv(" ", (gchar**)argv->data); + parse_cmd_line(ctl_line); + g_free (ctl_line); } static void @@ -1862,8 +1871,8 @@ main (int argc, char* argv[]) { create_stdin(); - if(uzbl.state.uri) - load_uri (uzbl.gui.web_view, uzbl.state.uri); + //if(uzbl.state.uri) + // load_uri (uzbl.gui.web_view, uzbl.state.uri); gtk_main (); diff --git a/uzbl.h b/uzbl.h index f2f907e..6b5f630 100644 --- a/uzbl.h +++ b/uzbl.h @@ -354,7 +354,7 @@ static void settings_init (); static void -search_text (WebKitWebView *page, const char *param, const gboolean forward); +search_text (WebKitWebView *page, GArray *argv, const gboolean forward); static void search_forward_text (WebKitWebView *page, GArray *argv); -- cgit v1.2.3 From 757b51da21442ffc4f3b39dfe173999bfcb8a3c8 Mon Sep 17 00:00:00 2001 From: DuClare Date: Tue, 19 May 2009 14:54:28 +0300 Subject: Disable splitting for some actions, fix sampleconfig-dev --- examples/configs/sampleconfig-dev | 4 +- uzbl.c | 100 +++++++++++++++++++------------------- uzbl.h | 2 +- 3 files changed, 52 insertions(+), 54 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index d80b927..3f9b5fa 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -95,7 +95,7 @@ bind p = sh "echo act uri `xclip -selection primary -o` > $4" # go to the page in clipboard bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" bind ZZ = exit -bind S = script 'alert("hi");' +bind S = script alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -103,7 +103,7 @@ bind S = script 'alert("hi");' # you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -bind XS = sh 'echo "act script \'alert (\\\"This is sent by the shell via a fifo\\\")\'" > "$4"' +bind XS = sh 'echo "act script alert (\\"This is sent by the shell via a fifo\\")" > "$4"' # Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... #hit F to toggle the Hints (now in form of link numbering) diff --git a/uzbl.c b/uzbl.c index 763004c..d699387 100644 --- a/uzbl.c +++ b/uzbl.c @@ -411,29 +411,29 @@ VIEWFUNC(go_forward) /* -- command to callback/function map for things we cannot attach to any signals */ // TODO: reload -static struct {char *name; Command command;} cmdlist[] = -{ - { "back", view_go_back }, - { "forward", view_go_forward }, - { "scroll_vert", scroll_vert }, - { "scroll_horz", scroll_horz }, - { "scroll_begin", scroll_begin }, - { "scroll_end", scroll_end }, - { "reload", view_reload, }, - { "reload_ign_cache", view_reload_bypass_cache}, - { "stop", view_stop_loading, }, - { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). - { "zoom_out", view_zoom_out, }, - { "uri", load_uri }, - { "script", run_js }, - { "toggle_status", toggle_status_cb }, - { "spawn", spawn }, - { "sh", spawn_sh }, - { "exit", close_uzbl }, - { "search", search_forward_text }, - { "search_reverse", search_reverse_text }, - { "insert_mode", set_insert_mode }, - { "runcmd", runcmd } +static struct {char *name; Command command[2];} 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}, }, + { "uri", {load_uri, NOSPLIT} }, + { "script", {run_js, NOSPLIT} }, + { "toggle_status", {toggle_status_cb, 0} }, + { "spawn", {spawn, 0} }, + { "sh", {spawn_sh, 0} }, + { "exit", {close_uzbl, 0} }, + { "search", {search_forward_text, NOSPLIT} }, + { "search_reverse", {search_reverse_text, NOSPLIT} }, + { "insert_mode", {set_insert_mode, 0} }, + { "runcmd", {runcmd, NOSPLIT} } }; static void @@ -485,32 +485,27 @@ set_insert_mode(WebKitWebView *page, GArray *argv) { } static void -load_uri (WebKitWebView * web_view, GArray *argv) { /* TODO: tell load_uri doesn't want splicing */ +load_uri (WebKitWebView *web_view, GArray *argv) { if (argv_idx(argv, 0)) { - gchar *u = g_strjoinv(" ", (gchar**)argv->data); - GString* newuri = g_string_new (u); - if (g_strrstr (u, "://") == NULL) + GString* newuri = g_string_new (argv_idx(argv, 0)); + if (g_strrstr (argv_idx(argv, 0), "://") == NULL) g_string_prepend (newuri, "http://"); /* if we do handle cookies, ask our handler for them */ webkit_web_view_load_uri (web_view, newuri->str); g_string_free (newuri, TRUE); - g_free (u); } } static void -run_js (WebKitWebView * web_view, GArray *argv) { /* TODO: tell run_js doesn't want splicing */ - if (argv_idx(argv, 0)) { - gchar *body = g_strjoinv(" ", (gchar**)argv->data); - webkit_web_view_execute_script (web_view, body); - g_free(body); - } +run_js (WebKitWebView * web_view, GArray *argv) { + if (argv_idx(argv, 0)) + webkit_web_view_execute_script (web_view, argv_idx(argv, 0)); } static void -search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { /* TODO: "" */ +search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) - uzbl.state.searchtx = g_strjoinv(" ", (gchar**)argv->data); + uzbl.state.searchtx = g_strdup(argv_idx(argv, 0)); if (uzbl.state.searchtx != NULL) { if (uzbl.state.verbose) @@ -890,17 +885,24 @@ spawn_sh(WebKitWebView *web_view, GArray *argv) { static void parse_command(const char *cmd, const char *param) { - Command c; + Command *c; if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) { - guint i; - gchar **par = split_quoted(param, TRUE); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - for (i = 0; i < g_strv_length(par); i++) - sharg_append(a, par[i]); - c(uzbl.gui.web_view, a); - g_strfreev (par); - g_array_free (a, TRUE); + + guint i; + gchar **par = split_quoted(param, TRUE); + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + + if (c[1]) { /* don't split */ + sharg_append(a, param); + } else { + for (i = 0; i < g_strv_length(par); i++) + sharg_append(a, par[i]); + } + c[0](uzbl.gui.web_view, a); + g_strfreev (par); + g_array_free (a, TRUE); + } else g_printerr ("command \"%s\" not understood. ignoring.\n", cmd); } @@ -1108,13 +1110,9 @@ set_var_value(gchar *name, gchar *val) { } static void -runcmd(WebKitWebView* page, GArray *argv) { /* TODO: tell runcmd doesn't want args spliced - or just wait 'till actions and commands are - merged :] */ +runcmd(WebKitWebView* page, GArray *argv) { (void) page; - gchar *ctl_line = g_strjoinv(" ", (gchar**)argv->data); - parse_cmd_line(ctl_line); - g_free (ctl_line); + parse_cmd_line(argv_idx(argv, 0)); } static void diff --git a/uzbl.h b/uzbl.h index 6b5f630..892d03b 100644 --- a/uzbl.h +++ b/uzbl.h @@ -14,7 +14,7 @@ #define STATUS_DEFAULT " MODE KEYCMD (LOAD_PROGRESS%) TITLE - Uzbl browser" #define TITLE_LONG_DEFAULT "KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI" #define TITLE_SHORT_DEFAULT "TITLE - Uzbl browser " - +#define NOSPLIT ((void*)1) enum { /* statusbar symbols */ -- cgit v1.2.3 From f67e723ba4c2332bec87c9a09ee661da41c5dcb9 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Wed, 20 May 2009 11:25:16 +0200 Subject: fix modkey --- examples/scripts/load_url_from_history.sh | 4 +-- uzbl.c | 41 ++++++++++++++----------------- 2 files changed, 20 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index ea6e7aa..649c6b7 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -17,5 +17,5 @@ else current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` fi -#[ -n "$goto" ] && echo "act uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" +[ -n "$goto" ] && echo "act uri $goto" > $4 +#[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" diff --git a/uzbl.c b/uzbl.c index f3b94ca..abb8cc0 100644 --- a/uzbl.c +++ b/uzbl.c @@ -57,8 +57,20 @@ static Uzbl uzbl; +typedef void (*Command)(WebKitWebView*, GArray *argv); + +/* commandline arguments (set initial values for the state variables) */ +static GOptionEntry entries[] = +{ + { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load at startup (equivalent to 'set uri = URI')", "URI" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", NULL }, + { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" }, + { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; -/* define names and pointers to all config specific variables */ + +/* associate command names to their properties */ typedef const struct { void **ptr; int type; @@ -84,7 +96,7 @@ const struct { { "insert_mode", {.ptr = (void *)&uzbl.behave.insert_mode, .type = TYPE_INT, .func = NULL}}, { "always_insert_mode", {.ptr = (void *)&uzbl.behave.always_insert_mode, .type = TYPE_INT, .func = cmd_always_insert_mode}}, { "reset_command_mode", {.ptr = (void *)&uzbl.behave.reset_command_mode, .type = TYPE_INT, .func = NULL}}, - { "modkey" , {.ptr = (void *)&uzbl.behave.modkey, .type = TYPE_STRING, .func = cmd_modkey}}, + { "modkey", {.ptr = (void *)&uzbl.behave.modkey, .type = TYPE_STRING, .func = cmd_modkey}}, { "load_finish_handler",{.ptr = (void *)&uzbl.behave.load_finish_handler, .type = TYPE_STRING, .func = NULL}}, { "load_start_handler", {.ptr = (void *)&uzbl.behave.load_start_handler, .type = TYPE_STRING, .func = NULL}}, { "load_commit_handler",{.ptr = (void *)&uzbl.behave.load_commit_handler, .type = TYPE_STRING, .func = NULL}}, @@ -138,17 +150,6 @@ make_var_to_name_hash() { } } -/* commandline arguments (set initial values for the state variables) */ -static GOptionEntry entries[] = -{ - { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load at startup (equivalent to 'set uri = URI')", "URI" }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", NULL }, - { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" }, - { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" }, - { NULL, 0, 0, 0, NULL, NULL, NULL } -}; - -typedef void (*Command)(WebKitWebView*, GArray *argv); /* --- UTILITY FUNCTIONS --- */ @@ -1045,9 +1046,10 @@ cmd_modkey() { buf = g_utf8_strup(uzbl.behave.modkey, -1); uzbl.behave.modmask = 0; - + if(uzbl.behave.modkey) free(uzbl.behave.modkey); + uzbl.behave.modkey = buf; for (i = 0; modkeys[i].key != NULL; i++) { if (g_strrstr(uzbl.behave.modkey, modkeys[i].key)) @@ -1062,7 +1064,7 @@ cmd_useragent() { buf = set_useragent(uzbl.net.useragent); if(uzbl.net.useragent) free(uzbl.net.useragent); - + uzbl.net.useragent = buf?buf:g_strdup(""); } @@ -1089,10 +1091,8 @@ move_statusbar() { static gboolean set_var_value(gchar *name, gchar *val) { - void *p = NULL; uzbl_cmdprop *c = NULL; char *endp = NULL; - char *buf=NULL; if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { /* check for the variable type */ @@ -1100,17 +1100,12 @@ set_var_value(gchar *name, gchar *val) { free(*c->ptr); *c->ptr = g_strdup(val); } else if(c->type == TYPE_INT) { - int *ip = c->ptr; + int *ip = GPOINTER_TO_INT(c->ptr); *ip = (int)strtoul(val, &endp, 10); } /* invoke a command specific function */ if(c->func) c->func(); - - /* this will be removed as soon as we have converted to - * the callback interface - */ - p = *c->ptr; } return TRUE; } -- cgit v1.2.3 From 1f8f2ae900a1b3b98d3438eb927782e7968a1ebf Mon Sep 17 00:00:00 2001 From: Jan Kolkmeier Date: Wed, 20 May 2009 21:18:46 +0200 Subject: fixed the download script (+ improvements?) --- examples/scripts/download.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh index 41c408e..8078cc8 100755 --- a/examples/scripts/download.sh +++ b/examples/scripts/download.sh @@ -1,2 +1,12 @@ #!/bin/bash -wget $6 +# A bit more advanced, try some pattern matching on the link to determine +# a target location. pushd and popd might be better than plain cd... +if [[ $8 =~ .*(.torrent) ]] +then + pushd /your/place/for/torrent/files +else + pushd /your/place/for/usual/downloads +fi +# Some sites block the default wget --user-agent... +wget --user-agent=Firefox $8 +popd -- cgit v1.2.3 From 8923aac8bd5af5bfb3748db28dd77a7d07e9b852 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 20 May 2009 21:47:04 +0200 Subject: fix for insert mode --- examples/configs/sampleconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index b19b850..cbdaf05 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -78,7 +78,8 @@ bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s bind i = toggle_insert_mode -bind I = toggle_insert_mode 0 # disable insert mode (1 to enable) +# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting +bind I = toggle_insert_mode 0 bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh -- cgit v1.2.3 From 7202d86bb3ccc5093975a42c7c7f81b1c44f265a Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 20 May 2009 21:47:50 +0200 Subject: fix for insert mode --- examples/configs/sampleconfig-dev | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index a8a1672..c21a6ae 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -79,7 +79,8 @@ bind o _ = uri %s bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s bind i = toggle_insert_mode -bind I = toggle_insert_mode 0 # disable insert mode (1 to enable) +# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting +bind I = toggle_insert_mode 0 # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters bind B = spawn ./examples/scripts/insert_bookmark.sh -- cgit v1.2.3 From b5f27664ac13c33a68b04d862b12024d1c1beaf0 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 20 May 2009 22:51:36 +0200 Subject: document progressbar tweaking --- README | 2 +- examples/configs/sampleconfig | 4 ++++ examples/configs/sampleconfig-dev | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/README b/README index bf4b35c..d0a615b 100644 --- a/README +++ b/README @@ -54,7 +54,7 @@ Time to change that! ### CONFIGURATION / CONTROL: The general idea is that uzbl by default is very bare bones. you can send it commands to update settings and perform actions, through various interfaces. (TODO: some default settings) -For examples, please see the sample config(s). +For examples of the possibilities, please see the sample config(s). There are several interfaces to interact with uzbl: * uzbl --config : will be read line by line, and the commands in it will be executed. useful to configure uzbl at startup. diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index cbdaf05..6386dd8 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -31,6 +31,10 @@ set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI +# set the characters to use for, and the width of the progress bar +set status_pbar_done = * +set status_pbar_pending = - +set status_pbar_width = 12 set modkey = Mod1 # reset to command mode when new page is loaded diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index c21a6ae..d20e98b 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -31,6 +31,10 @@ set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI +# set the characters to use for, and the width of the progress bar +set status_pbar_done = * +set status_pbar_pending = - +set status_pbar_width = 12 set modkey = Mod1 # reset to command mode when new page is loaded -- cgit v1.2.3 From 4227e4a5d0b78b66d8ead088a4164f6985af0b37 Mon Sep 17 00:00:00 2001 From: Jan Kolkmeier Date: Thu, 21 May 2009 00:04:51 +0200 Subject: Two link-following-scripts and how to use them --- examples/configs/sampleconfig | 9 +- examples/scripts/follow_Numbers.js | 225 +++++++++++++++++++++++++++++ examples/scripts/follow_Numbers_Strings.js | 205 ++++++++++++++++++++++++++ 3 files changed, 434 insertions(+), 5 deletions(-) create mode 100644 examples/scripts/follow_Numbers.js create mode 100644 examples/scripts/follow_Numbers_Strings.js (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 6386dd8..15e9c5c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -104,11 +104,10 @@ bind S = js alert("hi"); # Parameters are separated by spaces and the script body must be one parameter, so enclose it in # quotes and escape any inner quotes using backslashes bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' -# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... -#hit F to toggle the Hints (now in form of link numbering) -bind F= script /usr/share/uzbl/examples/scripts/hint.js -#hit f followed by linknumber and ENTER to follow that link -bind f_ = js window.location = document.links[%s].href; + +# Linkfollowing now in one script, very Vimperator alike. +# In examples/scripts will be different approaches. Here the most stable one: +bind f* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js # "home" page if you will set uri = uzbl.org diff --git a/examples/scripts/follow_Numbers.js b/examples/scripts/follow_Numbers.js new file mode 100644 index 0000000..b5c39b6 --- /dev/null +++ b/examples/scripts/follow_Numbers.js @@ -0,0 +1,225 @@ +/* This is the basic linkfollowing script. + * Its pretty stable, only using numbers to navigate. + * + * TODO: Some pages mess around a lot with the zIndex which + * lets some hints in the background. + * TODO: Some positions are not calculated correctly (mostly + * because of uber-fancy-designed-webpages. Basic HTML and CSS + * works good + * TODO: Still some links can't be followed/unexpected things + * happen. Blame some freaky webdesigners ;) + */ + +//Just some shortcuts and globals +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; +//Make onlick-links "clickable" +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +//Catch the ESC keypress to stop linkfollowing +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +//Calculate element position to draw the hint +//Pretty accurate but on fails in some very fancy cases +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +//Calculate if an element is visible +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +//Calculate if an element is on the viewport. +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +//Removes all hints/leftovers that might be generated +//by this script. +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +//Generate a hint for an element with the given label +//Here you can play around with the style of the hints! +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.zIndex = '1000'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +//Here we choose what to do with an element if we +//want to "follow" it. On form elements we "select" +//or pass the focus, on links we try to perform a click, +//but at least set the href of the link. (needs some improvements) +function clickElem(item) { + removeAllHints(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +//Returns a list of all links (in this version +//just the elements itself, but in other versions, we +//add the label here. +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + } + } + return res; +} +//Same as above, just for the form elements +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + } + } + } + return res; +} +//Draw all hints for all elements passed. "len" is for +//the number of chars we should use to avoid collisions +function reDrawHints(elems, chars) { + removeAllHints(); + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + hintdiv.style.opacity = '0.0'; + for (var i = 0; i < elems[0].length; i++) { + if (elems[0][i]) { + var label = elems[1][i].substring(chars); + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + hintdiv.style.opacity = '0.7' + } +} +//Put it all together +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + var label = j + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + for (var k = 0; k < s.length; k++) { + b = b && label.charAt(k) == s[k]; + } + if (b) { + leftover[0].push(elems[0][j]); + leftover[1].push(label); + } + } + reDrawHints(leftover, s.length); + } +} +followLinks('%s'); diff --git a/examples/scripts/follow_Numbers_Strings.js b/examples/scripts/follow_Numbers_Strings.js new file mode 100644 index 0000000..67da2f9 --- /dev/null +++ b/examples/scripts/follow_Numbers_Strings.js @@ -0,0 +1,205 @@ +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.zIndex = '1000'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +function clickElem(item) { + removeAllHints(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + res[1].push(li.innerText.toLowerCase()); + } + } + return res; +} +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + if (el.getAttribute('value')) { + res[1].push(el.getAttribute('value').toLowerCase()); + } else { + res[1].push(el.getAttribute('name').toLowerCase()); + } + } + } + } + return res; +} +function reDrawHints(elems, len) { + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + hintdiv.style.opacity = '0.0'; + for (var i = 0; i < elems[0].length; i++) { + var label = i + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + if (elems[0][i]) { + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + hintdiv.style.opacity = '0.7' + } +} +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + for (var k = 0; k < s.length; k++) { + b = b && elems[1][j].charAt(k) == s[k]; + } + if (!b) { + elems[0][j] = null; + elems[1][j] = null; + } else { + leftover[0].push(elems[0][j]); + leftover[1].push(elems[1][j]); + } + } + if (leftover[0].length == 1) { + clickElem(leftover[0][0]); + } else if (!oldDiv) { + if (linknr + 1 || s.length == 0) { + reDrawHints(elems, len); + } else { + reDrawHints(leftover, len); + } + } + } +} +followLinks('%s'); -- cgit v1.2.3 From 1f94ec0e146d4addb82388d7b2987a020559f678 Mon Sep 17 00:00:00 2001 From: jouz Date: Thu, 21 May 2009 00:13:25 +0200 Subject: ooops, forgot an %s --- examples/configs/sampleconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 15e9c5c..732a029 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -107,7 +107,7 @@ bind XS = sh 'echo "act script alert (\'This is sent by the shell via # Linkfollowing now in one script, very Vimperator alike. # In examples/scripts will be different approaches. Here the most stable one: -bind f* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js +bind f* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js %s # "home" page if you will set uri = uzbl.org -- cgit v1.2.3 From f4cff365f2b9613afbc0517ce2dddf770802dc5d Mon Sep 17 00:00:00 2001 From: jouz Date: Thu, 21 May 2009 01:16:40 +0200 Subject: fixed wikipedia (and a lot of other sites with it) --- examples/scripts/follow_Numbers.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/scripts/follow_Numbers.js b/examples/scripts/follow_Numbers.js index b5c39b6..efde4d7 100644 --- a/examples/scripts/follow_Numbers.js +++ b/examples/scripts/follow_Numbers.js @@ -98,13 +98,13 @@ function generateHint(el, label) { hint.style.backgroundColor = '#B9FF00'; hint.style.border = '2px solid #4A6600'; hint.style.color = 'black'; - hint.style.zIndex = '1000'; hint.style.fontSize = '9px'; hint.style.fontWeight = 'bold'; hint.style.lineHeight = '9px'; hint.style.margin = '0px'; hint.style.padding = '1px'; hint.style.position = 'absolute'; + hint.style.zIndex = '1000'; hint.style.left = pos[1] + 'px'; hint.style.top = pos[0] + 'px'; var img = el.getElementsByTagName('img'); @@ -177,7 +177,6 @@ function reDrawHints(elems, chars) { removeAllHints(); var hintdiv = doc.createElement('div'); hintdiv.setAttribute('id', uzbldivid); - hintdiv.style.opacity = '0.0'; for (var i = 0; i < elems[0].length; i++) { if (elems[0][i]) { var label = elems[1][i].substring(chars); @@ -187,7 +186,6 @@ function reDrawHints(elems, chars) { } if (document.body) { document.body.appendChild(hintdiv); - hintdiv.style.opacity = '0.7' } } //Put it all together -- cgit v1.2.3 From 0e02a4231a23414581b3140c1836aec50f1e49d4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 21 May 2009 08:50:38 +0200 Subject: make download script a bit more uzbl --- examples/scripts/download.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh index 8078cc8..0d38d3c 100755 --- a/examples/scripts/download.sh +++ b/examples/scripts/download.sh @@ -1,12 +1,16 @@ #!/bin/bash -# A bit more advanced, try some pattern matching on the link to determine -# a target location. pushd and popd might be better than plain cd... +# just an example of how you could handle your downloads +# try some pattern matching on the uri to determine what we should do + +# Some sites block the default wget --user-agent... +WGET="wget --user-agent=Firefox" + if [[ $8 =~ .*(.torrent) ]] then - pushd /your/place/for/torrent/files + pushd $HOME + $WGET $8 else - pushd /your/place/for/usual/downloads + pushd $HOME + $WGET $8 fi -# Some sites block the default wget --user-agent... -wget --user-agent=Firefox $8 popd -- cgit v1.2.3 From e2bd46bb34507f563c7befcc80be62e26625d254 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 21 May 2009 09:11:40 +0200 Subject: cleanup configs wrt link following --- examples/configs/sampleconfig | 14 +++++++++++--- examples/configs/sampleconfig-dev | 13 +++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 732a029..312ab91 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -105,9 +105,17 @@ bind S = js alert("hi"); # quotes and escape any inner quotes using backslashes bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' -# Linkfollowing now in one script, very Vimperator alike. -# In examples/scripts will be different approaches. Here the most stable one: -bind f* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js %s + +# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) +# this is similar to how it works in vimperator (and konqueror) +# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? +#hit F to toggle the Hints (now in form of link numbering) +bind F = script /usr/share/uzbl/examples/scripts/hint.js +# the most stable version: +bind fl* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js %s +# using strings, not polished yet: +bind fL* = script /usr/share/uzbl/examples/scripts/follow_Numbers_Strings.js %s + # "home" page if you will set uri = uzbl.org diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index d20e98b..c1b136c 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -110,11 +110,16 @@ bind S = js alert("hi"); # path, fifo & socket dirs, etc.) bind XS = sh 'echo "act script alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -# Keyboard based link following: work in progress! No C DOM bindings yet, no click() event for hyperlinks so no referrer set..Quite basic but does the job for now... + +# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) +# this is similar to how it works in vimperator (and konqueror) +# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? #hit F to toggle the Hints (now in form of link numbering) -bind F= script ./examples/scripts/hint.js -#hit f followed by linknumber and ENTER to follow that link -bind f_ = js window.location = document.links[%s].href; +bind F = script ./examples/scripts/hint.js +# the most stable version: +bind fl* = script ./examples/scripts/follow_Numbers.js %s +# using strings, not polished yet: +bind fL* = script ./examples/scripts/follow_Numbers_Strings.js %s # "home" page if you will set uri = uzbl.org -- cgit v1.2.3 From c372568af1af5d4ea2afc498d741022207c1de56 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Fri, 22 May 2009 16:11:17 +0200 Subject: added form filler script --- examples/scripts/formfiller.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100755 examples/scripts/formfiller.sh (limited to 'examples') diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh new file mode 100755 index 0000000..006678c --- /dev/null +++ b/examples/scripts/formfiller.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# simple login form filler for uzbl. +# put your login information in the file $keydir/ +# in the format : + +keydir=$XDG_CONFIG_HOME/uzbl/keys +editor=gvim + +config=$1; shift +pid=$1; shift +xid=$1; shift +fifo=$1; shift +socket=$1; shift +url=$1; shift +title=$1; shift + +domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') +if [[ -e $keydir/$domain ]]; then + gawk -F': ' '{ print "act script document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo +else + curl "$url" | grep '.*|\1: |p' > $keydir/$domain + $editor $keydir/$domain +fi -- cgit v1.2.3 From fbd666e85d85ca836ffa6ec86ad1034d4100abf4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 22 May 2009 21:05:01 +0200 Subject: updates/doc/fixes for formfiller script from Sylvester Johansson --- AUTHORS | 1 + docs/TODO | 1 + examples/configs/sampleconfig-dev | 4 ++++ examples/data/forms/bbs.archlinux.org | 5 +++++ examples/scripts/formfiller.sh | 26 +++++++++++++++++--------- 5 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 examples/data/forms/bbs.archlinux.org (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index 66bd93e..c5da932 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,6 +15,7 @@ Contributors: Damien Leon - misc Peter Suschlik - backwards searching (salinasv) - move some variables to heap + Sylvester Johansson (scj) - original form filler script Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c Which is copyrighted: diff --git a/docs/TODO b/docs/TODO index 0b0e035..0bd238b 100644 --- a/docs/TODO +++ b/docs/TODO @@ -41,6 +41,7 @@ More or less in order of importance/urgency * regex style page searching? so you can do 'or' and 'and' things. flags like case sensitive etc. * check for real command name, not just the first letter. * let users attach handlers to the most common events/signals in uzbl. + great use case: automatically calling formfiller for certain sites * write little script to open new urls with the urxvt url thing +document. SOMEDAY: diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index c1b136c..e0ae84c 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -111,6 +111,10 @@ bind S = js alert("hi"); bind XS = sh 'echo "act script alert (\\"This is sent by the shell via a fifo\\")" > "$4"' +# this script allows you to load predefined values into html forms. (eg login information) +# if you have no config file yet, it will let you create settings easily. +bind z = spawn ./examples/scripts/formfiller.sh + # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) # TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? diff --git a/examples/data/forms/bbs.archlinux.org b/examples/data/forms/bbs.archlinux.org new file mode 100644 index 0000000..73c1539 --- /dev/null +++ b/examples/data/forms/bbs.archlinux.org @@ -0,0 +1,5 @@ +form_sent: +redirect_url: +req_username: +req_password: +login: diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh index 006678c..e7ef3b5 100755 --- a/examples/scripts/formfiller.sh +++ b/examples/scripts/formfiller.sh @@ -1,23 +1,31 @@ #!/bin/bash # simple login form filler for uzbl. -# put your login information in the file $keydir/ +# put the form entry values you want to add (eg login information) in the file $keydir/ # in the format : +# (these files can be automatically created for you by setting editor and triggering this script on a site without a config) -keydir=$XDG_CONFIG_HOME/uzbl/keys -editor=gvim +[ -d /usr/share/uzbl/examples/data/forms ] && keydir=/usr/share/uzbl/examples/data/forms # you will probably get permission denied errors here. +[ -d $XDG_DATA_HOME/uzbl/forms ] && keydir=$XDG_DATA_HOME/uzbl/forms +[ -d ./examples/data/forms ] && keydir=./examples/data/forms #useful when developing +[ -z "$keydir" ] && exit 1 + +#editor=gvim +editor='urxvt -e vim' config=$1; shift -pid=$1; shift -xid=$1; shift -fifo=$1; shift +pid=$1; shift +xid=$1; shift +fifo=$1; shift socket=$1; shift -url=$1; shift -title=$1; shift +url=$1; shift +title=$1; shift + +[ -d $keydir ] || mkdir $keydir || exit 1 domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') if [[ -e $keydir/$domain ]]; then - gawk -F': ' '{ print "act script document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo + gawk -F': ' '{ print "act js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo else curl "$url" | grep '.*|\1: |p' > $keydir/$domain $editor $keydir/$domain -- cgit v1.2.3 From 9b5aee5b6cdf7487f82e3ec15c50d73c12b2a717 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 22 May 2009 21:41:43 +0200 Subject: document duclares stuff --- examples/configs/sampleconfig-dev | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index e0ae84c..b53ac48 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -16,6 +16,7 @@ set download_handler = spawn ./examples/scripts/download.sh set cookie_handler = ./examples/scripts/cookies.sh set minimum_font_size = 6 set default_font_size = 11 +set default_monospace_size = 11 # use with bind ... = sh set shell_cmd = sh -c @@ -125,5 +126,8 @@ bind fl* = script ./examples/scripts/follow_Numbers.js %s # using strings, not polished yet: bind fL* = script ./examples/scripts/follow_Numbers_Strings.js %s +# you can use this to disable all plugins +set disable_plugins = 0 + # "home" page if you will set uri = uzbl.org -- cgit v1.2.3 From 06ab9065f2ea437b5632d14d7c02c0a883540422 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 23 May 2009 14:02:17 +0200 Subject: somewhat better inputfield matching regex + allow control over the action (load, new, edit) --- examples/scripts/formfiller.sh | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh index e7ef3b5..45cde69 100755 --- a/examples/scripts/formfiller.sh +++ b/examples/scripts/formfiller.sh @@ -1,9 +1,16 @@ #!/bin/bash -# simple login form filler for uzbl. -# put the form entry values you want to add (eg login information) in the file $keydir/ -# in the format : -# (these files can be automatically created for you by setting editor and triggering this script on a site without a config) +# simple html form (eg for logins) filler (and manager) for uzbl. +# uses settings files like: $keydir/ +# files contain lines like: : + + +# user arg 1: +# edit: force editing the file (falls back to new if not found) +# new: start with a new file. +# load: try to load from file into form + +# something else (or empty): if file not available: new, otherwise load. [ -d /usr/share/uzbl/examples/data/forms ] && keydir=/usr/share/uzbl/examples/data/forms # you will probably get permission denied errors here. [ -d $XDG_DATA_HOME/uzbl/forms ] && keydir=$XDG_DATA_HOME/uzbl/forms @@ -20,13 +27,34 @@ fifo=$1; shift socket=$1; shift url=$1; shift title=$1; shift +action=$1 [ -d $keydir ] || mkdir $keydir || exit 1 +if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ] +then + action=new + [[ -e $keydir/$domain ]] && action=load +elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]] +then + action=new +fi domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') -if [[ -e $keydir/$domain ]]; then + + +#regex='s|.*.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page + regex='s|.*> $fifo else - curl "$url" | grep '.*|\1: |p' > $keydir/$domain - $editor $keydir/$domain + if [ "$action" == 'new' ] + then + curl "$url" | grep ' $keydir/$domain + fi + [[ -e $keydir/$domain ]] || exit 3 #this should never happen, but you never know. + $editor $keydir/$domain #TODO: if user aborts save in editor, the file is already overwritten fi -- cgit v1.2.3 From df1d2a49c7db5d6085bc30fb7b698efe4303fa6e Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 23 May 2009 15:05:30 +0300 Subject: Shorten some lines and rename default_*_size to *_size --- examples/configs/sampleconfig | 4 +- examples/configs/sampleconfig-dev | 4 +- uzbl.c | 95 ++++++++++++++++++++------------------- uzbl.h | 6 +-- 4 files changed, 59 insertions(+), 50 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 312ab91..0f0cc1d 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -15,7 +15,9 @@ set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh # TODO: cookie_handler can't take arbitrary actionsyet set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh set minimum_font_size = 6 -set default_font_size = 11 +set font_size = 11 +# monospace_size defaults to font_size, but you can alter it independently +#set monospace_size = 10 # use with bind ... = sh set shell_cmd = sh -c diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index c1b136c..5ea48dc 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -15,7 +15,9 @@ set download_handler = spawn ./examples/scripts/download.sh # TODO: you can't use actions in cookie handler yet. set cookie_handler = ./examples/scripts/cookies.sh set minimum_font_size = 6 -set default_font_size = 11 +set font_size = 11 +# monospace_size defaults to font_size, but you can alter it independently +#set monospace_size = 10 # use with bind ... = sh set shell_cmd = sh -c diff --git a/uzbl.c b/uzbl.c index c032543..8ae76d0 100644 --- a/uzbl.c +++ b/uzbl.c @@ -77,48 +77,53 @@ typedef const struct { void (*func)(void); } uzbl_cmdprop; -enum {TYPE_INT, TYPE_STRING}; +enum {TYPE_INT, TYPE_STR}; + +/* some abbreviations to help keep the table lines' width humane */ +#define VAR(x) .ptr = (void*)&(x) +#define T(x) .type = TYPE_##x +#define FUN(x) .func = x const struct { char *name; uzbl_cmdprop cp; } var_name_to_ptr[] = { -/* variable name pointer to variable in code variable type callback function */ -/* ------------------------------------------------------------------------------------------------------------------- */ - { "uri", {.ptr = (void *)&uzbl.state.uri, .type = TYPE_STRING, .func = cmd_load_uri}}, - { "status_message", {.ptr = (void *)&uzbl.gui.sbar.msg, .type = TYPE_STRING, .func = update_title}}, - { "show_status", {.ptr = (void *)&uzbl.behave.show_status, .type = TYPE_INT, .func = cmd_set_status}}, - { "status_top", {.ptr = (void *)&uzbl.behave.status_top, .type = TYPE_INT, .func = move_statusbar}}, - { "status_format", {.ptr = (void *)&uzbl.behave.status_format, .type = TYPE_STRING, .func = update_title}}, - { "status_pbar_done", {.ptr = (void *)&uzbl.gui.sbar.progress_s, .type = TYPE_STRING, .func = update_title}}, - { "status_pbar_pending",{.ptr = (void *)&uzbl.gui.sbar.progress_u, .type = TYPE_STRING, .func = update_title}}, - { "status_pbar_width", {.ptr = (void *)&uzbl.gui.sbar.progress_w, .type = TYPE_INT, .func = update_title}}, - { "status_background", {.ptr = (void *)&uzbl.behave.status_background, .type = TYPE_STRING, .func = update_title}}, - { "title_format_long", {.ptr = (void *)&uzbl.behave.title_format_long, .type = TYPE_STRING, .func = update_title}}, - { "title_format_short", {.ptr = (void *)&uzbl.behave.title_format_short, .type = TYPE_STRING, .func = update_title}}, - { "insert_mode", {.ptr = (void *)&uzbl.behave.insert_mode, .type = TYPE_INT, .func = NULL}}, - { "always_insert_mode", {.ptr = (void *)&uzbl.behave.always_insert_mode, .type = TYPE_INT, .func = cmd_always_insert_mode}}, - { "reset_command_mode", {.ptr = (void *)&uzbl.behave.reset_command_mode, .type = TYPE_INT, .func = NULL}}, - { "modkey", {.ptr = (void *)&uzbl.behave.modkey, .type = TYPE_STRING, .func = cmd_modkey}}, - { "load_finish_handler",{.ptr = (void *)&uzbl.behave.load_finish_handler, .type = TYPE_STRING, .func = NULL}}, - { "load_start_handler", {.ptr = (void *)&uzbl.behave.load_start_handler, .type = TYPE_STRING, .func = NULL}}, - { "load_commit_handler",{.ptr = (void *)&uzbl.behave.load_commit_handler, .type = TYPE_STRING, .func = NULL}}, - { "history_handler", {.ptr = (void *)&uzbl.behave.history_handler, .type = TYPE_STRING, .func = NULL}}, - { "download_handler", {.ptr = (void *)&uzbl.behave.download_handler, .type = TYPE_STRING, .func = NULL}}, - { "cookie_handler", {.ptr = (void *)&uzbl.behave.cookie_handler, .type = TYPE_STRING, .func = NULL}}, - { "fifo_dir", {.ptr = (void *)&uzbl.behave.fifo_dir, .type = TYPE_STRING, .func = cmd_fifo_dir}}, - { "socket_dir", {.ptr = (void *)&uzbl.behave.socket_dir, .type = TYPE_STRING, .func = cmd_socket_dir}}, - { "http_debug", {.ptr = (void *)&uzbl.behave.http_debug, .type = TYPE_INT, .func = cmd_http_debug}}, - { "default_font_size", {.ptr = (void *)&uzbl.behave.default_font_size, .type = TYPE_INT, .func = cmd_default_font_size}}, - { "default_monospace_size", {.ptr = (void *)&uzbl.behave.default_monospace_size, .type = TYPE_INT, .func = cmd_default_font_size}}, - { "minimum_font_size", {.ptr = (void *)&uzbl.behave.minimum_font_size, .type = TYPE_INT, .func = cmd_minimum_font_size}}, - { "disable_plugins", {.ptr = (void *)&uzbl.behave.disable_plugins, .type = TYPE_INT, .func = cmd_disable_plugins}}, - { "shell_cmd", {.ptr = (void *)&uzbl.behave.shell_cmd, .type = TYPE_STRING, .func = NULL}}, - { "proxy_url", {.ptr = (void *)&uzbl.net.proxy_url, .type = TYPE_STRING, .func = set_proxy_url}}, - { "max_conns", {.ptr = (void *)&uzbl.net.max_conns, .type = TYPE_INT, .func = cmd_max_conns}}, - { "max_conns_host", {.ptr = (void *)&uzbl.net.max_conns_host, .type = TYPE_INT, .func = cmd_max_conns_host}}, - { "useragent", {.ptr = (void *)&uzbl.net.useragent, .type = TYPE_STRING, .func = cmd_useragent}}, - { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}} +/* variable name pointer to variable in code var type callback function */ +/* -------------------------------------------------------------------------------------------- */ + { "uri", {VAR(uzbl.state.uri), T(STR), FUN(cmd_load_uri)}}, + { "status_message", {VAR(uzbl.gui.sbar.msg), T(STR), FUN(update_title)}}, + { "show_status", {VAR(uzbl.behave.show_status), T(INT), FUN(cmd_set_status)}}, + { "status_top", {VAR(uzbl.behave.status_top), T(INT), FUN(move_statusbar)}}, + { "status_format", {VAR(uzbl.behave.status_format), T(STR), FUN(update_title)}}, + { "status_pbar_done", {VAR(uzbl.gui.sbar.progress_s), T(STR), FUN(update_title)}}, + { "status_pbar_pending",{VAR(uzbl.gui.sbar.progress_u), T(STR), FUN(update_title)}}, + { "status_pbar_width", {VAR(uzbl.gui.sbar.progress_w), T(INT), FUN(update_title)}}, + { "status_background", {VAR(uzbl.behave.status_background), T(STR), FUN(update_title)}}, + { "title_format_long", {VAR(uzbl.behave.title_format_long), T(STR), FUN(update_title)}}, + { "title_format_short", {VAR(uzbl.behave.title_format_short), T(STR), FUN(update_title)}}, + { "insert_mode", {VAR(uzbl.behave.insert_mode), T(INT), FUN(NULL)}}, + { "always_insert_mode", {VAR(uzbl.behave.always_insert_mode), T(INT), FUN(cmd_always_insert_mode)}}, + { "reset_command_mode", {VAR(uzbl.behave.reset_command_mode), T(INT), FUN(NULL)}}, + { "modkey", {VAR(uzbl.behave.modkey), T(STR), FUN(cmd_modkey)}}, + { "load_finish_handler",{VAR(uzbl.behave.load_finish_handler), T(STR), FUN(NULL)}}, + { "load_start_handler", {VAR(uzbl.behave.load_start_handler), T(STR), FUN(NULL)}}, + { "load_commit_handler",{VAR(uzbl.behave.load_commit_handler), T(STR), FUN(NULL)}}, + { "history_handler", {VAR(uzbl.behave.history_handler), T(STR), FUN(NULL)}}, + { "download_handler", {VAR(uzbl.behave.download_handler), T(STR), FUN(NULL)}}, + { "cookie_handler", {VAR(uzbl.behave.cookie_handler), T(STR), FUN(NULL)}}, + { "fifo_dir", {VAR(uzbl.behave.fifo_dir), T(STR), FUN(cmd_fifo_dir)}}, + { "socket_dir", {VAR(uzbl.behave.socket_dir), T(STR), FUN(cmd_socket_dir)}}, + { "http_debug", {VAR(uzbl.behave.http_debug), T(INT), FUN(cmd_http_debug)}}, + { "font_size", {VAR(uzbl.behave.font_size), T(INT), FUN(cmd_font_size)}}, + { "monospace_size", {VAR(uzbl.behave.monospace_size), T(INT), FUN(cmd_font_size)}}, + { "minimum_font_size", {VAR(uzbl.behave.minimum_font_size), T(INT), FUN(cmd_minimum_font_size)}}, + { "disable_plugins", {VAR(uzbl.behave.disable_plugins), T(INT), FUN(cmd_disable_plugins)}}, + { "shell_cmd", {VAR(uzbl.behave.shell_cmd), T(STR), FUN(NULL)}}, + { "proxy_url", {VAR(uzbl.net.proxy_url), T(STR), FUN(set_proxy_url)}}, + { "max_conns", {VAR(uzbl.net.max_conns), T(INT), FUN(cmd_max_conns)}}, + { "max_conns_host", {VAR(uzbl.net.max_conns_host), T(INT), FUN(cmd_max_conns_host)}}, + { "useragent", {VAR(uzbl.net.useragent), T(STR), FUN(cmd_useragent)}}, + { NULL, {.ptr = NULL, T(INT), FUN(NULL)}} }, *n2v_p = var_name_to_ptr; const struct { @@ -1040,7 +1045,7 @@ get_var_value(gchar *name) { uzbl_cmdprop *c; if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(c->type == TYPE_STRING) + if(c->type == TYPE_STR) printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr); else if(c->type == TYPE_INT) printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr); @@ -1107,18 +1112,18 @@ cmd_http_debug() { } static void -cmd_default_font_size() { +cmd_font_size() { WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view); - if (uzbl.behave.default_font_size > 0) { - g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.default_font_size, NULL); + if (uzbl.behave.font_size > 0) { + g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL); } - if (uzbl.behave.default_monospace_size > 0) { + if (uzbl.behave.monospace_size > 0) { g_object_set (G_OBJECT(ws), "default-monospace-font-size", - uzbl.behave.default_monospace_size, NULL); + uzbl.behave.monospace_size, NULL); } else { g_object_set (G_OBJECT(ws), "default-monospace-font-size", - uzbl.behave.default_font_size, NULL); + uzbl.behave.font_size, NULL); } } @@ -1204,7 +1209,7 @@ set_var_value(gchar *name, gchar *val) { if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { /* check for the variable type */ - if (c->type == TYPE_STRING) { + if (c->type == TYPE_STR) { g_free(*c->ptr); *c->ptr = g_strdup(val); } else if(c->type == TYPE_INT) { diff --git a/uzbl.h b/uzbl.h index 530ca31..808e7a7 100644 --- a/uzbl.h +++ b/uzbl.h @@ -146,8 +146,8 @@ typedef struct { gchar* modkey; guint modmask; guint http_debug; - guint default_font_size; - guint default_monospace_size; + guint font_size; + guint monospace_size; guint minimum_font_size; guint disable_plugins; gchar* shell_cmd; @@ -402,7 +402,7 @@ static void cmd_max_conns_host(); static void -cmd_default_font_size(); +cmd_font_size(); static void cmd_disable_plugins(); -- cgit v1.2.3 From 7a2a0eefe161766ac8cb534dcc53a624bd082ce7 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 23 May 2009 14:08:26 +0200 Subject: keybinds corresponding to the new load/edit/new actions for the formfiller --- examples/configs/sampleconfig-dev | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index b53ac48..68444db 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -112,9 +112,11 @@ bind S = js alert("hi"); bind XS = sh 'echo "act script alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -# this script allows you to load predefined values into html forms. (eg login information) -# if you have no config file yet, it will let you create settings easily. -bind z = spawn ./examples/scripts/formfiller.sh +# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically +bind za = spawn ./examples/scripts/formfiller.sh +bind ze = spawn ./examples/scripts/formfiller.sh edit +bind zn = spawn ./examples/scripts/formfiller.sh new +bind zl = spawn ./examples/scripts/formfiller.sh load # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) -- cgit v1.2.3 From 3b9d97b8899c74d8e171b9896c83e7611063f070 Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 23 May 2009 16:35:49 +0300 Subject: Add (spawn|sh)_sync, make handle_cookies use run_handler --- examples/configs/sampleconfig-dev | 3 +- uzbl.c | 70 +++++++++++++++++++++++++++++---------- uzbl.h | 8 ++++- 3 files changed, 61 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 5ea48dc..73d332d 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -12,8 +12,7 @@ set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh -# TODO: you can't use actions in cookie handler yet. -set cookie_handler = ./examples/scripts/cookies.sh +set cookie_handler = spawn_sync ./examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 # monospace_size defaults to font_size, but you can alter it independently diff --git a/uzbl.c b/uzbl.c index 28ff64f..9da93d8 100644 --- a/uzbl.c +++ b/uzbl.c @@ -169,6 +169,9 @@ itos(int val) { return g_strdup(tmp); } +static gchar* +strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go + static gchar* argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } @@ -500,7 +503,9 @@ static struct {char *name; Command command[2];} cmdlist[] = { "script", {run_external_js, 0} }, { "toggle_status", {toggle_status_cb, 0} }, { "spawn", {spawn, 0} }, + { "spawn_sync", {spawn_sync, 0} }, // needed for cookie handler { "sh", {spawn_sh, 0} }, + { "sh_sync", {spawn_sh_sync, 0} }, // needed for cookie handler { "exit", {close_uzbl, 0} }, { "search", {search_forward_text, NOSPLIT} }, { "search_reverse", {search_reverse_text, NOSPLIT} }, @@ -907,10 +912,13 @@ run_command (const gchar *command, const guint npre, const gchar **args, sharg_append(a, args[i]); gboolean result; - if (sync) result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, stdout, NULL, NULL, &err); - else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, &err); + if (sync) { + if (*stdout) *stdout = strfree(*stdout); + + result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, stdout, NULL, NULL, &err); + } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &err); if (uzbl.state.verbose) { GString *s = g_string_new("spawned:"); @@ -978,6 +986,15 @@ spawn(WebKitWebView *web_view, GArray *argv) { run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL); } +static void +spawn_sync(WebKitWebView *web_view, GArray *argv) { + (void)web_view; + + if (argv_idx(argv, 0)) + run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), + TRUE, &uzbl.comm.sync_stdout); +} + static void spawn_sh(WebKitWebView *web_view, GArray *argv) { (void)web_view; @@ -999,6 +1016,28 @@ spawn_sh(WebKitWebView *web_view, GArray *argv) { g_strfreev (cmd); } +static void +spawn_sh_sync(WebKitWebView *web_view, GArray *argv) { + (void)web_view; + if (!uzbl.behave.shell_cmd) { + g_printerr ("spawn_sh_sync: shell_cmd is not set!\n"); + return; + } + + guint i; + gchar *spacer = g_strdup(""); + g_array_insert_val(argv, 1, spacer); + gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); + + for (i = 1; i < g_strv_length(cmd); i++) + g_array_prepend_val(argv, cmd[i]); + + if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, + TRUE, &uzbl.comm.sync_stdout); + g_free (spacer); + g_strfreev (cmd); +} + static void parse_command(const char *cmd, const char *param) { Command *c; @@ -1848,21 +1887,18 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use (void) user_data; if (!uzbl.behave.cookie_handler) return; - gchar * stdout = NULL; soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - gchar *action = g_strdup ("GET"); + GString *s = g_string_new (""); SoupURI * soup_uri = soup_message_get_uri(msg); - sharg_append(a, action); - sharg_append(a, soup_uri->host); - sharg_append(a, soup_uri->path); - run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, TRUE, &stdout); /* TODO: use handler */ - //run_handler(uzbl.behave.cookie_handler); /* TODO: global stdout pointer, spawn_sync */ - if(stdout) { - soup_message_headers_replace (msg->request_headers, "Cookie", stdout); - } - g_free (action); - g_array_free(a, TRUE); + g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path); + run_handler(uzbl.behave.cookie_handler, s->str); + + if(uzbl.comm.sync_stdout) + soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout); + printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging + if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + g_string_free(s, TRUE); } static void diff --git a/uzbl.h b/uzbl.h index 808e7a7..d314221 100644 --- a/uzbl.h +++ b/uzbl.h @@ -95,7 +95,7 @@ typedef struct { GRegex *keycmd_regex; GRegex *get_regex; GRegex *bind_regex; - gchar **sync_stdout; + gchar *sync_stdout; } Communication; @@ -291,6 +291,12 @@ spawn(WebKitWebView *web_view, GArray *argv); static void spawn_sh(WebKitWebView *web_view, GArray *argv); +static void +spawn_sync(WebKitWebView *web_view, GArray *argv); + +static void +spawn_sh_sync(WebKitWebView *web_view, GArray *argv); + static void parse_command(const char *cmd, const char *param); -- cgit v1.2.3 From 42094304f29662e4441b6dc9c26f3d9913afb37f Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 23 May 2009 16:59:47 +0300 Subject: Rename *_sync actions to sync_*, use run_handler in save_cookies --- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 73d332d..d991d00 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,8 +11,8 @@ # Usually you want to spawn a script to handle things, but any action (such as sh) can be used set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh +set cookie_handler = sync_spawn ./examples/scripts/cookies.sh -set cookie_handler = spawn_sync ./examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 # monospace_size defaults to font_size, but you can alter it independently diff --git a/uzbl.c b/uzbl.c index 9da93d8..3b3f564 100644 --- a/uzbl.c +++ b/uzbl.c @@ -503,9 +503,9 @@ static struct {char *name; Command command[2];} cmdlist[] = { "script", {run_external_js, 0} }, { "toggle_status", {toggle_status_cb, 0} }, { "spawn", {spawn, 0} }, - { "spawn_sync", {spawn_sync, 0} }, // needed for cookie handler + { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler { "sh", {spawn_sh, 0} }, - { "sh_sync", {spawn_sh_sync, 0} }, // needed for cookie handler + { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler { "exit", {close_uzbl, 0} }, { "search", {search_forward_text, NOSPLIT} }, { "search_reverse", {search_reverse_text, NOSPLIT} }, @@ -1908,17 +1908,12 @@ save_cookies (SoupMessage *msg, gpointer user_data){ char *cookie; for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ cookie = soup_cookie_to_set_cookie_header(ck->data); - GArray *a = g_array_new(TRUE, FALSE, sizeof(gchar*)); SoupURI * soup_uri = soup_message_get_uri(msg); - gchar *action = strdup("PUT"); - sharg_append(a, action); - sharg_append(a, soup_uri->host); - sharg_append(a, soup_uri->path); - sharg_append(a, cookie); - run_command(uzbl.behave.cookie_handler, 0, (const gchar **) a->data, FALSE, NULL); + GString *s = g_string_new (""); + g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie); + run_handler(uzbl.behave.cookie_handler, s->str); g_free (cookie); - g_free (action); - g_array_free(a, TRUE); + g_string_free(s, TRUE); } g_slist_free(ck); } -- cgit v1.2.3 From 07c832836d2c7fb22899d77af6eaab680e98e251 Mon Sep 17 00:00:00 2001 From: DuClare Date: Sat, 23 May 2009 17:33:39 +0300 Subject: Autoprepend sync_ to sh and spawn when setting cookie hdler; update sampleconfs --- examples/configs/sampleconfig | 3 +-- examples/configs/sampleconfig-dev | 2 +- uzbl.c | 16 ++++++++++++++-- uzbl.h | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 0f0cc1d..06f3f13 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -11,9 +11,8 @@ # You can use any action in place of spawn set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh +set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.sh -# TODO: cookie_handler can't take arbitrary actionsyet -set cookie_handler = /usr/share/uzbl/examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 # monospace_size defaults to font_size, but you can alter it independently diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index d991d00..0edaecd 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,7 +11,7 @@ # Usually you want to spawn a script to handle things, but any action (such as sh) can be used set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh -set cookie_handler = sync_spawn ./examples/scripts/cookies.sh +set cookie_handler = spawn ./examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 diff --git a/uzbl.c b/uzbl.c index 3b3f564..a45f816 100644 --- a/uzbl.c +++ b/uzbl.c @@ -108,7 +108,7 @@ const struct { { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, NULL)}, { "history_handler", PTR(uzbl.behave.history_handler, STR, NULL)}, { "download_handler", PTR(uzbl.behave.download_handler, STR, NULL)}, - { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, NULL)}, + { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, cmd_cookie_handler)}, { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, cmd_fifo_dir)}, { "socket_dir", PTR(uzbl.behave.socket_dir, STR, cmd_socket_dir)}, { "http_debug", PTR(uzbl.behave.http_debug, INT, cmd_http_debug)}, @@ -1176,6 +1176,18 @@ cmd_minimum_font_size() { g_object_set (G_OBJECT(ws), "minimum-font-size", uzbl.behave.minimum_font_size, NULL); } +static void +cmd_cookie_handler() { + gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.cookie_handler); + uzbl.behave.cookie_handler = + g_strdup_printf("sync_%s %s", split[0], split[1]); + } + g_strfreev (split); +} + static void cmd_fifo_dir() { uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); @@ -1895,7 +1907,7 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use if(uzbl.comm.sync_stdout) soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout); - printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging + //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); g_string_free(s, TRUE); diff --git a/uzbl.h b/uzbl.h index d314221..417df70 100644 --- a/uzbl.h +++ b/uzbl.h @@ -392,6 +392,9 @@ cmd_set_status(); static void set_proxy_url(); +static void +cmd_cookie_handler(); + static void move_statusbar(); -- cgit v1.2.3 From e5a72625ccb8f3d99e27e52765e44b9bbe3e19b7 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Sun, 24 May 2009 09:35:00 +0200 Subject: updated sampleconfig-dev --- examples/configs/sampleconfig-dev | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index a093574..73c61c8 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -15,9 +15,29 @@ set cookie_handler = spawn ./examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 -# monospace_size defaults to font_size, but you can alter it independently +## monospace_size defaults to font_size, but you can alter it independently #set monospace_size = 10 +## Display or supress images within html sites +#set autoload_images = 0 + +## Shrink images to window size +#set autoshrink_images = 0 + +## Spellchecker +#set enable_spellcheck = 1 + +## Private browsing +#set enbale_private = 0 + +## The URI of a stylesheet that is applied to every page +#set stylesheet_uri = http://www.user.com/mystylelesheet.css + +## enable/disable JavaScript +#set disbale_scripts = 1 + + +# # use with bind ... = sh set shell_cmd = sh -c -- cgit v1.2.3 From cb846147f695b9b3a5b235c3ce2deeab1fc9c96f Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Sun, 24 May 2009 20:51:51 +0200 Subject: more WebKitWebSettings exports --- examples/configs/sampleconfig-dev | 13 +++++++++++++ uzbl.c | 21 +++++++++++++++++++++ uzbl.h | 14 ++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 73c61c8..8652cc1 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -36,6 +36,19 @@ set font_size = 11 ## enable/disable JavaScript #set disbale_scripts = 1 +## Whether text areas are resizable +#set resizeable_text_areas = 1 + +## The default encoding used to display text +#set default_encoding = iso-8859-1 + +## Whether background images should be printed +#set print_background = 0 + +## Enforce a resolution of 96 DPI. This is meant for compatibility with +## web pages which cope badly with different screen resolutions +#set enforce_96_dpi = 1 + # # use with bind ... = sh diff --git a/uzbl.c b/uzbl.c index 2b983cb..e7eb5d5 100644 --- a/uzbl.c +++ b/uzbl.c @@ -129,6 +129,9 @@ const struct { { "enable_private", PTR(uzbl.behave.enable_private, INT, cmd_enable_private)}, { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, cmd_print_bg)}, { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, cmd_style_uri)}, + { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, cmd_resizable_txt)}, + { "default_encoding", PTR(uzbl.behave.default_encoding, STR, cmd_default_encoding)}, + { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, cmd_enforce_96dpi)}, { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}} }, *n2v_p = var_name_to_ptr; @@ -1260,6 +1263,24 @@ cmd_style_uri() { uzbl.behave.style_uri, NULL); } +static void +cmd_resizable_txt() { + g_object_set (G_OBJECT(view_settings()), "resizable-text-areas", + uzbl.behave.resizable_txt, NULL); +} + +static void +cmd_default_encoding() { + g_object_set (G_OBJECT(view_settings()), "default-encoding", + uzbl.behave.default_encoding, NULL); +} + +static void +cmd_enforce_96dpi() { + g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi", + uzbl.behave.enforce_96dpi, NULL); +} + static void cmd_cookie_handler() { gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); diff --git a/uzbl.h b/uzbl.h index d640492..3f5e60f 100644 --- a/uzbl.h +++ b/uzbl.h @@ -163,8 +163,9 @@ typedef struct { guint enable_private; guint print_bg; gchar* style_uri; - - + guint resizable_txt; + gchar* default_encoding; + guint enforce_96dpi; /* command list: name -> Command */ GHashTable* commands; @@ -470,5 +471,14 @@ cmd_print_bg(); static void cmd_style_uri(); +static void +cmd_resizable_txt(); + +static void +cmd_default_encoding(); + +static void +cmd_enforce_96dpi(); + /* vi: set et ts=4: */ -- cgit v1.2.3 From 5039fb8e90418df142131397af669f0232cb33fe Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Tue, 26 May 2009 20:01:47 +0200 Subject: new linkfollow.js for a more vimperator-ish browsing experience --- examples/scripts/linkfollow.js | 175 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 examples/scripts/linkfollow.js (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js new file mode 100644 index 0000000..9b7d811 --- /dev/null +++ b/examples/scripts/linkfollow.js @@ -0,0 +1,175 @@ +// link follower for uzbl +// requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 +// +// first, it needs to be loaded before every time it is used. +// One way would be to use something like load_start_handler to send +// "act script link_follower.js" +// +// when script is loaded, it can be invoked with +// bind f* = js setHints("%s") +// bind f_ = js followLink("%s") +// +// based on follow_Numbers.js +// +// TODO: add classes to hinted elements + + +var uzblid = 'uzbl_hint'; +var uzblclass = 'uzbl_hint_class' + +var doc = document; + +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; var width = el.offsetWidth; + var height = el.offsetHeight; + + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} + +function generateHint(el, label) { + var hint = doc.createElement('div'); + hint.setAttribute('class', uzblclass); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '10000'; + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} + +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return (up < window.pageYOffset + window.innerHeight && + left < window.pageXOffset + window.innerWidth + && (up + height) > window.pageYOffset + && (left + width) > window.pageXOffset); +} + +function isVisible(el) { + + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} + +var hintable = "//a[@href] | //img | //input"; + +function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function test(element) { + // test all the regexp + return words.every(function (regex) { return element.textContent.match(regex)}); + } + function toString(){ + return "{"+numbers+"},{"+words+"}"; + } +} + + +function setHints(r){ + if(doc.body) doc.body.setAttribute("onkeyup","keyPressHandler(event)"); + var re = new Matcher(r); + clearHints(); + var c = 1; + var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0; i < items.snapshotLength;i++){ + var item = items.snapshotItem(i); + if(re.test(item) && isVisible(item) && elementInViewport(item)){ + var h = generateHint(item,c); + item.appendChild(h); + c++; + } + } +} + +function clearHints(){ + var items = doc.evaluate("//div[@class='" + uzblclass + "']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0; i < items.snapshotLength;i++){ + var item = items.snapshotItem(i); + item.parentNode.removeChild(item); + } +} + +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + clearHints(); + doc.body.removeAttribute("onkeyup"); + } +} +function followLink(follow){ + var m = new Matcher(follow); + var elements = doc.evaluate("//*/div[@class='"+uzblclass+"']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + // filter + var matched = []; + for (var i = 0; i < elements.snapshotLength;i++){ + var item = elements.snapshotItem(i); + if(m.test(item.parentNode)){ + matched.push(item.parentNode); + } + } + clearHints(); + if(matched.length == 1) { + var item = matched[0]; + } else { + var item = matched[parseInt(m.numbers,10)-1]; + } + if (item) { + item.style.backgroundColor = "blue"; + + var name = item.tagName; + if (name == 'A') { + if(item.click) {item.click()}; + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} -- cgit v1.2.3 From aa66355dde399f9e2868a80617acca96213c03fe Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Tue, 26 May 2009 20:07:33 +0200 Subject: new formfiller script --- examples/scripts/formfiller.pl | 99 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100755 examples/scripts/formfiller.pl (limited to 'examples') diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl new file mode 100755 index 0000000..4c351b5 --- /dev/null +++ b/examples/scripts/formfiller.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +# a slightly more advanced form filler +# +# uses settings file like: $keydir/ + +# user arg 1: +# edit: force editing of the file (fetches if file is missing) +# load: fill forms from file (fetches if file is missing) +# new: fetch new file + +# usage example: +# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl load +# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl new +# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl edit + +use strict; +use Switch; + +my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/keys"; +my ($config,$pid,$xid,$fifo,$socket,$url,$title,$cmd) = @ARGV; +if($fifo eq "") { die "No fifo"; }; + +sub domain { + my ($url) = @_; + $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#; + return $url; +}; + +#my $editor = "xterm -e vim"; +my $editor = "gvim"; + +# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with +# Also, you may need to fake the user-agent on some sites (like facebook) + my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' "; +#my $downloader = "curl -s"; + +my @fields = ("type","name","value"); + +my %command; + +$command{load} = sub { + my ($domain) = @_; + my $file = "$keydir/$domain"; + if( -e $file){ + open(FH,$file); + my (@lines) = ; + close(FH); + $|++; + open(FIFO,">>$fifo"); + print "opened $fifo\n"; + foreach my $line (@lines) { + if($line !~ m/^#/){ + my ($type,$name,$value) = ($line =~ /\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); + switch ($type) { + case "" {} + case "checkbox" { printf FIFO 'act js document.getElementsByName("%s")[0].checked = %s;', $name, $value} + case "submit" { printf FIFO 'act js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name } + else { printf FIFO 'act js document.getElementsByName("%s")[0].value = "%s";', $name, $value} + } + + print FIFO "\n"; + } + } + $|--; + close(FIFO); + } else { + $command{new}->($domain); + $command{edit}->($domain); + } +}; +$command{edit} = sub { + my ($domain) = @_; + my $file = "$keydir/$domain"; + if(-e $file){ + system ($editor, $file); + } else { + $command{new}->($domain); +} +}; +$command{new} = sub { + my ($domain) = @_; + my $file = "$keydir/$domain"; + open(FILE,">>$file"); + $|++; + print FILE "#make sure that there are no extra submits, since it may trigger the wrong one\n"; + printf FILE "#%-10s | %-10s | %s\n", @fields; + print FILE "#------------------------------\n"; + my @data = `$downloader $url`; + foreach my $line (@data){ + if($line =~ m/].*?)>/i){ + $line =~ s/.*(].*?)>).*/\1/; + printf FILE " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; + }; + }; + close(FILE); + $|--; +}; +$command{$cmd}->(domain($url)); -- cgit v1.2.3 From 10c5302f00d3339bd45a47b23075e9ea64a8d0ab Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 26 May 2009 21:41:57 +0200 Subject: uzblcat script by mxf --- AUTHORS | 1 + examples/scripts/uzblcat | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100755 examples/scripts/uzblcat (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index ca9e102..9d4c865 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,6 +16,7 @@ Contributors: Peter Suschlik - backwards searching (salinasv) - move some variables to heap Sylvester Johansson (scj) - original form filler script + (mxf) - uzblcat Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c Which is copyrighted: diff --git a/examples/scripts/uzblcat b/examples/scripts/uzblcat new file mode 100755 index 0000000..82341c7 --- /dev/null +++ b/examples/scripts/uzblcat @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +# uzblcat - safely push html to uzbl +# See http://www.uzbl.org/wiki/html-mode +use strict; use warnings; + +my $html; +local $/; # slurp files +# automagically choose to read from stdin/files/... +$html .= $_ for <>; + +my $endmarker = rand; +$endmarker .= rand() while $html =~ /^\Q$endmarker\E$/m; + +print "set base_url = $ENV{BASE_URL}\n" if $ENV{BASE_URL}; +print << "EOS"; +set html_endmarker = $endmarker +set mode = 1 +$html +$endmarker +EOS -- cgit v1.2.3 From cd8ae0f8c77f7bd6940b8f65a338a3fa8736661a Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 26 May 2009 22:44:01 +0200 Subject: integrate sscj stuff --- AUTHORS | 2 +- examples/configs/sampleconfig-dev | 5 +++++ examples/scripts/formfiller.pl | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index 9d4c865..2212a87 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,7 +15,7 @@ Contributors: Damien Leon - misc Peter Suschlik - backwards searching (salinasv) - move some variables to heap - Sylvester Johansson (scj) - original form filler script + Sylvester Johansson (scj) - form filler script & different take on link follower (mxf) - uzblcat Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 8652cc1..3deeac1 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -151,6 +151,11 @@ bind ze = spawn ./examples/scripts/formfiller.sh edit bind zn = spawn ./examples/scripts/formfiller.sh new bind zl = spawn ./examples/scripts/formfiller.sh load +# other - more advanced - implementation using perl: (could not get this to run - Dieter ) +bind LL = spawn ./examples/scripts/formfiller.pl load +bind LN = spawn ./examples/scripts/formfiller.pl new +bind LE = spawn ./examples/scripts/formfiller.pl edit + # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) # TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl index 4c351b5..a6e07a0 100755 --- a/examples/scripts/formfiller.pl +++ b/examples/scripts/formfiller.pl @@ -10,14 +10,14 @@ # new: fetch new file # usage example: -# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl load -# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl new -# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller2.pl edit +# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load +# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller.pl new +# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit use strict; use Switch; -my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/keys"; +my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; my ($config,$pid,$xid,$fifo,$socket,$url,$title,$cmd) = @ARGV; if($fifo eq "") { die "No fifo"; }; @@ -27,8 +27,8 @@ sub domain { return $url; }; -#my $editor = "xterm -e vim"; -my $editor = "gvim"; +my $editor = "xterm -e vim"; +#my $editor = "gvim"; # ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with # Also, you may need to fake the user-agent on some sites (like facebook) -- cgit v1.2.3 From 881b7daf9da79abe80046f43008574b87d6e29e5 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 26 May 2009 23:20:52 +0200 Subject: disable cookies in master --- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 06f3f13..a541854 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -11,7 +11,7 @@ # You can use any action in place of spawn set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh -set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.sh +#set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3deeac1..3b1c069 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,7 +11,7 @@ # Usually you want to spawn a script to handle things, but any action (such as sh) can be used set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh -set cookie_handler = spawn ./examples/scripts/cookies.sh +#set cookie_handler = spawn ./examples/scripts/cookies.sh set minimum_font_size = 6 set font_size = 11 -- cgit v1.2.3 From 5967d904d18835d7f2dac806ffe5279d6ee2a0f2 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Tue, 26 May 2009 23:52:54 +0200 Subject: fixed hint tag for input fields --- examples/scripts/linkfollow.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 9b7d811..2adc03b 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -110,7 +110,7 @@ function setHints(r){ var item = items.snapshotItem(i); if(re.test(item) && isVisible(item) && elementInViewport(item)){ var h = generateHint(item,c); - item.appendChild(h); + item.parentNode.insertBefore(h,item); c++; } } @@ -132,15 +132,21 @@ function keyPressHandler(e) { doc.body.removeAttribute("onkeyup"); } } +function next(elem){ + do { + elem = elem.nextSibling; + } while (elem && elem.nodeType != 1); + return elem; +} function followLink(follow){ var m = new Matcher(follow); - var elements = doc.evaluate("//*/div[@class='"+uzblclass+"']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + var elements = doc.evaluate("//div[@class='"+uzblclass+"']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); // filter var matched = []; for (var i = 0; i < elements.snapshotLength;i++){ var item = elements.snapshotItem(i); - if(m.test(item.parentNode)){ - matched.push(item.parentNode); + if(m.test(next(item))){ + matched.push(next(item)); } } clearHints(); @@ -150,7 +156,8 @@ function followLink(follow){ var item = matched[parseInt(m.numbers,10)-1]; } if (item) { - item.style.backgroundColor = "blue"; + item.style.borderStyle = "dotted"; + item.style.borderWidth = "thin"; var name = item.tagName; if (name == 'A') { -- cgit v1.2.3 From 07d412af3c5b2503772357504fef42c85ec126d3 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Wed, 27 May 2009 01:58:01 +0200 Subject: moved the hint tags back into a main hint div --- examples/scripts/linkfollow.js | 104 ++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 2adc03b..5b72812 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -15,10 +15,27 @@ var uzblid = 'uzbl_hint'; -var uzblclass = 'uzbl_hint_class' +var uzblclass = 'uzbl_hint_class'; var doc = document; + + +function hasClass(ele,cls) { + return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); +} +  +function addClass(ele,cls) { + if (!hasClass(ele,cls)) ele.className += " "+cls; +} +  +function removeClass(ele,cls) { + if (hasClass(ele,cls)) { + var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); + ele.className=ele.className.replace(reg,' '); + } +} + function elementPosition(el) { var up = el.offsetTop; var left = el.offsetLeft; var width = el.offsetWidth; @@ -32,9 +49,9 @@ function elementPosition(el) { return [up, left, width, height]; } -function generateHint(el, label) { +function generateHint(pos, label) { var hint = doc.createElement('div'); - hint.setAttribute('class', uzblclass); + hint.setAttribute('name', uzblid); hint.innerText = label; hint.style.display = 'inline'; hint.style.backgroundColor = '#B9FF00'; @@ -46,7 +63,13 @@ function generateHint(el, label) { hint.style.margin = '0px'; hint.style.padding = '1px'; hint.style.position = 'absolute'; - hint.style.zIndex = '10000'; + hint.style.zIndex = '1000'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + //var img = el.getElementsByTagName('img'); + //if (img.length > 0) { + // hint.style.left = pos[1] + img[0].width / 2 + 'px'; + //} hint.style.textDecoration = 'none'; hint.style.webkitBorderRadius = '6px'; // Play around with this, pretty funny things to do :) @@ -54,8 +77,8 @@ function generateHint(el, label) { return hint; } -function elementInViewport(el) { - offset = elementPosition(el); +function elementInViewport(offset) { +// offset = elementPosition(el); var up = offset[0]; var left = offset[1]; var width = offset[2]; @@ -104,24 +127,42 @@ function setHints(r){ if(doc.body) doc.body.setAttribute("onkeyup","keyPressHandler(event)"); var re = new Matcher(r); clearHints(); + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzblid); var c = 1; var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); for (var i = 0; i < items.snapshotLength;i++){ var item = items.snapshotItem(i); - if(re.test(item) && isVisible(item) && elementInViewport(item)){ - var h = generateHint(item,c); - item.parentNode.insertBefore(h,item); + var pos = elementPosition(item); + if(re.test(item) && isVisible(item) && elementInViewport(pos)){ + var h = generateHint(pos,c); + h.href = function () {return item}; + hintdiv.appendChild(h); + addClass(item,uzblclass); c++; } } + if (document.body) { + document.body.insertBefore(hintdiv,document.body.firstChild); + } } function clearHints(){ - var items = doc.evaluate("//div[@class='" + uzblclass + "']",doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0; i < items.snapshotLength;i++){ - var item = items.snapshotItem(i); - item.parentNode.removeChild(item); + var hintdiv = doc.getElementById(uzblid); + if(hintdiv){ + //var items = doc.evaluate('//*[contains(@class="' + uzblclass + '"])',doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + //for (var i = 0; i < items.snapshotLength;i++){ + // var item = items.snapshotItem(i); + // //item.parentNode.removeChild(item); + // removeClass(item,uzblclass); + //} + hintdiv.parentNode.removeChild(hintdiv); } + var items = doc.getElementsByClassName(uzblclass); + for (var i = 0; i Date: Wed, 27 May 2009 03:23:47 +0200 Subject: created a hint object --- examples/scripts/linkfollow.js | 381 ++++++++++++++++++++--------------------- 1 file changed, 184 insertions(+), 197 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 5b72812..769f127 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -3,230 +3,217 @@ // // first, it needs to be loaded before every time it is used. // One way would be to use something like load_start_handler to send -// "act script link_follower.js" +// "act script linkfollow.js" +// (currently, it is recommended to use load_finish_handler since the JS code seems to get +// flushed. Using a load_start_handler with a 1s delay works but not always) // // when script is loaded, it can be invoked with -// bind f* = js setHints("%s") -// bind f_ = js followLink("%s") +// bind f* = js hints.set("%s") +// bind f_ = js hints.follow("%s") // // based on follow_Numbers.js // -// TODO: add classes to hinted elements +// TODO: set CSS styles +// TODO: load the script as soon as the DOM is ready -var uzblid = 'uzbl_hint'; -var uzblclass = 'uzbl_hint_class'; +function Hints(){ + var uzblid = 'uzbl_hint'; + var uzblclass = 'uzbl_hint_class'; + var doc = document; + this.set = setHints; + this.follow = followHint; + this.keyPressHandler = keyPressHandler; -var doc = document; - - - -function hasClass(ele,cls) { - return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); -} -  -function addClass(ele,cls) { - if (!hasClass(ele,cls)) ele.className += " "+cls; -} -  -function removeClass(ele,cls) { - if (hasClass(ele,cls)) { - var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); - ele.className=ele.className.replace(reg,' '); + function hasClass(ele,cls) { + return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); + } +   + function addClass(ele,cls) { + if (!hasClass(ele,cls)) ele.className += " "+cls; + } +   + function removeClass(ele,cls) { + if (hasClass(ele,cls)) { + var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); + ele.className=ele.className.replace(reg,' '); + } } -} - -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; var width = el.offsetWidth; - var height = el.offsetHeight; - - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} - -function generateHint(pos, label) { - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '1000'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - //var img = el.getElementsByTagName('img'); - //if (img.length > 0) { - // hint.style.left = pos[1] + img[0].width / 2 + 'px'; - //} - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} -function elementInViewport(offset) { -// offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return (up < window.pageYOffset + window.innerHeight && - left < window.pageXOffset + window.innerWidth - && (up + height) > window.pageYOffset - && (left + width) > window.pageXOffset); -} + function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; var width = el.offsetWidth; + var height = el.offsetHeight; -function isVisible(el) { - - if (el == doc) { return true; } - if (!el) { return false; } - if (!el.parentNode) { return false; } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; } - return isVisible(el.parentNode); -} + return [up, left, width, height]; + } -var hintable = "//a[@href] | //img | //input"; - -function Matcher(str){ - var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); - this.test = test; - this.toString = toString; - this.numbers = numbers; - function test(element) { - // test all the regexp - return words.every(function (regex) { return element.textContent.match(regex)}); + function generateHint(pos, label) { + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '1000'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + //var img = el.getElementsByTagName('img'); + //if (img.length > 0) { + // hint.style.left = pos[1] + img[0].width / 2 + 'px'; + //} + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; } - function toString(){ - return "{"+numbers+"},{"+words+"}"; + + function elementInViewport(offset) { + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return (up < window.pageYOffset + window.innerHeight && + left < window.pageXOffset + window.innerWidth + && (up + height) > window.pageYOffset + && (left + width) > window.pageXOffset); } -} + function isVisible(el) { + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); + } -function setHints(r){ - if(doc.body) doc.body.setAttribute("onkeyup","keyPressHandler(event)"); - var re = new Matcher(r); - clearHints(); - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzblid); - var c = 1; - var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0; i < items.snapshotLength;i++){ - var item = items.snapshotItem(i); - var pos = elementPosition(item); - if(re.test(item) && isVisible(item) && elementInViewport(pos)){ - var h = generateHint(pos,c); - h.href = function () {return item}; - hintdiv.appendChild(h); - addClass(item,uzblclass); - c++; + var hintable = "//a[@href] | //img | //input"; + + function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function test(element) { + // test all the regexp + return words.every(function (regex) { return element.textContent.match(regex)}); + } + function toString(){ + return "{"+numbers+"},{"+words+"}"; } } - if (document.body) { - document.body.insertBefore(hintdiv,document.body.firstChild); - } -} -function clearHints(){ - var hintdiv = doc.getElementById(uzblid); - if(hintdiv){ - //var items = doc.evaluate('//*[contains(@class="' + uzblclass + '"])',doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - //for (var i = 0; i < items.snapshotLength;i++){ - // var item = items.snapshotItem(i); - // //item.parentNode.removeChild(item); - // removeClass(item,uzblclass); - //} - hintdiv.parentNode.removeChild(hintdiv); - } - var items = doc.getElementsByClassName(uzblclass); - for (var i = 0; i Date: Wed, 27 May 2009 03:31:28 +0200 Subject: updated the yank.sh --- examples/configs/sampleconfig | 4 ++-- examples/scripts/yank.sh | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 06f3f13..df9b77b 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -89,8 +89,8 @@ bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 8 primary -bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard +bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 6 primary +bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script bind y2url = sh "echo -n $6 | xclip" # go the page from primary selection diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh index d4926be..ee140c7 100755 --- a/examples/scripts/yank.sh +++ b/examples/scripts/yank.sh @@ -2,10 +2,11 @@ # in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) # make the 2nd argument one of : primary, secondary, clipboard. # examples: -# bind yurl = spawn ./examples/scripts/yank.sh 8 primary -# bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard +# bind yurl = spawn ./examples/scripts/yank.sh 6 primary +# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard which xclip &>/dev/null || exit 1 -[ "$2" == primary -o "$2" == secondary -o "$2" == clipboard ] || exit 2 +[ "$9" == primary -o "$9" == secondary -o "$9" == clipboard ] || exit 2 -echo -n "${!1}" | xclip -selection $2 \ No newline at end of file +echo echo -n "${!8}" '|' xclip -selection $9 +echo -n "${!8}" | xclip -selection $9 -- cgit v1.2.3 From fbe5fd9783f4bba229a192e79eecc98b5279039c Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Wed, 27 May 2009 04:57:44 +0200 Subject: added (buggy) hint styling --- examples/data/style.css | 3 +++ examples/scripts/linkfollow.js | 37 ++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 examples/data/style.css (limited to 'examples') diff --git a/examples/data/style.css b/examples/data/style.css new file mode 100644 index 0000000..81bb6df --- /dev/null +++ b/examples/data/style.css @@ -0,0 +1,3 @@ +.uzbl_hint_class { background-color: yellow;} +.uzbl_hint_first { background-color: lightgreen;} + diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 769f127..327b82c 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -11,22 +11,27 @@ // bind f* = js hints.set("%s") // bind f_ = js hints.follow("%s") // +// To enable hint highlighting, add: +// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css +// // based on follow_Numbers.js // -// TODO: set CSS styles +// TODO: set CSS styles (done, but not working properly) // TODO: load the script as soon as the DOM is ready + function Hints(){ var uzblid = 'uzbl_hint'; - var uzblclass = 'uzbl_hint_class'; + var uzblclass = "uzbl_hint_class"; + var uzblclassfirst = "uzbl_hint_first"; var doc = document; this.set = setHints; this.follow = followHint; this.keyPressHandler = keyPressHandler; function hasClass(ele,cls) { - return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)')); + return ele.className.split(/ /).some(function (n) { return n == cls }); }   function addClass(ele,cls) { @@ -34,10 +39,7 @@ function Hints(){ }   function removeClass(ele,cls) { - if (hasClass(ele,cls)) { - var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)'); - ele.className=ele.className.replace(reg,' '); - } + ele.className = ele.className.split(/ /).filter(function (n) { n != cls}).join(" "); } function elementPosition(el) { @@ -140,7 +142,12 @@ function Hints(){ var h = generateHint(pos,c); h.href = function () {return item}; hintdiv.appendChild(h); - addClass(item,uzblclass); + if(c==1){ + addClass(item,uzblclassfirst); + // addClass(item,uzblclass); + } else { + addClass(item,uzblclass); + } c++; } } @@ -154,10 +161,15 @@ function Hints(){ if(hintdiv){ hintdiv.parentNode.removeChild(hintdiv); } + var first = doc.getElementsByClassName(uzblclassfirst)[0]; + if(first){ + removeClass(first,uzblclassfirst); + } + // TODO: not all class attributes get removed var items = doc.getElementsByClassName(uzblclass); - for (var i = 0; i Date: Wed, 27 May 2009 18:43:26 +0200 Subject: the hint styles are moved into ./examples/data/style.css --- examples/data/style.css | 23 +++++++++++++-- examples/scripts/linkfollow.js | 64 ++++++++++++++++++------------------------ 2 files changed, 48 insertions(+), 39 deletions(-) (limited to 'examples') diff --git a/examples/data/style.css b/examples/data/style.css index 81bb6df..9789e6f 100644 --- a/examples/data/style.css +++ b/examples/data/style.css @@ -1,3 +1,22 @@ -.uzbl_hint_class { background-color: yellow;} -.uzbl_hint_first { background-color: lightgreen;} +.uzbl_highlight { background-color: yellow;} +.uzbl_h_first { background-color: lightgreen;} + +#uzbl_hint > div { + display: inline; + border: 2px solid #4a6600; + background-color: #b9ff00; + color: black; + font-size: 9px; + font-weight: bold; + line-height: 9px; + margin: 0px; + padding: 0px; + position: absolute; + z-index: 1000; + -webkit-border-radius: 6px; + text-decoration: none; + -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); +} + +/* vim:set et ts=4: */ diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 327b82c..1ff7b4e 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -3,7 +3,7 @@ // // first, it needs to be loaded before every time it is used. // One way would be to use something like load_start_handler to send -// "act script linkfollow.js" +// "act script /usr/share/examples/scripts/linkfollow.js" // (currently, it is recommended to use load_finish_handler since the JS code seems to get // flushed. Using a load_start_handler with a 1s delay works but not always) // @@ -11,6 +11,9 @@ // bind f* = js hints.set("%s") // bind f_ = js hints.follow("%s") // +// At the moment, it may be useful to have way of forcing uzbl to load the script +// bind :lf = script /usr/share/examples/scripts/linkfollow.js +// // To enable hint highlighting, add: // set stylesheet_uri = /usr/share/uzbl/examples/data/style.css // @@ -23,8 +26,8 @@ function Hints(){ var uzblid = 'uzbl_hint'; - var uzblclass = "uzbl_hint_class"; - var uzblclassfirst = "uzbl_hint_first"; + var uzblclass = 'uzbl_highlight'; + var uzblclassfirst = 'uzbl_h_first'; var doc = document; this.set = setHints; this.follow = followHint; @@ -59,27 +62,13 @@ function Hints(){ var hint = doc.createElement('div'); hint.setAttribute('name', uzblid); hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '1000'; + //the css is set with ./examples/data/style.css hint.style.left = pos[1] + 'px'; hint.style.top = pos[0] + 'px'; //var img = el.getElementsByTagName('img'); //if (img.length > 0) { // hint.style.left = pos[1] + img[0].width / 2 + 'px'; //} - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; return hint; } @@ -203,25 +192,25 @@ function Hints(){ item.style.borderStyle = "dotted"; item.style.borderWidth = "thin"; - var name = item.tagName; - if (name == 'A') { - if(item.click) {item.click()}; - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } + var name = item.tagName; + if (name == 'A') { + if(item.click) {item.click()}; + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } } } } @@ -230,5 +219,6 @@ var hints; var hints = new Hints(); +// vim:set et tw=2: -- cgit v1.2.3 From 075fe52dac7f032640669f7c454789ba6506f1b6 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 27 May 2009 21:40:20 +0200 Subject: put sample indicators in config --- examples/configs/sampleconfig-dev | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3deeac1..0dcc0d2 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -60,7 +60,7 @@ set shell_cmd = sh -c set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser @@ -69,7 +69,8 @@ set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI set status_pbar_done = * set status_pbar_pending = - set status_pbar_width = 12 - +set insert_indicator = I +set command_indicator = C set modkey = Mod1 # reset to command mode when new page is loaded set reset_command_mode = 1 -- cgit v1.2.3 From bf412203b44431ee61936615664b60fca817592a Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 00:19:46 +0200 Subject: rewrite of linkfollow --- examples/scripts/linkfollow.js | 375 +++++++++++++++++++++-------------------- 1 file changed, 190 insertions(+), 185 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 1ff7b4e..382d33d 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -19,205 +19,210 @@ // // based on follow_Numbers.js // -// TODO: set CSS styles (done, but not working properly) +// TODO: fix styling for the first element // TODO: load the script as soon as the DOM is ready - function Hints(){ - var uzblid = 'uzbl_hint'; - var uzblclass = 'uzbl_highlight'; - var uzblclassfirst = 'uzbl_h_first'; - var doc = document; - this.set = setHints; - this.follow = followHint; - this.keyPressHandler = keyPressHandler; - - function hasClass(ele,cls) { - return ele.className.split(/ /).some(function (n) { return n == cls }); - } -   - function addClass(ele,cls) { - if (!hasClass(ele,cls)) ele.className += " "+cls; - } -   - function removeClass(ele,cls) { - ele.className = ele.className.split(/ /).filter(function (n) { n != cls}).join(" "); - } - - function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; var width = el.offsetWidth; - var height = el.offsetHeight; - - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; - } - - function generateHint(pos, label) { - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - //the css is set with ./examples/data/style.css - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - //var img = el.getElementsByTagName('img'); - //if (img.length > 0) { - // hint.style.left = pos[1] + img[0].width / 2 + 'px'; - //} - return hint; - } - - function elementInViewport(offset) { - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return (up < window.pageYOffset + window.innerHeight && - left < window.pageXOffset + window.innerWidth - && (up + height) > window.pageYOffset - && (left + width) > window.pageXOffset); - } - - function isVisible(el) { - if (el == doc) { return true; } - if (!el) { return false; } - if (!el.parentNode) { return false; } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); - } - - var hintable = "//a[@href] | //img | //input"; - - function Matcher(str){ - var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); - this.test = test; - this.toString = toString; - this.numbers = numbers; - function test(element) { - // test all the regexp - return words.every(function (regex) { return element.textContent.match(regex)}); - } - function toString(){ - return "{"+numbers+"},{"+words+"}"; - } - } - - - function setHints(r){ - if(doc.body) doc.body.onkeyup = this.keyPressHandler; - var re = new Matcher(r); - clearHints(); - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzblid); - var c = 1; - var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0; i < items.snapshotLength;i++){ - var item = items.snapshotItem(i); - var pos = elementPosition(item); - if(re.test(item) && isVisible(item) && elementInViewport(pos)){ - var h = generateHint(pos,c); - h.href = function () {return item}; - hintdiv.appendChild(h); - if(c==1){ - addClass(item,uzblclassfirst); - // addClass(item,uzblclass); - } else { - addClass(item,uzblclass); - } - c++; - } - } - if (document.body) { - document.body.insertBefore(hintdiv,document.body.firstChild); - } - } - - function clearHints(){ - var hintdiv = doc.getElementById(uzblid); - if(hintdiv){ - hintdiv.parentNode.removeChild(hintdiv); - } - var first = doc.getElementsByClassName(uzblclassfirst)[0]; - if(first){ - removeClass(first,uzblclassfirst); - } - // TODO: not all class attributes get removed - var items = doc.getElementsByClassName(uzblclass); - for (var i = 0; i window.pageYOffset && + (left + width) > window.pageXOffset); + } + + function isVisible(el) { + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); + } + + var hintable = "//a[@href] | //img | //input"; + + function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function test(element) { + // test all the regexp + return words.every(function (regex) { return element.node.textContent.match(regex)}); + } + } + + function HintElement(node,pos){ + + this.node = node; + this.isHinted = false; + this.position = pos; + + this.addHint = function (labelNum) { + if(!this.isHinted){ + this.node.className += " " + uzblclass; + } + this.isHinted = true; + + // create hint + var hintNode = doc.createElement('div'); + hintNode.name = uzblid; + hintNode.innerText = labelNum; + hintNode.style.left = this.position[1] + 'px'; + hintNode.style.top = this.position[0] + 'px'; + hintNode.style.position = "absolute"; + doc.body.firstChild.appendChild(hintNode); + + } + this.removeHint = function(){ + if(this.isHinted){ + var s = (this.num)?uzblclassfirst:uzblclass; + this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); + this.isHinted = false; + } + } + } + + function createHintDiv(){ + var hintdiv = doc.getElementById(uzblid); + if(hintdiv){ + hintdiv.parentNode.removeChild(hintdiv); + } + hintdiv = doc.createElement("div"); + hintdiv.setAttribute('id',uzblid); + doc.body.insertBefore(hintdiv,doc.body.firstChild); + return hintdiv; + } + + function init(){ + // WHAT? + doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); + hintdiv = createHintDiv(); + visible = []; + + var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0;i Date: Thu, 28 May 2009 00:33:08 +0200 Subject: minor fix --- examples/scripts/linkfollow.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 382d33d..20a756f 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -45,18 +45,14 @@ function Hints(){ up += el.offsetTop; left += el.offsetLeft; } - return [up, left, width, height]; + return {up: up, left: left, width: width, height: height}; } - function elementInViewport(offset) { - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return (up < window.pageYOffset + window.innerHeight && - left < window.pageXOffset + window.innerWidth && - (up + height) > window.pageYOffset && - (left + width) > window.pageXOffset); + function elementInViewport(p) { + return (p.up < window.pageYOffset + window.innerHeight && + p.left < window.pageXOffset + window.innerWidth && + (p.up + p.height) > window.pageYOffset && + (p.left + p.width) > window.pageXOffset); } function isVisible(el) { @@ -95,6 +91,7 @@ function Hints(){ this.position = pos; this.addHint = function (labelNum) { + // TODO: fix uzblclassfirst if(!this.isHinted){ this.node.className += " " + uzblclass; } @@ -104,8 +101,8 @@ function Hints(){ var hintNode = doc.createElement('div'); hintNode.name = uzblid; hintNode.innerText = labelNum; - hintNode.style.left = this.position[1] + 'px'; - hintNode.style.top = this.position[0] + 'px'; + hintNode.style.left = this.position.left + 'px'; + hintNode.style.top = this.position.up + 'px'; hintNode.style.position = "absolute"; doc.body.firstChild.appendChild(hintNode); -- cgit v1.2.3 From d5f877da89554d75f9b14e568fc35e2bdc0e555b Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 01:24:35 +0200 Subject: again, minor fixes --- examples/scripts/linkfollow.js | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 20a756f..5dbbd5b 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -14,7 +14,8 @@ // At the moment, it may be useful to have way of forcing uzbl to load the script // bind :lf = script /usr/share/examples/scripts/linkfollow.js // -// To enable hint highlighting, add: +// The default style for the hints are pretty ugly, so it is recommended to add the following +// to config file // set stylesheet_uri = /usr/share/uzbl/examples/data/style.css // // based on follow_Numbers.js @@ -70,7 +71,8 @@ function Hints(){ return isVisible(el.parentNode); } - var hintable = "//a[@href] | //img | //input"; + // the vimperator defaults minus the xhtml elements, since it gave DOM errors + var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link'] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; function Matcher(str){ var numbers = str.replace(/[^\d]/g,""); @@ -179,10 +181,33 @@ function Hints(){ doc.body.removeAttribute("onkeyup"); } } + this.openInNewWindow = function(item){ + // TODO: this doesn't work + simulateMouseOver(item); + window.open(item.href,"uzbl new",""); + } + this.openInThisWindow = function(item){ + window.location = item.href; + } - function follow(str){ - var m = new Matcher(str); +// found on stackoverflow +// function simulateMouseOver(item){ +// var evt = doc.createEvent("MouseEvents"); +// evt.initMouseEvent("mouseover",true,true, +// doc.defaultView,0,0,0,0,0, +// false,false,false,false,0,null); +// var canceled = !item.dispatchEvent(evt); +// if(canceled){ +// alert('Event Cancelled'); +// } +// } + + function follow(str,opener){ + var m = new Matcher(str); + if(!opener){ + var opener = this.openInThisWindow; + } var items = visible.filter(function (n) { return n.isHinted }); clear(); var num = parseInt(m.numbers,10); @@ -192,13 +217,15 @@ function Hints(){ var item = items[0].node; } if (item) { + item.style.margin -= 3; + item.style.padding -= 3; item.style.borderStyle = "dotted"; item.style.borderWidth = "thin"; var name = item.tagName; if (name == 'A') { if(item.click) {item.click()}; - window.location = item.href; + opener(item); } else if (name == 'INPUT') { var type = item.getAttribute('type').toUpperCase(); if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { @@ -212,7 +239,7 @@ function Hints(){ item.select(); } else { item.click(); - window.location = item.href; + opener(item); } } } @@ -221,6 +248,6 @@ function Hints(){ var hints = new Hints(); //document.attachEvent("onKeyUp",hints.keyPressHandler); -// vim:set et tw=2: +// vim:set et sw=2: -- cgit v1.2.3 From 53464e2affa6635e32f0fd55ddb3ad5d5ef124ef Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 01:42:32 +0200 Subject: misplaced comment --- examples/scripts/linkfollow.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 5dbbd5b..472f85d 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -183,7 +183,6 @@ function Hints(){ } this.openInNewWindow = function(item){ // TODO: this doesn't work - simulateMouseOver(item); window.open(item.href,"uzbl new",""); } this.openInThisWindow = function(item){ @@ -217,6 +216,8 @@ function Hints(){ var item = items[0].node; } if (item) { + // This causes some elements to move around. Guess it should only be applied to + // links item.style.margin -= 3; item.style.padding -= 3; item.style.borderStyle = "dotted"; -- cgit v1.2.3 From 6e15eb4b1a9bbec813a21fc55eccadddb49fe396 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 13:06:05 +0200 Subject: * added requireReturn setting * changed the hinting functions arguments --- examples/scripts/linkfollow.js | 69 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 472f85d..2b381cc 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -2,14 +2,12 @@ // requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 // // first, it needs to be loaded before every time it is used. -// One way would be to use something like load_start_handler to send -// "act script /usr/share/examples/scripts/linkfollow.js" -// (currently, it is recommended to use load_finish_handler since the JS code seems to get -// flushed. Using a load_start_handler with a 1s delay works but not always) +// One way would be to use the load_commit_handler: +// set load_commit_handler = sh 'echo "act script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' // // when script is loaded, it can be invoked with -// bind f* = js hints.set("%s") -// bind f_ = js hints.follow("%s") +// bind f* = js hints.set("%s", hints.open) +// bind f_ = js hints.follow("%s",hints.open) // // At the moment, it may be useful to have way of forcing uzbl to load the script // bind :lf = script /usr/share/examples/scripts/linkfollow.js @@ -21,10 +19,17 @@ // based on follow_Numbers.js // // TODO: fix styling for the first element -// TODO: load the script as soon as the DOM is ready +// TODO: emulate mouseover events when visiting some elements +// TODO: rewrite the element->action handling function Hints(){ + + + // if set to true, you must explicitly call hints.follow(), otherwise it will + // follow the link if there is only one matching result + var requireReturn = true; + var uzblid = 'uzbl_hint'; var uzblclass = 'uzbl_highlight'; var uzblclassfirst = 'uzbl_h_first'; @@ -91,6 +96,7 @@ function Hints(){ this.node = node; this.isHinted = false; this.position = pos; + this.num = 0; this.addHint = function (labelNum) { // TODO: fix uzblclassfirst @@ -155,7 +161,7 @@ function Hints(){ } } - function update(str) { + function update(str,openFun) { var match = new Matcher(str); hintdiv = createHintDiv(); var i = 1; @@ -166,11 +172,16 @@ function Hints(){ } else { n.removeHint(); }}); + if(!requireReturn){ + if(i==2){ //only been incremented once + follow(str,openFun); + } + } } - function hint(str){ + function hint(str,openFun){ if(str.length == 0) init(); - update(str); + update(str,openFun); } function keyPressHandler(e) { @@ -181,32 +192,27 @@ function Hints(){ doc.body.removeAttribute("onkeyup"); } } - this.openInNewWindow = function(item){ - // TODO: this doesn't work - window.open(item.href,"uzbl new",""); + + this.openNewWindow = function(item){ + // TODO: this doesn't work yet + window.open(item.href,"uzblnew",""); } - this.openInThisWindow = function(item){ + this.open = function(item){ + simulateMouseOver(item); window.location = item.href; } -// found on stackoverflow -// function simulateMouseOver(item){ -// var evt = doc.createEvent("MouseEvents"); -// evt.initMouseEvent("mouseover",true,true, -// doc.defaultView,0,0,0,0,0, -// false,false,false,false,0,null); -// var canceled = !item.dispatchEvent(evt); -// if(canceled){ -// alert('Event Cancelled'); -// } -// } + function simulateMouseOver(item){ + var evt = doc.createEvent("MouseEvents"); + evt.initMouseEvent("MouseOver",true,true, + doc.defaultView,1,0,0,0,0, + false,false,false,false,0,null); + return item.dispatchEvent(evt); + } - function follow(str,opener){ + function follow(str,openFunction){ var m = new Matcher(str); - if(!opener){ - var opener = this.openInThisWindow; - } var items = visible.filter(function (n) { return n.isHinted }); clear(); var num = parseInt(m.numbers,10); @@ -226,7 +232,7 @@ function Hints(){ var name = item.tagName; if (name == 'A') { if(item.click) {item.click()}; - opener(item); + openFunction(item); } else if (name == 'INPUT') { var type = item.getAttribute('type').toUpperCase(); if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { @@ -240,14 +246,13 @@ function Hints(){ item.select(); } else { item.click(); - opener(item); + openFunction(item); } } } } var hints = new Hints(); -//document.attachEvent("onKeyUp",hints.keyPressHandler); // vim:set et sw=2: -- cgit v1.2.3 From 09ae8e31a84ef94e82ccecae2196bad9ba12c538 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 15:08:49 +0200 Subject: Zaba_'s patch, fixing filehandles and removing Switch.pm --- examples/scripts/formfiller.pl | 60 +++++++++++++++++++++--------------------- examples/scripts/linkfollow.js | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'examples') diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl index a6e07a0..22f2c0d 100755 --- a/examples/scripts/formfiller.pl +++ b/examples/scripts/formfiller.pl @@ -15,11 +15,11 @@ # bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit use strict; -use Switch; +use warnings; my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; -my ($config,$pid,$xid,$fifo,$socket,$url,$title,$cmd) = @ARGV; -if($fifo eq "") { die "No fifo"; }; +my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; +if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } sub domain { my ($url) = @_; @@ -41,29 +41,29 @@ my %command; $command{load} = sub { my ($domain) = @_; - my $file = "$keydir/$domain"; - if( -e $file){ - open(FH,$file); - my (@lines) = ; - close(FH); + my $filename = "$keydir/$domain"; + if (-e $filename){ + open(my $file, $filename) or die "Failed to open $filename: $!"; + my (@lines) = <$file>; + close($file); $|++; - open(FIFO,">>$fifo"); - print "opened $fifo\n"; + open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; foreach my $line (@lines) { - if($line !~ m/^#/){ - my ($type,$name,$value) = ($line =~ /\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); - switch ($type) { - case "" {} - case "checkbox" { printf FIFO 'act js document.getElementsByName("%s")[0].checked = %s;', $name, $value} - case "submit" { printf FIFO 'act js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name } - else { printf FIFO 'act js document.getElementsByName("%s")[0].value = "%s";', $name, $value} - } - - print FIFO "\n"; + next if ($line =~ m/^#/); + my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); + if ($type eq "checkbox") + { + printf $fifo 'act js document.getElementsByName("%s")[0].checked = %s;', $name, $value; + } elsif ($type eq "submit") + { + printf $fifo 'act js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; + } elsif ($type ne "") + { + printf $fifo 'act js document.getElementsByName("%s")[0].value = "%s";', $name, $value; } + print $fifo "\n"; } $|--; - close(FIFO); } else { $command{new}->($domain); $command{edit}->($domain); @@ -76,24 +76,24 @@ $command{edit} = sub { system ($editor, $file); } else { $command{new}->($domain); -} + } }; $command{new} = sub { my ($domain) = @_; - my $file = "$keydir/$domain"; - open(FILE,">>$file"); + my $filename = "$keydir/$domain"; + open (my $file,">>", $filename) or die "Failed to open $filename: $!"; $|++; - print FILE "#make sure that there are no extra submits, since it may trigger the wrong one\n"; - printf FILE "#%-10s | %-10s | %s\n", @fields; - print FILE "#------------------------------\n"; + print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; + printf $file "#%-10s | %-10s | %s\n", @fields; + print $file "#------------------------------\n"; my @data = `$downloader $url`; foreach my $line (@data){ if($line =~ m/].*?)>/i){ - $line =~ s/.*(].*?)>).*/\1/; - printf FILE " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; + $line =~ s/.*(].*?)>).*/$1/; + printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; }; }; - close(FILE); $|--; }; + $command{$cmd}->(domain($url)); diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 2b381cc..e77219c 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -77,7 +77,7 @@ function Hints(){ } // the vimperator defaults minus the xhtml elements, since it gave DOM errors - var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link'] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; + var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; function Matcher(str){ var numbers = str.replace(/[^\d]/g,""); -- cgit v1.2.3 From afce27422a221c718958a06a1e7f804f0a59003d Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Thu, 28 May 2009 22:13:24 +0200 Subject: OH GOD I DON'T KNOW WHAT I AM DOING --- docs/INSTALL | 2 +- examples/configs/sampleconfig-dev | 5 +- examples/data/style.css | 4 + examples/scripts/linkfollow.js | 22 +++-- uzbl.c | 171 ++++++++++++++++++++++++-------------- uzbl.h | 14 ++++ 6 files changed, 144 insertions(+), 74 deletions(-) (limited to 'examples') diff --git a/docs/INSTALL b/docs/INSTALL index 440157a..3453e03 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -29,7 +29,7 @@ Dependencies * pkgconfig (for Make/gcc) * libwebkit 1.1.4 or higher * libsoup 2.24 or higher (dep for webkit/gtk+) -* gtk 2 something something +* gtk 2.14 or higher Optional/Recommended -------------------- diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3deeac1..0dcc0d2 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -60,7 +60,7 @@ set shell_cmd = sh -c set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser @@ -69,7 +69,8 @@ set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI set status_pbar_done = * set status_pbar_pending = - set status_pbar_width = 12 - +set insert_indicator = I +set command_indicator = C set modkey = Mod1 # reset to command mode when new page is loaded set reset_command_mode = 1 diff --git a/examples/data/style.css b/examples/data/style.css index 9789e6f..de0a38b 100644 --- a/examples/data/style.css +++ b/examples/data/style.css @@ -1,6 +1,10 @@ .uzbl_highlight { background-color: yellow;} .uzbl_h_first { background-color: lightgreen;} +.uzbl_follow { border-style: dotted; + border-width: thin; +} + #uzbl_hint > div { display: inline; border: 2px solid #4a6600; diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index e77219c..aad7353 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -10,7 +10,7 @@ // bind f_ = js hints.follow("%s",hints.open) // // At the moment, it may be useful to have way of forcing uzbl to load the script -// bind :lf = script /usr/share/examples/scripts/linkfollow.js +// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js // // The default style for the hints are pretty ugly, so it is recommended to add the following // to config file @@ -25,11 +25,20 @@ function Hints(){ + // Settings + //////////////////////////////////////////////////////////////////////////// // if set to true, you must explicitly call hints.follow(), otherwise it will // follow the link if there is only one matching result var requireReturn = true; + // Case sensitivity flag + var matchCase = "i"; + + // For case sensitive matching, uncomment: + // var matchCase = ""; + + var uzblid = 'uzbl_hint'; var uzblclass = 'uzbl_highlight'; var uzblclassfirst = 'uzbl_h_first'; @@ -81,7 +90,7 @@ function Hints(){ function Matcher(str){ var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,"i")}); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); this.test = test; this.toString = toString; this.numbers = numbers; @@ -195,10 +204,12 @@ function Hints(){ this.openNewWindow = function(item){ // TODO: this doesn't work yet + item.className += " uzbl_follow"; window.open(item.href,"uzblnew",""); } this.open = function(item){ simulateMouseOver(item); + item.className += " uzbl_follow"; window.location = item.href; } @@ -222,13 +233,6 @@ function Hints(){ var item = items[0].node; } if (item) { - // This causes some elements to move around. Guess it should only be applied to - // links - item.style.margin -= 3; - item.style.padding -= 3; - item.style.borderStyle = "dotted"; - item.style.borderWidth = "thin"; - var name = item.tagName; if (name == 'A') { if(item.click) {item.click()}; diff --git a/uzbl.c b/uzbl.c index 60c9eaa..ba6655a 100644 --- a/uzbl.c +++ b/uzbl.c @@ -81,72 +81,75 @@ GOptionEntry entries[] = typedef const struct { void **ptr; int type; + int dump; void (*func)(void); } uzbl_cmdprop; enum {TYPE_INT, TYPE_STR}; /* an abbreviation to help keep the table's width humane */ -#define PTR(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .func = fun } +#define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun } const struct { char *name; uzbl_cmdprop cp; } var_name_to_ptr[] = { -/* variable name pointer to variable in code type callback function */ +/* variable name pointer to variable in code type dump callback function */ /* --------------------------------------------------------------------------------------- */ - { "uri", PTR(uzbl.state.uri, STR, cmd_load_uri)}, - { "mode", PTR(uzbl.behave.mode, INT, NULL)}, - { "inject_html", PTR(uzbl.behave.inject_html, STR, cmd_inject_html)}, - { "base_url", PTR(uzbl.behave.base_url, STR, NULL)}, - { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, NULL)}, - { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, NULL)}, - { "status_message", PTR(uzbl.gui.sbar.msg, STR, update_title)}, - { "show_status", PTR(uzbl.behave.show_status, INT, cmd_set_status)}, - { "status_top", PTR(uzbl.behave.status_top, INT, move_statusbar)}, - { "status_format", PTR(uzbl.behave.status_format, STR, update_title)}, - { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, update_title)}, - { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, update_title)}, - { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, update_title)}, - { "status_background", PTR(uzbl.behave.status_background, STR, update_title)}, - { "title_format_long", PTR(uzbl.behave.title_format_long, STR, update_title)}, - { "title_format_short", PTR(uzbl.behave.title_format_short, STR, update_title)}, - { "insert_mode", PTR(uzbl.behave.insert_mode, INT, NULL)}, - { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, cmd_always_insert_mode)}, - { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, NULL)}, - { "modkey", PTR(uzbl.behave.modkey, STR, cmd_modkey)}, - { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, NULL)}, - { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, NULL)}, - { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, NULL)}, - { "history_handler", PTR(uzbl.behave.history_handler, STR, NULL)}, - { "download_handler", PTR(uzbl.behave.download_handler, STR, NULL)}, - { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, cmd_cookie_handler)}, - { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, cmd_fifo_dir)}, - { "socket_dir", PTR(uzbl.behave.socket_dir, STR, cmd_socket_dir)}, - { "http_debug", PTR(uzbl.behave.http_debug, INT, cmd_http_debug)}, - { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, NULL)}, - { "proxy_url", PTR(uzbl.net.proxy_url, STR, set_proxy_url)}, - { "max_conns", PTR(uzbl.net.max_conns, INT, cmd_max_conns)}, - { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, cmd_max_conns_host)}, - { "useragent", PTR(uzbl.net.useragent, STR, cmd_useragent)}, + { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)}, + { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)}, + { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)}, + { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)}, + { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)}, + { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)}, + { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)}, + { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)}, + { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)}, + { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)}, + { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)}, + { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)}, + { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)}, + { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)}, + { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)}, + { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)}, + { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)}, + { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)}, + { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)}, + { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)}, + { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)}, + { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)}, + { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)}, + { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)}, + { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)}, + { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)}, + { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)}, + { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, + { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, + { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, + { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, + { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)}, + { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)}, + { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)}, + { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)}, + { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)}, /* exported WebKitWebSettings properties*/ - { "font_size", PTR(uzbl.behave.font_size, INT, cmd_font_size)}, - { "monospace_size", PTR(uzbl.behave.monospace_size, INT, cmd_font_size)}, - { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, cmd_minimum_font_size)}, - { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, cmd_disable_plugins)}, - { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, cmd_disable_scripts)}, - { "autoload_images", PTR(uzbl.behave.autoload_img, INT, cmd_autoload_img)}, - { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, cmd_autoshrink_img)}, - { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, cmd_enable_spellcheck)}, - { "enable_private", PTR(uzbl.behave.enable_private, INT, cmd_enable_private)}, - { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, cmd_print_bg)}, - { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, cmd_style_uri)}, - { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, cmd_resizable_txt)}, - { "default_encoding", PTR(uzbl.behave.default_encoding, STR, cmd_default_encoding)}, - { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, cmd_enforce_96dpi)}, - { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, cmd_caret_browsing)}, - - { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}} + { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)}, + { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)}, + { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)}, + { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)}, + { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)}, + { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)}, + { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)}, + { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)}, + { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)}, + { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)}, + { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)}, + { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)}, + { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)}, + { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)}, + { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)}, + + { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}} }, *n2v_p = var_name_to_ptr; const struct { @@ -386,23 +389,27 @@ scroll (GtkAdjustment* bar, GArray *argv) { gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount); } -static void scroll_begin(WebKitWebView* page, GArray *argv) { +static void +scroll_begin(WebKitWebView* page, GArray *argv) { (void) page; (void) argv; gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v)); } -static void scroll_end(WebKitWebView* page, GArray *argv) { +static void +scroll_end(WebKitWebView* page, GArray *argv) { (void) page; (void) argv; gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) - gtk_adjustment_get_page_size(uzbl.gui.bar_v)); } -static void scroll_vert(WebKitWebView* page, GArray *argv) { +static void +scroll_vert(WebKitWebView* page, GArray *argv) { (void) page; scroll(uzbl.gui.bar_v, argv); } -static void scroll_horz(WebKitWebView* page, GArray *argv) { +static void +scroll_horz(WebKitWebView* page, GArray *argv) { (void) page; scroll(uzbl.gui.bar_h, argv); } @@ -559,7 +566,8 @@ static struct {char *name; Command command[2];} cmdlist[] = { "dehilight", {dehilight, 0} }, { "toggle_insert_mode", {toggle_insert_mode, 0} }, { "runcmd", {runcmd, NOSPLIT} }, - { "set", {set_var, NOSPLIT} } + { "set", {set_var, NOSPLIT} }, + { "dump_config", {act_dump_config, 0} } }; static void @@ -611,6 +619,11 @@ set_var(WebKitWebView *page, GArray *argv) { g_free(ctl_line); } +static void +act_dump_config() { + dump_config(); +} + static void toggle_insert_mode(WebKitWebView *page, GArray *argv) { (void)page; @@ -893,7 +906,8 @@ expand_template(const char *template, gboolean escape_markup) { break; case SYM_MODE: g_string_append(ret, - uzbl.behave.insert_mode?"[I]":"[C]"); + uzbl.behave.insert_mode? + uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator); break; case SYM_MSG: g_string_append(ret, @@ -1457,17 +1471,19 @@ static void parse_cmd_line(const char *ctl_line) { gchar **tokens = NULL; Behaviour *b = &uzbl.behave; + size_t len=0; if(b->mode == M_HTML) { - - if(!strncmp(b->html_endmarker, ctl_line, strlen(b->html_endmarker))) { + len = strlen(b->html_endmarker); + /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */ + if(len == strlen(ctl_line)-1 && + !strncmp(b->html_endmarker, ctl_line, len)) { set_timeout(0); set_var_value("mode", "0"); render_html(); return; } else { - /* set an alarm to kill us after the timeout */ set_timeout(b->html_timeout); g_string_append(b->html_buffer, ctl_line); } @@ -2217,7 +2233,34 @@ set_up_inspector() { g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL); } +static void +dump_var_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + uzbl_cmdprop *c = v; + + if(!c->dump) + return; + + if(c->type == TYPE_STR) + printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" "); + else if(c->type == TYPE_INT) + printf("set %s = %d\n", (char *)k, (int)*c->ptr); +} + +static void +dump_key_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + Action *a = v; + + printf("bind %s = %s %s\n", (char *)k , + (char *)a->name, a->param?(char *)a->param:""); +} +static 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); +} /** -- MAIN -- **/ int @@ -2261,6 +2304,10 @@ main (int argc, char* argv[]) { uzbl.behave.html_timeout = 60; uzbl.behave.base_url = g_strdup("http://invalid"); + /* default mode indicators */ + uzbl.behave.insert_indicator = g_strdup("I"); + uzbl.behave.cmd_indicator = g_strdup("C"); + setup_regex(); setup_scanner(); commands_hash (); diff --git a/uzbl.h b/uzbl.h index cd5e3ef..8618675 100644 --- a/uzbl.h +++ b/uzbl.h @@ -171,6 +171,8 @@ typedef struct { guint mode; gchar* base_url; gchar* html_endmarker; + gchar* insert_indicator; + gchar* cmd_indicator; GString* html_buffer; guint html_timeout; @@ -416,12 +418,24 @@ save_cookies (SoupMessage *msg, static void set_var(WebKitWebView *page, GArray *argv); +static void +act_dump_config(); + static void render_html(); static void set_timeout(int seconds); +static void +dump_var_hash(gpointer k, gpointer v, gpointer ud); + +static void +dump_key_hash(gpointer k, gpointer v, gpointer ud); + +static void +dump_config(); + /* Command callbacks */ static void -- cgit v1.2.3 From 89916092aef4b603c3fb5a711f0475d49aa7868e Mon Sep 17 00:00:00 2001 From: uranther Date: Fri, 29 May 2009 15:47:55 -0400 Subject: Added reset_zoom_level() to reset zoom to 100%, and added keybinding in sampleconfig --- examples/configs/sampleconfig | 1 + uzbl.c | 7 +++++++ uzbl.h | 3 +++ 3 files changed, 11 insertions(+) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index a541854..881173c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -69,6 +69,7 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out +bind = = reset_zoom bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. diff --git a/uzbl.c b/uzbl.c index 1758638..acae3cf 100644 --- a/uzbl.c +++ b/uzbl.c @@ -544,6 +544,7 @@ static struct {char *name; Command command[2];} cmdlist[] = { "stop", {view_stop_loading, 0}, }, { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?). { "zoom_out", {view_zoom_out, 0}, }, + { "reset_zoom", {reset_zoom_level, 0}, }, { "uri", {load_uri, NOSPLIT} }, { "js", {run_js, NOSPLIT} }, { "script", {run_external_js, 0} }, @@ -706,6 +707,12 @@ search_reverse_text (WebKitWebView *page, GArray *argv) { search_text(page, argv, FALSE); } +static void +reset_zoom_level (WebKitWebView *page, GArray *argv) { + (void) argv; + webkit_web_view_set_zoom_level (page, 1.0); +} + static void dehilight (WebKitWebView *page, GArray *argv) { (void) argv; diff --git a/uzbl.h b/uzbl.h index 4c4c4ea..51a788c 100644 --- a/uzbl.h +++ b/uzbl.h @@ -397,6 +397,9 @@ search_forward_text (WebKitWebView *page, GArray *argv); static void search_reverse_text (WebKitWebView *page, GArray *argv); +static void +reset_zoom_level (WebKitWebView *page, GArray *argv); + static void dehilight (WebKitWebView *page, GArray *argv); -- cgit v1.2.3 From 79bc5894756cf9ea267ec80938e7c9fe4881d1b4 Mon Sep 17 00:00:00 2001 From: uranther Date: Fri, 29 May 2009 16:51:05 -0400 Subject: Replaced reset_zoom with zoom_level; added floats to commands --- README | 1 - examples/configs/sampleconfig | 2 +- uzbl.c | 22 ++++++++++++---------- uzbl.h | 9 ++++++--- 4 files changed, 19 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/README b/README index 4d537a4..71cdcfa 100644 --- a/README +++ b/README @@ -153,7 +153,6 @@ actions follows: * `stop` * `zoom_in` * `zoom_out` -* `reset_zoom` * `uri
` * `js ` - execute the javascript in `` diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 881173c..603ee0f 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -69,7 +69,7 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out -bind = = reset_zoom +bind = = sh "echo set zoom_level = 1.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. diff --git a/uzbl.c b/uzbl.c index acae3cf..4f12637 100644 --- a/uzbl.c +++ b/uzbl.c @@ -84,7 +84,7 @@ typedef const struct { void (*func)(void); } uzbl_cmdprop; -enum {TYPE_INT, TYPE_STR}; +enum {TYPE_INT, TYPE_STR, TYPE_FLOAT}; /* an abbreviation to help keep the table's width humane */ #define PTR(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .func = fun } @@ -129,10 +129,11 @@ const struct { { "max_conns", PTR(uzbl.net.max_conns, INT, cmd_max_conns)}, { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, cmd_max_conns_host)}, { "useragent", PTR(uzbl.net.useragent, STR, cmd_useragent)}, - /* exported WebKitWebSettings properties*/ + /* exported WebKitWebSettings properties */ { "font_size", PTR(uzbl.behave.font_size, INT, cmd_font_size)}, { "monospace_size", PTR(uzbl.behave.monospace_size, INT, cmd_font_size)}, { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, cmd_minimum_font_size)}, + { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT, cmd_zoom_level)}, { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, cmd_disable_plugins)}, { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, cmd_disable_scripts)}, { "autoload_images", PTR(uzbl.behave.autoload_img, INT, cmd_autoload_img)}, @@ -544,7 +545,6 @@ static struct {char *name; Command command[2];} cmdlist[] = { "stop", {view_stop_loading, 0}, }, { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?). { "zoom_out", {view_zoom_out, 0}, }, - { "reset_zoom", {reset_zoom_level, 0}, }, { "uri", {load_uri, NOSPLIT} }, { "js", {run_js, NOSPLIT} }, { "script", {run_external_js, 0} }, @@ -707,12 +707,6 @@ search_reverse_text (WebKitWebView *page, GArray *argv) { search_text(page, argv, FALSE); } -static void -reset_zoom_level (WebKitWebView *page, GArray *argv) { - (void) argv; - webkit_web_view_set_zoom_level (page, 1.0); -} - static void dehilight (WebKitWebView *page, GArray *argv) { (void) argv; @@ -1257,6 +1251,11 @@ cmd_font_size() { } } +static void +cmd_zoom_level() { + webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level); +} + static void cmd_disable_plugins() { g_object_set (G_OBJECT(view_settings()), "enable-plugins", @@ -1429,9 +1428,12 @@ set_var_value(gchar *name, gchar *val) { if (c->type == TYPE_STR) { g_free(*c->ptr); *c->ptr = g_strdup(val); - } else if(c->type == TYPE_INT) { + } else if (c->type == TYPE_INT) { int *ip = (int *)c->ptr; *ip = (int)strtoul(val, &endp, 10); + } else if (c->type == TYPE_FLOAT) { + float *fp = (float *)c->ptr; + *fp = (float)strtof(val, &endp); } /* invoke a command specific function */ diff --git a/uzbl.h b/uzbl.h index 51a788c..91421bd 100644 --- a/uzbl.h +++ b/uzbl.h @@ -155,6 +155,7 @@ typedef struct { guint font_size; guint monospace_size; guint minimum_font_size; + gfloat zoom_level; guint disable_plugins; guint disable_scripts; guint autoload_img; @@ -397,9 +398,6 @@ search_forward_text (WebKitWebView *page, GArray *argv); static void search_reverse_text (WebKitWebView *page, GArray *argv); -static void -reset_zoom_level (WebKitWebView *page, GArray *argv); - static void dehilight (WebKitWebView *page, GArray *argv); @@ -454,9 +452,14 @@ cmd_max_conns(); static void cmd_max_conns_host(); +/* exported WebKitWebSettings properties */ + static void cmd_font_size(); +static void +cmd_zoom_level(); + static void cmd_disable_plugins(); -- cgit v1.2.3 From e80ef2dc33edb53bf6a1e36b9c1db8a64dfb025c Mon Sep 17 00:00:00 2001 From: DuClare Date: Fri, 29 May 2009 23:53:13 +0300 Subject: Update sampleconfigs. Commands and actions have been merged :) --- examples/configs/sampleconfig | 12 ++++++------ examples/configs/sampleconfig-dev | 13 ++++++------- 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 06f3f13..42edf75 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -2,13 +2,13 @@ # example uzbl config. in a real config, we should obey the xdg spec # all settings are optional. you can use uzbl without any config at all (but it won't do much) -# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# keyboard behavior is vimstyle by default (all commands -> 1 key). set # always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the actions +# if you do this, make sure you've set a modkey so you can reach the commands # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -# You can use any action in place of spawn +# You can use any command in place of spawn set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.sh @@ -94,9 +94,9 @@ bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 9 clipboard # does the same as yurl but without needing a script bind y2url = sh "echo -n $6 | xclip" # go the page from primary selection -bind p = sh "echo act uri `xclip -selection primary -o` > $4" +bind p = sh "echo uri `xclip -selection primary -o` > $4" # go to the page in clipboard -bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" +bind P = sh "echo uri `xclip -selection clipboard -o` > $4" bind ZZ = exit bind S = js alert("hi"); # example showing how to use sh @@ -104,7 +104,7 @@ bind S = js alert("hi"); # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it # Parameters are separated by spaces and the script body must be one parameter, so enclose it in # quotes and escape any inner quotes using backslashes -bind XS = sh 'echo "act script alert (\'This is sent by the shell via a fifo\')" > "$4"' +bind XS = sh 'echo "js alert (\'This is sent by the shell via a fifo\')" > "$4"' # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3deeac1..002f550 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -2,13 +2,13 @@ # example uzbl config. in a real config, we should obey the xdg spec # all settings are optional. you can use uzbl without any config at all (but it won't do much) -# keyboard behavior is vimstyle by default (all actions -> 1 key). set +# keyboard behavior is vimstyle by default (all commands -> 1 key). set # always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the actions +# if you do this, make sure you've set a modkey so you can reach the commands # from insert mode by combining them with the modkey # TODO: ability to attach misc things (spawn , script ,.. to internal events) -# Usually you want to spawn a script to handle things, but any action (such as sh) can be used +# Usually you want to spawn a script to handle things, but any command (such as sh) can be used set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh set cookie_handler = spawn ./examples/scripts/cookies.sh @@ -130,9 +130,9 @@ bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard # does the same as yurl but without needing a script bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection -bind p = sh "echo act uri `xclip -selection primary -o` > $4" +bind p = sh "echo uri `xclip -selection primary -o` > $4" # go to the page in clipboard -bind P = sh "echo act uri `xclip -selection clipboard -o` > $4" +bind P = sh "echo uri `xclip -selection clipboard -o` > $4" bind ZZ = exit bind S = js alert("hi"); # example showing how to use sh @@ -142,8 +142,7 @@ bind S = js alert("hi"); # you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -bind XS = sh 'echo "act script alert (\\"This is sent by the shell via a fifo\\")" > "$4"' - +bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically bind za = spawn ./examples/scripts/formfiller.sh -- cgit v1.2.3 From 19861c22bc98358b379d4ebde0b07fd94f819e54 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 31 May 2009 17:59:14 +0200 Subject: select more sense making paths for cookie data and config --- examples/scripts/cookies.sh | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index cd449dc..ecb6d60 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -21,15 +21,16 @@ # http://kb.mozillazine.org/Cookies.txt # don't always append cookies, sometimes we need to overwrite -if [ -f /usr/share/uzbl/examples/configs/cookies ] -then - file=/usr/share/uzbl/examples/configs/cookies -else - file=./examples/configs/cookies #useful when developing -fi +[ -f /usr/share/uzbl/examples/configs/cookies ] && file=/usr/share/uzbl/examples/configs/cookies +[ -f $XDG_CONFIG_HOME/uzbl/cookies ] && file=$XDG_CONFIG_HOME/uzbl/cookies +[ -f ./examples/configs/cookies ] && file=./examples/configs/cookies #useful when developing +[ -z "$file" ] && exit 1 + +[ -d /usr/share/uzbl/examples/data ] && cookie_file=/usr/share/uzbl/examples/data/cookies.txt +[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt +[ -d ./examples/data/ ] && cookie_file=./examples/data/cookies.txt #useful when developing +[ -z "$cookie_file" ] && exit 1 -#cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt -cookie_file=./examples/data/cookies.txt which zenity &>/dev/null || exit 2 -- cgit v1.2.3 From 4fbcb2837c40036b2677470c07deaefc19996a86 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 31 May 2009 18:34:44 +0200 Subject: notify user of stuff re: cookies + save_cookie function --- examples/scripts/cookies.sh | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index ecb6d60..efac322 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -1,4 +1,7 @@ #!/bin/bash + +# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! + # this is an example script of how you could manage your cookies.. # we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) # This is one textfile with entries like this: @@ -31,7 +34,13 @@ [ -d ./examples/data/ ] && cookie_file=./examples/data/cookies.txt #useful when developing [ -z "$cookie_file" ] && exit 1 - +# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. +#notifier= +#notifier=notify-send +notify_wrapper () { + echo "$@" >> $HOME/cookielog +} +notifier=notify_wrapper which zenity &>/dev/null || exit 2 # Example cookie: @@ -53,6 +62,10 @@ field_name= field_value= field_exp='end_session' +function notify () { + [ -n "$notifier" ] && $notifier "$@" +} + # FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET function parse_cookie () { @@ -80,19 +93,32 @@ function parse_cookie () { # match cookies in cookies.txt againsh hostname and path function get_cookie () { path_esc=${path//\//\\/} - cookie=`awk "/^[^\t]*$host\t[^\t]*\t$path_esc/" $cookie_file 2>/dev/null | tail -n 1` + search="^[^\t]*$host\t[^\t]*\t$path_esc" + cookie=`awk "/$search/" $cookie_file 2>/dev/null | tail -n 1` if [ -z "$cookie" ] then + notify "Get_cookie: search: $search in $cookie_file -> no result" false else + notify "Get_cookie: search: $search in $cookie_file -> result: $cookie" read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" cookie="$name=$value" - #echo "COOKIE $cookie" >> $HOME/cookielog true fi } -[ $action == PUT ] && parse_cookie && echo -e "$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" >> $cookie_file +function save_cookie () { + if parse_cookie + then + data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" + notify "save_cookie: adding $data to $cookie_file" + echo -e "$data" >> $cookie_file + else + notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" + fi +} + +[ $action == PUT ] && save_cookie [ $action == GET ] && get_cookie && echo "$cookie" exit -- cgit v1.2.3 From ce4ce4ad0cdb53af39092607fadc0b94e609d2e3 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 31 May 2009 23:29:09 +0200 Subject: adapt to new syntax --- examples/scripts/load_url_from_bookmarks.sh | 4 ++-- examples/scripts/load_url_from_history.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/scripts/load_url_from_bookmarks.sh b/examples/scripts/load_url_from_bookmarks.sh index 21ea33d..1ae39ff 100755 --- a/examples/scripts/load_url_from_bookmarks.sh +++ b/examples/scripts/load_url_from_bookmarks.sh @@ -18,5 +18,5 @@ else goto=`awk '{print $1}' $file | $DMENU $COLORS` fi -#[ -n "$goto" ] && echo "act uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh index 649c6b7..37c2afc 100755 --- a/examples/scripts/load_url_from_history.sh +++ b/examples/scripts/load_url_from_history.sh @@ -17,5 +17,5 @@ else current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` fi -[ -n "$goto" ] && echo "act uri $goto" > $4 -#[ -n "$goto" ] && uzblctrl -s $5 -c "act uri $goto" +[ -n "$goto" ] && echo "uri $goto" > $4 +#[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" -- cgit v1.2.3 From 16bb4ad6493cb7e5b4c15014670106428085deb3 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Mon, 1 Jun 2009 14:11:33 +0200 Subject: Removed "act" from utility scripts --- examples/scripts/clipboard.sh | 2 +- examples/scripts/formfiller.pl | 6 +++--- examples/scripts/formfiller.sh | 2 +- examples/scripts/linkfollow.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh index e13f053..c64b65c 100755 --- a/examples/scripts/clipboard.sh +++ b/examples/scripts/clipboard.sh @@ -9,7 +9,7 @@ selection=$(xclip -o) case $action in "yank" ) echo -n "$url" | xclip;; - "goto" ) echo "act uri $selection" > "$fifo";; + "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl index 22f2c0d..c590836 100755 --- a/examples/scripts/formfiller.pl +++ b/examples/scripts/formfiller.pl @@ -53,13 +53,13 @@ $command{load} = sub { my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); if ($type eq "checkbox") { - printf $fifo 'act js document.getElementsByName("%s")[0].checked = %s;', $name, $value; + printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; } elsif ($type eq "submit") { - printf $fifo 'act js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; + printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; } elsif ($type ne "") { - printf $fifo 'act js document.getElementsByName("%s")[0].value = "%s";', $name, $value; + printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; } print $fifo "\n"; } diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh index 45cde69..5debcce 100755 --- a/examples/scripts/formfiller.sh +++ b/examples/scripts/formfiller.sh @@ -49,7 +49,7 @@ domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') if [ "$action" = 'load' ] then [[ -e $keydir/$domain ]] || exit 2 - gawk -F': ' '{ print "act js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo + gawk -F': ' '{ print "js document.getElementsByName(\"" $1 "\")[0].value = \"" $2 "\";"}' $keydir/$domain >> $fifo else if [ "$action" == 'new' ] then diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index aad7353..b90b82d 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -3,7 +3,7 @@ // // first, it needs to be loaded before every time it is used. // One way would be to use the load_commit_handler: -// set load_commit_handler = sh 'echo "act script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' +// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' // // when script is loaded, it can be invoked with // bind f* = js hints.set("%s", hints.open) -- cgit v1.2.3 From dc1cd0bdaca44344bbd0e883f9ff7e14d476236e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 1 Jun 2009 17:23:33 +0200 Subject: fix fields for other sample config too --- examples/configs/sampleconfig-dev | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 3e2920f..c1c2e1d 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -126,8 +126,8 @@ bind B = spawn ./examples/scripts/insert_bookmark.sh bind U = spawn ./examples/scripts/load_url_from_history.sh bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn ./examples/scripts/yank.sh 8 primary -bind ytitle = spawn ./examples/scripts/yank.sh 9 clipboard +bind yurl = spawn ./examples/scripts/yank.sh 6 primary +bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection -- cgit v1.2.3 From dd6e51e7dde46dd64d703e7fda566dad7c87b82e Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Mon, 1 Jun 2009 19:29:53 +0200 Subject: match against buttons values --- examples/scripts/linkfollow.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index b90b82d..3b40f37 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -94,9 +94,17 @@ function Hints(){ this.test = test; this.toString = toString; this.numbers = numbers; + function matchAgainst(element){ + if(element.node.nodeName == "INPUT"){ + return element.node.title; + } else { + return element.node.textContent; + } + } function test(element) { // test all the regexp - return words.every(function (regex) { return element.node.textContent.match(regex)}); + var item = matchAgainst(element); + return words.every(function (regex) { return item.match(regex)}); } } -- cgit v1.2.3 From 488fa0c7963053fb8618fd4322f91b887308173c Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Mon, 1 Jun 2009 19:40:33 +0200 Subject: match against value on input forms --- examples/scripts/linkfollow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js index 3b40f37..a348af9 100644 --- a/examples/scripts/linkfollow.js +++ b/examples/scripts/linkfollow.js @@ -96,7 +96,7 @@ function Hints(){ this.numbers = numbers; function matchAgainst(element){ if(element.node.nodeName == "INPUT"){ - return element.node.title; + return element.node.value; } else { return element.node.textContent; } -- cgit v1.2.3 From f3ee2bb1790e96041bfc920e14d32518bf096e59 Mon Sep 17 00:00:00 2001 From: uranther Date: Mon, 1 Jun 2009 14:58:14 -0400 Subject: fixed sampleconfig so zoom level works again (changed = to 0) --- examples/configs/sampleconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index ce36fa6..6121ac4 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -69,7 +69,7 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out -bind = = sh "echo set zoom_level = 1.0 > $4" +bind 0 = sh "echo set zoom_level = 1.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. -- cgit v1.2.3 From bcae0ddb8615d2d5de180b2c781dd2ddda9332c2 Mon Sep 17 00:00:00 2001 From: bobpaul Date: Tue, 2 Jun 2009 16:58:50 -0500 Subject: Fixed session.sh script. --- examples/scripts/session.sh | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh index b8e2bd6..6d2a64d 100755 --- a/examples/scripts/session.sh +++ b/examples/scripts/session.sh @@ -1,34 +1,48 @@ #!/bin/bash # Very simple session manager for uzbl. When called with "endsession" as the -# argument, it'lla empty the sessionfile, look for fifos in $fifodir and +# argument, it'll backup $sessionfile, look for fifos in $fifodir and # instruct each of them to store their current url in $sessionfile and # terminate themselves. Run with "launch" as the argument and an instance of # uzbl will be launched for each stored url. "endinstance" is used internally # and doesn't need to be called manually at any point. +# Add a line like 'bind quit = /path/to/session.sh endsession' to your config - -scriptfile=$XDG_CONFIG_HOME/uzbl/session.sh # this script +scriptfile=$0 # this script sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored -UZBL="uzbl" # add custom flags and whatever here. +configfile=$XDG_DATA_HOME/uzbl/config # uzbl configuration file +UZBL="uzbl -c $configfile" # add custom flags and whatever here. fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere thisfifo="$4" act="$8" url="$6" +if [ "$act." = "." ]; then + act="$1" +fi + + case $act in "launch" ) - for url in $(cat $sessionfile); do - $UZBL --uri "$url" & - done - exit 0;; + urls=$(cat $sessionfile) + if [ "$urls." = "." ]; then + $UZBL + else + for url in $urls; do + $UZBL --uri "$url" & + done + fi + exit 0 + ;; + "endinstance" ) if [ "$url" != "(null)" ]; then echo "$url" >> $sessionfile; fi echo "exit" > "$thisfifo" ;; + "endsession" ) echo -n "" > "$sessionfile" for fifo in $fifodir/uzbl_fifo_*; do @@ -36,7 +50,13 @@ case $act in echo "spawn $scriptfile endinstance" > "$fifo" fi done - echo "spawn $scriptfile endinstance" > "$thisfifo";; - * ) echo "session manager: bad action";; + echo "spawn $scriptfile endinstance" > "$thisfifo" + ;; + + * ) echo "session manager: bad action" + echo "Usage: $scriptfile [COMMAND] where commands are:" + echo " launch - Restore a saved session or start a new one" + echo " endsession - Quit the running session. Must be called from uzbl" + ;; esac -- cgit v1.2.3 From a5e6e17fe183ce7b9fcfc353c1a608cb23e2e61b Mon Sep 17 00:00:00 2001 From: bobpaul Date: Wed, 3 Jun 2009 20:33:55 -0500 Subject: session.sh: backup rather than clearing existing session file --- examples/scripts/session.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh index 6d2a64d..e2642c7 100755 --- a/examples/scripts/session.sh +++ b/examples/scripts/session.sh @@ -44,7 +44,7 @@ case $act in ;; "endsession" ) - echo -n "" > "$sessionfile" + mv "$sessionfile" "$sessionfile~" for fifo in $fifodir/uzbl_fifo_*; do if [ "$fifo" != "$thisfifo" ]; then echo "spawn $scriptfile endinstance" > "$fifo" -- cgit v1.2.3 From 5ca3e6f86217c0615e806301e7bc0cb82ff27da4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 6 Jun 2009 18:57:58 +0200 Subject: bit more clear variable names and such --- examples/scripts/cookies.sh | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index efac322..c0c37db 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -24,22 +24,24 @@ # http://kb.mozillazine.org/Cookies.txt # don't always append cookies, sometimes we need to overwrite -[ -f /usr/share/uzbl/examples/configs/cookies ] && file=/usr/share/uzbl/examples/configs/cookies -[ -f $XDG_CONFIG_HOME/uzbl/cookies ] && file=$XDG_CONFIG_HOME/uzbl/cookies -[ -f ./examples/configs/cookies ] && file=./examples/configs/cookies #useful when developing -[ -z "$file" ] && exit 1 +[ -f /usr/share/uzbl/examples/configs/cookies ] && cookie_config=/usr/share/uzbl/examples/configs/cookies +[ -f $XDG_CONFIG_HOME/uzbl/cookies ] && cookie_config=$XDG_CONFIG_HOME/uzbl/cookies +[ -f ./examples/configs/cookies ] && cookie_config=./examples/configs/cookies #useful when developing +[ -z "$cookie_config" ] && exit 1 + +[ -d /usr/share/uzbl/examples/data ] && cookie_data=/usr/share/uzbl/examples/data/cookies.txt +[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_data=$XDG_DATA_HOME/uzbl/cookies.txt +[ -d ./examples/data/ ] && cookie_data=./examples/data/cookies.txt #useful when developing +[ -z "$cookie_data" ] && exit 1 -[ -d /usr/share/uzbl/examples/data ] && cookie_file=/usr/share/uzbl/examples/data/cookies.txt -[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_file=$XDG_DATA_HOME/uzbl/cookies.txt -[ -d ./examples/data/ ] && cookie_file=./examples/data/cookies.txt #useful when developing -[ -z "$cookie_file" ] && exit 1 -# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. #notifier= #notifier=notify-send notify_wrapper () { echo "$@" >> $HOME/cookielog } + +# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. notifier=notify_wrapper which zenity &>/dev/null || exit 2 @@ -90,17 +92,17 @@ function parse_cookie () { unset IFS } -# match cookies in cookies.txt againsh hostname and path +# match cookies in cookies.txt against hostname and path function get_cookie () { path_esc=${path//\//\\/} search="^[^\t]*$host\t[^\t]*\t$path_esc" - cookie=`awk "/$search/" $cookie_file 2>/dev/null | tail -n 1` + cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` if [ -z "$cookie" ] then - notify "Get_cookie: search: $search in $cookie_file -> no result" + notify "Get_cookie: search: $search in $cookie_data -> no result" false else - notify "Get_cookie: search: $search in $cookie_file -> result: $cookie" + notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" cookie="$name=$value" true @@ -111,8 +113,8 @@ function save_cookie () { if parse_cookie then data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" - notify "save_cookie: adding $data to $cookie_file" - echo -e "$data" >> $cookie_file + notify "save_cookie: adding $data to $cookie_data" + echo -e "$data" >> $cookie_data else notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" fi @@ -128,15 +130,15 @@ exit # $1 = section (TRUSTED or DENY) # $2 =url function match () { - sed -n "/$1/,/^\$/p" $file 2>/dev/null | grep -q "^$host" + sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" } function fetch_cookie () { - cookie=`cat $cookie_file/$host.cookie` + cookie=`cat $cookie_data` } function store_cookie () { - echo $cookie > $cookie_file/$host.cookie + echo $cookie > $cookie_data } if match TRUSTED $host -- cgit v1.2.3 From b121e01f4139136b193c8b277777a1d019f596f2 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 6 Jun 2009 20:09:12 +0200 Subject: use stdlib atof() instead of gnu99 strtof() + more sense making example binds for zoomlevels --- examples/configs/sampleconfig | 3 ++- examples/configs/sampleconfig-dev | 3 ++- uzbl.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 9bb0025..e853836 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -69,7 +69,8 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out -bind 0 = sh "echo set zoom_level = 1.0 > $4" +bind 1 = sh "echo set zoom_level = 1.0 > $4" +bind 2 = sh "echo set zoom_level = 2.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index c8eddd0..ad6de24 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -104,7 +104,8 @@ bind r = reload bind R = reload_ign_cache bind + = zoom_in bind - = zoom_out -bind 0 = sh "echo set zoom_level = 1.0 > $4" +bind 1 = sh "echo set zoom_level = 1.0 > $4" +bind 2 = sh "echo set zoom_level = 2.0 > $4" bind t = toggle_status # Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called # on every character you type. You can do `bind /_ = search %s' if you want it less interactive. diff --git a/uzbl.c b/uzbl.c index 4c37f08..1564192 100644 --- a/uzbl.c +++ b/uzbl.c @@ -1558,7 +1558,7 @@ set_var_value(gchar *name, gchar *val) { } else if (c->type == TYPE_FLOAT) { float *fp = (float *)c->ptr; buf = expand_vars(val); - *fp = strtof(buf, &endp); + *fp = atof(buf); g_free(buf); } -- cgit v1.2.3 From e752dc9376787b2545a0fcdb7594f1ccf1398483 Mon Sep 17 00:00:00 2001 From: Maximilian Gaß Date: Wed, 3 Jun 2009 21:13:50 +0200 Subject: examples/scripts/download.sh: pushd/popd are unnecessary there is nothing affected by the directory of that shell --- examples/scripts/download.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh index 0d38d3c..d87335f 100755 --- a/examples/scripts/download.sh +++ b/examples/scripts/download.sh @@ -7,10 +7,9 @@ WGET="wget --user-agent=Firefox" if [[ $8 =~ .*(.torrent) ]] then - pushd $HOME + cd $HOME $WGET $8 else - pushd $HOME + cd $HOME $WGET $8 fi -popd -- cgit v1.2.3 From 8e15fc2828d49b3028eb0ca47f79a18479d1683a Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 00:00:53 +0200 Subject: do not do cookie debugging (with notifier) by default --- examples/scripts/cookies.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index c0c37db..bbb0e88 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -35,14 +35,16 @@ [ -z "$cookie_data" ] && exit 1 -#notifier= +notifier= #notifier=notify-send -notify_wrapper () { - echo "$@" >> $HOME/cookielog -} +#notify_wrapper () { +# echo "$@" >> $HOME/cookielog +#} +#notifier=notifier_wrapper # if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. -notifier=notify_wrapper +# it's primarily used for debugging +notifier= which zenity &>/dev/null || exit 2 # Example cookie: -- cgit v1.2.3 From 3335c42600834657da0dd945589ab8a6a9210a10 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 11:49:48 +0200 Subject: add holizz' cookies.py --- AUTHORS | 2 +- examples/scripts/cookies.py | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100755 examples/scripts/cookies.py (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index e5e3806..83b87a1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,7 +21,7 @@ Contributors: Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch (uranther) - zoom level (bobpaul) - session script patches - Tom Adams (holizz) - few patches + Tom Adams (holizz) - few patches, cookies.py neutralinsomniac - load_progress = 0 fix Maximilian Gaß (mxey) - small patches Abel Camarillo (00z) - make it compile on OpenBSD diff --git a/examples/scripts/cookies.py b/examples/scripts/cookies.py new file mode 100755 index 0000000..3cc7eb0 --- /dev/null +++ b/examples/scripts/cookies.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import cookielib, sys, os, urllib2 + +class FakeRequest: + def __init__(self, argv): + self.argv = argv + self.cookies = None + if len(self.argv) == 12: + self.cookies = self.argv[11] + def get_full_url(self): + #TODO: this is a hack, fix in uzbl.c! + u = self.get_host()+self.argv[10] + if self.argv[6].startswith('https'): + u = 'https://'+u + else: + u = 'http://'+u + return u + def get_host(self): + return self.argv[9] + def get_type(self): + return self.get_full_url().split(':')[0] + def is_unverifiable(self): + return False + def get_origin_req_host(self): + return self.argv[9] + def has_header(self, header): + if header == 'Cookie': + return self.cookies!=None + def get_header(self, header_name, default=None): + if header_name == 'Cookie' and self.cookies: + return self.cookies + else: + return default + def header_items(self): + if self.cookies: + return [('Cookie',self.cookies)] + else: + return [] + def add_unredirected_header(self, key, header): + if key == 'Cookie': + self.cookies = header + +class FakeHeaders: + def __init__(self, argv): + self.argv = argv + def getallmatchingheaders(self, header): + if header == 'Set-Cookie' and len(self.argv) == 12: + return ['Set-Cookie: '+self.argv[11]] + else: + return [] + def getheaders(self, header): + if header == 'Set-Cookie' and len(self.argv) == 12: + return [self.argv[11]] + else: + return [] +class FakeResponse: + def __init__(self, argv): + self.argv = argv + def info(self): + return FakeHeaders(self.argv) + +if __name__ == '__main__': + jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') + try: + jar.load() + except: + pass + + req = FakeRequest(sys.argv) + + action = sys.argv[8] + + if action == 'GET': + jar.add_cookie_header(req) + if req.cookies: + print req.cookies + elif action == 'PUT': + res = FakeResponse(sys.argv) + jar.extract_cookies(res,req) + jar.save(ignore_discard=True) # save session cookies too + #jar.save() # save everything but session cookies \ No newline at end of file -- cgit v1.2.3 From 7aef97839a918a77b28180ee1c015ad2cc54741d Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 7 Jun 2009 12:07:58 +0200 Subject: pick datafile location for cookies more smartly --- examples/scripts/cookies.py | 7 +++++++ 1 file changed, 7 insertions(+) mode change 100755 => 100644 examples/scripts/cookies.py (limited to 'examples') diff --git a/examples/scripts/cookies.py b/examples/scripts/cookies.py old mode 100755 new mode 100644 index 3cc7eb0..0d2a65a --- a/examples/scripts/cookies.py +++ b/examples/scripts/cookies.py @@ -61,6 +61,13 @@ class FakeResponse: return FakeHeaders(self.argv) if __name__ == '__main__': + search = ['/usr/share/uzbl/examples/data', + os.environ['XDG_DATA_HOME']+'/uzbl', + './examples/data'] + for dir in search: + if os.path.isdir(dir): + cookie_file = dir+'/cookies.txt' + jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') try: jar.load() -- cgit v1.2.3 From fea380d3f8a2ea51d0bca25b3b8fed6cb4f41d6d Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 12:14:11 +0200 Subject: make cookies.py default sample cookie script --- docs/INSTALL | 2 ++ examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- examples/scripts/cookies.sh | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/docs/INSTALL b/docs/INSTALL index 1c0d007..43e139c 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -41,6 +41,8 @@ sample scripts: * dmenu (with vertical patch) * zenity * bash +* python (cookies.py) +* perl (formfiller.pl) File locations -------------- diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index e853836..daaf5c5 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -11,7 +11,7 @@ # You can use any command in place of spawn set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh -set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.sh +set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.py set minimum_font_size = 6 set font_size = 11 diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index ad6de24..94b60b1 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -11,7 +11,7 @@ # Usually you want to spawn a script to handle things, but any command (such as sh) can be used set history_handler = spawn ./examples/scripts/history.sh set download_handler = spawn ./examples/scripts/download.sh -set cookie_handler = spawn ./examples/scripts/cookies.sh +set cookie_handler = spawn ./examples/scripts/cookies.py set minimum_font_size = 6 set font_size = 11 diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh index bbb0e88..a875482 100755 --- a/examples/scripts/cookies.sh +++ b/examples/scripts/cookies.sh @@ -2,7 +2,7 @@ # THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! -# this is an example script of how you could manage your cookies.. +# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as cookies.py # we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) # This is one textfile with entries like this: # kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 -- cgit v1.2.3 From 178444bd79552c7e07cf5253997572c901d7138d Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 13:17:01 +0200 Subject: chmod cookies.py +x --- examples/scripts/cookies.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/scripts/cookies.py (limited to 'examples') diff --git a/examples/scripts/cookies.py b/examples/scripts/cookies.py old mode 100644 new mode 100755 -- cgit v1.2.3 From ec14eba5433c5813af1a7bc99f450a413825a6df Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 13:22:52 +0200 Subject: document dump_config --- README | 2 ++ docs/TODO | 2 +- examples/configs/sampleconfig | 2 +- examples/configs/sampleconfig-dev | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/README b/README index b8fd50e..4740b21 100644 --- a/README +++ b/README @@ -149,6 +149,8 @@ The following commands are recognized: - search with no string will search for the next/previous occurrence of the string previously searched for * `toggle_insert_mode ` - if the optional state is 0, disable insert mode. If 1, enable insert mode. +* `dump_config` + - dumps your current config (which may have been changed at runtime) to stdout, in a format you can use to pipe into uzbl again (or use as config file) * `keycmd ` * `keycmd_nl ` - keycmd sets the interactive command buffer to ``. If the given string is a valid binding, it will execute. `Keycmd_nl` is like `keycmd`, but it also emulates a press of return, causing bindings with a parameter to execute. For example, `keycmd_nl o google.com` would load the said url if you have a binding like `bind o _ = uri %s`. diff --git a/docs/TODO b/docs/TODO index dcee01b..561757c 100644 --- a/docs/TODO +++ b/docs/TODO @@ -48,7 +48,7 @@ More or less in order of importance/urgency link following webkit inspector usage scroll commands can take %s, eg scroll 100% for pages - chaining of actions, dump_config, print (and other actions that aren't documented yet) + chaining of actions, print (and other actions that aren't documented yet) overriding variables (such as -u) variable expansion (@var, @{var}, where do they get expanded? can users have their own vars?, should we merge this with the replacement we do for useragent/window title etc?) how %s works for the js command diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index daaf5c5..5daa21c 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -107,7 +107,7 @@ bind S = js alert("hi"); # Parameters are separated by spaces and the script body must be one parameter, so enclose it in # quotes and escape any inner quotes using backslashes bind XS = sh 'echo "js alert (\'This is sent by the shell via a fifo\')" > "$4"' - +bind dump = sh "echo dump_config > $4" # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 94b60b1..03310b4 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -146,7 +146,7 @@ bind S = js alert("hi"); # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' - +bind dump = sh "echo dump_config > $4" # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically bind za = spawn ./examples/scripts/formfiller.sh bind ze = spawn ./examples/scripts/formfiller.sh edit -- cgit v1.2.3 From 6cccec4508d6b0290e04716459db6a5790b2a072 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 20:28:35 +0200 Subject: make icon setting configurable --- examples/configs/sampleconfig | 1 + examples/configs/sampleconfig-dev | 2 ++ uzbl.c | 15 +++++++++++---- uzbl.h | 4 ++++ 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig index 5daa21c..736b49f 100644 --- a/examples/configs/sampleconfig +++ b/examples/configs/sampleconfig @@ -119,6 +119,7 @@ bind fl* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js %s # using strings, not polished yet: bind fL* = script /usr/share/uzbl/examples/scripts/follow_Numbers_Strings.js %s +set icon = /usr/share/uzbl/uzbl.png # "home" page if you will set uri = uzbl.org diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev index 03310b4..0aa0985 100644 --- a/examples/configs/sampleconfig-dev +++ b/examples/configs/sampleconfig-dev @@ -171,5 +171,7 @@ bind fL* = script ./examples/scripts/follow_Numbers_Strings.js %s # you can use this to disable all plugins set disable_plugins = 0 +set icon = ./uzbl.png + # "home" page if you will set uri = uzbl.org diff --git a/uzbl.c b/uzbl.c index 35a50fc..7b810dc 100644 --- a/uzbl.c +++ b/uzbl.c @@ -114,6 +114,7 @@ const struct { { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)}, { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)}, { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)}, + { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)}, { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)}, { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)}, { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)}, @@ -1311,6 +1312,16 @@ set_proxy_url() { return; } +static void +set_icon() { + if(file_exists(uzbl.gui.icon)) { + gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL); + } else { + g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon); + } + g_free (uzbl.gui.icon); +} + static void cmd_load_uri() { GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); @@ -2038,15 +2049,11 @@ create_mainbar () { static GtkWidget* create_window () { GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gchar* uzbl_icon = find_xdg_file(1, "/uzbl/uzbl.png"); gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); gtk_widget_set_name (window, "Uzbl browser"); - gtk_window_set_icon_from_file (GTK_WINDOW (window), uzbl_icon, NULL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL); g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL); - g_free (uzbl_icon); - return window; } diff --git a/uzbl.h b/uzbl.h index a6a3a6e..2e7ccf9 100644 --- a/uzbl.h +++ b/uzbl.h @@ -77,6 +77,7 @@ typedef struct { GtkAdjustment* bar_h; // and scrolling position WebKitWebView* web_view; gchar* main_title; + gchar* icon; /* WebInspector */ GtkWidget *inspector_window; @@ -460,6 +461,9 @@ cmd_set_status(); static void set_proxy_url(); +static void +set_icon(); + static void cmd_cookie_handler(); -- cgit v1.2.3 From 19489f84dbf0316222e27216c622929492d6fe4d Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 22:37:44 +0200 Subject: make the whole xdg/dev directories /configs etc more sense making. now theres just one config you can directly copy into your home and use without editing. the same config can be used while developing, the Makefile just overrides 2 xdg variables. also the scripts can be a bit simpler now --- Makefile | 11 +- examples/config/uzbl/cookies | 22 ++ examples/config/uzbl/sampleconfig | 177 ++++++++++++++ examples/configs/cookies | 22 -- examples/configs/sampleconfig | 125 ---------- examples/configs/sampleconfig-dev | 177 -------------- examples/data/bookmarks | 4 - examples/data/forms/bbs.archlinux.org | 5 - examples/data/style.css | 26 -- examples/data/uzbl/bookmarks | 4 + examples/data/uzbl/forms/bbs.archlinux.org | 5 + examples/data/uzbl/scripts/clipboard.sh | 15 ++ examples/data/uzbl/scripts/cookies.py | 82 +++++++ examples/data/uzbl/scripts/cookies.sh | 150 ++++++++++++ examples/data/uzbl/scripts/download.sh | 15 ++ examples/data/uzbl/scripts/follow_Numbers.js | 223 +++++++++++++++++ .../data/uzbl/scripts/follow_Numbers_Strings.js | 205 ++++++++++++++++ examples/data/uzbl/scripts/formfiller.pl | 99 ++++++++ examples/data/uzbl/scripts/formfiller.sh | 58 +++++ examples/data/uzbl/scripts/hint.js | 26 ++ examples/data/uzbl/scripts/history.sh | 3 + examples/data/uzbl/scripts/insert_bookmark.sh | 14 ++ examples/data/uzbl/scripts/linkfollow.js | 271 +++++++++++++++++++++ .../data/uzbl/scripts/load_url_from_bookmarks.sh | 20 ++ .../data/uzbl/scripts/load_url_from_history.sh | 20 ++ examples/data/uzbl/scripts/session.sh | 62 +++++ examples/data/uzbl/scripts/uzblcat | 20 ++ examples/data/uzbl/scripts/yank.sh | 12 + examples/data/uzbl/style.css | 26 ++ examples/data/uzbl/uzbl.png | Bin 0 -> 2185 bytes examples/scripts/clipboard.sh | 15 -- examples/scripts/cookies.py | 89 ------- examples/scripts/cookies.sh | 155 ------------ examples/scripts/download.sh | 15 -- examples/scripts/follow_Numbers.js | 223 ----------------- examples/scripts/follow_Numbers_Strings.js | 205 ---------------- examples/scripts/formfiller.pl | 99 -------- examples/scripts/formfiller.sh | 60 ----- examples/scripts/hint.js | 26 -- examples/scripts/history.sh | 4 - examples/scripts/insert_bookmark.sh | 17 -- examples/scripts/linkfollow.js | 271 --------------------- examples/scripts/load_url_from_bookmarks.sh | 22 -- examples/scripts/load_url_from_history.sh | 21 -- examples/scripts/session.sh | 62 ----- examples/scripts/uzblcat | 20 -- examples/scripts/yank.sh | 12 - uzbl.png | Bin 2185 -> 0 bytes 48 files changed, 1536 insertions(+), 1679 deletions(-) create mode 100644 examples/config/uzbl/cookies create mode 100644 examples/config/uzbl/sampleconfig delete mode 100644 examples/configs/cookies delete mode 100644 examples/configs/sampleconfig delete mode 100644 examples/configs/sampleconfig-dev delete mode 100644 examples/data/bookmarks delete mode 100644 examples/data/forms/bbs.archlinux.org delete mode 100644 examples/data/style.css create mode 100644 examples/data/uzbl/bookmarks create mode 100644 examples/data/uzbl/forms/bbs.archlinux.org create mode 100755 examples/data/uzbl/scripts/clipboard.sh create mode 100755 examples/data/uzbl/scripts/cookies.py create mode 100755 examples/data/uzbl/scripts/cookies.sh create mode 100755 examples/data/uzbl/scripts/download.sh create mode 100644 examples/data/uzbl/scripts/follow_Numbers.js create mode 100644 examples/data/uzbl/scripts/follow_Numbers_Strings.js create mode 100755 examples/data/uzbl/scripts/formfiller.pl create mode 100755 examples/data/uzbl/scripts/formfiller.sh create mode 100644 examples/data/uzbl/scripts/hint.js create mode 100755 examples/data/uzbl/scripts/history.sh create mode 100755 examples/data/uzbl/scripts/insert_bookmark.sh create mode 100644 examples/data/uzbl/scripts/linkfollow.js create mode 100755 examples/data/uzbl/scripts/load_url_from_bookmarks.sh create mode 100755 examples/data/uzbl/scripts/load_url_from_history.sh create mode 100755 examples/data/uzbl/scripts/session.sh create mode 100755 examples/data/uzbl/scripts/uzblcat create mode 100755 examples/data/uzbl/scripts/yank.sh create mode 100644 examples/data/uzbl/style.css create mode 100644 examples/data/uzbl/uzbl.png delete mode 100755 examples/scripts/clipboard.sh delete mode 100755 examples/scripts/cookies.py delete mode 100755 examples/scripts/cookies.sh delete mode 100755 examples/scripts/download.sh delete mode 100644 examples/scripts/follow_Numbers.js delete mode 100644 examples/scripts/follow_Numbers_Strings.js delete mode 100755 examples/scripts/formfiller.pl delete mode 100755 examples/scripts/formfiller.sh delete mode 100644 examples/scripts/hint.js delete mode 100755 examples/scripts/history.sh delete mode 100755 examples/scripts/insert_bookmark.sh delete mode 100644 examples/scripts/linkfollow.js delete mode 100755 examples/scripts/load_url_from_bookmarks.sh delete mode 100755 examples/scripts/load_url_from_history.sh delete mode 100755 examples/scripts/session.sh delete mode 100755 examples/scripts/uzblcat delete mode 100755 examples/scripts/yank.sh delete mode 100644 uzbl.png (limited to 'examples') diff --git a/Makefile b/Makefile index 2fef569..3e0647d 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,14 @@ test: uzbl ./uzbl --uri http://www.uzbl.org --verbose test-config: uzbl - ./uzbl --uri http://www.uzbl.org --config examples/configs/sampleconfig-dev --verbose + ./uzbl --uri http://www.uzbl.org --verbose + +test-config-dev: uzbl + XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --config $XDG_CONFIG_HOME/uzbl/sampleconfig --verbose + +test-config-share: uzbl + XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --config $XDG_CONFIG_HOME/uzbl/sampleconfig --verbose -test-config-real: uzbl - ./uzbl --uri http://www.uzbl.org --config /usr/share/uzbl/examples/configs/sampleconfig --verbose clean: rm -f uzbl @@ -26,7 +30,6 @@ install: cp -ax docs $(PREFIX)/share/uzbl/ cp -ax config.h $(PREFIX)/share/uzbl/docs/ cp -ax examples $(PREFIX)/share/uzbl/ - cp -ax uzbl.png $(PREFIX)/share/uzbl/ install -D -m644 AUTHORS $(PREFIX)/share/uzbl/docs install -D -m644 README $(PREFIX)/share/uzbl/docs diff --git a/examples/config/uzbl/cookies b/examples/config/uzbl/cookies new file mode 100644 index 0000000..9b7374a --- /dev/null +++ b/examples/config/uzbl/cookies @@ -0,0 +1,22 @@ +# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script. +# stick to this format. +# trusted -> always store what we get, send what we have (TODO: by default, or when requested?) +# deny -> deny storing + sending + +# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind... + + +TRUSTED +bbs.archlinux.org +archlinux.org +linux.com + + + + +DENY +www.icanhascheezburger.com + + + +# rest -> ask \ No newline at end of file diff --git a/examples/config/uzbl/sampleconfig b/examples/config/uzbl/sampleconfig new file mode 100644 index 0000000..53c4086 --- /dev/null +++ b/examples/config/uzbl/sampleconfig @@ -0,0 +1,177 @@ + +# example uzbl config. in a real config, we should obey the xdg spec +# all settings are optional. you can use uzbl without any config at all (but it won't do much) + +# keyboard behavior is vimstyle by default (all commands -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the commands +# from insert mode by combining them with the modkey + +# TODO: ability to attach misc things (spawn , script ,.. to internal events) +# Usually you want to spawn a script to handle things, but any command (such as sh) can be used +set history_handler = spawn $XDG_DATA_HOME/scripts/history.sh +set download_handler = spawn $XDG_DATA_HOME/scripts/download.sh +set cookie_handler = spawn $XDG_DATA_HOME/scripts/cookies.py + +set minimum_font_size = 6 +set font_size = 11 +## monospace_size defaults to font_size, but you can alter it independently +#set monospace_size = 10 + +## Display or supress images within html sites +#set autoload_images = 0 + +## Shrink images to window size +#set autoshrink_images = 0 + +## Spellchecker +#set enable_spellcheck = 1 + +## Private browsing +#set enbale_private = 0 + +## The URI of a stylesheet that is applied to every page +#set stylesheet_uri = http://www.user.com/mystylelesheet.css + +## enable/disable JavaScript +#set disbale_scripts = 1 + +## Whether text areas are resizable +#set resizeable_text_areas = 1 + +## The default encoding used to display text +#set default_encoding = iso-8859-1 + +## Whether background images should be printed +#set print_background = 0 + +## Enforce a resolution of 96 DPI. This is meant for compatibility with +## web pages which cope badly with different screen resolutions +#set enforce_96_dpi = 1 + + +# +# use with bind ... = sh +set shell_cmd = sh -c + + + +# Behaviour and appearance +set show_status = 1 +# you can optionally use this setting to override the background color of the statusbar from your GTK theme. +set status_background = #303030 +set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_top = 0 +# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) +set title_format_short = TITLE - Uzbl browser +set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI +# set the characters to use for, and the width of the progress bar +set status_pbar_done = * +set status_pbar_pending = - +set status_pbar_width = 12 +set insert_indicator = I +set command_indicator = C +set modkey = Mod1 +# reset to command mode when new page is loaded +set reset_command_mode = 1 +# this var has precedence over reset_command_mode +set always_insert_mode = 0 + +# to start a local socks server, do : ssh -fND localhost:8118 localhost +#set proxy_url = http://127.0.0.1:8118 +#values 0-3 +#set http_debug = 0 +#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) +# Example user agent containing everything: +set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) +#set max_conns = 0 +#set max_conns_host = 0 + +set fifo_dir = /tmp +set socket_dir = /tmp + +# Key bindings +bind j = scroll_vert 20 +bind k = scroll_vert -20 +bind h = scroll_horz -20 +bind l = scroll_horz 20 +bind << = scroll_begin +bind >> = scroll_end +bind b = back +bind m = forward +bind s = stop +bind r = reload +bind R = reload_ign_cache +bind + = zoom_in +bind - = zoom_out +bind 1 = sh "echo set zoom_level = 1.0 > $4" +bind 2 = sh "echo set zoom_level = 2.0 > $4" +bind t = toggle_status +# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called +# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. +bind /* = search %s +bind ?* = search_reverse %s +#jump to next +bind n = search +bind N = search_reverse +bind gh = uri http://www.uzbl.org +#TODO: set uri? +bind o _ = uri %s +bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ = uri http://www.google.com/search?q=%s +bind i = toggle_insert_mode +# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting +bind I = toggle_insert_mode 0 +# Enclose the executable in quotes if it has spaces. Any additional parameters you use will +# appear AFTER the default parameters +bind B = spawn $XDG_DATA_HOME/scripts/insert_bookmark.sh +bind U = spawn $XDG_DATA_HOME/scripts/load_url_from_history.sh +bind u = spawn $XDG_DATA_HOME/scripts/load_url_from_bookmarks.sh +# with the sample yank script, you can yank one of the arguments into clipboard/selection +bind yurl = spawn $XDG_DATA_HOME/scripts/yank.sh 6 primary +bind ytitle = spawn $XDG_DATA_HOME/scripts/yank.sh 7 clipboard +# does the same as yurl but without needing a script +bind y2url = sh 'echo -n $6 | xclip' +# go the page from primary selection +bind p = sh "echo uri `xclip -selection primary -o` > $4" +# go to the page in clipboard +bind P = sh "echo uri `xclip -selection clipboard -o` > $4" +bind ZZ = exit +bind S = js alert("hi"); +# example showing how to use sh +# it sends a command to the fifo, whose path is told via a positional param +# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it +# The body of the shell command should be one parameter, so if it has spaces like here, +# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes +# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file +# path, fifo & socket dirs, etc.) +bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' +bind dump = sh "echo dump_config > $4" +# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically +bind za = spawn $XDG_DATA_HOME/scripts/formfiller.sh +bind ze = spawn $XDG_DATA_HOME/scripts/formfiller.sh edit +bind zn = spawn $XDG_DATA_HOME/scripts/formfiller.sh new +bind zl = spawn $XDG_DATA_HOME/scripts/formfiller.sh load + +# other - more advanced - implementation using perl: (could not get this to run - Dieter ) +bind LL = spawn $XDG_DATA_HOME/scripts/formfiller.pl load +bind LN = spawn $XDG_DATA_HOME/scripts/formfiller.pl new +bind LE = spawn $XDG_DATA_HOME/scripts/formfiller.pl edit + +# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) +# this is similar to how it works in vimperator (and konqueror) +# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? +#hit F to toggle the Hints (now in form of link numbering) +bind F = script $XDG_DATA_HOME/scripts/hint.js +# the most stable version: +bind fl* = script $XDG_DATA_HOME/scripts/follow_Numbers.js %s +# using strings, not polished yet: +bind fL* = script $XDG_DATA_HOME/scripts/follow_Numbers_Strings.js %s + +# you can use this to disable all plugins +set disable_plugins = 0 + +set icon = ./uzbl.png + +# "home" page if you will +set uri = uzbl.org diff --git a/examples/configs/cookies b/examples/configs/cookies deleted file mode 100644 index 9b7374a..0000000 --- a/examples/configs/cookies +++ /dev/null @@ -1,22 +0,0 @@ -# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script. -# stick to this format. -# trusted -> always store what we get, send what we have (TODO: by default, or when requested?) -# deny -> deny storing + sending - -# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind... - - -TRUSTED -bbs.archlinux.org -archlinux.org -linux.com - - - - -DENY -www.icanhascheezburger.com - - - -# rest -> ask \ No newline at end of file diff --git a/examples/configs/sampleconfig b/examples/configs/sampleconfig deleted file mode 100644 index 736b49f..0000000 --- a/examples/configs/sampleconfig +++ /dev/null @@ -1,125 +0,0 @@ - -# example uzbl config. in a real config, we should obey the xdg spec -# all settings are optional. you can use uzbl without any config at all (but it won't do much) - -# keyboard behavior is vimstyle by default (all commands -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the commands -# from insert mode by combining them with the modkey - -# TODO: ability to attach misc things (spawn , script ,.. to internal events) -# You can use any command in place of spawn -set history_handler = spawn /usr/share/uzbl/examples/scripts/history.sh -set download_handler = spawn /usr/share/uzbl/examples/scripts/download.sh -set cookie_handler = spawn /usr/share/uzbl/examples/scripts/cookies.py - -set minimum_font_size = 6 -set font_size = 11 -# monospace_size defaults to font_size, but you can alter it independently -#set monospace_size = 10 - -# use with bind ... = sh -set shell_cmd = sh -c - - - -# Behaviour and appearance -set show_status = 1 -# you can optionally use this setting to override the background color of the statusbar from your GTK theme. -set status_background = #303030 -set status_format = MODE [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI -set status_top = 0 -# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) -set title_format_short = TITLE - Uzbl browser -set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI -# set the characters to use for, and the width of the progress bar -set status_pbar_done = * -set status_pbar_pending = - -set status_pbar_width = 12 - -set modkey = Mod1 -# reset to command mode when new page is loaded -set reset_command_mode = 1 -# this var has precedence over reset_command_mode -set always_insert_mode = 0 -# to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 -#values 0-3 -#set http_debug = 0 -#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) -# Example user agent containing everything: -set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) -#set max_conns = 0 -#set max_conns_host = 0 - -set fifo_dir = /tmp -set socket_dir = /tmp - -# Key bindings -bind j = scroll_vert 20 -bind k = scroll_vert -20 -bind h = scroll_horz -20 -bind l = scroll_horz 20 -bind << = scroll_begin -bind >> = scroll_end -bind b = back -bind m = forward -bind s = stop -bind r = reload -bind R = reload_ign_cache -bind + = zoom_in -bind - = zoom_out -bind 1 = sh "echo set zoom_level = 1.0 > $4" -bind 2 = sh "echo set zoom_level = 2.0 > $4" -bind t = toggle_status -# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called -# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. -bind /* = search %s -bind ?* = search_reverse %s -#jump to next -bind n = search -bind N = search_reverse -bind gh = uri http://www.uzbl.org -#TODO: set uri? -bind o _ = uri %s -bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ = uri http://www.google.com/search?q=%s -bind i = toggle_insert_mode -# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting -bind I = toggle_insert_mode 0 -bind B = spawn /usr/share/uzbl/examples/scripts/insert_bookmark.sh -bind U = spawn /usr/share/uzbl/examples/scripts/load_url_from_history.sh -bind u = spawn /usr/share/uzbl/examples/scripts/load_url_from_bookmarks.sh -# with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn /usr/share/uzbl/examples/scripts/yank.sh 6 primary -bind ytitle = spawn /usr/share/uzbl/examples/scripts/yank.sh 7 clipboard -# does the same as yurl but without needing a script -bind y2url = sh "echo -n $6 | xclip" -# go the page from primary selection -bind p = sh "echo uri `xclip -selection primary -o` > $4" -# go to the page in clipboard -bind P = sh "echo uri `xclip -selection clipboard -o` > $4" -bind ZZ = exit -bind S = js alert("hi"); -# example showing how to use sh -# it sends a command to the fifo, whose path is told via a positional param -# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -# Parameters are separated by spaces and the script body must be one parameter, so enclose it in -# quotes and escape any inner quotes using backslashes -bind XS = sh 'echo "js alert (\'This is sent by the shell via a fifo\')" > "$4"' -bind dump = sh "echo dump_config > $4" - -# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) -# this is similar to how it works in vimperator (and konqueror) -# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? -#hit F to toggle the Hints (now in form of link numbering) -bind F = script /usr/share/uzbl/examples/scripts/hint.js -# the most stable version: -bind fl* = script /usr/share/uzbl/examples/scripts/follow_Numbers.js %s -# using strings, not polished yet: -bind fL* = script /usr/share/uzbl/examples/scripts/follow_Numbers_Strings.js %s - -set icon = /usr/share/uzbl/uzbl.png - -# "home" page if you will -set uri = uzbl.org diff --git a/examples/configs/sampleconfig-dev b/examples/configs/sampleconfig-dev deleted file mode 100644 index 0aa0985..0000000 --- a/examples/configs/sampleconfig-dev +++ /dev/null @@ -1,177 +0,0 @@ - -# example uzbl config. in a real config, we should obey the xdg spec -# all settings are optional. you can use uzbl without any config at all (but it won't do much) - -# keyboard behavior is vimstyle by default (all commands -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the commands -# from insert mode by combining them with the modkey - -# TODO: ability to attach misc things (spawn , script ,.. to internal events) -# Usually you want to spawn a script to handle things, but any command (such as sh) can be used -set history_handler = spawn ./examples/scripts/history.sh -set download_handler = spawn ./examples/scripts/download.sh -set cookie_handler = spawn ./examples/scripts/cookies.py - -set minimum_font_size = 6 -set font_size = 11 -## monospace_size defaults to font_size, but you can alter it independently -#set monospace_size = 10 - -## Display or supress images within html sites -#set autoload_images = 0 - -## Shrink images to window size -#set autoshrink_images = 0 - -## Spellchecker -#set enable_spellcheck = 1 - -## Private browsing -#set enbale_private = 0 - -## The URI of a stylesheet that is applied to every page -#set stylesheet_uri = http://www.user.com/mystylelesheet.css - -## enable/disable JavaScript -#set disbale_scripts = 1 - -## Whether text areas are resizable -#set resizeable_text_areas = 1 - -## The default encoding used to display text -#set default_encoding = iso-8859-1 - -## Whether background images should be printed -#set print_background = 0 - -## Enforce a resolution of 96 DPI. This is meant for compatibility with -## web pages which cope badly with different screen resolutions -#set enforce_96_dpi = 1 - - -# -# use with bind ... = sh -set shell_cmd = sh -c - - - -# Behaviour and appearance -set show_status = 1 -# you can optionally use this setting to override the background color of the statusbar from your GTK theme. -set status_background = #303030 -set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI -set status_top = 0 -# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) -set title_format_short = TITLE - Uzbl browser -set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI -# set the characters to use for, and the width of the progress bar -set status_pbar_done = * -set status_pbar_pending = - -set status_pbar_width = 12 -set insert_indicator = I -set command_indicator = C -set modkey = Mod1 -# reset to command mode when new page is loaded -set reset_command_mode = 1 -# this var has precedence over reset_command_mode -set always_insert_mode = 0 - -# to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 -#values 0-3 -#set http_debug = 0 -#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) -# Example user agent containing everything: -set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) -#set max_conns = 0 -#set max_conns_host = 0 - -set fifo_dir = /tmp -set socket_dir = /tmp - -# Key bindings -bind j = scroll_vert 20 -bind k = scroll_vert -20 -bind h = scroll_horz -20 -bind l = scroll_horz 20 -bind << = scroll_begin -bind >> = scroll_end -bind b = back -bind m = forward -bind s = stop -bind r = reload -bind R = reload_ign_cache -bind + = zoom_in -bind - = zoom_out -bind 1 = sh "echo set zoom_level = 1.0 > $4" -bind 2 = sh "echo set zoom_level = 2.0 > $4" -bind t = toggle_status -# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called -# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. -bind /* = search %s -bind ?* = search_reverse %s -#jump to next -bind n = search -bind N = search_reverse -bind gh = uri http://www.uzbl.org -#TODO: set uri? -bind o _ = uri %s -bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ = uri http://www.google.com/search?q=%s -bind i = toggle_insert_mode -# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting -bind I = toggle_insert_mode 0 -# Enclose the executable in quotes if it has spaces. Any additional parameters you use will -# appear AFTER the default parameters -bind B = spawn ./examples/scripts/insert_bookmark.sh -bind U = spawn ./examples/scripts/load_url_from_history.sh -bind u = spawn ./examples/scripts/load_url_from_bookmarks.sh -# with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn ./examples/scripts/yank.sh 6 primary -bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard -# does the same as yurl but without needing a script -bind y2url = sh 'echo -n $6 | xclip' -# go the page from primary selection -bind p = sh "echo uri `xclip -selection primary -o` > $4" -# go to the page in clipboard -bind P = sh "echo uri `xclip -selection clipboard -o` > $4" -bind ZZ = exit -bind S = js alert("hi"); -# example showing how to use sh -# it sends a command to the fifo, whose path is told via a positional param -# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -# The body of the shell command should be one parameter, so if it has spaces like here, -# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes -# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file -# path, fifo & socket dirs, etc.) -bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -bind dump = sh "echo dump_config > $4" -# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically -bind za = spawn ./examples/scripts/formfiller.sh -bind ze = spawn ./examples/scripts/formfiller.sh edit -bind zn = spawn ./examples/scripts/formfiller.sh new -bind zl = spawn ./examples/scripts/formfiller.sh load - -# other - more advanced - implementation using perl: (could not get this to run - Dieter ) -bind LL = spawn ./examples/scripts/formfiller.pl load -bind LN = spawn ./examples/scripts/formfiller.pl new -bind LE = spawn ./examples/scripts/formfiller.pl edit - -# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) -# this is similar to how it works in vimperator (and konqueror) -# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? -#hit F to toggle the Hints (now in form of link numbering) -bind F = script ./examples/scripts/hint.js -# the most stable version: -bind fl* = script ./examples/scripts/follow_Numbers.js %s -# using strings, not polished yet: -bind fL* = script ./examples/scripts/follow_Numbers_Strings.js %s - -# you can use this to disable all plugins -set disable_plugins = 0 - -set icon = ./uzbl.png - -# "home" page if you will -set uri = uzbl.org diff --git a/examples/data/bookmarks b/examples/data/bookmarks deleted file mode 100644 index 13fcd48..0000000 --- a/examples/data/bookmarks +++ /dev/null @@ -1,4 +0,0 @@ -http://www.archlinux.org linux arch -http://www.uzbl.org uzbl browser -http://dieter.plaetinck.be uzbl -http://www.icanhascheezburger.com lolcats fun diff --git a/examples/data/forms/bbs.archlinux.org b/examples/data/forms/bbs.archlinux.org deleted file mode 100644 index 73c1539..0000000 --- a/examples/data/forms/bbs.archlinux.org +++ /dev/null @@ -1,5 +0,0 @@ -form_sent: -redirect_url: -req_username: -req_password: -login: diff --git a/examples/data/style.css b/examples/data/style.css deleted file mode 100644 index de0a38b..0000000 --- a/examples/data/style.css +++ /dev/null @@ -1,26 +0,0 @@ -.uzbl_highlight { background-color: yellow;} -.uzbl_h_first { background-color: lightgreen;} - -.uzbl_follow { border-style: dotted; - border-width: thin; -} - -#uzbl_hint > div { - display: inline; - border: 2px solid #4a6600; - background-color: #b9ff00; - color: black; - font-size: 9px; - font-weight: bold; - line-height: 9px; - margin: 0px; - padding: 0px; - position: absolute; - z-index: 1000; - -webkit-border-radius: 6px; - text-decoration: none; - -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); -} - -/* vim:set et ts=4: */ - diff --git a/examples/data/uzbl/bookmarks b/examples/data/uzbl/bookmarks new file mode 100644 index 0000000..13fcd48 --- /dev/null +++ b/examples/data/uzbl/bookmarks @@ -0,0 +1,4 @@ +http://www.archlinux.org linux arch +http://www.uzbl.org uzbl browser +http://dieter.plaetinck.be uzbl +http://www.icanhascheezburger.com lolcats fun diff --git a/examples/data/uzbl/forms/bbs.archlinux.org b/examples/data/uzbl/forms/bbs.archlinux.org new file mode 100644 index 0000000..73c1539 --- /dev/null +++ b/examples/data/uzbl/forms/bbs.archlinux.org @@ -0,0 +1,5 @@ +form_sent: +redirect_url: +req_username: +req_password: +login: diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh new file mode 100755 index 0000000..c64b65c --- /dev/null +++ b/examples/data/uzbl/scripts/clipboard.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard. + +fifo="$5" +action="$1" +url="$7" +selection=$(xclip -o) + +case $action in + "yank" ) echo -n "$url" | xclip;; + "goto" ) echo "uri $selection" > "$fifo";; + * ) echo "clipboard.sh: invalid action";; +esac + diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py new file mode 100755 index 0000000..3cc7eb0 --- /dev/null +++ b/examples/data/uzbl/scripts/cookies.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +import cookielib, sys, os, urllib2 + +class FakeRequest: + def __init__(self, argv): + self.argv = argv + self.cookies = None + if len(self.argv) == 12: + self.cookies = self.argv[11] + def get_full_url(self): + #TODO: this is a hack, fix in uzbl.c! + u = self.get_host()+self.argv[10] + if self.argv[6].startswith('https'): + u = 'https://'+u + else: + u = 'http://'+u + return u + def get_host(self): + return self.argv[9] + def get_type(self): + return self.get_full_url().split(':')[0] + def is_unverifiable(self): + return False + def get_origin_req_host(self): + return self.argv[9] + def has_header(self, header): + if header == 'Cookie': + return self.cookies!=None + def get_header(self, header_name, default=None): + if header_name == 'Cookie' and self.cookies: + return self.cookies + else: + return default + def header_items(self): + if self.cookies: + return [('Cookie',self.cookies)] + else: + return [] + def add_unredirected_header(self, key, header): + if key == 'Cookie': + self.cookies = header + +class FakeHeaders: + def __init__(self, argv): + self.argv = argv + def getallmatchingheaders(self, header): + if header == 'Set-Cookie' and len(self.argv) == 12: + return ['Set-Cookie: '+self.argv[11]] + else: + return [] + def getheaders(self, header): + if header == 'Set-Cookie' and len(self.argv) == 12: + return [self.argv[11]] + else: + return [] +class FakeResponse: + def __init__(self, argv): + self.argv = argv + def info(self): + return FakeHeaders(self.argv) + +if __name__ == '__main__': + jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') + try: + jar.load() + except: + pass + + req = FakeRequest(sys.argv) + + action = sys.argv[8] + + if action == 'GET': + jar.add_cookie_header(req) + if req.cookies: + print req.cookies + elif action == 'PUT': + res = FakeResponse(sys.argv) + jar.extract_cookies(res,req) + jar.save(ignore_discard=True) # save session cookies too + #jar.save() # save everything but session cookies \ No newline at end of file diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh new file mode 100755 index 0000000..78139d6 --- /dev/null +++ b/examples/data/uzbl/scripts/cookies.sh @@ -0,0 +1,150 @@ +#!/bin/bash + +# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! + +# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as cookies.py +# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) +# This is one textfile with entries like this: +# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 +# domain alow-read-other-subdomains path http-required expiration name value +# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) +# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" +# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( +# TODO: different cookie paths per config (eg per group of uzbl instances) + +# TODO: correct implementation. +# see http://curl.haxx.se/rfc/cookie_spec.html +# http://en.wikipedia.org/wiki/HTTP_cookie + +# TODO : check expires= before sending. +# write sample script that cleans up cookies dir based on expires attribute. +# TODO: check uri against domain attribute. and path also. +# implement secure attribute. +# support blocking or not for 3rd parties +# http://kb.mozillazine.org/Cookies.txt +# don't always append cookies, sometimes we need to overwrite + +cookie_config=$XDG_CONFIG_HOME/uzbl/cookies +[ -z "$cookie_config" ] && exit 1 +[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1 +[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_data=$XDG_DATA_HOME/uzbl/cookies.txt + + +notifier= +#notifier=notify-send +#notify_wrapper () { +# echo "$@" >> $HOME/cookielog +#} +#notifier=notifier_wrapper + +# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. +# it's primarily used for debugging +notifier= +which zenity &>/dev/null || exit 2 + +# Example cookie: +# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net + +# uri=$6 +# uri=${uri/http:\/\/} # strip 'http://' part +# host=${uri/\/*/} +action=$8 # GET/PUT +host=$9 +shift +path=$9 +shift +cookie=$9 + +field_domain=$host +field_path=$path +field_name= +field_value= +field_exp='end_session' + +function notify () { + [ -n "$notifier" ] && $notifier "$@" +} + + +# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET +function parse_cookie () { + IFS=$';' + first_pair=1 + for pair in $cookie + do + if [ "$first_pair" == 1 ] + then + field_name=${pair%%=*} + field_value=${pair#*=} + first_pair=0 + else + read -r pair <<< "$pair" #strip leading/trailing wite space + key=${pair%%=*} + val=${pair#*=} + [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` + # TODO: domain + [ "$key" == path ] && field_path=$val + fi + done + unset IFS +} + +# match cookies in cookies.txt against hostname and path +function get_cookie () { + path_esc=${path//\//\\/} + search="^[^\t]*$host\t[^\t]*\t$path_esc" + cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` + if [ -z "$cookie" ] + then + notify "Get_cookie: search: $search in $cookie_data -> no result" + false + else + notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" + read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" + cookie="$name=$value" + true + fi +} + +function save_cookie () { + if parse_cookie + then + data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" + notify "save_cookie: adding $data to $cookie_data" + echo -e "$data" >> $cookie_data + else + notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" + fi +} + +[ $action == PUT ] && save_cookie +[ $action == GET ] && get_cookie && echo "$cookie" + +exit + + +# TODO: implement this later. +# $1 = section (TRUSTED or DENY) +# $2 =url +function match () { + sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" +} + +function fetch_cookie () { + cookie=`cat $cookie_data` +} + +function store_cookie () { + echo $cookie > $cookie_data +} + +if match TRUSTED $host +then + [ $action == PUT ] && store_cookie $host + [ $action == GET ] && fetch_cookie && echo "$cookie" +elif ! match DENY $host +then + [ $action == PUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host + [ $action == GET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie +fi +exit 0 diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh new file mode 100755 index 0000000..d87335f --- /dev/null +++ b/examples/data/uzbl/scripts/download.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# just an example of how you could handle your downloads +# try some pattern matching on the uri to determine what we should do + +# Some sites block the default wget --user-agent... +WGET="wget --user-agent=Firefox" + +if [[ $8 =~ .*(.torrent) ]] +then + cd $HOME + $WGET $8 +else + cd $HOME + $WGET $8 +fi diff --git a/examples/data/uzbl/scripts/follow_Numbers.js b/examples/data/uzbl/scripts/follow_Numbers.js new file mode 100644 index 0000000..efde4d7 --- /dev/null +++ b/examples/data/uzbl/scripts/follow_Numbers.js @@ -0,0 +1,223 @@ +/* This is the basic linkfollowing script. + * Its pretty stable, only using numbers to navigate. + * + * TODO: Some pages mess around a lot with the zIndex which + * lets some hints in the background. + * TODO: Some positions are not calculated correctly (mostly + * because of uber-fancy-designed-webpages. Basic HTML and CSS + * works good + * TODO: Still some links can't be followed/unexpected things + * happen. Blame some freaky webdesigners ;) + */ + +//Just some shortcuts and globals +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; +//Make onlick-links "clickable" +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +//Catch the ESC keypress to stop linkfollowing +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +//Calculate element position to draw the hint +//Pretty accurate but on fails in some very fancy cases +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +//Calculate if an element is visible +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +//Calculate if an element is on the viewport. +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +//Removes all hints/leftovers that might be generated +//by this script. +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +//Generate a hint for an element with the given label +//Here you can play around with the style of the hints! +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '1000'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +//Here we choose what to do with an element if we +//want to "follow" it. On form elements we "select" +//or pass the focus, on links we try to perform a click, +//but at least set the href of the link. (needs some improvements) +function clickElem(item) { + removeAllHints(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +//Returns a list of all links (in this version +//just the elements itself, but in other versions, we +//add the label here. +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + } + } + return res; +} +//Same as above, just for the form elements +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + } + } + } + return res; +} +//Draw all hints for all elements passed. "len" is for +//the number of chars we should use to avoid collisions +function reDrawHints(elems, chars) { + removeAllHints(); + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + for (var i = 0; i < elems[0].length; i++) { + if (elems[0][i]) { + var label = elems[1][i].substring(chars); + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + } +} +//Put it all together +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + var label = j + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + for (var k = 0; k < s.length; k++) { + b = b && label.charAt(k) == s[k]; + } + if (b) { + leftover[0].push(elems[0][j]); + leftover[1].push(label); + } + } + reDrawHints(leftover, s.length); + } +} +followLinks('%s'); diff --git a/examples/data/uzbl/scripts/follow_Numbers_Strings.js b/examples/data/uzbl/scripts/follow_Numbers_Strings.js new file mode 100644 index 0000000..67da2f9 --- /dev/null +++ b/examples/data/uzbl/scripts/follow_Numbers_Strings.js @@ -0,0 +1,205 @@ +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.zIndex = '1000'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +function clickElem(item) { + removeAllHints(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + res[1].push(li.innerText.toLowerCase()); + } + } + return res; +} +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + if (el.getAttribute('value')) { + res[1].push(el.getAttribute('value').toLowerCase()); + } else { + res[1].push(el.getAttribute('name').toLowerCase()); + } + } + } + } + return res; +} +function reDrawHints(elems, len) { + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + hintdiv.style.opacity = '0.0'; + for (var i = 0; i < elems[0].length; i++) { + var label = i + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + if (elems[0][i]) { + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + hintdiv.style.opacity = '0.7' + } +} +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + for (var k = 0; k < s.length; k++) { + b = b && elems[1][j].charAt(k) == s[k]; + } + if (!b) { + elems[0][j] = null; + elems[1][j] = null; + } else { + leftover[0].push(elems[0][j]); + leftover[1].push(elems[1][j]); + } + } + if (leftover[0].length == 1) { + clickElem(leftover[0][0]); + } else if (!oldDiv) { + if (linknr + 1 || s.length == 0) { + reDrawHints(elems, len); + } else { + reDrawHints(leftover, len); + } + } + } +} +followLinks('%s'); diff --git a/examples/data/uzbl/scripts/formfiller.pl b/examples/data/uzbl/scripts/formfiller.pl new file mode 100755 index 0000000..c590836 --- /dev/null +++ b/examples/data/uzbl/scripts/formfiller.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +# a slightly more advanced form filler +# +# uses settings file like: $keydir/ + +# user arg 1: +# edit: force editing of the file (fetches if file is missing) +# load: fill forms from file (fetches if file is missing) +# new: fetch new file + +# usage example: +# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load +# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller.pl new +# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit + +use strict; +use warnings; + +my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; +my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; +if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } + +sub domain { + my ($url) = @_; + $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#; + return $url; +}; + +my $editor = "xterm -e vim"; +#my $editor = "gvim"; + +# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with +# Also, you may need to fake the user-agent on some sites (like facebook) + my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' "; +#my $downloader = "curl -s"; + +my @fields = ("type","name","value"); + +my %command; + +$command{load} = sub { + my ($domain) = @_; + my $filename = "$keydir/$domain"; + if (-e $filename){ + open(my $file, $filename) or die "Failed to open $filename: $!"; + my (@lines) = <$file>; + close($file); + $|++; + open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; + foreach my $line (@lines) { + next if ($line =~ m/^#/); + my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); + if ($type eq "checkbox") + { + printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; + } elsif ($type eq "submit") + { + printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; + } elsif ($type ne "") + { + printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; + } + print $fifo "\n"; + } + $|--; + } else { + $command{new}->($domain); + $command{edit}->($domain); + } +}; +$command{edit} = sub { + my ($domain) = @_; + my $file = "$keydir/$domain"; + if(-e $file){ + system ($editor, $file); + } else { + $command{new}->($domain); + } +}; +$command{new} = sub { + my ($domain) = @_; + my $filename = "$keydir/$domain"; + open (my $file,">>", $filename) or die "Failed to open $filename: $!"; + $|++; + print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; + printf $file "#%-10s | %-10s | %s\n", @fields; + print $file "#------------------------------\n"; + my @data = `$downloader $url`; + foreach my $line (@data){ + if($line =~ m/].*?)>/i){ + $line =~ s/.*(].*?)>).*/$1/; + printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; + }; + }; + $|--; +}; + +$command{$cmd}->(domain($url)); diff --git a/examples/data/uzbl/scripts/formfiller.sh b/examples/data/uzbl/scripts/formfiller.sh new file mode 100755 index 0000000..d54c626 --- /dev/null +++ b/examples/data/uzbl/scripts/formfiller.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# simple html form (eg for logins) filler (and manager) for uzbl. +# uses settings files like: $keydir/ +# files contain lines like: : + + +# user arg 1: +# edit: force editing the file (falls back to new if not found) +# new: start with a new file. +# load: try to load from file into form + +# something else (or empty): if file not available: new, otherwise load. + +keydir=$XDG_DATA_HOME/uzbl/forms +[ -z "$keydir" ] && exit 1 + +#editor=gvim +editor='urxvt -e vim' + +config=$1; shift +pid=$1; shift +xid=$1; shift +fifo=$1; shift +socket=$1; shift +url=$1; shift +title=$1; shift +action=$1 + +[ -d $keydir ] || mkdir $keydir || exit 1 + +if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ] +then + action=new + [[ -e $keydir/$domain ]] && action=load +elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]] +then + action=new +fi +domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') + + +#regex='s|.*.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page + regex='s|.*> $fifo +else + if [ "$action" == 'new' ] + then + curl "$url" | grep ' $keydir/$domain + fi + [[ -e $keydir/$domain ]] || exit 3 #this should never happen, but you never know. + $editor $keydir/$domain #TODO: if user aborts save in editor, the file is already overwritten +fi diff --git a/examples/data/uzbl/scripts/hint.js b/examples/data/uzbl/scripts/hint.js new file mode 100644 index 0000000..ec7f1e2 --- /dev/null +++ b/examples/data/uzbl/scripts/hint.js @@ -0,0 +1,26 @@ +for (var i=0; i < document.links.length; i++) { + var uzblid = 'uzbl_link_hint_'; + var li = document.links[i]; + var pre = document.getElementById(uzblid+i); + + if (pre) { + li.removeChild(pre); + } else { + var hint = document.createElement('div'); + hint.setAttribute('id',uzblid+i); + hint.innerHTML = i; + hint.style.display='inline'; + hint.style.lineHeight='90%'; + hint.style.backgroundColor='red'; + hint.style.color='white'; + hint.style.fontSize='small-xx'; + hint.style.fontWeight='light'; + hint.style.margin='0px'; + hint.style.padding='2px'; + hint.style.position='absolute'; + hint.style.textDecoration='none'; + hint.style.left=li.style.left; + hint.style.top=li.style.top; + li.insertAdjacentElement('afterBegin',hint); + } +} diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh new file mode 100755 index 0000000..69f4034 --- /dev/null +++ b/examples/data/uzbl/scripts/history.sh @@ -0,0 +1,3 @@ +#!/bin/bash +#TODO: strip 'http://' part +echo "$8 $6 $7" >> $XDG_DATA_HOME/uzbl/history diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh new file mode 100755 index 0000000..b3a7011 --- /dev/null +++ b/examples/data/uzbl/scripts/insert_bookmark.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) + +[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1 +file=$XDG_DATA_HOME/uzbl/bookmarks + +which zenity &>/dev/null || exit 2 + +entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` +url=`awk '{print $1}' <<< $entry` +# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags +echo "$entry" >/dev/null #for some reason we need this.. don't ask me why +echo -e "$entry" >> $file +true diff --git a/examples/data/uzbl/scripts/linkfollow.js b/examples/data/uzbl/scripts/linkfollow.js new file mode 100644 index 0000000..a348af9 --- /dev/null +++ b/examples/data/uzbl/scripts/linkfollow.js @@ -0,0 +1,271 @@ +// link follower for uzbl +// requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 +// +// first, it needs to be loaded before every time it is used. +// One way would be to use the load_commit_handler: +// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' +// +// when script is loaded, it can be invoked with +// bind f* = js hints.set("%s", hints.open) +// bind f_ = js hints.follow("%s",hints.open) +// +// At the moment, it may be useful to have way of forcing uzbl to load the script +// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js +// +// The default style for the hints are pretty ugly, so it is recommended to add the following +// to config file +// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css +// +// based on follow_Numbers.js +// +// TODO: fix styling for the first element +// TODO: emulate mouseover events when visiting some elements +// TODO: rewrite the element->action handling + + +function Hints(){ + + // Settings + //////////////////////////////////////////////////////////////////////////// + + // if set to true, you must explicitly call hints.follow(), otherwise it will + // follow the link if there is only one matching result + var requireReturn = true; + + // Case sensitivity flag + var matchCase = "i"; + + // For case sensitive matching, uncomment: + // var matchCase = ""; + + + var uzblid = 'uzbl_hint'; + var uzblclass = 'uzbl_highlight'; + var uzblclassfirst = 'uzbl_h_first'; + var doc = document; + var visible = []; + var hintdiv; + + this.set = hint; + this.follow = follow; + this.keyPressHandler = keyPressHandler; + + function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; var width = el.offsetWidth; + var height = el.offsetHeight; + + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return {up: up, left: left, width: width, height: height}; + } + + function elementInViewport(p) { + return (p.up < window.pageYOffset + window.innerHeight && + p.left < window.pageXOffset + window.innerWidth && + (p.up + p.height) > window.pageYOffset && + (p.left + p.width) > window.pageXOffset); + } + + function isVisible(el) { + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); + } + + // the vimperator defaults minus the xhtml elements, since it gave DOM errors + var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; + + function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function matchAgainst(element){ + if(element.node.nodeName == "INPUT"){ + return element.node.value; + } else { + return element.node.textContent; + } + } + function test(element) { + // test all the regexp + var item = matchAgainst(element); + return words.every(function (regex) { return item.match(regex)}); + } + } + + function HintElement(node,pos){ + + this.node = node; + this.isHinted = false; + this.position = pos; + this.num = 0; + + this.addHint = function (labelNum) { + // TODO: fix uzblclassfirst + if(!this.isHinted){ + this.node.className += " " + uzblclass; + } + this.isHinted = true; + + // create hint + var hintNode = doc.createElement('div'); + hintNode.name = uzblid; + hintNode.innerText = labelNum; + hintNode.style.left = this.position.left + 'px'; + hintNode.style.top = this.position.up + 'px'; + hintNode.style.position = "absolute"; + doc.body.firstChild.appendChild(hintNode); + + } + this.removeHint = function(){ + if(this.isHinted){ + var s = (this.num)?uzblclassfirst:uzblclass; + this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); + this.isHinted = false; + } + } + } + + function createHintDiv(){ + var hintdiv = doc.getElementById(uzblid); + if(hintdiv){ + hintdiv.parentNode.removeChild(hintdiv); + } + hintdiv = doc.createElement("div"); + hintdiv.setAttribute('id',uzblid); + doc.body.insertBefore(hintdiv,doc.body.firstChild); + return hintdiv; + } + + function init(){ + // WHAT? + doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); + hintdiv = createHintDiv(); + visible = []; + + var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0;i&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # show tags as well + goto=`$DMENU $COLORS < $file | awk '{print $1}'` +else + DMENU="dmenu -i" + # because they are all after each other, just show the url, not their tags. + goto=`awk '{print $1}' $file | $DMENU $COLORS` +fi + +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh new file mode 100755 index 0000000..39ef302 --- /dev/null +++ b/examples/data/uzbl/scripts/load_url_from_history.sh @@ -0,0 +1,20 @@ +#!/bin/bash +history_file=$XDG_DATA_HOME/uzbl/history + +# choose from all entries, sorted and uniqued +# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # choose an item in reverse order, showing also the date and page titles + # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. + goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` +else + DMENU="dmenu -i" + # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order + current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` +fi + +[ -n "$goto" ] && echo "uri $goto" > $4 +#[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh new file mode 100755 index 0000000..e2642c7 --- /dev/null +++ b/examples/data/uzbl/scripts/session.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# Very simple session manager for uzbl. When called with "endsession" as the +# argument, it'll backup $sessionfile, look for fifos in $fifodir and +# instruct each of them to store their current url in $sessionfile and +# terminate themselves. Run with "launch" as the argument and an instance of +# uzbl will be launched for each stored url. "endinstance" is used internally +# and doesn't need to be called manually at any point. +# Add a line like 'bind quit = /path/to/session.sh endsession' to your config + +scriptfile=$0 # this script +sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored +configfile=$XDG_DATA_HOME/uzbl/config # uzbl configuration file +UZBL="uzbl -c $configfile" # add custom flags and whatever here. + +fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere +thisfifo="$4" +act="$8" +url="$6" + +if [ "$act." = "." ]; then + act="$1" +fi + + +case $act in + "launch" ) + urls=$(cat $sessionfile) + if [ "$urls." = "." ]; then + $UZBL + else + for url in $urls; do + $UZBL --uri "$url" & + done + fi + exit 0 + ;; + + "endinstance" ) + if [ "$url" != "(null)" ]; then + echo "$url" >> $sessionfile; + fi + echo "exit" > "$thisfifo" + ;; + + "endsession" ) + mv "$sessionfile" "$sessionfile~" + for fifo in $fifodir/uzbl_fifo_*; do + if [ "$fifo" != "$thisfifo" ]; then + echo "spawn $scriptfile endinstance" > "$fifo" + fi + done + echo "spawn $scriptfile endinstance" > "$thisfifo" + ;; + + * ) echo "session manager: bad action" + echo "Usage: $scriptfile [COMMAND] where commands are:" + echo " launch - Restore a saved session or start a new one" + echo " endsession - Quit the running session. Must be called from uzbl" + ;; +esac + diff --git a/examples/data/uzbl/scripts/uzblcat b/examples/data/uzbl/scripts/uzblcat new file mode 100755 index 0000000..82341c7 --- /dev/null +++ b/examples/data/uzbl/scripts/uzblcat @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +# uzblcat - safely push html to uzbl +# See http://www.uzbl.org/wiki/html-mode +use strict; use warnings; + +my $html; +local $/; # slurp files +# automagically choose to read from stdin/files/... +$html .= $_ for <>; + +my $endmarker = rand; +$endmarker .= rand() while $html =~ /^\Q$endmarker\E$/m; + +print "set base_url = $ENV{BASE_URL}\n" if $ENV{BASE_URL}; +print << "EOS"; +set html_endmarker = $endmarker +set mode = 1 +$html +$endmarker +EOS diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh new file mode 100755 index 0000000..ee140c7 --- /dev/null +++ b/examples/data/uzbl/scripts/yank.sh @@ -0,0 +1,12 @@ +# use this script to pipe any variable to xclip, so you have it in your clipboard +# in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) +# make the 2nd argument one of : primary, secondary, clipboard. +# examples: +# bind yurl = spawn ./examples/scripts/yank.sh 6 primary +# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard + +which xclip &>/dev/null || exit 1 +[ "$9" == primary -o "$9" == secondary -o "$9" == clipboard ] || exit 2 + +echo echo -n "${!8}" '|' xclip -selection $9 +echo -n "${!8}" | xclip -selection $9 diff --git a/examples/data/uzbl/style.css b/examples/data/uzbl/style.css new file mode 100644 index 0000000..de0a38b --- /dev/null +++ b/examples/data/uzbl/style.css @@ -0,0 +1,26 @@ +.uzbl_highlight { background-color: yellow;} +.uzbl_h_first { background-color: lightgreen;} + +.uzbl_follow { border-style: dotted; + border-width: thin; +} + +#uzbl_hint > div { + display: inline; + border: 2px solid #4a6600; + background-color: #b9ff00; + color: black; + font-size: 9px; + font-weight: bold; + line-height: 9px; + margin: 0px; + padding: 0px; + position: absolute; + z-index: 1000; + -webkit-border-radius: 6px; + text-decoration: none; + -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); +} + +/* vim:set et ts=4: */ + diff --git a/examples/data/uzbl/uzbl.png b/examples/data/uzbl/uzbl.png new file mode 100644 index 0000000..773ea84 Binary files /dev/null and b/examples/data/uzbl/uzbl.png differ diff --git a/examples/scripts/clipboard.sh b/examples/scripts/clipboard.sh deleted file mode 100755 index c64b65c..0000000 --- a/examples/scripts/clipboard.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard. - -fifo="$5" -action="$1" -url="$7" -selection=$(xclip -o) - -case $action in - "yank" ) echo -n "$url" | xclip;; - "goto" ) echo "uri $selection" > "$fifo";; - * ) echo "clipboard.sh: invalid action";; -esac - diff --git a/examples/scripts/cookies.py b/examples/scripts/cookies.py deleted file mode 100755 index 0d2a65a..0000000 --- a/examples/scripts/cookies.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python - -import cookielib, sys, os, urllib2 - -class FakeRequest: - def __init__(self, argv): - self.argv = argv - self.cookies = None - if len(self.argv) == 12: - self.cookies = self.argv[11] - def get_full_url(self): - #TODO: this is a hack, fix in uzbl.c! - u = self.get_host()+self.argv[10] - if self.argv[6].startswith('https'): - u = 'https://'+u - else: - u = 'http://'+u - return u - def get_host(self): - return self.argv[9] - def get_type(self): - return self.get_full_url().split(':')[0] - def is_unverifiable(self): - return False - def get_origin_req_host(self): - return self.argv[9] - def has_header(self, header): - if header == 'Cookie': - return self.cookies!=None - def get_header(self, header_name, default=None): - if header_name == 'Cookie' and self.cookies: - return self.cookies - else: - return default - def header_items(self): - if self.cookies: - return [('Cookie',self.cookies)] - else: - return [] - def add_unredirected_header(self, key, header): - if key == 'Cookie': - self.cookies = header - -class FakeHeaders: - def __init__(self, argv): - self.argv = argv - def getallmatchingheaders(self, header): - if header == 'Set-Cookie' and len(self.argv) == 12: - return ['Set-Cookie: '+self.argv[11]] - else: - return [] - def getheaders(self, header): - if header == 'Set-Cookie' and len(self.argv) == 12: - return [self.argv[11]] - else: - return [] -class FakeResponse: - def __init__(self, argv): - self.argv = argv - def info(self): - return FakeHeaders(self.argv) - -if __name__ == '__main__': - search = ['/usr/share/uzbl/examples/data', - os.environ['XDG_DATA_HOME']+'/uzbl', - './examples/data'] - for dir in search: - if os.path.isdir(dir): - cookie_file = dir+'/cookies.txt' - - jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') - try: - jar.load() - except: - pass - - req = FakeRequest(sys.argv) - - action = sys.argv[8] - - if action == 'GET': - jar.add_cookie_header(req) - if req.cookies: - print req.cookies - elif action == 'PUT': - res = FakeResponse(sys.argv) - jar.extract_cookies(res,req) - jar.save(ignore_discard=True) # save session cookies too - #jar.save() # save everything but session cookies \ No newline at end of file diff --git a/examples/scripts/cookies.sh b/examples/scripts/cookies.sh deleted file mode 100755 index a875482..0000000 --- a/examples/scripts/cookies.sh +++ /dev/null @@ -1,155 +0,0 @@ -#!/bin/bash - -# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! - -# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as cookies.py -# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) -# This is one textfile with entries like this: -# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 -# domain alow-read-other-subdomains path http-required expiration name value -# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) -# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" -# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( -# TODO: different cookie paths per config (eg per group of uzbl instances) - -# TODO: correct implementation. -# see http://curl.haxx.se/rfc/cookie_spec.html -# http://en.wikipedia.org/wiki/HTTP_cookie - -# TODO : check expires= before sending. -# write sample script that cleans up cookies dir based on expires attribute. -# TODO: check uri against domain attribute. and path also. -# implement secure attribute. -# support blocking or not for 3rd parties -# http://kb.mozillazine.org/Cookies.txt -# don't always append cookies, sometimes we need to overwrite - -[ -f /usr/share/uzbl/examples/configs/cookies ] && cookie_config=/usr/share/uzbl/examples/configs/cookies -[ -f $XDG_CONFIG_HOME/uzbl/cookies ] && cookie_config=$XDG_CONFIG_HOME/uzbl/cookies -[ -f ./examples/configs/cookies ] && cookie_config=./examples/configs/cookies #useful when developing -[ -z "$cookie_config" ] && exit 1 - -[ -d /usr/share/uzbl/examples/data ] && cookie_data=/usr/share/uzbl/examples/data/cookies.txt -[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_data=$XDG_DATA_HOME/uzbl/cookies.txt -[ -d ./examples/data/ ] && cookie_data=./examples/data/cookies.txt #useful when developing -[ -z "$cookie_data" ] && exit 1 - - -notifier= -#notifier=notify-send -#notify_wrapper () { -# echo "$@" >> $HOME/cookielog -#} -#notifier=notifier_wrapper - -# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. -# it's primarily used for debugging -notifier= -which zenity &>/dev/null || exit 2 - -# Example cookie: -# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net - -# uri=$6 -# uri=${uri/http:\/\/} # strip 'http://' part -# host=${uri/\/*/} -action=$8 # GET/PUT -host=$9 -shift -path=$9 -shift -cookie=$9 - -field_domain=$host -field_path=$path -field_name= -field_value= -field_exp='end_session' - -function notify () { - [ -n "$notifier" ] && $notifier "$@" -} - - -# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET -function parse_cookie () { - IFS=$';' - first_pair=1 - for pair in $cookie - do - if [ "$first_pair" == 1 ] - then - field_name=${pair%%=*} - field_value=${pair#*=} - first_pair=0 - else - read -r pair <<< "$pair" #strip leading/trailing wite space - key=${pair%%=*} - val=${pair#*=} - [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` - # TODO: domain - [ "$key" == path ] && field_path=$val - fi - done - unset IFS -} - -# match cookies in cookies.txt against hostname and path -function get_cookie () { - path_esc=${path//\//\\/} - search="^[^\t]*$host\t[^\t]*\t$path_esc" - cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` - if [ -z "$cookie" ] - then - notify "Get_cookie: search: $search in $cookie_data -> no result" - false - else - notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" - read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" - cookie="$name=$value" - true - fi -} - -function save_cookie () { - if parse_cookie - then - data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" - notify "save_cookie: adding $data to $cookie_data" - echo -e "$data" >> $cookie_data - else - notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" - fi -} - -[ $action == PUT ] && save_cookie -[ $action == GET ] && get_cookie && echo "$cookie" - -exit - - -# TODO: implement this later. -# $1 = section (TRUSTED or DENY) -# $2 =url -function match () { - sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" -} - -function fetch_cookie () { - cookie=`cat $cookie_data` -} - -function store_cookie () { - echo $cookie > $cookie_data -} - -if match TRUSTED $host -then - [ $action == PUT ] && store_cookie $host - [ $action == GET ] && fetch_cookie && echo "$cookie" -elif ! match DENY $host -then - [ $action == PUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host - [ $action == GET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie -fi -exit 0 diff --git a/examples/scripts/download.sh b/examples/scripts/download.sh deleted file mode 100755 index d87335f..0000000 --- a/examples/scripts/download.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# just an example of how you could handle your downloads -# try some pattern matching on the uri to determine what we should do - -# Some sites block the default wget --user-agent... -WGET="wget --user-agent=Firefox" - -if [[ $8 =~ .*(.torrent) ]] -then - cd $HOME - $WGET $8 -else - cd $HOME - $WGET $8 -fi diff --git a/examples/scripts/follow_Numbers.js b/examples/scripts/follow_Numbers.js deleted file mode 100644 index efde4d7..0000000 --- a/examples/scripts/follow_Numbers.js +++ /dev/null @@ -1,223 +0,0 @@ -/* This is the basic linkfollowing script. - * Its pretty stable, only using numbers to navigate. - * - * TODO: Some pages mess around a lot with the zIndex which - * lets some hints in the background. - * TODO: Some positions are not calculated correctly (mostly - * because of uber-fancy-designed-webpages. Basic HTML and CSS - * works good - * TODO: Still some links can't be followed/unexpected things - * happen. Blame some freaky webdesigners ;) - */ - -//Just some shortcuts and globals -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; -//Make onlick-links "clickable" -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -//Catch the ESC keypress to stop linkfollowing -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -//Calculate element position to draw the hint -//Pretty accurate but on fails in some very fancy cases -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -//Calculate if an element is visible -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -//Calculate if an element is on the viewport. -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -//Removes all hints/leftovers that might be generated -//by this script. -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -//Generate a hint for an element with the given label -//Here you can play around with the style of the hints! -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '1000'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} -//Here we choose what to do with an element if we -//want to "follow" it. On form elements we "select" -//or pass the focus, on links we try to perform a click, -//but at least set the href of the link. (needs some improvements) -function clickElem(item) { - removeAllHints(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} -//Returns a list of all links (in this version -//just the elements itself, but in other versions, we -//add the label here. -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - } - } - return res; -} -//Same as above, just for the form elements -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - } - } - } - return res; -} -//Draw all hints for all elements passed. "len" is for -//the number of chars we should use to avoid collisions -function reDrawHints(elems, chars) { - removeAllHints(); - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - for (var i = 0; i < elems[0].length; i++) { - if (elems[0][i]) { - var label = elems[1][i].substring(chars); - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - } -} -//Put it all together -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - var label = j + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - for (var k = 0; k < s.length; k++) { - b = b && label.charAt(k) == s[k]; - } - if (b) { - leftover[0].push(elems[0][j]); - leftover[1].push(label); - } - } - reDrawHints(leftover, s.length); - } -} -followLinks('%s'); diff --git a/examples/scripts/follow_Numbers_Strings.js b/examples/scripts/follow_Numbers_Strings.js deleted file mode 100644 index 67da2f9..0000000 --- a/examples/scripts/follow_Numbers_Strings.js +++ /dev/null @@ -1,205 +0,0 @@ -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.zIndex = '1000'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} -function clickElem(item) { - removeAllHints(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - res[1].push(li.innerText.toLowerCase()); - } - } - return res; -} -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - if (el.getAttribute('value')) { - res[1].push(el.getAttribute('value').toLowerCase()); - } else { - res[1].push(el.getAttribute('name').toLowerCase()); - } - } - } - } - return res; -} -function reDrawHints(elems, len) { - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - hintdiv.style.opacity = '0.0'; - for (var i = 0; i < elems[0].length; i++) { - var label = i + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - if (elems[0][i]) { - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - hintdiv.style.opacity = '0.7' - } -} -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - for (var k = 0; k < s.length; k++) { - b = b && elems[1][j].charAt(k) == s[k]; - } - if (!b) { - elems[0][j] = null; - elems[1][j] = null; - } else { - leftover[0].push(elems[0][j]); - leftover[1].push(elems[1][j]); - } - } - if (leftover[0].length == 1) { - clickElem(leftover[0][0]); - } else if (!oldDiv) { - if (linknr + 1 || s.length == 0) { - reDrawHints(elems, len); - } else { - reDrawHints(leftover, len); - } - } - } -} -followLinks('%s'); diff --git a/examples/scripts/formfiller.pl b/examples/scripts/formfiller.pl deleted file mode 100755 index c590836..0000000 --- a/examples/scripts/formfiller.pl +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/perl - -# a slightly more advanced form filler -# -# uses settings file like: $keydir/ - -# user arg 1: -# edit: force editing of the file (fetches if file is missing) -# load: fill forms from file (fetches if file is missing) -# new: fetch new file - -# usage example: -# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load -# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller.pl new -# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit - -use strict; -use warnings; - -my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; -my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; -if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } - -sub domain { - my ($url) = @_; - $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#; - return $url; -}; - -my $editor = "xterm -e vim"; -#my $editor = "gvim"; - -# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with -# Also, you may need to fake the user-agent on some sites (like facebook) - my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' "; -#my $downloader = "curl -s"; - -my @fields = ("type","name","value"); - -my %command; - -$command{load} = sub { - my ($domain) = @_; - my $filename = "$keydir/$domain"; - if (-e $filename){ - open(my $file, $filename) or die "Failed to open $filename: $!"; - my (@lines) = <$file>; - close($file); - $|++; - open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; - foreach my $line (@lines) { - next if ($line =~ m/^#/); - my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); - if ($type eq "checkbox") - { - printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; - } elsif ($type eq "submit") - { - printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; - } elsif ($type ne "") - { - printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; - } - print $fifo "\n"; - } - $|--; - } else { - $command{new}->($domain); - $command{edit}->($domain); - } -}; -$command{edit} = sub { - my ($domain) = @_; - my $file = "$keydir/$domain"; - if(-e $file){ - system ($editor, $file); - } else { - $command{new}->($domain); - } -}; -$command{new} = sub { - my ($domain) = @_; - my $filename = "$keydir/$domain"; - open (my $file,">>", $filename) or die "Failed to open $filename: $!"; - $|++; - print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; - printf $file "#%-10s | %-10s | %s\n", @fields; - print $file "#------------------------------\n"; - my @data = `$downloader $url`; - foreach my $line (@data){ - if($line =~ m/].*?)>/i){ - $line =~ s/.*(].*?)>).*/$1/; - printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; - }; - }; - $|--; -}; - -$command{$cmd}->(domain($url)); diff --git a/examples/scripts/formfiller.sh b/examples/scripts/formfiller.sh deleted file mode 100755 index 5debcce..0000000 --- a/examples/scripts/formfiller.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# simple html form (eg for logins) filler (and manager) for uzbl. -# uses settings files like: $keydir/ -# files contain lines like: : - - -# user arg 1: -# edit: force editing the file (falls back to new if not found) -# new: start with a new file. -# load: try to load from file into form - -# something else (or empty): if file not available: new, otherwise load. - -[ -d /usr/share/uzbl/examples/data/forms ] && keydir=/usr/share/uzbl/examples/data/forms # you will probably get permission denied errors here. -[ -d $XDG_DATA_HOME/uzbl/forms ] && keydir=$XDG_DATA_HOME/uzbl/forms -[ -d ./examples/data/forms ] && keydir=./examples/data/forms #useful when developing -[ -z "$keydir" ] && exit 1 - -#editor=gvim -editor='urxvt -e vim' - -config=$1; shift -pid=$1; shift -xid=$1; shift -fifo=$1; shift -socket=$1; shift -url=$1; shift -title=$1; shift -action=$1 - -[ -d $keydir ] || mkdir $keydir || exit 1 - -if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ] -then - action=new - [[ -e $keydir/$domain ]] && action=load -elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]] -then - action=new -fi -domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') - - -#regex='s|.*.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page - regex='s|.*> $fifo -else - if [ "$action" == 'new' ] - then - curl "$url" | grep ' $keydir/$domain - fi - [[ -e $keydir/$domain ]] || exit 3 #this should never happen, but you never know. - $editor $keydir/$domain #TODO: if user aborts save in editor, the file is already overwritten -fi diff --git a/examples/scripts/hint.js b/examples/scripts/hint.js deleted file mode 100644 index ec7f1e2..0000000 --- a/examples/scripts/hint.js +++ /dev/null @@ -1,26 +0,0 @@ -for (var i=0; i < document.links.length; i++) { - var uzblid = 'uzbl_link_hint_'; - var li = document.links[i]; - var pre = document.getElementById(uzblid+i); - - if (pre) { - li.removeChild(pre); - } else { - var hint = document.createElement('div'); - hint.setAttribute('id',uzblid+i); - hint.innerHTML = i; - hint.style.display='inline'; - hint.style.lineHeight='90%'; - hint.style.backgroundColor='red'; - hint.style.color='white'; - hint.style.fontSize='small-xx'; - hint.style.fontWeight='light'; - hint.style.margin='0px'; - hint.style.padding='2px'; - hint.style.position='absolute'; - hint.style.textDecoration='none'; - hint.style.left=li.style.left; - hint.style.top=li.style.top; - li.insertAdjacentElement('afterBegin',hint); - } -} diff --git a/examples/scripts/history.sh b/examples/scripts/history.sh deleted file mode 100755 index 19b5218..0000000 --- a/examples/scripts/history.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -#TODO: strip 'http://' part -# you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) -echo "$8 $6 $7" >> /tmp/uzbl.history diff --git a/examples/scripts/insert_bookmark.sh b/examples/scripts/insert_bookmark.sh deleted file mode 100755 index 180f4cd..0000000 --- a/examples/scripts/insert_bookmark.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) - - -[ -f /usr/share/uzbl/examples/data/bookmarks ] && file=/usr/share/uzbl/examples/data/bookmarks # you will probably get permission denied errors here. -[ -f $XDG_DATA_HOME/uzbl/bookmarks ] && file=$XDG_DATA_HOME/uzbl/bookmarks -[ -f ./examples/data/bookmarks ] && file=./examples/data/bookmarks #useful when developing -[ -z "$file" ] && exit 1 - -which zenity &>/dev/null || exit 2 - -entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` -url=`awk '{print $1}' <<< $entry` -# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags -echo "$entry" >/dev/null #for some reason we need this.. don't ask me why -echo -e "$entry" >> $file -true \ No newline at end of file diff --git a/examples/scripts/linkfollow.js b/examples/scripts/linkfollow.js deleted file mode 100644 index a348af9..0000000 --- a/examples/scripts/linkfollow.js +++ /dev/null @@ -1,271 +0,0 @@ -// link follower for uzbl -// requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 -// -// first, it needs to be loaded before every time it is used. -// One way would be to use the load_commit_handler: -// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' -// -// when script is loaded, it can be invoked with -// bind f* = js hints.set("%s", hints.open) -// bind f_ = js hints.follow("%s",hints.open) -// -// At the moment, it may be useful to have way of forcing uzbl to load the script -// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js -// -// The default style for the hints are pretty ugly, so it is recommended to add the following -// to config file -// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css -// -// based on follow_Numbers.js -// -// TODO: fix styling for the first element -// TODO: emulate mouseover events when visiting some elements -// TODO: rewrite the element->action handling - - -function Hints(){ - - // Settings - //////////////////////////////////////////////////////////////////////////// - - // if set to true, you must explicitly call hints.follow(), otherwise it will - // follow the link if there is only one matching result - var requireReturn = true; - - // Case sensitivity flag - var matchCase = "i"; - - // For case sensitive matching, uncomment: - // var matchCase = ""; - - - var uzblid = 'uzbl_hint'; - var uzblclass = 'uzbl_highlight'; - var uzblclassfirst = 'uzbl_h_first'; - var doc = document; - var visible = []; - var hintdiv; - - this.set = hint; - this.follow = follow; - this.keyPressHandler = keyPressHandler; - - function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; var width = el.offsetWidth; - var height = el.offsetHeight; - - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return {up: up, left: left, width: width, height: height}; - } - - function elementInViewport(p) { - return (p.up < window.pageYOffset + window.innerHeight && - p.left < window.pageXOffset + window.innerWidth && - (p.up + p.height) > window.pageYOffset && - (p.left + p.width) > window.pageXOffset); - } - - function isVisible(el) { - if (el == doc) { return true; } - if (!el) { return false; } - if (!el.parentNode) { return false; } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); - } - - // the vimperator defaults minus the xhtml elements, since it gave DOM errors - var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; - - function Matcher(str){ - var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); - this.test = test; - this.toString = toString; - this.numbers = numbers; - function matchAgainst(element){ - if(element.node.nodeName == "INPUT"){ - return element.node.value; - } else { - return element.node.textContent; - } - } - function test(element) { - // test all the regexp - var item = matchAgainst(element); - return words.every(function (regex) { return item.match(regex)}); - } - } - - function HintElement(node,pos){ - - this.node = node; - this.isHinted = false; - this.position = pos; - this.num = 0; - - this.addHint = function (labelNum) { - // TODO: fix uzblclassfirst - if(!this.isHinted){ - this.node.className += " " + uzblclass; - } - this.isHinted = true; - - // create hint - var hintNode = doc.createElement('div'); - hintNode.name = uzblid; - hintNode.innerText = labelNum; - hintNode.style.left = this.position.left + 'px'; - hintNode.style.top = this.position.up + 'px'; - hintNode.style.position = "absolute"; - doc.body.firstChild.appendChild(hintNode); - - } - this.removeHint = function(){ - if(this.isHinted){ - var s = (this.num)?uzblclassfirst:uzblclass; - this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); - this.isHinted = false; - } - } - } - - function createHintDiv(){ - var hintdiv = doc.getElementById(uzblid); - if(hintdiv){ - hintdiv.parentNode.removeChild(hintdiv); - } - hintdiv = doc.createElement("div"); - hintdiv.setAttribute('id',uzblid); - doc.body.insertBefore(hintdiv,doc.body.firstChild); - return hintdiv; - } - - function init(){ - // WHAT? - doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); - hintdiv = createHintDiv(); - visible = []; - - var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0;i&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # show tags as well - goto=`$DMENU $COLORS < $file | awk '{print $1}'` -else - DMENU="dmenu -i" - # because they are all after each other, just show the url, not their tags. - goto=`awk '{print $1}' $file | $DMENU $COLORS` -fi - -#[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/load_url_from_history.sh b/examples/scripts/load_url_from_history.sh deleted file mode 100755 index 37c2afc..0000000 --- a/examples/scripts/load_url_from_history.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# you probably really want this in your $XDG_DATA_HOME (eg $HOME/.local/share/uzbl/history) -history_file=/tmp/uzbl.history - -# choose from all entries, sorted and uniqued -# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # choose an item in reverse order, showing also the date and page titles - # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. - goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` -else - DMENU="dmenu -i" - # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` -fi - -[ -n "$goto" ] && echo "uri $goto" > $4 -#[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/scripts/session.sh b/examples/scripts/session.sh deleted file mode 100755 index e2642c7..0000000 --- a/examples/scripts/session.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# Very simple session manager for uzbl. When called with "endsession" as the -# argument, it'll backup $sessionfile, look for fifos in $fifodir and -# instruct each of them to store their current url in $sessionfile and -# terminate themselves. Run with "launch" as the argument and an instance of -# uzbl will be launched for each stored url. "endinstance" is used internally -# and doesn't need to be called manually at any point. -# Add a line like 'bind quit = /path/to/session.sh endsession' to your config - -scriptfile=$0 # this script -sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored -configfile=$XDG_DATA_HOME/uzbl/config # uzbl configuration file -UZBL="uzbl -c $configfile" # add custom flags and whatever here. - -fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -thisfifo="$4" -act="$8" -url="$6" - -if [ "$act." = "." ]; then - act="$1" -fi - - -case $act in - "launch" ) - urls=$(cat $sessionfile) - if [ "$urls." = "." ]; then - $UZBL - else - for url in $urls; do - $UZBL --uri "$url" & - done - fi - exit 0 - ;; - - "endinstance" ) - if [ "$url" != "(null)" ]; then - echo "$url" >> $sessionfile; - fi - echo "exit" > "$thisfifo" - ;; - - "endsession" ) - mv "$sessionfile" "$sessionfile~" - for fifo in $fifodir/uzbl_fifo_*; do - if [ "$fifo" != "$thisfifo" ]; then - echo "spawn $scriptfile endinstance" > "$fifo" - fi - done - echo "spawn $scriptfile endinstance" > "$thisfifo" - ;; - - * ) echo "session manager: bad action" - echo "Usage: $scriptfile [COMMAND] where commands are:" - echo " launch - Restore a saved session or start a new one" - echo " endsession - Quit the running session. Must be called from uzbl" - ;; -esac - diff --git a/examples/scripts/uzblcat b/examples/scripts/uzblcat deleted file mode 100755 index 82341c7..0000000 --- a/examples/scripts/uzblcat +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env perl -# uzblcat - safely push html to uzbl -# See http://www.uzbl.org/wiki/html-mode -use strict; use warnings; - -my $html; -local $/; # slurp files -# automagically choose to read from stdin/files/... -$html .= $_ for <>; - -my $endmarker = rand; -$endmarker .= rand() while $html =~ /^\Q$endmarker\E$/m; - -print "set base_url = $ENV{BASE_URL}\n" if $ENV{BASE_URL}; -print << "EOS"; -set html_endmarker = $endmarker -set mode = 1 -$html -$endmarker -EOS diff --git a/examples/scripts/yank.sh b/examples/scripts/yank.sh deleted file mode 100755 index ee140c7..0000000 --- a/examples/scripts/yank.sh +++ /dev/null @@ -1,12 +0,0 @@ -# use this script to pipe any variable to xclip, so you have it in your clipboard -# in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) -# make the 2nd argument one of : primary, secondary, clipboard. -# examples: -# bind yurl = spawn ./examples/scripts/yank.sh 6 primary -# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard - -which xclip &>/dev/null || exit 1 -[ "$9" == primary -o "$9" == secondary -o "$9" == clipboard ] || exit 2 - -echo echo -n "${!8}" '|' xclip -selection $9 -echo -n "${!8}" | xclip -selection $9 diff --git a/uzbl.png b/uzbl.png deleted file mode 100644 index 773ea84..0000000 Binary files a/uzbl.png and /dev/null differ -- cgit v1.2.3 From 264c01baa1cf9287cf44dd28e9de7c1716d5141e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 7 Jun 2009 22:50:57 +0200 Subject: fixes to make the dir refactoring work --- Makefile | 7 +- examples/config/uzbl/config | 177 ++++++++++++++++++++++++++++++++++++++ examples/config/uzbl/sampleconfig | 177 -------------------------------------- 3 files changed, 179 insertions(+), 182 deletions(-) create mode 100644 examples/config/uzbl/config delete mode 100644 examples/config/uzbl/sampleconfig (limited to 'examples') diff --git a/Makefile b/Makefile index 3e0647d..b23b020 100644 --- a/Makefile +++ b/Makefile @@ -7,14 +7,11 @@ PREFIX?=$(DESTDIR)/usr test: uzbl ./uzbl --uri http://www.uzbl.org --verbose -test-config: uzbl - ./uzbl --uri http://www.uzbl.org --verbose - test-config-dev: uzbl - XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --config $XDG_CONFIG_HOME/uzbl/sampleconfig --verbose + XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose test-config-share: uzbl - XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --config $XDG_CONFIG_HOME/uzbl/sampleconfig --verbose + XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --verbose clean: diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config new file mode 100644 index 0000000..bbe3a75 --- /dev/null +++ b/examples/config/uzbl/config @@ -0,0 +1,177 @@ + +# example uzbl config. in a real config, we should obey the xdg spec +# all settings are optional. you can use uzbl without any config at all (but it won't do much) + +# keyboard behavior is vimstyle by default (all commands -> 1 key). set +# always_insert_mode to always be in insert mode and disable going out of it. +# if you do this, make sure you've set a modkey so you can reach the commands +# from insert mode by combining them with the modkey + +# TODO: ability to attach misc things (spawn , script ,.. to internal events) +# Usually you want to spawn a script to handle things, but any command (such as sh) can be used +set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh +set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh +set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py + +set minimum_font_size = 6 +set font_size = 11 +## monospace_size defaults to font_size, but you can alter it independently +#set monospace_size = 10 + +## Display or supress images within html sites +#set autoload_images = 0 + +## Shrink images to window size +#set autoshrink_images = 0 + +## Spellchecker +#set enable_spellcheck = 1 + +## Private browsing +#set enbale_private = 0 + +## The URI of a stylesheet that is applied to every page +#set stylesheet_uri = http://www.user.com/mystylelesheet.css + +## enable/disable JavaScript +#set disbale_scripts = 1 + +## Whether text areas are resizable +#set resizeable_text_areas = 1 + +## The default encoding used to display text +#set default_encoding = iso-8859-1 + +## Whether background images should be printed +#set print_background = 0 + +## Enforce a resolution of 96 DPI. This is meant for compatibility with +## web pages which cope badly with different screen resolutions +#set enforce_96_dpi = 1 + + +# +# use with bind ... = sh +set shell_cmd = sh -c + + + +# Behaviour and appearance +set show_status = 1 +# you can optionally use this setting to override the background color of the statusbar from your GTK theme. +set status_background = #303030 +set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_top = 0 +# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) +set title_format_short = TITLE - Uzbl browser +set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI +# set the characters to use for, and the width of the progress bar +set status_pbar_done = * +set status_pbar_pending = - +set status_pbar_width = 12 +set insert_indicator = I +set command_indicator = C +set modkey = Mod1 +# reset to command mode when new page is loaded +set reset_command_mode = 1 +# this var has precedence over reset_command_mode +set always_insert_mode = 0 + +# to start a local socks server, do : ssh -fND localhost:8118 localhost +#set proxy_url = http://127.0.0.1:8118 +#values 0-3 +#set http_debug = 0 +#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) +# Example user agent containing everything: +set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) +#set max_conns = 0 +#set max_conns_host = 0 + +set fifo_dir = /tmp +set socket_dir = /tmp + +# Key bindings +bind j = scroll_vert 20 +bind k = scroll_vert -20 +bind h = scroll_horz -20 +bind l = scroll_horz 20 +bind << = scroll_begin +bind >> = scroll_end +bind b = back +bind m = forward +bind s = stop +bind r = reload +bind R = reload_ign_cache +bind + = zoom_in +bind - = zoom_out +bind 1 = sh "echo set zoom_level = 1.0 > $4" +bind 2 = sh "echo set zoom_level = 2.0 > $4" +bind t = toggle_status +# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called +# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. +bind /* = search %s +bind ?* = search_reverse %s +#jump to next +bind n = search +bind N = search_reverse +bind gh = uri http://www.uzbl.org +#TODO: set uri? +bind o _ = uri %s +bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +bind gg _ = uri http://www.google.com/search?q=%s +bind i = toggle_insert_mode +# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting +bind I = toggle_insert_mode 0 +# Enclose the executable in quotes if it has spaces. Any additional parameters you use will +# appear AFTER the default parameters +bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh +bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh +bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh +# with the sample yank script, you can yank one of the arguments into clipboard/selection +bind yurl = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 6 primary +bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard +# does the same as yurl but without needing a script +bind y2url = sh 'echo -n $6 | xclip' +# go the page from primary selection +bind p = sh "echo uri `xclip -selection primary -o` > $4" +# go to the page in clipboard +bind P = sh "echo uri `xclip -selection clipboard -o` > $4" +bind ZZ = exit +bind S = js alert("hi"); +# example showing how to use sh +# it sends a command to the fifo, whose path is told via a positional param +# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it +# The body of the shell command should be one parameter, so if it has spaces like here, +# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes +# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file +# path, fifo & socket dirs, etc.) +bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' +bind dump = sh "echo dump_config > $4" +# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically +bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh +bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit +bind zn = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh new +bind zl = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh load + +# other - more advanced - implementation using perl: (could not get this to run - Dieter ) +bind LL = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl load +bind LN = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl new +bind LE = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl edit + +# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) +# this is similar to how it works in vimperator (and konqueror) +# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? +#hit F to toggle the Hints (now in form of link numbering) +bind F = script $XDG_DATA_HOME/uzbl/scripts/hint.js +# the most stable version: +bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s +# using strings, not polished yet: +bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s + +# you can use this to disable all plugins +set disable_plugins = 0 + +set icon = ./uzbl.png + +# "home" page if you will +set uri = uzbl.org diff --git a/examples/config/uzbl/sampleconfig b/examples/config/uzbl/sampleconfig deleted file mode 100644 index 53c4086..0000000 --- a/examples/config/uzbl/sampleconfig +++ /dev/null @@ -1,177 +0,0 @@ - -# example uzbl config. in a real config, we should obey the xdg spec -# all settings are optional. you can use uzbl without any config at all (but it won't do much) - -# keyboard behavior is vimstyle by default (all commands -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the commands -# from insert mode by combining them with the modkey - -# TODO: ability to attach misc things (spawn , script ,.. to internal events) -# Usually you want to spawn a script to handle things, but any command (such as sh) can be used -set history_handler = spawn $XDG_DATA_HOME/scripts/history.sh -set download_handler = spawn $XDG_DATA_HOME/scripts/download.sh -set cookie_handler = spawn $XDG_DATA_HOME/scripts/cookies.py - -set minimum_font_size = 6 -set font_size = 11 -## monospace_size defaults to font_size, but you can alter it independently -#set monospace_size = 10 - -## Display or supress images within html sites -#set autoload_images = 0 - -## Shrink images to window size -#set autoshrink_images = 0 - -## Spellchecker -#set enable_spellcheck = 1 - -## Private browsing -#set enbale_private = 0 - -## The URI of a stylesheet that is applied to every page -#set stylesheet_uri = http://www.user.com/mystylelesheet.css - -## enable/disable JavaScript -#set disbale_scripts = 1 - -## Whether text areas are resizable -#set resizeable_text_areas = 1 - -## The default encoding used to display text -#set default_encoding = iso-8859-1 - -## Whether background images should be printed -#set print_background = 0 - -## Enforce a resolution of 96 DPI. This is meant for compatibility with -## web pages which cope badly with different screen resolutions -#set enforce_96_dpi = 1 - - -# -# use with bind ... = sh -set shell_cmd = sh -c - - - -# Behaviour and appearance -set show_status = 1 -# you can optionally use this setting to override the background color of the statusbar from your GTK theme. -set status_background = #303030 -set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI -set status_top = 0 -# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) -set title_format_short = TITLE - Uzbl browser -set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI -# set the characters to use for, and the width of the progress bar -set status_pbar_done = * -set status_pbar_pending = - -set status_pbar_width = 12 -set insert_indicator = I -set command_indicator = C -set modkey = Mod1 -# reset to command mode when new page is loaded -set reset_command_mode = 1 -# this var has precedence over reset_command_mode -set always_insert_mode = 0 - -# to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 -#values 0-3 -#set http_debug = 0 -#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) -# Example user agent containing everything: -set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) -#set max_conns = 0 -#set max_conns_host = 0 - -set fifo_dir = /tmp -set socket_dir = /tmp - -# Key bindings -bind j = scroll_vert 20 -bind k = scroll_vert -20 -bind h = scroll_horz -20 -bind l = scroll_horz 20 -bind << = scroll_begin -bind >> = scroll_end -bind b = back -bind m = forward -bind s = stop -bind r = reload -bind R = reload_ign_cache -bind + = zoom_in -bind - = zoom_out -bind 1 = sh "echo set zoom_level = 1.0 > $4" -bind 2 = sh "echo set zoom_level = 2.0 > $4" -bind t = toggle_status -# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called -# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. -bind /* = search %s -bind ?* = search_reverse %s -#jump to next -bind n = search -bind N = search_reverse -bind gh = uri http://www.uzbl.org -#TODO: set uri? -bind o _ = uri %s -bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ = uri http://www.google.com/search?q=%s -bind i = toggle_insert_mode -# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting -bind I = toggle_insert_mode 0 -# Enclose the executable in quotes if it has spaces. Any additional parameters you use will -# appear AFTER the default parameters -bind B = spawn $XDG_DATA_HOME/scripts/insert_bookmark.sh -bind U = spawn $XDG_DATA_HOME/scripts/load_url_from_history.sh -bind u = spawn $XDG_DATA_HOME/scripts/load_url_from_bookmarks.sh -# with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn $XDG_DATA_HOME/scripts/yank.sh 6 primary -bind ytitle = spawn $XDG_DATA_HOME/scripts/yank.sh 7 clipboard -# does the same as yurl but without needing a script -bind y2url = sh 'echo -n $6 | xclip' -# go the page from primary selection -bind p = sh "echo uri `xclip -selection primary -o` > $4" -# go to the page in clipboard -bind P = sh "echo uri `xclip -selection clipboard -o` > $4" -bind ZZ = exit -bind S = js alert("hi"); -# example showing how to use sh -# it sends a command to the fifo, whose path is told via a positional param -# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -# The body of the shell command should be one parameter, so if it has spaces like here, -# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes -# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file -# path, fifo & socket dirs, etc.) -bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -bind dump = sh "echo dump_config > $4" -# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically -bind za = spawn $XDG_DATA_HOME/scripts/formfiller.sh -bind ze = spawn $XDG_DATA_HOME/scripts/formfiller.sh edit -bind zn = spawn $XDG_DATA_HOME/scripts/formfiller.sh new -bind zl = spawn $XDG_DATA_HOME/scripts/formfiller.sh load - -# other - more advanced - implementation using perl: (could not get this to run - Dieter ) -bind LL = spawn $XDG_DATA_HOME/scripts/formfiller.pl load -bind LN = spawn $XDG_DATA_HOME/scripts/formfiller.pl new -bind LE = spawn $XDG_DATA_HOME/scripts/formfiller.pl edit - -# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) -# this is similar to how it works in vimperator (and konqueror) -# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? -#hit F to toggle the Hints (now in form of link numbering) -bind F = script $XDG_DATA_HOME/scripts/hint.js -# the most stable version: -bind fl* = script $XDG_DATA_HOME/scripts/follow_Numbers.js %s -# using strings, not polished yet: -bind fL* = script $XDG_DATA_HOME/scripts/follow_Numbers_Strings.js %s - -# you can use this to disable all plugins -set disable_plugins = 0 - -set icon = ./uzbl.png - -# "home" page if you will -set uri = uzbl.org -- cgit v1.2.3 From 63c75cbb67228924d5dc1c7f45054f40cd2d395f Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 8 Jun 2009 21:16:25 +0200 Subject: be more friendly to people who have no XDG variables set + bitter checking and such --- examples/data/uzbl/scripts/cookies.py | 7 +++++-- examples/data/uzbl/scripts/cookies.sh | 5 ++--- examples/data/uzbl/scripts/formfiller.pl | 2 +- examples/data/uzbl/scripts/formfiller.sh | 5 +++-- examples/data/uzbl/scripts/history.sh | 4 +++- examples/data/uzbl/scripts/insert_bookmark.sh | 5 ++--- examples/data/uzbl/scripts/load_url_from_bookmarks.sh | 4 ++-- examples/data/uzbl/scripts/load_url_from_history.sh | 3 ++- examples/data/uzbl/scripts/session.sh | 5 +++-- 9 files changed, 23 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index 3cc7eb0..8d7027b 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -61,7 +61,10 @@ class FakeResponse: return FakeHeaders(self.argv) if __name__ == '__main__': - jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') + if os.environ['XDG_DATA_HOME']: + jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') + else: + jar = cookielib.MozillaCookieJar(os.environ['HOME']+'.local/share/uzbl/cookies.txt') try: jar.load() except: @@ -79,4 +82,4 @@ if __name__ == '__main__': res = FakeResponse(sys.argv) jar.extract_cookies(res,req) jar.save(ignore_discard=True) # save session cookies too - #jar.save() # save everything but session cookies \ No newline at end of file + #jar.save() # save everything but session cookies diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh index 78139d6..56b9c79 100755 --- a/examples/data/uzbl/scripts/cookies.sh +++ b/examples/data/uzbl/scripts/cookies.sh @@ -24,10 +24,9 @@ # http://kb.mozillazine.org/Cookies.txt # don't always append cookies, sometimes we need to overwrite -cookie_config=$XDG_CONFIG_HOME/uzbl/cookies +cookie_config=${XDG_CONFIG_HOME:-$HOME/.config}/uzbl/cookies [ -z "$cookie_config" ] && exit 1 -[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1 -[ -d $XDG_DATA_HOME/uzbl/ ] && cookie_data=$XDG_DATA_HOME/uzbl/cookies.txt +[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/ ] && cookie_data=${XDG_DATA_HOME:-$home/.local/share}/uzbl/cookies.txt || exit 1 notifier= diff --git a/examples/data/uzbl/scripts/formfiller.pl b/examples/data/uzbl/scripts/formfiller.pl index c590836..9ac6959 100755 --- a/examples/data/uzbl/scripts/formfiller.pl +++ b/examples/data/uzbl/scripts/formfiller.pl @@ -3,7 +3,7 @@ # a slightly more advanced form filler # # uses settings file like: $keydir/ - +#TODO: fallback to $HOME/.local/share # user arg 1: # edit: force editing of the file (fetches if file is missing) # load: fill forms from file (fetches if file is missing) diff --git a/examples/data/uzbl/scripts/formfiller.sh b/examples/data/uzbl/scripts/formfiller.sh index d54c626..bbb9d1a 100755 --- a/examples/data/uzbl/scripts/formfiller.sh +++ b/examples/data/uzbl/scripts/formfiller.sh @@ -12,8 +12,9 @@ # something else (or empty): if file not available: new, otherwise load. -keydir=$XDG_DATA_HOME/uzbl/forms -[ -z "$keydir" ] && exit 1 +keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms +[ -d "`dirname $keydir`" ] || exit 1 +[ -d "$keydir" ] || mkdir "$keydir" #editor=gvim editor='urxvt -e vim' diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh index 69f4034..ccc6b40 100755 --- a/examples/data/uzbl/scripts/history.sh +++ b/examples/data/uzbl/scripts/history.sh @@ -1,3 +1,5 @@ #!/bin/bash #TODO: strip 'http://' part -echo "$8 $6 $7" >> $XDG_DATA_HOME/uzbl/history +file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history +[ -d `dirname $file` ] || exit 1 +echo "$8 $6 $7" >> $file diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh index b3a7011..23c0d31 100755 --- a/examples/data/uzbl/scripts/insert_bookmark.sh +++ b/examples/data/uzbl/scripts/insert_bookmark.sh @@ -1,8 +1,7 @@ #!/bin/bash -# you probably want your bookmarks file in your $XDG_DATA_HOME ( eg $HOME/.local/share/uzbl/bookmarks) -[ -d "$XDG_DATA_HOME/uzbl" ] || exit 1 -file=$XDG_DATA_HOME/uzbl/bookmarks +[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1 +file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks which zenity &>/dev/null || exit 2 diff --git a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh index eb04873..78ee726 100755 --- a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh +++ b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh @@ -2,8 +2,8 @@ #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. -file=$XDG_DATA_HOME/uzbl/bookmarks -[ -z "$file" ] && exit +file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks +[ -r "$file" ] || exit COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh index 39ef302..57d634a 100755 --- a/examples/data/uzbl/scripts/load_url_from_history.sh +++ b/examples/data/uzbl/scripts/load_url_from_history.sh @@ -1,5 +1,6 @@ #!/bin/bash -history_file=$XDG_DATA_HOME/uzbl/history +history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history +[ -r "$history_file" ] || exit 1 # choose from all entries, sorted and uniqued # goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh index e2642c7..4dbae55 100755 --- a/examples/data/uzbl/scripts/session.sh +++ b/examples/data/uzbl/scripts/session.sh @@ -8,9 +8,10 @@ # and doesn't need to be called manually at any point. # Add a line like 'bind quit = /path/to/session.sh endsession' to your config +[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1 scriptfile=$0 # this script -sessionfile=$XDG_DATA_HOME/uzbl/session # the file in which the "session" (i.e. urls) are stored -configfile=$XDG_DATA_HOME/uzbl/config # uzbl configuration file +sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/session # the file in which the "session" (i.e. urls) are stored +configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file UZBL="uzbl -c $configfile" # add custom flags and whatever here. fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -- cgit v1.2.3 From d3cb6e5f11499f5b76f7e3d2fbb8bb0abc527f7e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 8 Jun 2009 22:18:25 +0200 Subject: fix quotes regression --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 714daa2..9606edd 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -134,9 +134,9 @@ bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection -bind p = sh "echo uri `xclip -selection primary -o` > $4" +bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # go to the page in clipboard -bind P = sh "echo uri `xclip -selection clipboard -o` > $4" +bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' bind ZZ = exit bind S = js alert("hi"); # example showing how to use sh -- cgit v1.2.3 From 087bca445cd96d69a5fe9aa56b7ba88e9f9f7de6 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 8 Jun 2009 22:48:12 +0200 Subject: slightly better example config with a few new cool examples --- examples/config/uzbl/config | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9606edd..dcb00fd 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,18 +1,22 @@ - -# example uzbl config. in a real config, we should obey the xdg spec +# example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) -# keyboard behavior is vimstyle by default (all commands -> 1 key). set -# always_insert_mode to always be in insert mode and disable going out of it. +# keyboard behavior is vimstyle by default, but you can change this +# set always_insert_mode to always be in insert mode and disable going out of it. # if you do this, make sure you've set a modkey so you can reach the commands # from insert mode by combining them with the modkey -# TODO: ability to attach misc things (spawn , script ,.. to internal events) # Usually you want to spawn a script to handle things, but any command (such as sh) can be used set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py +# You can bind whatever things (spawn , script ,..) to some events TODO: make events system more generic +set load_start_handler = set status_message = wait +set load_commit_handler = set status_message = recv +set load_finish_handler = set status_message = done + + set minimum_font_size = 6 set font_size = 11 ## monospace_size defaults to font_size, but you can alter it independently @@ -61,7 +65,7 @@ set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI -set status_top = 0 +set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = TITLE - Uzbl browser set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI @@ -99,7 +103,7 @@ bind << = scroll_begin bind >> = scroll_end bind b = back bind m = forward -bind s = stop +bind S = stop bind r = reload bind R = reload_ign_cache bind + = zoom_in @@ -116,9 +120,15 @@ bind ?* = search_reverse %s bind n = search bind N = search_reverse bind gh = uri http://www.uzbl.org -#TODO: set uri? + +# like this you can enter any command at runtime, interactively. prefixed by ':' +bind :_ = chain '%s' + +# shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..' bind o _ = uri %s -bind :wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +# shortcut to set variables +bind s _ = set %s +bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go bind gg _ = uri http://www.google.com/search?q=%s bind i = toggle_insert_mode # disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting @@ -138,7 +148,7 @@ bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # go to the page in clipboard bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' bind ZZ = exit -bind S = js alert("hi"); +bind Xs = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -147,7 +157,10 @@ bind S = js alert("hi"); # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -bind dump = sh "echo dump_config > $4" + +bind !dump = sh "echo dump_config > $4" +bind !reload = sh 'cat $1 > $4' + # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit -- cgit v1.2.3 From 0b052006d64f176a85e562f57df94c0d4d05fc39 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 8 Jun 2009 22:50:43 +0200 Subject: keybind to start a new uzbl instance from the page in primary selection --- examples/config/uzbl/config | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index dcb00fd..e7c03dc 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -147,6 +147,8 @@ bind y2url = sh 'echo -n $6 | xclip' bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # go to the page in clipboard bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' +# start a new uzbl instance from the page in primary selection +bind 'p = sh 'exec uzbl --uri $(xclip -o)' bind ZZ = exit bind Xs = js alert("hi"); # example showing how to use sh -- cgit v1.2.3 From ddcec48929b6ab18bc6a6324d2d5919b081f48a4 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 8 Jun 2009 22:51:57 +0200 Subject: indentation fix --- examples/data/uzbl/scripts/cookies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index 8d7027b..1845c26 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -61,9 +61,9 @@ class FakeResponse: return FakeHeaders(self.argv) if __name__ == '__main__': - if os.environ['XDG_DATA_HOME']: + if os.environ['XDG_DATA_HOME']: jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') - else: + else: jar = cookielib.MozillaCookieJar(os.environ['HOME']+'.local/share/uzbl/cookies.txt') try: jar.load() -- cgit v1.2.3 From 6ce2ada0bd5a7966573a0b89cef8fc08336b2423 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 9 Jun 2009 22:11:00 +0200 Subject: merge in holizz uzbl_tabbed --- AUTHORS | 2 +- examples/data/uzbl/scripts/uzbl_tabbed.py | 41 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100755 examples/data/uzbl/scripts/uzbl_tabbed.py (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index 1253144..1873492 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,7 +21,7 @@ Contributors: Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch (uranther) - zoom level (bobpaul) - session script patches - Tom Adams (holizz) - few patches, cookies.py + Tom Adams (holizz) - few patches, cookies.py, gtkplugk/socket & uzbl_tabbed.py neutralinsomniac - load_progress = 0 fix Maximilian Gaß (mxey) - small patches Abel Camarillo (00z) - make it compile on OpenBSD diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py new file mode 100755 index 0000000..4c3a934 --- /dev/null +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -0,0 +1,41 @@ +#!/usr/bin/python + +import string, pygtk, gtk, sys, subprocess +pygtk.require('2.0') + +def new_tab(nothing): + socket = gtk.Socket() + socket.show() + notebook.append_page(socket, gtk.Label('title goes here')) + sid = socket.get_id() + subprocess.call(['sh', '-c', 'uzbl -s %s &'%sid]) + + +window = gtk.Window() +window.show() + +vbox = gtk.VBox() +vbox.show() +window.add(vbox) + +button = gtk.Button(stock=gtk.STOCK_ADD) +button.connect('clicked', new_tab) +button.show() +vbox.add(button) + +notebook = gtk.Notebook() +vbox.add(notebook) +notebook.show() + +window.connect("destroy", lambda w: gtk.main_quit()) + +#def plugged_event(widget): +# print "I (", widget, ") have just had a plug inserted!" + +#socket.connect("plug-added", plugged_event) +#socket.connect("plug-removed", plugged_event) + +if len(sys.argv) == 2: + socket.add_id(long(sys.argv[1])) + +gtk.main() \ No newline at end of file -- cgit v1.2.3 From b58b53ec93587bd9ddd8b2ec2fed63607ee8662b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 23 Jun 2009 16:06:30 +0800 Subject: Checks if XDA_DATA_HOME in os.environ before use Additionally when XDA_DATA_HOME doesn't exist the cookie jar location defaults to os.environ["HOME"] + '.local/share/uzbl/cookies.txt' however when these strings are concatenated they are missing the path seperator '/'. Problem solved by using the builtin os.path.join to join the environ path and jar location. On branch experimental: Changes to be committed: modified: examples/data/uzbl/scripts/cookies.py --- examples/data/uzbl/scripts/cookies.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index 1845c26..4f80359 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -61,10 +61,12 @@ class FakeResponse: return FakeHeaders(self.argv) if __name__ == '__main__': - if os.environ['XDG_DATA_HOME']: - jar = cookielib.MozillaCookieJar(os.environ['XDG_DATA_HOME']+'/uzbl/cookies.txt') + if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: + jar = cookielib.MozillaCookieJar(\ + os.path.join(os.environ['XDG_DATA_HOME'],'/uzbl/cookies.txt')) else: - jar = cookielib.MozillaCookieJar(os.environ['HOME']+'.local/share/uzbl/cookies.txt') + jar = cookielib.MozillaCookieJar(\ + os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) try: jar.load() except: -- cgit v1.2.3 From d36686924a2b7d81ad5c74b38249e53af0b6449e Mon Sep 17 00:00:00 2001 From: Abel `00z' Camarillo <00z@the00z.org> Date: Sun, 28 Jun 2009 02:42:31 -0500 Subject: make domnload.sh more portable now not bash-specific. --- examples/data/uzbl/scripts/download.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh index d87335f..aa1ca09 100755 --- a/examples/data/uzbl/scripts/download.sh +++ b/examples/data/uzbl/scripts/download.sh @@ -1,15 +1,19 @@ -#!/bin/bash +#!/bin/sh # just an example of how you could handle your downloads # try some pattern matching on the uri to determine what we should do -# Some sites block the default wget --user-agent... -WGET="wget --user-agent=Firefox" +# Some sites block the default wget --user-agent.. +GET="wget --user-agent=Firefox" -if [[ $8 =~ .*(.torrent) ]] +dest="$HOME" +url="$8" + +test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } + +# only changes the dir for the $get sub process +if echo "$url" | grep -E '.*\.torrent' >/dev/null; then - cd $HOME - $WGET $8 + ( cd "$dest"; eval "$GET" "$url") else - cd $HOME - $WGET $8 + ( cd "$dest"; eval "$GET" "$url") fi -- cgit v1.2.3 From 135b490546cd5833aec76588825eba6634f8fd21 Mon Sep 17 00:00:00 2001 From: Abel `00z' Camarillo <00z@the00z.org> Date: Sun, 28 Jun 2009 13:03:22 -0500 Subject: more portability on shell scripts i haven't really tested this, but i expect that someone that knows the code (and cares about it) to do the last portability changes. i don't think that this scripts are going to run with a shell different than bash anyway... --- examples/data/uzbl/scripts/clipboard.sh | 9 ++-- examples/data/uzbl/scripts/cookies.sh | 53 +++++++++++++--------- examples/data/uzbl/scripts/history.sh | 3 +- examples/data/uzbl/scripts/insert_bookmark.sh | 5 +- .../data/uzbl/scripts/load_url_from_history.sh | 9 ++-- examples/data/uzbl/scripts/session.sh | 4 +- examples/data/uzbl/scripts/yank.sh | 9 ++-- 7 files changed, 57 insertions(+), 35 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh index c64b65c..85ccbc6 100755 --- a/examples/data/uzbl/scripts/clipboard.sh +++ b/examples/data/uzbl/scripts/clipboard.sh @@ -1,14 +1,17 @@ -#!/bin/bash +#!/bin/sh # with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard. +clip=xclip + fifo="$5" action="$1" url="$7" -selection=$(xclip -o) + +selection=`$clip -o` case $action in - "yank" ) echo -n "$url" | xclip;; + "yank" ) echo -n "$url" | eval "$clip";; "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh index 56b9c79..03ddef8 100755 --- a/examples/data/uzbl/scripts/cookies.sh +++ b/examples/data/uzbl/scripts/cookies.sh @@ -1,4 +1,6 @@ -#!/bin/bash +#!/bin/sh + +set -n; # THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! @@ -24,10 +26,10 @@ # http://kb.mozillazine.org/Cookies.txt # don't always append cookies, sometimes we need to overwrite -cookie_config=${XDG_CONFIG_HOME:-$HOME/.config}/uzbl/cookies -[ -z "$cookie_config" ] && exit 1 -[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/ ] && cookie_data=${XDG_DATA_HOME:-$home/.local/share}/uzbl/cookies.txt || exit 1 - +cookie_config=${XDG_CONFIG_HOME:-${HOME}/.config}/uzbl/cookies +[ "x$cookie_config" = x ] && exit 1 +[ -d "${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/" ] &&\ +cookie_data=${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/cookies.txt || exit 1 notifier= #notifier=notify-send @@ -60,24 +62,24 @@ field_name= field_value= field_exp='end_session' -function notify () { +notify() { [ -n "$notifier" ] && $notifier "$@" } # FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET -function parse_cookie () { +parse_cookie() { IFS=$';' first_pair=1 for pair in $cookie do - if [ "$first_pair" == 1 ] + if [ "x$first_pair" = x1 ] then field_name=${pair%%=*} field_value=${pair#*=} first_pair=0 else - read -r pair <<< "$pair" #strip leading/trailing wite space + echo "$pair" | read -r pair #strip leading/trailing wite space key=${pair%%=*} val=${pair#*=} [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` @@ -89,7 +91,7 @@ function parse_cookie () { } # match cookies in cookies.txt against hostname and path -function get_cookie () { +get_cookie() { path_esc=${path//\//\\/} search="^[^\t]*$host\t[^\t]*\t$path_esc" cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` @@ -99,13 +101,15 @@ function get_cookie () { false else notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" - read domain alow_read_other_subdomains path http_required expiration name value <<< "$cookie" + echo "$cookie" | \ + read domain alow_read_other_subdomains path http_required expiration name \ + value; cookie="$name=$value" true fi } -function save_cookie () { +save_cookie() { if parse_cookie then data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" @@ -116,8 +120,8 @@ function save_cookie () { fi } -[ $action == PUT ] && save_cookie -[ $action == GET ] && get_cookie && echo "$cookie" +[ "x$action" = xPUT ] && save_cookie +[ "x$action" = xGET ] && get_cookie && echo "$cookie" exit @@ -125,25 +129,32 @@ exit # TODO: implement this later. # $1 = section (TRUSTED or DENY) # $2 =url -function match () { +match() { sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" } -function fetch_cookie () { +fetch_cookie() { cookie=`cat $cookie_data` } -function store_cookie () { +store_cookie() { echo $cookie > $cookie_data } if match TRUSTED $host then - [ $action == PUT ] && store_cookie $host - [ $action == GET ] && fetch_cookie && echo "$cookie" + [ "x$action" = xPUT ] && store_cookie $host + [ "x$action" = xGET ] && fetch_cookie && echo "$cookie" elif ! match DENY $host then - [ $action == PUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host - [ $action == GET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie + [ "x$action" = xPUT ] && \ + cookie=`zenity --entry --title 'Uzbl Cookie handler' \ + --text "Accept this cookie from $host ?" --entry-text="$cookie"` \ + && store_cookie $host + + [ "x$action" = xGET ] && fetch_cookie \ + && cookie=`zenity --entry --title 'Uzbl Cookie handler' \ + --text "Submit this cookie to $host ?" --entry-text="$cookie"` \ + && echo $cookie fi exit 0 diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh index ccc6b40..d726f9c 100755 --- a/examples/data/uzbl/scripts/history.sh +++ b/examples/data/uzbl/scripts/history.sh @@ -1,5 +1,6 @@ -#!/bin/bash +#!/bin/sh #TODO: strip 'http://' part + file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history [ -d `dirname $file` ] || exit 1 echo "$8 $6 $7" >> $file diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh index 23c0d31..e04e6d4 100755 --- a/examples/data/uzbl/scripts/insert_bookmark.sh +++ b/examples/data/uzbl/scripts/insert_bookmark.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1 file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks @@ -6,7 +6,8 @@ file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks which zenity &>/dev/null || exit 2 entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` -url=`awk '{print $1}' <<< $entry` +url=`echo $entry | awk '{print $1}'` + # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags echo "$entry" >/dev/null #for some reason we need this.. don't ask me why echo -e "$entry" >> $file diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh index 57d634a..f207837 100755 --- a/examples/data/uzbl/scripts/load_url_from_history.sh +++ b/examples/data/uzbl/scripts/load_url_from_history.sh @@ -1,11 +1,12 @@ -#!/bin/bash +#!/bin/sh + history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history [ -r "$history_file" ] || exit 1 # choose from all entries, sorted and uniqued # goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'; then DMENU="dmenu -i -xs -rs -l 10" # vertical patch # choose an item in reverse order, showing also the date and page titles @@ -14,7 +15,9 @@ then else DMENU="dmenu -i" # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" | sort -u) | $DMENU $COLORS` + current=`tail -n 1 $history_file | awk '{print $3}'`; + goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \ + | sort -u) | $DMENU $COLORS` fi [ -n "$goto" ] && echo "uri $goto" > $4 diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh index 4dbae55..4f1e045 100755 --- a/examples/data/uzbl/scripts/session.sh +++ b/examples/data/uzbl/scripts/session.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Very simple session manager for uzbl. When called with "endsession" as the # argument, it'll backup $sessionfile, look for fifos in $fifodir and @@ -26,7 +26,7 @@ fi case $act in "launch" ) - urls=$(cat $sessionfile) + urls=`cat $sessionfile` if [ "$urls." = "." ]; then $UZBL else diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh index ee140c7..ddd0a4b 100755 --- a/examples/data/uzbl/scripts/yank.sh +++ b/examples/data/uzbl/scripts/yank.sh @@ -1,3 +1,4 @@ +#!/bin/sh # use this script to pipe any variable to xclip, so you have it in your clipboard # in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) # make the 2nd argument one of : primary, secondary, clipboard. @@ -5,8 +6,10 @@ # bind yurl = spawn ./examples/scripts/yank.sh 6 primary # bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard +clip=xclip + which xclip &>/dev/null || exit 1 -[ "$9" == primary -o "$9" == secondary -o "$9" == clipboard ] || exit 2 +[ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2 -echo echo -n "${!8}" '|' xclip -selection $9 -echo -n "${!8}" | xclip -selection $9 +echo "echo -n '${8}' | $clip -selection $9" +echo -n "'${8}' | $clip -selection $9" -- cgit v1.2.3 From f6fd0e88b1f18ae22c2160552a97b6a1f7890549 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 03:40:28 +0800 Subject: uzbl_tabbed.py re-write. Re-written the uzbl_tabbed.py script to use a fifo control interface and inherit configuration options from the users uzbl configuration file (if it exists). --- examples/data/uzbl/scripts/uzbl_tabbed.py | 764 ++++++++++++++++++++++++++++-- 1 file changed, 737 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 4c3a934..d10105b 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,41 +1,751 @@ #!/usr/bin/python -import string, pygtk, gtk, sys, subprocess +# Uzbl tabbing wrapper using a fifo socket interface +# Copywrite (c) 2009, Tom Adams +# Copywrite (c) 2009, quigybo +# Copywrite (c) 2009, Mason Larobina +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Author(s): +# Tom Adams +# Wrote the original uzbl_tabbed.py as a proof of concept. +# +# quigybo +# Made signifigant headway on the uzbl_tabbing.py script on the +# uzbl wiki +# +# Mason Larobina +# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface +# and inherit configuration options from the user's uzbl config. +# +# Contributor(s): +# (None yet) + + +# Issues: +# - status_background colour is not honoured (reverts to gtk default). +# - new windows are not caught and opened in a new tab. +# - need an easier way to read a uzbl instances window title instead of +# spawning a shell to spawn uzblctrl to communicate to the uzbl +# instance via socket to dump the window title to then pipe it to +# the tabbing managers fifo socket. +# - probably missing some os.path.expandvars somewhere. + + +# Todo: +# - add command line options to use a different session file, not use a +# session file and or open a uri on starup. +# - ellipsize individual tab titles when the tab-list becomes over-crowded +# - add "<" & ">" arrows to tablist to indicate that only a subset of the +# currently open tabs are being displayed on the tablist. +# - probably missing some os.path.expandvars somewhere and other +# user-friendly.. things, this is still a very early version. +# - fix status_background issues & style tablist. +# - add the small tab-list display when both gtk tabs and text vim-like +# tablist are hidden (I.e. [ 1 2 3 4 5 ]) +# - check spelling. + + +import pygtk +import gtk +import subprocess +import os +import re +import time +import getopt +import pango +import select +import sys +import gobject + pygtk.require('2.0') -def new_tab(nothing): - socket = gtk.Socket() - socket.show() - notebook.append_page(socket, gtk.Label('title goes here')) - sid = socket.get_id() - subprocess.call(['sh', '-c', 'uzbl -s %s &'%sid]) +def error(msg): + sys.stderr.write("%s\n"%msg) + +if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: + data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') + +else: + data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + +# === Default Configuration ==================================================== + +# Location of your uzbl configuration file. +uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') + +# All of these settings can be inherited from your uzbl config file. +config = {'show_tabs': True, + 'show_gtk_tabs': False, + 'switch_to_new_tabs': True, + 'save_session': True, + 'fifo_dir': '/tmp', + 'icon_path': os.path.join(data_dir, 'uzbl.png'), + 'session_file': os.path.join(data_dir, 'session'), + 'tab_colours': 'foreground = "#000000"', + 'selected_tab': 'foreground = "#000000" background="#bbbbbb"', + 'window_size': "800,800", + 'monospace_size': 10, + 'bind_new_tab': 'gn', + 'bind_tab_from_clipboard': 'gY', + 'bind_close_tab': 'gC', + 'bind_next_tab': 'gt', + 'bind_prev_tab': 'gT', + 'bind_goto_tab': 'gi_', + 'bind_goto_first': 'g<', + 'bind_goto_last':'g>'} + +# === End Configuration ======================================================= + +def readconfig(uzbl_config, config): + '''Loads relevant config from the users uzbl config file into the global + config dictionary.''' + + if not os.path.exists(uzbl_config): + error("Unable to load config %r" % uzbl_config) + return None + + # Define parsing regular expressions + isint = re.compile("^[0-9]+$").match + findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ + re.MULTILINE).findall + + h = open(os.path.expandvars(uzbl_config), 'r') + rawconfig = h.read() + h.close() + + for (key, value) in findsets(rawconfig): + key = key.strip() + if key not in config.keys(): continue + if isint(value): value = int(value) + config[key] = value + + +def rmkdir(path): + '''Recursively make directories. + I.e. `mkdir -p /some/nonexistant/path/`''' + + path, sep = os.path.realpath(path), os.path.sep + dirs = path.split(sep) + for i in range(2,len(dirs)+1): + dir = os.path.join(sep,sep.join(dirs[:i])) + if not os.path.exists(dir): + os.mkdir(dir) + + +def counter(): + '''To infinity and beyond!''' + + i = 0 + while True: + i += 1 + yield i + + +class UzblTabbed: + '''A tabbed version of uzbl using gtk.Notebook''' + + TIMEOUT = 100 # Millisecond interval between timeouts + + class UzblInstance: + '''Uzbl instance meta-data/meta-action object.''' + + def __init__(self, parent, socket, fifo, pid, url='', switch=True): + self.parent = parent + self.socket = socket # the gtk socket + self.fifo = fifo + self.pid = pid + self.title = "New tab" + self.url = url + self.timers = {} + self._lastprobe = 0 + self._switch_on_config = switch + self._outgoing = [] + self._configured = False + + # When notebook tab deleted the kill switch is raised. + self._kill = False + + # Queue binds for uzbl child + self.parent.config_uzbl(self) + + + def flush(self, timer_call=False): + '''Flush messages from the queue.''' + + if self._kill: + error("Flush called on dead page.") + return False + + if os.path.exists(self.fifo): + h = open(self.fifo, 'w') + while len(self._outgoing): + msg = self._outgoing.pop(0) + h.write("%s\n" % msg) + h.close() + + elif not timer_call and self._configured: + # TODO: I dont know what to do here. A previously thought + # alright uzbl client fifo socket has now gone missing. + # I think this should be fatal (at least for the page in + # question). I'll wait until this error appears in the wild. + error("Error: fifo %r lost in action." % self.fifo) + + if not len(self._outgoing) and timer_call: + self._configured = True + + if timer_call in self.timers.keys(): + gobject.source_remove(self.timers[timer_call]) + del self.timers[timer_call] + + if self._switch_on_config: + notebook = list(self.parent.notebook) + try: + tabid = notebook.index(self.socket) + self.parent.goto_tab(tabid) + + except ValueError: + pass + + return len(self._outgoing) + + + def probe(self): + '''Probes the client for information about its self.''' + + # Ugly way of getting the socket path. Screwed if fifo is in any + # other part of the fifo socket path. + + socket = 'socket'.join(self.fifo.split('fifo')) + + # I feel so dirty + subcmd = 'print title %s @@' % self.pid + cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ + self.parent.fifo_socket) + + subprocess.Popen([cmd], shell=True) + + self._lastprobe = time.time() + + + def send(self, msg): + '''Child fifo write function.''' + + self._outgoing.append(msg) + # Flush messages from the queue if able. + return self.flush() + + + def __init__(self): + '''Create tablist, window and notebook.''' + + self.pages = {} + self._pidcounter = counter() + self.next_pid = self._pidcounter.next + self._watchers = {} + self._timers = {} + self._buffer = "" + + # Create main window + self.window = gtk.Window() + try: + window_size = map(int, config['window_size'].split(',')) + self.window.set_default_size(*window_size) + + except: + error("Invalid value for default_size in config file.") + + self.window.set_title("Uzbl Browser") + self.window.set_border_width(0) + + # Set main window icon + icon_path = config['icon_path'] + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + else: + icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + # Attach main window event handlers + self.window.connect("delete-event", self.quit) + + # Create tab list + if config['show_tabs']: + vbox = gtk.VBox() + self.window.add(vbox) + + self.tablist = gtk.Label() + self.tablist.set_use_markup(True) + self.tablist.set_justify(gtk.JUSTIFY_LEFT) + self.tablist.set_line_wrap(False) + self.tablist.set_selectable(False) + self.tablist.set_padding(2,2) + self.tablist.set_alignment(0,0) + self.tablist.set_ellipsize(pango.ELLIPSIZE_END) + self.tablist.set_text(" ") + self.tablist.show() + vbox.pack_start(self.tablist, False, False, 0) + + # Create notebook + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(config['show_gtk_tabs']) + self.notebook.set_show_border(False) + self.notebook.connect("page-removed", self.tab_closed) + self.notebook.connect("switch-page", self.tab_changed) + self.notebook.show() + if config['show_tabs']: + vbox.pack_end(self.notebook, True, True, 0) + vbox.show() + else: + self.window.add(self.notebook) + + self.window.show() + self.wid = self.notebook.window.xid + # Fifo socket definition + self._refindfifos = re.compile('^uzbl_fifo_%s_[0-9]+$' % self.wid) + fifo_filename = 'uzbltabbed_%d' % os.getpid() + self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + + self._watchers = {} + self._buffer = "" + self._create_fifo_socket(self.fifo_socket) + self._setup_fifo_watcher(self.fifo_socket) + + + def run(self): + + # Update tablist timer + timer = "update-tablist" + timerid = gobject.timeout_add(500, self.update_tablist,timer) + self._timers[timer] = timerid + + # Due to the hackish way in which the window titles are read + # too many window will cause the application to slow down insanely + timer = "probe-clients" + timerid = gobject.timeout_add(1000, self.probe_clients, timer) + self._timers[timer] = timerid + + gtk.main() + + + def _find_fifos(self, fifo_dir): + '''Find all child fifo sockets in fifo_dir.''' + + dirlist = '\n'.join(os.listdir(fifo_dir)) + allfifos = self._refindfifos.findall(dirlist) + return sorted(allfifos) + + + def _create_fifo_socket(self, fifo_socket): + '''Create interprocess communication fifo socket.''' + + if os.path.exists(fifo_socket): + if not os.access(fifo_socket, os.F_OK | os.R_OK | os.W_OK): + os.mkfifo(fifo_socket) + + else: + basedir = os.path.dirname(self.fifo_socket) + if not os.path.exists(basedir): + rmkdir(basedir) + os.mkfifo(self.fifo_socket) + + print "Listening on %s" % self.fifo_socket + + + def _setup_fifo_watcher(self, fifo_socket, fd=None): + '''Open fifo socket fd and setup gobject IO_IN & IO_HUP watchers. + Also log the creation of a fd and store the the internal + self._watchers dictionary along with the filename of the fd.''' + + #TODO: Convert current self._watcher dict manipulation to the better + # IMHO self._timers handling by using "timer-keys" as the keys instead + # of the fifo fd's as keys. + + if fd: + os.close(fd) + if fd in self._watchers.keys(): + d = self._watchers[fd] + watchers = d['watchers'] + for watcher in list(watchers): + gobject.source_remove(watcher) + watchers.remove(watcher) + del self._watchers[fd] + + fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) + self._watchers[fd] = {'watchers': [], 'filename': fifo_socket} + + watcher = self._watchers[fd]['watchers'].append + watcher(gobject.io_add_watch(fd, gobject.IO_IN, self.read_fifo)) + watcher(gobject.io_add_watch(fd, gobject.IO_HUP, self.fifo_hangup)) + + + def probe_clients(self, timer_call): + '''Load balance probe all uzbl clients for up-to-date window titles + and uri's.''' + + p = self.pages + probetimes = [(s, p[s]._lastprobe) for s in p.keys()] + socket, lasttime = sorted(probetimes, key=lambda t: t[1])[0] + + if (time.time()-lasttime) > 5: + # Probe a uzbl instance at most once every 10 seconds + self.pages[socket].probe() + + return True + + + def fifo_hangup(self, fd, cb_condition): + '''Handle fifo socket hangups.''' + + # Close fd, re-open fifo_socket and watch. + self._setup_fifo_watcher(self.fifo_socket, fd) + + # And to kill any gobject event handlers calling this function: + return False + + + def read_fifo(self, fd, cb_condition): + '''Read from fifo socket and handle fifo socket hangups.''' + + self._buffer = os.read(fd, 1024) + temp = self._buffer.split("\n") + self._buffer = temp.pop() + + for cmd in [s.strip().split() for s in temp if len(s.strip())]: + try: + #print cmd + self.parse_command(cmd) + + except: + #raise + error("Invalid command: %s" % ' '.join(cmd)) + + 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. + # 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. + # url {pid} {document-location} + + # WARNING SOME OF THESE COMMANDS MIGHT NOT BE WORKING YET OR FAIL. + + if cmd[0] == "new": + if len(cmd) == 2: + self.new_tab(cmd[1]) + + else: + self.new_tab() + + elif cmd[0] == "newfromclip": + url = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + stdout=subprocess.PIPE).communicate()[0] + if url: + self.new_tab(url) + + elif cmd[0] == "close": + if len(cmd) == 2: + self.close_tab(int(cmd[1])) + + else: + self.close_tab() + + elif cmd[0] == "next": + if len(cmd) == 2: + self.next_tab(int(cmd[1])) + + else: + self.next_tab() + + elif cmd[0] == "prev": + if len(cmd) == 2: + self.prev_tab(int(cmd[1])) + + else: + self.prev_tab() + + elif cmd[0] == "goto": + self.goto_tab(int(cmd[1])) + + elif cmd[0] == "first": + self.goto_tab(0) + + elif cmd[0] == "last": + self.goto_tab(-1) + + elif cmd[0] in ["title", "url"]: + if len(cmd) > 2: + uzbl = self.get_uzbl_by_pid(int(cmd[1])) + if uzbl: + setattr(uzbl, cmd[0], ' '.join(cmd[2:])) + else: + error("Cannot find uzbl instance with pid %r" % int(cmd[1])) + else: + error("Unknown command: %s" % ' '.join(cmd)) + + + def get_uzbl_by_pid(self, pid): + '''Return uzbl instance by pid.''' + + for socket in self.pages.keys(): + if self.pages[socket].pid == pid: + return self.pages[socket] + return False + + + def new_tab(self,url='', switch=True): + '''Add a new tab to the notebook and start a new instance of uzbl. + Use the switch option to negate config['switch_to_new_tabs'] option + when you need to load multiple tabs at a time (I.e. like when + restoring a session from a file).''' + + pid = self.next_pid() + socket = gtk.Socket() + socket.show() + self.notebook.append_page(socket) + sid = socket.get_id() + + if url: + url = '--uri %s' % url + + fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) + fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + uzbl = self.UzblInstance(self, socket, fifo_socket, pid,\ + url=url, switch=switch) + self.pages[socket] = uzbl + cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, url) + subprocess.Popen([cmd], shell=True) + + # Add gobject timer to make sure the config is pushed when fifo socket + # has been created. + timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") + uzbl.timers['flush-initial-config'] = timerid + + + def config_uzbl(self, uzbl): + '''Send bind commands for tab new/close/next/prev to a uzbl + instance.''' + + binds = [] + bind_format = 'bind %s = sh "echo \\\"%s\\\" > \\\"%s\\\""' + bind = lambda key, action: binds.append(bind_format % (key, action, \ + self.fifo_socket)) + + # Keys are defined in the config section + # bind ( key , command back to fifo ) + bind(config['bind_new_tab'], 'new') + bind(config['bind_tab_from_clipboard'], 'newfromclip') + bind(config['bind_close_tab'], 'close') + bind(config['bind_next_tab'], 'next') + bind(config['bind_prev_tab'], 'prev') + bind(config['bind_goto_tab'], 'goto %s') + bind(config['bind_goto_first'], 'goto 0') + bind(config['bind_goto_last'], 'goto -1') + + uzbl.send("\n".join(binds)) + + + def goto_tab(self, n): + '''Goto tab n (supports negative indexing).''' + + notebook = list(self.notebook) + + try: + page = notebook[n] + i = notebook.index(page) + self.notebook.set_current_page(i) + + except IndexError: + pass + + + def next_tab(self, n=1): + '''Switch to next tab or n tabs right.''' + + if n >= 1: + numofpages = self.notebook.get_n_pages() + pagen = self.notebook.get_current_page() + n + self.notebook.set_current_page( pagen % numofpages ) + + + def prev_tab(self, n=1): + '''Switch to prev tab or n tabs left.''' + + if n >= 1: + numofpages = self.notebook.get_n_pages() + pagen = self.notebook.get_current_page() - n + while pagen < 0: + pagen += numofpages + self.notebook.set_current_page(pagen) + + + def close_tab(self, tabid=None): + '''Closes current tab. Supports negative indexing.''' + + if not tabid: + tabid = self.notebook.get_current_page() + + try: + socket = list(self.notebook)[tabid] + + except IndexError: + error("Invalid index. Cannot close tab.") + return False + + uzbl = self.pages[socket] + # Kill timers: + for timer in uzbl.timers.keys(): + error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + gobject.source_remove(uzbl.timers[timer]) + + uzbl._outgoing = [] + uzbl._kill = True + del self.pages[socket] + self.notebook.remove_page(tabid) + + + def tab_closed(self, notebook, socket, page_num): + '''Close the window if no tabs are left. Called by page-removed + signal.''' + + if socket in self.pages.keys(): + uzbl = self.pages[socket] + for timer in uzbl.timers.keys(): + error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + gobject.source_remove(uzbl.timers[timer]) + + uzbl._outgoing = [] + uzbl._kill = True + del self.pages[socket] + + if self.notebook.get_n_pages() == 0: + gtk.main_quit() + + + def tab_changed(self, notebook, page, page_num): + '''Refresh tab list. Called by switch-page signal.''' + + self.tablist.set_text(str(list(self.notebook))) + + self.update_tablist() + + + def update_tablist(self, timer_call=None): + '''Upate tablist status bar.''' + + pango = "" + + normal, selected = config['tab_colours'], config['selected_tab'] + tab_format = " [ %d %s ] " + + uzblkeys = self.pages.keys() + curpage = self.notebook.get_current_page() + + for index, socket in enumerate(self.notebook): + if socket not in uzblkeys: + #error("Theres a socket in the notebook that I have no uzbl "\ + # "record of.") + continue + uzbl = self.pages[socket] + + if index == curpage: + colours = selected + else: + colours = normal + + pango += tab_format % (colours, index, uzbl.title) + + self.tablist.set_markup(pango) + + return True + + + def quit(self, window, event): + '''Cleanup the application and quit. Called by delete-event signal.''' + for fd in self._watchers.keys(): + d = self._watchers[fd] + watchers = d['watchers'] + for watcher in list(watchers): + gobject.source_remove(watcher) + + for timer in self._timers.keys(): + gobject.source_remove(self._timers[timer]) -window = gtk.Window() -window.show() + if os.path.exists(self.fifo_socket): + os.unlink(self.fifo_socket) + print "Unlinked %s" % self.fifo_socket + + if config['save_session']: + session_file = os.path.expandvars(config['session_file']) + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + rmkdir(dirname) + h = open(session_file, 'w') + h.write('current = %s\n' % self.notebook.get_current_page()) + h.close() + for socket in list(self.notebook): + if socket not in self.pages.keys(): continue + uzbl = self.pages[socket] + uzbl.send('sh "echo $6 >> %s"' % session_file) + time.sleep(0.05) -vbox = gtk.VBox() -vbox.show() -window.add(vbox) + gtk.main_quit() -button = gtk.Button(stock=gtk.STOCK_ADD) -button.connect('clicked', new_tab) -button.show() -vbox.add(button) -notebook = gtk.Notebook() -vbox.add(notebook) -notebook.show() -window.connect("destroy", lambda w: gtk.main_quit()) -#def plugged_event(widget): -# print "I (", widget, ") have just had a plug inserted!" +if __name__ == "__main__": + + # Read from the uzbl config into the global config dictionary. + readconfig(uzbl_config, config) + + uzbl = UzblTabbed() + + if os.path.isfile(os.path.expandvars(config['session_file'])): + h = open(os.path.expandvars(config['session_file']),'r') + urls = [s.strip() for s in h.readlines()] + h.close() + current = 0 + for url in urls: + if url.startswith("current"): + current = int(url.split()[-1]) + else: + uzbl.new_tab(url, False) + else: + uzbl.new_tab() -#socket.connect("plug-added", plugged_event) -#socket.connect("plug-removed", plugged_event) + uzbl.run() -if len(sys.argv) == 2: - socket.add_id(long(sys.argv[1])) -gtk.main() \ No newline at end of file -- cgit v1.2.3 From 74e67a7aae087c0ab8429c0b0e9bacea8378c335 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 03:51:58 +0800 Subject: Removed redundant timeout variable (minor edit) --- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index d10105b..a0500e7 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -158,8 +158,6 @@ def counter(): class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' - TIMEOUT = 100 # Millisecond interval between timeouts - class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' -- cgit v1.2.3 From 5748f64c214b610eddb581ae0709b3d1257350d5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 14:04:27 +0800 Subject: Reduced tablist update delay. By calling self.update_tablist() manually after any notebook tab manipulation. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index a0500e7..6fc23d2 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -549,7 +549,9 @@ class UzblTabbed: # has been created. timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") uzbl.timers['flush-initial-config'] = timerid - + + self.update_tablist() + def config_uzbl(self, uzbl): '''Send bind commands for tab new/close/next/prev to a uzbl @@ -583,10 +585,12 @@ class UzblTabbed: page = notebook[n] i = notebook.index(page) self.notebook.set_current_page(i) - + except IndexError: pass + self.update_tablist() + def next_tab(self, n=1): '''Switch to next tab or n tabs right.''' @@ -596,6 +600,8 @@ class UzblTabbed: pagen = self.notebook.get_current_page() + n self.notebook.set_current_page( pagen % numofpages ) + self.update_tablist() + def prev_tab(self, n=1): '''Switch to prev tab or n tabs left.''' @@ -607,6 +613,8 @@ class UzblTabbed: pagen += numofpages self.notebook.set_current_page(pagen) + self.update_tablist() + def close_tab(self, tabid=None): '''Closes current tab. Supports negative indexing.''' @@ -632,6 +640,8 @@ class UzblTabbed: del self.pages[socket] self.notebook.remove_page(tabid) + self.update_tablist() + def tab_closed(self, notebook, socket, page_num): '''Close the window if no tabs are left. Called by page-removed @@ -650,12 +660,12 @@ class UzblTabbed: if self.notebook.get_n_pages() == 0: gtk.main_quit() + self.update_tablist() + def tab_changed(self, notebook, page, page_num): '''Refresh tab list. Called by switch-page signal.''' - self.tablist.set_text(str(list(self.notebook))) - self.update_tablist() -- cgit v1.2.3 From 1202432f4d336aff88ad5013413bf258fba68ff2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 14:15:34 +0800 Subject: Delete session file when empty. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 38 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 6fc23d2..0069859 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -658,7 +658,7 @@ class UzblTabbed: del self.pages[socket] if self.notebook.get_n_pages() == 0: - gtk.main_quit() + self.quit() self.update_tablist() @@ -699,7 +699,8 @@ class UzblTabbed: return True - def quit(self, window, event): + #def quit(self, window, event): + def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' for fd in self._watchers.keys(): @@ -717,21 +718,28 @@ class UzblTabbed: if config['save_session']: session_file = os.path.expandvars(config['session_file']) - if not os.path.isfile(session_file): - dirname = os.path.dirname(session_file) - rmkdir(dirname) - h = open(session_file, 'w') - h.write('current = %s\n' % self.notebook.get_current_page()) - h.close() - for socket in list(self.notebook): - if socket not in self.pages.keys(): continue - uzbl = self.pages[socket] - uzbl.send('sh "echo $6 >> %s"' % session_file) - time.sleep(0.05) - - gtk.main_quit() + if self.notebook.get_n_pages(): + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + if not os.path.isdir(dirname): + rmkdir(dirname) + + h = open(session_file, 'w') + h.write('current = %s\n' % self.notebook.get_current_page()) + h.close() + for socket in list(self.notebook): + if socket not in self.pages.keys(): continue + uzbl = self.pages[socket] + uzbl.send('sh "echo $6 >> %s"' % session_file) + time.sleep(0.05) + else: + # Notebook has no pages so delete session file if it exists. + # Its better to not exist than be blank IMO. + if os.path.isfile(session_file): + os.remove(session_file) + gtk.main_quit() if __name__ == "__main__": -- cgit v1.2.3 From eda9f14939e500b18a4c0601a625df440ef6e742 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 15:14:30 +0800 Subject: Style tablist text & update window title. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 0069859..60d2495 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -95,8 +95,10 @@ config = {'show_tabs': True, 'fifo_dir': '/tmp', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), - 'tab_colours': 'foreground = "#000000"', - 'selected_tab': 'foreground = "#000000" background="#bbbbbb"', + 'tab_colours': 'foreground = "#999"', + 'tab_text_colours': 'foreground = "#444"', + 'selected_tab': 'foreground = "#aaa" background="#303030"', + 'selected_tab_text': 'foreground = "green"', 'window_size': "800,800", 'monospace_size': 10, 'bind_new_tab': 'gn', @@ -292,7 +294,7 @@ class UzblTabbed: self.tablist.set_justify(gtk.JUSTIFY_LEFT) self.tablist.set_line_wrap(False) self.tablist.set_selectable(False) - self.tablist.set_padding(2,2) + self.tablist.set_padding(0,2) self.tablist.set_alignment(0,0) self.tablist.set_ellipsize(pango.ELLIPSIZE_END) self.tablist.set_text(" ") @@ -674,9 +676,13 @@ class UzblTabbed: pango = "" - normal, selected = config['tab_colours'], config['selected_tab'] - tab_format = " [ %d %s ] " + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + tab_format = " [ %d %s ] " + + title_format = "%s - Uzbl Browser" + uzblkeys = self.pages.keys() curpage = self.notebook.get_current_page() @@ -689,10 +695,12 @@ class UzblTabbed: if index == curpage: colours = selected + self.window.set_title(title_format % uzbl.title) + else: colours = normal - pango += tab_format % (colours, index, uzbl.title) + pango += tab_format % (colours[0], index, colours[1], uzbl.title) self.tablist.set_markup(pango) -- cgit v1.2.3 From 7d864e7411ca1660db85e284fb65b112bd2825ab Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 15:44:37 +0800 Subject: Fix spelling. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 60d2495..5fff98f 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,9 +1,9 @@ #!/usr/bin/python # Uzbl tabbing wrapper using a fifo socket interface -# Copywrite (c) 2009, Tom Adams -# Copywrite (c) 2009, quigybo -# Copywrite (c) 2009, Mason Larobina +# Copyrite (c) 2009, Tom Adams +# Copyrite (c) 2009, quigybo +# Copyrite (c) 2009, Mason Larobina # # 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 -- cgit v1.2.3 From d6d1485b3dc7e49f0c460062bf631c7f6e66228b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 18:40:39 +0800 Subject: Added static probe cmds to uzbl instance class --- examples/data/uzbl/scripts/uzbl_tabbed.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 5fff98f..26f9fc3 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -176,9 +176,18 @@ class UzblTabbed: self._outgoing = [] self._configured = False + # Probe commands + self._probeurl = 'sh \'echo "url %s $6" > "%s"\'' % (self.pid,\ + self.parent.fifo_socket) + + # As soon as the variable expansion bug is fixed in uzbl + # I can start using this command to fetch the winow title + self._probetitle = 'sh \'echo "title %s @window_title" > "%s"\'' \ + % (self.pid, self.parent.fifo_socket) + # When notebook tab deleted the kill switch is raised. self._kill = False - + # Queue binds for uzbl child self.parent.config_uzbl(self) @@ -228,19 +237,20 @@ class UzblTabbed: # Ugly way of getting the socket path. Screwed if fifo is in any # other part of the fifo socket path. - socket = 'socket'.join(self.fifo.split('fifo')) - - # I feel so dirty + # Hackish & wasteful way of getting the window title. subcmd = 'print title %s @@' % self.pid cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ self.parent.fifo_socket) - subprocess.Popen([cmd], shell=True) + self.send(self._probeurl) + + # Wont work yet. + #self.send(self._probetitle) self._lastprobe = time.time() - - + + def send(self, msg): '''Child fifo write function.''' @@ -508,7 +518,11 @@ class UzblTabbed: if len(cmd) > 2: uzbl = self.get_uzbl_by_pid(int(cmd[1])) if uzbl: - setattr(uzbl, cmd[0], ' '.join(cmd[2:])) + old = getattr(uzbl, cmd[0]) + new = ' '.join(cmd[2:]) + setattr(uzbl, cmd[0], new) + if old != new: + self.update_tablist() else: error("Cannot find uzbl instance with pid %r" % int(cmd[1])) else: -- cgit v1.2.3 From 858000db7ff7a2c84054e1b165b4613939a5d675 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:20:17 +0800 Subject: uzbl_config path now respects XDG_CONFIG_HOME --- examples/data/uzbl/scripts/uzbl_tabbed.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 26f9fc3..fa428b2 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -85,7 +85,10 @@ else: # === Default Configuration ==================================================== # Location of your uzbl configuration file. -uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') +if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: + uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') +else: + uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') # All of these settings can be inherited from your uzbl config file. config = {'show_tabs': True, -- cgit v1.2.3 From c138928fc694a611ab45e5ac65416e34a53c8a5b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:26:56 +0800 Subject: Added mxey to uzbl_tabbed contributors section. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index fa428b2..1dfd6b6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -32,7 +32,8 @@ # and inherit configuration options from the user's uzbl config. # # Contributor(s): -# (None yet) +# mxey +# uzbl_config path now honors XDG_CONFIG_HOME if it exists. # Issues: -- cgit v1.2.3 From af592bb6578c7e7ce5da3cb1b4905d56c011d581 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 19:32:35 +0800 Subject: Spelleng fix. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 1dfd6b6..485adcc 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,9 +1,9 @@ #!/usr/bin/python # Uzbl tabbing wrapper using a fifo socket interface -# Copyrite (c) 2009, Tom Adams -# Copyrite (c) 2009, quigybo -# Copyrite (c) 2009, Mason Larobina +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, quigybo +# Copyright (c) 2009, Mason Larobina # # 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 -- cgit v1.2.3 From 820826cde67d99812e22b02d70cbcd667da08b17 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 29 Jun 2009 20:42:10 +0800 Subject: Resolved status bar styling issue and added help text in file. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 57 +++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 485adcc..77f4bc5 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -36,8 +36,40 @@ # uzbl_config path now honors XDG_CONFIG_HOME if it exists. +# Configuration: +# Because this version of uzbl_tabbed is able to inherit options from your main +# uzbl configuration file you may wish to configure uzbl tabbed from there. +# Here is a list of configuration options that can be customised and some +# example values for each: +# +# set show_tabs = 1 +# set show_gtk_tabs = 0 +# set switch_to_new_tabs = 1 +# set save_session = 1 +# set status_background = #303030 +# set session_file = $HOME/.local/share/session +# set tab_colours = foreground = "#999" +# set tab_text_colours = foreground = "#444" +# set selected_tab = foreground = "#aaa" background="#303030" +# set selected_tab_text = foreground = "green" +# set window_size = 800,800 +# +# And the keybindings: +# +# set bind_new_tab = gn +# set bind_tab_from_clip = gY +# set bind_close_tab = gC +# set bind_next_tab = gt +# set bind_prev_tab = gT +# set bind_goto_tab = gi_ +# set bind_goto_first = g< +# set bind_goto_last = g> +# +# And uzbl_tabbed.py takes care of the actual binding of the commands via each +# instances fifo socket. + + # Issues: -# - status_background colour is not honoured (reverts to gtk default). # - new windows are not caught and opened in a new tab. # - need an easier way to read a uzbl instances window title instead of # spawning a shell to spawn uzblctrl to communicate to the uzbl @@ -99,14 +131,15 @@ config = {'show_tabs': True, 'fifo_dir': '/tmp', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), - 'tab_colours': 'foreground = "#999"', - 'tab_text_colours': 'foreground = "#444"', - 'selected_tab': 'foreground = "#aaa" background="#303030"', - 'selected_tab_text': 'foreground = "green"', + 'status_background': "#303030", + 'tab_colours': 'foreground = "#888"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff" background = "#303030"', + 'selected_tab_text': 'foreground = "#99FF66"', 'window_size': "800,800", 'monospace_size': 10, 'bind_new_tab': 'gn', - 'bind_tab_from_clipboard': 'gY', + 'bind_tab_from_clip': 'gY', 'bind_close_tab': 'gC', 'bind_next_tab': 'gt', 'bind_prev_tab': 'gT', @@ -302,18 +335,22 @@ class UzblTabbed: if config['show_tabs']: vbox = gtk.VBox() self.window.add(vbox) - + ebox = gtk.EventBox() self.tablist = gtk.Label() self.tablist.set_use_markup(True) self.tablist.set_justify(gtk.JUSTIFY_LEFT) self.tablist.set_line_wrap(False) self.tablist.set_selectable(False) - self.tablist.set_padding(0,2) + self.tablist.set_padding(2,2) self.tablist.set_alignment(0,0) self.tablist.set_ellipsize(pango.ELLIPSIZE_END) self.tablist.set_text(" ") self.tablist.show() - vbox.pack_start(self.tablist, False, False, 0) + ebox.add(self.tablist) + ebox.show() + bgcolor = gtk.gdk.color_parse(config['status_background']) + ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) + vbox.pack_start(ebox, False, False, 0) # Create notebook self.notebook = gtk.Notebook() @@ -585,7 +622,7 @@ class UzblTabbed: # Keys are defined in the config section # bind ( key , command back to fifo ) bind(config['bind_new_tab'], 'new') - bind(config['bind_tab_from_clipboard'], 'newfromclip') + bind(config['bind_tab_from_clip'], 'newfromclip') bind(config['bind_close_tab'], 'close') bind(config['bind_next_tab'], 'next') bind(config['bind_prev_tab'], 'prev') -- cgit v1.2.3 From ac6c7b6946b5bd492f7ec5497ed1de09c8127428 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 00:52:21 +0800 Subject: uzbl_tabbed refactor, huge internal changes. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 507 ++++++++++++++++-------------- 1 file changed, 269 insertions(+), 238 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 77f4bc5..9ecfb09 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -46,6 +46,7 @@ # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 +# set new_tab_title = New tab # set status_background = #303030 # set session_file = $HOME/.local/share/session # set tab_colours = foreground = "#999" @@ -103,6 +104,7 @@ import pango import select import sys import gobject +import socket pygtk.require('2.0') @@ -129,6 +131,8 @@ config = {'show_tabs': True, 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', + 'socket_dir': '/tmp', + 'new_tab_title': 'New tab', 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), 'status_background': "#303030", @@ -197,115 +201,126 @@ def counter(): class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' - class UzblInstance: + class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' - def __init__(self, parent, socket, fifo, pid, url='', switch=True): + def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ + uri, switch): + self.parent = parent - self.socket = socket # the gtk socket - self.fifo = fifo + self.tab = tab + self.fifo_socket = fifo_socket + self.socket_file = socket_file self.pid = pid - self.title = "New tab" - self.url = url + self.title = config['new_tab_title'] + self.uri = uri self.timers = {} self._lastprobe = 0 - self._switch_on_config = switch - self._outgoing = [] - self._configured = False - - # Probe commands - self._probeurl = 'sh \'echo "url %s $6" > "%s"\'' % (self.pid,\ - self.parent.fifo_socket) - - # As soon as the variable expansion bug is fixed in uzbl - # I can start using this command to fetch the winow title - self._probetitle = 'sh \'echo "title %s @window_title" > "%s"\'' \ - % (self.pid, self.parent.fifo_socket) - - # When notebook tab deleted the kill switch is raised. + self._fifoout = [] + self._socketout = [] + self._socket = None + self._buffer = "" + # Switch to tab after connection + self._switch = switch + # fifo/socket files exists and socket connected. + self._connected = False + # The kill switch self._kill = False + + # Gen probe commands string + probes = [] + probe = probes.append + probe('print uri %d @uri' % self.pid) + probe('print title %d @@' % self.pid) + self._probecmds = '\n'.join(probes) - # Queue binds for uzbl child + # Enqueue keybinding config for child uzbl instance self.parent.config_uzbl(self) def flush(self, timer_call=False): - '''Flush messages from the queue.''' + '''Flush messages from the socket-out and fifo-out queues.''' if self._kill: - error("Flush called on dead page.") - return False + if self._socket: + self._socket.close() + self._socket = None - if os.path.exists(self.fifo): - h = open(self.fifo, 'w') - while len(self._outgoing): - msg = self._outgoing.pop(0) - h.write("%s\n" % msg) - h.close() + error("Flush called on dead tab.") + return False - elif not timer_call and self._configured: - # TODO: I dont know what to do here. A previously thought - # alright uzbl client fifo socket has now gone missing. - # I think this should be fatal (at least for the page in - # question). I'll wait until this error appears in the wild. - error("Error: fifo %r lost in action." % self.fifo) + if len(self._fifoout): + if os.path.exists(self.fifo_socket): + h = open(self.fifo_socket, 'w') + while len(self._fifoout): + msg = self._fifoout.pop(0) + h.write("%s\n"%msg) + h.close() - if not len(self._outgoing) and timer_call: - self._configured = True - - if timer_call in self.timers.keys(): - gobject.source_remove(self.timers[timer_call]) - del self.timers[timer_call] - - if self._switch_on_config: - notebook = list(self.parent.notebook) - try: - tabid = notebook.index(self.socket) + if len(self._socketout): + if not self._socket and os.path.exists(self.socket_file): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.socket_file) + self._socket = sock + + if self._socket: + while len(self._socketout): + msg = self._socketout.pop(0) + self._socket.send("%s\n"%msg) + + if not self._connected and timer_call: + if not len(self._fifoout + self._socketout): + self._connected = True + + if timer_call in self.timers.keys(): + gobject.source_remove(self.timers[timer_call]) + del self.timers[timer_call] + + if self._switch: + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) self.parent.goto_tab(tabid) - - except ValueError: - pass - return len(self._outgoing) + return len(self._fifoout + self._socketout) def probe(self): '''Probes the client for information about its self.''' - # Ugly way of getting the socket path. Screwed if fifo is in any - # other part of the fifo socket path. - socket = 'socket'.join(self.fifo.split('fifo')) - # Hackish & wasteful way of getting the window title. - subcmd = 'print title %s @@' % self.pid - cmd = 'uzblctrl -s "%s" -c "%s" > "%s" &' % (socket, subcmd, \ - self.parent.fifo_socket) - subprocess.Popen([cmd], shell=True) - self.send(self._probeurl) - - # Wont work yet. - #self.send(self._probetitle) - - self._lastprobe = time.time() + if self._connected: + self.send(self._probecmds) + self._lastprobe = time.time() - def send(self, msg): + def write(self, msg): '''Child fifo write function.''' - self._outgoing.append(msg) + self._fifoout.append(msg) # Flush messages from the queue if able. return self.flush() + def send(self, msg): + '''Child socket send function.''' + + self._socketout.append(msg) + # Flush messages from queue if able. + return self.flush() + + def __init__(self): '''Create tablist, window and notebook.''' - self.pages = {} - self._pidcounter = counter() - self.next_pid = self._pidcounter.next - self._watchers = {} + self._fifos = {} self._timers = {} self._buffer = "" - + + # Holds metadata on the uzbl childen open. + self.tabs = {} + + # Generates a unique id for uzbl socket filenames. + self.next_pid = counter().next + # Create main window self.window = gtk.Window() try: @@ -367,41 +382,14 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Fifo socket definition - self._refindfifos = re.compile('^uzbl_fifo_%s_[0-9]+$' % self.wid) + + # Create the uzbl_tabbed fifo fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - - self._watchers = {} - self._buffer = "" self._create_fifo_socket(self.fifo_socket) self._setup_fifo_watcher(self.fifo_socket) - def run(self): - - # Update tablist timer - timer = "update-tablist" - timerid = gobject.timeout_add(500, self.update_tablist,timer) - self._timers[timer] = timerid - - # Due to the hackish way in which the window titles are read - # too many window will cause the application to slow down insanely - timer = "probe-clients" - timerid = gobject.timeout_add(1000, self.probe_clients, timer) - self._timers[timer] = timerid - - gtk.main() - - - def _find_fifos(self, fifo_dir): - '''Find all child fifo sockets in fifo_dir.''' - - dirlist = '\n'.join(os.listdir(fifo_dir)) - allfifos = self._refindfifos.findall(dirlist) - return sorted(allfifos) - - def _create_fifo_socket(self, fifo_socket): '''Create interprocess communication fifo socket.''' @@ -418,76 +406,113 @@ class UzblTabbed: print "Listening on %s" % self.fifo_socket - def _setup_fifo_watcher(self, fifo_socket, fd=None): + def _setup_fifo_watcher(self, fifo_socket): '''Open fifo socket fd and setup gobject IO_IN & IO_HUP watchers. Also log the creation of a fd and store the the internal self._watchers dictionary along with the filename of the fd.''' - - #TODO: Convert current self._watcher dict manipulation to the better - # IMHO self._timers handling by using "timer-keys" as the keys instead - # of the fifo fd's as keys. - if fd: + if fifo_socket in self._fifos.keys(): + fd, watchers = self._fifos[fifo_socket] os.close(fd) - if fd in self._watchers.keys(): - d = self._watchers[fd] - watchers = d['watchers'] - for watcher in list(watchers): - gobject.source_remove(watcher) - watchers.remove(watcher) - del self._watchers[fd] + for watcherid in watchers.keys(): + gobject.source_remove(watchers[watcherid]) + del watchers[watcherid] + + del self._fifos[fifo_socket] + # Re-open fifo and add listeners. fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) - self._watchers[fd] = {'watchers': [], 'filename': fifo_socket} - - watcher = self._watchers[fd]['watchers'].append - watcher(gobject.io_add_watch(fd, gobject.IO_IN, self.read_fifo)) - watcher(gobject.io_add_watch(fd, gobject.IO_HUP, self.fifo_hangup)) + watchers = {} + self._fifos[fifo_socket] = (fd, watchers) + watcher = lambda key, id: watchers.__setitem__(key, id) + + # Watch for incoming data. + gid = gobject.io_add_watch(fd, gobject.IO_IN, self.main_fifo_read) + watcher('main-fifo-read', gid) + + # Watch for fifo hangups. + gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) + watcher('main-fifo-hangup', gid) - def probe_clients(self, timer_call): - '''Load balance probe all uzbl clients for up-to-date window titles - and uri's.''' + def run(self): + '''UzblTabbed main function that calls the gtk loop.''' + + # Update tablist timer + #timer = "update-tablist" + #timerid = gobject.timeout_add(500, self.update_tablist,timer) + #self._timers[timer] = timerid - p = self.pages - probetimes = [(s, p[s]._lastprobe) for s in p.keys()] - socket, lasttime = sorted(probetimes, key=lambda t: t[1])[0] + # Probe clients every second for window titles and location + timer = "probe-clients" + timerid = gobject.timeout_add(1000, self.probe_clients, timer) + self._timers[timer] = timerid + + gtk.main() - if (time.time()-lasttime) > 5: - # Probe a uzbl instance at most once every 10 seconds - self.pages[socket].probe() + + def probe_clients(self, timer_call): + '''Probe all uzbl clients for up-to-date window titles and uri's.''' + + sockd = {} + + for tab in self.tabs.keys(): + uzbl = self.tabs[tab] + uzbl.probe() + if uzbl._socket: + sockd[uzbl._socket] = uzbl + + sockets = sockd.keys() + (reading, _, errors) = select.select(sockets, [], sockets, 0) + + for sock in reading: + uzbl = sockd[sock] + uzbl._buffer = sock.recv(1024) + temp = uzbl._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: + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise return True - def fifo_hangup(self, fd, cb_condition): - '''Handle fifo socket hangups.''' + def main_fifo_hangup(self, fd, cb_condition): + '''Handle main fifo socket hangups.''' # Close fd, re-open fifo_socket and watch. - self._setup_fifo_watcher(self.fifo_socket, fd) + self._setup_fifo_watcher(self.fifo_socket) # And to kill any gobject event handlers calling this function: return False - def read_fifo(self, fd, cb_condition): - '''Read from fifo socket and handle fifo socket hangups.''' + 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 [s.strip().split() for s in temp if len(s.strip())]: + for cmd in cmds: try: - #print cmd + print cmd self.parse_command(cmd) except: - #raise - error("Invalid command: %s" % ' '.join(cmd)) + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise return True + def parse_command(self, cmd): '''Parse instructions from uzbl child processes.''' @@ -508,9 +533,7 @@ class UzblTabbed: # goto last tab. # title {pid} {document-title} # updates tablist title. - # url {pid} {document-location} - - # WARNING SOME OF THESE COMMANDS MIGHT NOT BE WORKING YET OR FAIL. + # uri {pid} {document-location} if cmd[0] == "new": if len(cmd) == 2: @@ -520,10 +543,10 @@ class UzblTabbed: self.new_tab() elif cmd[0] == "newfromclip": - url = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ stdout=subprocess.PIPE).communicate()[0] - if url: - self.new_tab(url) + if uri: + self.new_tab(uri) elif cmd[0] == "close": if len(cmd) == 2: @@ -555,9 +578,9 @@ class UzblTabbed: elif cmd[0] == "last": self.goto_tab(-1) - elif cmd[0] in ["title", "url"]: + elif cmd[0] in ["title", "uri"]: if len(cmd) > 2: - uzbl = self.get_uzbl_by_pid(int(cmd[1])) + uzbl = self.get_tab_by_pid(int(cmd[1])) if uzbl: old = getattr(uzbl, cmd[0]) new = ' '.join(cmd[2:]) @@ -565,42 +588,45 @@ class UzblTabbed: if old != new: self.update_tablist() else: - error("Cannot find uzbl instance with pid %r" % int(cmd[1])) + error("parse_command: no uzbl with pid %r" % int(cmd[1])) else: - error("Unknown command: %s" % ' '.join(cmd)) + error("parse_command: unknown command %r" % ' '.join(cmd)) - def get_uzbl_by_pid(self, pid): + def get_tab_by_pid(self, pid): '''Return uzbl instance by pid.''' - for socket in self.pages.keys(): - if self.pages[socket].pid == pid: - return self.pages[socket] + for tab in self.tabs.keys(): + if self.tabs[tab].pid == pid: + return self.tabs[tab] + return False - def new_tab(self,url='', switch=True): + def new_tab(self, uri='', switch=True): '''Add a new tab to the notebook and start a new instance of uzbl. Use the switch option to negate config['switch_to_new_tabs'] option when you need to load multiple tabs at a time (I.e. like when restoring a session from a file).''' pid = self.next_pid() - socket = gtk.Socket() - socket.show() - self.notebook.append_page(socket) - sid = socket.get_id() - - if url: - url = '--uri %s' % url + tab = gtk.Socket() + tab.show() + self.notebook.append_page(tab) + sid = tab.get_id() fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - uzbl = self.UzblInstance(self, socket, fifo_socket, pid,\ - url=url, switch=switch) - self.pages[socket] = uzbl - cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, url) - subprocess.Popen([cmd], shell=True) + socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) + socket_file = os.path.join(config['socket_dir'], socket_filename) + + # Create meta-instance and spawn child + if uri: uri = '--uri %s' % uri + uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ + uri, switch) + self.tabs[tab] = uzbl + cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) + subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? # Add gobject timer to make sure the config is pushed when fifo socket # has been created. @@ -630,89 +656,91 @@ class UzblTabbed: bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') + # uzbl.send via socket or uzbl.write via fifo, I'll try send. uzbl.send("\n".join(binds)) def goto_tab(self, n): '''Goto tab n (supports negative indexing).''' - notebook = list(self.notebook) - + if 0 <= n < self.notebook.get_n_pages(): + self.notebook.set_current_page(n) + self.update_tablist() + return None + try: - page = notebook[n] - i = notebook.index(page) + tabs = list(self.notebook) + tab = tabs[n] + i = tabs.index(tab) self.notebook.set_current_page(i) + self.update_tablist() except IndexError: pass - self.update_tablist() - - def next_tab(self, n=1): + def next_tab(self, step=1): '''Switch to next tab or n tabs right.''' - if n >= 1: - numofpages = self.notebook.get_n_pages() - pagen = self.notebook.get_current_page() + n - self.notebook.set_current_page( pagen % numofpages ) - + if step < 1: + error("next_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() + step + self.notebook.set_current_page(tabn % ntabs) self.update_tablist() - def prev_tab(self, n=1): + def prev_tab(self, step=1): '''Switch to prev tab or n tabs left.''' - if n >= 1: - numofpages = self.notebook.get_n_pages() - pagen = self.notebook.get_current_page() - n - while pagen < 0: - pagen += numofpages - self.notebook.set_current_page(pagen) + if step < 1: + error("prev_tab: invalid step %r" % step) + return None + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() - step + while tabn < 0: tabn += ntabs + self.notebook.set_current_page(tabn) self.update_tablist() - def close_tab(self, tabid=None): + def close_tab(self, tabn=None): '''Closes current tab. Supports negative indexing.''' - if not tabid: - tabid = self.notebook.get_current_page() + if tabn is None: + tabn = self.notebook.get_current_page() try: - socket = list(self.notebook)[tabid] + tab = list(self.notebook)[tabn] + except IndexError: - error("Invalid index. Cannot close tab.") - return False - - uzbl = self.pages[socket] - # Kill timers: - for timer in uzbl.timers.keys(): - error("Removing timer %r %r" % (timer, uzbl.timers[timer])) - gobject.source_remove(uzbl.timers[timer]) + error("close_tab: invalid index %r" % tabn) + return None - uzbl._outgoing = [] - uzbl._kill = True - del self.pages[socket] - self.notebook.remove_page(tabid) + self.notebook.remove_page(tabn) - self.update_tablist() - - def tab_closed(self, notebook, socket, page_num): + def tab_closed(self, notebook, tab, page_num): '''Close the window if no tabs are left. Called by page-removed signal.''' - if socket in self.pages.keys(): - uzbl = self.pages[socket] + if tab in self.tabs.keys(): + uzbl = self.tabs[tab] for timer in uzbl.timers.keys(): - error("Removing timer %r %r" % (timer, uzbl.timers[timer])) + error("tab_closed: removing timer %r" % timer) gobject.source_remove(uzbl.timers[timer]) + + if uzbl._socket: + uzbl._socket.close() + uzbl._socket = None - uzbl._outgoing = [] + uzbl._fifoout = [] + uzbl._socketout = [] uzbl._kill = True - del self.pages[socket] + del self.tabs[tab] if self.notebook.get_n_pages() == 0: self.quit() @@ -726,7 +754,7 @@ class UzblTabbed: self.update_tablist() - def update_tablist(self, timer_call=None): + def update_tablist(self): '''Upate tablist status bar.''' pango = "" @@ -735,21 +763,17 @@ class UzblTabbed: selected = (config['selected_tab'], config['selected_tab_text']) tab_format = " [ %d %s ] " - title_format = "%s - Uzbl Browser" - uzblkeys = self.pages.keys() + tabs = self.tabs.keys() curpage = self.notebook.get_current_page() - for index, socket in enumerate(self.notebook): - if socket not in uzblkeys: - #error("Theres a socket in the notebook that I have no uzbl "\ - # "record of.") - continue - uzbl = self.pages[socket] + for index, tab in enumerate(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] if index == curpage: - colours = selected + colours = selected self.window.set_title(title_format % uzbl.title) else: @@ -762,23 +786,26 @@ class UzblTabbed: return True - #def quit(self, window, event): def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' + + for fifo_socket in self._fifos.keys(): + fd, watchers = self._fifos[fifo_socket] + os.close(fd) + for watcherid in watchers.keys(): + gobject.source_remove(watchers[watcherid]) + del watchers[watcherid] - for fd in self._watchers.keys(): - d = self._watchers[fd] - watchers = d['watchers'] - for watcher in list(watchers): - gobject.source_remove(watcher) + del self._fifos[fifo_socket] - for timer in self._timers.keys(): - gobject.source_remove(self._timers[timer]) + for timerid in self._timers.keys(): + gobject.source_remove(self._timers[timerid]) + del self._timers[timerid] if os.path.exists(self.fifo_socket): os.unlink(self.fifo_socket) print "Unlinked %s" % self.fifo_socket - + if config['save_session']: session_file = os.path.expandvars(config['session_file']) if self.notebook.get_n_pages(): @@ -789,16 +816,15 @@ class UzblTabbed: h = open(session_file, 'w') h.write('current = %s\n' % self.notebook.get_current_page()) + tabs = self.tabs.keys() + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + h.write("%s\n" % uzbl.uri) h.close() - for socket in list(self.notebook): - if socket not in self.pages.keys(): continue - uzbl = self.pages[socket] - uzbl.send('sh "echo $6 >> %s"' % session_file) - time.sleep(0.05) - + else: # Notebook has no pages so delete session file if it exists. - # Its better to not exist than be blank IMO. if os.path.isfile(session_file): os.remove(session_file) @@ -814,14 +840,19 @@ if __name__ == "__main__": if os.path.isfile(os.path.expandvars(config['session_file'])): h = open(os.path.expandvars(config['session_file']),'r') - urls = [s.strip() for s in h.readlines()] + lines = [line.strip() for line in h.readlines()] h.close() current = 0 - for url in urls: - if url.startswith("current"): - current = int(url.split()[-1]) + for line in lines: + if line.startswith("current"): + current = int(line.split()[-1]) + else: - uzbl.new_tab(url, False) + uzbl.new_tab(line, False) + + if not len(lines): + self.new_tab() + else: uzbl.new_tab() -- cgit v1.2.3 From f4fa6569bf24d8a94b9bfffc105d17ff46767cd5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 00:58:32 +0800 Subject: Update todo list. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 9ecfb09..31c9416 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -72,10 +72,6 @@ # Issues: # - new windows are not caught and opened in a new tab. -# - need an easier way to read a uzbl instances window title instead of -# spawning a shell to spawn uzblctrl to communicate to the uzbl -# instance via socket to dump the window title to then pipe it to -# the tabbing managers fifo socket. # - probably missing some os.path.expandvars somewhere. -- cgit v1.2.3 From 490abcb73515e667acef6a8c2d9135aa71413c1b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 30 Jun 2009 22:19:19 +0800 Subject: Added tablist style policy handler, updated author info & bug fixes. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 130 ++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 31c9416..932d4f6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -2,7 +2,7 @@ # Uzbl tabbing wrapper using a fifo socket interface # Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, quigybo +# Copyright (c) 2009, Chris van Dijk # Copyright (c) 2009, Mason Larobina # # This program is free software: you can redistribute it and/or modify @@ -23,8 +23,8 @@ # Tom Adams # Wrote the original uzbl_tabbed.py as a proof of concept. # -# quigybo -# Made signifigant headway on the uzbl_tabbing.py script on the +# Chris van Dijk (quigybo) +# Made signifigant headway on the old uzbl_tabbing.py script on the # uzbl wiki # # Mason Larobina @@ -42,7 +42,7 @@ # Here is a list of configuration options that can be customised and some # example values for each: # -# set show_tabs = 1 +# set show_tablist = 1 # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 @@ -83,7 +83,6 @@ # currently open tabs are being displayed on the tablist. # - probably missing some os.path.expandvars somewhere and other # user-friendly.. things, this is still a very early version. -# - fix status_background issues & style tablist. # - add the small tab-list display when both gtk tabs and text vim-like # tablist are hidden (I.e. [ 1 2 3 4 5 ]) # - check spelling. @@ -113,8 +112,10 @@ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: else: data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + # === Default Configuration ==================================================== + # Location of your uzbl configuration file. if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') @@ -122,22 +123,21 @@ else: uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') # All of these settings can be inherited from your uzbl config file. -config = {'show_tabs': True, +config = {'show_tablist': True, 'show_gtk_tabs': False, 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', 'socket_dir': '/tmp', 'new_tab_title': 'New tab', + 'tablist_top': True, 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), 'status_background': "#303030", - 'tab_colours': 'foreground = "#888"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff" background = "#303030"', - 'selected_tab_text': 'foreground = "#99FF66"', 'window_size': "800,800", 'monospace_size': 10, + + # Key binding options. 'bind_new_tab': 'gn', 'bind_tab_from_clip': 'gY', 'bind_close_tab': 'gC', @@ -145,10 +145,56 @@ config = {'show_tabs': True, 'bind_prev_tab': 'gT', 'bind_goto_tab': 'gi_', 'bind_goto_first': 'g<', - 'bind_goto_last':'g>'} + 'bind_goto_last':'g>', + + # Add custom tab style definitions to be used by the tab colour policy + # handler here. Because these are added to the config dictionary like + # any other uzbl_tabbed configuration option remember that they can + # be superseeded from your main uzbl config file. + 'tab_colours': 'foreground = "#888"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"',} + +# This is the tab style policy handler. Every time the tablist is updated +# this function is called to determine how to colourise that specific tab +# according the simple/complex rules as defined here. You may even wish to +# move this function into another python script and import it using: +# from mycustomtabbingconfig import colour_selector +# Remember to rename, delete or comment out this function if you do that. + +def colour_selector(tabindex, currentpage, uzbl): + '''Tablist styling policy handler. This function must return a tuple of + the form (tab style, text style).''' + + # Just as an example: + # if 'error' in uzbl.title: + # if tabindex == currentpage: + # return ('foreground="#fff"', 'foreground="red"') + # return ('foreground="#888"', 'foreground="red"') + + # Style tabs to indicate connected via https. + if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): + if tabindex == currentpage: + return (config['selected_https'], config['selected_https_text']) + return (config['https_colours'], config['https_text_colours']) + + # Style to indicate selected. + if tabindex == currentpage: + return (config['selected_tab'], config['selected_tab_text']) + + # Default tab style. + return (config['tab_colours'], config['tab_text_colours']) + # === End Configuration ======================================================= + def readconfig(uzbl_config, config): '''Loads relevant config from the users uzbl config file into the global config dictionary.''' @@ -158,7 +204,7 @@ def readconfig(uzbl_config, config): return None # Define parsing regular expressions - isint = re.compile("^[0-9]+$").match + isint = re.compile("^(\-|)[0-9]+$").match findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ re.MULTILINE).findall @@ -167,7 +213,7 @@ def readconfig(uzbl_config, config): h.close() for (key, value) in findsets(rawconfig): - key = key.strip() + key, value = key.strip(), value.strip() if key not in config.keys(): continue if isint(value): value = int(value) config[key] = value @@ -343,7 +389,7 @@ class UzblTabbed: self.window.connect("delete-event", self.quit) # Create tab list - if config['show_tabs']: + if config['show_tablist']: vbox = gtk.VBox() self.window.add(vbox) ebox = gtk.EventBox() @@ -361,7 +407,6 @@ class UzblTabbed: ebox.show() bgcolor = gtk.gdk.color_parse(config['status_background']) ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) - vbox.pack_start(ebox, False, False, 0) # Create notebook self.notebook = gtk.Notebook() @@ -370,9 +415,17 @@ class UzblTabbed: self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) self.notebook.show() - if config['show_tabs']: - vbox.pack_end(self.notebook, True, True, 0) + if config['show_tablist']: + if config['tablist_top']: + vbox.pack_start(ebox, False, False, 0) + vbox.pack_end(self.notebook, True, True, 0) + + else: + vbox.pack_start(self.notebook, True, True, 0) + vbox.pack_end(ebox, False, False, 0) + vbox.show() + else: self.window.add(self.notebook) @@ -469,7 +522,7 @@ class UzblTabbed: cmds = [s.strip().split() for s in temp if len(s.strip())] for cmd in cmds: try: - print cmd + #print cmd self.parse_command(cmd) except: @@ -499,7 +552,7 @@ class UzblTabbed: for cmd in cmds: try: - print cmd + #print cmd self.parse_command(cmd) except: @@ -752,32 +805,43 @@ class UzblTabbed: def update_tablist(self): '''Upate tablist status bar.''' - - pango = "" - - normal = (config['tab_colours'], config['tab_text_colours']) - selected = (config['selected_tab'], config['selected_tab_text']) - - tab_format = " [ %d %s ] " - title_format = "%s - Uzbl Browser" + + show_tablist = config['show_tablist'] + show_gtk_tabs = config['show_gtk_tabs'] + if not show_tablist and not show_gtk_tabs: + return True tabs = self.tabs.keys() curpage = self.notebook.get_current_page() + title_format = "%s - Uzbl Browser" + + if show_tablist: + pango = "" + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + tab_format = " [ %d %s ] " + + if show_gtk_tabs: + gtk_tab_format = "%d %s" for index, tab in enumerate(self.notebook): if tab not in tabs: continue uzbl = self.tabs[tab] if index == curpage: - colours = selected self.window.set_title(title_format % uzbl.title) - else: - colours = normal - - pango += tab_format % (colours[0], index, colours[1], uzbl.title) + if show_gtk_tabs: + self.notebook.set_tab_label_text(tab, \ + gtk_tab_format % (index, uzbl.title)) - self.tablist.set_markup(pango) + if show_tablist: + style = colour_selector(index, curpage, uzbl) + (tabc, textc) = style + pango += tab_format % (tabc, index, textc, uzbl.title) + + if show_tablist: + self.tablist.set_markup(pango) return True -- cgit v1.2.3 From 80e271cabfc4b34a9883353e2d48344d6f33523b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 1 Jul 2009 00:32:02 +0800 Subject: Feature requests, gtk_title_pos tab_titles max_title_len --- examples/data/uzbl/scripts/uzbl_tabbed.py | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 932d4f6..019b235 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -46,6 +46,8 @@ # set show_gtk_tabs = 0 # set switch_to_new_tabs = 1 # set save_session = 1 +# set gtk_tab_pos = (left|bottom|top|right) +# set max_title_len = 50 # set new_tab_title = New tab # set status_background = #303030 # set session_file = $HOME/.local/share/session @@ -125,11 +127,14 @@ else: # All of these settings can be inherited from your uzbl config file. config = {'show_tablist': True, 'show_gtk_tabs': False, + 'gtk_tab_pos': "top", # top left bottom right 'switch_to_new_tabs': True, 'save_session': True, 'fifo_dir': '/tmp', + 'tab_titles': True, 'socket_dir': '/tmp', 'new_tab_title': 'New tab', + 'max_title_len': 50, 'tablist_top': True, 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), @@ -411,6 +416,13 @@ class UzblTabbed: # Create notebook self.notebook = gtk.Notebook() self.notebook.set_show_tabs(config['show_gtk_tabs']) + + # Set tab position + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} + if config['gtk_tab_pos'] in allposes.keys(): + self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + self.notebook.set_show_border(False) self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) @@ -808,18 +820,23 @@ class UzblTabbed: show_tablist = config['show_tablist'] show_gtk_tabs = config['show_gtk_tabs'] + tab_titles = config['tab_titles'] if not show_tablist and not show_gtk_tabs: return True tabs = self.tabs.keys() curpage = self.notebook.get_current_page() title_format = "%s - Uzbl Browser" + max_title_len = config['max_title_len'] if show_tablist: pango = "" normal = (config['tab_colours'], config['tab_text_colours']) selected = (config['selected_tab'], config['selected_tab_text']) - tab_format = " [ %d %s ] " + if tab_titles: + tab_format = " [ %d %s ] " + else: + tab_format = " [ %d ] " if show_gtk_tabs: gtk_tab_format = "%d %s" @@ -832,13 +849,20 @@ class UzblTabbed: self.window.set_title(title_format % uzbl.title) if show_gtk_tabs: - self.notebook.set_tab_label_text(tab, \ - gtk_tab_format % (index, uzbl.title)) + if tab_titles: + self.notebook.set_tab_label_text(tab, \ + gtk_tab_format % (index, uzbl.title[:max_title_len])) + else: + self.notebook.set_tab_label_text(tab, str(index)) if show_tablist: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style - pango += tab_format % (tabc, index, textc, uzbl.title) + if tab_titles: + pango += tab_format % (tabc, index, textc,\ + uzbl.title[:max_title_len]) + else: + pango += tab_format % (tabc, textc, index) if show_tablist: self.tablist.set_markup(pango) -- cgit v1.2.3 From 84d7728bf5da12cbda3da5c13887d5cf8d52c122 Mon Sep 17 00:00:00 2001 From: Sylvester Johansson Date: Tue, 30 Jun 2009 20:57:23 +0200 Subject: typos --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e7c03dc..a4a5f45 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -32,13 +32,13 @@ set font_size = 11 #set enable_spellcheck = 1 ## Private browsing -#set enbale_private = 0 +#set enable_private = 0 ## The URI of a stylesheet that is applied to every page #set stylesheet_uri = http://www.user.com/mystylelesheet.css ## enable/disable JavaScript -#set disbale_scripts = 1 +#set disable_scripts = 1 ## Whether text areas are resizable #set resizeable_text_areas = 1 -- cgit v1.2.3 From 439d787699e5eb5e49cb4fe4b7cdd4ed4fd80dee Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 1 Jul 2009 21:22:18 +0800 Subject: Missing os.path.expandvars functions & use markers for message termination --- examples/data/uzbl/scripts/uzbl_tabbed.py | 128 ++++++++++++++++++------------ 1 file changed, 79 insertions(+), 49 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 019b235..4e9e1fb 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -74,7 +74,7 @@ # Issues: # - new windows are not caught and opened in a new tab. -# - probably missing some os.path.expandvars somewhere. +# - when uzbl_tabbed.py crashes it takes all the children with it. # Todo: @@ -83,11 +83,11 @@ # - ellipsize individual tab titles when the tab-list becomes over-crowded # - add "<" & ">" arrows to tablist to indicate that only a subset of the # currently open tabs are being displayed on the tablist. -# - probably missing some os.path.expandvars somewhere and other -# user-friendly.. things, this is still a very early version. # - add the small tab-list display when both gtk tabs and text vim-like # tablist are hidden (I.e. [ 1 2 3 4 5 ]) # - check spelling. +# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into +# the collective. Resistance is futile! import pygtk @@ -102,69 +102,82 @@ import select import sys import gobject import socket +import random +import hashlib pygtk.require('2.0') def error(msg): sys.stderr.write("%s\n"%msg) + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# Location of your uzbl data directory. if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') - else: data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') - - -# === Default Configuration ==================================================== - +if not os.path.exists(data_dir): + error("Warning: uzbl data_dir does not exist: %r" % data_dir) # Location of your uzbl configuration file. if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') else: uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') +if not os.path.exists(uzbl_config): + error("Warning: Cannot locate your uzbl_config file %r" % uzbl_config) # All of these settings can be inherited from your uzbl config file. -config = {'show_tablist': True, - 'show_gtk_tabs': False, - 'gtk_tab_pos': "top", # top left bottom right - 'switch_to_new_tabs': True, - 'save_session': True, - 'fifo_dir': '/tmp', - 'tab_titles': True, - 'socket_dir': '/tmp', - 'new_tab_title': 'New tab', - 'max_title_len': 50, - 'tablist_top': True, - 'icon_path': os.path.join(data_dir, 'uzbl.png'), - 'session_file': os.path.join(data_dir, 'session'), - 'status_background': "#303030", - 'window_size': "800,800", - 'monospace_size': 10, +config = { + # Tab options + 'show_tablist': True, + 'show_gtk_tabs': False, + 'max_title_len': 50, + 'tablist_top': True, + 'tab_titles': True, + 'gtk_tab_pos': 'top', # (top|left|bottom|right) + 'new_tab_title': 'New tab', + 'switch_to_new_tabs': True, + + # uzbl options + 'save_session': True, + 'fifo_dir': '/tmp', + 'socket_dir': '/tmp', + 'icon_path': os.path.join(data_dir, 'uzbl.png'), + 'session_file': os.path.join(data_dir, 'session'), + 'status_background': "#303030", + 'window_size': "800,800", # in pixels + 'monospace_size': 10, - # Key binding options. - 'bind_new_tab': 'gn', - 'bind_tab_from_clip': 'gY', - 'bind_close_tab': 'gC', - 'bind_next_tab': 'gt', - 'bind_prev_tab': 'gT', - 'bind_goto_tab': 'gi_', - 'bind_goto_first': 'g<', - 'bind_goto_last':'g>', + # Key bindings. + 'bind_new_tab': 'gn', + 'bind_tab_from_clip': 'gY', + 'bind_close_tab': 'gC', + 'bind_next_tab': 'gt', + 'bind_prev_tab': 'gT', + 'bind_goto_tab': 'gi_', + 'bind_goto_first': 'g<', + 'bind_goto_last': 'g>', # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like # any other uzbl_tabbed configuration option remember that they can # be superseeded from your main uzbl config file. - 'tab_colours': 'foreground = "#888"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff"', - 'selected_tab_text': 'foreground = "green"', - 'tab_indicate_https': True, - 'https_colours': 'foreground = "#888"', - 'https_text_colours': 'foreground = "#9c8e2d"', - 'selected_https': 'foreground = "#fff"', - 'selected_https_text': 'foreground = "gold"',} + 'tab_colours': 'foreground = "#888" background = "#303030"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"', + + } # End of config dict. # This is the tab style policy handler. Every time the tablist is updated # this function is called to determine how to colourise that specific tab @@ -197,7 +210,9 @@ def colour_selector(tabindex, currentpage, uzbl): return (config['tab_colours'], config['tab_text_colours']) -# === End Configuration ======================================================= +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ def readconfig(uzbl_config, config): @@ -212,7 +227,7 @@ def readconfig(uzbl_config, config): isint = re.compile("^(\-|)[0-9]+$").match findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ re.MULTILINE).findall - + h = open(os.path.expandvars(uzbl_config), 'r') rawconfig = h.read() h.close() @@ -222,6 +237,11 @@ def readconfig(uzbl_config, config): if key not in config.keys(): continue if isint(value): value = int(value) config[key] = value + + # Ensure that config keys that relate to paths are expanded. + expand = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path'] + for key in expand: + config[key] = os.path.expandvars(config[key]) def rmkdir(path): @@ -245,6 +265,12 @@ def counter(): yield i +def gen_endmarker(): + '''Generates a random md5 for socket message-termination endmarkers.''' + + return hashlib.md5(str(random.random()*time.time())).hexdigest() + + class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' @@ -273,12 +299,16 @@ class UzblTabbed: self._connected = False # The kill switch self._kill = False - + + # Message termination endmarker. + self._marker = gen_endmarker() + # Gen probe commands string probes = [] probe = probes.append - probe('print uri %d @uri' % self.pid) - probe('print title %d @@' % self.pid) + probe('print uri %d @uri %s' % (self.pid, self._marker)) + probe('print title %d @@ %s' % (self.pid,\ + self._marker)) self._probecmds = '\n'.join(probes) # Enqueue keybinding config for child uzbl instance @@ -528,8 +558,8 @@ class UzblTabbed: for sock in reading: uzbl = sockd[sock] - uzbl._buffer = sock.recv(1024) - temp = uzbl._buffer.split("\n") + uzbl._buffer = sock.recv(1024).replace('\n',' ') + temp = uzbl._buffer.split(uzbl._marker) self._buffer = temp.pop() cmds = [s.strip().split() for s in temp if len(s.strip())] for cmd in cmds: -- cgit v1.2.3 From ea2f26a2c194fece493856b22a9c0ca145c3c6b5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 2 Jul 2009 23:01:21 +0800 Subject: Fix cookies.py for XDG_DATA_HOME users. --- examples/data/uzbl/scripts/cookies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index 4f80359..bf2d2e6 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -63,7 +63,7 @@ class FakeResponse: if __name__ == '__main__': if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: jar = cookielib.MozillaCookieJar(\ - os.path.join(os.environ['XDG_DATA_HOME'],'/uzbl/cookies.txt')) + os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')) else: jar = cookielib.MozillaCookieJar(\ os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) -- cgit v1.2.3 From dd78febd4d7f063bf42e5c80d852540a61ab1adf Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 3 Jul 2009 23:16:31 +0800 Subject: Bug fixes, added "open-tab-from-clipboard" binding --- examples/data/uzbl/scripts/uzbl_tabbed.py | 206 ++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 67 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 4e9e1fb..93592da 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -75,6 +75,10 @@ # Issues: # - new windows are not caught and opened in a new tab. # - when uzbl_tabbed.py crashes it takes all the children with it. +# - when a new tab is opened when using gtk tabs the tab button itself +# grabs focus from its child for a few seconds. +# - when switch_to_new_tabs is not selected the notebook page is +# maintained but the new window grabs focus (try as I might to stop it). # Todo: @@ -134,34 +138,39 @@ if not os.path.exists(uzbl_config): # All of these settings can be inherited from your uzbl config file. config = { # Tab options - 'show_tablist': True, - 'show_gtk_tabs': False, - 'max_title_len': 50, - 'tablist_top': True, - 'tab_titles': True, - 'gtk_tab_pos': 'top', # (top|left|bottom|right) - 'new_tab_title': 'New tab', - 'switch_to_new_tabs': True, + 'show_tablist': True, # Show text uzbl like statusbar tab-list + 'show_gtk_tabs': False, # Show gtk notebook tabs + 'tablist_top': True, # Display tab-list at top of window + 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) + 'switch_to_new_tabs': True, # Upon opening a new tab switch to it - # uzbl options - 'save_session': True, - 'fifo_dir': '/tmp', - 'socket_dir': '/tmp', + # Tab title options + 'tab_titles': True, # Display tab titles (else only tab-nums) + 'new_tab_title': 'Loading', # New tab title + 'max_title_len': 50, # Truncate title at n characters + 'show_ellipsis': True, # Show ellipsis when truncating titles + + # Core options + 'save_session': True, # Save session in file when quit + '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'), 'session_file': os.path.join(data_dir, 'session'), - 'status_background': "#303030", - 'window_size': "800,800", # in pixels - 'monospace_size': 10, + + # Window options + 'status_background': "#303030", # Default background for all panels + 'window_size': "800,800", # width,height in pixels # Key bindings. - 'bind_new_tab': 'gn', - 'bind_tab_from_clip': 'gY', - 'bind_close_tab': 'gC', - 'bind_next_tab': 'gt', - 'bind_prev_tab': 'gT', - 'bind_goto_tab': 'gi_', - 'bind_goto_first': 'g<', - 'bind_goto_last': 'g>', + 'bind_new_tab': 'gn', # Open new tab. + 'bind_tab_from_clip': 'gY', # Open tab from clipboard. + 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. + 'bind_close_tab': 'gC', # Close tab. + 'bind_next_tab': 'gt', # Next tab. + 'bind_prev_tab': 'gT', # Prev tab. + 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title) + 'bind_goto_first': 'g<', # Goto first tab + 'bind_goto_last': 'g>', # Goto last tab # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like @@ -293,7 +302,7 @@ class UzblTabbed: self._socketout = [] self._socket = None self._buffer = "" - # Switch to tab after connection + # Switch to tab after loading self._switch = switch # fifo/socket files exists and socket connected. self._connected = False @@ -354,12 +363,18 @@ class UzblTabbed: del self.timers[timer_call] if self._switch: - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) - self.parent.goto_tab(tabid) - + self.grabfocus() + return len(self._fifoout + self._socketout) + + def grabfocus(self): + '''Steal parent focus and switch the notebook to my own tab.''' + + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) + self.parent.goto_tab(tabid) + def probe(self): '''Probes the client for information about its self.''' @@ -392,6 +407,12 @@ class UzblTabbed: self._timers = {} self._buffer = "" + # Once a second is updated with the latest tabs' uris so that when the + # window is killed the session is saved. + self._tabsuris = [] + # And index of current page in self._tabsuris + self._curpage = 0 + # Holds metadata on the uzbl childen open. self.tabs = {} @@ -454,8 +475,13 @@ class UzblTabbed: self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) self.notebook.set_show_border(False) + self.notebook.set_scrollable(True) + self.notebook.set_border_width(0) + self.notebook.connect("page-removed", self.tab_closed) self.notebook.connect("switch-page", self.tab_changed) + self.notebook.connect("page-added", self.tab_opened) + self.notebook.show() if config['show_tablist']: if config['tablist_top']: @@ -525,7 +551,7 @@ class UzblTabbed: gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) watcher('main-fifo-hangup', gid) - + def run(self): '''UzblTabbed main function that calls the gtk loop.''' @@ -546,13 +572,21 @@ class UzblTabbed: '''Probe all uzbl clients for up-to-date window titles and uri's.''' sockd = {} + uriinventory = [] + tabskeys = self.tabs.keys() + notebooklist = list(self.notebook) - for tab in self.tabs.keys(): + for tab in notebooklist: + if tab not in tabskeys: continue uzbl = self.tabs[tab] + uriinventory.append(uzbl.uri) uzbl.probe() if uzbl._socket: sockd[uzbl._socket] = uzbl + self._tabsuris = uriinventory + self._curpage = self.notebook.get_current_page() + sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) @@ -694,7 +728,7 @@ class UzblTabbed: return False - def new_tab(self, uri='', switch=True): + def new_tab(self, uri='', switch=None): '''Add a new tab to the notebook and start a new instance of uzbl. Use the switch option to negate config['switch_to_new_tabs'] option when you need to load multiple tabs at a time (I.e. like when @@ -711,8 +745,14 @@ class UzblTabbed: socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) socket_file = os.path.join(config['socket_dir'], socket_filename) + if switch is None: + switch = config['switch_to_new_tabs'] + + # Create meta-instance and spawn child - if uri: uri = '--uri %s' % uri + if len(uri.strip()): + uri = '--uri %s' % uri + uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ uri, switch) self.tabs[tab] = uzbl @@ -740,6 +780,7 @@ class UzblTabbed: # bind ( key , command back to fifo ) bind(config['bind_new_tab'], 'new') bind(config['bind_tab_from_clip'], 'newfromclip') + bind(config['bind_tab_from_uri'], 'new %s') bind(config['bind_close_tab'], 'close') bind(config['bind_next_tab'], 'next') bind(config['bind_prev_tab'], 'prev') @@ -751,19 +792,21 @@ class UzblTabbed: uzbl.send("\n".join(binds)) - def goto_tab(self, n): + def goto_tab(self, index): '''Goto tab n (supports negative indexing).''' - if 0 <= n < self.notebook.get_n_pages(): - self.notebook.set_current_page(n) + tabs = list(self.notebook) + if 0 <= index < len(tabs): + self.notebook.set_current_page(index) self.update_tablist() return None try: - tabs = list(self.notebook) - tab = tabs[n] - i = tabs.index(tab) - self.notebook.set_current_page(i) + tab = tabs[index] + # Update index because index might have previously been a + # negative index. + index = tabs.index(tab) + self.notebook.set_current_page(index) self.update_tablist() except IndexError: @@ -778,8 +821,8 @@ class UzblTabbed: return None ntabs = self.notebook.get_n_pages() - tabn = self.notebook.get_current_page() + step - self.notebook.set_current_page(tabn % ntabs) + tabn = (self.notebook.get_current_page() + step) % ntabs + self.notebook.set_current_page(tabn) self.update_tablist() @@ -803,18 +846,30 @@ class UzblTabbed: if tabn is None: tabn = self.notebook.get_current_page() - try: - tab = list(self.notebook)[tabn] + else: + try: + tab = list(self.notebook)[tabn] - - except IndexError: - error("close_tab: invalid index %r" % tabn) - return None + except IndexError: + error("close_tab: invalid index %r" % tabn) + return None self.notebook.remove_page(tabn) + + def tab_opened(self, notebook, tab, index): + '''Called upon tab creation. Called by page-added signal.''' + + if config['switch_to_new_tabs']: + self.notebook.set_focus_child(tab) + + else: + oldindex = self.notebook.get_current_page() + oldtab = self.notebook.get_nth_page(oldindex) + self.notebook.set_focus_child(oldtab) + - def tab_closed(self, notebook, tab, page_num): + def tab_closed(self, notebook, tab, index): '''Close the window if no tabs are left. Called by page-removed signal.''' @@ -838,24 +893,32 @@ class UzblTabbed: self.update_tablist() + return True - def tab_changed(self, notebook, page, page_num): - '''Refresh tab list. Called by switch-page signal.''' - self.update_tablist() + def tab_changed(self, notebook, page, index): + '''Refresh tab list. Called by switch-page signal.''' + + tab = self.notebook.get_nth_page(index) + self.notebook.set_focus_child(tab) + self.update_tablist(index) + return True - def update_tablist(self): + def update_tablist(self, curpage=None): '''Upate tablist status bar.''' show_tablist = config['show_tablist'] show_gtk_tabs = config['show_gtk_tabs'] tab_titles = config['tab_titles'] + show_ellipsis = config['show_ellipsis'] if not show_tablist and not show_gtk_tabs: return True tabs = self.tabs.keys() - curpage = self.notebook.get_current_page() + if curpage is None: + curpage = self.notebook.get_current_page() + title_format = "%s - Uzbl Browser" max_title_len = config['max_title_len'] @@ -877,20 +940,24 @@ class UzblTabbed: if index == curpage: self.window.set_title(title_format % uzbl.title) + + tabtitle = uzbl.title[:max_title_len] + if show_ellipsis and len(tabtitle) != len(uzbl.title): + tabtitle = "%s\xe2\x80\xa6" % tabtitle[:-1] # Show Ellipsis if show_gtk_tabs: if tab_titles: - self.notebook.set_tab_label_text(tab, \ - gtk_tab_format % (index, uzbl.title[:max_title_len])) + self.notebook.set_tab_label_text(tab,\ + gtk_tab_format % (index, tabtitle)) else: self.notebook.set_tab_label_text(tab, str(index)) if show_tablist: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style + if tab_titles: - pango += tab_format % (tabc, index, textc,\ - uzbl.title[:max_title_len]) + pango += tab_format % (tabc, index, textc, tabtitle) else: pango += tab_format % (tabc, textc, index) @@ -921,20 +988,17 @@ class UzblTabbed: print "Unlinked %s" % self.fifo_socket if config['save_session']: - session_file = os.path.expandvars(config['session_file']) - if self.notebook.get_n_pages(): + session_file = config['session_file'] + if len(self._tabsuris): if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): + # Recursive mkdir not rmdir. rmkdir(dirname) - + + sessionstr = '\n'.join(self._tabsuris) h = open(session_file, 'w') - h.write('current = %s\n' % self.notebook.get_current_page()) - tabs = self.tabs.keys() - for tab in list(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - h.write("%s\n" % uzbl.uri) + h.write('current = %s\n%s' % (self._curpage, sessionstr)) h.close() else: @@ -957,14 +1021,22 @@ if __name__ == "__main__": lines = [line.strip() for line in h.readlines()] h.close() current = 0 + urls = [] for line in lines: if line.startswith("current"): current = int(line.split()[-1]) else: + urls.append(line.strip()) + + for (index, url) in enumerate(urls): + if current == index: + uzbl.new_tab(line, True) + + else: uzbl.new_tab(line, False) - if not len(lines): + if not len(urls): self.new_tab() else: -- cgit v1.2.3 From 14185edd46e52478907eacc1bd95e2a18c469e1b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 4 Jul 2009 19:55:08 +0800 Subject: Update configuration section at the head of uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 73 +++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 93592da..6ed902d 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -42,34 +42,60 @@ # Here is a list of configuration options that can be customised and some # example values for each: # -# set show_tablist = 1 -# set show_gtk_tabs = 0 -# set switch_to_new_tabs = 1 -# set save_session = 1 -# set gtk_tab_pos = (left|bottom|top|right) -# set max_title_len = 50 -# set new_tab_title = New tab -# set status_background = #303030 -# set session_file = $HOME/.local/share/session -# set tab_colours = foreground = "#999" -# set tab_text_colours = foreground = "#444" -# set selected_tab = foreground = "#aaa" background="#303030" -# set selected_tab_text = foreground = "green" -# set window_size = 800,800 +# General tabbing options: +# show_tablist = 1 +# show_gtk_tabs = 0 +# tablist_top = 1 +# gtk_tab_pos = (top|left|bottom|right) +# switch_to_new_tabs = 1 +# +# Tab title options: +# tab_titles = 1 +# new_tab_title = Loading +# max_title_len = 50 +# show_ellipsis = 1 # -# And the keybindings: +# Core options: +# save_session = 1 +# fifo_dir = /tmp +# socket_dir = /tmp +# icon_path = $HOME/.local/share/uzbl/uzbl.png +# session_file = $HOME/.local/share/uzbl/session # -# set bind_new_tab = gn -# set bind_tab_from_clip = gY -# set bind_close_tab = gC -# set bind_next_tab = gt -# set bind_prev_tab = gT -# set bind_goto_tab = gi_ -# set bind_goto_first = g< -# set bind_goto_last = g> +# Window options: +# status_background = #303030 +# window_size = 800,800 +# +# And the key bindings: +# bind_new_tab = gn +# bind_tab_from_clip = gY +# bind_tab_from_uri = go _ +# bind_close_tab = gC +# bind_next_tab = gt +# bind_prev_tab = gT +# bind_goto_tab = gi_ +# bind_goto_first = g< +# bind_goto_last = g> # # And uzbl_tabbed.py takes care of the actual binding of the commands via each # instances fifo socket. +# +# Custom tab styling: +# tab_colours = foreground = "#888" background = "#303030" +# tab_text_colours = foreground = "#bbb" +# selected_tab = foreground = "#fff" +# selected_tab_text = foreground = "green" +# tab_indicate_https = 1 +# https_colours = foreground = "#888" +# https_text_colours = foreground = "#9c8e2d" +# selected_https = foreground = "#fff" +# selected_https_text = foreground = "gold" +# +# How these styling values are used are soley defined by the syling policy +# handler below (the function in the config section). So you can for example +# turn the tab text colour Firetruck-Red in the event "error" appears in the +# tab title or some other arbitrary event. You may wish to make a trusted +# hosts file and turn tab titles of tabs visiting trusted hosts purple. # Issues: @@ -92,6 +118,7 @@ # - check spelling. # - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into # the collective. Resistance is futile! +# - on demand store the session to file (need binding & command for that) import pygtk -- cgit v1.2.3 From 23f6ed74c0305bdb25aac4520f5b2c9558838215 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 7 Jul 2009 12:02:02 +0800 Subject: fixed markup in window titles messing up pango tabtitle formatting. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 6ed902d..40a93a6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -301,6 +301,14 @@ def counter(): yield i +def escape(s): + '''Replaces html markup in tab titles that screw around with pango.''' + + for (split, glue) in [('&','&'), ('<', '<'), ('>', '>')]: + s = s.replace(split, glue) + return s + + def gen_endmarker(): '''Generates a random md5 for socket message-termination endmarkers.''' @@ -984,7 +992,8 @@ class UzblTabbed: (tabc, textc) = style if tab_titles: - pango += tab_format % (tabc, index, textc, tabtitle) + pango += tab_format % (tabc, index, textc,\ + escape(tabtitle)) else: pango += tab_format % (tabc, textc, index) -- cgit v1.2.3 From 81119479a70c877481271a1a58a7723ac596bc87 Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Tue, 7 Jul 2009 04:50:15 -0600 Subject: use expand instead of expand_template for useragent. --- examples/config/uzbl/config | 4 +- tests/test-expand.c | 20 ++++---- uzbl.c | 109 +++++++++++++++++++++----------------------- uzbl.h | 20 ++------ 4 files changed, 68 insertions(+), 85 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a4a5f45..c431822 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -85,9 +85,9 @@ set always_insert_mode = 0 #set proxy_url = http://127.0.0.1:8118 #values 0-3 #set http_debug = 0 -#set useragent = uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) +#set useragent = uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) # Example user agent containing everything: -set useragent = Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT) +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@SYSNAME @NODENAME @KERNREL @KERNVER @ARCH_SYSTEM [@ARCH_UZBL]) (Commit @COMMIT) #set max_conns = 0 #set max_conns_host = 0 diff --git a/tests/test-expand.c b/tests/test-expand.c index d9fb6e9..c0eae41 100644 --- a/tests/test-expand.c +++ b/tests/test-expand.c @@ -27,6 +27,7 @@ extern Uzbl uzbl; +extern gchar* expand(char*, guint); extern gchar* expand_template(const char*, gboolean); extern void make_var_to_name_hash(void); @@ -106,16 +107,13 @@ test_WEBKIT_VERSION (void) { g_string_append(expected, " "); g_string_append(expected, itos(WEBKIT_MICRO_VERSION)); - g_assert_cmpstr(expand_template("WEBKIT_MAJOR WEBKIT_MINOR WEBKIT_MICRO", FALSE), ==, g_string_free(expected, FALSE)); + g_assert_cmpstr(expand("@WEBKIT_MAJOR @WEBKIT_MINOR @WEBKIT_MICRO", 0), ==, g_string_free(expected, FALSE)); } void test_UNAMEINFO (void) { GString* expected = g_string_new(""); - if(uname(&uzbl.state.unameinfo) == -1) - g_printerr("Can't retrieve unameinfo. This test might fail.\n"); - g_string_append(expected, uzbl.state.unameinfo.sysname); g_string_append(expected, " "); g_string_append(expected, uzbl.state.unameinfo.nodename); @@ -126,17 +124,17 @@ test_UNAMEINFO (void) { g_string_append(expected, " "); g_string_append(expected, uzbl.state.unameinfo.machine); - g_assert_cmpstr(expand_template("SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM", FALSE), ==, g_string_free(expected, FALSE)); + g_assert_cmpstr(expand("@SYSNAME @NODENAME @KERNREL @KERNVER @ARCH_SYSTEM", 0), ==, g_string_free(expected, FALSE)); } void test_ARCH_UZBL (void) { - g_assert_cmpstr(expand_template("ARCH_UZBL", FALSE), ==, ARCH); + g_assert_cmpstr(expand("@ARCH_UZBL", 0), ==, ARCH); } void test_COMMIT (void) { - g_assert_cmpstr(expand_template("COMMIT", FALSE), ==, COMMIT); + g_assert_cmpstr(expand("@COMMIT", 0), ==, COMMIT); } void @@ -149,7 +147,7 @@ test_cmd_useragent_simple (void) { g_string_append(expected, itos(WEBKIT_MICRO_VERSION)); g_string_append(expected, ")"); - set_var_value("useragent", "Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO)"); + set_var_value("useragent", "Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO)"); g_assert_cmpstr(uzbl.net.useragent, ==, g_string_free(expected, FALSE)); } @@ -178,7 +176,7 @@ test_cmd_useragent_full (void) { g_string_append(expected, COMMIT); g_string_append(expected, ")"); - set_var_value("useragent", "Uzbl (Webkit WEBKIT_MAJOR.WEBKIT_MINOR.WEBKIT_MICRO) (SYSNAME NODENAME KERNREL KERNVER ARCH_SYSTEM [ARCH_UZBL]) (Commit COMMIT)"); + set_var_value("useragent", "Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@SYSNAME @NODENAME @KERNREL @KERNVER @ARCH_SYSTEM [@ARCH_UZBL]) (Commit @COMMIT)"); g_assert_cmpstr(uzbl.net.useragent, ==, g_string_free(expected, FALSE)); } @@ -210,6 +208,10 @@ main (int argc, char *argv[]) { g_thread_init (NULL); uzbl.net.soup_session = webkit_get_default_session(); + + if(uname(&uzbl.state.unameinfo) == -1) + g_printerr("Can't retrieve unameinfo. This test might fail.\n"); + setup_scanner(); make_var_to_name_hash(); diff --git a/uzbl.c b/uzbl.c index 1d2a6c9..3c89bb2 100644 --- a/uzbl.c +++ b/uzbl.c @@ -156,6 +156,30 @@ const struct { { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}} }, *n2v_p = var_name_to_ptr; +const struct { + char *name; + struct { + void *ptr; + int type; + } cp; +} const_name_to_ptr[] = { + { "WEBKIT_MAJOR", {(void*)WEBKIT_MAJOR_VERSION, TYPE_INT}}, + { "WEBKIT_MINOR", {(void*)WEBKIT_MINOR_VERSION, TYPE_INT}}, + { "WEBKIT_MICRO", {(void*)WEBKIT_MICRO_VERSION, TYPE_INT}}, + { "SYSNAME", {&(uzbl.state.unameinfo.sysname), TYPE_STR}}, + { "NODENAME", {&(uzbl.state.unameinfo.nodename), TYPE_STR}}, + { "KERNREL", {&(uzbl.state.unameinfo.release), TYPE_STR}}, + { "KERNVER", {&(uzbl.state.unameinfo.version), TYPE_STR}}, + { "ARCH_SYSTEM", {&(uzbl.state.unameinfo.machine), TYPE_STR}}, + { "ARCH_UZBL", {&(ARCH), TYPE_STR}}, +#ifdef _GNU_SOURCE + { "DOMAINNAME", {&(uzbl.state.unameinfo.domainname), TYPE_STR}}, +#endif + { "COMMIT", {&(COMMIT), TYPE_STR}}, + + { NULL, {NULL, TYPE_INT}} +}, *n2c_p = const_name_to_ptr; + const struct { char *key; guint mask; @@ -180,7 +204,8 @@ const struct { }; -/* construct a hash from the var_name_to_ptr array for quick access */ +/* construct a hash from the var_name_to_ptr and the const_name_to_ptr array + * for quick access */ void make_var_to_name_hash() { uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal); @@ -188,6 +213,12 @@ make_var_to_name_hash() { g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp); n2v_p++; } + + uzbl.comm.proto_const = g_hash_table_new(g_str_hash, g_str_equal); + while(n2c_p->name) { + g_hash_table_insert(uzbl.comm.proto_const, n2c_p->name, (gpointer) &n2c_p->cp); + n2c_p++; + } } /* --- UTILITY FUNCTIONS --- */ @@ -212,7 +243,7 @@ return EXP_ERR; * recurse == 1: don't expand '@(command)@' * recurse == 2: don't expand '@@' */ -static gchar * +gchar * expand(char *s, guint recurse) { uzbl_cmdprop *c; guint etype; @@ -276,17 +307,25 @@ expand(char *s, guint recurse) { break; } - if(etype == EXP_SIMPLE_VAR || + if(etype == EXP_SIMPLE_VAR || etype == EXP_BRACED_VAR) { - if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) { - if(c->type == TYPE_STR) - g_string_append(buf, (gchar *)*c->ptr); - else if(c->type == TYPE_INT) { - char *b = itos((int)*c->ptr); - g_string_append(buf, b); - g_free(b); - } + void *ptr; + + if('A' <= ret[0] && 'Z' >= ret[0] && + (c = g_hash_table_lookup(uzbl.comm.proto_const, ret))) { + ptr = c->ptr; + } else if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) { + ptr = *c->ptr; + } + + if(c && c->type == TYPE_STR) { + g_string_append(buf, (gchar *)ptr); + } else if(c && c->type == TYPE_INT) { + char *b = itos((uintptr_t)ptr); + g_string_append(buf, b); + g_free(b); } + if(etype == EXP_SIMPLE_VAR) s = vend; else @@ -1278,47 +1317,6 @@ expand_template(const char *template, gboolean escape_markup) { uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:""); break; /* useragent syms */ - case SYM_WK_MAJ: - buf = itos(WEBKIT_MAJOR_VERSION); - g_string_append(ret, buf); - g_free(buf); - break; - case SYM_WK_MIN: - buf = itos(WEBKIT_MINOR_VERSION); - g_string_append(ret, buf); - g_free(buf); - break; - case SYM_WK_MIC: - buf = itos(WEBKIT_MICRO_VERSION); - g_string_append(ret, buf); - g_free(buf); - break; - case SYM_SYSNAME: - g_string_append(ret, uzbl.state.unameinfo.sysname); - break; - case SYM_NODENAME: - g_string_append(ret, uzbl.state.unameinfo.nodename); - break; - case SYM_KERNREL: - g_string_append(ret, uzbl.state.unameinfo.release); - break; - case SYM_KERNVER: - g_string_append(ret, uzbl.state.unameinfo.version); - break; - case SYM_ARCHSYS: - g_string_append(ret, uzbl.state.unameinfo.machine); - break; - case SYM_ARCHUZBL: - g_string_append(ret, ARCH); - break; -#ifdef _GNU_SOURCE - case SYM_DOMAINNAME: - g_string_append(ret, uzbl.state.unameinfo.domainname); - break; -#endif - case SYM_COMMIT: - g_string_append(ret, COMMIT); - break; default: break; } @@ -1764,11 +1762,8 @@ cmd_useragent() { g_free (uzbl.net.useragent); uzbl.net.useragent = NULL; } else { - gchar *ua = expand_template(uzbl.net.useragent, FALSE); - if (ua) - g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL); - g_free(uzbl.net.useragent); - uzbl.net.useragent = ua; + g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, + uzbl.net.useragent, NULL); } } diff --git a/uzbl.h b/uzbl.h index daed44f..e9134fc 100644 --- a/uzbl.h +++ b/uzbl.h @@ -17,12 +17,6 @@ enum { SYM_LOADPRGS, SYM_LOADPRGSBAR, SYM_KEYCMD, SYM_MODE, SYM_MSG, SYM_SELECTED_URI, - /* useragent symbols */ - SYM_WK_MAJ, SYM_WK_MIN, SYM_WK_MIC, - SYM_SYSNAME, SYM_NODENAME, - SYM_KERNREL, SYM_KERNVER, - SYM_ARCHSYS, SYM_ARCHUZBL, - SYM_DOMAINNAME, SYM_COMMIT }; const struct { @@ -39,17 +33,6 @@ const struct { {"LOAD_PROGRESS", SYM_LOADPRGS}, {"LOAD_PROGRESSBAR", SYM_LOADPRGSBAR}, - {"WEBKIT_MAJOR", SYM_WK_MAJ}, - {"WEBKIT_MINOR", SYM_WK_MIN}, - {"WEBKIT_MICRO", SYM_WK_MIC}, - {"SYSNAME", SYM_SYSNAME}, - {"NODENAME", SYM_NODENAME}, - {"KERNREL", SYM_KERNREL}, - {"KERNVER", SYM_KERNVER}, - {"ARCH_SYSTEM", SYM_ARCHSYS}, - {"ARCH_UZBL", SYM_ARCHUZBL}, - {"DOMAINNAME", SYM_DOMAINNAME}, - {"COMMIT", SYM_COMMIT}, {NULL, 0} }, *symp = symbols; @@ -93,6 +76,9 @@ typedef struct { gchar *socket_path; /* stores (key)"variable name" -> (value)"pointer to this var*/ GHashTable *proto_var; + /* stores (key)"CONSTANT NAME" -> (value)"pointer to this var*/ + GHashTable *proto_const; + gchar *sync_stdout; } Communication; -- cgit v1.2.3 From e023b8d9e014d552ca8f4f9a381d3a5a2a7dc638 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 8 Jul 2009 09:08:18 +0800 Subject: Applied patch to fix session restoration code by Romain Bignon --- examples/data/uzbl/scripts/uzbl_tabbed.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 40a93a6..ef82374 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -34,6 +34,9 @@ # Contributor(s): # mxey # uzbl_config path now honors XDG_CONFIG_HOME if it exists. +# +# Romain Bignon +# Fix for session restoration code. # Configuration: @@ -1073,7 +1076,7 @@ if __name__ == "__main__": uzbl.new_tab(line, False) if not len(urls): - self.new_tab() + uzbl.new_tab() else: uzbl.new_tab() -- cgit v1.2.3 From bbe8e80c26a08c1c3f7531b7f8673e6941bc2c84 Mon Sep 17 00:00:00 2001 From: Tassilo Horn Date: Sat, 11 Jul 2009 10:51:13 +0200 Subject: Respect the value of $VISUAL for the formfiller.sh if it is set. --- examples/data/uzbl/scripts/formfiller.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/formfiller.sh b/examples/data/uzbl/scripts/formfiller.sh index bbb9d1a..3d50a7f 100755 --- a/examples/data/uzbl/scripts/formfiller.sh +++ b/examples/data/uzbl/scripts/formfiller.sh @@ -16,8 +16,10 @@ keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms [ -d "`dirname $keydir`" ] || exit 1 [ -d "$keydir" ] || mkdir "$keydir" -#editor=gvim -editor='urxvt -e vim' +editor=${VISUAL} +if [[ -z ${editor} ]]; then + editor='urxvt -e vim' +fi config=$1; shift pid=$1; shift -- cgit v1.2.3 From 8ddfa7f1b80c910525570eb33254a540a24ab75f Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 27 Jun 2009 11:17:15 +0100 Subject: Don't need backslashes here. --- examples/data/uzbl/scripts/cookies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index bf2d2e6..c8cf8c0 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -62,10 +62,10 @@ class FakeResponse: if __name__ == '__main__': if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - jar = cookielib.MozillaCookieJar(\ + jar = cookielib.MozillaCookieJar( os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')) else: - jar = cookielib.MozillaCookieJar(\ + jar = cookielib.MozillaCookieJar( os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) try: jar.load() -- cgit v1.2.3 From 14a53251bbedb94ff0d78321276d5b0de9504f9a Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 11 Jul 2009 12:11:13 +0100 Subject: Added new_window handler. --- examples/config/uzbl/config | 4 ++++ uzbl.c | 20 ++++++++++++++++++++ uzbl.h | 4 ++++ 3 files changed, 28 insertions(+) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a4a5f45..3c2b7bf 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -11,6 +11,10 @@ set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py +# Control how new windows should open +#set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour +#set new_window = sh 'echo uri "$8" > $4' # open in same window + # You can bind whatever things (spawn , script ,..) to some events TODO: make events system more generic set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv diff --git a/uzbl.c b/uzbl.c index a998b91..a5d78f5 100644 --- a/uzbl.c +++ b/uzbl.c @@ -129,6 +129,7 @@ const struct { { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)}, { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)}, { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, + { "new_window", PTR(uzbl.behave.new_window, STR, 1, cmd_new_window)}, { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, @@ -1049,6 +1050,12 @@ dehilight (WebKitWebView *page, GArray *argv, GString *result) { static void new_window_load_uri (const gchar * uri) { + if (uzbl.behave.new_window) { + GString *s = g_string_new (""); + g_string_printf(s, "'%s'", uri); + run_handler(uzbl.behave.new_window, s->str); + return; + } GString* to_execute = g_string_new (""); g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri); int i; @@ -1723,6 +1730,19 @@ cmd_cookie_handler() { g_strfreev (split); } +static void +cmd_new_window() { + gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.new_window); + uzbl.behave.new_window = + g_strdup_printf("%s %s", split[0], split[1]); + } + g_strfreev (split); +} + static void cmd_fifo_dir() { uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); diff --git a/uzbl.h b/uzbl.h index 9a7ccd2..d67a84e 100644 --- a/uzbl.h +++ b/uzbl.h @@ -137,6 +137,7 @@ typedef struct { gchar* socket_dir; gchar* download_handler; gchar* cookie_handler; + gchar* new_window; gboolean always_insert_mode; gboolean show_status; gboolean insert_mode; @@ -493,6 +494,9 @@ set_icon(); static void cmd_cookie_handler(); +static void +cmd_new_window(); + static void move_statusbar(); -- cgit v1.2.3 From 3b209125f06785c0baf23478433ed36230281ea3 Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Sun, 12 Jul 2009 13:09:45 -0600 Subject: updated readme and example config --- README | 44 +++++++++++++++++++++++++++++++++++--------- examples/config/uzbl/config | 8 ++++---- 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/README b/README index ae9932b..266a207 100644 --- a/README +++ b/README @@ -235,22 +235,48 @@ the java script in @< >@. Variable expansion also works within a java script substitution. +When a piece of text needs to be XML escaped after it is expanded (for example, +in the status bar format), you can use @[ ]@ substitution: + + print This text is XML escaped: @[<&>]@ + + # prints: This text is XML escaped: <&> + + NOTE: If you need to use literal @ or \ characters you will need to escape them: print At sign: \@ and backslash: \\ -### VARIABLE REPLACEMENT -Some of the variables are interpreted: +### TITLE AND STATUS BAR EVALUATION + +The contents of the status bar can be customized by setting the status_format +variable. The contents of the window title can be customized by setting the +title_format_short variable (which is used when the status bar is displayed) and +the title_format_long variable (which is used when the status bar is not +displayed). Their values can be set using the expansion and substitution +techniques described above. + +These variables are expanded in multiple stages; once when the variable is set, +and again every time that the status bar or window title are updated. Expansions +that should be evaluated on every update need to be escaped: + + set title_format_short = @(date)@ + # this expansion will be evaluated when the variable is set. + # the title will stay constant with the date that the variable was set. + + set title_format_short = \@(date)\@ + # this expansion will be evaluated when the window title is updated. + # the date in the title will change when you change pages, for example. -* title bar: variable replacement (long and short version, depending if statusbar is visible or not) -* user agent: variable replacement -* statusbar: variable replacement + pango markup + set title_format_short = \\\@(date)\\\@ + # the title will stay constant as a literal "@(date)@" -This means you can customize how these things appear, what's shown in them and for the statusbar you can even play with the layout. -For examples, see the example config. -For a list of possible variables, see uzbl.h -For more info about the markup format see http://library.gnome.org/devel/pango/stable/PangoMarkupFormat.html +The status_format variable can contain Pango markup (see +). In the +status_format, variables that might contain characters like '<', '&' and '>', +should be wrapped in a @[]@ substitution so that they don't interfere with the +status bar's markup; see the example config for examples. ### EXTERNAL SCRIPTS diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 4d455b1..126df49 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -68,11 +68,11 @@ set shell_cmd = sh -c set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = [MODE] [KEYCMD] LOAD_PROGRESSBAR URI NAME MSGSELECTED_URI +set status_format = [\@[\@MODE]\@] [\@[\@ keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message\@[\@ SELECTED_URI]\@ set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) -set title_format_short = TITLE - Uzbl browser -set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI +set title_format_short = \@TITLE - Uzbl browser <\@NAME> +set title_format_long = \@keycmd \@MODE \@TITLE - Uzbl browser <\@NAME> > \@SELECTED_URI # set the characters to use for, and the width of the progress bar set status_pbar_done = * set status_pbar_pending = - @@ -91,7 +91,7 @@ set always_insert_mode = 0 #set http_debug = 0 #set useragent = uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) # Example user agent containing everything: -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@SYSNAME @NODENAME @KERNREL @KERNVER @ARCH_SYSTEM [@ARCH_UZBL]) (Commit @COMMIT) +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname-s)@ @(uname -n)@ @(uname -r)@ @(uname -v)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) #set max_conns = 0 #set max_conns_host = 0 -- cgit v1.2.3 From fcb0c08792fb264c5f629dff57c602e8a88bd952 Mon Sep 17 00:00:00 2001 From: Abel `00z' Camarillo <00z@the00z.org> Date: Sun, 12 Jul 2009 14:21:50 -0500 Subject: replace that ugly ${!8} bashism --- examples/data/uzbl/scripts/yank.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh index ddd0a4b..d702788 100755 --- a/examples/data/uzbl/scripts/yank.sh +++ b/examples/data/uzbl/scripts/yank.sh @@ -11,5 +11,7 @@ clip=xclip which xclip &>/dev/null || exit 1 [ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2 -echo "echo -n '${8}' | $clip -selection $9" -echo -n "'${8}' | $clip -selection $9" +value=`eval "echo -n \\${$8}"` + +echo "echo -n '${value}' | $clip -selection $9" +echo -n "'${value}' | $clip -selection $9" -- cgit v1.2.3 From fe84dba46082f9cc949b86e2fd32c6e055aec0a0 Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 12 Jul 2009 21:54:21 +0100 Subject: Add request address scheme to cookie_handler's arguments. --- README | 7 ++++--- examples/data/uzbl/scripts/cookies.sh | 1 + uzbl.c | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/README b/README index ae9932b..d5db188 100644 --- a/README +++ b/README @@ -290,9 +290,10 @@ The script specific arguments are this: * cookie handler $8 GET/PUT - $9 request address host (if current page url is www.foo.com/somepage, this could be something else than foo, eg advertising from another host) - $10 request address path - $11 cookie (only with PUT requests) + $9 request address scheme (e.g. http or https) + $10 request address host (if current page url is www.foo.com/somepage, this could be something else than foo, eg advertising from another host) + $11 request address path + $12 cookie (only with PUT requests) Custom, userdefined scripts (`spawn foo bar`) get first the arguments as specified in the config and then the above 7 are added at the end. diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh index 56b9c79..4398a03 100755 --- a/examples/data/uzbl/scripts/cookies.sh +++ b/examples/data/uzbl/scripts/cookies.sh @@ -48,6 +48,7 @@ which zenity &>/dev/null || exit 2 # uri=${uri/http:\/\/} # strip 'http://' part # host=${uri/\/*/} action=$8 # GET/PUT +shift host=$9 shift path=$9 diff --git a/uzbl.c b/uzbl.c index 193d0ba..c31b41c 100644 --- a/uzbl.c +++ b/uzbl.c @@ -2554,7 +2554,7 @@ static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer use soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); GString *s = g_string_new (""); SoupURI * soup_uri = soup_message_get_uri(msg); - g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path); + g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path); run_handler(uzbl.behave.cookie_handler, s->str); if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { @@ -2577,7 +2577,7 @@ save_cookies (SoupMessage *msg, gpointer user_data){ cookie = soup_cookie_to_set_cookie_header(ck->data); SoupURI * soup_uri = soup_message_get_uri(msg); GString *s = g_string_new (""); - g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie); + 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); g_free (cookie); g_string_free(s, TRUE); -- cgit v1.2.3 From e4ec794daa2a27f4476f53aacbf947f57a27ce5c Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 12 Jul 2009 22:22:49 +0100 Subject: cookies.py now fits in with the new arguments, and works better. --- examples/data/uzbl/scripts/cookies.py | 94 ++++++++--------------------------- 1 file changed, 22 insertions(+), 72 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py index c8cf8c0..10f90fa 100755 --- a/examples/data/uzbl/scripts/cookies.py +++ b/examples/data/uzbl/scripts/cookies.py @@ -1,87 +1,37 @@ #!/usr/bin/env python -import cookielib, sys, os, urllib2 - -class FakeRequest: - def __init__(self, argv): - self.argv = argv - self.cookies = None - if len(self.argv) == 12: - self.cookies = self.argv[11] - def get_full_url(self): - #TODO: this is a hack, fix in uzbl.c! - u = self.get_host()+self.argv[10] - if self.argv[6].startswith('https'): - u = 'https://'+u - else: - u = 'http://'+u - return u - def get_host(self): - return self.argv[9] - def get_type(self): - return self.get_full_url().split(':')[0] - def is_unverifiable(self): - return False - def get_origin_req_host(self): - return self.argv[9] - def has_header(self, header): - if header == 'Cookie': - return self.cookies!=None - def get_header(self, header_name, default=None): - if header_name == 'Cookie' and self.cookies: - return self.cookies - else: - return default - def header_items(self): - if self.cookies: - return [('Cookie',self.cookies)] - else: - return [] - def add_unredirected_header(self, key, header): - if key == 'Cookie': - self.cookies = header - -class FakeHeaders: - def __init__(self, argv): - self.argv = argv - def getallmatchingheaders(self, header): - if header == 'Set-Cookie' and len(self.argv) == 12: - return ['Set-Cookie: '+self.argv[11]] - else: - return [] - def getheaders(self, header): - if header == 'Set-Cookie' and len(self.argv) == 12: - return [self.argv[11]] - else: - return [] -class FakeResponse: - def __init__(self, argv): - self.argv = argv - def info(self): - return FakeHeaders(self.argv) +import StringIO, cookielib, os, sys, urllib2 if __name__ == '__main__': + action = sys.argv[8] + uri = urllib2.urlparse.ParseResult( + scheme=sys.argv[9], + netloc=sys.argv[10], + path=sys.argv[11], + params='', + query='', + fragment='').geturl() + set_cookie = sys.argv[12] if len(sys.argv)>12 else None + if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - jar = cookielib.MozillaCookieJar( - os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt')) + f = os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt') else: - jar = cookielib.MozillaCookieJar( - os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt')) + f = os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt') + jar = cookielib.MozillaCookieJar(f) + try: - jar.load() + jar.load(ignore_discard=True) except: pass - req = FakeRequest(sys.argv) - - action = sys.argv[8] + req = urllib2.Request(uri) if action == 'GET': jar.add_cookie_header(req) - if req.cookies: - print req.cookies + if req.has_header('Cookie'): + print req.get_header('Cookie') elif action == 'PUT': - res = FakeResponse(sys.argv) + hdr = urllib2.httplib.HTTPMessage(StringIO.StringIO('Set-Cookie: %s' % set_cookie)) + res = urllib2.addinfourl(StringIO.StringIO(), hdr, req.get_full_url()) jar.extract_cookies(res,req) - jar.save(ignore_discard=True) # save session cookies too - #jar.save() # save everything but session cookies + jar.save(ignore_discard=True) -- cgit v1.2.3 From f52c73418f9a68bde9d2668e5215960a0f20cbcf Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Mon, 13 Jul 2009 08:55:35 +0200 Subject: tidy up move to expand() --- config.h | 6 +++--- examples/config/uzbl/config | 4 ++-- uzbl.c | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/config.h b/config.h index ab6e195..c6e3f35 100644 --- a/config.h +++ b/config.h @@ -2,8 +2,8 @@ const struct { char *command; } default_config[] = { { "set reset_command_mode = 1"}, -{ "set status_format = MODE KEYCMD (LOAD_PROGRESS%) TITLE - Uzbl browser"}, -{ "set title_format_long = KEYCMD MODE TITLE - Uzbl browser > SELECTED_URI"}, -{ "set title_format_short = TITLE - Uzbl browser "}, +{ "set status_format = \\@MODE \\@[\\@keycmd]\\@ (\\@LOAD_PROGRESS%) \\@[\\@TITLE]\\@ - Uzbl browser"}, +{ "set title_format_long = \\@keycmd \\@MODE \\@TITLE - Uzbl browser <\\@NAME> > \\@SELECTED_URI"}, +{ "set title_format_short = \\@TITLE - Uzbl browser <\\@NAME>"}, { NULL } }; diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 126df49..e75789d 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -68,7 +68,7 @@ set shell_cmd = sh -c set show_status = 1 # you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 -set status_format = [\@[\@MODE]\@] [\@[\@ keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message\@[\@ SELECTED_URI]\@ +set status_format = [\@[\@MODE]\@] [\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ set status_top = 0 # define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) set title_format_short = \@TITLE - Uzbl browser <\@NAME> @@ -91,7 +91,7 @@ set always_insert_mode = 0 #set http_debug = 0 #set useragent = uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) # Example user agent containing everything: -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname-s)@ @(uname -n)@ @(uname -r)@ @(uname -v)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -s)@ @(uname -n)@ @(uname -r)@ @(uname -v)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) #set max_conns = 0 #set max_conns_host = 0 diff --git a/uzbl.c b/uzbl.c index 5b2ece7..9e833d6 100644 --- a/uzbl.c +++ b/uzbl.c @@ -143,6 +143,7 @@ const struct { { "max_conns", PTR_V(uzbl.net.max_conns, INT, 1, cmd_max_conns)}, { "max_conns_host", PTR_V(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)}, { "useragent", PTR_V(uzbl.net.useragent, STR, 1, cmd_useragent)}, + /* exported WebKitWebSettings properties */ { "zoom_level", PTR_V(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)}, { "font_size", PTR_V(uzbl.behave.font_size, INT, 1, cmd_font_size)}, @@ -2665,7 +2666,6 @@ initialize(int argc, char *argv[]) { /* default mode indicators */ uzbl.behave.insert_indicator = g_strdup("I"); uzbl.behave.cmd_indicator = g_strdup("C"); - set_insert_mode(FALSE); uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION; uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION; @@ -2734,6 +2734,7 @@ main (int argc, char* argv[]) { gboolean verbose_override = uzbl.state.verbose; settings_init (); + set_insert_mode(FALSE); if (!uzbl.behave.show_status) gtk_widget_hide(uzbl.gui.mainbar); -- cgit v1.2.3 From c4faad1f9a553bafea9f24917bf709b2bb70213f Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Tue, 14 Jul 2009 22:35:49 +0100 Subject: Whitespace fixes. And ignore whitespace in formfiller data files. --- .gitattributes | 1 + AUTHORS | 4 +- Makefile | 2 +- Makefile-new-test | 2 +- README | 10 +- docs/INSTALL | 4 +- docs/TODO | 2 +- examples/data/uzbl/scripts/clipboard.sh | 1 - examples/data/uzbl/scripts/cookies.sh | 4 +- examples/data/uzbl/scripts/formfiller.pl | 2 +- examples/data/uzbl/scripts/linkfollow.js | 14 +- .../data/uzbl/scripts/load_url_from_bookmarks.sh | 2 +- .../data/uzbl/scripts/load_url_from_history.sh | 6 +- examples/data/uzbl/scripts/session.sh | 1 - examples/data/uzbl/scripts/uzbl_tabbed.py | 296 ++++++++++----------- examples/data/uzbl/scripts/uzblcat | 6 +- examples/data/uzbl/style.css | 3 +- uzbl.c | 2 +- uzblctrl.c | 12 +- 19 files changed, 183 insertions(+), 191 deletions(-) create mode 100644 .gitattributes (limited to 'examples') diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7799c58 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +examples/data/uzbl/forms/bbs.archlinux.org whitespace=-trailing-space diff --git a/AUTHORS b/AUTHORS index e9b97a9..e744900 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,7 +5,7 @@ Developers: Michael Walker (Barrucadu) Přemysl Hrubý (anydot) Robert Manea (robm) - Henri Kemppainen (DuClare) + Henri Kemppainen (DuClare) Contributors: Zane Ashby (HashBox) - Rewrote FIFO interface. Fixed various bugs. @@ -15,7 +15,7 @@ Contributors: Damien Leon - misc Peter Suschlik - backwards searching (salinasv) - move some variables to heap - Sylvester Johansson (scj) - form filler script & different take on link follower + Sylvester Johansson (scj) - form filler script & different take on link follower (mxf) - uzblcat Mark Nevill - misc patches Uli Schlachter (psychon) - basic mime_policy_cb & Makefile patch diff --git a/Makefile b/Makefile index 857494c..b0c4e54 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ test-dev: uzbl test-share: uzbl XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --verbose - + clean: rm -f uzbl rm -f uzblctrl diff --git a/Makefile-new-test b/Makefile-new-test index 5985c90..9f85a4e 100644 --- a/Makefile-new-test +++ b/Makefile-new-test @@ -27,7 +27,7 @@ test-config: uzbl test-config-real: uzbl ./uzbl --uri http://www.uzbl.org < $(EXMPLSDIR)/configs/sampleconfig - + clean: rm -f uzbl rm -f uzblctrl diff --git a/README b/README index d5db188..6a04544 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ In my opinion, any program can only be really useful if it complies to the unix philosophy. Web browsers are frequent violators of this principle: -* They build in way too much things into the browser, dramatically decreasing the options to do things the way you want. +* They build in way too much things into the browser, dramatically decreasing the options to do things the way you want. * They store things in way too fancy formats (xml, rdf, sqlite, ... ) which are hard to store under version control, reuse in other scripts, ... Time to change that! @@ -26,7 +26,7 @@ Time to change that! Here are the general ideas: * each instance of uzbl renders 1 page (eg it's a small wrapper around webkit), no tabbing, tab previews, or speed dial things. - For "multiple instances management" use your window managers, scripts or wrappers. + For "multiple instances management" use your window managers, scripts or wrappers. This way you can get something much more useful than tabbing by default * very simple, plaintext , changeable at runtime configuration * various interfaces for (programmatic) interaction with uzbl (see below) @@ -196,7 +196,7 @@ Copying the Uzbl object and creating public functions should be taken with care ### VARIABLE EXPANSION AND COMMAND/JAVA SCRIPT SUBSTITUTION -Variable expansion works pretty much as known from shell interpreters (sh, bash, etc.). This means you can +Variable expansion works pretty much as known from shell interpreters (sh, bash, etc.). This means you can construct strings with uzbl variables in them and have uzbl replace the variable name with its contents. In order to let uzbl know what to expand you'll need to prepend @ to the variable name: @@ -256,7 +256,7 @@ For more info about the markup format see http://library.gnome.org/devel/pango/s ### EXTERNAL SCRIPTS You can use external scripts with uzbl the following ways: -* let uzbl call them. these scripts are called handlers in the uzbl config. used for handling logging history, handling a new download,.. +* let uzbl call them. these scripts are called handlers in the uzbl config. used for handling logging history, handling a new download,.. * call them yourself from inside uzbl. you can bind keys for this. examples: add new bookmark, load new url,.. * You could also use xbindkeys or your WM config to trigger scripts if uzbl does not have focus @@ -319,5 +319,3 @@ known bugs: * Segfaults when using zoom commands (happens when max zoom already reached?). Please report new issues @ uzbl.org/bugs - - diff --git a/docs/INSTALL b/docs/INSTALL index be6e85b..9213cc3 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -40,7 +40,7 @@ sample scripts: * dmenu (with vertical patch) * zenity -* bash +* bash * python (cookies.py) * perl (formfiller.pl) @@ -50,7 +50,7 @@ After installing - using either method - you will find: * /usr/bin : uzbl [and uzblctrl] * /usr/share/uzbl/docs/ : documentation files included with uzbl. (readme, checklist, .. ) -* /usr/share/uzbl/examples: sample scripts, config files and a sample data (boomarks, .. ) +* /usr/share/uzbl/examples: sample scripts, config files and a sample data (boomarks, .. ) You will probably want to change the scripts to behave more like you want, so copy the scripts to your home dir. If you save your config as $XDG\_CONFIG\_HOME/uzbl/config (this expands to ~/.config/uzbl/config on most systems) it will be recognized automatically. You can also pass the path to diff --git a/docs/TODO b/docs/TODO index 00166eb..80ccb9c 100644 --- a/docs/TODO +++ b/docs/TODO @@ -53,7 +53,7 @@ More or less in order of importance/urgency overriding variables (such as -u) variable expansion (@var, @{var}, where do they get expanded? can users have their own vars?, should we merge this with the replacement we do for useragent/window title etc?) how %s works for the js command - + SOMEDAY: figure out caching with webkit and in general how we can speed up everything diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh index 85ccbc6..60567d3 100755 --- a/examples/data/uzbl/scripts/clipboard.sh +++ b/examples/data/uzbl/scripts/clipboard.sh @@ -15,4 +15,3 @@ case $action in "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac - diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh index 6951b84..339c6fc 100755 --- a/examples/data/uzbl/scripts/cookies.sh +++ b/examples/data/uzbl/scripts/cookies.sh @@ -8,7 +8,7 @@ set -n; # we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) # This is one textfile with entries like this: # kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 -# domain alow-read-other-subdomains path http-required expiration name value +# domain alow-read-other-subdomains path http-required expiration name value # you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) # Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" # MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( @@ -105,7 +105,7 @@ get_cookie() { echo "$cookie" | \ read domain alow_read_other_subdomains path http_required expiration name \ value; - cookie="$name=$value" + cookie="$name=$value" true fi } diff --git a/examples/data/uzbl/scripts/formfiller.pl b/examples/data/uzbl/scripts/formfiller.pl index 9ac6959..23da347 100755 --- a/examples/data/uzbl/scripts/formfiller.pl +++ b/examples/data/uzbl/scripts/formfiller.pl @@ -7,7 +7,7 @@ # user arg 1: # edit: force editing of the file (fetches if file is missing) # load: fill forms from file (fetches if file is missing) -# new: fetch new file +# new: fetch new file # usage example: # bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load diff --git a/examples/data/uzbl/scripts/linkfollow.js b/examples/data/uzbl/scripts/linkfollow.js index a348af9..0eb629b 100644 --- a/examples/data/uzbl/scripts/linkfollow.js +++ b/examples/data/uzbl/scripts/linkfollow.js @@ -64,9 +64,9 @@ function Hints(){ } function elementInViewport(p) { - return (p.up < window.pageYOffset + window.innerHeight && - p.left < window.pageXOffset + window.innerWidth && - (p.up + p.height) > window.pageYOffset && + return (p.up < window.pageYOffset + window.innerHeight && + p.left < window.pageXOffset + window.innerWidth && + (p.up + p.height) > window.pageYOffset && (p.left + p.width) > window.pageXOffset); } @@ -121,8 +121,8 @@ function Hints(){ this.node.className += " " + uzblclass; } this.isHinted = true; - - // create hint + + // create hint var hintNode = doc.createElement('div'); hintNode.name = uzblid; hintNode.innerText = labelNum; @@ -130,7 +130,7 @@ function Hints(){ hintNode.style.top = this.position.up + 'px'; hintNode.style.position = "absolute"; doc.body.firstChild.appendChild(hintNode); - + } this.removeHint = function(){ if(this.isHinted){ @@ -267,5 +267,3 @@ function Hints(){ var hints = new Hints(); // vim:set et sw=2: - - diff --git a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh index 78ee726..f57d7b3 100755 --- a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh +++ b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh @@ -3,7 +3,7 @@ #NOTE: it's the job of the script that inserts bookmarks to make sure there are no dupes. file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks -[ -r "$file" ] || exit +[ -r "$file" ] || exit COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' then diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh index f207837..1eaf0f2 100755 --- a/examples/data/uzbl/scripts/load_url_from_history.sh +++ b/examples/data/uzbl/scripts/load_url_from_history.sh @@ -12,13 +12,13 @@ then # choose an item in reverse order, showing also the date and page titles # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` -else +else DMENU="dmenu -i" # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; + current=`tail -n 1 $history_file | awk '{print $3}'`; goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \ | sort -u) | $DMENU $COLORS` -fi +fi [ -n "$goto" ] && echo "uri $goto" > $4 #[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh index 4f1e045..22d48a2 100755 --- a/examples/data/uzbl/scripts/session.sh +++ b/examples/data/uzbl/scripts/session.sh @@ -60,4 +60,3 @@ case $act in echo " endsession - Quit the running session. Must be called from uzbl" ;; esac - diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 6ed902d..bf5ee97 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -19,13 +19,13 @@ # along with this program. If not, see . -# Author(s): +# Author(s): # Tom Adams # Wrote the original uzbl_tabbed.py as a proof of concept. # # Chris van Dijk (quigybo) -# Made signifigant headway on the old uzbl_tabbing.py script on the -# uzbl wiki +# Made signifigant headway on the old uzbl_tabbing.py script on the +# uzbl wiki # # Mason Larobina # Rewrite of the uzbl_tabbing.py script to use a fifo socket interface @@ -43,12 +43,12 @@ # example values for each: # # General tabbing options: -# show_tablist = 1 -# show_gtk_tabs = 0 -# tablist_top = 1 +# show_tablist = 1 +# show_gtk_tabs = 0 +# tablist_top = 1 # gtk_tab_pos = (top|left|bottom|right) # switch_to_new_tabs = 1 -# +# # Tab title options: # tab_titles = 1 # new_tab_title = Loading @@ -58,19 +58,19 @@ # Core options: # save_session = 1 # fifo_dir = /tmp -# socket_dir = /tmp +# socket_dir = /tmp # icon_path = $HOME/.local/share/uzbl/uzbl.png # session_file = $HOME/.local/share/uzbl/session # # Window options: # status_background = #303030 # window_size = 800,800 -# +# # And the key bindings: -# bind_new_tab = gn +# bind_new_tab = gn # bind_tab_from_clip = gY # bind_tab_from_uri = go _ -# bind_close_tab = gC +# bind_close_tab = gC # bind_next_tab = gt # bind_prev_tab = gT # bind_goto_tab = gi_ @@ -78,9 +78,9 @@ # bind_goto_last = g> # # And uzbl_tabbed.py takes care of the actual binding of the commands via each -# instances fifo socket. +# instances fifo socket. # -# Custom tab styling: +# Custom tab styling: # tab_colours = foreground = "#888" background = "#303030" # tab_text_colours = foreground = "#bbb" # selected_tab = foreground = "#fff" @@ -93,30 +93,30 @@ # # How these styling values are used are soley defined by the syling policy # handler below (the function in the config section). So you can for example -# turn the tab text colour Firetruck-Red in the event "error" appears in the +# turn the tab text colour Firetruck-Red in the event "error" appears in the # tab title or some other arbitrary event. You may wish to make a trusted -# hosts file and turn tab titles of tabs visiting trusted hosts purple. +# hosts file and turn tab titles of tabs visiting trusted hosts purple. -# Issues: +# Issues: # - new windows are not caught and opened in a new tab. # - when uzbl_tabbed.py crashes it takes all the children with it. -# - when a new tab is opened when using gtk tabs the tab button itself -# grabs focus from its child for a few seconds. -# - when switch_to_new_tabs is not selected the notebook page is +# - when a new tab is opened when using gtk tabs the tab button itself +# grabs focus from its child for a few seconds. +# - when switch_to_new_tabs is not selected the notebook page is # maintained but the new window grabs focus (try as I might to stop it). -# Todo: +# Todo: # - add command line options to use a different session file, not use a -# session file and or open a uri on starup. +# session file and or open a uri on starup. # - ellipsize individual tab titles when the tab-list becomes over-crowded -# - add "<" & ">" arrows to tablist to indicate that only a subset of the +# - add "<" & ">" arrows to tablist to indicate that only a subset of the # currently open tabs are being displayed on the tablist. # - add the small tab-list display when both gtk tabs and text vim-like # tablist are hidden (I.e. [ 1 2 3 4 5 ]) # - check spelling. -# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into +# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into # the collective. Resistance is futile! # - on demand store the session to file (need binding & command for that) @@ -146,7 +146,7 @@ def error(msg): # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ -# Location of your uzbl data directory. +# Location of your uzbl data directory. if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') else: @@ -163,14 +163,14 @@ if not os.path.exists(uzbl_config): error("Warning: Cannot locate your uzbl_config file %r" % uzbl_config) # All of these settings can be inherited from your uzbl config file. -config = { +config = { # Tab options 'show_tablist': True, # Show text uzbl like statusbar tab-list 'show_gtk_tabs': False, # Show gtk notebook tabs 'tablist_top': True, # Display tab-list at top of window 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) 'switch_to_new_tabs': True, # Upon opening a new tab switch to it - + # Tab title options 'tab_titles': True, # Display tab titles (else only tab-nums) 'new_tab_title': 'Loading', # New tab title @@ -180,53 +180,53 @@ config = { # Core options 'save_session': True, # Save session in file when quit 'fifo_dir': '/tmp', # Path to look for uzbl fifo - 'socket_dir': '/tmp', # Path to look for uzbl socket + 'socket_dir': '/tmp', # Path to look for uzbl socket 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), # Window options 'status_background': "#303030", # Default background for all panels 'window_size': "800,800", # width,height in pixels - + # Key bindings. - 'bind_new_tab': 'gn', # Open new tab. + 'bind_new_tab': 'gn', # Open new tab. 'bind_tab_from_clip': 'gY', # Open tab from clipboard. 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. - 'bind_close_tab': 'gC', # Close tab. + 'bind_close_tab': 'gC', # Close tab. 'bind_next_tab': 'gt', # Next tab. 'bind_prev_tab': 'gT', # Prev tab. 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title) 'bind_goto_first': 'g<', # Goto first tab 'bind_goto_last': 'g>', # Goto last tab - - # Add custom tab style definitions to be used by the tab colour policy + + # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like - # any other uzbl_tabbed configuration option remember that they can - # be superseeded from your main uzbl config file. + # any other uzbl_tabbed configuration option remember that they can + # be superseeded from your main uzbl config file. 'tab_colours': 'foreground = "#888" background = "#303030"', - 'tab_text_colours': 'foreground = "#bbb"', + 'tab_text_colours': 'foreground = "#bbb"', 'selected_tab': 'foreground = "#fff"', 'selected_tab_text': 'foreground = "green"', 'tab_indicate_https': True, 'https_colours': 'foreground = "#888"', - 'https_text_colours': 'foreground = "#9c8e2d"', + 'https_text_colours': 'foreground = "#9c8e2d"', 'selected_https': 'foreground = "#fff"', 'selected_https_text': 'foreground = "gold"', - + } # End of config dict. -# This is the tab style policy handler. Every time the tablist is updated +# This is the tab style policy handler. Every time the tablist is updated # this function is called to determine how to colourise that specific tab -# according the simple/complex rules as defined here. You may even wish to +# according the simple/complex rules as defined here. You may even wish to # move this function into another python script and import it using: # from mycustomtabbingconfig import colour_selector # Remember to rename, delete or comment out this function if you do that. def colour_selector(tabindex, currentpage, uzbl): - '''Tablist styling policy handler. This function must return a tuple of + '''Tablist styling policy handler. This function must return a tuple of the form (tab style, text style).''' - - # Just as an example: + + # Just as an example: # if 'error' in uzbl.title: # if tabindex == currentpage: # return ('foreground="#fff"', 'foreground="red"') @@ -239,11 +239,11 @@ def colour_selector(tabindex, currentpage, uzbl): return (config['https_colours'], config['https_text_colours']) # Style to indicate selected. - if tabindex == currentpage: + if tabindex == currentpage: return (config['selected_tab'], config['selected_tab_text']) # Default tab style. - return (config['tab_colours'], config['tab_text_colours']) + return (config['tab_colours'], config['tab_text_colours']) # ============================================================================ @@ -258,26 +258,26 @@ def readconfig(uzbl_config, config): if not os.path.exists(uzbl_config): error("Unable to load config %r" % uzbl_config) return None - + # Define parsing regular expressions isint = re.compile("^(\-|)[0-9]+$").match findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ re.MULTILINE).findall - + h = open(os.path.expandvars(uzbl_config), 'r') rawconfig = h.read() h.close() - + for (key, value) in findsets(rawconfig): key, value = key.strip(), value.strip() if key not in config.keys(): continue if isint(value): value = int(value) config[key] = value - + # Ensure that config keys that relate to paths are expanded. expand = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path'] for key in expand: - config[key] = os.path.expandvars(config[key]) + config[key] = os.path.expandvars(config[key]) def rmkdir(path): @@ -310,14 +310,14 @@ def gen_endmarker(): class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' - class UzblInstance: + class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ uri, switch): self.parent = parent - self.tab = tab + self.tab = tab self.fifo_socket = fifo_socket self.socket_file = socket_file self.pid = pid @@ -331,12 +331,12 @@ class UzblTabbed: self._buffer = "" # Switch to tab after loading self._switch = switch - # fifo/socket files exists and socket connected. + # fifo/socket files exists and socket connected. self._connected = False # The kill switch self._kill = False - # Message termination endmarker. + # Message termination endmarker. self._marker = gen_endmarker() # Gen probe commands string @@ -346,16 +346,16 @@ class UzblTabbed: probe('print title %d @@ %s' % (self.pid,\ self._marker)) self._probecmds = '\n'.join(probes) - + # Enqueue keybinding config for child uzbl instance self.parent.config_uzbl(self) def flush(self, timer_call=False): '''Flush messages from the socket-out and fifo-out queues.''' - + if self._kill: - if self._socket: + if self._socket: self._socket.close() self._socket = None @@ -369,7 +369,7 @@ class UzblTabbed: msg = self._fifoout.pop(0) h.write("%s\n"%msg) h.close() - + if len(self._socketout): if not self._socket and os.path.exists(self.socket_file): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -380,11 +380,11 @@ class UzblTabbed: while len(self._socketout): msg = self._socketout.pop(0) self._socket.send("%s\n"%msg) - + if not self._connected and timer_call: if not len(self._fifoout + self._socketout): self._connected = True - + if timer_call in self.timers.keys(): gobject.source_remove(self.timers[timer_call]) del self.timers[timer_call] @@ -394,10 +394,10 @@ class UzblTabbed: return len(self._fifoout + self._socketout) - + def grabfocus(self): '''Steal parent focus and switch the notebook to my own tab.''' - + tabs = list(self.parent.notebook) tabid = tabs.index(self.tab) self.parent.goto_tab(tabid) @@ -405,7 +405,7 @@ class UzblTabbed: def probe(self): '''Probes the client for information about its self.''' - + if self._connected: self.send(self._probecmds) self._lastprobe = time.time() @@ -425,16 +425,16 @@ class UzblTabbed: self._socketout.append(msg) # Flush messages from queue if able. return self.flush() - + def __init__(self): '''Create tablist, window and notebook.''' - + self._fifos = {} self._timers = {} self._buffer = "" - - # Once a second is updated with the latest tabs' uris so that when the + + # Once a second is updated with the latest tabs' uris so that when the # window is killed the session is saved. self._tabsuris = [] # And index of current page in self._tabsuris @@ -442,13 +442,13 @@ class UzblTabbed: # Holds metadata on the uzbl childen open. self.tabs = {} - + # Generates a unique id for uzbl socket filenames. self.next_pid = counter().next - + # Create main window self.window = gtk.Window() - try: + try: window_size = map(int, config['window_size'].split(',')) self.window.set_default_size(*window_size) @@ -457,7 +457,7 @@ class UzblTabbed: self.window.set_title("Uzbl Browser") self.window.set_border_width(0) - + # Set main window icon icon_path = config['icon_path'] if os.path.exists(icon_path): @@ -467,11 +467,11 @@ class UzblTabbed: icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' if os.path.exists(icon_path): self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) - + # Attach main window event handlers self.window.connect("delete-event", self.quit) - - # Create tab list + + # Create tab list if config['show_tablist']: vbox = gtk.VBox() self.window.add(vbox) @@ -490,13 +490,13 @@ class UzblTabbed: ebox.show() bgcolor = gtk.gdk.color_parse(config['status_background']) ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) - + # Create notebook self.notebook = gtk.Notebook() self.notebook.set_show_tabs(config['show_gtk_tabs']) # Set tab position - allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} if config['gtk_tab_pos'] in allposes.keys(): self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) @@ -523,10 +523,10 @@ class UzblTabbed: else: self.window.add(self.notebook) - + self.window.show() self.wid = self.notebook.window.xid - + # Create the uzbl_tabbed fifo fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) @@ -535,7 +535,7 @@ class UzblTabbed: def _create_fifo_socket(self, fifo_socket): - '''Create interprocess communication fifo socket.''' + '''Create interprocess communication fifo socket.''' if os.path.exists(fifo_socket): if not os.access(fifo_socket, os.F_OK | os.R_OK | os.W_OK): @@ -546,7 +546,7 @@ class UzblTabbed: if not os.path.exists(basedir): rmkdir(basedir) os.mkfifo(self.fifo_socket) - + print "Listening on %s" % self.fifo_socket @@ -563,22 +563,22 @@ class UzblTabbed: del watchers[watcherid] del self._fifos[fifo_socket] - + # Re-open fifo and add listeners. fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) watchers = {} self._fifos[fifo_socket] = (fd, watchers) watcher = lambda key, id: watchers.__setitem__(key, id) - + # Watch for incoming data. gid = gobject.io_add_watch(fd, gobject.IO_IN, self.main_fifo_read) watcher('main-fifo-read', gid) - + # Watch for fifo hangups. gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) watcher('main-fifo-hangup', gid) - - + + def run(self): '''UzblTabbed main function that calls the gtk loop.''' @@ -586,7 +586,7 @@ class UzblTabbed: #timer = "update-tablist" #timerid = gobject.timeout_add(500, self.update_tablist,timer) #self._timers[timer] = timerid - + # Probe clients every second for window titles and location timer = "probe-clients" timerid = gobject.timeout_add(1000, self.probe_clients, timer) @@ -597,7 +597,7 @@ class UzblTabbed: def probe_clients(self, timer_call): '''Probe all uzbl clients for up-to-date window titles and uri's.''' - + sockd = {} uriinventory = [] tabskeys = self.tabs.keys() @@ -616,7 +616,7 @@ class UzblTabbed: sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) - + for sock in reading: uzbl = sockd[sock] uzbl._buffer = sock.recv(1024).replace('\n',' ') @@ -637,7 +637,7 @@ class UzblTabbed: def main_fifo_hangup(self, fd, cb_condition): '''Handle main fifo socket hangups.''' - + # Close fd, re-open fifo_socket and watch. self._setup_fifo_watcher(self.fifo_socket) @@ -661,28 +661,28 @@ class UzblTabbed: except: 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 ) + + # Commands ( [] = optional, {} = required ) # new [uri] - # open new tab and head to optional uri. - # close [tab-num] + # open new tab and head to optional uri. + # 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. + # goto tab n. # first # goto first tab. # last - # goto last tab. + # goto last tab. # title {pid} {document-title} # updates tablist title. # uri {pid} {document-location} @@ -710,7 +710,7 @@ class UzblTabbed: elif cmd[0] == "next": if len(cmd) == 2: self.next_tab(int(cmd[1])) - + else: self.next_tab() @@ -720,7 +720,7 @@ class UzblTabbed: else: self.prev_tab() - + elif cmd[0] == "goto": self.goto_tab(int(cmd[1])) @@ -744,7 +744,7 @@ class UzblTabbed: else: error("parse_command: unknown command %r" % ' '.join(cmd)) - + def get_tab_by_pid(self, pid): '''Return uzbl instance by pid.''' @@ -753,25 +753,25 @@ class UzblTabbed: return self.tabs[tab] return False - + def new_tab(self, uri='', switch=None): '''Add a new tab to the notebook and start a new instance of uzbl. - Use the switch option to negate config['switch_to_new_tabs'] option - when you need to load multiple tabs at a time (I.e. like when + Use the switch option to negate config['switch_to_new_tabs'] option + when you need to load multiple tabs at a time (I.e. like when restoring a session from a file).''' - + pid = self.next_pid() tab = gtk.Socket() tab.show() self.notebook.append_page(tab) sid = tab.get_id() - + fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) socket_file = os.path.join(config['socket_dir'], socket_filename) - + if switch is None: switch = config['switch_to_new_tabs'] @@ -785,26 +785,26 @@ class UzblTabbed: self.tabs[tab] = uzbl cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? - + # Add gobject timer to make sure the config is pushed when fifo socket - # has been created. + # has been created. timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") uzbl.timers['flush-initial-config'] = timerid - + self.update_tablist() def config_uzbl(self, uzbl): - '''Send bind commands for tab new/close/next/prev to a uzbl + '''Send bind commands for tab new/close/next/prev to a uzbl instance.''' binds = [] bind_format = 'bind %s = sh "echo \\\"%s\\\" > \\\"%s\\\""' bind = lambda key, action: binds.append(bind_format % (key, action, \ self.fifo_socket)) - + # Keys are defined in the config section - # bind ( key , command back to fifo ) + # bind ( key , command back to fifo ) bind(config['bind_new_tab'], 'new') bind(config['bind_tab_from_clip'], 'newfromclip') bind(config['bind_tab_from_uri'], 'new %s') @@ -815,38 +815,38 @@ class UzblTabbed: bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') - # uzbl.send via socket or uzbl.write via fifo, I'll try send. + # uzbl.send via socket or uzbl.write via fifo, I'll try send. uzbl.send("\n".join(binds)) def goto_tab(self, index): '''Goto tab n (supports negative indexing).''' - + tabs = list(self.notebook) if 0 <= index < len(tabs): self.notebook.set_current_page(index) self.update_tablist() return None - try: + try: tab = tabs[index] # Update index because index might have previously been a - # negative index. + # negative index. index = tabs.index(tab) self.notebook.set_current_page(index) self.update_tablist() - + except IndexError: pass def next_tab(self, step=1): '''Switch to next tab or n tabs right.''' - + if step < 1: error("next_tab: invalid step %r" % step) return None - + ntabs = self.notebook.get_n_pages() tabn = (self.notebook.get_current_page() + step) % ntabs self.notebook.set_current_page(tabn) @@ -855,7 +855,7 @@ class UzblTabbed: def prev_tab(self, step=1): '''Switch to prev tab or n tabs left.''' - + if step < 1: error("prev_tab: invalid step %r" % step) return None @@ -869,24 +869,24 @@ class UzblTabbed: def close_tab(self, tabn=None): '''Closes current tab. Supports negative indexing.''' - - if tabn is None: + + if tabn is None: tabn = self.notebook.get_current_page() - + else: - try: + try: tab = list(self.notebook)[tabn] - + except IndexError: error("close_tab: invalid index %r" % tabn) return None self.notebook.remove_page(tabn) - + def tab_opened(self, notebook, tab, index): '''Called upon tab creation. Called by page-added signal.''' - + if config['switch_to_new_tabs']: self.notebook.set_focus_child(tab) @@ -897,15 +897,15 @@ class UzblTabbed: def tab_closed(self, notebook, tab, index): - '''Close the window if no tabs are left. Called by page-removed + '''Close the window if no tabs are left. Called by page-removed signal.''' - + if tab in self.tabs.keys(): uzbl = self.tabs[tab] for timer in uzbl.timers.keys(): error("tab_closed: removing timer %r" % timer) gobject.source_remove(uzbl.timers[timer]) - + if uzbl._socket: uzbl._socket.close() uzbl._socket = None @@ -914,7 +914,7 @@ class UzblTabbed: uzbl._socketout = [] uzbl._kill = True del self.tabs[tab] - + if self.notebook.get_n_pages() == 0: self.quit() @@ -925,7 +925,7 @@ class UzblTabbed: def tab_changed(self, notebook, page, index): '''Refresh tab list. Called by switch-page signal.''' - + tab = self.notebook.get_nth_page(index) self.notebook.set_focus_child(tab) self.update_tablist(index) @@ -934,7 +934,7 @@ class UzblTabbed: def update_tablist(self, curpage=None): '''Upate tablist status bar.''' - + show_tablist = config['show_tablist'] show_gtk_tabs = config['show_gtk_tabs'] tab_titles = config['tab_titles'] @@ -957,17 +957,17 @@ class UzblTabbed: tab_format = " [ %d %s ] " else: tab_format = " [ %d ] " - + if show_gtk_tabs: gtk_tab_format = "%d %s" for index, tab in enumerate(self.notebook): if tab not in tabs: continue uzbl = self.tabs[tab] - + if index == curpage: self.window.set_title(title_format % uzbl.title) - + tabtitle = uzbl.title[:max_title_len] if show_ellipsis and len(tabtitle) != len(uzbl.title): tabtitle = "%s\xe2\x80\xa6" % tabtitle[:-1] # Show Ellipsis @@ -987,7 +987,7 @@ class UzblTabbed: pango += tab_format % (tabc, index, textc, tabtitle) else: pango += tab_format % (tabc, textc, index) - + if show_tablist: self.tablist.set_markup(pango) @@ -996,7 +996,7 @@ class UzblTabbed: def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' - + for fifo_socket in self._fifos.keys(): fd, watchers = self._fifos[fifo_socket] os.close(fd) @@ -1005,7 +1005,7 @@ class UzblTabbed: del watchers[watcherid] del self._fifos[fifo_socket] - + for timerid in self._timers.keys(): gobject.source_remove(self._timers[timerid]) del self._timers[timerid] @@ -1020,29 +1020,29 @@ class UzblTabbed: if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): - # Recursive mkdir not rmdir. + # Recursive mkdir not rmdir. rmkdir(dirname) - + sessionstr = '\n'.join(self._tabsuris) h = open(session_file, 'w') h.write('current = %s\n%s' % (self._curpage, sessionstr)) h.close() - + else: # Notebook has no pages so delete session file if it exists. if os.path.isfile(session_file): os.remove(session_file) - gtk.main_quit() + gtk.main_quit() if __name__ == "__main__": - - # Read from the uzbl config into the global config dictionary. + + # Read from the uzbl config into the global config dictionary. readconfig(uzbl_config, config) - + uzbl = UzblTabbed() - + if os.path.isfile(os.path.expandvars(config['session_file'])): h = open(os.path.expandvars(config['session_file']),'r') lines = [line.strip() for line in h.readlines()] @@ -1059,8 +1059,8 @@ if __name__ == "__main__": for (index, url) in enumerate(urls): if current == index: uzbl.new_tab(line, True) - - else: + + else: uzbl.new_tab(line, False) if not len(urls): @@ -1070,5 +1070,3 @@ if __name__ == "__main__": uzbl.new_tab() uzbl.run() - - diff --git a/examples/data/uzbl/scripts/uzblcat b/examples/data/uzbl/scripts/uzblcat index 82341c7..5c3063e 100755 --- a/examples/data/uzbl/scripts/uzblcat +++ b/examples/data/uzbl/scripts/uzblcat @@ -2,15 +2,15 @@ # uzblcat - safely push html to uzbl # See http://www.uzbl.org/wiki/html-mode use strict; use warnings; - + my $html; local $/; # slurp files # automagically choose to read from stdin/files/... $html .= $_ for <>; - + my $endmarker = rand; $endmarker .= rand() while $html =~ /^\Q$endmarker\E$/m; - + print "set base_url = $ENV{BASE_URL}\n" if $ENV{BASE_URL}; print << "EOS"; set html_endmarker = $endmarker diff --git a/examples/data/uzbl/style.css b/examples/data/uzbl/style.css index de0a38b..f9b111e 100644 --- a/examples/data/uzbl/style.css +++ b/examples/data/uzbl/style.css @@ -5,7 +5,7 @@ border-width: thin; } -#uzbl_hint > div { +#uzbl_hint > div { display: inline; border: 2px solid #4a6600; background-color: #b9ff00; @@ -23,4 +23,3 @@ } /* vim:set et ts=4: */ - diff --git a/uzbl.c b/uzbl.c index c31b41c..9b33f33 100644 --- a/uzbl.c +++ b/uzbl.c @@ -2516,7 +2516,7 @@ settings_init () { for (i = 0; default_config[i].command != NULL; i++) { parse_cmd_line(default_config[i].command, NULL); } - + if (g_strcmp0(s->config_file, "-") == 0) { s->config_file = NULL; create_stdin(); diff --git a/uzblctrl.c b/uzblctrl.c index 93584bc..e768b7f 100644 --- a/uzblctrl.c +++ b/uzblctrl.c @@ -33,27 +33,27 @@ main(int argc, char* argv[]) { int s, len; struct sockaddr_un remote; char tmp; - + if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) { perror ("socket"); exit (1); } - + remote.sun_family = AF_UNIX; strcpy (remote.sun_path, (char *) sockpath); len = strlen (remote.sun_path) + sizeof (remote.sun_family); - + if (connect (s, (struct sockaddr *) &remote, len) == -1) { perror ("connect"); exit (1); } - + if ((send (s, command, strlen (command), 0) == -1) || (send (s, "\n", 1, 0) == -1)) { perror ("send"); exit (1); } - + while ((len = recv (s, &tmp, 1, 0))) { putchar(tmp); if (tmp == '\n') @@ -61,7 +61,7 @@ main(int argc, char* argv[]) { } close(s); - + return 0; } else { fprintf(stderr, "Usage: uzblctrl -s /path/to/socket -c \"command\""); -- cgit v1.2.3 From 862965a38b0b17e1a8ae865c29bafcd85d75bd70 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 17 Jul 2009 23:11:24 +0800 Subject: Use built-in os.makedirs instead of homemade mkdirs function. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index d384fc6..9de6fba 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -283,18 +283,6 @@ def readconfig(uzbl_config, config): config[key] = os.path.expandvars(config[key]) -def rmkdir(path): - '''Recursively make directories. - I.e. `mkdir -p /some/nonexistant/path/`''' - - path, sep = os.path.realpath(path), os.path.sep - dirs = path.split(sep) - for i in range(2,len(dirs)+1): - dir = os.path.join(sep,sep.join(dirs[:i])) - if not os.path.exists(dir): - os.mkdir(dir) - - def counter(): '''To infinity and beyond!''' @@ -555,7 +543,8 @@ class UzblTabbed: else: basedir = os.path.dirname(self.fifo_socket) if not os.path.exists(basedir): - rmkdir(basedir) + os.makedirs(basedir) + os.mkfifo(self.fifo_socket) print "Listening on %s" % self.fifo_socket @@ -1032,8 +1021,7 @@ class UzblTabbed: if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): - # Recursive mkdir not rmdir. - rmkdir(dirname) + os.makedirs(dirname) sessionstr = '\n'.join(self._tabsuris) h = open(session_file, 'w') -- cgit v1.2.3 From 17f97643c15981752f867ed7b5ee7684157d5a08 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 17 Jul 2009 22:37:12 +0200 Subject: document fixes + document all variables/constants in readme, so example config can be a bit cleaner --- README | 152 +++++++++++++++++++++++++++++++++----------- docs/TODO | 2 +- examples/config/uzbl/config | 98 ++++------------------------ uzbl.c | 2 +- 4 files changed, 127 insertions(+), 127 deletions(-) (limited to 'examples') diff --git a/README b/README index ef50f14..8adcf99 100644 --- a/README +++ b/README @@ -2,20 +2,20 @@ * people want a browser that does everything * people who want a browser with things like a built-in bookmark manager, address bar, forward/back buttons, ... * people who expect something that works by default. You'll need to read configs and write/edit scripts - +* people who like nothing from this list: mpd, moc, wmii, dwm, awesome, mutt, pine, vim, dmenu, screen, irssi, weechat, bitlbee ### TO NEW PEOPLE: * please read the documentation in /usr/share/uzbl/docs * invoke uzbl --help * to get you started: `XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config uzbl --uri www.archlinux.org` -* study the sample config, have a look at all the bindings, and note how you can call the scripts to load new url from history and the bookmarks file +* try and study the sample config, read the readme to find out how it works. * You can change the url with commands (if you have setup the appropriate keybinds) but to be most effective it's better to do url editing/changing _outside_ of uzbl. Eg, you can use the `load_from_*` dmenu based scripts to pick/edit a url or type a new one. * If you have questions, you are likely to find answers in the FAQ or in the other documentation. ### INTRODUCTION - In my opinion, any program can only be really useful if it complies to the unix philosophy. + Any program can only be really useful if it complies to the unix philosophy. Web browsers are frequent violators of this principle: * They build in way too much things into the browser, dramatically decreasing the options to do things the way you want. @@ -23,11 +23,10 @@ Time to change that! - Here are the general ideas: + Here are the general ideas (not all of these are implemented perfectly yet): * each instance of uzbl renders 1 page (eg it's a small wrapper around webkit), no tabbing, tab previews, or speed dial things. For "multiple instances management" use your window managers, scripts or wrappers. - This way you can get something much more useful than tabbing by default * very simple, plaintext , changeable at runtime configuration * various interfaces for (programmatic) interaction with uzbl (see below) * customizable keyboard shortcuts in vim or emacs style (whatever user wants) @@ -56,7 +55,7 @@ Time to change that! The general idea is that uzbl by default is very bare bones. you can send it commands to update settings and perform actions, through various interfaces. There is a limited default configuration. Please see config.h to see what it contains. By default, there are *no* keybinds defined at all. (Default keybinds would work counterproductive when you try to customize) -For examples of the possibilities what you can do, please see the sample config(s). +For examples of the possibilities what you can do, please see the sample config(s), and uzbl wiki page. There are several interfaces to interact with uzbl: * uzbl --config : will be read line by line, and the commands in it will be executed. useful to configure uzbl at startup. @@ -66,7 +65,6 @@ There are several interfaces to interact with uzbl: By default, the behaviour is modal (vi style): command mode: every keystroke is interpreted to run commands insert mode: keystrokes are not interpreted so you can enter text into html forms - Press ESC/i to toggle command/insert mode But if you don't like modal interfaces, you can set `always_insert_mode` and configure a modkey to execute the commands. (emacs style). There is also support for "chained" commands (multiple characters long) (with backspace/esc shortcuts), and keyworded commands. Also you can have incremental matching on commands or match after pressing return. (see sampleconfig for more info) @@ -161,38 +159,83 @@ The following commands are recognized: - remember to quote the commands; one command must come as one parameter - if you use `chain` with a handler script which must return some output (such as a cookie handler -- uzbl will wait for and use its output), use sync_spawn or sync_sh instead of spawn or sh in the command that should give the output -### JAVASCRIPT HELPER OBJECT +### VARIABLES AND CONSTANTS +Uzbl has a lot of internal variables and constants. You can get the values (using the `print` command, see above), and for variables you can also change the value at +runtime. Some of the values can be passed at start up through commandline arguments, others need to be set by using commands (eg in config file). +Some of them have default values (see config.h) +Some variables have callback functions which will get called after setting the variable to perform some additional logic (see below) + +* Variables: + - uri (callback: load the uri) + - verbose: affects output on stdout + - mode:insert or command mode + - inject_html + - base_url: used when passing html through stdin + - html_endmarker: delimiter when passing html through stdin + - html_mode_timeout: consider end of html input after x seconds when no endmarker found + - keycmd: holds the input buffer (callback: update input buffer) + - status_message (callback: update title) + - show_status: show statusbar or not + - status_top: statusbar on top? + - status_format: marked up, to be expanded string for statusbar (callback: update statusbar) + - status_pbar_done: character to denote done % of pageload + - status_pbar_pending: character to denote pending % of pageload + - status_pbar_width: width of progressbar + - status_background: color which can be used to override Gtk theme. + - insert_indicator: string to denote insert mode + - command_indicator: string to denote command mode + - title_format_long: titlebar string when no statusbar shown (will be expanded + - title_format_short: titlebar string when statusbar shown (will be expanded) + - icon: path to icon for Gtk + - insert_mode: whether insert mode is active + - always_insert_mode: set this to true if you don't like modal (vim-like) interfaces + - reset_command_mode: automatically revert to command mode on pageload (unless always_insert_mode is set) + - modkey: modkey which can be pressed to activate keybind from inside insert mode + - load_finish_handler + - load_start_handler + - load_commit_handler + - history_handler + - download_handler + - cookie_handler + - new_window: handler to execute to invoke new uzbl window (TODO better name) + - fifo_dir: location to store fifo's + - socket_dir: location to store sockets + - http_debug: http debug mode (value 0-3) + - shell_cmd: alias which will be expanded to use shell commands (eg sh -c) + - proxy_url: http traffic socks proxy (eg: http://:) + - max_conns + - max_conns_host + - useragent: to be expanded strin + - zoom_level + - font_size + - monospace_size + - minimum_font_size + - disable_plugins (TODO rename to enable) + - disable_scripts (TODO rename to enable) + - autoload_images + - autoshrink_images: shrink images to window size (default 0) + - enable_spellcheck + - enable_private + - print_backgrounds: print background images? (default 0) + - stylesheet_uri: use this to override the pagelayout with a custom stylesheet + - resizable_text_areas + - default_encoding: iso-8859-1 by default + - enforce_96_dpi: 1 by default + - caret_browsing + +* Constants (not dumpable or writeable): + - WEBKIT_MAJOR: set at compile time + - WEBKIT_MINOR: set at compile time + - WEBKIT_MICRO: set at compile time + - ARCH_UZBL: set at compile time + - COMMIT: set at compile time + - LOAD_PROGRESS + - LOAD_PROGRESSBAR + - TITLE + - SELECTED_URI + - MODE + - NAME: name of the uzbl instance (Xorg window id, unless set by cmdline arg) (TODO: can't we make this a variable?) -Javascript code run from uzbl is given a special object in the global namespace which gives special privileges to these scripts. This object is called `Uzbl`, and it is added and removed before and after the script execution so that it is hidden to web javascripts (There is no race condition, since all the javascript code runs in a single thread) - -Currently, the `Uzbl` object provides only one function: - -* `Uzbl.run( )` - - command is any uzbl command as defined above - - return value: a string, either empty or containing the output of the command. Very few commands return their output currently, including js, script, and print. - - Examples: - * `Uzbl.run("spawn insert_bookmark.sh")` - * `uri = Uzbl.run("print @uri")` (see variable expansion below) - -### JAVASCRIPT SECURITY - -Since defined variables and functions are set in the global namespace (`window` object) as default, it is recommended to wrap your scripts like this: - - (function(Uzbl) { - ... - })(Uzbl); - -This way, everything is kept private. It also turns Uzbl into a local variable, which can be accessed from callback functions defined inside. However for some situations, isolating everything isn't an option, for example, with binds. You can define them directly in the script body, and use `var Uzbl = window.Uzbl;` to make the Uzbl variable local, as in the following example: - - function f() { - var Uzbl = window.Uzbl; - Uzbl.run(...); - setTimeout(function() { - Uzbl.run(...); - }, 500); - } - -Copying the Uzbl object and creating public functions should be taken with care to avoid creating security holes. Keep in mind that the "f" function above would be defined in the `window` object, and as such any javascript in the current page can call it. ### VARIABLE EXPANSION AND COMMAND/JAVA SCRIPT SUBSTITUTION @@ -324,6 +367,39 @@ The script specific arguments are this: Custom, userdefined scripts (`spawn foo bar`) get first the arguments as specified in the config and then the above 7 are added at the end. +### JAVASCRIPT HELPER OBJECT + +Javascript code run from uzbl is given a special object in the global namespace which gives special privileges to these scripts. This object is called `Uzbl`, and it is added and removed before and after the script execution so that it is hidden to web javascripts (There is no race condition, since all the javascript code runs in a single thread) + +Currently, the `Uzbl` object provides only one function: + +* `Uzbl.run( )` + - command is any uzbl command as defined above + - return value: a string, either empty or containing the output of the command. Very few commands return their output currently, including js, script, and print. + - Examples: + * `Uzbl.run("spawn insert_bookmark.sh")` + * `uri = Uzbl.run("print @uri")` (see variable expansion below) + +### JAVASCRIPT SECURITY + +Since defined variables and functions are set in the global namespace (`window` object) as default, it is recommended to wrap your scripts like this: + + (function(Uzbl) { + ... + })(Uzbl); + +This way, everything is kept private. It also turns Uzbl into a local variable, which can be accessed from callback functions defined inside. However for some situations, isolating everything isn't an option, for example, with binds. You can define them directly in the script body, and use `var Uzbl = window.Uzbl;` to make the Uzbl variable local, as in the following example: + + function f() { + var Uzbl = window.Uzbl; + Uzbl.run(...); + setTimeout(function() { + Uzbl.run(...); + }, 500); + } + +Copying the Uzbl object and creating public functions should be taken with care to avoid creating security holes. Keep in mind that the "f" function above would be defined in the `window` object, and as such any javascript in the current page can call it. + ### COMMAND LINE ARGUMENTS uzbl [ uri ] -u, --uri=URI alternative way to load uri on start. (equivalent to 'set uri = URI') diff --git a/docs/TODO b/docs/TODO index 0b4c433..45f4539 100644 --- a/docs/TODO +++ b/docs/TODO @@ -40,7 +40,7 @@ More or less in order of importance/urgency * check for real command name, not just the first letter. * Allow the spacebar to be binded to a command * let users attach handlers to the most common events/signals in uzbl. - great use case: automatically calling formfiller for certain sites + great use case: automatically calling formfiller for certain sites, doing stuff at uzbl startup, etc * document: stylesheet overridding formfiller diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e75789d..ab2cf7f 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,104 +1,38 @@ # example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) -# keyboard behavior is vimstyle by default, but you can change this -# set always_insert_mode to always be in insert mode and disable going out of it. -# if you do this, make sure you've set a modkey so you can reach the commands -# from insert mode by combining them with the modkey +# keyboard behavior in this sample config is sort of vimstyle -# Usually you want to spawn a script to handle things, but any command (such as sh) can be used +# Handlers set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py - -# Control how new windows should open -#set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour -#set new_window = sh 'echo uri "$8" > $4' # open in same window - -# You can bind whatever things (spawn , script ,..) to some events TODO: make events system more generic +#set new_window = sh 'echo uri "$8" > $4' # open in same window +set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv set load_finish_handler = set status_message = done -set minimum_font_size = 6 -set font_size = 11 -## monospace_size defaults to font_size, but you can alter it independently -#set monospace_size = 10 - -## Display or supress images within html sites -#set autoload_images = 0 - -## Shrink images to window size -#set autoshrink_images = 0 - -## Spellchecker -#set enable_spellcheck = 1 - -## Private browsing -#set enable_private = 0 - -## The URI of a stylesheet that is applied to every page -#set stylesheet_uri = http://www.user.com/mystylelesheet.css - -## enable/disable JavaScript -#set disable_scripts = 1 - -## Whether text areas are resizable -#set resizeable_text_areas = 1 - -## The default encoding used to display text -#set default_encoding = iso-8859-1 - -## Whether background images should be printed -#set print_background = 0 - -## Enforce a resolution of 96 DPI. This is meant for compatibility with -## web pages which cope badly with different screen resolutions -#set enforce_96_dpi = 1 - - -# -# use with bind ... = sh -set shell_cmd = sh -c - - # Behaviour and appearance set show_status = 1 -# you can optionally use this setting to override the background color of the statusbar from your GTK theme. set status_background = #303030 set status_format = [\@[\@MODE]\@] [\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ set status_top = 0 -# define how your titlebar should look like. (short = statusbar is also shown, long = show everything you must see if statusbar is off) -set title_format_short = \@TITLE - Uzbl browser <\@NAME> -set title_format_long = \@keycmd \@MODE \@TITLE - Uzbl browser <\@NAME> > \@SELECTED_URI -# set the characters to use for, and the width of the progress bar -set status_pbar_done = * -set status_pbar_pending = - -set status_pbar_width = 12 set insert_indicator = I set command_indicator = C -set modkey = Mod1 -# reset to command mode when new page is loaded -set reset_command_mode = 1 -# this var has precedence over reset_command_mode -set always_insert_mode = 0 - -# to start a local socks server, do : ssh -fND localhost:8118 localhost -#set proxy_url = http://127.0.0.1:8118 -#values 0-3 -#set http_debug = 0 -#set useragent = uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) -# Example user agent containing everything: -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -s)@ @(uname -n)@ @(uname -r)@ @(uname -v)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) -#set max_conns = 0 -#set max_conns_host = 0 +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -s)@ @(uname -n)@ @(uname -r)@ @(uname -v)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp set socket_dir = /tmp +set shell_cmd = sh -c + +# Keyboard interface +set modkey = Mod1 +# like this you can enter any command at runtime, interactively. prefixed by ':' +bind :_ = chain '%s' -# Key bindings bind j = scroll_vert 20 bind k = scroll_vert -20 bind h = scroll_horz -20 @@ -116,18 +50,12 @@ bind T = toggle_zoom_type bind 1 = sh "echo set zoom_level = 1.0 > $4" bind 2 = sh "echo set zoom_level = 2.0 > $4" bind t = toggle_status -# Hilight matches. Notice the * after the slash - it makes the command incremental, i.e. gets called -# on every character you type. You can do `bind /_ = search %s' if you want it less interactive. bind /* = search %s bind ?* = search_reverse %s #jump to next bind n = search bind N = search_reverse bind gh = uri http://www.uzbl.org - -# like this you can enter any command at runtime, interactively. prefixed by ':' -bind :_ = chain '%s' - # shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..' bind o _ = uri %s # shortcut to set variables @@ -188,10 +116,6 @@ bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s # using strings, not polished yet: bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s -# you can use this to disable all plugins -set disable_plugins = 0 - -set icon = ./uzbl.png # "home" page if you will set uri = uzbl.org diff --git a/uzbl.c b/uzbl.c index d7d0f83..7129bee 100644 --- a/uzbl.c +++ b/uzbl.c @@ -2653,7 +2653,7 @@ initialize(int argc, char *argv[]) { if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR) fprintf(stderr, "uzbl: error hooking SIGALARM\n"); - uzbl.gui.sbar.progress_s = g_strdup("="); + uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h uzbl.gui.sbar.progress_u = g_strdup("·"); uzbl.gui.sbar.progress_w = 10; -- cgit v1.2.3 From 6618dc4cb5cbc2746aed7a256e19d72788db2d23 Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 19 Jul 2009 19:24:43 +0100 Subject: Added scheme_handler callback. Conflicts: uzbl.c uzbl.h --- README | 1 + examples/config/uzbl/config | 1 + examples/data/uzbl/scripts/scheme.py | 14 ++++++++++++++ uzbl.c | 28 ++++++++++++++++++++++++++++ uzbl.h | 4 ++++ 5 files changed, 48 insertions(+) create mode 100755 examples/data/uzbl/scripts/scheme.py (limited to 'examples') diff --git a/README b/README index d73bab1..73b99fd 100644 --- a/README +++ b/README @@ -198,6 +198,7 @@ Some variables have callback functions which will get called after setting the v - download_handler - cookie_handler - new_window: handler to execute to invoke new uzbl window (TODO better name) + - scheme_handler: handler to be executed for all URIs not of the http/https/data schema - fifo_dir: location to store fifo's - socket_dir: location to store sockets - http_debug: http debug mode (value 0-3) diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index ab2cf7f..04e482b 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -9,6 +9,7 @@ set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour +set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv set load_finish_handler = set status_message = done diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py new file mode 100755 index 0000000..c09db08 --- /dev/null +++ b/examples/data/uzbl/scripts/scheme.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os, subprocess, sys, urlparse + +if __name__ == '__main__': + uri = sys.argv[8] + u = urlparse.urlparse(uri) + if u.scheme == 'mailto': + subprocess.call(['xterm', '-e', 'mail %s' % u.path]) + elif u.scheme == 'xmpp': + subprocess.call(['gajim-remote', 'open_chat', uri]) + #elif u.scheme == 'git': + #os.chdir(os.path.expanduser('~/src')) + #subprocess.call(['git', 'clone', uri]) diff --git a/uzbl.c b/uzbl.c index 64bdf15..bb8c152 100644 --- a/uzbl.c +++ b/uzbl.c @@ -135,6 +135,7 @@ const struct { { "download_handler", PTR_V(uzbl.behave.download_handler, STR, 1, NULL)}, { "cookie_handler", PTR_V(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, { "new_window", PTR_V(uzbl.behave.new_window, STR, 1, NULL)}, + { "scheme_handler", PTR_V(uzbl.behave.scheme_handler, STR, 1, NULL)}, { "fifo_dir", PTR_V(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, { "socket_dir", PTR_V(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, { "http_debug", PTR_V(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, @@ -519,6 +520,32 @@ catch_alrm(int s) { /* --- CALLBACKS --- */ +gboolean +navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { + (void) web_view; + (void) frame; + (void) navigation_action; + (void) policy_decision; + (void) user_data; + const gchar* uri = webkit_network_request_get_uri (request); + if (uzbl.state.verbose) + printf("Navigation requested -> %s\n", uri); + SoupURI *suri = soup_uri_new(uri); + if (suri && strcmp (suri->scheme, "http") && + strcmp (suri->scheme, "https") && + strcmp (suri->scheme, "data") && + strcmp (suri->scheme, "about")) { + if (uzbl.behave.scheme_handler) { + GString *s = g_string_new (""); + g_string_printf(s, "'%s'", uri); + run_handler(uzbl.behave.scheme_handler, s->str); + webkit_web_policy_decision_ignore(policy_decision); + return TRUE; + } + } + return FALSE; +} + gboolean new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { (void) web_view; @@ -2168,6 +2195,7 @@ create_browser () { g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view); diff --git a/uzbl.h b/uzbl.h index 130f33f..55243ee 100644 --- a/uzbl.h +++ b/uzbl.h @@ -116,6 +116,7 @@ typedef struct { gchar* download_handler; gchar* cookie_handler; gchar* new_window; + gchar* scheme_handler; gboolean always_insert_mode; gboolean show_status; gboolean insert_mode; @@ -240,6 +241,9 @@ set_var_value(gchar *name, gchar *val); void print(WebKitWebView *page, GArray *argv, GString *result); +gboolean +navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); + gboolean new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); -- cgit v1.2.3 From 13dfbb00e1b7b581444f856ae1d90a7fcfe3dd0f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 20 Jul 2009 19:45:41 +0800 Subject: Added support for uzbl's new window handler in uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 9de6fba..cffdf07 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -64,6 +64,7 @@ # socket_dir = /tmp # icon_path = $HOME/.local/share/uzbl/uzbl.png # session_file = $HOME/.local/share/uzbl/session +# capture_new_windows = 1 # # Window options: # status_background = #303030 @@ -186,6 +187,7 @@ config = { 'socket_dir': '/tmp', # Path to look for uzbl socket 'icon_path': os.path.join(data_dir, 'uzbl.png'), 'session_file': os.path.join(data_dir, 'session'), + 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows # Window options 'status_background': "#303030", # Default background for all panels @@ -799,12 +801,17 @@ class UzblTabbed: instance.''' binds = [] - bind_format = 'bind %s = sh "echo \\\"%s\\\" > \\\"%s\\\""' - bind = lambda key, action: binds.append(bind_format % (key, action, \ + bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""' + bind = lambda key, action: binds.append(bind_format % (key, action,\ self.fifo_socket)) - # Keys are defined in the config section - # bind ( key , command back to fifo ) + sets = [] + set_format = r'set %s = sh \"echo \\"%s\\" > \\"%s\\""' + set = lambda key, action: binds.append(set_format % (key, action,\ + self.fifo_socket)) + + # Bind definitions here + # bind(key, command back to fifo) bind(config['bind_new_tab'], 'new') bind(config['bind_tab_from_clip'], 'newfromclip') bind(config['bind_tab_from_uri'], 'new %s') @@ -814,9 +821,14 @@ class UzblTabbed: bind(config['bind_goto_tab'], 'goto %s') bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') - - # uzbl.send via socket or uzbl.write via fifo, I'll try send. - uzbl.send("\n".join(binds)) + + # Set definitions here + # set(key, command back to fifo) + if config['capture_new_windows']: + set("new_window", r'new $8') + + # Send config to uzbl instance via its socket file. + uzbl.send("\n".join(binds+sets)) def goto_tab(self, index): -- cgit v1.2.3 From 5ba89ab331bd2f28fa02c62c50e02f608f8963a7 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 20 Jul 2009 22:02:22 +0800 Subject: Use dict.items() when iterating over a dict. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index cffdf07..b84f758 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -273,9 +273,10 @@ def readconfig(uzbl_config, config): rawconfig = h.read() h.close() + configkeys, strip = config.keys(), str.strip for (key, value) in findsets(rawconfig): - key, value = key.strip(), value.strip() - if key not in config.keys(): continue + key, value = strip(key), strip(value) + if key not in configkeys: continue if isint(value): value = int(value) config[key] = value @@ -560,8 +561,8 @@ class UzblTabbed: if fifo_socket in self._fifos.keys(): fd, watchers = self._fifos[fifo_socket] os.close(fd) - for watcherid in watchers.keys(): - gobject.source_remove(watchers[watcherid]) + for (watcherid, gid) in watchers.items(): + gobject.source_remove(gid) del watchers[watcherid] del self._fifos[fifo_socket] @@ -750,9 +751,9 @@ class UzblTabbed: def get_tab_by_pid(self, pid): '''Return uzbl instance by pid.''' - for tab in self.tabs.keys(): - if self.tabs[tab].pid == pid: - return self.tabs[tab] + for (tab, uzbl) in self.tabs.items(): + if uzbl.pid == pid: + return uzbl return False @@ -914,9 +915,10 @@ class UzblTabbed: if tab in self.tabs.keys(): uzbl = self.tabs[tab] - for timer in uzbl.timers.keys(): + for (timer, gid) in uzbl.timers.items(): error("tab_closed: removing timer %r" % timer) - gobject.source_remove(uzbl.timers[timer]) + gobject.source_remove(gid) + del uzbl.timers[timer] if uzbl._socket: uzbl._socket.close() @@ -1010,17 +1012,16 @@ class UzblTabbed: def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' - for fifo_socket in self._fifos.keys(): - fd, watchers = self._fifos[fifo_socket] + for (fifo_socket, (fd, watchers)) in self._fifos.items(): os.close(fd) - for watcherid in watchers.keys(): - gobject.source_remove(watchers[watcherid]) + for (watcherid, gid) in watchers.items(): + gobject.source_remove(gid) del watchers[watcherid] del self._fifos[fifo_socket] - for timerid in self._timers.keys(): - gobject.source_remove(self._timers[timerid]) + for (timerid, gid) in self._timers.items(): + gobject.source_remove(gid) del self._timers[timerid] if os.path.exists(self.fifo_socket): -- cgit v1.2.3 From e52ee26e2ca27f45ec8d96eb09983384f17d4404 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 20 Jul 2009 22:10:51 +0800 Subject: uzbl takes the first un-parsed argument as the uri, no need for --uri --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index b84f758..a1ce952 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -769,6 +769,7 @@ class UzblTabbed: tab.show() self.notebook.append_page(tab) sid = tab.get_id() + uri = uri.strip() fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) @@ -778,11 +779,6 @@ class UzblTabbed: if switch is None: switch = config['switch_to_new_tabs'] - - # Create meta-instance and spawn child - if len(uri.strip()): - uri = '--uri %s' % uri - uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ uri, switch) self.tabs[tab] = uzbl -- cgit v1.2.3 From 610391eb2859972ba7a8fec5de9038f9db117bc1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 20 Jul 2009 22:34:38 +0800 Subject: Found and fixed the real source of the state restoration bug. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index a1ce952..3cac08a 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -781,6 +781,10 @@ class UzblTabbed: uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ uri, switch) + + if len(uri): + uri = "--uri %s" % uri + self.tabs[tab] = uzbl cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? @@ -1064,13 +1068,13 @@ if __name__ == "__main__": else: urls.append(line.strip()) - + for (index, url) in enumerate(urls): if current == index: - uzbl.new_tab(line, True) + uzbl.new_tab(url, True) else: - uzbl.new_tab(line, False) + uzbl.new_tab(url, False) if not len(urls): uzbl.new_tab() -- cgit v1.2.3 From dd7e57ebc4dc3d4e12a618ed843c5f4a52194cd3 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 20 Jul 2009 23:55:22 +0800 Subject: uzbl_tabbed.py modified to use json for state saving & restoration. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 3cac08a..7a79c96 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -63,7 +63,7 @@ # fifo_dir = /tmp # socket_dir = /tmp # icon_path = $HOME/.local/share/uzbl/uzbl.png -# session_file = $HOME/.local/share/uzbl/session +# session_file = $HOME/.local/share/uzbl/session.json # capture_new_windows = 1 # # Window options: @@ -140,6 +140,9 @@ import socket import random import hashlib +# simplejson required for session saving & restoration. +import simplejson as json + pygtk.require('2.0') def error(msg): @@ -186,7 +189,7 @@ config = { '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'), - 'session_file': os.path.join(data_dir, 'session'), + 'session_file': os.path.join(data_dir, 'session.json'), 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows # Window options @@ -316,14 +319,14 @@ class UzblTabbed: '''Uzbl instance meta-data/meta-action object.''' def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ - uri, switch): + uri, title, switch): self.parent = parent self.tab = tab self.fifo_socket = fifo_socket self.socket_file = socket_file self.pid = pid - self.title = config['new_tab_title'] + self.title = title self.uri = uri self.timers = {} self._lastprobe = 0 @@ -436,10 +439,8 @@ class UzblTabbed: self._timers = {} self._buffer = "" - # Once a second is updated with the latest tabs' uris so that when the - # window is killed the session is saved. - self._tabsuris = [] - # And index of current page in self._tabsuris + # Is updated periodically with the current uzbl_tabbed.py state. + self._state = [] self._curpage = 0 # Holds metadata on the uzbl childen open. @@ -602,19 +603,19 @@ class UzblTabbed: '''Probe all uzbl clients for up-to-date window titles and uri's.''' sockd = {} - uriinventory = [] + state = [] tabskeys = self.tabs.keys() notebooklist = list(self.notebook) for tab in notebooklist: if tab not in tabskeys: continue uzbl = self.tabs[tab] - uriinventory.append(uzbl.uri) + state += [(uzbl.uri, uzbl.title),] uzbl.probe() if uzbl._socket: - sockd[uzbl._socket] = uzbl + sockd[uzbl._socket] = uzbl - self._tabsuris = uriinventory + self._state = state self._curpage = self.notebook.get_current_page() sockets = sockd.keys() @@ -758,7 +759,7 @@ class UzblTabbed: return False - def new_tab(self, uri='', switch=None): + def new_tab(self, uri='', title='', switch=None): '''Add a new tab to the notebook and start a new instance of uzbl. Use the switch option to negate config['switch_to_new_tabs'] option when you need to load multiple tabs at a time (I.e. like when @@ -778,12 +779,15 @@ class UzblTabbed: if switch is None: switch = config['switch_to_new_tabs'] + + if not title: + title = config['new_tab_title'] uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ - uri, switch) + uri, title, switch) if len(uri): - uri = "--uri %s" % uri + uri = "--uri %r" % uri self.tabs[tab] = uzbl cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) @@ -1030,15 +1034,17 @@ class UzblTabbed: if config['save_session']: session_file = config['session_file'] - if len(self._tabsuris): + if len(self._state): if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): os.makedirs(dirname) - sessionstr = '\n'.join(self._tabsuris) + session = {'curtab': self._curpage, + 'state': self._state} + h = open(session_file, 'w') - h.write('current = %s\n%s' % (self._curpage, sessionstr)) + h.write(json.dumps(session)) h.close() else: @@ -1055,28 +1061,23 @@ if __name__ == "__main__": readconfig(uzbl_config, config) uzbl = UzblTabbed() + session_file = config['session_file'] + if os.path.isfile(os.path.expandvars(session_file)): + try: + h = open(os.path.expandvars(session_file),'r') + rawjson = h.read() + h.close() + session = json.loads(rawjson) + currenttab = session['curtab'] + for (index, (uri, title)) in enumerate(session['state']): + uzbl.new_tab(uri=uri, title=title, switch=(currenttab == index)) - if os.path.isfile(os.path.expandvars(config['session_file'])): - h = open(os.path.expandvars(config['session_file']),'r') - lines = [line.strip() for line in h.readlines()] - h.close() - current = 0 - urls = [] - for line in lines: - if line.startswith("current"): - current = int(line.split()[-1]) - - else: - urls.append(line.strip()) - - for (index, url) in enumerate(urls): - if current == index: - uzbl.new_tab(url, True) - - else: - uzbl.new_tab(url, False) + if not len(session['state']): + uzbl.new_tab() - if not len(urls): + except: + error("Error loading jsonified state from %r" % session_file) + os.remove(session_file) uzbl.new_tab() else: -- cgit v1.2.3 From cf6a5628e03b2c958ec716e40e0d1b493571d66d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 21 Jul 2009 21:38:58 +0800 Subject: Huge refactorisation of session handling in uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 169 ++++++++++++++++++++++-------- 1 file changed, 123 insertions(+), 46 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 7a79c96..552ff45 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -60,10 +60,11 @@ # # Core options: # save_session = 1 +# json_session = 1 # fifo_dir = /tmp # socket_dir = /tmp # icon_path = $HOME/.local/share/uzbl/uzbl.png -# session_file = $HOME/.local/share/uzbl/session.json +# session_file = $HOME/.local/share/uzbl/session # capture_new_windows = 1 # # Window options: @@ -140,9 +141,6 @@ import socket import random import hashlib -# simplejson required for session saving & restoration. -import simplejson as json - pygtk.require('2.0') def error(msg): @@ -186,10 +184,11 @@ config = { # Core options 'save_session': True, # Save session in file when quit + 'json_session': True, # Use json to save session. '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'), - 'session_file': os.path.join(data_dir, 'session.json'), + 'session_file': os.path.join(data_dir, 'session'), 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows # Window options @@ -439,9 +438,9 @@ class UzblTabbed: self._timers = {} self._buffer = "" - # Is updated periodically with the current uzbl_tabbed.py state. - self._state = [] - self._curpage = 0 + # This is updated periodically with the current state. + # Tabs is a list of (url, title) tuples. + self._state = {'curtab': 0, 'tabs': []} # Holds metadata on the uzbl childen open. self.tabs = {} @@ -535,7 +534,7 @@ class UzblTabbed: self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) self._create_fifo_socket(self.fifo_socket) self._setup_fifo_watcher(self.fifo_socket) - + def _create_fifo_socket(self, fifo_socket): '''Create interprocess communication fifo socket.''' @@ -585,7 +584,13 @@ class UzblTabbed: def run(self): '''UzblTabbed main function that calls the gtk loop.''' - + + if config['save_session']: + self.load_session() + + if not len(self.tabs): + self.new_tab() + # Update tablist timer #timer = "update-tablist" #timerid = gobject.timeout_add(500, self.update_tablist,timer) @@ -601,22 +606,28 @@ class UzblTabbed: def probe_clients(self, timer_call): '''Probe all uzbl clients for up-to-date window titles and uri's.''' + + save_session = config['save_session'] sockd = {} - state = [] + if save_session: + session = [] tabskeys = self.tabs.keys() notebooklist = list(self.notebook) for tab in notebooklist: if tab not in tabskeys: continue uzbl = self.tabs[tab] - state += [(uzbl.uri, uzbl.title),] uzbl.probe() if uzbl._socket: sockd[uzbl._socket] = uzbl + + if save_session: + session += [(uzbl.uri, uzbl.title),] - self._state = state - self._curpage = self.notebook.get_current_page() + if save_session: + self._state['tabs'] = session + self._state['curtab'] = self.notebook.get_current_page() sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) @@ -1013,6 +1024,93 @@ class UzblTabbed: return True + def save_session(self, session_file=None): + '''Save the current session to file for restoration on next load.''' + + strip = str.strip + + if session_file is None: + session_file = config['session_file'] + + if config['json_session']: + session = json.dumps(self._state) + + else: + lines = ["curtab = %d" % self._state['curtab'],] + for (uri, title) in self._state['tabs']: + lines += ["%s\t%s" % (strip(uri), strip(title)),] + + session = "\n".join(lines) + + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + h = open(session_file, 'w') + h.write(session) + h.close() + + + def load_session(self, session_file=None): + '''Load a saved session from file.''' + + default_path = False + strip = str.strip + json_session = config['json_session'] + + if session_file is None: + default_path = True + session_file = config['session_file'] + + if not os.path.isfile(session_file): + return False + + h = open(session_file, 'r') + raw = h.read() + h.close() + + if json_session: + if sum([1 for s in raw.split("\n") if strip(s)]) != 1: + error("Warning: The session file %r does not look json. "\ + "Trying to load it as a non-json session file."\ + % session_file) + json_session = False + + if json_session: + try: + session = json.loads(raw) + curtab, tabs = session['curtab'], session['tabs'] + + except: + if not default_path: + error("Failed to load json session from %r"\ + % session_file) + return None + + else: + tabs = [] + strip = str.strip + curtab, tabs = 0, [] + lines = [s for s in raw.split("\n") if strip(s)] + if len(lines) < 2: + error("Warning: The non-json session file %r looks invalid."\ + % session_file) + return None + + for line in lines: + if line.startswith("curtab"): + curtab = int(line.split()[-1]) + + else: + uri, title = line.split("\t") + tabs += [(strip(uri), strip(title)),] + + # Now populate notebook with the loaded session. + for (index, (uri, title)) in enumerate(tabs): + self.new_tab(uri=uri, title=title, switch=(curtab==index)) + + def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' @@ -1033,19 +1131,8 @@ class UzblTabbed: print "Unlinked %s" % self.fifo_socket if config['save_session']: - session_file = config['session_file'] - if len(self._state): - if not os.path.isfile(session_file): - dirname = os.path.dirname(session_file) - if not os.path.isdir(dirname): - os.makedirs(dirname) - - session = {'curtab': self._curpage, - 'state': self._state} - - h = open(session_file, 'w') - h.write(json.dumps(session)) - h.close() + if len(self._state['tabs']): + self.save_session() else: # Notebook has no pages so delete session file if it exists. @@ -1060,27 +1147,17 @@ if __name__ == "__main__": # Read from the uzbl config into the global config dictionary. readconfig(uzbl_config, config) - uzbl = UzblTabbed() - session_file = config['session_file'] - if os.path.isfile(os.path.expandvars(session_file)): + if config['json_session']: try: - h = open(os.path.expandvars(session_file),'r') - rawjson = h.read() - h.close() - session = json.loads(rawjson) - currenttab = session['curtab'] - for (index, (uri, title)) in enumerate(session['state']): - uzbl.new_tab(uri=uri, title=title, switch=(currenttab == index)) - - if not len(session['state']): - uzbl.new_tab() + import simplejson as json except: - error("Error loading jsonified state from %r" % session_file) - os.remove(session_file) - uzbl.new_tab() - - else: - uzbl.new_tab() + error("Warning: json_session set but cannot import the python "\ + "module simplejson. Fix: \"set json_session = 0\" or "\ + "install the simplejson python module to remove this warning.") + config['json_session'] = False + uzbl = UzblTabbed() uzbl.run() + + -- cgit v1.2.3 From fdbc0adb186d0abe0de1e0164c5de9d533748bdd Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Wed, 22 Jul 2009 00:18:57 +0100 Subject: Only navigate to URI if scheme_handler doesn't print "USED". --- examples/data/uzbl/scripts/scheme.py | 22 +++++++++++++----- uzbl.c | 43 +++++++++++++++++++++++++++++++----- uzbl.h | 3 +++ 3 files changed, 57 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index c09db08..dde9ba1 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -2,13 +2,25 @@ import os, subprocess, sys, urlparse +def detach_open(cmd): + # Thanks to the vast knowledge of Laurence Withers (lwithers) and this message: + # http://mail.python.org/pipermail/python-list/2006-November/587523.html + if not os.fork(): + null = os.open(os.devnull,os.O_WRONLY) + for i in range(3): os.dup2(null,i) + os.close(null) + subprocess.Popen(cmd) + if __name__ == '__main__': uri = sys.argv[8] u = urlparse.urlparse(uri) if u.scheme == 'mailto': - subprocess.call(['xterm', '-e', 'mail %s' % u.path]) + detach_open(['xterm', '-e', 'mail %s' % u.path]) elif u.scheme == 'xmpp': - subprocess.call(['gajim-remote', 'open_chat', uri]) - #elif u.scheme == 'git': - #os.chdir(os.path.expanduser('~/src')) - #subprocess.call(['git', 'clone', uri]) + detach_open(['gajim-remote', 'open_chat', uri]) + elif u.scheme == 'git': + detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src')) + else: + print 'DIY!' + exit() + print 'USED' diff --git a/uzbl.c b/uzbl.c index 1a5094e..381222d 100644 --- a/uzbl.c +++ b/uzbl.c @@ -135,7 +135,7 @@ const struct { { "download_handler", PTR_V(uzbl.behave.download_handler, STR, 1, NULL)}, { "cookie_handler", PTR_V(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)}, { "new_window", PTR_V(uzbl.behave.new_window, STR, 1, NULL)}, - { "scheme_handler", PTR_V(uzbl.behave.scheme_handler, STR, 1, NULL)}, + { "scheme_handler", PTR_V(uzbl.behave.scheme_handler, STR, 1, cmd_scheme_handler)}, { "fifo_dir", PTR_V(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)}, { "socket_dir", PTR_V(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)}, { "http_debug", PTR_V(uzbl.behave.http_debug, INT, 1, cmd_http_debug)}, @@ -525,12 +525,15 @@ navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNe (void) web_view; (void) frame; (void) navigation_action; - (void) policy_decision; (void) user_data; + const gchar* uri = webkit_network_request_get_uri (request); + SoupURI *suri = soup_uri_new(uri); + gboolean decision_made = FALSE; + if (uzbl.state.verbose) printf("Navigation requested -> %s\n", uri); - SoupURI *suri = soup_uri_new(uri); + if (suri && strcmp (suri->scheme, "http") && strcmp (suri->scheme, "https") && strcmp (suri->scheme, "data") && @@ -539,12 +542,27 @@ navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNe if (uzbl.behave.scheme_handler) { GString *s = g_string_new (""); g_string_printf(s, "'%s'", uri); + run_handler(uzbl.behave.scheme_handler, s->str); - webkit_web_policy_decision_ignore(policy_decision); - return TRUE; + + if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { + char *p = strchr(uzbl.comm.sync_stdout, '\n' ); + if ( p != NULL ) *p = '\0'; + if (!strcmp(uzbl.comm.sync_stdout, "USED")) { + webkit_web_policy_decision_ignore(policy_decision); + decision_made = TRUE; + } + } + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + g_string_free(s, TRUE); } } - return FALSE; + if (!decision_made) + webkit_web_policy_decision_use(policy_decision); + + return TRUE; } gboolean @@ -1640,6 +1658,19 @@ cmd_cookie_handler() { g_strfreev (split); } +void +cmd_scheme_handler() { + gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.scheme_handler); + uzbl.behave.scheme_handler = + g_strdup_printf("sync_%s %s", split[0], split[1]); + } + g_strfreev (split); +} + void cmd_fifo_dir() { uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); diff --git a/uzbl.h b/uzbl.h index 55243ee..b0a0171 100644 --- a/uzbl.h +++ b/uzbl.h @@ -505,6 +505,9 @@ set_icon(); void cmd_cookie_handler(); +void +cmd_scheme_handler(); + void move_statusbar(); -- cgit v1.2.3 From c6d4b338203c436d5a9da38a67701b14b6ee3510 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 22 Jul 2009 12:25:42 +0800 Subject: Added session preset adding/saving/listing/deleting. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 211 ++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 52 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 552ff45..8de3006 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -51,6 +51,7 @@ # tablist_top = 1 # gtk_tab_pos = (top|left|bottom|right) # switch_to_new_tabs = 1 +# capture_new_windows = 1 # # Tab title options: # tab_titles = 1 @@ -58,17 +59,18 @@ # max_title_len = 50 # show_ellipsis = 1 # -# Core options: +# Session options: # save_session = 1 # json_session = 1 +# session_file = $HOME/.local/share/uzbl/session +# +# Inherited uzbl options: # fifo_dir = /tmp # socket_dir = /tmp # icon_path = $HOME/.local/share/uzbl/uzbl.png -# session_file = $HOME/.local/share/uzbl/session -# capture_new_windows = 1 +# status_background = #303030 # # Window options: -# status_background = #303030 # window_size = 800,800 # # And the key bindings: @@ -81,6 +83,13 @@ # bind_goto_tab = gi_ # bind_goto_first = g< # bind_goto_last = g> +# bind_clean_slate = gQ +# +# Session preset key bindings: +# bind_save_preset = gsave _ +# bind_load_preset = gload _ +# bind_del_preset = gdel _ +# bind_list_presets = glist # # And uzbl_tabbed.py takes care of the actual binding of the commands via each # instances fifo socket. @@ -123,7 +132,6 @@ # - check spelling. # - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into # the collective. Resistance is futile! -# - on demand store the session to file (need binding & command for that) import pygtk @@ -175,6 +183,7 @@ config = { 'tablist_top': True, # Display tab-list at top of window 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) 'switch_to_new_tabs': True, # Upon opening a new tab switch to it + 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows # Tab title options 'tab_titles': True, # Display tab titles (else only tab-nums) @@ -182,29 +191,38 @@ config = { 'max_title_len': 50, # Truncate title at n characters 'show_ellipsis': True, # Show ellipsis when truncating titles - # Core options + # Session options 'save_session': True, # Save session in file when quit 'json_session': True, # Use json to save session. - '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'), + 'saved_sessions_dir': os.path.join(data_dir, 'sessions/'), 'session_file': os.path.join(data_dir, 'session'), - 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows + + # 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. # Window options - 'status_background': "#303030", # Default background for all panels - 'window_size': "800,800", # width,height in pixels + 'window_size': "800,800", # width,height in pixels. - # Key bindings. + # Key bindings 'bind_new_tab': 'gn', # Open new tab. 'bind_tab_from_clip': 'gY', # Open tab from clipboard. 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. 'bind_close_tab': 'gC', # Close tab. 'bind_next_tab': 'gt', # Next tab. 'bind_prev_tab': 'gT', # Prev tab. - 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title) - 'bind_goto_first': 'g<', # Goto first tab - 'bind_goto_last': 'g>', # Goto last tab + 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title). + 'bind_goto_first': 'g<', # Goto first tab. + 'bind_goto_last': 'g>', # Goto last tab. + 'bind_clean_slate': 'gQ', # Close all tabs and open new tab. + + # Session preset key bindings + 'bind_save_preset': 'gsave _', # Save session to file %s. + 'bind_load_preset': 'gload _', # Load preset session from file %s. + 'bind_del_preset': 'gdel _', # Delete preset session %s. + 'bind_list_presets': 'glist', # List all session presets. # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like @@ -437,10 +455,10 @@ class UzblTabbed: self._fifos = {} self._timers = {} self._buffer = "" - - # This is updated periodically with the current state. - # Tabs is a list of (url, title) tuples. - self._state = {'curtab': 0, 'tabs': []} + self._killed = False + + # A list of the recently closed tabs + self._closed = [] # Holds metadata on the uzbl childen open. self.tabs = {} @@ -471,7 +489,7 @@ class UzblTabbed: self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) # Attach main window event handlers - self.window.connect("delete-event", self.quit) + self.window.connect("delete-event", self.quitrequest) # Create tab list if config['show_tablist']: @@ -610,8 +628,6 @@ class UzblTabbed: save_session = config['save_session'] sockd = {} - if save_session: - session = [] tabskeys = self.tabs.keys() notebooklist = list(self.notebook) @@ -621,13 +637,6 @@ class UzblTabbed: uzbl.probe() if uzbl._socket: sockd[uzbl._socket] = uzbl - - if save_session: - session += [(uzbl.uri, uzbl.title),] - - if save_session: - self._state['tabs'] = session - self._state['curtab'] = self.notebook.get_current_page() sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) @@ -756,6 +765,50 @@ class UzblTabbed: self.update_tablist() else: error("parse_command: no uzbl with pid %r" % int(cmd[1])) + + elif cmd[0] == "preset": + if len(cmd) < 3: + error("parse_command: invalid preset command") + + elif cmd[1] == "save": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.save_session(path) + + elif cmd[1] == "load": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.load_session(path) + + elif cmd[1] == "del": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + if os.path.isfile(path): + os.remove(path) + + else: + error("parse_command: preset %r does not exist." % path) + + elif cmd[1] == "list": + uzbl = self.get_tab_by_pid(int(cmd[2])) + if uzbl: + if not os.path.isdir(config['saved_sessions_dir']): + js = "js alert('No saved presets.');" + uzbl.send(js) + + else: + listdir = os.listdir(config['saved_sessions_dir']) + listdir = "\\n".join(listdir) + js = "js alert('Session presets:\\n\\n%s');" % listdir + uzbl.send(js) + + else: + error("parse_command: unknown tab pid.") + + else: + error("parse_command: unknown parse command %r"\ + % ' '.join(cmd)) + + elif cmd[0] == "clean": + self.clean_slate() + else: error("parse_command: unknown command %r" % ' '.join(cmd)) @@ -812,6 +865,17 @@ class UzblTabbed: self.update_tablist() + def clean_slate(self): + '''Close all open tabs and open a fresh brand new one.''' + + self.new_tab() + tabs = self.tabs.keys() + for tab in list(self.notebook)[:-1]: + if tab not in tabs: continue + uzbl = self.tabs[tab] + uzbl.send("exit") + + def config_uzbl(self, uzbl): '''Send bind commands for tab new/close/next/prev to a uzbl instance.''' @@ -837,7 +901,14 @@ class UzblTabbed: bind(config['bind_goto_tab'], 'goto %s') bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') - + bind(config['bind_clean_slate'], 'clean') + + # session preset binds + bind(config['bind_save_preset'], 'preset save %s') + bind(config['bind_load_preset'], 'preset load %s') + bind(config['bind_del_preset'], 'preset del %s') + bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid) + # Set definitions here # set(key, command back to fifo) if config['capture_new_windows']: @@ -942,9 +1013,16 @@ class UzblTabbed: uzbl._fifoout = [] uzbl._socketout = [] uzbl._kill = True + self._closed.append((uzbl.uri, uzbl.title)) + self._closed = self._closed[-10:] del self.tabs[tab] if self.notebook.get_n_pages() == 0: + if not self._killed and config['save_session']: + if len(self._closed): + d = {'curtab': 0, 'tabs': [self._closed[-1],]} + self.save_session(session=d) + self.quit() self.update_tablist() @@ -1024,23 +1102,35 @@ class UzblTabbed: return True - def save_session(self, session_file=None): + def save_session(self, session_file=None, session=None): '''Save the current session to file for restoration on next load.''' strip = str.strip if session_file is None: session_file = config['session_file'] + + if session is None: + tabs = self.tabs.keys() + state = [] + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + if not uzbl.uri: continue + state += [(uzbl.uri, uzbl.title),] + + session = {'curtab': self.notebook.get_current_page(), + 'tabs': state} if config['json_session']: - session = json.dumps(self._state) + raw = json.dumps(session) else: - lines = ["curtab = %d" % self._state['curtab'],] - for (uri, title) in self._state['tabs']: + lines = ["curtab = %d" % session['curtab'],] + for (uri, title) in session['tabs']: lines += ["%s\t%s" % (strip(uri), strip(title)),] - session = "\n".join(lines) + raw = "\n".join(lines) if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) @@ -1048,7 +1138,7 @@ class UzblTabbed: os.makedirs(dirname) h = open(session_file, 'w') - h.write(session) + h.write(raw) h.close() @@ -1069,7 +1159,6 @@ class UzblTabbed: h = open(session_file, 'r') raw = h.read() h.close() - if json_session: if sum([1 for s in raw.split("\n") if strip(s)]) != 1: error("Warning: The session file %r does not look json. "\ @@ -1083,9 +1172,8 @@ class UzblTabbed: curtab, tabs = session['curtab'], session['tabs'] except: - if not default_path: - error("Failed to load json session from %r"\ - % session_file) + error("Failed to load jsonifed session from %r"\ + % session_file) return None else: @@ -1103,17 +1191,45 @@ class UzblTabbed: curtab = int(line.split()[-1]) else: - uri, title = line.split("\t") + uri, title = line.split("\t",1) tabs += [(strip(uri), strip(title)),] + + session = {'curtab': curtab, 'tabs': tabs} # Now populate notebook with the loaded session. for (index, (uri, title)) in enumerate(tabs): self.new_tab(uri=uri, title=title, switch=(curtab==index)) + # There may be other state information in the session dict of use to + # other functions. Of course however the non-json session object is + # just a dummy object of no use to no one. + return session + + + def quitrequest(self, *args): + '''Called by delete-event signal to kill all uzbl instances.''' + + #TODO: Even though I send the kill request to all uzbl instances + # i should add a gobject timeout to check they all die. + + self._killed = True + + if config['save_session']: + if len(list(self.notebook)): + self.save_session() + else: + # Notebook has no pages so delete session file if it exists. + if os.path.isfile(session_file): + os.remove(session_file) + + for (tab, uzbl) in self.tabs.items(): + uzbl.send("exit") + + def quit(self, *args): '''Cleanup the application and quit. Called by delete-event signal.''' - + for (fifo_socket, (fd, watchers)) in self._fifos.items(): os.close(fd) for (watcherid, gid) in watchers.items(): @@ -1130,15 +1246,6 @@ class UzblTabbed: os.unlink(self.fifo_socket) print "Unlinked %s" % self.fifo_socket - if config['save_session']: - if len(self._state['tabs']): - self.save_session() - - else: - # Notebook has no pages so delete session file if it exists. - if os.path.isfile(session_file): - os.remove(session_file) - gtk.main_quit() -- cgit v1.2.3 From 977eef6d10d762bf8ba517eecef1eca8c89f8704 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 22 Jul 2009 13:48:51 +0800 Subject: bugfix: uzbl_tabbed.py crashed when loading old format session file --- examples/data/uzbl/scripts/uzbl_tabbed.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 8de3006..5742494 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1185,15 +1185,20 @@ class UzblTabbed: error("Warning: The non-json session file %r looks invalid."\ % session_file) return None - - for line in lines: - if line.startswith("curtab"): - curtab = int(line.split()[-1]) + + try: + for line in lines: + if line.startswith("curtab"): + curtab = int(line.split()[-1]) else: uri, title = line.split("\t",1) tabs += [(strip(uri), strip(title)),] + except: + error("Warning: failed to load session file %r" % session_file) + return None + session = {'curtab': curtab, 'tabs': tabs} # Now populate notebook with the loaded session. -- cgit v1.2.3 From 423b0b26e0a3427d82b639114b0f3364135a7fb1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 22 Jul 2009 16:50:14 +0800 Subject: Made json_session false by default. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 5742494..8c456b9 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -61,7 +61,7 @@ # # Session options: # save_session = 1 -# json_session = 1 +# json_session = 0 # session_file = $HOME/.local/share/uzbl/session # # Inherited uzbl options: @@ -193,7 +193,7 @@ config = { # Session options 'save_session': True, # Save session in file when quit - 'json_session': True, # Use json to save session. + 'json_session': False, # Use json to save session. 'saved_sessions_dir': os.path.join(data_dir, 'sessions/'), 'session_file': os.path.join(data_dir, 'session'), -- cgit v1.2.3 From ef06fad4fa1a3d5f5c8e1ff8ecc5dc43539b034d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 22 Jul 2009 17:03:49 +0800 Subject: Added dependencies section to the top of uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 8c456b9..bbc05b9 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -39,6 +39,19 @@ # Fix for session restoration code. +# Dependencies: +# pygtk - python bindings for gtk. +# pango - python bindings needed for text rendering & layout in gtk widgets. +# pygobject - GLib's GObject bindings for python. +# +# Optional dependencies: +# simplejson - save uzbl_tabbed.py sessions & presets in json. +# +# Note: I haven't included version numbers with this dependency list because +# I've only ever tested uzbl_tabbed.py on the latest stable versions of these +# packages in Gentoo's portage. Package names may vary on different systems. + + # Configuration: # Because this version of uzbl_tabbed is able to inherit options from your main # uzbl configuration file you may wish to configure uzbl tabbed from there. -- cgit v1.2.3 From a10aeff77406e87cec11cc719e9680f46312faf7 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 22 Jul 2009 17:35:29 +0800 Subject: Bugfix: Accidentally broke non-json session loading. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index bbc05b9..eed2d2f 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1204,9 +1204,9 @@ class UzblTabbed: if line.startswith("curtab"): curtab = int(line.split()[-1]) - else: - uri, title = line.split("\t",1) - tabs += [(strip(uri), strip(title)),] + else: + uri, title = line.split("\t",1) + tabs += [(strip(uri), strip(title)),] except: error("Warning: failed to load session file %r" % session_file) -- cgit v1.2.3 From bf92bf9182559c590c501b8abde490d2e0d41650 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 24 Jul 2009 21:04:08 +0800 Subject: Use #!/usr/bin/env python instead of #!/usr/bin/python --- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index eed2d2f..7a9abf5 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # Uzbl tabbing wrapper using a fifo socket interface # Copyright (c) 2009, Tom Adams -- cgit v1.2.3 From 948630efe45e6573e02ac142855229fb3198d480 Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 25 Jul 2009 23:00:26 +0100 Subject: Make scheme.py a better example. --- examples/data/uzbl/scripts/scheme.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index dde9ba1..7286703 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -10,6 +10,7 @@ def detach_open(cmd): for i in range(3): os.dup2(null,i) os.close(null) subprocess.Popen(cmd) + print 'USED' if __name__ == '__main__': uri = sys.argv[8] @@ -20,7 +21,3 @@ if __name__ == '__main__': detach_open(['gajim-remote', 'open_chat', uri]) elif u.scheme == 'git': detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src')) - else: - print 'DIY!' - exit() - print 'USED' -- cgit v1.2.3 From c3888158026eb8dd0c2043b42cd9775f16bcb8b9 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 06:51:06 +0800 Subject: indentation fix --- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 7a9abf5..11a1767 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -23,7 +23,7 @@ # Tom Adams # Wrote the original uzbl_tabbed.py as a proof of concept. # -# Chris van Dijk (quigybo) +# Chris van Dijk (quigybo) # Made signifigant headway on the old uzbl_tabbing.py script on the # uzbl wiki # -- cgit v1.2.3 From 78a1581ea05bf7036403f802c316a7094ff764e4 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 06:52:28 +0800 Subject: Initial commit of cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 255 ++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100755 examples/data/uzbl/scripts/cookie_daemon.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py new file mode 100755 index 0000000..3137098 --- /dev/null +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -0,0 +1,255 @@ +#!/usr/biin/env python + +# Uzbl tabbing wrapper using a fifo socket interface +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, Dieter Plaetinck +# Copyright (c) 2009, Mason Larobina +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import cookielib +import os +import sys +import urllib2 +import select +import socket +import time + +try: + import cStringIO as StringIO + +except ImportError: + import StringIO + + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# Location of the uzbl cache directory. +if 'XDG_CACHE_HOME' in os.environ.keys() and os.environ['XDG_CACHE_HOME']: + cache_dir = os.path.join(os.environ['XDG_CACHE_HOME'], 'uzbl/') + +else: + cache_dir = os.path.join(os.environ['HOME'], '.cache/uzbl/') + +# Location of the uzbl data directory. +if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: + data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') + +else: + data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + +# Create cache dir and data dir if they are missing. +for path in [data_dir, cache_dir]: + if not os.path.exists(path): + os.makedirs(path) + +# Default config +cookie_socket = os.path.join(cache_dir, 'cookie_daemon_socket') +cookie_jar = os.path.join(data_dir, 'cookies.txt') +#daemon_timeout = 360 +daemon_timeout = 0 + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +class CookieMonster: + '''The uzbl cookie daemon class.''' + + def __init__(self, cookie_socket, cookie_jar, daemon_timeout): + + self.cookie_socket = os.path.expandvars(cookie_socket) + self.server_socket = None + self.cookie_jar = os.path.expandvars(cookie_jar) + self.jar = None + self.daemon_timeout = daemon_timeout + self.last_request = time.time() + + + def run(self): + '''Start the daemon.''' + + try: + # Daemonize process. + #self.daemonize() + + # Create cookie_socket + self.create_socket() + + # Create jar object + self.open_cookie_jar() + + # Listen for GET and PULL cookie requests. + self.listen() + + except: + #raise + print "%r" % sys.exc_info()[1] + + self.quit() + + + def daemonize(function): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): sys.exit(0) + + except OSError, e: + sys.stderr.write("fork #1 failed: %s\n" % e) + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): sys.exit(0) + + except OSError, e: + sys.stderr.write("fork #2 failed: %s\n" % e) + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + + def open_cookie_jar(self): + '''Open the cookie jar.''' + + # Open cookie jar. + self.jar = cookielib.MozillaCookieJar(cookie_jar) + try: + self.jar.load(ignore_discard=True) + + except: + pass + + + def create_socket(self): + '''Open socket AF_UNIX socket for uzbl instance <-> daemon + communication.''' + + if os.path.exists(self.cookie_socket): + # Don't you just love racetrack conditions! + sys.exit(1) + + self.server_socket = socket.socket(socket.AF_UNIX,\ + socket.SOCK_SEQPACKET) + + self.server_socket.bind(self.cookie_socket) + + + def listen(self): + '''Listen for incoming cookie PUT and GET requests.''' + + while True: + # If you get broken pipe errors increase this listen number. + self.server_socket.listen(1) + + if bool(select.select([self.server_socket],[],[],1)[0]): + client_socket, _ = self.server_socket.accept() + self.handle_request(client_socket) + self.last_request = time.time() + + if self.daemon_timeout: + idle = time.time() - self.last_request + if idle > self.daemon_timeout: break + + + def handle_request(self, client_socket): + '''Connection has been made by uzbl instance now to serve + cookie PUT or GET request.''' + + # Receive full request from client. + data = client_socket.recv(4096) + + argv = data.split("\0") + + # For debugging: + #print argv + + action = argv[0] + set_cookie = argv[4] if len(argv) > 3 else None + uri = urllib2.urlparse.ParseResult( + scheme=argv[1], + netloc=argv[2], + path=argv[3], + params='', + query='', + fragment='').geturl() + + req = urllib2.Request(uri) + + if action == "GET": + self.jar.add_cookie_header(req) + if req.has_header('Cookie'): + client_socket.send(req.get_header('Cookie')) + + else: + client_socket.send("\0") + + elif action == "PUT": + hdr = urllib2.httplib.HTTPMessage(\ + StringIO.StringIO('Set-Cookie: %s' % set_cookie)) + res = urllib2.addinfourl(StringIO.StringIO(), hdr,\ + req.get_full_url()) + self.jar.extract_cookies(res,req) + self.jar.save(ignore_discard=True) + + client_socket.close() + + + def quit(self): + '''Called on exit to make sure all loose ends are tied up.''' + + # Only one loose end so far. + self.del_socket() + + # And die gracefully. + sys.exit(0) + + + def del_socket(self): + '''Remove the cookie_socket file on exit. In a way the cookie_socket + is the daemons pid file equivalent.''' + + if self.server_socket: + self.server_socket.close() + + if os.path.exists(self.cookie_socket): + os.remove(self.cookie_socket) + + +if __name__ == "__main__": + + if os.path.exists(cookie_socket): + print "Error: cookie socket already exists: %r" % cookie_socket + sys.exit(1) + + CookieMonster(cookie_socket, cookie_jar, daemon_timeout).run() + -- cgit v1.2.3 From 7a0599e60af50bdb0c9dcc09c0c223dfc41bbf37 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 06:58:41 +0800 Subject: Typo fix. --- examples/data/uzbl/scripts/cookie_daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 3137098..79226f3 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -1,4 +1,4 @@ -#!/usr/biin/env python +#!/usr/bin/env python # Uzbl tabbing wrapper using a fifo socket interface # Copyright (c) 2009, Tom Adams -- cgit v1.2.3 From b2729b628bf4b7f53c97b046ce460318bbd40242 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 07:01:14 +0800 Subject: Update docstring. --- examples/data/uzbl/scripts/cookie_daemon.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 79226f3..80b421f 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -182,8 +182,7 @@ class CookieMonster: def handle_request(self, client_socket): - '''Connection has been made by uzbl instance now to serve - cookie PUT or GET request.''' + '''Connection made, now to serve a cookie PUT or GET request.''' # Receive full request from client. data = client_socket.recv(4096) -- cgit v1.2.3 From c4d922036adca090e5cb9d2f3520e51c5e22edc3 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 17:45:22 +0800 Subject: Verbosify cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 80b421f..3e70b91 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -188,9 +188,9 @@ class CookieMonster: data = client_socket.recv(4096) argv = data.split("\0") - + # For debugging: - #print argv + print ' '.join(argv) action = argv[0] set_cookie = argv[4] if len(argv) > 3 else None -- cgit v1.2.3 From b5f1039351fdf4889afdba27e3dbe5bdb837f283 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 22:44:31 +0800 Subject: Several bug fixes to cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 85 +++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 3e70b91..89aeecd 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -19,6 +19,11 @@ # along with this program. If not, see . +# Todo list: +# - Setup some option parsing so the daemon can take optional command line +# arguments. + + import cookielib import os import sys @@ -26,6 +31,8 @@ import urllib2 import select import socket import time +import atexit +from signal import signal, SIGTERM try: import cStringIO as StringIO @@ -60,9 +67,15 @@ for path in [data_dir, cache_dir]: # Default config cookie_socket = os.path.join(cache_dir, 'cookie_daemon_socket') cookie_jar = os.path.join(data_dir, 'cookies.txt') -#daemon_timeout = 360 + +# Time out after x seconds of inactivity (set to 0 for never time out). +# Set to 0 by default until talk_to_socket is doing the spawning. daemon_timeout = 0 +# Enable/disable daemonizing the process (useful when debugging). +# Set to False by default until talk_to_socket is doing the spawning. +daemon_mode = False + # ============================================================================ # ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: # ============================================================================ @@ -71,11 +84,13 @@ daemon_timeout = 0 class CookieMonster: '''The uzbl cookie daemon class.''' - def __init__(self, cookie_socket, cookie_jar, daemon_timeout): + def __init__(self, cookie_socket, cookie_jar, daemon_timeout,\ + daemon_mode): self.cookie_socket = os.path.expandvars(cookie_socket) self.server_socket = None self.cookie_jar = os.path.expandvars(cookie_jar) + self.daemon_mode = daemon_mode self.jar = None self.daemon_timeout = daemon_timeout self.last_request = time.time() @@ -84,31 +99,42 @@ class CookieMonster: def run(self): '''Start the daemon.''' - try: - # Daemonize process. - #self.daemonize() + # Daemonize process. + if self.daemon_mode: + self.daemonize() + # Cleanup & quit function + atexit.register(self.quit) + + # Tell SIGTERM to act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + try: # Create cookie_socket self.create_socket() # Create jar object self.open_cookie_jar() - + # Listen for GET and PULL cookie requests. self.listen() + + except KeyboardInterrupt: + print except: - #raise - print "%r" % sys.exc_info()[1] - - self.quit() + # Clean up + self.del_socket() + # Raise exception + raise + def daemonize(function): '''Daemonize the process using the Stevens' double-fork magic.''' try: - if os.fork(): sys.exit(0) + if os.fork(): os._exit(0) except OSError, e: sys.stderr.write("fork #1 failed: %s\n" % e) @@ -119,7 +145,7 @@ class CookieMonster: os.umask(0) try: - if os.fork(): sys.exit(0) + if os.fork(): os._exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %s\n" % e) @@ -162,6 +188,9 @@ class CookieMonster: socket.SOCK_SEQPACKET) self.server_socket.bind(self.cookie_socket) + + # Only allow the current user to read and write to the socket. + os.chmod(self.cookie_socket, 0600) def listen(self): @@ -184,16 +213,15 @@ class CookieMonster: def handle_request(self, client_socket): '''Connection made, now to serve a cookie PUT or GET request.''' - # Receive full request from client. - data = client_socket.recv(4096) - + # Receive cookie request from client. + data = client_socket.recv(8192) argv = data.split("\0") # For debugging: - print ' '.join(argv) + print ' '.join(argv[:4]) action = argv[0] - set_cookie = argv[4] if len(argv) > 3 else None + uri = urllib2.urlparse.ParseResult( scheme=argv[1], netloc=argv[2], @@ -207,29 +235,39 @@ class CookieMonster: if action == "GET": self.jar.add_cookie_header(req) if req.has_header('Cookie'): - client_socket.send(req.get_header('Cookie')) + cookie = req.get_header('Cookie') + client_socket.send(cookie) + print cookie else: client_socket.send("\0") elif action == "PUT": + if len(argv) > 3: + set_cookie = argv[4] + print set_cookie + + else: + set_cookie = None + hdr = urllib2.httplib.HTTPMessage(\ StringIO.StringIO('Set-Cookie: %s' % set_cookie)) res = urllib2.addinfourl(StringIO.StringIO(), hdr,\ req.get_full_url()) self.jar.extract_cookies(res,req) - self.jar.save(ignore_discard=True) + self.jar.save(ignore_discard=True) + + print client_socket.close() - def quit(self): + def quit(self, *args): '''Called on exit to make sure all loose ends are tied up.''' # Only one loose end so far. self.del_socket() - - # And die gracefully. + sys.exit(0) @@ -250,5 +288,6 @@ if __name__ == "__main__": print "Error: cookie socket already exists: %r" % cookie_socket sys.exit(1) - CookieMonster(cookie_socket, cookie_jar, daemon_timeout).run() + CookieMonster(cookie_socket, cookie_jar, daemon_timeout,\ + daemon_mode).run() -- cgit v1.2.3 From 73def5a36108a3ae94becf498b9562393b5ed731 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 22:58:11 +0800 Subject: Fix comment, minor update. --- examples/data/uzbl/scripts/cookie_daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 89aeecd..9f52aa1 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -103,7 +103,7 @@ class CookieMonster: if self.daemon_mode: self.daemonize() - # Cleanup & quit function + # Register a function to cleanup on exit. atexit.register(self.quit) # Tell SIGTERM to act orderly. -- cgit v1.2.3 From ee1ced6106ccabd8fab4e7e8a53ff9499c28e616 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 26 Jul 2009 23:15:39 +0800 Subject: Also chmod(cookie_jar, 0600) in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 9f52aa1..7ac7d80 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -168,10 +168,14 @@ class CookieMonster: '''Open the cookie jar.''' # Open cookie jar. - self.jar = cookielib.MozillaCookieJar(cookie_jar) + self.jar = cookielib.MozillaCookieJar(self.cookie_jar) try: + # Load cookies from the cookie_jar file. self.jar.load(ignore_discard=True) + # Check cookie_jar only readable and writable by this user. + os.chmod(self.cookie_jar, 0600) + except: pass -- cgit v1.2.3 From e42f79385a4b6909a31c17efcc58461b93e252e8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 27 Jul 2009 23:36:52 +0800 Subject: cookie_daemon.py now deletes abandoned cookie daemon sockets. --- examples/data/uzbl/scripts/cookie_daemon.py | 115 ++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 7ac7d80..6866ae2 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -76,11 +76,20 @@ daemon_timeout = 0 # Set to False by default until talk_to_socket is doing the spawning. daemon_mode = False +# Set true to print helpful debugging messages to the terminal. +verbose = True + # ============================================================================ # ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: # ============================================================================ +_scriptname = os.path.basename(sys.argv[0]) +def echo(msg): + if verbose: + print "%s: %s" % (_scriptname, msg) + + class CookieMonster: '''The uzbl cookie daemon class.''' @@ -99,24 +108,31 @@ class CookieMonster: def run(self): '''Start the daemon.''' + # Check if another daemon is running. The reclaim_socket function will + # exit if another daemon is detected listening on the cookie socket + # and remove the abandoned socket if there isnt. + if os.path.exists(self.cookie_socket): + self.reclaim_socket() + # Daemonize process. if self.daemon_mode: + echo("entering daemon mode.") self.daemonize() # Register a function to cleanup on exit. atexit.register(self.quit) - # Tell SIGTERM to act orderly. + # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - - try: - # Create cookie_socket - self.create_socket() + + # Create cookie daemon socket. + self.create_socket() - # Create jar object - self.open_cookie_jar() - - # Listen for GET and PULL cookie requests. + # Create cookie jar object from file. + self.open_cookie_jar() + + try: + # Listen for incoming cookie puts/gets. self.listen() except KeyboardInterrupt: @@ -128,7 +144,34 @@ class CookieMonster: # Raise exception raise - + + + def reclaim_socket(self): + '''Check if another process (hopefully a cookie_daemon.py) is listening + on the cookie daemon socket. If another process is found to be + listening on the socket exit the daemon immediately and leave the + socket alone. If the connect fails assume the socket has been abandoned + and delete it (to be re-created in the create socket function).''' + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(self.cookie_socket) + sock.close() + + except socket.error: + # Failed to connect to cookie_socket so assume it has been + # abandoned by another cookie daemon process. + echo("reclaiming abandoned cookie_socket %r." % self.cookie_socket) + if os.path.exists(self.cookie_socket): + os.remove(self.cookie_socket) + + return + + echo("detected another process listening on %r." % self.cookie_socket) + echo("exiting.") + # Use os._exit() to avoid tripping the atexit cleanup function. + os._exit(1) + def daemonize(function): '''Daemonize the process using the Stevens' double-fork magic.''' @@ -167,13 +210,16 @@ class CookieMonster: def open_cookie_jar(self): '''Open the cookie jar.''' - # Open cookie jar. + # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(self.cookie_jar) + try: - # Load cookies from the cookie_jar file. + # Attempt to load cookies from the cookie jar. self.jar.load(ignore_discard=True) - # Check cookie_jar only readable and writable by this user. + # Ensure restrictive permissions are set on the cookie jar + # to prevent other users on the system from hi-jacking your + # authenticated sessions simply by copying your cookie jar. os.chmod(self.cookie_jar, 0600) except: @@ -181,19 +227,20 @@ class CookieMonster: def create_socket(self): - '''Open socket AF_UNIX socket for uzbl instance <-> daemon - communication.''' + '''Create AF_UNIX socket for interprocess uzbl instance <-> cookie + daemon communication.''' - if os.path.exists(self.cookie_socket): - # Don't you just love racetrack conditions! - sys.exit(1) - self.server_socket = socket.socket(socket.AF_UNIX,\ socket.SOCK_SEQPACKET) + if os.path.exists(self.cookie_socket): + # Accounting for super-rare super-fast racetrack condition. + self.reclaim_socket() + self.server_socket.bind(self.cookie_socket) - # Only allow the current user to read and write to the socket. + # Set restrictive permissions on the cookie socket to prevent other + # users on the system from data-mining your cookies. os.chmod(self.cookie_socket, 0600) @@ -201,9 +248,11 @@ class CookieMonster: '''Listen for incoming cookie PUT and GET requests.''' while True: - # If you get broken pipe errors increase this listen number. + # This line tells the socket how many pending incoming connections + # to enqueue. I haven't had any broken pipe errors so far while + # using the non-obvious value of 1 under heavy load conditions. self.server_socket.listen(1) - + if bool(select.select([self.server_socket],[],[],1)[0]): client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) @@ -219,11 +268,15 @@ class CookieMonster: # Receive cookie request from client. data = client_socket.recv(8192) + if not data: return + + # Cookie argument list in packet is null separated. argv = data.split("\0") - - # For debugging: - print ' '.join(argv[:4]) + # Determine whether or not to print cookie data to terminal. + print_cookie = (verbose and not self.daemon_mode) + if print_cookie: print ' '.join(argv[:4]) + action = argv[0] uri = urllib2.urlparse.ParseResult( @@ -241,7 +294,7 @@ class CookieMonster: if req.has_header('Cookie'): cookie = req.get_header('Cookie') client_socket.send(cookie) - print cookie + if print_cookie: print cookie else: client_socket.send("\0") @@ -249,7 +302,7 @@ class CookieMonster: elif action == "PUT": if len(argv) > 3: set_cookie = argv[4] - print set_cookie + if print_cookie: print set_cookie else: set_cookie = None @@ -261,7 +314,7 @@ class CookieMonster: self.jar.extract_cookies(res,req) self.jar.save(ignore_discard=True) - print + if print_cookie: print client_socket.close() @@ -272,7 +325,7 @@ class CookieMonster: # Only one loose end so far. self.del_socket() - sys.exit(0) + os._exit(0) def del_socket(self): @@ -288,10 +341,6 @@ class CookieMonster: if __name__ == "__main__": - if os.path.exists(cookie_socket): - print "Error: cookie socket already exists: %r" % cookie_socket - sys.exit(1) - CookieMonster(cookie_socket, cookie_jar, daemon_timeout,\ daemon_mode).run() -- cgit v1.2.3 From bce790790d1982167b4003e8d8b8457619e6b386 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 28 Jul 2009 00:17:12 +0800 Subject: Close socket after the handle_request function not inside handle_request --- examples/data/uzbl/scripts/cookie_daemon.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 6866ae2..21a03d6 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -257,6 +257,7 @@ class CookieMonster: client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) self.last_request = time.time() + client_socket.close() if self.daemon_timeout: idle = time.time() - self.last_request @@ -316,8 +317,6 @@ class CookieMonster: if print_cookie: print - client_socket.close() - def quit(self, *args): '''Called on exit to make sure all loose ends are tied up.''' -- cgit v1.2.3 From ca982ad25b14317bbf00981b0b475d4bd2ca6d17 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 29 Jul 2009 00:56:35 +0800 Subject: Added simple command line option parsing to uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 11a1767..6d458f5 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -162,6 +162,8 @@ import socket import random import hashlib +from optparse import OptionParser, OptionGroup + pygtk.require('2.0') def error(msg): @@ -566,6 +568,10 @@ class UzblTabbed: self._create_fifo_socket(self.fifo_socket) self._setup_fifo_watcher(self.fifo_socket) + # If we are using sessions then load the last one if it exists. + if config['save_session']: + self.load_session() + def _create_fifo_socket(self, fifo_socket): '''Create interprocess communication fifo socket.''' @@ -616,9 +622,6 @@ class UzblTabbed: def run(self): '''UzblTabbed main function that calls the gtk loop.''' - if config['save_session']: - self.load_session() - if not len(self.tabs): self.new_tab() @@ -1272,6 +1275,20 @@ if __name__ == "__main__": # Read from the uzbl config into the global config dictionary. readconfig(uzbl_config, config) + # Build command line parser + parser = OptionParser() + parser.add_option('-n', '--no-session', dest='nosession',\ + action='store_true', help="ignore session saving a loading.") + group = OptionGroup(parser, "Note", "All other command line arguments are "\ + "interpreted as uris and loaded in new tabs.") + parser.add_option_group(group) + + # Parse command line options + (options, uris) = parser.parse_args() + + if options.nosession: + config['save_session'] = False + if config['json_session']: try: import simplejson as json @@ -1283,6 +1300,11 @@ if __name__ == "__main__": config['json_session'] = False uzbl = UzblTabbed() - uzbl.run() + # All extra arguments given to uzbl_tabbed.py are interpreted as + # web-locations to opened in new tabs. + lasturi = len(uris)-1 + for (index,uri) in enumerate(uris): + uzbl.new_tab(uri, switch=(index==lasturi)) + uzbl.run() -- cgit v1.2.3 From 6008838a3d5cc5afd3dc41f63e5e449ceb8372bf Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 31 Jul 2009 00:44:09 +0800 Subject: Improvements made to the uzbl_tabbed.py fifo init and fifo cleanup code. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 290 +++++++++++++++++++----------- 1 file changed, 181 insertions(+), 109 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 6d458f5..b1a5c86 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -161,19 +161,27 @@ import gobject import socket import random import hashlib +import atexit +from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP +from signal import signal, SIGTERM, SIGINT from optparse import OptionParser, OptionGroup pygtk.require('2.0') +_scriptname = os.path.basename(sys.argv[0]) def error(msg): - sys.stderr.write("%s\n"%msg) + sys.stderr.write("%s: %s\n" % (_scriptname, msg)) + +def echo(msg): + print "%s: %s" % (_scriptname, msg) # ============================================================================ # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ + # Location of your uzbl data directory. if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') @@ -253,7 +261,7 @@ config = { 'selected_https': 'foreground = "#fff"', 'selected_https_text': 'foreground = "gold"', - } # End of config dict. +} # End of config dict. # This is the tab style policy handler. Every time the tablist is updated # this function is called to determine how to colourise that specific tab @@ -423,7 +431,7 @@ class UzblTabbed: self._connected = True if timer_call in self.timers.keys(): - gobject.source_remove(self.timers[timer_call]) + source_remove(self.timers[timer_call]) del self.timers[timer_call] if self._switch: @@ -467,7 +475,9 @@ class UzblTabbed: def __init__(self): '''Create tablist, window and notebook.''' - self._fifos = {} + # Store information about the applications fifo_socket. + self._fifo = None + self._timers = {} self._buffer = "" self._killed = False @@ -505,7 +515,7 @@ class UzblTabbed: # Attach main window event handlers self.window.connect("delete-event", self.quitrequest) - + # Create tab list if config['show_tablist']: vbox = gtk.VBox() @@ -562,23 +572,84 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Create the uzbl_tabbed fifo + # Generate the fifo socket filename. fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - self._create_fifo_socket(self.fifo_socket) - self._setup_fifo_watcher(self.fifo_socket) + + # Now initialise the fifo socket at self.fifo_socket + self.init_fifo_socket() # If we are using sessions then load the last one if it exists. if config['save_session']: self.load_session() - def _create_fifo_socket(self, fifo_socket): + def run(self): + '''UzblTabbed main function that calls the gtk loop.''' + + if not len(self.tabs): + self.new_tab() + + # Update tablist timer + #timer = "update-tablist" + #timerid = timeout_add(500, self.update_tablist,timer) + #self._timers[timer] = timerid + + # Probe clients every second for window titles and location + timer = "probe-clients" + timerid = timeout_add(1000, self.probe_clients, timer) + self._timers[timer] = timerid + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) + + # Catch keyboard interrupts + signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) + + try: + gtk.main() + + except: + error("encounted error %r" % sys.exc_info()[1]) + + # Unlink fifo socket + self.unlink_fifo_socket() + + # Attempt to close all uzbl instances nicely. + self.quitrequest() + + # Allow time for all the uzbl instances to quit. + time.sleep(1) + + raise + + + def terminate(self, termsig=None): + '''Handle termination signals and exit safely and cleanly.''' + + # Not required but at least it lets the user know what killed his + # browsing session. + if termsig == SIGTERM: + error("caught SIGTERM signal") + + elif termsig == SIGINT: + error("caught keyboard interrupt") + + else: + error("caught unknown signal") + + error("commencing infanticide!") + + # Sends the exit signal to all uzbl instances. + self.quitrequest() + + + def init_fifo_socket(self): '''Create interprocess communication fifo socket.''' - if os.path.exists(fifo_socket): - if not os.access(fifo_socket, os.F_OK | os.R_OK | os.W_OK): - os.mkfifo(fifo_socket) + if os.path.exists(self.fifo_socket): + if not os.access(self.fifo_socket, os.F_OK | os.R_OK | os.W_OK): + os.mkfifo(self.fifo_socket) else: basedir = os.path.dirname(self.fifo_socket) @@ -586,56 +657,89 @@ class UzblTabbed: os.makedirs(basedir) os.mkfifo(self.fifo_socket) + + # Add event handlers for IO_IN & IO_HUP events. + self.setup_fifo_watchers() - print "Listening on %s" % self.fifo_socket + echo("listening at %r" % self.fifo_socket) + # Add atexit register to destroy the socket on program termination. + atexit.register(self.unlink_fifo_socket) - def _setup_fifo_watcher(self, fifo_socket): - '''Open fifo socket fd and setup gobject IO_IN & IO_HUP watchers. - Also log the creation of a fd and store the the internal - self._watchers dictionary along with the filename of the fd.''' - if fifo_socket in self._fifos.keys(): - fd, watchers = self._fifos[fifo_socket] - os.close(fd) - for (watcherid, gid) in watchers.items(): - gobject.source_remove(gid) - del watchers[watcherid] + def unlink_fifo_socket(self): + '''Unlink the fifo socket. Note: This function is called automatically + on exit by an atexit register.''' + + # Make sure the fifo_socket fd is closed. + self.close_fifo() - del self._fifos[fifo_socket] + # And unlink if the real fifo_socket exists. + if os.path.exists(self.fifo_socket): + os.unlink(self.fifo_socket) + echo("unlinked %r" % self.fifo_socket) - # Re-open fifo and add listeners. - fd = os.open(fifo_socket, os.O_RDONLY | os.O_NONBLOCK) - watchers = {} - self._fifos[fifo_socket] = (fd, watchers) - watcher = lambda key, id: watchers.__setitem__(key, id) + + def close_fifo(self): + '''Remove all event handlers watching the fifo and close the fd.''' + + # Already closed + if self._fifo is None: return - # Watch for incoming data. - gid = gobject.io_add_watch(fd, gobject.IO_IN, self.main_fifo_read) - watcher('main-fifo-read', gid) + (fd, watchers) = self._fifo + os.close(fd) - # Watch for fifo hangups. - gid = gobject.io_add_watch(fd, gobject.IO_HUP, self.main_fifo_hangup) - watcher('main-fifo-hangup', gid) + # Stop all gobject io watchers watching the fifo. + for gid in watchers: + source_remove(gid) + self._fifo = None - def run(self): - '''UzblTabbed main function that calls the gtk loop.''' - - if not len(self.tabs): - self.new_tab() - - # Update tablist timer - #timer = "update-tablist" - #timerid = gobject.timeout_add(500, self.update_tablist,timer) - #self._timers[timer] = timerid - # Probe clients every second for window titles and location - timer = "probe-clients" - timerid = gobject.timeout_add(1000, self.probe_clients, timer) - self._timers[timer] = timerid + def setup_fifo_watchers(self): + '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event + handlers.''' + + # Close currently open fifo_socket fd and kill all watchers + self.close_fifo() + + fd = os.open(self.fifo_socket, 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 + - gtk.main() + 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: + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise + + return True def probe_clients(self, timer_call): @@ -675,36 +779,6 @@ class UzblTabbed: return True - def main_fifo_hangup(self, fd, cb_condition): - '''Handle main fifo socket hangups.''' - - # Close fd, re-open fifo_socket and watch. - self._setup_fifo_watcher(self.fifo_socket) - - # And to kill any gobject event handlers calling this 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: - error("parse_command: invalid command %s" % ' '.join(cmd)) - raise - - return True - - def parse_command(self, cmd): '''Parse instructions from uzbl child processes.''' @@ -778,7 +852,8 @@ class UzblTabbed: new = ' '.join(cmd[2:]) setattr(uzbl, cmd[0], new) if old != new: - self.update_tablist() + self.update_tablist() + else: error("parse_command: no uzbl with pid %r" % int(cmd[1])) @@ -875,7 +950,7 @@ class UzblTabbed: # Add gobject timer to make sure the config is pushed when fifo socket # has been created. - timerid = gobject.timeout_add(100, uzbl.flush, "flush-initial-config") + timerid = timeout_add(100, uzbl.flush, "flush-initial-config") uzbl.timers['flush-initial-config'] = timerid self.update_tablist() @@ -918,8 +993,6 @@ class UzblTabbed: bind(config['bind_goto_first'], 'goto 0') bind(config['bind_goto_last'], 'goto -1') bind(config['bind_clean_slate'], 'clean') - - # session preset binds bind(config['bind_save_preset'], 'preset save %s') bind(config['bind_load_preset'], 'preset load %s') bind(config['bind_del_preset'], 'preset del %s') @@ -1019,7 +1092,7 @@ class UzblTabbed: uzbl = self.tabs[tab] for (timer, gid) in uzbl.timers.items(): error("tab_closed: removing timer %r" % timer) - gobject.source_remove(gid) + source_remove(gid) del uzbl.timers[timer] if uzbl._socket: @@ -1040,7 +1113,7 @@ class UzblTabbed: self.save_session(session=d) self.quit() - + self.update_tablist() return True @@ -1230,9 +1303,6 @@ class UzblTabbed: def quitrequest(self, *args): '''Called by delete-event signal to kill all uzbl instances.''' - #TODO: Even though I send the kill request to all uzbl instances - # i should add a gobject timeout to check they all die. - self._killed = True if config['save_session']: @@ -1241,34 +1311,36 @@ class UzblTabbed: else: # Notebook has no pages so delete session file if it exists. - if os.path.isfile(session_file): - os.remove(session_file) + if os.path.isfile(config['session_file']): + os.remove(config['session_file']) for (tab, uzbl) in self.tabs.items(): uzbl.send("exit") - - - def quit(self, *args): - '''Cleanup the application and quit. Called by delete-event signal.''' - - for (fifo_socket, (fd, watchers)) in self._fifos.items(): - os.close(fd) - for (watcherid, gid) in watchers.items(): - gobject.source_remove(gid) - del watchers[watcherid] - del self._fifos[fifo_socket] + # Add a gobject timer to make sure the application force-quits after a period. + timer = "force-quit" + timerid = timeout_add(5000, self.quit, timer) + self._timers[timer] = timerid + + def quit(self, *args): + '''Cleanup and quit. Called by delete-event signal.''' + + # Close the fifo socket, remove any gobject io event handlers and + # delete socket. + self.unlink_fifo_socket() + + # Remove all gobject timers that are still ticking. for (timerid, gid) in self._timers.items(): - gobject.source_remove(gid) + source_remove(gid) del self._timers[timerid] + + try: + gtk.main_quit() - if os.path.exists(self.fifo_socket): - os.unlink(self.fifo_socket) - print "Unlinked %s" % self.fifo_socket - - gtk.main_quit() - + except: + pass + if __name__ == "__main__": -- cgit v1.2.3 From d9c14fb22568fed3ded726fc0f9a14676c270d94 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 31 Jul 2009 00:51:59 +0800 Subject: Removed trailing whitespace from uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 96 +++++++++++++++---------------- 1 file changed, 48 insertions(+), 48 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index b1a5c86..b7612e6 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -47,7 +47,7 @@ # Optional dependencies: # simplejson - save uzbl_tabbed.py sessions & presets in json. # -# Note: I haven't included version numbers with this dependency list because +# Note: I haven't included version numbers with this dependency list because # I've only ever tested uzbl_tabbed.py on the latest stable versions of these # packages in Gentoo's portage. Package names may vary on different systems. @@ -163,7 +163,7 @@ import random import hashlib import atexit -from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP +from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP from signal import signal, SIGTERM, SIGINT from optparse import OptionParser, OptionGroup @@ -481,7 +481,7 @@ class UzblTabbed: self._timers = {} self._buffer = "" self._killed = False - + # A list of the recently closed tabs self._closed = [] @@ -515,7 +515,7 @@ class UzblTabbed: # Attach main window event handlers self.window.connect("delete-event", self.quitrequest) - + # Create tab list if config['show_tablist']: vbox = gtk.VBox() @@ -572,13 +572,13 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Generate the fifo socket filename. + # Generate the fifo socket filename. fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) # Now initialise the fifo socket at self.fifo_socket self.init_fifo_socket() - + # If we are using sessions then load the last one if it exists. if config['save_session']: self.load_session() @@ -586,7 +586,7 @@ class UzblTabbed: def run(self): '''UzblTabbed main function that calls the gtk loop.''' - + if not len(self.tabs): self.new_tab() @@ -600,13 +600,13 @@ class UzblTabbed: timerid = timeout_add(1000, self.probe_clients, timer) self._timers[timer] = timerid - # Make SIGTERM act orderly. + # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) # Catch keyboard interrupts signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) - try: + try: gtk.main() except: @@ -615,7 +615,7 @@ class UzblTabbed: # Unlink fifo socket self.unlink_fifo_socket() - # Attempt to close all uzbl instances nicely. + # Attempt to close all uzbl instances nicely. self.quitrequest() # Allow time for all the uzbl instances to quit. @@ -623,18 +623,18 @@ class UzblTabbed: raise - + def terminate(self, termsig=None): '''Handle termination signals and exit safely and cleanly.''' - - # Not required but at least it lets the user know what killed his + + # Not required but at least it lets the user know what killed his # browsing session. - if termsig == SIGTERM: + if termsig == SIGTERM: error("caught SIGTERM signal") elif termsig == SIGINT: error("caught keyboard interrupt") - + else: error("caught unknown signal") @@ -657,8 +657,8 @@ class UzblTabbed: os.makedirs(basedir) os.mkfifo(self.fifo_socket) - - # Add event handlers for IO_IN & IO_HUP events. + + # Add event handlers for IO_IN & IO_HUP events. self.setup_fifo_watchers() echo("listening at %r" % self.fifo_socket) @@ -670,7 +670,7 @@ class UzblTabbed: def unlink_fifo_socket(self): '''Unlink the fifo socket. Note: This function is called automatically on exit by an atexit register.''' - + # Make sure the fifo_socket fd is closed. self.close_fifo() @@ -679,10 +679,10 @@ class UzblTabbed: os.unlink(self.fifo_socket) echo("unlinked %r" % self.fifo_socket) - + def close_fifo(self): '''Remove all event handlers watching the fifo and close the fd.''' - + # Already closed if self._fifo is None: return @@ -705,7 +705,7 @@ class UzblTabbed: fd = os.open(self.fifo_socket, os.O_RDONLY | os.O_NONBLOCK) - # Add gobject io event handlers to the fifo socket. + # 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)] @@ -744,7 +744,7 @@ class UzblTabbed: def probe_clients(self, timer_call): '''Probe all uzbl clients for up-to-date window titles and uri's.''' - + save_session = config['save_session'] sockd = {} @@ -756,7 +756,7 @@ class UzblTabbed: uzbl = self.tabs[tab] uzbl.probe() if uzbl._socket: - sockd[uzbl._socket] = uzbl + sockd[uzbl._socket] = uzbl sockets = sockd.keys() (reading, _, errors) = select.select(sockets, [], sockets, 0) @@ -860,7 +860,7 @@ class UzblTabbed: 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) @@ -876,7 +876,7 @@ class UzblTabbed: else: error("parse_command: preset %r does not exist." % path) - + elif cmd[1] == "list": uzbl = self.get_tab_by_pid(int(cmd[2])) if uzbl: @@ -899,7 +899,7 @@ class UzblTabbed: elif cmd[0] == "clean": self.clean_slate() - + else: error("parse_command: unknown command %r" % ' '.join(cmd)) @@ -934,7 +934,7 @@ class UzblTabbed: if switch is None: switch = config['switch_to_new_tabs'] - + if not title: title = config['new_tab_title'] @@ -965,7 +965,7 @@ class UzblTabbed: if tab not in tabs: continue uzbl = self.tabs[tab] uzbl.send("exit") - + def config_uzbl(self, uzbl): '''Send bind commands for tab new/close/next/prev to a uzbl @@ -1002,7 +1002,7 @@ class UzblTabbed: # set(key, command back to fifo) if config['capture_new_windows']: set("new_window", r'new $8') - + # Send config to uzbl instance via its socket file. uzbl.send("\n".join(binds+sets)) @@ -1113,7 +1113,7 @@ class UzblTabbed: self.save_session(session=d) self.quit() - + self.update_tablist() return True @@ -1198,7 +1198,7 @@ class UzblTabbed: if session_file is None: session_file = config['session_file'] - + if session is None: tabs = self.tabs.keys() state = [] @@ -1220,7 +1220,7 @@ class UzblTabbed: lines += ["%s\t%s" % (strip(uri), strip(title)),] raw = "\n".join(lines) - + if not os.path.isfile(session_file): dirname = os.path.dirname(session_file) if not os.path.isdir(dirname): @@ -1229,11 +1229,11 @@ class UzblTabbed: h = open(session_file, 'w') h.write(raw) h.close() - + def load_session(self, session_file=None): '''Load a saved session from file.''' - + default_path = False strip = str.strip json_session = config['json_session'] @@ -1254,8 +1254,8 @@ class UzblTabbed: "Trying to load it as a non-json session file."\ % session_file) json_session = False - - if json_session: + + if json_session: try: session = json.loads(raw) curtab, tabs = session['curtab'], session['tabs'] @@ -1274,7 +1274,7 @@ class UzblTabbed: error("Warning: The non-json session file %r looks invalid."\ % session_file) return None - + try: for line in lines: if line.startswith("curtab"): @@ -1289,20 +1289,20 @@ class UzblTabbed: return None session = {'curtab': curtab, 'tabs': tabs} - + # Now populate notebook with the loaded session. for (index, (uri, title)) in enumerate(tabs): self.new_tab(uri=uri, title=title, switch=(curtab==index)) - # There may be other state information in the session dict of use to - # other functions. Of course however the non-json session object is + # There may be other state information in the session dict of use to + # other functions. Of course however the non-json session object is # just a dummy object of no use to no one. return session def quitrequest(self, *args): '''Called by delete-event signal to kill all uzbl instances.''' - + self._killed = True if config['save_session']: @@ -1313,7 +1313,7 @@ class UzblTabbed: # Notebook has no pages so delete session file if it exists. if os.path.isfile(config['session_file']): os.remove(config['session_file']) - + for (tab, uzbl) in self.tabs.items(): uzbl.send("exit") @@ -1325,22 +1325,22 @@ 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 fifo socket, remove any gobject io event handlers and # delete socket. self.unlink_fifo_socket() - + # Remove all gobject timers that are still ticking. for (timerid, gid) in self._timers.items(): source_remove(gid) del self._timers[timerid] - + try: gtk.main_quit() - except: + except: pass - + if __name__ == "__main__": -- cgit v1.2.3 From 17a60c4e168c56973bbd5b5c6e9a212f4e3ec901 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 1 Aug 2009 23:59:41 +0800 Subject: Fix code comment. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index b7612e6..9ffa97d 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1317,7 +1317,9 @@ class UzblTabbed: for (tab, uzbl) in self.tabs.items(): uzbl.send("exit") - # Add a gobject timer to make sure the application force-quits after a period. + # Add a gobject timer to make sure the application force-quits after a + # reasonable period. Calling quit when all the tabs haven't had time to + # close should be a last resort. timer = "force-quit" timerid = timeout_add(5000, self.quit, timer) self._timers[timer] = timerid -- cgit v1.2.3 From b192615851fda2f0ab5394e64cdc6cd058febb21 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 2 Aug 2009 00:11:38 +0800 Subject: Removed trailing whitespace from cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 91 ++++++++++++++--------------- 1 file changed, 45 insertions(+), 46 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 21a03d6..f552173 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -21,7 +21,7 @@ # Todo list: # - Setup some option parsing so the daemon can take optional command line -# arguments. +# arguments. import cookielib @@ -62,7 +62,7 @@ else: # Create cache dir and data dir if they are missing. for path in [data_dir, cache_dir]: if not os.path.exists(path): - os.makedirs(path) + os.makedirs(path) # Default config cookie_socket = os.path.join(cache_dir, 'cookie_daemon_socket') @@ -72,7 +72,7 @@ cookie_jar = os.path.join(data_dir, 'cookies.txt') # Set to 0 by default until talk_to_socket is doing the spawning. daemon_timeout = 0 -# Enable/disable daemonizing the process (useful when debugging). +# Enable/disable daemonizing the process (useful when debugging). # Set to False by default until talk_to_socket is doing the spawning. daemon_mode = False @@ -104,13 +104,13 @@ class CookieMonster: self.daemon_timeout = daemon_timeout self.last_request = time.time() - + def run(self): '''Start the daemon.''' - + # Check if another daemon is running. The reclaim_socket function will - # exit if another daemon is detected listening on the cookie socket - # and remove the abandoned socket if there isnt. + # exit if another daemon is detected listening on the cookie socket + # and remove the abandoned socket if there isnt. if os.path.exists(self.cookie_socket): self.reclaim_socket() @@ -118,23 +118,23 @@ class CookieMonster: if self.daemon_mode: echo("entering daemon mode.") self.daemonize() - - # Register a function to cleanup on exit. + + # Register a function to cleanup on exit. atexit.register(self.quit) # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - + # Create cookie daemon socket. self.create_socket() - + # Create cookie jar object from file. self.open_cookie_jar() - + try: # Listen for incoming cookie puts/gets. self.listen() - + except KeyboardInterrupt: print @@ -145,14 +145,14 @@ class CookieMonster: # Raise exception raise - + def reclaim_socket(self): '''Check if another process (hopefully a cookie_daemon.py) is listening - on the cookie daemon socket. If another process is found to be - listening on the socket exit the daemon immediately and leave the + on the cookie daemon socket. If another process is found to be + listening on the socket exit the daemon immediately and leave the socket alone. If the connect fails assume the socket has been abandoned and delete it (to be re-created in the create socket function).''' - + try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) sock.connect(self.cookie_socket) @@ -165,7 +165,7 @@ class CookieMonster: if os.path.exists(self.cookie_socket): os.remove(self.cookie_socket) - return + return echo("detected another process listening on %r." % self.cookie_socket) echo("exiting.") @@ -182,18 +182,18 @@ class CookieMonster: except OSError, e: sys.stderr.write("fork #1 failed: %s\n" % e) sys.exit(1) - + os.chdir('/') os.setsid() os.umask(0) - + try: if os.fork(): os._exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %s\n" % e) sys.exit(1) - + sys.stdout.flush() sys.stderr.flush() @@ -205,11 +205,11 @@ class CookieMonster: os.dup2(stdin.fileno(), sys.stdin.fileno()) os.dup2(stdout.fileno(), sys.stdout.fileno()) os.dup2(stderr.fileno(), sys.stderr.fileno()) - + def open_cookie_jar(self): '''Open the cookie jar.''' - + # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(self.cookie_jar) @@ -217,8 +217,8 @@ class CookieMonster: # Attempt to load cookies from the cookie jar. self.jar.load(ignore_discard=True) - # Ensure restrictive permissions are set on the cookie jar - # to prevent other users on the system from hi-jacking your + # Ensure restrictive permissions are set on the cookie jar + # to prevent other users on the system from hi-jacking your # authenticated sessions simply by copying your cookie jar. os.chmod(self.cookie_jar, 0600) @@ -229,18 +229,18 @@ class CookieMonster: def create_socket(self): '''Create AF_UNIX socket for interprocess uzbl instance <-> cookie daemon communication.''' - + self.server_socket = socket.socket(socket.AF_UNIX,\ socket.SOCK_SEQPACKET) if os.path.exists(self.cookie_socket): # Accounting for super-rare super-fast racetrack condition. self.reclaim_socket() - + self.server_socket.bind(self.cookie_socket) - + # Set restrictive permissions on the cookie socket to prevent other - # users on the system from data-mining your cookies. + # users on the system from data-mining your cookies. os.chmod(self.cookie_socket, 0600) @@ -248,25 +248,25 @@ class CookieMonster: '''Listen for incoming cookie PUT and GET requests.''' while True: - # This line tells the socket how many pending incoming connections - # to enqueue. I haven't had any broken pipe errors so far while + # This line tells the socket how many pending incoming connections + # to enqueue. I haven't had any broken pipe errors so far while # using the non-obvious value of 1 under heavy load conditions. self.server_socket.listen(1) - + if bool(select.select([self.server_socket],[],[],1)[0]): client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) self.last_request = time.time() client_socket.close() - + if self.daemon_timeout: idle = time.time() - self.last_request if idle > self.daemon_timeout: break - + def handle_request(self, client_socket): '''Connection made, now to serve a cookie PUT or GET request.''' - + # Receive cookie request from client. data = client_socket.recv(8192) if not data: return @@ -277,9 +277,9 @@ class CookieMonster: # Determine whether or not to print cookie data to terminal. print_cookie = (verbose and not self.daemon_mode) if print_cookie: print ' '.join(argv[:4]) - + action = argv[0] - + uri = urllib2.urlparse.ParseResult( scheme=argv[1], netloc=argv[2], @@ -287,7 +287,7 @@ class CookieMonster: params='', query='', fragment='').geturl() - + req = urllib2.Request(uri) if action == "GET": @@ -313,24 +313,24 @@ class CookieMonster: res = urllib2.addinfourl(StringIO.StringIO(), hdr,\ req.get_full_url()) self.jar.extract_cookies(res,req) - self.jar.save(ignore_discard=True) + self.jar.save(ignore_discard=True) if print_cookie: print - + def quit(self, *args): '''Called on exit to make sure all loose ends are tied up.''' - + # Only one loose end so far. self.del_socket() os._exit(0) - + def del_socket(self): - '''Remove the cookie_socket file on exit. In a way the cookie_socket + '''Remove the cookie_socket file on exit. In a way the cookie_socket is the daemons pid file equivalent.''' - + if self.server_socket: self.server_socket.close() @@ -339,7 +339,6 @@ class CookieMonster: if __name__ == "__main__": - + CookieMonster(cookie_socket, cookie_jar, daemon_timeout,\ daemon_mode).run() - -- cgit v1.2.3 From 6217ae8a928e9b5ce75ed29e765e403678a2ce61 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Fri, 7 Aug 2009 23:11:54 +0200 Subject: removed html_mode in favour of "data URI scheme" --- README | 4 --- examples/data/uzbl/scripts/uzblcat | 22 +++++-------- uzbl.c | 64 +------------------------------------- uzbl.h | 6 ---- 4 files changed, 8 insertions(+), 88 deletions(-) (limited to 'examples') diff --git a/README b/README index 3314bf7..b36293c 100644 --- a/README +++ b/README @@ -174,11 +174,7 @@ Besides the builtin variables you can also define your own ones and use them in * Variables: - uri (callback: load the uri) - verbose: affects output on stdout - - mode:insert or command mode - inject_html - - base_url: used when passing html through stdin - - html_endmarker: delimiter when passing html through stdin - - html_mode_timeout: consider end of html input after x seconds when no endmarker found - keycmd: holds the input buffer (callback: update input buffer) - status_message (callback: update title) - show_status: show statusbar or not diff --git a/examples/data/uzbl/scripts/uzblcat b/examples/data/uzbl/scripts/uzblcat index 5c3063e..e955608 100755 --- a/examples/data/uzbl/scripts/uzblcat +++ b/examples/data/uzbl/scripts/uzblcat @@ -1,20 +1,12 @@ -#!/usr/bin/env perl +#!/usr/bin/env python # uzblcat - safely push html to uzbl # See http://www.uzbl.org/wiki/html-mode -use strict; use warnings; -my $html; -local $/; # slurp files -# automagically choose to read from stdin/files/... -$html .= $_ for <>; +from sys import stdin, stdout -my $endmarker = rand; -$endmarker .= rand() while $html =~ /^\Q$endmarker\E$/m; +stdout.write("uri data:text/html,") +for line in stdin: + stdout.write(line[0:-1]) + +# vim: set noet ff=unix -print "set base_url = $ENV{BASE_URL}\n" if $ENV{BASE_URL}; -print << "EOS"; -set html_endmarker = $endmarker -set mode = 1 -$html -$endmarker -EOS diff --git a/uzbl.c b/uzbl.c index e2148fd..38dcc5f 100644 --- a/uzbl.c +++ b/uzbl.c @@ -115,11 +115,8 @@ const struct var_name_to_ptr_t { /* ---------------------------------------------------------------------------------------------- */ { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)}, { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)}, - { "mode", PTR_V_INT(uzbl.behave.mode, 0, NULL)}, { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)}, { "base_url", PTR_V_STR(uzbl.behave.base_url, 1, NULL)}, - { "html_endmarker", PTR_V_STR(uzbl.behave.html_endmarker, 1, NULL)}, - { "html_mode_timeout", PTR_V_INT(uzbl.behave.html_timeout, 1, NULL)}, { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)}, { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)}, { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)}, @@ -496,20 +493,6 @@ clean_up(void) { g_hash_table_destroy(uzbl.behave.commands); } -/* used for html_mode_timeout - * be sure to extend this function to use - * more timers if needed in other places -*/ -void -set_timeout(int seconds) { - struct itimerval t; - memset(&t, 0, sizeof t); - - t.it_value.tv_sec = seconds; - t.it_value.tv_usec = 0; - setitimer(ITIMER_REAL, &t, NULL); -} - /* --- SIGNAL HANDLER --- */ void @@ -525,15 +508,6 @@ catch_sigint(int s) { exit(EXIT_SUCCESS); } -void -catch_alrm(int s) { - (void) s; - - set_var_value("mode", "0"); - render_html(); -} - - /* --- CALLBACKS --- */ gboolean @@ -1920,40 +1894,12 @@ set_var_value(const gchar *name, gchar *val) { return TRUE; } -void -render_html() { - Behaviour *b = &uzbl.behave; - - if(b->html_buffer->str) { - webkit_web_view_load_html_string (uzbl.gui.web_view, - b->html_buffer->str, b->base_url); - g_string_free(b->html_buffer, TRUE); - b->html_buffer = g_string_new(""); - } -} - enum {M_CMD, M_HTML}; void parse_cmd_line(const char *ctl_line, GString *result) { - Behaviour *b = &uzbl.behave; size_t len=0; - if(b->mode == M_HTML) { - len = strlen(b->html_endmarker); - /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */ - if(len == strlen(ctl_line)-1 && - !strncmp(b->html_endmarker, ctl_line, len)) { - set_timeout(0); - set_var_value("mode", "0"); - render_html(); - return; - } - else { - set_timeout(b->html_timeout); - g_string_append(b->html_buffer, ctl_line); - } - } - else if((ctl_line[0] == '#') /* Comments */ + if((ctl_line[0] == '#') /* Comments */ || (ctl_line[0] == ' ') || (ctl_line[0] == '\n')) ; /* ignore these lines */ @@ -2844,19 +2790,11 @@ initialize(int argc, char *argv[]) { fprintf(stderr, "uzbl: error hooking SIGTERM\n"); if(setup_signal(SIGINT, catch_sigint) == SIG_ERR) fprintf(stderr, "uzbl: error hooking SIGINT\n"); - if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR) - fprintf(stderr, "uzbl: error hooking SIGALARM\n"); uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h uzbl.gui.sbar.progress_u = g_strdup("·"); uzbl.gui.sbar.progress_w = 10; - /* HTML mode defaults*/ - uzbl.behave.html_buffer = g_string_new(""); - uzbl.behave.html_endmarker = g_strdup("."); - uzbl.behave.html_timeout = 60; - uzbl.behave.base_url = g_strdup("http://invalid"); - /* default mode indicators */ uzbl.behave.insert_indicator = g_strdup("I"); uzbl.behave.cmd_indicator = g_strdup("C"); diff --git a/uzbl.h b/uzbl.h index b99a89c..b175ccb 100644 --- a/uzbl.h +++ b/uzbl.h @@ -134,11 +134,8 @@ typedef struct { guint caret_browsing; guint mode; gchar* base_url; - gchar* html_endmarker; gchar* insert_indicator; gchar* cmd_indicator; - GString* html_buffer; - guint html_timeout; gboolean print_version; /* command list: name -> Command */ @@ -450,9 +447,6 @@ act_bind(WebKitWebView *page, GArray *argv, GString *result); void act_dump_config(); -void -render_html(); - void set_timeout(int seconds); -- cgit v1.2.3 From c52adae384101be50477c3b72581dc583e992480 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 8 Aug 2009 20:54:31 +0800 Subject: Added command line options to cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 177 +++++++++++++++++++++------- 1 file changed, 134 insertions(+), 43 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index f552173..eb6f4af 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -19,9 +19,20 @@ # along with this program. If not, see . +# Issues: +# - There is no easy way of stopping a running daemon. +# - Some users experience the broken pipe socket error seemingly randomly. +# Currently when a broken pipe error is received the daemon fatally fails. + + # Todo list: -# - Setup some option parsing so the daemon can take optional command line -# arguments. +# - Use a pid file to make stopping a running daemon easy. +# - add {start|stop|restart} command line arguments to make the cookie_daemon +# functionally similar to the daemons found in /etc/init.d/ (in gentoo) +# or /etc/rc.d/ (in arch). +# - Recover from broken pipe socket errors. +# - Add option to create a throwaway cookie jar in /tmp and delete it upon +# closing the daemon. import cookielib @@ -33,6 +44,7 @@ import socket import time import atexit from signal import signal, SIGTERM +from optparse import OptionParser try: import cStringIO as StringIO @@ -45,6 +57,7 @@ except ImportError: # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ + # Location of the uzbl cache directory. if 'XDG_CACHE_HOME' in os.environ.keys() and os.environ['XDG_CACHE_HOME']: cache_dir = os.path.join(os.environ['XDG_CACHE_HOME'], 'uzbl/') @@ -59,25 +72,26 @@ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: else: data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') -# Create cache dir and data dir if they are missing. -for path in [data_dir, cache_dir]: - if not os.path.exists(path): - os.makedirs(path) - # Default config -cookie_socket = os.path.join(cache_dir, 'cookie_daemon_socket') -cookie_jar = os.path.join(data_dir, 'cookies.txt') +config = { -# Time out after x seconds of inactivity (set to 0 for never time out). -# Set to 0 by default until talk_to_socket is doing the spawning. -daemon_timeout = 0 + # Default cookie jar and daemon socket locations. + 'cookie_socket': os.path.join(cache_dir, 'cookie_daemon_socket'), + 'cookie_jar': os.path.join(data_dir, 'cookies.txt'), -# Enable/disable daemonizing the process (useful when debugging). -# Set to False by default until talk_to_socket is doing the spawning. -daemon_mode = False + # Time out after x seconds of inactivity (set to 0 for never time out). + # Set to 0 by default until talk_to_socket is doing the spawning. + 'daemon_timeout': 0, + + # Enable/disable daemonizing the process (useful when debugging). + # Set to False by default until talk_to_socket is doing the spawning. + 'daemon_mode': True, + + # Set true to print helpful debugging messages to the terminal. + 'verbose': False, + +} # End of config dictionary. -# Set true to print helpful debugging messages to the terminal. -verbose = True # ============================================================================ # ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: @@ -86,22 +100,27 @@ verbose = True _scriptname = os.path.basename(sys.argv[0]) def echo(msg): - if verbose: + if config['verbose']: print "%s: %s" % (_scriptname, msg) +def mkbasedir(filepath): + '''Create base directory of filepath if it doesn't exist.''' + + dirname = os.path.dirname(filepath) + if not os.path.exists(dirname): + echo("creating dirs: %r" % dirname) + os.makedirs(dirname) + + class CookieMonster: '''The uzbl cookie daemon class.''' - def __init__(self, cookie_socket, cookie_jar, daemon_timeout,\ - daemon_mode): + def __init__(self): + '''Initialise class variables.''' - self.cookie_socket = os.path.expandvars(cookie_socket) self.server_socket = None - self.cookie_jar = os.path.expandvars(cookie_jar) - self.daemon_mode = daemon_mode self.jar = None - self.daemon_timeout = daemon_timeout self.last_request = time.time() @@ -111,11 +130,11 @@ class CookieMonster: # Check if another daemon is running. The reclaim_socket function will # exit if another daemon is detected listening on the cookie socket # and remove the abandoned socket if there isnt. - if os.path.exists(self.cookie_socket): + if os.path.exists(config['cookie_socket']): self.reclaim_socket() # Daemonize process. - if self.daemon_mode: + if config['daemon_mode']: echo("entering daemon mode.") self.daemonize() @@ -133,6 +152,7 @@ class CookieMonster: try: # Listen for incoming cookie puts/gets. + echo("listening on %r" % config['cookie_socket']) self.listen() except KeyboardInterrupt: @@ -153,21 +173,23 @@ class CookieMonster: socket alone. If the connect fails assume the socket has been abandoned and delete it (to be re-created in the create socket function).''' + cookie_socket = config['cookie_socket'] + try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(self.cookie_socket) + sock.connect(cookie_socket) sock.close() except socket.error: # Failed to connect to cookie_socket so assume it has been # abandoned by another cookie daemon process. - echo("reclaiming abandoned cookie_socket %r." % self.cookie_socket) - if os.path.exists(self.cookie_socket): - os.remove(self.cookie_socket) + echo("reclaiming abandoned cookie_socket %r." % cookie_socket) + if os.path.exists(cookie_socket): + os.remove(cookie_socket) return - echo("detected another process listening on %r." % self.cookie_socket) + echo("detected another process listening on %r." % cookie_socket) echo("exiting.") # Use os._exit() to avoid tripping the atexit cleanup function. os._exit(1) @@ -210,8 +232,11 @@ class CookieMonster: def open_cookie_jar(self): '''Open the cookie jar.''' + cookie_jar = config['cookie_jar'] + mkbasedir(cookie_jar) + # Create cookie jar object from file. - self.jar = cookielib.MozillaCookieJar(self.cookie_jar) + self.jar = cookielib.MozillaCookieJar(cookie_jar) try: # Attempt to load cookies from the cookie jar. @@ -220,7 +245,7 @@ class CookieMonster: # Ensure restrictive permissions are set on the cookie jar # to prevent other users on the system from hi-jacking your # authenticated sessions simply by copying your cookie jar. - os.chmod(self.cookie_jar, 0600) + os.chmod(cookie_jar, 0600) except: pass @@ -230,18 +255,21 @@ class CookieMonster: '''Create AF_UNIX socket for interprocess uzbl instance <-> cookie daemon communication.''' + cookie_socket = config['cookie_socket'] + mkbasedir(cookie_socket) + self.server_socket = socket.socket(socket.AF_UNIX,\ socket.SOCK_SEQPACKET) - if os.path.exists(self.cookie_socket): + if os.path.exists(cookie_socket): # Accounting for super-rare super-fast racetrack condition. self.reclaim_socket() - self.server_socket.bind(self.cookie_socket) + self.server_socket.bind(cookie_socket) # Set restrictive permissions on the cookie socket to prevent other # users on the system from data-mining your cookies. - os.chmod(self.cookie_socket, 0600) + os.chmod(cookie_socket, 0600) def listen(self): @@ -259,9 +287,9 @@ class CookieMonster: self.last_request = time.time() client_socket.close() - if self.daemon_timeout: + if config['daemon_timeout']: idle = time.time() - self.last_request - if idle > self.daemon_timeout: break + if idle > config['daemon_timeout']: break def handle_request(self, client_socket): @@ -275,7 +303,7 @@ class CookieMonster: argv = data.split("\0") # Determine whether or not to print cookie data to terminal. - print_cookie = (verbose and not self.daemon_mode) + print_cookie = (config['verbose'] and not config['daemon_mode']) if print_cookie: print ' '.join(argv[:4]) action = argv[0] @@ -334,11 +362,74 @@ class CookieMonster: if self.server_socket: self.server_socket.close() - if os.path.exists(self.cookie_socket): - os.remove(self.cookie_socket) + cookie_socket = config['cookie_socket'] + if os.path.exists(cookie_socket): + echo("deleting socket %r" % cookie_socket) + os.remove(cookie_socket) if __name__ == "__main__": - CookieMonster(cookie_socket, cookie_jar, daemon_timeout,\ - daemon_mode).run() + + parser = OptionParser() + parser.add_option('-d', '--daemon-mode', dest='daemon_mode',\ + action='store_true', help="daemonise the cookie handler.") + + parser.add_option('-n', '--no-daemon', dest='no_daemon',\ + action='store_true', help="don't daemonise the process.") + + parser.add_option('-v', '--verbose', dest="verbose",\ + action='store_true', help="print verbose output.") + + parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout',\ + action="store", metavar="SECONDS", help="shutdown the daemon after x "\ + "seconds inactivity. WARNING: Do not use this when launching the "\ + "cookie daemon manually.") + + parser.add_option('-s', '--cookie-socket', dest="cookie_socket",\ + metavar="SOCKET", help="manually specify the socket location.") + + parser.add_option('-j', '--cookie-jar', dest='cookie_jar',\ + metavar="FILE", help="manually specify the cookie jar location.") + + (options, args) = parser.parse_args() + + if options.daemon_mode and options.no_daemon: + config['verbose'] = True + echo("fatal error: conflicting options --daemon-mode & --no-daemon") + sys.exit(1) + + if options.verbose: + config['verbose'] = True + echo("verbose mode on.") + + if options.daemon_mode: + echo("daemon mode on.") + config['daemon_mode'] = True + + if options.no_daemon: + echo("daemon mode off") + config['daemon_mode'] = False + + if options.cookie_socket: + echo("using cookie_socket %r" % options.cookie_socket) + config['cookie_socket'] = options.cookie_socket + + if options.cookie_jar: + echo("using cookie_jar %r" % options.cookie_jar) + config['cookie_jar'] = options.cookie_jar + + if options.daemon_timeout: + try: + config['daemon_timeout'] = int(options.daemon_timeout) + echo("set timeout to %d seconds." % config['daemon_timeout']) + + except ValueError: + config['verbose'] = True + echo("fatal error: expected int argument for --daemon-timeout") + sys.exit(1) + + for key in ['cookie_socket', 'cookie_jar']: + config[key] = os.path.expandvars(config[key]) + + CookieMonster().run() -- cgit v1.2.3 From 8a3d2dc65e7c4882b81d51f3a4fd81403147a73d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 00:50:45 +0800 Subject: Removed redundant --daemon-mode command & fixed broken socket errors --- examples/data/uzbl/scripts/cookie_daemon.py | 78 ++++++++++++++++------------- 1 file changed, 44 insertions(+), 34 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index eb6f4af..8adb2d3 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -21,8 +21,6 @@ # Issues: # - There is no easy way of stopping a running daemon. -# - Some users experience the broken pipe socket error seemingly randomly. -# Currently when a broken pipe error is received the daemon fatally fails. # Todo list: @@ -30,7 +28,6 @@ # - add {start|stop|restart} command line arguments to make the cookie_daemon # functionally similar to the daemons found in /etc/init.d/ (in gentoo) # or /etc/rc.d/ (in arch). -# - Recover from broken pipe socket errors. # - Add option to create a throwaway cookie jar in /tmp and delete it upon # closing the daemon. @@ -43,6 +40,7 @@ import select import socket import time import atexit +from traceback import print_exc from signal import signal, SIGTERM from optparse import OptionParser @@ -83,8 +81,7 @@ config = { # Set to 0 by default until talk_to_socket is doing the spawning. 'daemon_timeout': 0, - # Enable/disable daemonizing the process (useful when debugging). - # Set to False by default until talk_to_socket is doing the spawning. + # Tell process to daemonise 'daemon_mode': True, # Set true to print helpful debugging messages to the terminal. @@ -122,6 +119,7 @@ class CookieMonster: self.server_socket = None self.jar = None self.last_request = time.time() + self._running = False def run(self): @@ -144,26 +142,36 @@ class CookieMonster: # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - # Create cookie daemon socket. - self.create_socket() - # Create cookie jar object from file. self.open_cookie_jar() - try: - # Listen for incoming cookie puts/gets. - echo("listening on %r" % config['cookie_socket']) - self.listen() + # Creating a way to exit nested loops by setting a running flag. + self._running = True - except KeyboardInterrupt: - print + while self._running: + # Create cookie daemon socket. + self.create_socket() - except: - # Clean up - self.del_socket() + try: + # Enter main listen loop. + self.listen() + + except KeyboardInterrupt: + self._running = False + print - # Raise exception - raise + except socket.error: + print_exc() + + except: + # Clean up + self.del_socket() + + # Raise exception + raise + + # Always delete the socket before calling create again. + self.del_socket() def reclaim_socket(self): @@ -275,7 +283,9 @@ class CookieMonster: def listen(self): '''Listen for incoming cookie PUT and GET requests.''' - while True: + echo("listening on %r" % config['cookie_socket']) + + while self._running: # This line tells the socket how many pending incoming connections # to enqueue. I haven't had any broken pipe errors so far while # using the non-obvious value of 1 under heavy load conditions. @@ -289,7 +299,8 @@ class CookieMonster: if config['daemon_timeout']: idle = time.time() - self.last_request - if idle > config['daemon_timeout']: break + if idle > config['daemon_timeout']: + self._running = False def handle_request(self, client_socket): @@ -302,6 +313,11 @@ class CookieMonster: # Cookie argument list in packet is null separated. argv = data.split("\0") + # Catch the EXIT command sent to kill the daemon. + if len(argv) == 1 and argv[0].strip() == "EXIT": + self._running = False + return None + # Determine whether or not to print cookie data to terminal. print_cookie = (config['verbose'] and not config['daemon_mode']) if print_cookie: print ' '.join(argv[:4]) @@ -360,7 +376,13 @@ class CookieMonster: is the daemons pid file equivalent.''' if self.server_socket: - self.server_socket.close() + try: + self.server_socket.close() + + except: + pass + + self.server_socket = None cookie_socket = config['cookie_socket'] if os.path.exists(cookie_socket): @@ -372,9 +394,6 @@ if __name__ == "__main__": parser = OptionParser() - parser.add_option('-d', '--daemon-mode', dest='daemon_mode',\ - action='store_true', help="daemonise the cookie handler.") - parser.add_option('-n', '--no-daemon', dest='no_daemon',\ action='store_true', help="don't daemonise the process.") @@ -394,19 +413,10 @@ if __name__ == "__main__": (options, args) = parser.parse_args() - if options.daemon_mode and options.no_daemon: - config['verbose'] = True - echo("fatal error: conflicting options --daemon-mode & --no-daemon") - sys.exit(1) - if options.verbose: config['verbose'] = True echo("verbose mode on.") - if options.daemon_mode: - echo("daemon mode on.") - config['daemon_mode'] = True - if options.no_daemon: echo("daemon mode off") config['daemon_mode'] = False -- cgit v1.2.3 From bdfa6ebf88d1f0af0403f9e345bbffa3cbc65044 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 00:58:40 +0800 Subject: Added link to cookie_daemon.py wiki page. --- examples/data/uzbl/scripts/cookie_daemon.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 8adb2d3..f661a9f 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -17,12 +17,13 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - - +# +# For configuration and cookie daemon usage examples check out the the +# cookie daemon wiki page at http://www.uzbl.org/wiki/cookie_daemon.py +# # Issues: # - There is no easy way of stopping a running daemon. - - +# # Todo list: # - Use a pid file to make stopping a running daemon easy. # - add {start|stop|restart} command line arguments to make the cookie_daemon -- cgit v1.2.3 From 5c381e25c7e6e74441a332809d79750ca44b4d7f Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sat, 8 Aug 2009 17:57:48 +0100 Subject: Add option to cookie_daemon.py to not write cookies to disk. --- examples/data/uzbl/scripts/cookie_daemon.py | 37 ++++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index f661a9f..8be495e 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -29,8 +29,6 @@ # - add {start|stop|restart} command line arguments to make the cookie_daemon # functionally similar to the daemons found in /etc/init.d/ (in gentoo) # or /etc/rc.d/ (in arch). -# - Add option to create a throwaway cookie jar in /tmp and delete it upon -# closing the daemon. import cookielib @@ -242,22 +240,24 @@ class CookieMonster: '''Open the cookie jar.''' cookie_jar = config['cookie_jar'] - mkbasedir(cookie_jar) + if config['cookie_jar']: + mkbasedir(cookie_jar) # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) - try: - # Attempt to load cookies from the cookie jar. - self.jar.load(ignore_discard=True) + if config['cookie_jar']: + try: + # Attempt to load cookies from the cookie jar. + self.jar.load(ignore_discard=True) - # Ensure restrictive permissions are set on the cookie jar - # to prevent other users on the system from hi-jacking your - # authenticated sessions simply by copying your cookie jar. - os.chmod(cookie_jar, 0600) + # Ensure restrictive permissions are set on the cookie jar + # to prevent other users on the system from hi-jacking your + # authenticated sessions simply by copying your cookie jar. + os.chmod(cookie_jar, 0600) - except: - pass + except: + pass def create_socket(self): @@ -358,7 +358,8 @@ class CookieMonster: res = urllib2.addinfourl(StringIO.StringIO(), hdr,\ req.get_full_url()) self.jar.extract_cookies(res,req) - self.jar.save(ignore_discard=True) + if config['cookie_jar']: + self.jar.save(ignore_discard=True) if print_cookie: print @@ -412,6 +413,9 @@ if __name__ == "__main__": parser.add_option('-j', '--cookie-jar', dest='cookie_jar',\ metavar="FILE", help="manually specify the cookie jar location.") + parser.add_option('-m', '--memory', dest='memory', action='store_true', + help="store cookies in memory only - do not write to disk") + (options, args) = parser.parse_args() if options.verbose: @@ -430,6 +434,10 @@ if __name__ == "__main__": echo("using cookie_jar %r" % options.cookie_jar) config['cookie_jar'] = options.cookie_jar + if options.memory: + echo("using memory %r" % options.memory) + config['cookie_jar'] = None + if options.daemon_timeout: try: config['daemon_timeout'] = int(options.daemon_timeout) @@ -441,6 +449,7 @@ if __name__ == "__main__": sys.exit(1) for key in ['cookie_socket', 'cookie_jar']: - config[key] = os.path.expandvars(config[key]) + if config[key]: + config[key] = os.path.expandvars(config[key]) CookieMonster().run() -- cgit v1.2.3 From b1f012aa38fd0238a2e88d6a96ccc23986dd2d96 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 01:18:24 +0800 Subject: Cleaned up trailing whitespace. --- examples/data/uzbl/scripts/cookie_daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index f661a9f..8a2e154 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -18,7 +18,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -# For configuration and cookie daemon usage examples check out the the +# For configuration and cookie daemon usage examples check out the the # cookie daemon wiki page at http://www.uzbl.org/wiki/cookie_daemon.py # # Issues: @@ -443,4 +443,4 @@ if __name__ == "__main__": for key in ['cookie_socket', 'cookie_jar']: config[key] = os.path.expandvars(config[key]) - CookieMonster().run() + CookieMonster().run() \ No newline at end of file -- cgit v1.2.3 From 6c2d3df5e74340a781ca7a53b4af660aaad404f8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 02:05:10 +0800 Subject: Minor changes to cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 8be495e..3451727 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -18,7 +18,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -# For configuration and cookie daemon usage examples check out the the +# For configuration and cookie daemon usage examples check out the the # cookie daemon wiki page at http://www.uzbl.org/wiki/cookie_daemon.py # # Issues: @@ -240,13 +240,13 @@ class CookieMonster: '''Open the cookie jar.''' cookie_jar = config['cookie_jar'] - if config['cookie_jar']: + if cookie_jar: mkbasedir(cookie_jar) # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) - if config['cookie_jar']: + if cookie_jar: try: # Attempt to load cookies from the cookie jar. self.jar.load(ignore_discard=True) @@ -414,7 +414,7 @@ if __name__ == "__main__": metavar="FILE", help="manually specify the cookie jar location.") parser.add_option('-m', '--memory', dest='memory', action='store_true', - help="store cookies in memory only - do not write to disk") + help="store cookies in memory only - do not write to disk") (options, args) = parser.parse_args() @@ -423,7 +423,7 @@ if __name__ == "__main__": echo("verbose mode on.") if options.no_daemon: - echo("daemon mode off") + echo("daemon mode off.") config['daemon_mode'] = False if options.cookie_socket: @@ -448,6 +448,7 @@ if __name__ == "__main__": echo("fatal error: expected int argument for --daemon-timeout") sys.exit(1) + # Expand $VAR's in config keys that relate to paths. for key in ['cookie_socket', 'cookie_jar']: if config[key]: config[key] = os.path.expandvars(config[key]) -- cgit v1.2.3 From e7b142d92aa14e523bd097c1acb3f607517aefbd Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 15:08:09 +0800 Subject: cookie_daemon.py now has a 9.78/10 pylint rating. --- examples/data/uzbl/scripts/cookie_daemon.py | 313 +++++++++++++++++----------- 1 file changed, 197 insertions(+), 116 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 5501251..13f38e1 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -17,19 +17,75 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# -# For configuration and cookie daemon usage examples check out the the -# cookie daemon wiki page at http://www.uzbl.org/wiki/cookie_daemon.py -# -# Issues: -# - There is no easy way of stopping a running daemon. -# -# Todo list: -# - Use a pid file to make stopping a running daemon easy. -# - add {start|stop|restart} command line arguments to make the cookie_daemon -# functionally similar to the daemons found in /etc/init.d/ (in gentoo) -# or /etc/rc.d/ (in arch). +''' +The Python Cookie Daemon +======================== + +This application is a re-write of the original cookies.py script found in +uzbl's master branch. This script provides more functionality than the original +cookies.py by adding command line options to specify different cookie jar +locations, socket locations, verbose output, etc. + +Keep up to date +=============== + +Check the cookie daemon uzbl-wiki page for more information on where to +find the latest version of the cookie_daemon.py + + http://www.uzbl.org/wiki/cookie_daemon.py + +Command line options +==================== + +Usage: cookie_daemon.py [options] + +Options: + -h, --help show this help message and exit + -n, --no-daemon don't daemonise the process. + -v, --verbose print verbose output. + -t SECONDS, --daemon-timeout=SECONDS + shutdown the daemon after x seconds inactivity. + WARNING: Do not use this when launching the cookie + daemon manually. + -s SOCKET, --cookie-socket=SOCKET + manually specify the socket location. + -j FILE, --cookie-jar=FILE + manually specify the cookie jar location. + -m, --memory store cookies in memory only - do not write to disk + +Talking with uzbl +================= + +In order to get uzbl to talk to a running cookie daemon you add the following +to your uzbl config: + + set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket + +Or if you prefer using the $HOME variable: + + set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket + +Issues +====== + + - There is no easy way of stopping a running daemon. + +Todo list +========= + + - Use a pid file to make stopping a running daemon easy. + - add {start|stop|restart} command line arguments to make the cookie_daemon + functionally similar to the daemons found in /etc/init.d/ (in gentoo) + or /etc/rc.d/ (in arch). + +Reporting bugs / getting help +============================= + +The best and fastest way to get hold of the maintainers of the cookie_daemon.py +is to send them a message in the #uzbl irc channel found on the Freenode IRC +network (irc.freenode.org). +''' import cookielib import os @@ -57,24 +113,24 @@ except ImportError: # Location of the uzbl cache directory. if 'XDG_CACHE_HOME' in os.environ.keys() and os.environ['XDG_CACHE_HOME']: - cache_dir = os.path.join(os.environ['XDG_CACHE_HOME'], 'uzbl/') + CACHE_DIR = os.path.join(os.environ['XDG_CACHE_HOME'], 'uzbl/') else: - cache_dir = os.path.join(os.environ['HOME'], '.cache/uzbl/') + CACHE_DIR = os.path.join(os.environ['HOME'], '.cache/uzbl/') # Location of the uzbl data directory. if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') + DATA_DIR = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') else: - data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') + DATA_DIR = os.path.join(os.environ['HOME'], '.local/share/uzbl/') # Default config config = { # Default cookie jar and daemon socket locations. - 'cookie_socket': os.path.join(cache_dir, 'cookie_daemon_socket'), - 'cookie_jar': os.path.join(data_dir, 'cookies.txt'), + 'cookie_socket': os.path.join(CACHE_DIR, 'cookie_daemon_socket'), + 'cookie_jar': os.path.join(DATA_DIR, 'cookies.txt'), # Time out after x seconds of inactivity (set to 0 for never time out). # Set to 0 by default until talk_to_socket is doing the spawning. @@ -94,10 +150,12 @@ config = { # ============================================================================ -_scriptname = os.path.basename(sys.argv[0]) +_SCRIPTNAME = os.path.basename(sys.argv[0]) def echo(msg): + '''Prints messages sent to it only if the verbose flag has been set.''' + if config['verbose']: - print "%s: %s" % (_scriptname, msg) + print "%s: %s" % (_SCRIPTNAME, msg) def mkbasedir(filepath): @@ -109,6 +167,73 @@ def mkbasedir(filepath): os.makedirs(dirname) +def reclaim_socket(): + '''Check if another process (hopefully a cookie_daemon.py) is listening + on the cookie daemon socket. If another process is found to be + listening on the socket exit the daemon immediately and leave the + socket alone. If the connect fails assume the socket has been abandoned + and delete it (to be re-created in the create socket function).''' + + cookie_socket = config['cookie_socket'] + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.close() + + except socket.error: + # Failed to connect to cookie_socket so assume it has been + # abandoned by another cookie daemon process. + echo("reclaiming abandoned cookie_socket %r." % cookie_socket) + if os.path.exists(cookie_socket): + os.remove(cookie_socket) + + return + + echo("detected another process listening on %r." % cookie_socket) + echo("exiting.") + # Use os._exit() to avoid tripping the atexit cleanup function. + sys.exit(1) + + +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + class CookieMonster: '''The uzbl cookie daemon class.''' @@ -128,12 +253,12 @@ class CookieMonster: # exit if another daemon is detected listening on the cookie socket # and remove the abandoned socket if there isnt. if os.path.exists(config['cookie_socket']): - self.reclaim_socket() + reclaim_socket() # Daemonize process. if config['daemon_mode']: echo("entering daemon mode.") - self.daemonize() + daemonize() # Register a function to cleanup on exit. atexit.register(self.quit) @@ -173,69 +298,6 @@ class CookieMonster: self.del_socket() - def reclaim_socket(self): - '''Check if another process (hopefully a cookie_daemon.py) is listening - on the cookie daemon socket. If another process is found to be - listening on the socket exit the daemon immediately and leave the - socket alone. If the connect fails assume the socket has been abandoned - and delete it (to be re-created in the create socket function).''' - - cookie_socket = config['cookie_socket'] - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(cookie_socket) - sock.close() - - except socket.error: - # Failed to connect to cookie_socket so assume it has been - # abandoned by another cookie daemon process. - echo("reclaiming abandoned cookie_socket %r." % cookie_socket) - if os.path.exists(cookie_socket): - os.remove(cookie_socket) - - return - - echo("detected another process listening on %r." % cookie_socket) - echo("exiting.") - # Use os._exit() to avoid tripping the atexit cleanup function. - os._exit(1) - - - def daemonize(function): - '''Daemonize the process using the Stevens' double-fork magic.''' - - try: - if os.fork(): os._exit(0) - - except OSError, e: - sys.stderr.write("fork #1 failed: %s\n" % e) - sys.exit(1) - - os.chdir('/') - os.setsid() - os.umask(0) - - try: - if os.fork(): os._exit(0) - - except OSError, e: - sys.stderr.write("fork #2 failed: %s\n" % e) - sys.exit(1) - - sys.stdout.flush() - sys.stderr.flush() - - devnull = '/dev/null' - stdin = file(devnull, 'r') - stdout = file(devnull, 'a+') - stderr = file(devnull, 'a+', 0) - - os.dup2(stdin.fileno(), sys.stdin.fileno()) - os.dup2(stdout.fileno(), sys.stdout.fileno()) - os.dup2(stderr.fileno(), sys.stderr.fileno()) - - def open_cookie_jar(self): '''Open the cookie jar.''' @@ -267,12 +329,12 @@ class CookieMonster: cookie_socket = config['cookie_socket'] mkbasedir(cookie_socket) - self.server_socket = socket.socket(socket.AF_UNIX,\ + self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) if os.path.exists(cookie_socket): # Accounting for super-rare super-fast racetrack condition. - self.reclaim_socket() + reclaim_socket() self.server_socket.bind(cookie_socket) @@ -292,7 +354,7 @@ class CookieMonster: # using the non-obvious value of 1 under heavy load conditions. self.server_socket.listen(1) - if bool(select.select([self.server_socket],[],[],1)[0]): + if bool(select.select([self.server_socket], [], [], 1)[0]): client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) self.last_request = time.time() @@ -309,7 +371,8 @@ class CookieMonster: # Receive cookie request from client. data = client_socket.recv(8192) - if not data: return + if not data: + return # Cookie argument list in packet is null separated. argv = data.split("\0") @@ -321,7 +384,8 @@ class CookieMonster: # Determine whether or not to print cookie data to terminal. print_cookie = (config['verbose'] and not config['daemon_mode']) - if print_cookie: print ' '.join(argv[:4]) + if print_cookie: + print ' '.join(argv[:4]) action = argv[0] @@ -340,37 +404,40 @@ class CookieMonster: if req.has_header('Cookie'): cookie = req.get_header('Cookie') client_socket.send(cookie) - if print_cookie: print cookie + if print_cookie: + print cookie else: client_socket.send("\0") elif action == "PUT": - if len(argv) > 3: - set_cookie = argv[4] - if print_cookie: print set_cookie + cookie = argv[4] if len(argv) > 3 else None + if print_cookie: + print cookie + + self.put_cookie(req, cookie) + + if print_cookie: + print - else: - set_cookie = None - hdr = urllib2.httplib.HTTPMessage(\ - StringIO.StringIO('Set-Cookie: %s' % set_cookie)) - res = urllib2.addinfourl(StringIO.StringIO(), hdr,\ - req.get_full_url()) - self.jar.extract_cookies(res,req) - if config['cookie_jar']: - self.jar.save(ignore_discard=True) + def put_cookie(self, req, cookie=None): + '''Put a cookie in the cookie jar.''' - if print_cookie: print + hdr = urllib2.httplib.HTTPMessage(\ + StringIO.StringIO('Set-Cookie: %s' % cookie)) + res = urllib2.addinfourl(StringIO.StringIO(), hdr, + req.get_full_url()) + self.jar.extract_cookies(res, req) + if config['cookie_jar']: + self.jar.save(ignore_discard=True) - def quit(self, *args): + def quit(self): '''Called on exit to make sure all loose ends are tied up.''' - # Only one loose end so far. self.del_socket() - - os._exit(0) + sys.exit(0) def del_socket(self): @@ -392,32 +459,42 @@ class CookieMonster: os.remove(cookie_socket) -if __name__ == "__main__": - +def main(): + '''Main function.''' + # Define command line parameters. parser = OptionParser() - parser.add_option('-n', '--no-daemon', dest='no_daemon',\ + parser.add_option('-n', '--no-daemon', dest='no_daemon', action='store_true', help="don't daemonise the process.") - parser.add_option('-v', '--verbose', dest="verbose",\ + parser.add_option('-v', '--verbose', dest="verbose", action='store_true', help="print verbose output.") - parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout',\ + parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout', action="store", metavar="SECONDS", help="shutdown the daemon after x "\ "seconds inactivity. WARNING: Do not use this when launching the "\ "cookie daemon manually.") - parser.add_option('-s', '--cookie-socket', dest="cookie_socket",\ + parser.add_option('-s', '--cookie-socket', dest="cookie_socket", metavar="SOCKET", help="manually specify the socket location.") - parser.add_option('-j', '--cookie-jar', dest='cookie_jar',\ + parser.add_option('-j', '--cookie-jar', dest='cookie_jar', metavar="FILE", help="manually specify the cookie jar location.") parser.add_option('-m', '--memory', dest='memory', action='store_true', help="store cookies in memory only - do not write to disk") + # Parse the command line arguments. (options, args) = parser.parse_args() + if len(args): + config['verbose'] = True + for arg in args: + echo("unknown argument %r" % arg) + + echo("exiting.") + sys.exit(1) + if options.verbose: config['verbose'] = True echo("verbose mode on.") @@ -453,4 +530,8 @@ if __name__ == "__main__": if config[key]: config[key] = os.path.expandvars(config[key]) - CookieMonster().run() \ No newline at end of file + CookieMonster().run() + + +if __name__ == "__main__": + main() -- cgit v1.2.3 From 29c9641e146e9c567572d116dc3eef5baa282b7a Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 15:14:21 +0800 Subject: Fix wording in docstring. --- examples/data/uzbl/scripts/cookie_daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 13f38e1..c9931c9 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -27,8 +27,8 @@ uzbl's master branch. This script provides more functionality than the original cookies.py by adding command line options to specify different cookie jar locations, socket locations, verbose output, etc. -Keep up to date -=============== +Keeping up to date +================== Check the cookie daemon uzbl-wiki page for more information on where to find the latest version of the cookie_daemon.py -- cgit v1.2.3 From ff9c6e807322a288cfb46cb75291d0337f58e85e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 9 Aug 2009 15:42:06 +0800 Subject: Fix docstring --- examples/data/uzbl/scripts/cookie_daemon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index c9931c9..3546d92 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -152,7 +152,7 @@ config = { _SCRIPTNAME = os.path.basename(sys.argv[0]) def echo(msg): - '''Prints messages sent to it only if the verbose flag has been set.''' + '''Prints messages sent only if the verbose flag has been set.''' if config['verbose']: print "%s: %s" % (_SCRIPTNAME, msg) -- cgit v1.2.3 From fa4f3430215808ae4f9af78f00869e9a96b244ef Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 10 Aug 2009 17:00:15 +0800 Subject: General code and comment cleanups in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 113 +++++++++++++++------------- 1 file changed, 59 insertions(+), 54 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 3546d92..af53e73 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -22,10 +22,12 @@ The Python Cookie Daemon ======================== -This application is a re-write of the original cookies.py script found in -uzbl's master branch. This script provides more functionality than the original -cookies.py by adding command line options to specify different cookie jar -locations, socket locations, verbose output, etc. +This daemon is a re-write of the original cookies.py script found in uzbl's +master branch. This script provides more functionality than the original +cookies.py by adding numerous command line options to specify different cookie +jar locations, socket locations, verbose output, etc. This functionality is +very useful as it allows you to run multiple daemons at once serving cookies +to different groups of uzbl instances as required. Keeping up to date ================== @@ -82,8 +84,8 @@ Todo list Reporting bugs / getting help ============================= -The best and fastest way to get hold of the maintainers of the cookie_daemon.py -is to send them a message in the #uzbl irc channel found on the Freenode IRC +The best way to report bugs and or get help with the cookie daemon is to +contact the maintainers it the #uzbl irc channel found on the Freenode IRC network (irc.freenode.org). ''' @@ -133,13 +135,13 @@ config = { 'cookie_jar': os.path.join(DATA_DIR, 'cookies.txt'), # Time out after x seconds of inactivity (set to 0 for never time out). - # Set to 0 by default until talk_to_socket is doing the spawning. + # WARNING: Do not use this option if you are manually launching the daemon. 'daemon_timeout': 0, - # Tell process to daemonise + # Daemonise by default. 'daemon_mode': True, - # Set true to print helpful debugging messages to the terminal. + # Optionally print helpful debugging messages to the terminal. 'verbose': False, } # End of config dictionary. @@ -152,14 +154,22 @@ config = { _SCRIPTNAME = os.path.basename(sys.argv[0]) def echo(msg): - '''Prints messages sent only if the verbose flag has been set.''' + '''Prints only if the verbose flag has been set.''' if config['verbose']: - print "%s: %s" % (_SCRIPTNAME, msg) + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error message and exits.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + sys.exit(1) def mkbasedir(filepath): - '''Create base directory of filepath if it doesn't exist.''' + '''Create the base directories of the file in the file-path if the dirs + don't exist.''' dirname = os.path.dirname(filepath) if not os.path.exists(dirname): @@ -167,34 +177,36 @@ def mkbasedir(filepath): os.makedirs(dirname) -def reclaim_socket(): +def check_socket_health(cookie_socket): '''Check if another process (hopefully a cookie_daemon.py) is listening on the cookie daemon socket. If another process is found to be listening on the socket exit the daemon immediately and leave the socket alone. If the connect fails assume the socket has been abandoned and delete it (to be re-created in the create socket function).''' - cookie_socket = config['cookie_socket'] + if not os.path.exists(cookie_socket): + # What once was is now no more. + return None + + if os.path.isfile(cookie_socket): + error("regular file at %r is not a socket" % cookie_socket) + + if os.path.isdir(cookie_socket): + error("directory at %r is not a socket" % cookie_socket) try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) sock.connect(cookie_socket) sock.close() + error("detected another process listening on %r" % cookie_socket) except socket.error: # Failed to connect to cookie_socket so assume it has been # abandoned by another cookie daemon process. - echo("reclaiming abandoned cookie_socket %r." % cookie_socket) if os.path.exists(cookie_socket): + echo("deleting abandoned socket %r" % cookie_socket) os.remove(cookie_socket) - return - - echo("detected another process listening on %r." % cookie_socket) - echo("exiting.") - # Use os._exit() to avoid tripping the atexit cleanup function. - sys.exit(1) - def daemonize(): '''Daemonize the process using the Stevens' double-fork magic.''' @@ -249,15 +261,15 @@ class CookieMonster: def run(self): '''Start the daemon.''' - # Check if another daemon is running. The reclaim_socket function will - # exit if another daemon is detected listening on the cookie socket - # and remove the abandoned socket if there isnt. + # The check healthy function will exit if another daemon is detected + # listening on the cookie socket and remove the abandoned socket if + # there isnt. if os.path.exists(config['cookie_socket']): - reclaim_socket() + check_socket_health(config['cookie_socket']) # Daemonize process. if config['daemon_mode']: - echo("entering daemon mode.") + echo("entering daemon mode") daemonize() # Register a function to cleanup on exit. @@ -269,7 +281,7 @@ class CookieMonster: # Create cookie jar object from file. self.open_cookie_jar() - # Creating a way to exit nested loops by setting a running flag. + # Create a way to exit nested loops by setting a running flag. self._running = True while self._running: @@ -323,8 +335,7 @@ class CookieMonster: def create_socket(self): - '''Create AF_UNIX socket for interprocess uzbl instance <-> cookie - daemon communication.''' + '''Create AF_UNIX socket for communication with uzbl instances.''' cookie_socket = config['cookie_socket'] mkbasedir(cookie_socket) @@ -334,7 +345,7 @@ class CookieMonster: if os.path.exists(cookie_socket): # Accounting for super-rare super-fast racetrack condition. - reclaim_socket() + check_socket_health(cookie_socket) self.server_socket.bind(cookie_socket) @@ -350,8 +361,8 @@ class CookieMonster: while self._running: # This line tells the socket how many pending incoming connections - # to enqueue. I haven't had any broken pipe errors so far while - # using the non-obvious value of 1 under heavy load conditions. + # to enqueue at once. Raising this number may or may not increase + # performance. self.server_socket.listen(1) if bool(select.select([self.server_socket], [], [], 1)[0]): @@ -361,6 +372,7 @@ class CookieMonster: client_socket.close() if config['daemon_timeout']: + # Checks if the daemon has been idling for too long. idle = time.time() - self.last_request if idle > config['daemon_timeout']: self._running = False @@ -377,10 +389,10 @@ class CookieMonster: # Cookie argument list in packet is null separated. argv = data.split("\0") - # Catch the EXIT command sent to kill the daemon. + # Catch the EXIT command sent to kill running daemons. if len(argv) == 1 and argv[0].strip() == "EXIT": self._running = False - return None + return # Determine whether or not to print cookie data to terminal. print_cookie = (config['verbose'] and not config['daemon_mode']) @@ -433,13 +445,6 @@ class CookieMonster: self.jar.save(ignore_discard=True) - def quit(self): - '''Called on exit to make sure all loose ends are tied up.''' - - self.del_socket() - sys.exit(0) - - def del_socket(self): '''Remove the cookie_socket file on exit. In a way the cookie_socket is the daemons pid file equivalent.''' @@ -459,6 +464,13 @@ class CookieMonster: os.remove(cookie_socket) + def quit(self): + '''Called on exit to make sure all loose ends are tied up.''' + + self.del_socket() + sys.exit(0) + + def main(): '''Main function.''' @@ -488,19 +500,14 @@ def main(): (options, args) = parser.parse_args() if len(args): - config['verbose'] = True - for arg in args: - echo("unknown argument %r" % arg) - - echo("exiting.") - sys.exit(1) + error("unknown argument %r" % args[0]) if options.verbose: config['verbose'] = True - echo("verbose mode on.") + echo("verbose mode on") if options.no_daemon: - echo("daemon mode off.") + echo("daemon mode off") config['daemon_mode'] = False if options.cookie_socket: @@ -518,12 +525,10 @@ def main(): if options.daemon_timeout: try: config['daemon_timeout'] = int(options.daemon_timeout) - echo("set timeout to %d seconds." % config['daemon_timeout']) + echo("set timeout to %d seconds" % config['daemon_timeout']) except ValueError: - config['verbose'] = True - echo("fatal error: expected int argument for --daemon-timeout") - sys.exit(1) + error("expected int argument for -t, --daemon-timeout") # Expand $VAR's in config keys that relate to paths. for key in ['cookie_socket', 'cookie_jar']: -- cgit v1.2.3 From d65956b40cb3b4c1ba21b54d2e5184d67c27cbe9 Mon Sep 17 00:00:00 2001 From: Paweł Zuzelski Date: Fri, 21 Aug 2009 11:57:02 +0200 Subject: Pass proxy_url to download handler Pass the value of proxy_url variable as optional 9th argument of download handler. Added support for http proxy to the example download handler script. Updated README file. --- README | 1 + examples/data/uzbl/scripts/download.sh | 3 +++ uzbl.c | 12 +++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/README b/README index b36293c..f9037c9 100644 --- a/README +++ b/README @@ -364,6 +364,7 @@ The script specific arguments are this: * download: $8 url of item to download + $9 url of http proxy (optional) * cookie handler diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh index aa1ca09..c8eb6ba 100755 --- a/examples/data/uzbl/scripts/download.sh +++ b/examples/data/uzbl/scripts/download.sh @@ -8,6 +8,9 @@ GET="wget --user-agent=Firefox" dest="$HOME" url="$8" +http_proxy="$9" +export http_proxy + test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } # only changes the dir for the $get sub process diff --git a/uzbl.c b/uzbl.c index e90d220..80a3cfc 100644 --- a/uzbl.c +++ b/uzbl.c @@ -565,7 +565,17 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { if (uzbl.state.verbose) printf("Download -> %s\n",uri); /* if urls not escaped, we may have to escape and quote uri before this call */ - run_handler(uzbl.behave.download_handler, uri); + + GString *args = g_string_new(uri); + + if (uzbl.net.proxy_url) { + g_string_append_c(args, ' '); + g_string_append(args, uzbl.net.proxy_url); + } + + run_handler(uzbl.behave.download_handler, args->str); + + g_string_free(args, TRUE); } return (FALSE); } -- cgit v1.2.3 From 769f5f32d395a2c01f0ab06f29da952b3d13485e Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Mon, 24 Aug 2009 08:28:00 +0100 Subject: Remove uzblctrl - use socat instead. --- .gitignore | 1 - Makefile | 5 +- Makefile-new-test | 5 +- README | 7 +-- docs/FAQ | 2 +- docs/INSTALL | 2 +- .../data/uzbl/scripts/load_url_from_bookmarks.sh | 2 +- .../data/uzbl/scripts/load_url_from_history.sh | 2 +- uzblctrl.c | 71 ---------------------- 9 files changed, 9 insertions(+), 88 deletions(-) delete mode 100644 uzblctrl.c (limited to 'examples') diff --git a/.gitignore b/.gitignore index 1ee1e9e..bbc3d90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ uzbl -uzblctrl uzbl.o *~ tags diff --git a/Makefile b/Makefile index fbc85a1..c5ddc60 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CFLAGS!=echo -std=c99 `pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthre LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -pthread $(LDFLAGS) LDFLAGS!=echo `pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0` -pthread $(LDFLAGS) -all: uzbl uzblctrl +all: uzbl PREFIX?=$(DESTDIR)/usr @@ -27,7 +27,6 @@ test-share: uzbl clean: rm -f uzbl - rm -f uzblctrl rm -f uzbl.o cd ./tests/; $(MAKE) clean @@ -36,7 +35,6 @@ install: install -d $(PREFIX)/share/uzbl/docs install -d $(PREFIX)/share/uzbl/examples install -m755 uzbl $(PREFIX)/bin/uzbl - install -m755 uzblctrl $(PREFIX)/bin/uzblctrl cp -rp docs $(PREFIX)/share/uzbl/ cp -rp config.h $(PREFIX)/share/uzbl/docs/ cp -rp examples $(PREFIX)/share/uzbl/ @@ -46,5 +44,4 @@ install: uninstall: rm -rf $(PREFIX)/bin/uzbl - rm -rf $(PREFIX)/bin/uzblctrl rm -rf $(PREFIX)/share/uzbl diff --git a/Makefile-new-test b/Makefile-new-test index 9f85a4e..a1efa56 100644 --- a/Makefile-new-test +++ b/Makefile-new-test @@ -12,7 +12,7 @@ UZBLDATA ?= $(PREFIX)/share/uzbl DOCSDIR ?= $(PREFIX)/share/uzbl/docs EXMPLSDIR ?= $(PREFIX)/share/uzbl/examples -all: uzbl uzblctrl +all: uzbl uzbl: uzbl.c uzbl.h config.h @@ -30,14 +30,12 @@ test-config-real: uzbl clean: rm -f uzbl - rm -f uzblctrl install: install -d $(BINDIR) install -d $(DOCSDIR) install -d $(EXMPLSDIR) install -D -m755 uzbl $(BINDIR)/uzbl - install -D -m755 uzblctrl $(BINDIR)/uzblctrl cp -ax docs/* $(DOCSDIR) cp -ax config.h $(DOCSDIR) cp -ax examples/* $(EXMPLSDIR) @@ -47,5 +45,4 @@ install: uninstall: rm -rf $(BINDIR)/uzbl - rm -rf $(BINDIR)/uzblctrl rm -rf $(UZBLDATA) diff --git a/README b/README index b36293c..fbb849f 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ Time to change that! - privoxy looks cool and perfectly demonstrates the unix philosphy. - same for http://bfilter.sourceforge.net - /etc/hosts (not very good cause you need root and it affects the whole system) - uzblctrl would need to support an option to list all images on a page, so you can easily pick the links to ads to add them to your /etc/hosts. + one can list all images on a page using the socket, so you can easily pick the links to ads to add them to your /etc/hosts. * vimperator/konqueror-like hyperlink following. * password management. maybe an encrypted store that unlocks with an ssh key? * no messing in the users $HOME or in /etc: no writing of anything unless the user (or sysadmin) asks for it. @@ -73,9 +73,8 @@ There are several interfaces to interact with uzbl: * shift insert (paste primary selection buffer) * FIFO & socket file: if enabled by setting their paths through one of the above means, you can have socket and fifo files available which are very useful to programatically control uzbl (from scripts etc). The advantage of the fifo is you can write plaintxt commands to it, but it's half duplex only (uzbl cannot send a response to you). - The socket is full duplex but you need a socket-compatible wrapper such as netcat to work with it, or uzblctrl of course, - an utitly we include with uzbl made especially for writing commnands to the socket (and at some point, it will be able to tell you the response - too): `uzblctrl -s -c ` + The socket is full duplex but you need a socket-compatible wrapper such as socat to work with it. + For example: echo | socat - unix-connect: When uzbl forks a new instance (eg "open in new window") it will use the same commandline arguments (eg the same --config ), except --uri and--name. If you made changes to the configuration at runtime, these are not pased on to the child. diff --git a/docs/FAQ b/docs/FAQ index f8e6e8a..b5c4dcc 100644 --- a/docs/FAQ +++ b/docs/FAQ @@ -112,7 +112,7 @@ Yes, Webkit takes care of all of that. Not that we like all of these, but you c They both have advantages and disadvantages: * fifo's are _very_ easy to work with. You can write just plaintext commands into them, but they are unidirectional (you can only communicate in one direction) - * Sockets are bidirectional but more complex. You cannot just write a plaintext string into them. In shellscripts you can use uzblctrl or netcat to work with sockets, when programming you need to use library functions. + * Sockets are bidirectional but more complex. You cannot just write a plaintext string into them. In shellscripts you can use socat to work with sockets, when programming you need to use library functions. So, when writing scripts, using fifo's is usually the fastest method (because you do not need to fork another process), so fifo is preferred unless you need a response. diff --git a/docs/INSTALL b/docs/INSTALL index 9213cc3..41acff1 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -48,7 +48,7 @@ File locations -------------- After installing - using either method - you will find: -* /usr/bin : uzbl [and uzblctrl] +* /usr/bin : uzbl * /usr/share/uzbl/docs/ : documentation files included with uzbl. (readme, checklist, .. ) * /usr/share/uzbl/examples: sample scripts, config files and a sample data (boomarks, .. ) diff --git a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh index f57d7b3..1e9f9e7 100755 --- a/examples/data/uzbl/scripts/load_url_from_bookmarks.sh +++ b/examples/data/uzbl/scripts/load_url_from_bookmarks.sh @@ -17,4 +17,4 @@ else fi #[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" +[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh index 1eaf0f2..62e02ac 100755 --- a/examples/data/uzbl/scripts/load_url_from_history.sh +++ b/examples/data/uzbl/scripts/load_url_from_history.sh @@ -21,4 +21,4 @@ else fi [ -n "$goto" ] && echo "uri $goto" > $4 -#[ -n "$goto" ] && uzblctrl -s $5 -c "uri $goto" +#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/uzblctrl.c b/uzblctrl.c deleted file mode 100644 index 2547bc7..0000000 --- a/uzblctrl.c +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- c-basic-offset: 4; -*- */ -/* Socket code more or less completely copied from here: http://www.ecst.csuchico.edu/~beej/guide/ipc/usock.html */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static gchar* sockpath; -static gchar* command; - -static GOptionEntry entries[] = -{ - { "socket", 's', 0, G_OPTION_ARG_STRING, &sockpath, "Path to the uzbl socket", NULL }, - { "command", 'c', 0, G_OPTION_ARG_STRING, &command, "The uzbl command to execute", NULL }, - { NULL, 0, 0, 0, NULL, NULL, NULL } -}; - -int -main(int argc, char* argv[]) { - GError *error = NULL; - GOptionContext* context = g_option_context_new ("- utility for controlling and interacting with uzbl through its socket file"); /* TODO: get stuff back from uzbl */ - g_option_context_add_main_entries (context, entries, NULL); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - g_option_context_parse (context, &argc, &argv, &error); - - - if (sockpath && command) { - int s, len; - struct sockaddr_un remote; - char tmp; - - if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) { - perror ("socket"); - exit (EXIT_FAILURE); - } - - remote.sun_family = AF_UNIX; - strcpy (remote.sun_path, (char *) sockpath); - len = strlen (remote.sun_path) + sizeof (remote.sun_family); - - if (connect (s, (struct sockaddr *) &remote, len) == -1) { - perror ("connect"); - exit (EXIT_FAILURE); - } - - if ((send (s, command, strlen (command), 0) == -1) || - (send (s, "\n", 1, 0) == -1)) { - perror ("send"); - exit (EXIT_FAILURE); - } - - while ((len = recv (s, &tmp, 1, 0))) { - putchar(tmp); - if (tmp == '\n') - break; - } - - close(s); - - return 0; - } else { - fprintf(stderr, "Usage: uzblctrl -s /path/to/socket -c \"command\""); - return 1; - } -} -/* vi: set et ts=4: */ -- cgit v1.2.3 From 46da0c91288a9c9d20af3a92c58b1dc6a00de4f4 Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 23 Aug 2009 20:16:25 +0100 Subject: Remove redundant history_handler. --- examples/config/uzbl/config | 3 +-- examples/data/uzbl/scripts/history.sh | 3 +-- uzbl.c | 15 --------------- uzbl.h | 4 ---- 4 files changed, 2 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index ab2cf7f..86f4268 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -4,14 +4,13 @@ # keyboard behavior in this sample config is sort of vimstyle # Handlers -set history_handler = spawn $XDG_DATA_HOME/uzbl/scripts/history.sh set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv -set load_finish_handler = set status_message = done +set load_finish_handler = chain 'set status_message = done' 'spawn $XDG_DATA_HOME/uzbl/scripts/history.sh' diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh index d726f9c..7c83aa6 100755 --- a/examples/data/uzbl/scripts/history.sh +++ b/examples/data/uzbl/scripts/history.sh @@ -1,6 +1,5 @@ #!/bin/sh -#TODO: strip 'http://' part file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history [ -d `dirname $file` ] || exit 1 -echo "$8 $6 $7" >> $file +echo `date +'%Y-%m-%d %H:%M:%S'`" $6 $7" >> $file diff --git a/uzbl.c b/uzbl.c index e90d220..76f1416 100644 --- a/uzbl.c +++ b/uzbl.c @@ -137,7 +137,6 @@ const struct var_name_to_ptr_t { { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)}, { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)}, { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)}, - { "history_handler", PTR_V_STR(uzbl.behave.history_handler, 1, NULL)}, { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)}, { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, cmd_new_window)}, @@ -750,19 +749,6 @@ destroy_cb (GtkWidget* widget, gpointer data) { gtk_main_quit (); } -void -log_history_cb () { - if (uzbl.behave.history_handler) { - time_t rawtime; - struct tm * timeinfo; - char date [80]; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); - strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo); - run_handler(uzbl.behave.history_handler, date); - } -} - /* VIEW funcs (little webkit wrappers) */ #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);} @@ -2318,7 +2304,6 @@ create_browser () { g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); diff --git a/uzbl.h b/uzbl.h index 658eae4..f43eaad 100644 --- a/uzbl.h +++ b/uzbl.h @@ -93,7 +93,6 @@ typedef struct { gchar* title_format_short; gchar* title_format_long; gchar* status_background; - gchar* history_handler; gchar* fifo_dir; gchar* socket_dir; gchar* download_handler; @@ -265,9 +264,6 @@ load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); void destroy_cb (GtkWidget* widget, gpointer data); -void -log_history_cb (); - void commands_hash(void); -- cgit v1.2.3 From 36859a3a174387421dd4397f5f14a3f62b0deeed Mon Sep 17 00:00:00 2001 From: Tom Adams Date: Sun, 23 Aug 2009 21:47:37 +0100 Subject: Don't reset keycmd in load_start_cb. To emulate the old functionality, include 'set keycmd = ' in your load_start_handler. Fixes: FS#86 - Command resets on load finish --- examples/config/uzbl/config | 2 +- uzbl.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 86f4268..890a0b9 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -8,7 +8,7 @@ set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour -set load_start_handler = set status_message = wait +set load_start_handler = chain 'set keycmd = ' 'set status_message = wait' set load_commit_handler = set status_message = recv set load_finish_handler = chain 'set status_message = done' 'spawn $XDG_DATA_HOME/uzbl/scripts/history.sh' diff --git a/uzbl.c b/uzbl.c index ec3828b..d016176 100644 --- a/uzbl.c +++ b/uzbl.c @@ -722,7 +722,6 @@ load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { (void) frame; (void) data; uzbl.gui.sbar.load_progress = 0; - clear_keycmd(); // don't need old commands to remain on new page? if (uzbl.behave.load_start_handler) run_handler(uzbl.behave.load_start_handler, ""); } -- cgit v1.2.3 From de07e980a04ac794b5820b765f50b6926415f8b2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 26 Aug 2009 21:25:11 +0800 Subject: When closing uzbl_tabbed.py with one tab open don't save a session. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 41 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 9ffa97d..b71cbfd 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -324,8 +324,9 @@ def readconfig(uzbl_config, config): config[key] = value # Ensure that config keys that relate to paths are expanded. - expand = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path'] - for key in expand: + pathkeys = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path', + 'saved_sessions_dir'] + for key in pathkeys: config[key] = os.path.expandvars(config[key]) @@ -1108,9 +1109,8 @@ class UzblTabbed: if self.notebook.get_n_pages() == 0: if not self._killed and config['save_session']: - if len(self._closed): - d = {'curtab': 0, 'tabs': [self._closed[-1],]} - self.save_session(session=d) + if os.path.exists(config['session_file']): + os.remove(config['session_file']) self.quit() @@ -1191,7 +1191,7 @@ class UzblTabbed: return True - def save_session(self, session_file=None, session=None): + def save_session(self, session_file=None): '''Save the current session to file for restoration on next load.''' strip = str.strip @@ -1199,17 +1199,16 @@ class UzblTabbed: if session_file is None: session_file = config['session_file'] - if session is None: - tabs = self.tabs.keys() - state = [] - for tab in list(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - if not uzbl.uri: continue - state += [(uzbl.uri, uzbl.title),] + tabs = self.tabs.keys() + state = [] + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + if not uzbl.uri: continue + state += [(uzbl.uri, uzbl.title),] - session = {'curtab': self.notebook.get_current_page(), - 'tabs': state} + session = {'curtab': self.notebook.get_current_page(), + 'tabs': state} if config['json_session']: raw = json.dumps(session) @@ -1237,9 +1236,11 @@ class UzblTabbed: default_path = False strip = str.strip json_session = config['json_session'] + delete_loaded = False if session_file is None: default_path = True + delete_loaded = True session_file = config['session_file'] if not os.path.isfile(session_file): @@ -1294,6 +1295,10 @@ class UzblTabbed: for (index, (uri, title)) in enumerate(tabs): self.new_tab(uri=uri, title=title, switch=(curtab==index)) + # A saved session has been loaded now delete it. + if delete_loaded and os.path.exists(session_file): + os.remove(session_file) + # There may be other state information in the session dict of use to # other functions. Of course however the non-json session object is # just a dummy object of no use to no one. @@ -1306,11 +1311,11 @@ class UzblTabbed: self._killed = True if config['save_session']: - if len(list(self.notebook)): + if len(list(self.notebook)) > 1: self.save_session() else: - # Notebook has no pages so delete session file if it exists. + # Notebook has one page open so delete the session file. if os.path.isfile(config['session_file']): os.remove(config['session_file']) -- cgit v1.2.3 From 8bef7d4c269866deccdd9ae4bcf94c9df3564e02 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 26 Aug 2009 22:09:25 +0800 Subject: Added a quit keybinding to uzbl_tabbed.py --- examples/data/uzbl/scripts/uzbl_tabbed.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index b71cbfd..c1667dd 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -240,6 +240,7 @@ config = { 'bind_goto_first': 'g<', # Goto first tab. 'bind_goto_last': 'g>', # Goto last tab. 'bind_clean_slate': 'gQ', # Close all tabs and open new tab. + 'bind_exit': 'gZ', # Exit nicely. # Session preset key bindings 'bind_save_preset': 'gsave _', # Save session to file %s. @@ -901,6 +902,9 @@ class UzblTabbed: elif cmd[0] == "clean": self.clean_slate() + elif cmd[0] == "exit": + self.quitrequest() + else: error("parse_command: unknown command %r" % ' '.join(cmd)) @@ -998,6 +1002,7 @@ class UzblTabbed: bind(config['bind_load_preset'], 'preset load %s') bind(config['bind_del_preset'], 'preset del %s') bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid) + bind(config['bind_exit'], 'exit') # Set definitions here # set(key, command back to fifo) @@ -1306,7 +1311,7 @@ class UzblTabbed: def quitrequest(self, *args): - '''Called by delete-event signal to kill all uzbl instances.''' + '''Attempt to close all uzbl instances nicely and exit.''' self._killed = True -- cgit v1.2.3 From af61915a7ab19f6f33742e3f7adde9c79e3b7236 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 26 Aug 2009 22:20:21 +0800 Subject: Added exit keybinding/usage comments. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index c1667dd..e07f48f 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -97,6 +97,7 @@ # bind_goto_first = g< # bind_goto_last = g> # bind_clean_slate = gQ +# bind_exit = gZ # # Session preset key bindings: # bind_save_preset = gsave _ @@ -802,6 +803,9 @@ class UzblTabbed: # title {pid} {document-title} # updates tablist title. # uri {pid} {document-location} + # updates tablist uri + # exit + # exits uzbl_tabbed.py if cmd[0] == "new": if len(cmd) == 2: -- cgit v1.2.3 From 4ce187854300d9d0fd21d95dfa3c3db79473b61d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 26 Aug 2009 22:23:19 +0800 Subject: Fix comment alignment. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index e07f48f..827f8ab 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -100,10 +100,10 @@ # bind_exit = gZ # # Session preset key bindings: -# bind_save_preset = gsave _ -# bind_load_preset = gload _ -# bind_del_preset = gdel _ -# bind_list_presets = glist +# bind_save_preset = gsave _ +# bind_load_preset = gload _ +# bind_del_preset = gdel _ +# bind_list_presets = glist # # And uzbl_tabbed.py takes care of the actual binding of the commands via each # instances fifo socket. -- cgit v1.2.3 From 9a83f9595c5a66df60a2b9ebbc8ce41117df0e55 Mon Sep 17 00:00:00 2001 From: Michael Fiano Date: Thu, 27 Aug 2009 14:18:03 +0800 Subject: Added a whitelist to the cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 30 ++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index af53e73..4850802 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -127,12 +127,19 @@ if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: else: DATA_DIR = os.path.join(os.environ['HOME'], '.local/share/uzbl/') +# Location of the uzbl configuration directory. +if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: + CONFIG_DIR = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/') +else: + CONFIG_DIR = os.path.join(os.environ['HOME'], '.config/uzbl/') + # Default config config = { - # Default cookie jar and daemon socket locations. - 'cookie_socket': os.path.join(CACHE_DIR, 'cookie_daemon_socket'), + # Default cookie jar, whitelist, and daemon socket locations. 'cookie_jar': os.path.join(DATA_DIR, 'cookies.txt'), + 'cookie_whitelist': os.path.join(CONFIG_DIR, 'cookie_whitelist'), + 'cookie_socket': os.path.join(CACHE_DIR, 'cookie_daemon_socket'), # Time out after x seconds of inactivity (set to 0 for never time out). # WARNING: Do not use this option if you are manually launching the daemon. @@ -314,12 +321,29 @@ class CookieMonster: '''Open the cookie jar.''' cookie_jar = config['cookie_jar'] + cookie_whitelist = config['cookie_whitelist'] + if cookie_jar: mkbasedir(cookie_jar) + if cookie_whitelist: + mkbasedir(cookie_whitelist) + + # Create cookie whitelist file if it does not exist. + if not os.path.exists(cookie_whitelist): + open(cookie_whitelist, 'w').close() + + # Read cookie whitelist file into list. + file = open(cookie_whitelist,'r') + domain_list = [line.rstrip('\n') for line in file] + file.close() # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) + # Define policy of allowed domains. + policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) + self.jar.set_policy(policy) + if cookie_jar: try: # Attempt to load cookies from the cookie jar. @@ -531,7 +555,7 @@ def main(): error("expected int argument for -t, --daemon-timeout") # Expand $VAR's in config keys that relate to paths. - for key in ['cookie_socket', 'cookie_jar']: + for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']: if config[key]: config[key] = os.path.expandvars(config[key]) -- cgit v1.2.3 From 5c30d7b726a3b221d12087bcca2ce3d35a6c7ae2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 27 Aug 2009 14:24:58 +0800 Subject: Added Michael Fiano to AUTHORS file and cookie_daemon.py header. --- AUTHORS | 3 ++- examples/data/uzbl/scripts/cookie_daemon.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index 89db5fe..15afb3e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,7 +29,7 @@ Contributors: (kmeaw) - fix for multibyte utf8 characters segfault (evocallaghan) - tiny patches Aaron Griffin (phrakture) - Makefile patches to build on OSX - Mason Larobina - os.environ.keys() & os.path.join fix in cookies.py, work on uzbl_tabbed.py, cookies_daemon.py + Mason Larobina - os.environ.keys() & os.path.join fix in cookies.py, work on uzbl_tabbed.py, cookie_daemon.py (dequis) - Uzbl.run, birectional socket, javascript commands Brendan Taylor (bct) - various bugfixes, making misc variables much better using expand(), refactoring some internal var stuff Chris van Dijk (quigybo) - work on uzbl_tabbed.py @@ -40,6 +40,7 @@ Contributors: Andraž 'ruskie' Levstik - font_family patch Helmut Grohne (helmut) - move void **ptr to union, various fixes Paweł Zuzelski (pawelz) - download handler proxy patch + Michael Fiano (axionix) - added cookie_daemon.py whitelist Originaly based on http://trac.webkit.org/browser/trunk/WebKitTools/GtkLauncher/main.c diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 4850802..29d5e47 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -4,6 +4,7 @@ # Copyright (c) 2009, Tom Adams # Copyright (c) 2009, Dieter Plaetinck # Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Michael Fiano # # 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 -- cgit v1.2.3 From dd162c69450ab0042da0e76cf671c55140a0d023 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 27 Aug 2009 14:58:06 +0800 Subject: Removed duplicated xdg code in cookie_daemon.py config section. --- examples/data/uzbl/scripts/cookie_daemon.py | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 29d5e47..167ffdf 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -101,6 +101,7 @@ import atexit from traceback import print_exc from signal import signal, SIGTERM from optparse import OptionParser +from os.path import join try: import cStringIO as StringIO @@ -113,34 +114,33 @@ except ImportError: # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' -# Location of the uzbl cache directory. -if 'XDG_CACHE_HOME' in os.environ.keys() and os.environ['XDG_CACHE_HOME']: - CACHE_DIR = os.path.join(os.environ['XDG_CACHE_HOME'], 'uzbl/') + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] -else: - CACHE_DIR = os.path.join(os.environ['HOME'], '.cache/uzbl/') + return join(os.environ['HOME'], default) -# Location of the uzbl data directory. -if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - DATA_DIR = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') +# Setup xdg paths. +CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/') +DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/') +CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/') -else: - DATA_DIR = os.path.join(os.environ['HOME'], '.local/share/uzbl/') - -# Location of the uzbl configuration directory. -if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - CONFIG_DIR = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/') -else: - CONFIG_DIR = os.path.join(os.environ['HOME'], '.config/uzbl/') +# Ensure data paths exist. +for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]: + if not os.path.exists(path): + os.makedirs(path) # Default config config = { # Default cookie jar, whitelist, and daemon socket locations. - 'cookie_jar': os.path.join(DATA_DIR, 'cookies.txt'), - 'cookie_whitelist': os.path.join(CONFIG_DIR, 'cookie_whitelist'), - 'cookie_socket': os.path.join(CACHE_DIR, 'cookie_daemon_socket'), + 'cookie_jar': join(DATA_DIR, 'cookies.txt'), + 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), + 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), # Time out after x seconds of inactivity (set to 0 for never time out). # WARNING: Do not use this option if you are manually launching the daemon. -- cgit v1.2.3 From 76d9c104e68e630cbbe2b8600b9be25a17e48cb1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 27 Aug 2009 16:15:08 +0800 Subject: Live whitelist reloading & whitelist off by default in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 87 ++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 14 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 167ffdf..6edf687 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -142,6 +142,9 @@ config = { 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), + # Don't use a cookie whitelist policy by default. + 'use_whitelist': False, + # Time out after x seconds of inactivity (set to 0 for never time out). # WARNING: Do not use this option if you are manually launching the daemon. 'daemon_timeout': 0, @@ -265,6 +268,9 @@ class CookieMonster: self.last_request = time.time() self._running = False + # Grab the last modified time of the cookie whitelist. + self._whitelistmtime = None + def run(self): '''Start the daemon.''' @@ -318,14 +324,11 @@ class CookieMonster: self.del_socket() - def open_cookie_jar(self): - '''Open the cookie jar.''' + def load_whitelist(self): + '''Load the cookie jar whitelist policy.''' - cookie_jar = config['cookie_jar'] cookie_whitelist = config['cookie_whitelist'] - if cookie_jar: - mkbasedir(cookie_jar) if cookie_whitelist: mkbasedir(cookie_whitelist) @@ -338,12 +341,29 @@ class CookieMonster: domain_list = [line.rstrip('\n') for line in file] file.close() + # Define policy of allowed domains + policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) + self.jar.set_policy(policy) + + # Save the last modified time of the whitelist. + self._whitelistmtime = os.stat(cookie_whitelist).st_mtime + + + def open_cookie_jar(self): + '''Open the cookie jar.''' + + cookie_jar = config['cookie_jar'] + cookie_whitelist = config['cookie_whitelist'] + + if cookie_jar: + mkbasedir(cookie_jar) + # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) - # Define policy of allowed domains. - policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) - self.jar.set_policy(policy) + # Load cookie whitelist policy. + if config['use_whitelist']: + self.load_whitelist() if cookie_jar: try: @@ -358,6 +378,20 @@ class CookieMonster: except: pass + def check_whitelist(self): + '''Check if the cookie whitelist has been modified since it was last + loaded.''' + + cookie_whitelist = config['cookie_whitelist'] + if os.path.exists(cookie_whitelist): + mtime = os.stat(cookie_whitelist).st_mtime + + # Reload cookie jar if the mtimes don't match. + if self._whitelistmtime != mtime: + del self.jar + echo("reloading modified whitelist %r" % cookie_whitelist) + self.open_cookie_jar() + def create_socket(self): '''Create AF_UNIX socket for communication with uzbl instances.''' @@ -382,6 +416,8 @@ class CookieMonster: def listen(self): '''Listen for incoming cookie PUT and GET requests.''' + daemon_timeout = config['daemon_timeout'] + use_whitelist = config['use_whitelist'] echo("listening on %r" % config['cookie_socket']) while self._running: @@ -395,13 +431,17 @@ class CookieMonster: self.handle_request(client_socket) self.last_request = time.time() client_socket.close() + continue - if config['daemon_timeout']: + if daemon_timeout: # Checks if the daemon has been idling for too long. idle = time.time() - self.last_request - if idle > config['daemon_timeout']: + if idle > daemon_timeout: self._running = False + if use_whitelist: + self.check_whitelist() + def handle_request(self, client_socket): '''Connection made, now to serve a cookie PUT or GET request.''' @@ -521,9 +561,18 @@ def main(): parser.add_option('-m', '--memory', dest='memory', action='store_true', help="store cookies in memory only - do not write to disk") + parser.add_option('-u', '--use-whitelist', dest='usewhitelist', + action='store_true', help="use cookie whitelist policy") + + parser.add_option('-w', '--cookie-whitelist', dest='whitelist', + action='store', help="manually specify whitelist location", + metavar='FILE') + # Parse the command line arguments. (options, args) = parser.parse_args() + expand = lambda p: os.path.realpath(os.path.expandvars(p)) + if len(args): error("unknown argument %r" % args[0]) @@ -536,17 +585,27 @@ def main(): config['daemon_mode'] = False if options.cookie_socket: - echo("using cookie_socket %r" % options.cookie_socket) - config['cookie_socket'] = options.cookie_socket + config['cookie_socket'] = expand(options.cookie_socket) + echo("using cookie_socket %r" % config['cookie_socket']) if options.cookie_jar: - echo("using cookie_jar %r" % options.cookie_jar) - config['cookie_jar'] = options.cookie_jar + config['cookie_jar'] = expand(options.cookie_jar) + echo("using cookie_jar %r" % config['cookie_jar']) if options.memory: echo("using memory %r" % options.memory) config['cookie_jar'] = None + if options.whitelist: + echo("whitelist mode on") + config['use_whitelist'] = True + config['cookie_whitelist'] = expand(options.whitelist) + echo("using whitelist %r" % config['cookie_whitelist']) + + if not config['use_whitelist'] and options.usewhitelist: + echo("whitelist mode on") + config['use_whitelist'] = True + if options.daemon_timeout: try: config['daemon_timeout'] = int(options.daemon_timeout) -- cgit v1.2.3 From e16624aceb823567500030b84cde505de72d2fca Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 27 Aug 2009 16:20:42 +0800 Subject: This is cookie_daemon.py not uzbl_tabbed.py --- examples/data/uzbl/scripts/cookie_daemon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 6edf687..2dec742 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -1,8 +1,8 @@ #!/usr/bin/env python -# Uzbl tabbing wrapper using a fifo socket interface +# The Python Cookie Daemon for Uzbl. # Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, Dieter Plaetinck +# Copyright (c) 2009, Dieter Plaetinck # Copyright (c) 2009, Mason Larobina # Copyright (c) 2009, Michael Fiano # -- cgit v1.2.3 From 1f6c39f8c2b2702a57a598caf0049767961a7e2a Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 27 Aug 2009 16:33:16 +0800 Subject: Reduced command line usage section in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 2dec742..0b3954a 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -41,21 +41,10 @@ find the latest version of the cookie_daemon.py Command line options ==================== -Usage: cookie_daemon.py [options] - -Options: - -h, --help show this help message and exit - -n, --no-daemon don't daemonise the process. - -v, --verbose print verbose output. - -t SECONDS, --daemon-timeout=SECONDS - shutdown the daemon after x seconds inactivity. - WARNING: Do not use this when launching the cookie - daemon manually. - -s SOCKET, --cookie-socket=SOCKET - manually specify the socket location. - -j FILE, --cookie-jar=FILE - manually specify the cookie jar location. - -m, --memory store cookies in memory only - do not write to disk +Use the following command to get a full list of the cookie_daemon.py command +line options: + + ./cookie_daemon.py --help Talking with uzbl ================= -- cgit v1.2.3 From 8358831de537895a7935efba021eda149d3fde28 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 28 Aug 2009 01:13:12 +0800 Subject: Poll for whitelist changes only after idle periods in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 0b3954a..ae9c4f4 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -407,6 +407,9 @@ class CookieMonster: daemon_timeout = config['daemon_timeout'] use_whitelist = config['use_whitelist'] + if use_whitelist: + check_whitelist = False + echo("listening on %r" % config['cookie_socket']) while self._running: @@ -416,6 +419,12 @@ class CookieMonster: self.server_socket.listen(1) if bool(select.select([self.server_socket], [], [], 1)[0]): + # If the daemons been idle check if the whitelist has been + # modified. + if use_whitelist and check_whitelist: + self.check_whitelist() + check_whitelist = False + client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) self.last_request = time.time() @@ -428,8 +437,10 @@ class CookieMonster: if idle > daemon_timeout: self._running = False - if use_whitelist: - self.check_whitelist() + if use_whitelist and not check_whitelist: + # Signals that the daemon has been idle and the whitelist + # should be checked before serving the next cookie request. + check_whitelist = True def handle_request(self, client_socket): -- cgit v1.2.3 From 77e19b4214536eaa1a227df81d957c38c39a5f6b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Sep 2009 15:37:24 +0800 Subject: Added init like {start|stop|restart} control to cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 152 ++++++++++++++++------------ 1 file changed, 87 insertions(+), 65 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index ae9c4f4..a587687 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -58,18 +58,10 @@ Or if you prefer using the $HOME variable: set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket -Issues -====== - - - There is no easy way of stopping a running daemon. - Todo list ========= - - Use a pid file to make stopping a running daemon easy. - - add {start|stop|restart} command line arguments to make the cookie_daemon - functionally similar to the daemons found in /etc/init.d/ (in gentoo) - or /etc/rc.d/ (in arch). + - Use a pid file to make force killing a running daemon possible. Reporting bugs / getting help ============================= @@ -177,7 +169,7 @@ def mkbasedir(filepath): os.makedirs(dirname) -def check_socket_health(cookie_socket): +def daemon_running(cookie_socket): '''Check if another process (hopefully a cookie_daemon.py) is listening on the cookie daemon socket. If another process is found to be listening on the socket exit the daemon immediately and leave the @@ -185,28 +177,58 @@ def check_socket_health(cookie_socket): and delete it (to be re-created in the create socket function).''' if not os.path.exists(cookie_socket): - # What once was is now no more. - return None + return False if os.path.isfile(cookie_socket): - error("regular file at %r is not a socket" % cookie_socket) + raise Exception("regular file at %r is not a socket" % cookie_socket) + if os.path.isdir(cookie_socket): - error("directory at %r is not a socket" % cookie_socket) + raise Exception("directory at %r is not a socket" % cookie_socket) try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) sock.connect(cookie_socket) sock.close() - error("detected another process listening on %r" % cookie_socket) + echo("detected daemon listening on %r" % cookie_socket) + return True except socket.error: # Failed to connect to cookie_socket so assume it has been # abandoned by another cookie daemon process. if os.path.exists(cookie_socket): - echo("deleting abandoned socket %r" % cookie_socket) + echo("deleting abandoned socket at %r" % cookie_socket) os.remove(cookie_socket) + return False + + +def kill_daemon(cookie_socket): + '''Send the "EXIT" command to running cookie_daemon.''' + + if not daemon_running(cookie_socket): + return + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.send("EXIT") + sock.close() + + failed, start = False, time.time() + while not failed and os.path.exists(cookie_socket): + time.sleep(0.1) + if (time.time() - start) > 5: + raise Exception("Failed to kill socket in time.") + + echo("stopped daemon listening on %r"% cookie_socket) + + except: + print_exc() + if os.path.exists(cookie_socket): + os.remove(cookie_socket) + echo("removed abandoned socket %r" % cookie_socket) + def daemonize(): '''Daemonize the process using the Stevens' double-fork magic.''' @@ -268,7 +290,8 @@ class CookieMonster: # listening on the cookie socket and remove the abandoned socket if # there isnt. if os.path.exists(config['cookie_socket']): - check_socket_health(config['cookie_socket']) + if daemon_running(config['cookie_socket']): + sys.exit(1) # Daemonize process. if config['daemon_mode']: @@ -347,6 +370,10 @@ class CookieMonster: if cookie_jar: mkbasedir(cookie_jar) + # Remove any stale cookie jars. + if self.jar: + del self.jar + # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) @@ -367,19 +394,14 @@ class CookieMonster: except: pass - def check_whitelist(self): - '''Check if the cookie whitelist has been modified since it was last - loaded.''' + + def reload_whitelist(self): + '''Reload the cookie whitelist.''' cookie_whitelist = config['cookie_whitelist'] if os.path.exists(cookie_whitelist): - mtime = os.stat(cookie_whitelist).st_mtime - - # Reload cookie jar if the mtimes don't match. - if self._whitelistmtime != mtime: - del self.jar - echo("reloading modified whitelist %r" % cookie_whitelist) - self.open_cookie_jar() + echo("reloading whitelist %r" % cookie_whitelist) + self.open_cookie_jar() def create_socket(self): @@ -391,10 +413,6 @@ class CookieMonster: self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - if os.path.exists(cookie_socket): - # Accounting for super-rare super-fast racetrack condition. - check_socket_health(cookie_socket) - self.server_socket.bind(cookie_socket) # Set restrictive permissions on the cookie socket to prevent other @@ -406,10 +424,6 @@ class CookieMonster: '''Listen for incoming cookie PUT and GET requests.''' daemon_timeout = config['daemon_timeout'] - use_whitelist = config['use_whitelist'] - if use_whitelist: - check_whitelist = False - echo("listening on %r" % config['cookie_socket']) while self._running: @@ -419,12 +433,6 @@ class CookieMonster: self.server_socket.listen(1) if bool(select.select([self.server_socket], [], [], 1)[0]): - # If the daemons been idle check if the whitelist has been - # modified. - if use_whitelist and check_whitelist: - self.check_whitelist() - check_whitelist = False - client_socket, _ = self.server_socket.accept() self.handle_request(client_socket) self.last_request = time.time() @@ -437,11 +445,6 @@ class CookieMonster: if idle > daemon_timeout: self._running = False - if use_whitelist and not check_whitelist: - # Signals that the daemon has been idle and the whitelist - # should be checked before serving the next cookie request. - check_whitelist = True - def handle_request(self, client_socket): '''Connection made, now to serve a cookie PUT or GET request.''' @@ -453,19 +456,28 @@ class CookieMonster: # Cookie argument list in packet is null separated. argv = data.split("\0") + action = argv[0].upper().strip() # Catch the EXIT command sent to kill running daemons. - if len(argv) == 1 and argv[0].strip() == "EXIT": + if action == "EXIT": self._running = False return + # Catch whitelist RELOAD command. + elif action == "RELOAD": + self.reload_whitelist() + return + + # Return if command unknown. + elif action not in ['GET', 'PUT']: + error("unknown command %r." % argv) + return + # Determine whether or not to print cookie data to terminal. print_cookie = (config['verbose'] and not config['daemon_mode']) if print_cookie: print ' '.join(argv[:4]) - action = argv[0] - uri = urllib2.urlparse.ParseResult( scheme=argv[1], netloc=argv[2], @@ -540,7 +552,8 @@ def main(): '''Main function.''' # Define command line parameters. - parser = OptionParser() + usage = "usage: %prog [options] {start|stop|restart}" + parser = OptionParser(usage=usage) parser.add_option('-n', '--no-daemon', dest='no_daemon', action='store_true', help="don't daemonise the process.") @@ -573,43 +586,43 @@ def main(): expand = lambda p: os.path.realpath(os.path.expandvars(p)) + initcommands = ['start', 'stop', 'restart'] + for arg in args: + if arg not in initcommands: + error("unknown argument %r" % args[0]) + sys.exit(1) + + if len(args) > 1: + error("the daemon only accepts one command line argument at a time.") + sys.exit(1) + if len(args): - error("unknown argument %r" % args[0]) + action = args[0] - if options.verbose: - config['verbose'] = True - echo("verbose mode on") + else: + action = "start" if options.no_daemon: - echo("daemon mode off") config['daemon_mode'] = False if options.cookie_socket: config['cookie_socket'] = expand(options.cookie_socket) - echo("using cookie_socket %r" % config['cookie_socket']) if options.cookie_jar: config['cookie_jar'] = expand(options.cookie_jar) - echo("using cookie_jar %r" % config['cookie_jar']) if options.memory: - echo("using memory %r" % options.memory) config['cookie_jar'] = None if options.whitelist: - echo("whitelist mode on") - config['use_whitelist'] = True config['cookie_whitelist'] = expand(options.whitelist) - echo("using whitelist %r" % config['cookie_whitelist']) - if not config['use_whitelist'] and options.usewhitelist: - echo("whitelist mode on") + if options.whitelist or options.usewhitelist: config['use_whitelist'] = True if options.daemon_timeout: try: config['daemon_timeout'] = int(options.daemon_timeout) - echo("set timeout to %d seconds" % config['daemon_timeout']) except ValueError: error("expected int argument for -t, --daemon-timeout") @@ -619,7 +632,16 @@ def main(): if config[key]: config[key] = os.path.expandvars(config[key]) - CookieMonster().run() + if options.verbose: + config['verbose'] = True + import pprint + map(echo, pprint.pformat(config).split('\n')) + + if action in ['stop', 'restart']: + kill_daemon(config['cookie_socket']) + + if action in ['start', 'restart']: + CookieMonster().run() if __name__ == "__main__": -- cgit v1.2.3 From 0ae71dd75692dba01f12670eaa422c01a53e3052 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Sep 2009 16:26:37 +0800 Subject: Added verbose option to uzbl_tabbed.py & cleaned up config code. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 81 +++++++++++++++++++------------ 1 file changed, 49 insertions(+), 32 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 827f8ab..0c706e1 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -83,8 +83,9 @@ # icon_path = $HOME/.local/share/uzbl/uzbl.png # status_background = #303030 # -# Window options: +# Misc options: # window_size = 800,800 +# verbose = 0 # # And the key bindings: # bind_new_tab = gn @@ -168,36 +169,41 @@ from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP from signal import signal, SIGTERM, SIGINT from optparse import OptionParser, OptionGroup + pygtk.require('2.0') -_scriptname = os.path.basename(sys.argv[0]) +_SCRIPTNAME = os.path.basename(sys.argv[0]) def error(msg): - sys.stderr.write("%s: %s\n" % (_scriptname, msg)) - -def echo(msg): - print "%s: %s" % (_scriptname, msg) - + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) # ============================================================================ # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return os.path.join(os.environ['HOME'], default) -# Location of your uzbl data directory. -if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - data_dir = os.path.join(os.environ['XDG_DATA_HOME'], 'uzbl/') -else: - data_dir = os.path.join(os.environ['HOME'], '.local/share/uzbl/') -if not os.path.exists(data_dir): - error("Warning: uzbl data_dir does not exist: %r" % data_dir) +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +CONFIG_DIR = os.path.join(xdghome('CONFIG', '.config/'), 'uzbl/') -# Location of your uzbl configuration file. -if 'XDG_CONFIG_HOME' in os.environ.keys() and os.environ['XDG_CONFIG_HOME']: - uzbl_config = os.path.join(os.environ['XDG_CONFIG_HOME'], 'uzbl/config') -else: - uzbl_config = os.path.join(os.environ['HOME'],'.config/uzbl/config') -if not os.path.exists(uzbl_config): - error("Warning: Cannot locate your uzbl_config file %r" % uzbl_config) +# Ensure uzbl xdg paths exist +for path in [DATA_DIR, CONFIG_DIR]: + if not os.path.exists(path): + os.makedirs(path) + +# Path to uzbl config +UZBL_CONFIG = os.path.join(CONFIG_DIR, 'config') +if not os.path.exists(UZBL_CONFIG): + error("cannot find uzbl config file at %r" % UZBL_CONFIG) + sys.exit(1) # All of these settings can be inherited from your uzbl config file. config = { @@ -218,17 +224,18 @@ config = { # Session options 'save_session': True, # Save session in file when quit 'json_session': False, # Use json to save session. - 'saved_sessions_dir': os.path.join(data_dir, 'sessions/'), - 'session_file': os.path.join(data_dir, 'session'), + 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'), + 'session_file': os.path.join(DATA_DIR, 'session'), # Inherited uzbl options 'fifo_dir': '/tmp', # Path to look for uzbl fifo. 'socket_dir': '/tmp', # Path to look for uzbl socket. - 'icon_path': os.path.join(data_dir, 'uzbl.png'), + 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'), 'status_background': "#303030", # Default background for all panels. - # Window options + # Misc options 'window_size': "800,800", # width,height in pixels. + 'verbose': False, # Print verbose output. # Key bindings 'bind_new_tab': 'gn', # Open new tab. @@ -295,11 +302,14 @@ def colour_selector(tabindex, currentpage, uzbl): # Default tab style. return (config['tab_colours'], config['tab_text_colours']) - # ============================================================================ # ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: # ============================================================================ +def echo(msg): + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + def readconfig(uzbl_config, config): '''Loads relevant config from the users uzbl config file into the global @@ -1361,15 +1371,15 @@ class UzblTabbed: if __name__ == "__main__": # Read from the uzbl config into the global config dictionary. - readconfig(uzbl_config, config) + readconfig(UZBL_CONFIG, config) # Build command line parser - parser = OptionParser() - parser.add_option('-n', '--no-session', dest='nosession',\ + usage = "usage: %prog [OPTIONS] {URIS}..." + parser = OptionParser(usage=usage) + parser.add_option('-n', '--no-session', dest='nosession', action='store_true', help="ignore session saving a loading.") - group = OptionGroup(parser, "Note", "All other command line arguments are "\ - "interpreted as uris and loaded in new tabs.") - parser.add_option_group(group) + parser.add_option('-v', '--verbose', dest='verbose', + action='store_true', help='print verbose output.') # Parse command line options (options, uris) = parser.parse_args() @@ -1377,6 +1387,9 @@ if __name__ == "__main__": if options.nosession: config['save_session'] = False + if options.verbose: + config['verbose'] = True + if config['json_session']: try: import simplejson as json @@ -1387,6 +1400,10 @@ if __name__ == "__main__": "install the simplejson python module to remove this warning.") config['json_session'] = False + if config['verbose']: + import pprint + map(echo, pprint.pformat(config).split('\n')) + uzbl = UzblTabbed() # All extra arguments given to uzbl_tabbed.py are interpreted as -- cgit v1.2.3 From 3fbcfe6148d67d83772b52dfe503e37b4740e69d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 2 Sep 2009 14:26:22 +0800 Subject: Added reload command to {start|stop|restart} in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 46 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index a587687..9c297df 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -203,31 +203,45 @@ def daemon_running(cookie_socket): return False -def kill_daemon(cookie_socket): - '''Send the "EXIT" command to running cookie_daemon.''' +def send_command(cookie_socket, cmd): + '''Send a command to a running cookie daemon.''' if not daemon_running(cookie_socket): - return + return False try: sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) sock.connect(cookie_socket) - sock.send("EXIT") + sock.send(cmd) sock.close() + echo("sent command %r to %r" % (cmd, cookie_socket)) + return True + + except socket.error: + print_exc() + error("failed to send message %r to %r" % (cmd, cookie_socket)) + return False - failed, start = False, time.time() - while not failed and os.path.exists(cookie_socket): + +def kill_daemon(cookie_socket): + '''Send the "EXIT" command to running cookie_daemon.''' + + if send_command(cookie_socket, "EXIT"): + # Now ensure the cookie_socket is cleaned up. + start = time.time() + while os.path.exists(cookie_socket): time.sleep(0.1) if (time.time() - start) > 5: - raise Exception("Failed to kill socket in time.") + error("force deleting socket %r" % cookie_socket) + os.remove(cookie_socket) + return echo("stopped daemon listening on %r"% cookie_socket) - except: - print_exc() + else: if os.path.exists(cookie_socket): os.remove(cookie_socket) - echo("removed abandoned socket %r" % cookie_socket) + echo("removed abandoned/broken socket %r" % cookie_socket) def daemonize(): @@ -552,7 +566,7 @@ def main(): '''Main function.''' # Define command line parameters. - usage = "usage: %prog [options] {start|stop|restart}" + usage = "usage: %prog [options] {start|stop|restart|reload}" parser = OptionParser(usage=usage) parser.add_option('-n', '--no-daemon', dest='no_daemon', action='store_true', help="don't daemonise the process.") @@ -586,14 +600,15 @@ def main(): expand = lambda p: os.path.realpath(os.path.expandvars(p)) - initcommands = ['start', 'stop', 'restart'] + initcommands = ['start', 'stop', 'restart', 'reload'] for arg in args: if arg not in initcommands: error("unknown argument %r" % args[0]) sys.exit(1) if len(args) > 1: - error("the daemon only accepts one command line argument at a time.") + error("the daemon only accepts one {%s} action at a time." + % '|'.join(initcommands)) sys.exit(1) if len(args): @@ -635,7 +650,10 @@ def main(): if options.verbose: config['verbose'] = True import pprint - map(echo, pprint.pformat(config).split('\n')) + sys.stderr.write("%s\n" % pprint.pformat(config)) + + if action == "reload": + send_command(config['cookie_socket'], "RELOAD") if action in ['stop', 'restart']: kill_daemon(config['cookie_socket']) -- cgit v1.2.3 From 7c7bd642757cad50e2d08b054e59e75ca4c3cfb2 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 3 Sep 2009 16:42:39 +0200 Subject: add sample key handler from RobM. taken from http://lists.uzbl.org/pipermail/uzbl-dev-uzbl.org/2009-August/000261.html --- examples/data/uzbl/scripts/dispatcher.sh | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 examples/data/uzbl/scripts/dispatcher.sh (limited to 'examples') diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh new file mode 100644 index 0000000..6f33406 --- /dev/null +++ b/examples/data/uzbl/scripts/dispatcher.sh @@ -0,0 +1,76 @@ +#!/bin/sh +# +# Sample uzbl key handler +# +# demonstrating one possible way to access and process +# uzbl's event messages +# +# Usage: uzbl | keyhandler +# + +ALTPRESSED=0 + +clear_modifiers() { + ALT_PRESSED=0 + CONTROL_PRESSED=0 + #etc. + echo 'set status_message = ' > "$FIFO_PATH" +} + +while read EVENT; do + # get eventname + ENAME=`echo "$EVENT" | sed -ne 's/\([A-Z]*\) .*/\1/p'` + + if [ x"$ENAME" = x'KEYPRESS' ]; then + KEY=$(echo "$EVENT" | sed -ne 's/KEYPRESS \[.*\] \(.*$\)/\1/p') + FIFO_PATH='/tmp/uzbl_fifo_'$(echo "$EVENT" | sed -ne 's/KEYPRESS \[\(.*\)\] .*$/\1/p') + + # Clear mofifiers on Escape + # + [ "$KEY" = Escape ] && clear_modifiers + + # Modifier: Alt_L + # + if [ x"$KEY" = x'Alt_L' ];then + clear_modifiers + ALT_PRESSED=1 + + # place an indicator showing the active modifier + # on uzbl's statusbar + # + echo 'set status_message = @status_message Alt' > "$FIFO_PATH" + fi + + if [ "$ALT_PRESSED" = 1 ]; then + + # Keys + # + if [ x"$KEY" = x'a' ]; then + ALT_PRESSED=0 + echo 'set inject_html =

You pressed Alt+a

' > "$FIFO_PATH" + echo 'set status_message = ' > "$FIFO_PATH" + + # delete keycmd + # here not needed. loading a new page + # resets it by default + # + #echo 'set keycmd = ' > "$F_PATH" + fi + if [ x"$KEY" = x'b' ]; then + ALT_PRESSED=0 + echo 'set inject_html =

You pressed Alt+b

' > "$FIFO_PATH" + echo 'set status_message = ' > "$FIFO_PATH" + fi + + fi + + # Modifier: Control_L and Control_R. + # + if [ x"$KEY" = x'Control_L' -o x"$KEY" = x'Control_R' ];then + clear_modifiers + CONTROL_PRESSED=1 + echo 'set status_message = @status_message Control' > "$FIFO_PATH" + #etc. + fi + fi +done -- cgit v1.2.3 From b04492700c40837bbae771c53ba2aafaadcd3a65 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 3 Sep 2009 19:04:17 +0200 Subject: refactored dispatcher that supports getting fifo path from event --- examples/data/uzbl/scripts/dispatcher.sh | 37 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) mode change 100644 => 100755 examples/data/uzbl/scripts/dispatcher.sh (limited to 'examples') diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh old mode 100644 new mode 100755 index 6f33406..e3e2706 --- a/examples/data/uzbl/scripts/dispatcher.sh +++ b/examples/data/uzbl/scripts/dispatcher.sh @@ -1,27 +1,44 @@ #!/bin/sh # -# Sample uzbl key handler +# Sample uzbl eventhandler # # demonstrating one possible way to access and process # uzbl's event messages # -# Usage: uzbl | keyhandler +# Usage: uzbl | eventhandler # +VERBOSE=1 + + ALTPRESSED=0 +log () { + [ -n "$VERBOSE" ] && echo "$1" +} + +fifo () { + log "$1 > ${FIFO_PATH:-unset}" + [ -n "$FIFO_PATH" ] && echo "$1" > "$FIFO_PATH" +} + +log "Init eventhandler" + clear_modifiers() { ALT_PRESSED=0 CONTROL_PRESSED=0 #etc. - echo 'set status_message = ' > "$FIFO_PATH" + fifo 'set status_message = ' } while read EVENT; do # get eventname ENAME=`echo "$EVENT" | sed -ne 's/\([A-Z]*\) .*/\1/p'` - if [ x"$ENAME" = x'KEYPRESS' ]; then + if [ x"$ENAME" = 'xFIFO_SET' ]; then + FIFO_PATH=`echo $EVENT | cut -d ' ' -f 3` + + elif [ x"$ENAME" = x'KEYPRESS' ]; then KEY=$(echo "$EVENT" | sed -ne 's/KEYPRESS \[.*\] \(.*$\)/\1/p') FIFO_PATH='/tmp/uzbl_fifo_'$(echo "$EVENT" | sed -ne 's/KEYPRESS \[\(.*\)\] .*$/\1/p') @@ -38,7 +55,7 @@ while read EVENT; do # place an indicator showing the active modifier # on uzbl's statusbar # - echo 'set status_message = @status_message Alt' > "$FIFO_PATH" + fifo 'set status_message = @status_message Alt' fi if [ "$ALT_PRESSED" = 1 ]; then @@ -47,8 +64,8 @@ while read EVENT; do # if [ x"$KEY" = x'a' ]; then ALT_PRESSED=0 - echo 'set inject_html =

You pressed Alt+a

' > "$FIFO_PATH" - echo 'set status_message = ' > "$FIFO_PATH" + fifo 'set inject_html =

You pressed Alt+a

' + fifo 'set status_message = ' # delete keycmd # here not needed. loading a new page @@ -58,8 +75,8 @@ while read EVENT; do fi if [ x"$KEY" = x'b' ]; then ALT_PRESSED=0 - echo 'set inject_html =

You pressed Alt+b

' > "$FIFO_PATH" - echo 'set status_message = ' > "$FIFO_PATH" + fifo 'set inject_html =

You pressed Alt+b

' + fifo 'set status_message = ' fi fi @@ -69,7 +86,7 @@ while read EVENT; do if [ x"$KEY" = x'Control_L' -o x"$KEY" = x'Control_R' ];then clear_modifiers CONTROL_PRESSED=1 - echo 'set status_message = @status_message Control' > "$FIFO_PATH" + fifo 'set status_message = @status_message Control' #etc. fi fi -- cgit v1.2.3 From 499951e3d148d5199e1c86a6bf5c82bef0e54e6a Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 3 Sep 2009 19:44:21 +0200 Subject: prefix events with "EVENT " for easier filtering --- examples/data/uzbl/scripts/dispatcher.sh | 4 ++++ uzbl.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh index e3e2706..0e9ba6b 100755 --- a/examples/data/uzbl/scripts/dispatcher.sh +++ b/examples/data/uzbl/scripts/dispatcher.sh @@ -32,6 +32,10 @@ clear_modifiers() { } while read EVENT; do + if [ "$(echo $EVENT | cut -d ' ' -f 1)" != 'EVENT' ]; then + continue; + fi + EVENT="`echo $EVENT | sed 's/^EVENT //'`" # get eventname ENAME=`echo "$EVENT" | sed -ne 's/\([A-Z]*\) .*/\1/p'` diff --git a/uzbl.c b/uzbl.c index efe885a..c58cade 100644 --- a/uzbl.c +++ b/uzbl.c @@ -422,7 +422,7 @@ void send_event(int type, const gchar *details) { if(type < LAST_EVENT) { - printf("%s [%s] %s\n", event_table[type], uzbl.state.instance_name, details); + printf("EVENT %s [%s] %s\n", event_table[type], uzbl.state.instance_name, details); fflush(stdout); } } -- cgit v1.2.3 From 6c2689caf449fe47bd88b60ba2555a5dd4e19732 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 3 Sep 2009 19:48:22 +0200 Subject: fix for KEY_PRESS + no more need for ugly fifo assignments --- examples/data/uzbl/scripts/dispatcher.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh index 0e9ba6b..3d0aa03 100755 --- a/examples/data/uzbl/scripts/dispatcher.sh +++ b/examples/data/uzbl/scripts/dispatcher.sh @@ -42,9 +42,8 @@ while read EVENT; do if [ x"$ENAME" = 'xFIFO_SET' ]; then FIFO_PATH=`echo $EVENT | cut -d ' ' -f 3` - elif [ x"$ENAME" = x'KEYPRESS' ]; then - KEY=$(echo "$EVENT" | sed -ne 's/KEYPRESS \[.*\] \(.*$\)/\1/p') - FIFO_PATH='/tmp/uzbl_fifo_'$(echo "$EVENT" | sed -ne 's/KEYPRESS \[\(.*\)\] .*$/\1/p') + elif [ x"$ENAME" = x'KEY_PRESS' ]; then + KEY=$(echo "$EVENT" | sed -ne 's/KEY_PRESS \[.*\] \(.*$\)/\1/p') # Clear mofifiers on Escape # -- cgit v1.2.3 From 369119525001e17d5e601578b3c61a0a3d5264fa Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 3 Sep 2009 22:09:23 +0200 Subject: todo updates --- docs/TODO | 2 ++ examples/data/uzbl/scripts/dispatcher.sh | 1 + 2 files changed, 3 insertions(+) (limited to 'examples') diff --git a/docs/TODO b/docs/TODO index abc5b44..1613053 100644 --- a/docs/TODO +++ b/docs/TODO @@ -4,6 +4,8 @@ * add key_release callback and event * remove all binding ('bind = ' etc.) stuff and port to new system * VARIABLE_SET for all types (but probably not useful for custom vars) +* port keycmd to dispatcher. we can now more cleanly send BackSpace instead of keycmd_bs and so on + = key handling (example dispatcher.sh) = * on escape: diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh index 3d0aa03..e8c3aed 100755 --- a/examples/data/uzbl/scripts/dispatcher.sh +++ b/examples/data/uzbl/scripts/dispatcher.sh @@ -12,6 +12,7 @@ VERBOSE=1 ALTPRESSED=0 +KEYCMD= # buffer for building up commands log () { [ -n "$VERBOSE" ] && echo "$1" -- cgit v1.2.3 From 8738261ec767c9708b99512e4938c189d861f5a1 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 4 Sep 2009 11:55:09 +0200 Subject: use python based event manager instead of sh one. posix sh was a dead end --- Makefile | 2 +- README | 8 +- docs/TODO | 8 +- examples/data/uzbl/scripts/dispatcher.sh | 97 ------------------------ examples/data/uzbl/scripts/event_manager.py | 113 ++++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 106 deletions(-) delete mode 100755 examples/data/uzbl/scripts/dispatcher.sh create mode 100755 examples/data/uzbl/scripts/event_manager.py (limited to 'examples') diff --git a/Makefile b/Makefile index 7549f97..498791d 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ test-dev: uzbl XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose test-dev-dispatched: uzbl - XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose | ./examples/data/uzbl/scripts/dispatcher.sh + XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose | ./examples/data/uzbl/scripts/event_manager.py test-share: uzbl XDG_DATA_HOME=${PREFIX}/share/uzbl/examples/data XDG_CONFIG_HOME=${PREFIX}/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --verbose diff --git a/README b/README index 2f939fa..54366bd 100644 --- a/README +++ b/README @@ -412,15 +412,15 @@ Copying the Uzbl object and creating public functions should be taken with care ### EVENTS ### -unlike commands, events are not handled in uzbl itself, but are propagated asynchronously through text stream on -stdout. You'll usually use uzbl by piping it's output to a so called 'dispatcher' +unlike commands, events are not handled in uzbl itself, but are propagated (dispatched) asynchronously through +a text stream on stdout. You'll usually use uzbl by piping it's output to a so called 'event handler' - makes it possible to use whichever language you want for event handling (python, perl, bash, .. you name it). you'll usually send commands (see above) back to uzbl through its fifo or socket - keybindings use x keysyms - many finegrained events (hover_over_link, key_press, key_down,..) -- see example dispatcher.sh +- see example event_handler.py -Note: cookie events are not sent to a dispatcher but handled internally through the cookie handler because of their synchronous nature. +Note: cookie events are not sent to an event handler but handled internally through the cookie handler because of their synchronous nature. Cookie events are really something completely different from all other events. maybe someday we'll use http proxies or something for cookies, but for now we still use the handler code) diff --git a/docs/TODO b/docs/TODO index 1613053..3722d45 100644 --- a/docs/TODO +++ b/docs/TODO @@ -1,13 +1,13 @@ == event-messages specific == * throw out all old code -* document the dispatching mechanism, all events, how to get started with sample dispatcher +* document the event handling mechanism, all events, how to get started with sample event handler * add key_release callback and event * remove all binding ('bind = ' etc.) stuff and port to new system * VARIABLE_SET for all types (but probably not useful for custom vars) -* port keycmd to dispatcher. we can now more cleanly send BackSpace instead of keycmd_bs and so on +* port keycmd to evt handler. we can now more cleanly send BackSpace instead of keycmd_bs and so on +* use a data-driven new config format which supports keypresses and keyreleases, modkey and all x keysyms - -= key handling (example dispatcher.sh) = += key handling (example event_handler.py) = * on escape: if insert mode: set_insert_mode(uzbl.behave.always_insert_mode); update_title else: clear_keycmd(); update_title; dehilight(uzbl.gui.web_view, NULL, NULL); diff --git a/examples/data/uzbl/scripts/dispatcher.sh b/examples/data/uzbl/scripts/dispatcher.sh deleted file mode 100755 index e8c3aed..0000000 --- a/examples/data/uzbl/scripts/dispatcher.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh -# -# Sample uzbl eventhandler -# -# demonstrating one possible way to access and process -# uzbl's event messages -# -# Usage: uzbl | eventhandler -# - -VERBOSE=1 - - -ALTPRESSED=0 -KEYCMD= # buffer for building up commands - -log () { - [ -n "$VERBOSE" ] && echo "$1" -} - -fifo () { - log "$1 > ${FIFO_PATH:-unset}" - [ -n "$FIFO_PATH" ] && echo "$1" > "$FIFO_PATH" -} - -log "Init eventhandler" - -clear_modifiers() { - ALT_PRESSED=0 - CONTROL_PRESSED=0 - #etc. - fifo 'set status_message = ' -} - -while read EVENT; do - if [ "$(echo $EVENT | cut -d ' ' -f 1)" != 'EVENT' ]; then - continue; - fi - EVENT="`echo $EVENT | sed 's/^EVENT //'`" - # get eventname - ENAME=`echo "$EVENT" | sed -ne 's/\([A-Z]*\) .*/\1/p'` - - if [ x"$ENAME" = 'xFIFO_SET' ]; then - FIFO_PATH=`echo $EVENT | cut -d ' ' -f 3` - - elif [ x"$ENAME" = x'KEY_PRESS' ]; then - KEY=$(echo "$EVENT" | sed -ne 's/KEY_PRESS \[.*\] \(.*$\)/\1/p') - - # Clear mofifiers on Escape - # - [ "$KEY" = Escape ] && clear_modifiers - - # Modifier: Alt_L - # - if [ x"$KEY" = x'Alt_L' ];then - clear_modifiers - ALT_PRESSED=1 - - # place an indicator showing the active modifier - # on uzbl's statusbar - # - fifo 'set status_message = @status_message Alt' - fi - - if [ "$ALT_PRESSED" = 1 ]; then - - # Keys - # - if [ x"$KEY" = x'a' ]; then - ALT_PRESSED=0 - fifo 'set inject_html =

You pressed Alt+a

' - fifo 'set status_message = ' - - # delete keycmd - # here not needed. loading a new page - # resets it by default - # - #echo 'set keycmd = ' > "$F_PATH" - fi - if [ x"$KEY" = x'b' ]; then - ALT_PRESSED=0 - fifo 'set inject_html =

You pressed Alt+b

' - fifo 'set status_message = ' - fi - - fi - - # Modifier: Control_L and Control_R. - # - if [ x"$KEY" = x'Control_L' -o x"$KEY" = x'Control_R' ];then - clear_modifiers - CONTROL_PRESSED=1 - fifo 'set status_message = @status_message Control' - #etc. - fi - fi -done diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py new file mode 100755 index 0000000..d6f4a36 --- /dev/null +++ b/examples/data/uzbl/scripts/event_manager.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +# Uzbl sample event manager +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +''' +The Python Event Manager +======================== + +Sample event manager written in python + +Usage +==== +uzbl | + +''' + +import sys +import os + +# 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 config +config = { + + 'uzbl_fifo': '', + 'verbose': True, + +} # End of config dictionary. + +# buffer for building up commands +keycmd = '' + + +_SCRIPTNAME = os.path.basename(sys.argv[0]) +def echo(msg): + '''Prints only if the verbose flag has been set.''' + + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error message and exits.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + sys.exit(1) + +def fifo(msg): + '''Writes commands to uzbl's fifo, if the fifo path is known''' + + 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''' + + fifo ('set keycmd = ' + keycmd) + + +def main(): + '''Main function.''' + + echo ("Init eventhandler") + + 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 + +if __name__ == "__main__": + main() + \ No newline at end of file -- cgit v1.2.3 From d773602ec80e64b5ef4ca48d83ac87548bf2a807 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 4 Sep 2009 18:51:34 +0800 Subject: Remove redundant code in cookie_daemon.py --- examples/data/uzbl/scripts/cookie_daemon.py | 7 ------- 1 file changed, 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 9c297df..9bdf807 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -293,9 +293,6 @@ class CookieMonster: self.last_request = time.time() self._running = False - # Grab the last modified time of the cookie whitelist. - self._whitelistmtime = None - def run(self): '''Start the daemon.''' @@ -384,10 +381,6 @@ class CookieMonster: if cookie_jar: mkbasedir(cookie_jar) - # Remove any stale cookie jars. - if self.jar: - del self.jar - # Create cookie jar object from file. self.jar = cookielib.MozillaCookieJar(cookie_jar) -- cgit v1.2.3 From f347cc6d1f125b61cee1345e19ae10c02c63c488 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 4 Sep 2009 19:10:07 +0800 Subject: Use pprint to dump the config dict on -v (uzbl_tabbed.py) --- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 0c706e1..b3a8053 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -1402,7 +1402,7 @@ if __name__ == "__main__": if config['verbose']: import pprint - map(echo, pprint.pformat(config).split('\n')) + sys.stderr.write("%s\n" % pprint.pformat(config)) uzbl = UzblTabbed() -- cgit v1.2.3 From c0514b06f6b9c0917614b5fde89b3ca5afa6e06b Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 4 Sep 2009 14:04:43 +0200 Subject: add stupid note about socat would be better for reloading.. in theory --- examples/data/uzbl/scripts/cookie_daemon.py | 1 + 1 file changed, 1 insertion(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index 9bdf807..a47a663 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -645,6 +645,7 @@ def main(): import pprint sys.stderr.write("%s\n" % pprint.pformat(config)) + # it would be better if we didn't need to start this python process just to send a command to the socket, but unfortunately socat doesn't seem to support SEQPACKET if action == "reload": send_command(config['cookie_socket'], "RELOAD") -- cgit v1.2.3 From b9013fb779379c502b7707169eeac7dc15cfdd51 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 5 Sep 2009 19:22:30 +0200 Subject: move 'uzbl' to more specific 'uzbl-core' program, and add 'uzbl-browser' script which wraps around it to make the browser --- Makefile | 27 +- README | 8 +- examples/data/uzbl/scripts/session.sh | 8 +- examples/data/uzbl/scripts/uzbl_tabbed.py | 2 +- tests/Makefile | 4 +- tests/test-command.c | 4 +- tests/test-expand.c | 4 +- uzbl-browser | 9 + uzbl-core.c | 3014 +++++++++++++++++++++++++++++ uzbl-core.h | 607 ++++++ uzbl.c | 3014 ----------------------------- uzbl.h | 607 ------ 12 files changed, 3660 insertions(+), 3648 deletions(-) create mode 100755 uzbl-browser create mode 100644 uzbl-core.c create mode 100644 uzbl-core.h delete mode 100644 uzbl.c delete mode 100644 uzbl.h (limited to 'examples') diff --git a/Makefile b/Makefile index 498791d..8bda961 100644 --- a/Makefile +++ b/Makefile @@ -8,43 +8,46 @@ LDFLAGS!=echo `pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0` -p all: uzbl +uzbl: uzbl-core + PREFIX?=$(DESTDIR)/usr/local # When compiling unit tests, compile uzbl as a library first -tests: uzbl.o - $(CC) -DUZBL_LIBRARY -shared -Wl uzbl.o -o ./tests/libuzbl.so +tests: uzbl-core.o + $(CC) -DUZBL_LIBRARY -shared -Wl uzbl-core.o -o ./tests/libuzbl-core.so cd ./tests/; $(MAKE) test: uzbl - ./uzbl --uri http://www.uzbl.org --verbose + PATH="`pwd`:$$PATH" ./uzbl-browser --uri http://www.uzbl.org --verbose test-dev: uzbl - XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose + XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl-browser --uri http://www.uzbl.org --verbose test-dev-dispatched: uzbl - XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl --uri http://www.uzbl.org --verbose | ./examples/data/uzbl/scripts/event_manager.py + XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl-browser --uri http://www.uzbl.org --verbose | ./examples/data/uzbl/scripts/event_manager.py test-share: uzbl - XDG_DATA_HOME=${PREFIX}/share/uzbl/examples/data XDG_CONFIG_HOME=${PREFIX}/share/uzbl/examples/config ./uzbl --uri http://www.uzbl.org --verbose + XDG_DATA_HOME=${PREFIX}/share/uzbl/examples/data XDG_CONFIG_HOME=${PREFIX}/share/uzbl/examples/config ./uzbl-browser --uri http://www.uzbl.org --verbose clean: - rm -f uzbl - rm -f uzbl.o + rm -f uzbl-core + rm -f uzbl-core.o cd ./tests/; $(MAKE) clean install: install -d $(PREFIX)/bin install -d $(PREFIX)/share/uzbl/docs install -d $(PREFIX)/share/uzbl/examples - install -m755 uzbl $(PREFIX)/bin/uzbl cp -rp docs $(PREFIX)/share/uzbl/ cp -rp config.h $(PREFIX)/share/uzbl/docs/ cp -rp examples $(PREFIX)/share/uzbl/ - install -m644 AUTHORS $(PREFIX)/share/uzbl/docs - install -m644 README $(PREFIX)/share/uzbl/docs + install -m755 uzbl-core $(PREFIX)/bin/uzbl-core + install -m755 uzbl-browser $(PREFIX)/bin/uzbl-browser + install -m644 AUTHORS $(PREFIX)/share/uzbl/docs + install -m644 README $(PREFIX)/share/uzbl/docs uninstall: - rm -rf $(PREFIX)/bin/uzbl + rm -rf $(PREFIX)/bin/uzbl-* rm -rf $(PREFIX)/share/uzbl diff --git a/README b/README index 54366bd..43e9627 100644 --- a/README +++ b/README @@ -5,11 +5,11 @@ * people who like nothing from this list: mpd, moc, wmii, dwm, awesome, mutt, pine, vim, dmenu, screen, irssi, weechat, bitlbee ### TO NEW PEOPLE: -* invoke uzbl --help -* to get you started: `XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config uzbl --uri www.archlinux.org` +* invoke uzbl-browser --help +* to get you started: `XDG_DATA_HOME=/usr/share/uzbl/examples/data XDG_CONFIG_HOME=/usr/share/uzbl/examples/config uzbl-browser --uri www.archlinux.org` * alternatively, copy the above data to your real `$XDG_DATA_HOME` and `$XDG_CONFIG_HOME` directories * try and study the sample config, read the readme to find out how it works. -* You can change the url with commands (if you have setup the appropriate keybinds) but to be most effective it's better to do url editing/changing _outside_ of uzbl. +* You can change the url with commands (if you have setup the appropriate keybinds) but to be most effective it's better to do url editing/changing _outside_ of uzbl-browser. Eg, you can use the `load_from_*` dmenu based scripts to pick/edit a url or type a new one. * If you have questions, you are likely to find answers in the FAQ or in the other documentation. * documentation is in /usr/share/uzbl/docs @@ -81,7 +81,7 @@ When uzbl forks a new instance (eg "open in new window") it will use the same co If you made changes to the configuration at runtime, these are not pased on to the child. ### COMMAND SYNTAX -Uzbl will read commands via standard input, named fifo pipe (if `fifo_dir` is set) and IPC socket (when `socket_dir` is set). +Uzbl-browser will read commands via standard input, named fifo pipe (if `fifo_dir` is set) and IPC socket (when `socket_dir` is set). For convenience, uzbl can also be instructed to read commands from a file on startup by using the `-c` option. Indeed, the config file is nothing more than a list of commands. Each command starts with the name of the command, which must be the first thing on a line; preceding whitespace is not allowed. diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh index 22d48a2..1059b5e 100755 --- a/examples/data/uzbl/scripts/session.sh +++ b/examples/data/uzbl/scripts/session.sh @@ -1,18 +1,18 @@ #!/bin/sh -# Very simple session manager for uzbl. When called with "endsession" as the +# Very simple session manager for uzbl-browser. When called with "endsession" as the # argument, it'll backup $sessionfile, look for fifos in $fifodir and # instruct each of them to store their current url in $sessionfile and # terminate themselves. Run with "launch" as the argument and an instance of -# uzbl will be launched for each stored url. "endinstance" is used internally +# uzbl-browser will be launched for each stored url. "endinstance" is used internally # and doesn't need to be called manually at any point. # Add a line like 'bind quit = /path/to/session.sh endsession' to your config [ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1 scriptfile=$0 # this script -sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/session # the file in which the "session" (i.e. urls) are stored +sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/browser-session # the file in which the "session" (i.e. urls) are stored configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file -UZBL="uzbl -c $configfile" # add custom flags and whatever here. +UZBL="uzbl-browser -c $configfile" # add custom flags and whatever here. fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere thisfifo="$4" diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 9ffa97d..feae9b9 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -945,7 +945,7 @@ class UzblTabbed: uri = "--uri %r" % uri self.tabs[tab] = uzbl - cmd = 'uzbl -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) + cmd = 'uzbl-browser -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? # Add gobject timer to make sure the config is pushed when fifo socket diff --git a/tests/Makefile b/tests/Makefile index 9db398a..3f63adf 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -CFLAGS:=-std=c99 -I$(shell pwd)/../ -L$(shell pwd) -luzbl $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -lgthread-2.0 -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS) +CFLAGS:=-std=c99 -I$(shell pwd)/../ -L$(shell pwd) -luzbl-core $(shell pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -ggdb -Wall -W -DARCH="\"$(shell uname -m)\"" -lgthread-2.0 -DG_ERRORCHECK_MUTEXES -DCOMMIT="\"$(shell git log | head -n1 | sed "s/.* //")\"" $(CPPFLAGS) CFLAGS!=echo -std=c99 `pkg-config --cflags gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0` -ggdb -Wall -W -DARCH='"\""'`uname -m`'"\""' -lgthread-2.0 -DG_ERRORCHECK_MUTEXES -DCOMMIT='"\""'`git log | head -n1 | sed "s/.* //"`'"\""' $(CPPFLAGS) LDFLAGS:=$(shell pkg-config --libs gtk+-2.0 webkit-1.0 libsoup-2.4 gthread-2.0) -pthread $(LDFLAGS) @@ -14,4 +14,4 @@ all: $(TEST_PROGS) clean: rm -f $(TEST_PROGS) - rm -f libuzbl.so + rm -f libuzbl-core.so diff --git a/tests/test-command.c b/tests/test-command.c index aee4bf2..a752ca6 100644 --- a/tests/test-command.c +++ b/tests/test-command.c @@ -22,10 +22,10 @@ #include #include -#include +#include #include -extern Uzbl uzbl; +extern UzblCore uzbl; void test_keycmd (void) { diff --git a/tests/test-expand.c b/tests/test-expand.c index 2299227..0ced1f4 100644 --- a/tests/test-expand.c +++ b/tests/test-expand.c @@ -22,10 +22,10 @@ #include #include -#include +#include #include -extern Uzbl uzbl; +extern UzblCore uzbl; extern gchar* expand(char*, guint); extern void make_var_to_name_hash(void); diff --git a/uzbl-browser b/uzbl-browser new file mode 100755 index 0000000..93ba2d7 --- /dev/null +++ b/uzbl-browser @@ -0,0 +1,9 @@ +#!/bin/sh +# this script implements are more useful "browsing experience". make sure to have the event manager in the appropriate place. + +if [ x"$XDG_DATA_HOME" != 'x' ] +then + uzbl-core "$@" | $XDG_DATA_HOME/uzbl/scripts/event_manager.py +else + uzbl-core "$@" | $HOME/.local/share/uzbl/scripts/event_manager.py +fi diff --git a/uzbl-core.c b/uzbl-core.c new file mode 100644 index 0000000..ad7dd56 --- /dev/null +++ b/uzbl-core.c @@ -0,0 +1,3014 @@ +/* -*- c-basic-offset: 4; -*- */ +// Original code taken from the example webkit-gtk+ application. see notice below. +// Modified code is licensed under the GPL 3. See LICENSE file. + + +/* + * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#define LENGTH(x) (sizeof x / sizeof x[0]) +#define _POSIX_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uzbl-core.h" +#include "config.h" + +UzblCore uzbl; + +/* commandline arguments (set initial values for the state variables) */ +const +GOptionEntry entries[] = +{ + { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, + "Uri to load at startup (equivalent to 'uzbl ' or 'set uri = URI' after uzbl has launched)", "URI" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, + "Whether to print all messages or just errors.", NULL }, + { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, + "Name of the current instance (defaults to Xorg window id)", "NAME" }, + { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, + "Path to config file or '-' for stdin", "FILE" }, + { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id, + "Socket ID", "SOCKET" }, + { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry, + "Set window geometry (format: WIDTHxHEIGHT+-X+-Y)", "GEOMETRY" }, + { "version", 'V', 0, G_OPTION_ARG_NONE, &uzbl.behave.print_version, + "Print the version and exit", NULL }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT}; + +/* associate command names to their properties */ +typedef struct { + enum ptr_type type; + union { + int *i; + float *f; + gchar **s; + } ptr; + int dump; + int writeable; + /*@null@*/ void (*func)(void); +} uzbl_cmdprop; + +/* abbreviations to help keep the table's width humane */ +#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun } +#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun } +#define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun } +#define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun } +#define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun } +#define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun } + +const struct var_name_to_ptr_t { + const char *name; + uzbl_cmdprop cp; +} var_name_to_ptr[] = { +/* variable name pointer to variable in code dump callback function */ +/* ---------------------------------------------------------------------------------------------- */ + { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)}, + { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)}, + { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)}, + { "geometry", PTR_V_STR(uzbl.gui.geometry, 1, cmd_set_geometry)}, + { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)}, + { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)}, + { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)}, + { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)}, + { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, update_title)}, + { "status_pbar_done", PTR_V_STR(uzbl.gui.sbar.progress_s, 1, update_title)}, + { "status_pbar_pending", PTR_V_STR(uzbl.gui.sbar.progress_u, 1, update_title)}, + { "status_pbar_width", PTR_V_INT(uzbl.gui.sbar.progress_w, 1, update_title)}, + { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, update_title)}, + { "insert_indicator", PTR_V_STR(uzbl.behave.insert_indicator, 1, update_indicator)}, + { "command_indicator", PTR_V_STR(uzbl.behave.cmd_indicator, 1, update_indicator)}, + { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, update_title)}, + { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, update_title)}, + { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)}, + { "insert_mode", PTR_V_INT(uzbl.behave.insert_mode, 1, set_mode_indicator)}, + { "always_insert_mode", PTR_V_INT(uzbl.behave.always_insert_mode, 1, cmd_always_insert_mode)}, + { "reset_command_mode", PTR_V_INT(uzbl.behave.reset_command_mode, 1, NULL)}, + { "modkey", PTR_V_STR(uzbl.behave.modkey, 1, cmd_modkey)}, + { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)}, + { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)}, + { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)}, + { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, + { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)}, + { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)}, + { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, cmd_scheme_handler)}, + { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, + { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)}, + { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)}, + { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)}, + { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)}, + { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)}, + { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)}, + { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)}, + + /* exported WebKitWebSettings properties */ + { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)}, + { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)}, + { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)}, + { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)}, + { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)}, + { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)}, + { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)}, + { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)}, + { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)}, + { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)}, + { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)}, + { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)}, + { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)}, + { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)}, + { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)}, + { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)}, + { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)}, + { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)}, + { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)}, + { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)}, + { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)}, + { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)}, + + /* constants (not dumpable or writeable) */ + { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)}, + { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)}, + { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)}, + { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)}, + { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)}, + { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)}, + { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)}, + { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)}, + { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)}, + { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)}, + { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)}, + + { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}} +}; + +/* Event id to name mapping + * 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" , + "KEY_PRESS" , + "KEY_RELEASE" , + "DOWNLOAD_REQUEST" , + "COMMAND_EXECUTED" , + "LINK_HOVER" , + "TITLE_CHANGED" , + "GEOMETRY_CHANGED" , + "WEBINSPECTOR" , + "COOKIE" , + "NEW_WINDOW" , + "SELECTION_CHANGED", + "VARIABLE_SET", + "FIFO_SET" +}; + + +const struct { + /*@null@*/ char *key; + guint mask; +} modkeys[] = { + { "SHIFT", GDK_SHIFT_MASK }, // shift + { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings + { "CONTROL", GDK_CONTROL_MASK }, // control + { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings + { "MOD2", GDK_MOD2_MASK }, // 5th mod + { "MOD3", GDK_MOD3_MASK }, // 6th mod + { "MOD4", GDK_MOD4_MASK }, // 7th mod + { "MOD5", GDK_MOD5_MASK }, // 8th mod + { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button + { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button + { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button + { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button + { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button + { "SUPER", GDK_SUPER_MASK }, // super (since 2.10) + { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10) + { "META", GDK_META_MASK }, // meta (since 2.10) + { NULL, 0 } +}; + + +/* construct a hash from the var_name_to_ptr array for quick access */ +void +create_var_to_name_hash() { + const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr; + uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal); + while(n2v_p->name) { + g_hash_table_insert(uzbl.comm.proto_var, + (gpointer) n2v_p->name, + (gpointer) &n2v_p->cp); + n2v_p++; + } +} + + +/* --- UTILITY FUNCTIONS --- */ +enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE}; +enum exp_type +get_exp_type(const gchar *s) { + /* variables */ + if(*(s+1) == '(') + return EXP_EXPR; + else if(*(s+1) == '{') + return EXP_BRACED_VAR; + else if(*(s+1) == '<') + return EXP_JS; + else if(*(s+1) == '[') + return EXP_ESCAPE; + else + return EXP_SIMPLE_VAR; + + /*@notreached@*/ +return EXP_ERR; +} + +/* + * recurse == 1: don't expand '@(command)@' + * recurse == 2: don't expand '@@' +*/ +gchar * +expand(const char *s, guint recurse) { + uzbl_cmdprop *c; + enum exp_type etype; + char *end_simple_var = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½"; + char *ret = NULL; + char *vend = NULL; + GError *err = NULL; + gchar *cmd_stdout = NULL; + gchar *mycmd = NULL; + GString *buf = g_string_new(""); + GString *js_ret = g_string_new(""); + + while(*s) { + switch(*s) { + case '\\': + g_string_append_c(buf, *++s); + s++; + break; + + case '@': + etype = get_exp_type(s); + s++; + + switch(etype) { + case EXP_SIMPLE_VAR: + vend = strpbrk(s, end_simple_var); + if(!vend) vend = strchr(s, '\0'); + break; + case EXP_BRACED_VAR: + s++; + vend = strchr(s, '}'); + if(!vend) vend = strchr(s, '\0'); + break; + case EXP_EXPR: + s++; + vend = strstr(s, ")@"); + if(!vend) vend = strchr(s, '\0'); + break; + case EXP_JS: + s++; + vend = strstr(s, ">@"); + if(!vend) vend = strchr(s, '\0'); + break; + case EXP_ESCAPE: + s++; + vend = strstr(s, "]@"); + if(!vend) vend = strchr(s, '\0'); + break; + /*@notreached@*/ + case EXP_ERR: + break; + } + assert(vend); + + ret = g_strndup(s, vend-s); + + if(etype == EXP_SIMPLE_VAR || + etype == EXP_BRACED_VAR) { + if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) { + if(c->type == TYPE_STR && *c->ptr.s != NULL) { + g_string_append(buf, (gchar *)*c->ptr.s); + } + else if(c->type == TYPE_INT) { + g_string_append_printf(buf, "%d", *c->ptr.i); + } + else if(c->type == TYPE_FLOAT) { + g_string_append_printf(buf, "%f", *c->ptr.f); + } + } + + if(etype == EXP_SIMPLE_VAR) + s = vend; + else + s = vend+1; + } + else if(recurse != 1 && + etype == EXP_EXPR) { + mycmd = expand(ret, 1); + g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err); + g_free(mycmd); + + if (err) { + g_printerr("error on running command: %s\n", err->message); + g_error_free (err); + } + else if (*cmd_stdout) { + size_t len = strlen(cmd_stdout); + + if(len > 0 && cmd_stdout[len-1] == '\n') + cmd_stdout[--len] = '\0'; /* strip trailing newline */ + + g_string_append(buf, cmd_stdout); + g_free(cmd_stdout); + } + s = vend+2; + } + else if(recurse != 2 && + etype == EXP_JS) { + mycmd = expand(ret, 2); + eval_js(uzbl.gui.web_view, mycmd, js_ret); + g_free(mycmd); + + if(js_ret->str) { + g_string_append(buf, js_ret->str); + g_string_free(js_ret, TRUE); + js_ret = g_string_new(""); + } + s = vend+2; + } + else if(etype == EXP_ESCAPE) { + mycmd = expand(ret, 0); + char *escaped = g_markup_escape_text(mycmd, strlen(mycmd)); + + g_string_append(buf, escaped); + + g_free(escaped); + g_free(mycmd); + s = vend+2; + } + + g_free(ret); + ret = NULL; + break; + + default: + g_string_append_c(buf, *s); + s++; + break; + } + } + g_string_free(js_ret, TRUE); + return g_string_free(buf, FALSE); +} + +/* send events as strings to stdout (do we need to support fifo/socket as output mechanism?) + * we send all events to the output. it's the users task to filter out what he cares about. +*/ +void +send_event(int type, const gchar *details) { + + if(type < LAST_EVENT) { + printf("EVENT %s [%s] %s\n", event_table[type], uzbl.state.instance_name, details); + fflush(stdout); + } +} + +char * +itos(int val) { + char tmp[20]; + + snprintf(tmp, sizeof(tmp), "%i", val); + return g_strdup(tmp); +} + +gchar* +strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go + +gchar* +argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } + +char * +str_replace (const char* search, const char* replace, const char* string) { + gchar **buf; + char *ret; + + buf = g_strsplit (string, search, -1); + ret = g_strjoinv (replace, buf); + g_strfreev(buf); // somebody said this segfaults + + return ret; +} + +GArray* +read_file_by_line (const gchar *path) { + GIOChannel *chan = NULL; + gchar *readbuf = NULL; + gsize len; + GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*)); + int i = 0; + + chan = g_io_channel_new_file(path, "r", NULL); + + if (chan) { + while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) { + const gchar* val = g_strdup (readbuf); + g_array_append_val (lines, val); + g_free (readbuf); + i ++; + } + + g_io_channel_unref (chan); + } else { + fprintf(stderr, "File '%s' not be read.\n", path); + } + + return lines; +} + +gchar* +parseenv (char* string) { + extern char** environ; + gchar* tmpstr = NULL; + int i = 0; + + + while (environ[i] != NULL) { + gchar** env = g_strsplit (environ[i], "=", 2); + gchar* envname = g_strconcat ("$", env[0], NULL); + + if (g_strrstr (string, envname) != NULL) { + tmpstr = g_strdup(string); + g_free (string); + string = str_replace(envname, env[1], tmpstr); + g_free (tmpstr); + } + + g_free (envname); + g_strfreev (env); // somebody said this breaks uzbl + i++; + } + + return string; +} + +sigfunc* +setup_signal(int signr, sigfunc *shandler) { + struct sigaction nh, oh; + + nh.sa_handler = shandler; + sigemptyset(&nh.sa_mask); + nh.sa_flags = 0; + + if(sigaction(signr, &nh, &oh) < 0) + return SIG_ERR; + + return NULL; +} + +void +clean_up(void) { + if (uzbl.behave.fifo_dir) + unlink (uzbl.comm.fifo_path); + if (uzbl.behave.socket_dir) + unlink (uzbl.comm.socket_path); + + g_free(uzbl.state.executable_path); + g_free(uzbl.state.keycmd); + g_hash_table_destroy(uzbl.bindings); + g_hash_table_destroy(uzbl.behave.commands); +} + +/* --- SIGNAL HANDLER --- */ + +void +catch_sigterm(int s) { + (void) s; + clean_up(); +} + +void +catch_sigint(int s) { + (void) s; + clean_up(); + exit(EXIT_SUCCESS); +} + +/* --- CALLBACKS --- */ + +gboolean +navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { + (void) web_view; + (void) frame; + (void) navigation_action; + (void) user_data; + + const gchar* uri = webkit_network_request_get_uri (request); + gboolean decision_made = FALSE; + + if (uzbl.state.verbose) + printf("Navigation requested -> %s\n", uri); + + if (uzbl.behave.scheme_handler) { + GString *s = g_string_new (""); + g_string_printf(s, "'%s'", uri); + + run_handler(uzbl.behave.scheme_handler, s->str); + + if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { + char *p = strchr(uzbl.comm.sync_stdout, '\n' ); + if ( p != NULL ) *p = '\0'; + if (!strcmp(uzbl.comm.sync_stdout, "USED")) { + webkit_web_policy_decision_ignore(policy_decision); + decision_made = TRUE; + } + } + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + g_string_free(s, TRUE); + } + if (!decision_made) + webkit_web_policy_decision_use(policy_decision); + + return TRUE; +} + +gboolean +new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { + (void) web_view; + (void) frame; + (void) navigation_action; + (void) policy_decision; + (void) user_data; + const gchar* uri = webkit_network_request_get_uri (request); + if (uzbl.state.verbose) + printf("New window requested -> %s \n", uri); + webkit_web_policy_decision_use(policy_decision); + send_event(NEW_WINDOW, uri); + return TRUE; +} + +gboolean +mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { + (void) frame; + (void) request; + (void) user_data; + + /* If we can display it, let's display it... */ + if (webkit_web_view_can_show_mime_type (web_view, mime_type)) { + webkit_web_policy_decision_use (policy_decision); + return TRUE; + } + + /* ...everything we can't display is downloaded */ + webkit_web_policy_decision_download (policy_decision); + return TRUE; +} + +/*@null@*/ WebKitWebView* +create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) { + (void) web_view; + (void) frame; + (void) user_data; + if (uzbl.state.selected_url != NULL) { + if (uzbl.state.verbose) + printf("\nNew web view -> %s\n",uzbl.state.selected_url); + new_window_load_uri(uzbl.state.selected_url); + } else { + if (uzbl.state.verbose) + printf("New web view -> %s\n","Nothing to open, exiting"); + } + return (NULL); +} + +gboolean +download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { + (void) web_view; + (void) user_data; + if (uzbl.behave.download_handler) { + const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download); + if (uzbl.state.verbose) + printf("Download -> %s\n",uri); + /* if urls not escaped, we may have to escape and quote uri before this call */ + + GString *args = g_string_new(uri); + + if (uzbl.net.proxy_url) { + g_string_append_c(args, ' '); + g_string_append(args, uzbl.net.proxy_url); + } + + run_handler(uzbl.behave.download_handler, args->str); + + g_string_free(args, TRUE); + } + send_event(DOWNLOAD_REQ, webkit_download_get_uri ((WebKitDownload*)download)); + return (FALSE); +} + +/* scroll a bar in a given direction */ +void +scroll (GtkAdjustment* bar, GArray *argv) { + gchar *end; + gdouble max_value; + + gdouble page_size = gtk_adjustment_get_page_size(bar); + gdouble value = gtk_adjustment_get_value(bar); + gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end); + + if (*end == '%') + value += page_size * amount * 0.01; + else + value += amount; + + max_value = gtk_adjustment_get_upper(bar) - page_size; + + if (value > max_value) + value = max_value; /* don't scroll past the end of the page */ + + gtk_adjustment_set_value (bar, value); +} + +void +scroll_begin(WebKitWebView* page, GArray *argv, GString *result) { + (void) page; (void) argv; (void) result; + gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v)); +} + +void +scroll_end(WebKitWebView* page, GArray *argv, GString *result) { + (void) page; (void) argv; (void) result; + gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) - + gtk_adjustment_get_page_size(uzbl.gui.bar_v)); +} + +void +scroll_vert(WebKitWebView* page, GArray *argv, GString *result) { + (void) page; (void) result; + scroll(uzbl.gui.bar_v, argv); +} + +void +scroll_horz(WebKitWebView* page, GArray *argv, GString *result) { + (void) page; (void) result; + scroll(uzbl.gui.bar_h, argv); +} + +void +cmd_set_geometry() { + if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) { + if(uzbl.state.verbose) + printf("Error in geometry string: %s\n", uzbl.gui.geometry); + } + /* update geometry var with the actual geometry + this is necessary as some WMs don't seem to honour + the above setting and we don't want to end up with + wrong geometry information + */ + retrieve_geometry(); +} + +void +cmd_set_status() { + if (!uzbl.behave.show_status) { + gtk_widget_hide(uzbl.gui.mainbar); + } else { + gtk_widget_show(uzbl.gui.mainbar); + } + update_title(); +} + +void +toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) { + (void)page; + (void)argv; + (void)result; + + webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page)); +} + +void +toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) { + (void)page; + (void)argv; + (void)result; + + if (uzbl.behave.show_status) { + gtk_widget_hide(uzbl.gui.mainbar); + } else { + gtk_widget_show(uzbl.gui.mainbar); + } + uzbl.behave.show_status = !uzbl.behave.show_status; + update_title(); +} + +void +link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) { + (void) page; + (void) title; + (void) data; + //Set selected_url state variable + g_free(uzbl.state.selected_url); + uzbl.state.selected_url = NULL; + if (link) { + uzbl.state.selected_url = g_strdup(link); + send_event(LINK_HOVER, uzbl.state.selected_url); + } + update_title(); +} + +void +title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { + (void) web_view; + (void) param_spec; + const gchar *title = webkit_web_view_get_title(web_view); + if (uzbl.gui.main_title) + 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); +} + +void +progress_change_cb (WebKitWebView* page, gint progress, gpointer data) { + (void) page; + (void) data; + uzbl.gui.sbar.load_progress = progress; + + g_free(uzbl.gui.sbar.progress_bar); + uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress); + + update_title(); +} + +void +selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) { + (void)ud; + gchar *tmp; + + webkit_web_view_copy_clipboard(webkitwebview); + tmp = gtk_clipboard_wait_for_text(gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); + send_event(SELECTION_CHANGED, tmp); + g_free(tmp); +} + +void +load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { + (void) page; + (void) data; + + if (uzbl.behave.load_finish_handler) + run_handler(uzbl.behave.load_finish_handler, ""); + + send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame)); +} + +void clear_keycmd() { + g_free(uzbl.state.keycmd); + uzbl.state.keycmd = g_strdup(""); +} + +void +load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { + (void) page; + (void) frame; + (void) data; + uzbl.gui.sbar.load_progress = 0; + if (uzbl.behave.load_start_handler) + run_handler(uzbl.behave.load_start_handler, ""); + + send_event(LOAD_START, uzbl.state.uri); +} + +void +load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) { + (void) page; + (void) frame; + (void) ud; + GError *err = web_err; + gchar *details; + + details = g_strdup_printf("%s %d:%s", uri, err->code, err->message); + send_event(LOAD_ERROR, details); + g_free(details); +} + +void +load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { + (void) page; + (void) data; + g_free (uzbl.state.uri); + GString* newuri = g_string_new (webkit_web_frame_get_uri (frame)); + uzbl.state.uri = g_string_free (newuri, FALSE); + if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) { + set_insert_mode(uzbl.behave.always_insert_mode); + update_title(); + } + if (uzbl.behave.load_commit_handler) + run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri); + + /* event message */ + send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame)); +} + +void +destroy_cb (GtkWidget* widget, gpointer data) { + (void) widget; + (void) data; + gtk_main_quit (); +} + + +/* VIEW funcs (little webkit wrappers) */ +#define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);} +VIEWFUNC(reload) +VIEWFUNC(reload_bypass_cache) +VIEWFUNC(stop_loading) +VIEWFUNC(zoom_in) +VIEWFUNC(zoom_out) +VIEWFUNC(go_back) +VIEWFUNC(go_forward) +#undef VIEWFUNC + +/* -- command to callback/function map for things we cannot attach to any signals */ +struct {const char *key; CommandInfo value;} cmdlist[] = +{ /* 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} } +}; + +void +commands_hash(void) +{ + unsigned int i; + uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal); + + for (i = 0; i < LENGTH(cmdlist); i++) + g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value); +} + +/* -- CORE FUNCTIONS -- */ + +void +free_action(gpointer act) { + Action *action = (Action*)act; + g_free(action->name); + if (action->param) + g_free(action->param); + g_free(action); +} + +Action* +new_action(const gchar *name, const gchar *param) { + Action *action = g_new(Action, 1); + + action->name = g_strdup(name); + if (param) + action->param = g_strdup(param); + else + action->param = NULL; + + return action; +} + +bool +file_exists (const char * filename) { + return (access(filename, F_OK) == 0); +} + +void +set_var(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); + if (split[0] != NULL) { + gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); + set_var_value(g_strstrip(split[0]), value); + g_free(value); + } + g_strfreev(split); +} + +void +update_gui(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) argv; (void) result; + + update_title(); +} + +void +print(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + gchar* buf; + + buf = expand(argv_idx(argv, 0), 0); + g_string_assign(result, buf); + g_free(buf); +} + +void +act_bind(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2); + gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); + add_binding(g_strstrip(split[0]), value); + g_free(value); + g_strfreev(split); +} + + +void +act_dump_config() { + dump_config(); +} + +void +set_keycmd() { + run_keycmd(FALSE); + update_title(); +} + +void +set_mode_indicator() { + uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ? + uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator); +} + +void +update_indicator() { + set_mode_indicator(); + update_title(); +} + +void +set_insert_mode(gboolean mode) { + uzbl.behave.insert_mode = mode; + set_mode_indicator(); +} + +void +toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + + if (argv_idx(argv, 0)) { + if (strcmp (argv_idx(argv, 0), "0") == 0) { + set_insert_mode(FALSE); + } else { + set_insert_mode(TRUE); + } + } else { + set_insert_mode( !uzbl.behave.insert_mode ); + } + + update_title(); +} + +void +load_uri (WebKitWebView *web_view, GArray *argv, GString *result) { + (void) result; + + if (argv_idx(argv, 0)) { + GString* newuri = g_string_new (argv_idx(argv, 0)); + if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) { + run_js(web_view, argv, NULL); + return; + } + if (!soup_uri_new(argv_idx(argv, 0))) + g_string_prepend (newuri, "http://"); + /* if we do handle cookies, ask our handler for them */ + webkit_web_view_load_uri (web_view, newuri->str); + g_string_free (newuri, TRUE); + } +} + +/* Javascript*/ + +JSValueRef +js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, + size_t argumentCount, const JSValueRef arguments[], + JSValueRef* exception) { + (void) function; + (void) thisObject; + (void) exception; + + JSStringRef js_result_string; + GString *result = g_string_new(""); + + if (argumentCount >= 1) { + JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL); + size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg); + char ctl_line[arg_size]; + JSStringGetUTF8CString(arg, ctl_line, arg_size); + + parse_cmd_line(ctl_line, result); + + JSStringRelease(arg); + } + js_result_string = JSStringCreateWithUTF8CString(result->str); + + g_string_free(result, TRUE); + + return JSValueMakeString(ctx, js_result_string); +} + +JSStaticFunction js_static_functions[] = { + {"run", js_run_command, kJSPropertyAttributeNone}, +}; + +void +js_init() { + /* This function creates the class and its definition, only once */ + if (!uzbl.js.initialized) { + /* it would be pretty cool to make this dynamic */ + uzbl.js.classdef = kJSClassDefinitionEmpty; + uzbl.js.classdef.staticFunctions = js_static_functions; + + uzbl.js.classref = JSClassCreate(&uzbl.js.classdef); + } +} + + +void +eval_js(WebKitWebView * web_view, gchar *script, GString *result) { + WebKitWebFrame *frame; + JSGlobalContextRef context; + JSObjectRef globalobject; + JSStringRef var_name; + + JSStringRef js_script; + JSValueRef js_result; + JSStringRef js_result_string; + size_t js_result_size; + + js_init(); + + frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view)); + context = webkit_web_frame_get_global_context(frame); + globalobject = JSContextGetGlobalObject(context); + + /* uzbl javascript namespace */ + var_name = JSStringCreateWithUTF8CString("Uzbl"); + JSObjectSetProperty(context, globalobject, var_name, + JSObjectMake(context, uzbl.js.classref, NULL), + kJSClassAttributeNone, NULL); + + /* evaluate the script and get return value*/ + js_script = JSStringCreateWithUTF8CString(script); + js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL); + if (js_result && !JSValueIsUndefined(context, js_result)) { + js_result_string = JSValueToStringCopy(context, js_result, NULL); + js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string); + + if (js_result_size) { + char js_result_utf8[js_result_size]; + JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size); + g_string_assign(result, js_result_utf8); + } + + JSStringRelease(js_result_string); + } + + /* cleanup */ + JSObjectDeleteProperty(context, globalobject, var_name, NULL); + + JSStringRelease(var_name); + JSStringRelease(js_script); +} + +void +run_js (WebKitWebView * web_view, GArray *argv, GString *result) { + if (argv_idx(argv, 0)) + eval_js(web_view, argv_idx(argv, 0), result); +} + +void +run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) { + (void) result; + if (argv_idx(argv, 0)) { + GArray* lines = read_file_by_line (argv_idx (argv, 0)); + gchar* js = NULL; + int i = 0; + gchar* line; + + while ((line = g_array_index(lines, gchar*, i))) { + if (js == NULL) { + js = g_strdup (line); + } else { + gchar* newjs = g_strconcat (js, line, NULL); + js = newjs; + } + i ++; + g_free (line); + } + + if (uzbl.state.verbose) + printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0)); + + if (argv_idx (argv, 1)) { + gchar* newjs = str_replace("%s", argv_idx (argv, 1), js); + g_free (js); + js = newjs; + } + eval_js (web_view, js, result); + g_free (js); + g_array_free (lines, TRUE); + } +} + +void +search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { + if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) { + if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) { + webkit_web_view_unmark_text_matches (page); + webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0); + uzbl.state.searchtx = g_strdup(argv_idx(argv, 0)); + } + } + + if (uzbl.state.searchtx) { + if (uzbl.state.verbose) + printf ("Searching: %s\n", uzbl.state.searchtx); + webkit_web_view_set_highlight_text_matches (page, TRUE); + webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE); + } +} + +void +search_forward_text (WebKitWebView *page, GArray *argv, GString *result) { + (void) result; + search_text(page, argv, TRUE); +} + +void +search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) { + (void) result; + search_text(page, argv, FALSE); +} + +void +dehilight (WebKitWebView *page, GArray *argv, GString *result) { + (void) argv; (void) result; + webkit_web_view_set_highlight_text_matches (page, FALSE); +} + + +void +new_window_load_uri (const gchar * uri) { + if (uzbl.behave.new_window) { + GString *s = g_string_new (""); + g_string_printf(s, "'%s'", uri); + run_handler(uzbl.behave.new_window, s->str); + send_event(NEW_WINDOW, s->str); + return; + } + GString* to_execute = g_string_new (""); + g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri); + int i; + for (i = 0; entries[i].long_name != NULL; i++) { + if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) { + gchar** str = (gchar**)entries[i].arg_data; + if (*str!=NULL) { + g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str); + } + } + } + if (uzbl.state.verbose) + printf("\n%s\n", to_execute->str); + g_spawn_command_line_async (to_execute->str, NULL); + /* TODO: should we just report the uri as event detail? */ + send_event(NEW_WINDOW, to_execute->str); + g_string_free (to_execute, TRUE); +} + +void +chain (WebKitWebView *page, GArray *argv, GString *result) { + (void) page; (void) result; + gchar *a = NULL; + gchar **parts = NULL; + guint i = 0; + while ((a = argv_idx(argv, i++))) { + parts = g_strsplit (a, " ", 2); + if (parts[0]) + parse_command(parts[0], parts[1], result); + g_strfreev (parts); + } +} + +void +keycmd (WebKitWebView *page, GArray *argv, GString *result) { + (void)page; + (void)argv; + (void)result; + uzbl.state.keycmd = g_strdup(argv_idx(argv, 0)); + run_keycmd(FALSE); + update_title(); +} + +void +keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) { + (void)page; + (void)argv; + (void)result; + uzbl.state.keycmd = g_strdup(argv_idx(argv, 0)); + run_keycmd(TRUE); + update_title(); +} + +void +keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) { + gchar *prev; + (void)page; + (void)argv; + (void)result; + int len = strlen(uzbl.state.keycmd); + prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len); + if (prev) + uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0'; + update_title(); +} + +void +close_uzbl (WebKitWebView *page, GArray *argv, GString *result) { + (void)page; + (void)argv; + (void)result; + gtk_main_quit (); +} + +/* --Statusbar functions-- */ +char* +build_progressbar_ascii(int percent) { + int width=uzbl.gui.sbar.progress_w; + int i; + double l; + GString *bar = g_string_new(""); + + l = (double)percent*((double)width/100.); + l = (int)(l+.5)>=(int)l ? l+.5 : l; + + for(i=0; i<(int)l; i++) + g_string_append(bar, uzbl.gui.sbar.progress_s); + + for(; i [args] + GError *err = NULL; + + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + gchar *pid = itos(getpid()); + gchar *xwin = itos(uzbl.xwin); + guint i; + sharg_append(a, command); + for (i = 0; i < npre; i++) /* add n args before the default vars */ + sharg_append(a, args[i]); + sharg_append(a, uzbl.state.config_file); + sharg_append(a, pid); + sharg_append(a, xwin); + sharg_append(a, uzbl.comm.fifo_path); + sharg_append(a, uzbl.comm.socket_path); + sharg_append(a, uzbl.state.uri); + sharg_append(a, uzbl.gui.main_title); + + for (i = npre; i < g_strv_length((gchar**)args); i++) + sharg_append(a, args[i]); + + gboolean result; + if (sync) { + if (*output_stdout) *output_stdout = strfree(*output_stdout); + + result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, output_stdout, NULL, NULL, &err); + } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, &err); + + if (uzbl.state.verbose) { + GString *s = g_string_new("spawned:"); + for (i = 0; i < (a->len); i++) { + gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i)); + g_string_append_printf(s, " %s", qarg); + g_free (qarg); + } + g_string_append_printf(s, " -- result: %s", (result ? "true" : "false")); + printf("%s\n", s->str); + g_string_free(s, TRUE); + if(output_stdout) { + printf("Stdout: %s\n", *output_stdout); + } + } + if (err) { + g_printerr("error on run_command: %s\n", err->message); + g_error_free (err); + } + g_free (pid); + g_free (xwin); + g_array_free (a, TRUE); + return result; +} + +/*@null@*/ gchar** +split_quoted(const gchar* src, const gboolean unquote) { + /* split on unquoted space, return array of strings; + remove a layer of quotes and backslashes if unquote */ + if (!src) return NULL; + + gboolean dq = FALSE; + gboolean sq = FALSE; + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + GString *s = g_string_new (""); + const gchar *p; + gchar **ret; + gchar *dup; + for (p = src; *p != '\0'; p++) { + if ((*p == '\\') && unquote) g_string_append_c(s, *++p); + else if (*p == '\\') { g_string_append_c(s, *p++); + g_string_append_c(s, *p); } + else if ((*p == '"') && unquote && !sq) dq = !dq; + else if (*p == '"' && !sq) { g_string_append_c(s, *p); + dq = !dq; } + else if ((*p == '\'') && unquote && !dq) sq = !sq; + else if (*p == '\'' && !dq) { g_string_append_c(s, *p); + sq = ! sq; } + else if ((*p == ' ') && !dq && !sq) { + dup = g_strdup(s->str); + g_array_append_val(a, dup); + g_string_truncate(s, 0); + } else g_string_append_c(s, *p); + } + dup = g_strdup(s->str); + g_array_append_val(a, dup); + ret = (gchar**)a->data; + g_array_free (a, FALSE); + g_string_free (s, TRUE); + return ret; +} + +void +spawn(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after + if (argv_idx(argv, 0)) + run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL); +} + +void +spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + + if (argv_idx(argv, 0)) + run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), + TRUE, &uzbl.comm.sync_stdout); +} + +void +spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + if (!uzbl.behave.shell_cmd) { + g_printerr ("spawn_sh: shell_cmd is not set!\n"); + return; + } + + guint i; + gchar *spacer = g_strdup(""); + g_array_insert_val(argv, 1, spacer); + gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); + + for (i = 1; i < g_strv_length(cmd); i++) + g_array_prepend_val(argv, cmd[i]); + + if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL); + g_free (spacer); + g_strfreev (cmd); +} + +void +spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + if (!uzbl.behave.shell_cmd) { + g_printerr ("spawn_sh_sync: shell_cmd is not set!\n"); + return; + } + + guint i; + gchar *spacer = g_strdup(""); + g_array_insert_val(argv, 1, spacer); + gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); + + for (i = 1; i < g_strv_length(cmd); i++) + g_array_prepend_val(argv, cmd[i]); + + if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, + TRUE, &uzbl.comm.sync_stdout); + g_free (spacer); + g_strfreev (cmd); +} + +void +talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) { + (void)web_view; (void)result; + + int fd, len; + struct sockaddr_un sa; + char* sockpath; + ssize_t ret; + struct pollfd pfd; + struct iovec* iov; + guint i; + + if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + /* This function could be optimised by storing a hash table of socket paths + and associated connected file descriptors rather than closing and + re-opening for every call. Also we could launch a script if socket connect + fails. */ + + /* First element argv[0] is path to socket. Following elements are tokens to + write to the socket. We write them as a single packet with each token + separated by an ASCII nul (\0). */ + if(argv->len < 2) { + g_printerr("talk_to_socket called with only %d args (need at least two).\n", + (int)argv->len); + return; + } + + /* copy socket path, null terminate result */ + sockpath = g_array_index(argv, char*, 0); + g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path)); + sa.sun_family = AF_UNIX; + + /* create socket file descriptor and connect it to path */ + fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if(fd == -1) { + g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno)); + return; + } + if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) { + g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno)); + close(fd); + return; + } + + /* build request vector */ + iov = g_malloc(sizeof(struct iovec) * (argv->len - 1)); + if(!iov) { + g_printerr("talk_to_socket: unable to allocated memory for token vector\n"); + close(fd); + return; + } + for(i = 1; i < argv->len; ++i) { + iov[i - 1].iov_base = g_array_index(argv, char*, i); + iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */ + } + + /* write request */ + ret = writev(fd, iov, argv->len - 1); + g_free(iov); + if(ret == -1) { + g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno)); + close(fd); + return; + } + + /* wait for a response, with a 500ms timeout */ + pfd.fd = fd; + pfd.events = POLLIN; + while(1) { + ret = poll(&pfd, 1, 500); + if(ret == 1) break; + if(ret == 0) errno = ETIMEDOUT; + if(errno == EINTR) continue; + g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n", + strerror(errno)); + close(fd); + return; + } + + /* get length of response */ + if(ioctl(fd, FIONREAD, &len) == -1) { + g_printerr("talk_to_socket: cannot find daemon response length, " + "ioctl failed (%s)\n", strerror(errno)); + close(fd); + return; + } + + /* if there is a response, read it */ + if(len) { + uzbl.comm.sync_stdout = g_malloc(len + 1); + if(!uzbl.comm.sync_stdout) { + g_printerr("talk_to_socket: failed to allocate %d bytes\n", len); + close(fd); + return; + } + uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */ + + ret = read(fd, uzbl.comm.sync_stdout, len); + if(ret == -1) { + g_printerr("talk_to_socket: failed to read from socket (%s)\n", + strerror(errno)); + close(fd); + return; + } + } + + /* clean up */ + close(fd); + return; +} + +void +parse_command(const char *cmd, const char *param, GString *result) { + CommandInfo *c; + + if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) { + guint i; + gchar **par = split_quoted(param, TRUE); + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + + if (c->no_split) { /* don't split */ + sharg_append(a, param); + } else if (par) { + for (i = 0; i < g_strv_length(par); i++) + sharg_append(a, par[i]); + } + + if (result == NULL) { + GString *result_print = g_string_new(""); + + c->function(uzbl.gui.web_view, a, result_print); + if (result_print->len) + printf("%*s\n", (int)result_print->len, result_print->str); + + g_string_free(result_print, TRUE); + } else { + c->function(uzbl.gui.web_view, a, result); + } + g_strfreev (par); + g_array_free (a, TRUE); + + } else + g_printerr ("command \"%s\" not understood. ignoring.\n", cmd); +} + +void +set_proxy_url() { + SoupURI *suri; + + if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') { + soup_session_remove_feature_by_type(uzbl.net.soup_session, + (GType) SOUP_SESSION_PROXY_URI); + } + else { + suri = soup_uri_new(uzbl.net.proxy_url); + g_object_set(G_OBJECT(uzbl.net.soup_session), + SOUP_SESSION_PROXY_URI, + suri, NULL); + soup_uri_free(suri); + } + return; +} + +void +set_icon() { + if(file_exists(uzbl.gui.icon)) { + if (uzbl.gui.main_window) + gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL); + } else { + g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon); + } +} + +void +cmd_load_uri() { + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + g_array_append_val (a, uzbl.state.uri); + load_uri(uzbl.gui.web_view, a, NULL); + g_array_free (a, TRUE); +} + +void +cmd_always_insert_mode() { + set_insert_mode(uzbl.behave.always_insert_mode); + update_title(); +} + +void +cmd_max_conns() { + g_object_set(G_OBJECT(uzbl.net.soup_session), + SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL); +} + +void +cmd_max_conns_host() { + g_object_set(G_OBJECT(uzbl.net.soup_session), + SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL); +} + +void +cmd_http_debug() { + soup_session_remove_feature + (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); + /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */ + /*g_free(uzbl.net.soup_logger);*/ + + uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1); + soup_session_add_feature(uzbl.net.soup_session, + SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); +} + +WebKitWebSettings* +view_settings() { + return webkit_web_view_get_settings(uzbl.gui.web_view); +} + +void +cmd_font_size() { + WebKitWebSettings *ws = view_settings(); + if (uzbl.behave.font_size > 0) { + g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL); + } + + if (uzbl.behave.monospace_size > 0) { + g_object_set (G_OBJECT(ws), "default-monospace-font-size", + uzbl.behave.monospace_size, NULL); + } else { + g_object_set (G_OBJECT(ws), "default-monospace-font-size", + uzbl.behave.font_size, NULL); + } +} + +void +cmd_default_font_family() { + g_object_set (G_OBJECT(view_settings()), "default-font-family", + uzbl.behave.default_font_family, NULL); +} + +void +cmd_monospace_font_family() { + g_object_set (G_OBJECT(view_settings()), "monospace-font-family", + uzbl.behave.monospace_font_family, NULL); +} + +void +cmd_sans_serif_font_family() { + g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family", + uzbl.behave.sans_serif_font_family, NULL); +} + +void +cmd_serif_font_family() { + g_object_set (G_OBJECT(view_settings()), "serif-font-family", + uzbl.behave.serif_font_family, NULL); +} + +void +cmd_cursive_font_family() { + g_object_set (G_OBJECT(view_settings()), "cursive-font-family", + uzbl.behave.cursive_font_family, NULL); +} + +void +cmd_fantasy_font_family() { + g_object_set (G_OBJECT(view_settings()), "fantasy-font-family", + uzbl.behave.fantasy_font_family, NULL); +} + +void +cmd_zoom_level() { + webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level); +} + +void +cmd_disable_plugins() { + g_object_set (G_OBJECT(view_settings()), "enable-plugins", + !uzbl.behave.disable_plugins, NULL); +} + +void +cmd_disable_scripts() { + g_object_set (G_OBJECT(view_settings()), "enable-scripts", + !uzbl.behave.disable_scripts, NULL); +} + +void +cmd_minimum_font_size() { + g_object_set (G_OBJECT(view_settings()), "minimum-font-size", + uzbl.behave.minimum_font_size, NULL); +} +void +cmd_autoload_img() { + g_object_set (G_OBJECT(view_settings()), "auto-load-images", + uzbl.behave.autoload_img, NULL); +} + + +void +cmd_autoshrink_img() { + g_object_set (G_OBJECT(view_settings()), "auto-shrink-images", + uzbl.behave.autoshrink_img, NULL); +} + + +void +cmd_enable_spellcheck() { + g_object_set (G_OBJECT(view_settings()), "enable-spell-checking", + uzbl.behave.enable_spellcheck, NULL); +} + +void +cmd_enable_private() { + g_object_set (G_OBJECT(view_settings()), "enable-private-browsing", + uzbl.behave.enable_private, NULL); +} + +void +cmd_print_bg() { + g_object_set (G_OBJECT(view_settings()), "print-backgrounds", + uzbl.behave.print_bg, NULL); +} + +void +cmd_style_uri() { + g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri", + uzbl.behave.style_uri, NULL); +} + +void +cmd_resizable_txt() { + g_object_set (G_OBJECT(view_settings()), "resizable-text-areas", + uzbl.behave.resizable_txt, NULL); +} + +void +cmd_default_encoding() { + g_object_set (G_OBJECT(view_settings()), "default-encoding", + uzbl.behave.default_encoding, NULL); +} + +void +cmd_enforce_96dpi() { + g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi", + uzbl.behave.enforce_96dpi, NULL); +} + +void +cmd_caret_browsing() { + g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing", + uzbl.behave.caret_browsing, NULL); +} + +void +cmd_cookie_handler() { + gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.cookie_handler); + uzbl.behave.cookie_handler = + g_strdup_printf("sync_%s %s", split[0], split[1]); + } + g_strfreev (split); +} + +void +cmd_scheme_handler() { + gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2); + /* pitfall: doesn't handle chain actions; must the sync_ action manually */ + if ((g_strcmp0(split[0], "sh") == 0) || + (g_strcmp0(split[0], "spawn") == 0)) { + g_free (uzbl.behave.scheme_handler); + uzbl.behave.scheme_handler = + g_strdup_printf("sync_%s %s", split[0], split[1]); + } + g_strfreev (split); +} + +void +cmd_fifo_dir() { + uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); +} + +void +cmd_socket_dir() { + uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir); +} + +void +cmd_inject_html() { + if(uzbl.behave.inject_html) { + webkit_web_view_load_html_string (uzbl.gui.web_view, + uzbl.behave.inject_html, NULL); + } +} + +void +cmd_modkey() { + int i; + char *buf; + + buf = g_utf8_strup(uzbl.behave.modkey, -1); + uzbl.behave.modmask = 0; + + if(uzbl.behave.modkey) + g_free(uzbl.behave.modkey); + uzbl.behave.modkey = buf; + + for (i = 0; modkeys[i].key != NULL; i++) { + if (g_strrstr(buf, modkeys[i].key)) + uzbl.behave.modmask |= modkeys[i].mask; + } +} + +void +cmd_useragent() { + if (*uzbl.net.useragent == ' ') { + g_free (uzbl.net.useragent); + uzbl.net.useragent = NULL; + } else { + g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, + uzbl.net.useragent, NULL); + } +} + +void +move_statusbar() { + if (!uzbl.gui.scrolled_win && + !uzbl.gui.mainbar) + return; + + gtk_widget_ref(uzbl.gui.scrolled_win); + gtk_widget_ref(uzbl.gui.mainbar); + gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win); + gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar); + + if(uzbl.behave.status_top) { + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + } + else { + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + } + gtk_widget_unref(uzbl.gui.scrolled_win); + gtk_widget_unref(uzbl.gui.mainbar); + gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); + return; +} + +gboolean +set_var_value(const gchar *name, gchar *val) { + uzbl_cmdprop *c = NULL; + char *endp = NULL; + char *buf = NULL; + char *invalid_chars = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½"; + GString *msg; + + if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { + if(!c->writeable) return FALSE; + + /* 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); + } else if(c->type == TYPE_INT) { + buf = expand(val, 0); + *c->ptr.i = (int)strtoul(buf, &endp, 10); + g_free(buf); + } else if (c->type == TYPE_FLOAT) { + buf = expand(val, 0); + *c->ptr.f = strtod(buf, &endp); + g_free(buf); + } + + /* invoke a command specific function */ + if(c->func) c->func(); + } else { + /* check wether name violates our naming scheme */ + if(strpbrk(name, invalid_chars)) { + if (uzbl.state.verbose) + printf("Invalid variable name\n"); + return FALSE; + } + + /* custom vars */ + c = malloc(sizeof(uzbl_cmdprop)); + c->type = TYPE_STR; + c->dump = 0; + c->func = NULL; + c->writeable = 1; + buf = expand(val, 0); + c->ptr.s = malloc(sizeof(char *)); + *c->ptr.s = buf; + g_hash_table_insert(uzbl.comm.proto_var, + g_strdup(name), (gpointer) c); + } + return TRUE; +} + +enum {M_CMD, M_HTML}; +void +parse_cmd_line(const char *ctl_line, GString *result) { + size_t len=0; + + if((ctl_line[0] == '#') /* Comments */ + || (ctl_line[0] == ' ') + || (ctl_line[0] == '\n')) + ; /* ignore these lines */ + else { /* parse a command */ + gchar *ctlstrip; + gchar **tokens = NULL; + len = strlen(ctl_line); + + if (ctl_line[len - 1] == '\n') /* strip trailing newline */ + ctlstrip = g_strndup(ctl_line, len - 1); + else ctlstrip = g_strdup(ctl_line); + + tokens = g_strsplit(ctlstrip, " ", 2); + parse_command(tokens[0], tokens[1], result); + g_free(ctlstrip); + g_strfreev(tokens); + } +} + +/*@null@*/ gchar* +build_stream_name(int type, const gchar* dir) { + State *s = &uzbl.state; + gchar *str = NULL; + + if (type == FIFO) { + str = g_strdup_printf + ("%s/uzbl_fifo_%s", dir, s->instance_name); + } else if (type == SOCKET) { + str = g_strdup_printf + ("%s/uzbl_socket_%s", dir, s->instance_name); + } + return str; +} + +gboolean +control_fifo(GIOChannel *gio, GIOCondition condition) { + if (uzbl.state.verbose) + printf("triggered\n"); + gchar *ctl_line; + GIOStatus ret; + GError *err = NULL; + + if (condition & G_IO_HUP) + g_error ("Fifo: Read end of pipe died!\n"); + + if(!gio) + g_error ("Fifo: GIOChannel broke\n"); + + ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err); + if (ret == G_IO_STATUS_ERROR) { + g_error ("Fifo: Error reading: %s\n", err->message); + g_error_free (err); + } + + parse_cmd_line(ctl_line, NULL); + g_free(ctl_line); + + return TRUE; +} + +/*@null@*/ gchar* +init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ + if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */ + if (unlink(uzbl.comm.fifo_path) == -1) + g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path); + g_free(uzbl.comm.fifo_path); + uzbl.comm.fifo_path = NULL; + } + + GIOChannel *chan = NULL; + GError *error = NULL; + gchar *path = build_stream_name(FIFO, dir); + + if (!file_exists(path)) { + if (mkfifo (path, 0666) == 0) { + // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file. + chan = g_io_channel_new_file(path, "r+", &error); + if (chan) { + if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { + if (uzbl.state.verbose) + printf ("init_fifo: created successfully as %s\n", path); + send_event(FIFO_SET, path); + uzbl.comm.fifo_path = path; + return dir; + } else g_warning ("init_fifo: could not add watch on %s\n", path); + } else g_warning ("init_fifo: can't open: %s\n", error->message); + } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno)); + } else g_warning ("init_fifo: can't create %s: file exists\n", path); + + /* if we got this far, there was an error; cleanup */ + if (error) g_error_free (error); + g_free(dir); + g_free(path); + return NULL; +} + +gboolean +control_stdin(GIOChannel *gio, GIOCondition condition) { + (void) condition; + gchar *ctl_line = NULL; + GIOStatus ret; + + ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL); + if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) + return FALSE; + + parse_cmd_line(ctl_line, NULL); + g_free(ctl_line); + + return TRUE; +} + +void +create_stdin () { + GIOChannel *chan = NULL; + GError *error = NULL; + + chan = g_io_channel_unix_new(fileno(stdin)); + if (chan) { + if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) { + g_error ("Stdin: could not add watch\n"); + } else { + if (uzbl.state.verbose) + printf ("Stdin: watch added successfully\n"); + } + } else { + g_error ("Stdin: Error while opening: %s\n", error->message); + } + if (error) g_error_free (error); +} + +gboolean +control_socket(GIOChannel *chan) { + struct sockaddr_un remote; + unsigned int t = sizeof(remote); + int clientsock; + GIOChannel *clientchan; + + clientsock = accept (g_io_channel_unix_get_fd(chan), + (struct sockaddr *) &remote, &t); + + if ((clientchan = g_io_channel_unix_new(clientsock))) { + g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP, + (GIOFunc) control_client_socket, clientchan); + } + + return TRUE; +} + +gboolean +control_client_socket(GIOChannel *clientchan) { + char *ctl_line; + GString *result = g_string_new(""); + GError *error = NULL; + GIOStatus ret; + gsize len; + + ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error reading: %s\n", error->message); + g_io_channel_shutdown(clientchan, TRUE, &error); + return FALSE; + } else if (ret == G_IO_STATUS_EOF) { + /* shutdown and remove channel watch from main loop */ + g_io_channel_shutdown(clientchan, TRUE, &error); + return FALSE; + } + + if (ctl_line) { + parse_cmd_line (ctl_line, result); + g_string_append_c(result, '\n'); + ret = g_io_channel_write_chars (clientchan, result->str, result->len, + &len, &error); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error writing: %s", error->message); + } + g_io_channel_flush(clientchan, &error); + } + + if (error) g_error_free (error); + g_string_free(result, TRUE); + g_free(ctl_line); + return TRUE; +} + +/*@null@*/ gchar* +init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */ + if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */ + if (unlink(uzbl.comm.socket_path) == -1) + g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path); + g_free(uzbl.comm.socket_path); + uzbl.comm.socket_path = NULL; + } + + if (*dir == ' ') { + g_free(dir); + return NULL; + } + + GIOChannel *chan = NULL; + int sock, len; + struct sockaddr_un local; + gchar *path = build_stream_name(SOCKET, dir); + + sock = socket (AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strcpy (local.sun_path, path); + unlink (local.sun_path); + + len = strlen (local.sun_path) + sizeof (local.sun_family); + if (bind (sock, (struct sockaddr *) &local, len) != -1) { + if (uzbl.state.verbose) + printf ("init_socket: opened in %s\n", path); + listen (sock, 5); + + 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; + return dir; + } + } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno)); + + /* if we got this far, there was an error; cleanup */ + g_free(path); + g_free(dir); + return NULL; +} + +/* + NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state + it will probably improve performance if we would "cache" the processed variant, but for now it works well enough... +*/ +// this function may be called very early when the templates are not set (yet), hence the checks +void +update_title (void) { + Behaviour *b = &uzbl.behave; + gchar *parsed; + + if (b->show_status) { + if (b->title_format_short) { + parsed = expand(b->title_format_short, 0); + if (uzbl.gui.main_window) + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); + g_free(parsed); + } + if (b->status_format) { + parsed = expand(b->status_format, 0); + gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed); + g_free(parsed); + } + if (b->status_background) { + GdkColor color; + gdk_color_parse (b->status_background, &color); + //labels and hboxes do not draw their own background. applying this on the vbox/main_window is ok as the statusbar is the only affected widget. (if not, we could also use GtkEventBox) + if (uzbl.gui.main_window) + gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color); + else if (uzbl.gui.plug) + gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color); + } + } else { + if (b->title_format_long) { + parsed = expand(b->title_format_long, 0); + if (uzbl.gui.main_window) + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); + g_free(parsed); + } + } +} + +gboolean +configure_event_cb(GtkWidget* window, GdkEventConfigure* event) { + (void) window; + (void) event; + + retrieve_geometry(); + send_event(GEOMETRY_CHANGED, uzbl.gui.geometry); + return FALSE; +} + +gboolean +key_press_cb (GtkWidget* window, GdkEventKey* event) +{ + //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. + + (void) window; + + if(event->type == GDK_KEY_PRESS) + send_event(KEY_PRESS, gdk_keyval_name(event->keyval) ); + + if (event->type != GDK_KEY_PRESS || + event->keyval == GDK_Page_Up || + event->keyval == GDK_Page_Down || + event->keyval == GDK_Home || + event->keyval == GDK_End || + event->keyval == GDK_Up || + event->keyval == GDK_Down || + event->keyval == GDK_Left || + event->keyval == GDK_Right || + event->keyval == GDK_Shift_L || + event->keyval == GDK_Shift_R) + return FALSE; + + if (uzbl.behave.insert_mode && + ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || + (!uzbl.behave.modmask) + ) + ) + return FALSE; + + return TRUE; +} + +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; + + if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) { + clear_keycmd(); + parse_command(act->name, act->param, NULL); + + tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); + send_event(COMMAND_EXECUTED, tmp); + g_free(tmp); + return; + } + + /* try if it's an incremental keycmd or one that takes args, and run it */ + GString* short_keys = g_string_new (""); + GString* short_keys_inc = g_string_new (""); + guint i; + guint len = strlen(uzbl.state.keycmd); + for (i=0; istr); + g_string_append_c(short_keys, '_'); + g_string_append_c(short_keys_inc, '*'); + + if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) { + /* run normal cmds only if return was pressed */ + exec_paramcmd(act, i); + clear_keycmd(); + tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); + send_event(COMMAND_EXECUTED, tmp); + g_free(tmp); + break; + } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) { + if (key_ret) /* just quit the incremental command on return */ + clear_keycmd(); + else { + exec_paramcmd(act, i); /* otherwise execute the incremental */ + tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); + send_event(COMMAND_EXECUTED, tmp); + g_free(tmp); + } + break; + } + + g_string_truncate(short_keys, short_keys->len - 1); + } + g_string_free (short_keys, TRUE); + g_string_free (short_keys_inc, TRUE); +} + +void +exec_paramcmd(const Action *act, const guint i) { + GString *parampart = g_string_new (uzbl.state.keycmd); + GString *actionname = g_string_new (""); + GString *actionparam = g_string_new (""); + g_string_erase (parampart, 0, i+1); + if (act->name) + g_string_printf (actionname, act->name, parampart->str); + if (act->param) + g_string_printf (actionparam, act->param, parampart->str); + parse_command(actionname->str, actionparam->str, NULL); + g_string_free(actionname, TRUE); + g_string_free(actionparam, TRUE); + g_string_free(parampart, TRUE); +} + + +void +create_browser () { + GUI *g = &uzbl.gui; + + g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); + + g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL); + g_signal_connect (G_OBJECT (g->web_view), "selection-changed", G_CALLBACK (selection_changed_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-error", G_CALLBACK (load_error_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view); +} + +GtkWidget* +create_mainbar () { + GUI *g = &uzbl.gui; + + g->mainbar = gtk_hbox_new (FALSE, 0); + + /* keep a reference to the bar so we can re-pack it at runtime*/ + //sbar_ref = g_object_ref(g->mainbar); + + g->mainbar_label = gtk_label_new (""); + gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE); + gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0); + gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2); + gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0); + g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL); + return g->mainbar; +} + +GtkWidget* +create_window () { + GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); + gtk_widget_set_name (window, "Uzbl browser"); + g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL); + g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL); + g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL); + + return window; +} + +GtkPlug* +create_plug () { + GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id)); + g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL); + g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL); + + return plug; +} + + +gchar** +inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) { + /* + If actname is one that calls an external command, this function will inject + newargs in front of the user-provided args in that command line. They will + come become after the body of the script (in sh) or after the name of + the command to execute (in spawn). + i.e. sh becomes sh and + spawn becomes spawn . + + The return value consist of two strings: the action (sh, ...) and its args. + + If act is not one that calls an external command, then the given action merely + gets duplicated. + */ + GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*)); + /* Arrr! Here be memory leaks */ + gchar *actdup = g_strdup(actname); + g_array_append_val(rets, actdup); + + if ((g_strcmp0(actname, "spawn") == 0) || + (g_strcmp0(actname, "sh") == 0) || + (g_strcmp0(actname, "sync_spawn") == 0) || + (g_strcmp0(actname, "sync_sh") == 0) || + (g_strcmp0(actname, "talk_to_socket") == 0)) { + guint i; + GString *a = g_string_new(""); + gchar **spawnparts = split_quoted(origargs, FALSE); + g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */ + if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */ + + for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ + if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]); + + g_array_append_val(rets, a->str); + g_string_free(a, FALSE); + g_strfreev(spawnparts); + } else { + gchar *origdup = g_strdup(origargs); + g_array_append_val(rets, origdup); + } + return (gchar**)g_array_free(rets, FALSE); +} + +void +run_handler (const gchar *act, const gchar *args) { + /* Consider this code a temporary hack to make the handlers usable. + In practice, all this splicing, injection, and reconstruction is + inefficient, annoying and hard to manage. Potential pitfalls arise + when the handler specific args 1) are not quoted (the handler + callbacks should take care of this) 2) are quoted but interfere + with the users' own quotation. A more ideal solution is + to refactor parse_command so that it doesn't just take a string + and execute it; rather than that, we should have a function which + returns the argument vector parsed from the string. This vector + could be modified (e.g. insert additional args into it) before + passing it to the next function that actually executes it. Though + it still isn't perfect for chain actions.. will reconsider & re- + factor when I have the time. -duc */ + + char **parts = g_strsplit(act, " ", 2); + if (!parts) return; + if (g_strcmp0(parts[0], "chain") == 0) { + GString *newargs = g_string_new(""); + gchar **chainparts = split_quoted(parts[1], FALSE); + + /* for every argument in the chain, inject the handler args + and make sure the new parts are wrapped in quotes */ + gchar **cp = chainparts; + gchar quot = '\''; + gchar *quotless = NULL; + gchar **spliced_quotless = NULL; // sigh -_-; + gchar **inpart = NULL; + + while (*cp) { + if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */ + quot = **cp; + quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2); + } else quotless = g_strdup(*cp); + + spliced_quotless = g_strsplit(quotless, " ", 2); + inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args); + g_strfreev(spliced_quotless); + + g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot); + g_free(quotless); + g_strfreev(inpart); + cp++; + } + + parse_command(parts[0], &(newargs->str[1]), NULL); + g_string_free(newargs, TRUE); + g_strfreev(chainparts); + + } else { + gchar **inparts = inject_handler_args(parts[0], parts[1], args); + parse_command(inparts[0], inparts[1], NULL); + g_free(inparts[0]); + g_free(inparts[1]); + } + g_strfreev(parts); +} + +void +add_binding (const gchar *key, const gchar *act) { + char **parts = g_strsplit(act, " ", 2); + Action *action; + + if (!parts) + return; + + //Debug: + if (uzbl.state.verbose) + printf ("Binding %-10s : %s\n", key, act); + action = new_action(parts[0], parts[1]); + + if (g_hash_table_remove (uzbl.bindings, key)) + g_warning ("Overwriting existing binding for \"%s\"", key); + g_hash_table_replace(uzbl.bindings, g_strdup(key), action); + g_strfreev(parts); +} + +/*@null@*/ gchar* +get_xdg_var (XDG_Var xdg) { + const gchar* actual_value = getenv (xdg.environmental); + const gchar* home = getenv ("HOME"); + gchar* return_value; + + if (! actual_value || strcmp (actual_value, "") == 0) { + if (xdg.default_value) { + return_value = str_replace ("~", home, xdg.default_value); + } else { + return_value = NULL; + } + } else { + return_value = str_replace("~", home, actual_value); + } + + return return_value; +} + +/*@null@*/ gchar* +find_xdg_file (int xdg_type, const char* filename) { + /* xdg_type = 0 => config + xdg_type = 1 => data + xdg_type = 2 => cache*/ + + gchar* xdgv = get_xdg_var (XDG[xdg_type]); + gchar* temporary_file = g_strconcat (xdgv, filename, NULL); + g_free (xdgv); + + gchar* temporary_string; + char* saveptr; + char* buf; + + if (! file_exists (temporary_file) && xdg_type != 2) { + buf = get_xdg_var (XDG[3 + xdg_type]); + temporary_string = (char *) strtok_r (buf, ":", &saveptr); + g_free(buf); + + while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) { + g_free (temporary_file); + temporary_file = g_strconcat (temporary_string, filename, NULL); + } + } + + //g_free (temporary_string); - segfaults. + + if (file_exists (temporary_file)) { + return temporary_file; + } else { + g_free(temporary_file); + return NULL; + } +} +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); + } + + if (g_strcmp0(s->config_file, "-") == 0) { + s->config_file = NULL; + create_stdin(); + } + + else if (!s->config_file) { + s->config_file = find_xdg_file (0, "/uzbl/config"); + } + + if (s->config_file) { + GArray* lines = read_file_by_line (s->config_file); + int i = 0; + gchar* line; + + while ((line = g_array_index(lines, gchar*, i))) { + parse_cmd_line (line, NULL); + i ++; + g_free (line); + } + g_array_free (lines, TRUE); + } else { + if (uzbl.state.verbose) + printf ("No configuration file loaded.\n"); + } + + g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL); +} + +void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ + (void) session; + (void) user_data; + //if (!uzbl.behave.cookie_handler) + // return; + + soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); + GString *s = g_string_new (""); + SoupURI * soup_uri = soup_message_get_uri(msg); + 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) { + char *p = strchr(uzbl.comm.sync_stdout, '\n' ); + if ( p != NULL ) *p = '\0'; + soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout); + + } + if (uzbl.comm.sync_stdout) + uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + + g_string_free(s, TRUE); +} + +void +save_cookies (SoupMessage *msg, gpointer user_data){ + (void) user_data; + GSList *ck; + char *cookie; + for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ + cookie = soup_cookie_to_set_cookie_header(ck->data); + SoupURI * soup_uri = soup_message_get_uri(msg); + 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); + } + g_slist_free(ck); +} + +/* --- WEBINSPECTOR --- */ +void +hide_window_cb(GtkWidget *widget, gpointer data) { + (void) data; + + gtk_widget_hide(widget); +} + +WebKitWebView* +create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){ + (void) data; + (void) page; + (void) web_inspector; + GtkWidget* scrolled_window; + GtkWidget* new_web_view; + GUI *g = &uzbl.gui; + + g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(G_OBJECT(g->inspector_window), "delete-event", + G_CALLBACK(hide_window_cb), NULL); + + gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector"); + gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300); + gtk_widget_show(g->inspector_window); + + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window); + gtk_widget_show(scrolled_window); + + new_web_view = webkit_web_view_new(); + gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view); + + return WEBKIT_WEB_VIEW(new_web_view); +} + +gboolean +inspector_show_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + gtk_widget_show(uzbl.gui.inspector_window); + + send_event(WEBINSPECTOR, "open"); + return TRUE; +} + +/* TODO: Add variables and code to make use of these functions */ +gboolean +inspector_close_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + send_event(WEBINSPECTOR, "close"); + return TRUE; +} + +gboolean +inspector_attach_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +gboolean +inspector_detach_window_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +gboolean +inspector_uri_changed_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +gboolean +inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){ + (void) inspector; + return FALSE; +} + +void +set_up_inspector() { + GUI *g = &uzbl.gui; + WebKitWebSettings *settings = view_settings(); + g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL); + + uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view); + g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL); + g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL); + + g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL); +} + +void +dump_var_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + uzbl_cmdprop *c = v; + + if(!c->dump) + return; + + if(c->type == TYPE_STR) + printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " "); + else if(c->type == TYPE_INT) + printf("set %s = %d\n", (char *)k, *c->ptr.i); + else if(c->type == TYPE_FLOAT) + printf("set %s = %f\n", (char *)k, *c->ptr.f); +} + +void +dump_key_hash(gpointer k, gpointer v, gpointer ud) { + (void) ud; + Action *a = v; + + printf("bind %s = %s %s\n", (char *)k , + (char *)a->name, a->param?(char *)a->param:""); +} + +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); +} + +void +retrieve_geometry() { + int w, h, x, y; + GString *buf = g_string_new(""); + + gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h); + gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y); + + g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y); + + if(uzbl.gui.geometry) + g_free(uzbl.gui.geometry); + uzbl.gui.geometry = g_string_free(buf, FALSE); +} + +/* set up gtk, gobject, variable defaults and other things that tests and other + * external applications need to do anyhow */ +void +initialize(int argc, char *argv[]) { + if (!g_thread_supported ()) + g_thread_init (NULL); + uzbl.state.executable_path = g_strdup(argv[0]); + uzbl.state.selected_url = NULL; + uzbl.state.searchtx = NULL; + + GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_free(context); + + if (uzbl.behave.print_version) { + printf("Commit: %s\n", COMMIT); + exit(EXIT_SUCCESS); + } + + /* initialize hash table */ + uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); + + uzbl.net.soup_session = webkit_get_default_session(); + uzbl.state.keycmd = g_strdup(""); + + if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR) + fprintf(stderr, "uzbl: error hooking SIGTERM\n"); + if(setup_signal(SIGINT, catch_sigint) == SIG_ERR) + fprintf(stderr, "uzbl: error hooking SIGINT\n"); + + uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h + uzbl.gui.sbar.progress_u = g_strdup("·"); + uzbl.gui.sbar.progress_w = 10; + + /* default mode indicators */ + uzbl.behave.insert_indicator = g_strdup("I"); + uzbl.behave.cmd_indicator = g_strdup("C"); + + uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION; + uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION; + uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION; + uzbl.info.arch = ARCH; + uzbl.info.commit = COMMIT; + + commands_hash (); + create_var_to_name_hash(); + + create_browser(); +} + +#ifndef UZBL_LIBRARY +/** -- MAIN -- **/ +int +main (int argc, char* argv[]) { + initialize(argc, argv); + + gtk_init (&argc, &argv); + + uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL); + //main_window_ref = g_object_ref(scrolled_window); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win), + GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does + + gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win), + GTK_WIDGET (uzbl.gui.web_view)); + + uzbl.gui.vbox = gtk_vbox_new (FALSE, 0); + + create_mainbar(); + + /* initial packing */ + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); + + if (uzbl.state.socket_id) { + uzbl.gui.plug = create_plug (); + gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox); + gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug)); + } else { + uzbl.gui.main_window = create_window (); + gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); + gtk_widget_show_all (uzbl.gui.main_window); + uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window); + } + + if(!uzbl.state.instance_name) + uzbl.state.instance_name = itos((int)uzbl.xwin); + + gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); + + if (uzbl.state.verbose) { + printf("Uzbl start location: %s\n", argv[0]); + if (uzbl.state.socket_id) + printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug)); + else + printf("window_id %i\n",(int) uzbl.xwin); + printf("pid %i\n", getpid ()); + printf("name: %s\n", uzbl.state.instance_name); + printf("commit: %s\n", uzbl.info.commit); + } + + uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); + uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v); + uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); + uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h); + gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v); + + /* Check uzbl is in window mode before getting/setting geometry */ + if (uzbl.gui.main_window) { + if(uzbl.gui.geometry) + cmd_set_geometry(); + else + retrieve_geometry(); + } + + gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL); + if (argc > 1 && !uzbl.state.uri) + uri_override = g_strdup(argv[1]); + gboolean verbose_override = uzbl.state.verbose; + + settings_init (); + + if (!uzbl.behave.always_insert_mode) + set_insert_mode(FALSE); + + if (!uzbl.behave.show_status) + gtk_widget_hide(uzbl.gui.mainbar); + else + update_title(); + + /* WebInspector */ + set_up_inspector(); + + if (verbose_override > uzbl.state.verbose) + uzbl.state.verbose = verbose_override; + + if (uri_override) { + set_var_value("uri", uri_override); + g_free(uri_override); + } else if (uzbl.state.uri) + cmd_load_uri(); + + gtk_main (); + clean_up(); + + return EXIT_SUCCESS; +} +#endif + +/* vi: set et ts=4: */ diff --git a/uzbl-core.h b/uzbl-core.h new file mode 100644 index 0000000..010cbe5 --- /dev/null +++ b/uzbl-core.h @@ -0,0 +1,607 @@ +/* -*- c-basic-offset: 4; -*- + + * See LICENSE for license details + * + * Changelog: + * --------- + * + * (c) 2009 by Robert Manea + * - introduced struct concept + * - statusbar template + * + */ + +/* status bar elements */ +typedef struct { + gint load_progress; + gchar *msg; + gchar *progress_s, *progress_u; + int progress_w; + gchar *progress_bar; + gchar *mode_indicator; +} StatusBar; + + +/* gui elements */ +typedef struct { + GtkWidget* main_window; + gchar* geometry; + GtkPlug* plug; + GtkWidget* scrolled_win; + GtkWidget* vbox; + GtkWidget* mainbar; + GtkWidget* mainbar_label; + GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar + GtkScrollbar* scbar_h; // (These are still hidden) + GtkAdjustment* bar_v; // Information about document length + GtkAdjustment* bar_h; // and scrolling position + WebKitWebView* web_view; + gchar* main_title; + gchar* icon; + + /* WebInspector */ + GtkWidget *inspector_window; + WebKitWebInspector *inspector; + + StatusBar sbar; +} GUI; + + +/* external communication*/ +enum { FIFO, SOCKET}; +typedef struct { + gchar *fifo_path; + gchar *socket_path; + /* stores (key)"variable name" -> (value)"pointer to this var*/ + GHashTable *proto_var; + + gchar *sync_stdout; +} Communication; + + +/* internal state */ +typedef struct { + gchar *uri; + gchar *config_file; + int socket_id; + char *instance_name; + gchar *selected_url; + gchar *executable_path; + gchar* keycmd; + gchar* searchtx; + gboolean verbose; +} State; + + +/* networking */ +typedef struct { + SoupSession *soup_session; + SoupLogger *soup_logger; + char *proxy_url; + char *useragent; + gint max_conns; + gint max_conns_host; +} Network; + + +/* behaviour */ +typedef struct { + gchar* load_finish_handler; + gchar* load_start_handler; + gchar* load_commit_handler; + gchar* status_format; + gchar* title_format_short; + gchar* title_format_long; + gchar* status_background; + gchar* fifo_dir; + gchar* socket_dir; + gchar* download_handler; + gchar* cookie_handler; + gchar* new_window; + gchar* default_font_family; + gchar* monospace_font_family; + gchar* sans_serif_font_family; + gchar* serif_font_family; + gchar* fantasy_font_family; + gchar* cursive_font_family; + gchar* scheme_handler; + gboolean always_insert_mode; + gboolean show_status; + gboolean insert_mode; + gboolean status_top; + gboolean reset_command_mode; + gchar* modkey; + guint modmask; + guint http_debug; + gchar* shell_cmd; + /* WebKitWebSettings exports */ + guint font_size; + guint monospace_size; + guint minimum_font_size; + gfloat zoom_level; + guint disable_plugins; + guint disable_scripts; + guint autoload_img; + guint autoshrink_img; + guint enable_spellcheck; + guint enable_private; + guint print_bg; + gchar* style_uri; + guint resizable_txt; + gchar* default_encoding; + guint enforce_96dpi; + gchar *inject_html; + guint caret_browsing; + guint mode; + gchar* base_url; + gchar* insert_indicator; + gchar* cmd_indicator; + gboolean print_version; + + /* command list: (key)name -> (value)Command */ + GHashTable* commands; + /* event lookup: (key)event_id -> (value)event_name */ + GHashTable *event_lookup; +} Behaviour; + +/* javascript */ +typedef struct { + gboolean initialized; + JSClassDefinition classdef; + JSClassRef classref; +} Javascript; + +/* static information */ +typedef struct { + int webkit_major; + int webkit_minor; + int webkit_micro; + gchar *arch; + gchar *commit; +} Info; + +/* main uzbl data structure */ +typedef struct { + GUI gui; + State state; + Network net; + Behaviour behave; + Communication comm; + Javascript js; + Info info; + + Window xwin; + + /* group bindings: key -> action */ + GHashTable* bindings; +} UzblCore; + + +typedef struct { + char* name; + char* param; +} Action; + +typedef void sigfunc(int); + +/* Event system */ +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, + + /* must be last entry */ + LAST_EVENT +}; + +/* XDG Stuff */ +typedef struct { + gchar* environmental; + gchar* default_value; +} XDG_Var; + +XDG_Var XDG[] = +{ + { "XDG_CONFIG_HOME", "~/.config" }, + { "XDG_DATA_HOME", "~/.local/share" }, + { "XDG_CACHE_HOME", "~/.cache" }, + { "XDG_CONFIG_DIRS", "/etc/xdg" }, + { "XDG_DATA_DIRS", "/usr/local/share/:/usr/share/" }, +}; + +/* Functions */ +char * +itos(int val); + +char * +str_replace (const char* search, const char* replace, const char* string); + +GArray* +read_file_by_line (const gchar *path); + +gchar* +parseenv (char* string); + +void +clean_up(void); + +void +catch_sigterm(int s); + +sigfunc * +setup_signal(int signe, sigfunc *shandler); + +gboolean +set_var_value(const gchar *name, gchar *val); + +void +print(WebKitWebView *page, GArray *argv, GString *result); + +gboolean +navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); + +gboolean +new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); + +gboolean +mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data); + +/*@null@*/ WebKitWebView* +create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data); + +gboolean +download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data); + +void +toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result); + +void +toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result); + +void +link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data); + +void +title_change_cb (WebKitWebView* web_view, GParamSpec param_spec); + +void +progress_change_cb (WebKitWebView* page, gint progress, gpointer data); + +void +load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); + +void +load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); + +void +load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); + +void +selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud); + +void +destroy_cb (GtkWidget* widget, gpointer data); + +void +commands_hash(void); + +void +free_action(gpointer act); + +Action* +new_action(const gchar *name, const gchar *param); + +bool +file_exists (const char * filename); + +void +set_keycmd(); + +void +set_mode_indicator(); + +void +update_indicator(); + +void +set_insert_mode(gboolean mode); + +void +toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result); + +void +load_uri (WebKitWebView * web_view, GArray *argv, GString *result); + +void +new_window_load_uri (const gchar * uri); + +void +chain (WebKitWebView *page, GArray *argv, GString *result); + +void +keycmd (WebKitWebView *page, GArray *argv, GString *result); + +void +keycmd_nl (WebKitWebView *page, GArray *argv, GString *result); + +void +keycmd_bs (WebKitWebView *page, GArray *argv, GString *result); + +void +close_uzbl (WebKitWebView *page, GArray *argv, GString *result); + +gboolean +run_command(const gchar *command, const guint npre, + const gchar **args, const gboolean sync, char **output_stdout); + +char* +build_progressbar_ascii(int percent); + +void +talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result); + +void +spawn(WebKitWebView *web_view, GArray *argv, GString *result); + +void +spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result); + +void +spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result); + +void +spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result); + +void +parse_command(const char *cmd, const char *param, GString *result); + +void +parse_cmd_line(const char *ctl_line, GString *result); + +/*@null@*/ gchar* +build_stream_name(int type, const gchar *dir); + +gboolean +control_fifo(GIOChannel *gio, GIOCondition condition); + +/*@null@*/ gchar* +init_fifo(gchar *dir); + +gboolean +control_stdin(GIOChannel *gio, GIOCondition condition); + +void +create_stdin(); + +/*@null@*/ gchar* +init_socket(gchar *dir); + +gboolean +control_socket(GIOChannel *chan); + +gboolean +control_client_socket(GIOChannel *chan); + +void +update_title (void); + +gboolean +key_press_cb (GtkWidget* window, GdkEventKey* event); + +void +run_keycmd(const gboolean key_ret); + +void +exec_paramcmd(const Action* act, const guint i); + +void +initialize (int argc, char *argv[]); + +void +create_browser (); + +GtkWidget* +create_mainbar (); + +GtkWidget* +create_window (); + +GtkPlug* +create_plug (); + +void +run_handler (const gchar *act, const gchar *args); + +void +add_binding (const gchar *key, const gchar *act); + +/*@null@*/ gchar* +get_xdg_var (XDG_Var xdg); + +/*@null@*/ gchar* +find_xdg_file (int xdg_type, const char* filename); + +void +settings_init (); + +void +search_text (WebKitWebView *page, GArray *argv, const gboolean forward); + +void +search_forward_text (WebKitWebView *page, GArray *argv, GString *result); + +void +search_reverse_text (WebKitWebView *page, GArray *argv, GString *result); + +void +dehilight (WebKitWebView *page, GArray *argv, GString *result); + +void +run_js (WebKitWebView * web_view, GArray *argv, GString *result); + +void +run_external_js (WebKitWebView * web_view, GArray *argv, GString *result); + +void +eval_js(WebKitWebView * web_view, gchar *script, GString *result); + +void handle_cookies (SoupSession *session, + SoupMessage *msg, + gpointer user_data); +void +save_cookies (SoupMessage *msg, + gpointer user_data); + +void +set_var(WebKitWebView *page, GArray *argv, GString *result); + +void +act_bind(WebKitWebView *page, GArray *argv, GString *result); + +void +act_dump_config(); + +void +dump_var_hash(gpointer k, gpointer v, gpointer ud); + +void +dump_key_hash(gpointer k, gpointer v, gpointer ud); + +void +dump_config(); + +void +retrieve_geometry(); + +void +update_gui(WebKitWebView *page, GArray *argv, GString *result); + +gboolean +configure_event_cb(GtkWidget* window, GdkEventConfigure* event); + +typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result); +typedef struct { + Command function; + gboolean no_split; +} CommandInfo; + +/* Command callbacks */ +void +cmd_load_uri(); + +void +cmd_set_status(); + +void +set_proxy_url(); + +void +set_icon(); + +void +cmd_cookie_handler(); + +void +cmd_scheme_handler(); + +void +move_statusbar(); + +void +cmd_always_insert_mode(); + +void +cmd_http_debug(); + +void +cmd_max_conns(); + +void +cmd_max_conns_host(); + +/* exported WebKitWebSettings properties */ + +void +cmd_font_size(); + +void +cmd_default_font_family(); + +void +cmd_monospace_font_family(); + +void +cmd_sans_serif_font_family(); + +void +cmd_serif_font_family(); + +void +cmd_cursive_font_family(); + +void +cmd_fantasy_font_family(); + +void +cmd_zoom_level(); + +void +cmd_disable_plugins(); + +void +cmd_disable_scripts(); + +void +cmd_minimum_font_size(); + +void +cmd_fifo_dir(); + +void +cmd_socket_dir(); + +void +cmd_modkey(); + +void +cmd_useragent() ; + +void +cmd_autoload_img(); + +void +cmd_autoshrink_img(); + +void +cmd_enable_spellcheck(); + +void +cmd_enable_private(); + +void +cmd_print_bg(); + +void +cmd_style_uri(); + +void +cmd_resizable_txt(); + +void +cmd_default_encoding(); + +void +cmd_enforce_96dpi(); + +void +cmd_inject_html(); + +void +cmd_caret_browsing(); + +void +cmd_set_geometry(); + +/* vi: set et ts=4: */ diff --git a/uzbl.c b/uzbl.c deleted file mode 100644 index 5832a12..0000000 --- a/uzbl.c +++ /dev/null @@ -1,3014 +0,0 @@ -/* -*- c-basic-offset: 4; -*- */ -// Original code taken from the example webkit-gtk+ application. see notice below. -// Modified code is licensed under the GPL 3. See LICENSE file. - - -/* - * Copyright (C) 2006, 2007 Apple Inc. - * Copyright (C) 2007 Alp Toker - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#define LENGTH(x) (sizeof x / sizeof x[0]) -#define _POSIX_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "uzbl.h" -#include "config.h" - -Uzbl uzbl; - -/* commandline arguments (set initial values for the state variables) */ -const -GOptionEntry entries[] = -{ - { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, - "Uri to load at startup (equivalent to 'uzbl ' or 'set uri = URI' after uzbl has launched)", "URI" }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, - "Whether to print all messages or just errors.", NULL }, - { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, - "Name of the current instance (defaults to Xorg window id)", "NAME" }, - { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, - "Path to config file or '-' for stdin", "FILE" }, - { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id, - "Socket ID", "SOCKET" }, - { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry, - "Set window geometry (format: WIDTHxHEIGHT+-X+-Y)", "GEOMETRY" }, - { "version", 'V', 0, G_OPTION_ARG_NONE, &uzbl.behave.print_version, - "Print the version and exit", NULL }, - { NULL, 0, 0, 0, NULL, NULL, NULL } -}; - -enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT}; - -/* associate command names to their properties */ -typedef struct { - enum ptr_type type; - union { - int *i; - float *f; - gchar **s; - } ptr; - int dump; - int writeable; - /*@null@*/ void (*func)(void); -} uzbl_cmdprop; - -/* abbreviations to help keep the table's width humane */ -#define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun } -#define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun } -#define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun } -#define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun } -#define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun } -#define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun } - -const struct var_name_to_ptr_t { - const char *name; - uzbl_cmdprop cp; -} var_name_to_ptr[] = { -/* variable name pointer to variable in code dump callback function */ -/* ---------------------------------------------------------------------------------------------- */ - { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)}, - { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)}, - { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)}, - { "geometry", PTR_V_STR(uzbl.gui.geometry, 1, cmd_set_geometry)}, - { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)}, - { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)}, - { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)}, - { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)}, - { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, update_title)}, - { "status_pbar_done", PTR_V_STR(uzbl.gui.sbar.progress_s, 1, update_title)}, - { "status_pbar_pending", PTR_V_STR(uzbl.gui.sbar.progress_u, 1, update_title)}, - { "status_pbar_width", PTR_V_INT(uzbl.gui.sbar.progress_w, 1, update_title)}, - { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, update_title)}, - { "insert_indicator", PTR_V_STR(uzbl.behave.insert_indicator, 1, update_indicator)}, - { "command_indicator", PTR_V_STR(uzbl.behave.cmd_indicator, 1, update_indicator)}, - { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, update_title)}, - { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, update_title)}, - { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)}, - { "insert_mode", PTR_V_INT(uzbl.behave.insert_mode, 1, set_mode_indicator)}, - { "always_insert_mode", PTR_V_INT(uzbl.behave.always_insert_mode, 1, cmd_always_insert_mode)}, - { "reset_command_mode", PTR_V_INT(uzbl.behave.reset_command_mode, 1, NULL)}, - { "modkey", PTR_V_STR(uzbl.behave.modkey, 1, cmd_modkey)}, - { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)}, - { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)}, - { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)}, - { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, - { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)}, - { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)}, - { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, cmd_scheme_handler)}, - { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, - { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)}, - { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)}, - { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)}, - { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)}, - { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)}, - { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)}, - { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)}, - - /* exported WebKitWebSettings properties */ - { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)}, - { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)}, - { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)}, - { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)}, - { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)}, - { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)}, - { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)}, - { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)}, - { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)}, - { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)}, - { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)}, - { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)}, - { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)}, - { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)}, - { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)}, - { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)}, - { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)}, - { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)}, - { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)}, - { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)}, - { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)}, - { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)}, - - /* constants (not dumpable or writeable) */ - { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)}, - { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)}, - { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)}, - { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)}, - { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)}, - { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)}, - { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)}, - { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)}, - { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)}, - { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)}, - { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)}, - - { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}} -}; - -/* Event id to name mapping - * 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" , - "KEY_PRESS" , - "KEY_RELEASE" , - "DOWNLOAD_REQUEST" , - "COMMAND_EXECUTED" , - "LINK_HOVER" , - "TITLE_CHANGED" , - "GEOMETRY_CHANGED" , - "WEBINSPECTOR" , - "COOKIE" , - "NEW_WINDOW" , - "SELECTION_CHANGED", - "VARIABLE_SET", - "FIFO_SET" -}; - - -const struct { - /*@null@*/ char *key; - guint mask; -} modkeys[] = { - { "SHIFT", GDK_SHIFT_MASK }, // shift - { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings - { "CONTROL", GDK_CONTROL_MASK }, // control - { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings - { "MOD2", GDK_MOD2_MASK }, // 5th mod - { "MOD3", GDK_MOD3_MASK }, // 6th mod - { "MOD4", GDK_MOD4_MASK }, // 7th mod - { "MOD5", GDK_MOD5_MASK }, // 8th mod - { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button - { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button - { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button - { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button - { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button - { "SUPER", GDK_SUPER_MASK }, // super (since 2.10) - { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10) - { "META", GDK_META_MASK }, // meta (since 2.10) - { NULL, 0 } -}; - - -/* construct a hash from the var_name_to_ptr array for quick access */ -void -create_var_to_name_hash() { - const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr; - uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal); - while(n2v_p->name) { - g_hash_table_insert(uzbl.comm.proto_var, - (gpointer) n2v_p->name, - (gpointer) &n2v_p->cp); - n2v_p++; - } -} - - -/* --- UTILITY FUNCTIONS --- */ -enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE}; -enum exp_type -get_exp_type(const gchar *s) { - /* variables */ - if(*(s+1) == '(') - return EXP_EXPR; - else if(*(s+1) == '{') - return EXP_BRACED_VAR; - else if(*(s+1) == '<') - return EXP_JS; - else if(*(s+1) == '[') - return EXP_ESCAPE; - else - return EXP_SIMPLE_VAR; - - /*@notreached@*/ -return EXP_ERR; -} - -/* - * recurse == 1: don't expand '@(command)@' - * recurse == 2: don't expand '@@' -*/ -gchar * -expand(const char *s, guint recurse) { - uzbl_cmdprop *c; - enum exp_type etype; - char *end_simple_var = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½"; - char *ret = NULL; - char *vend = NULL; - GError *err = NULL; - gchar *cmd_stdout = NULL; - gchar *mycmd = NULL; - GString *buf = g_string_new(""); - GString *js_ret = g_string_new(""); - - while(*s) { - switch(*s) { - case '\\': - g_string_append_c(buf, *++s); - s++; - break; - - case '@': - etype = get_exp_type(s); - s++; - - switch(etype) { - case EXP_SIMPLE_VAR: - vend = strpbrk(s, end_simple_var); - if(!vend) vend = strchr(s, '\0'); - break; - case EXP_BRACED_VAR: - s++; - vend = strchr(s, '}'); - if(!vend) vend = strchr(s, '\0'); - break; - case EXP_EXPR: - s++; - vend = strstr(s, ")@"); - if(!vend) vend = strchr(s, '\0'); - break; - case EXP_JS: - s++; - vend = strstr(s, ">@"); - if(!vend) vend = strchr(s, '\0'); - break; - case EXP_ESCAPE: - s++; - vend = strstr(s, "]@"); - if(!vend) vend = strchr(s, '\0'); - break; - /*@notreached@*/ - case EXP_ERR: - break; - } - assert(vend); - - ret = g_strndup(s, vend-s); - - if(etype == EXP_SIMPLE_VAR || - etype == EXP_BRACED_VAR) { - if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) { - if(c->type == TYPE_STR && *c->ptr.s != NULL) { - g_string_append(buf, (gchar *)*c->ptr.s); - } - else if(c->type == TYPE_INT) { - g_string_append_printf(buf, "%d", *c->ptr.i); - } - else if(c->type == TYPE_FLOAT) { - g_string_append_printf(buf, "%f", *c->ptr.f); - } - } - - if(etype == EXP_SIMPLE_VAR) - s = vend; - else - s = vend+1; - } - else if(recurse != 1 && - etype == EXP_EXPR) { - mycmd = expand(ret, 1); - g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err); - g_free(mycmd); - - if (err) { - g_printerr("error on running command: %s\n", err->message); - g_error_free (err); - } - else if (*cmd_stdout) { - size_t len = strlen(cmd_stdout); - - if(len > 0 && cmd_stdout[len-1] == '\n') - cmd_stdout[--len] = '\0'; /* strip trailing newline */ - - g_string_append(buf, cmd_stdout); - g_free(cmd_stdout); - } - s = vend+2; - } - else if(recurse != 2 && - etype == EXP_JS) { - mycmd = expand(ret, 2); - eval_js(uzbl.gui.web_view, mycmd, js_ret); - g_free(mycmd); - - if(js_ret->str) { - g_string_append(buf, js_ret->str); - g_string_free(js_ret, TRUE); - js_ret = g_string_new(""); - } - s = vend+2; - } - else if(etype == EXP_ESCAPE) { - mycmd = expand(ret, 0); - char *escaped = g_markup_escape_text(mycmd, strlen(mycmd)); - - g_string_append(buf, escaped); - - g_free(escaped); - g_free(mycmd); - s = vend+2; - } - - g_free(ret); - ret = NULL; - break; - - default: - g_string_append_c(buf, *s); - s++; - break; - } - } - g_string_free(js_ret, TRUE); - return g_string_free(buf, FALSE); -} - -/* send events as strings to stdout (do we need to support fifo/socket as output mechanism?) - * we send all events to the output. it's the users task to filter out what he cares about. -*/ -void -send_event(int type, const gchar *details) { - - if(type < LAST_EVENT) { - printf("EVENT %s [%s] %s\n", event_table[type], uzbl.state.instance_name, details); - fflush(stdout); - } -} - -char * -itos(int val) { - char tmp[20]; - - snprintf(tmp, sizeof(tmp), "%i", val); - return g_strdup(tmp); -} - -gchar* -strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go - -gchar* -argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } - -char * -str_replace (const char* search, const char* replace, const char* string) { - gchar **buf; - char *ret; - - buf = g_strsplit (string, search, -1); - ret = g_strjoinv (replace, buf); - g_strfreev(buf); // somebody said this segfaults - - return ret; -} - -GArray* -read_file_by_line (const gchar *path) { - GIOChannel *chan = NULL; - gchar *readbuf = NULL; - gsize len; - GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*)); - int i = 0; - - chan = g_io_channel_new_file(path, "r", NULL); - - if (chan) { - while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) { - const gchar* val = g_strdup (readbuf); - g_array_append_val (lines, val); - g_free (readbuf); - i ++; - } - - g_io_channel_unref (chan); - } else { - fprintf(stderr, "File '%s' not be read.\n", path); - } - - return lines; -} - -gchar* -parseenv (char* string) { - extern char** environ; - gchar* tmpstr = NULL; - int i = 0; - - - while (environ[i] != NULL) { - gchar** env = g_strsplit (environ[i], "=", 2); - gchar* envname = g_strconcat ("$", env[0], NULL); - - if (g_strrstr (string, envname) != NULL) { - tmpstr = g_strdup(string); - g_free (string); - string = str_replace(envname, env[1], tmpstr); - g_free (tmpstr); - } - - g_free (envname); - g_strfreev (env); // somebody said this breaks uzbl - i++; - } - - return string; -} - -sigfunc* -setup_signal(int signr, sigfunc *shandler) { - struct sigaction nh, oh; - - nh.sa_handler = shandler; - sigemptyset(&nh.sa_mask); - nh.sa_flags = 0; - - if(sigaction(signr, &nh, &oh) < 0) - return SIG_ERR; - - return NULL; -} - -void -clean_up(void) { - if (uzbl.behave.fifo_dir) - unlink (uzbl.comm.fifo_path); - if (uzbl.behave.socket_dir) - unlink (uzbl.comm.socket_path); - - g_free(uzbl.state.executable_path); - g_free(uzbl.state.keycmd); - g_hash_table_destroy(uzbl.bindings); - g_hash_table_destroy(uzbl.behave.commands); -} - -/* --- SIGNAL HANDLER --- */ - -void -catch_sigterm(int s) { - (void) s; - clean_up(); -} - -void -catch_sigint(int s) { - (void) s; - clean_up(); - exit(EXIT_SUCCESS); -} - -/* --- CALLBACKS --- */ - -gboolean -navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { - (void) web_view; - (void) frame; - (void) navigation_action; - (void) user_data; - - const gchar* uri = webkit_network_request_get_uri (request); - gboolean decision_made = FALSE; - - if (uzbl.state.verbose) - printf("Navigation requested -> %s\n", uri); - - if (uzbl.behave.scheme_handler) { - GString *s = g_string_new (""); - g_string_printf(s, "'%s'", uri); - - run_handler(uzbl.behave.scheme_handler, s->str); - - if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { - char *p = strchr(uzbl.comm.sync_stdout, '\n' ); - if ( p != NULL ) *p = '\0'; - if (!strcmp(uzbl.comm.sync_stdout, "USED")) { - webkit_web_policy_decision_ignore(policy_decision); - decision_made = TRUE; - } - } - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - - g_string_free(s, TRUE); - } - if (!decision_made) - webkit_web_policy_decision_use(policy_decision); - - return TRUE; -} - -gboolean -new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { - (void) web_view; - (void) frame; - (void) navigation_action; - (void) policy_decision; - (void) user_data; - const gchar* uri = webkit_network_request_get_uri (request); - if (uzbl.state.verbose) - printf("New window requested -> %s \n", uri); - webkit_web_policy_decision_use(policy_decision); - send_event(NEW_WINDOW, uri); - return TRUE; -} - -gboolean -mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) { - (void) frame; - (void) request; - (void) user_data; - - /* If we can display it, let's display it... */ - if (webkit_web_view_can_show_mime_type (web_view, mime_type)) { - webkit_web_policy_decision_use (policy_decision); - return TRUE; - } - - /* ...everything we can't display is downloaded */ - webkit_web_policy_decision_download (policy_decision); - return TRUE; -} - -/*@null@*/ WebKitWebView* -create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) { - (void) web_view; - (void) frame; - (void) user_data; - if (uzbl.state.selected_url != NULL) { - if (uzbl.state.verbose) - printf("\nNew web view -> %s\n",uzbl.state.selected_url); - new_window_load_uri(uzbl.state.selected_url); - } else { - if (uzbl.state.verbose) - printf("New web view -> %s\n","Nothing to open, exiting"); - } - return (NULL); -} - -gboolean -download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) { - (void) web_view; - (void) user_data; - if (uzbl.behave.download_handler) { - const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download); - if (uzbl.state.verbose) - printf("Download -> %s\n",uri); - /* if urls not escaped, we may have to escape and quote uri before this call */ - - GString *args = g_string_new(uri); - - if (uzbl.net.proxy_url) { - g_string_append_c(args, ' '); - g_string_append(args, uzbl.net.proxy_url); - } - - run_handler(uzbl.behave.download_handler, args->str); - - g_string_free(args, TRUE); - } - send_event(DOWNLOAD_REQ, webkit_download_get_uri ((WebKitDownload*)download)); - return (FALSE); -} - -/* scroll a bar in a given direction */ -void -scroll (GtkAdjustment* bar, GArray *argv) { - gchar *end; - gdouble max_value; - - gdouble page_size = gtk_adjustment_get_page_size(bar); - gdouble value = gtk_adjustment_get_value(bar); - gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end); - - if (*end == '%') - value += page_size * amount * 0.01; - else - value += amount; - - max_value = gtk_adjustment_get_upper(bar) - page_size; - - if (value > max_value) - value = max_value; /* don't scroll past the end of the page */ - - gtk_adjustment_set_value (bar, value); -} - -void -scroll_begin(WebKitWebView* page, GArray *argv, GString *result) { - (void) page; (void) argv; (void) result; - gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v)); -} - -void -scroll_end(WebKitWebView* page, GArray *argv, GString *result) { - (void) page; (void) argv; (void) result; - gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) - - gtk_adjustment_get_page_size(uzbl.gui.bar_v)); -} - -void -scroll_vert(WebKitWebView* page, GArray *argv, GString *result) { - (void) page; (void) result; - scroll(uzbl.gui.bar_v, argv); -} - -void -scroll_horz(WebKitWebView* page, GArray *argv, GString *result) { - (void) page; (void) result; - scroll(uzbl.gui.bar_h, argv); -} - -void -cmd_set_geometry() { - if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) { - if(uzbl.state.verbose) - printf("Error in geometry string: %s\n", uzbl.gui.geometry); - } - /* update geometry var with the actual geometry - this is necessary as some WMs don't seem to honour - the above setting and we don't want to end up with - wrong geometry information - */ - retrieve_geometry(); -} - -void -cmd_set_status() { - if (!uzbl.behave.show_status) { - gtk_widget_hide(uzbl.gui.mainbar); - } else { - gtk_widget_show(uzbl.gui.mainbar); - } - update_title(); -} - -void -toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) { - (void)page; - (void)argv; - (void)result; - - webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page)); -} - -void -toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) { - (void)page; - (void)argv; - (void)result; - - if (uzbl.behave.show_status) { - gtk_widget_hide(uzbl.gui.mainbar); - } else { - gtk_widget_show(uzbl.gui.mainbar); - } - uzbl.behave.show_status = !uzbl.behave.show_status; - update_title(); -} - -void -link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) { - (void) page; - (void) title; - (void) data; - //Set selected_url state variable - g_free(uzbl.state.selected_url); - uzbl.state.selected_url = NULL; - if (link) { - uzbl.state.selected_url = g_strdup(link); - send_event(LINK_HOVER, uzbl.state.selected_url); - } - update_title(); -} - -void -title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { - (void) web_view; - (void) param_spec; - const gchar *title = webkit_web_view_get_title(web_view); - if (uzbl.gui.main_title) - 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); -} - -void -progress_change_cb (WebKitWebView* page, gint progress, gpointer data) { - (void) page; - (void) data; - uzbl.gui.sbar.load_progress = progress; - - g_free(uzbl.gui.sbar.progress_bar); - uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress); - - update_title(); -} - -void -selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) { - (void)ud; - gchar *tmp; - - webkit_web_view_copy_clipboard(webkitwebview); - tmp = gtk_clipboard_wait_for_text(gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); - send_event(SELECTION_CHANGED, tmp); - g_free(tmp); -} - -void -load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { - (void) page; - (void) data; - - if (uzbl.behave.load_finish_handler) - run_handler(uzbl.behave.load_finish_handler, ""); - - send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame)); -} - -void clear_keycmd() { - g_free(uzbl.state.keycmd); - uzbl.state.keycmd = g_strdup(""); -} - -void -load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { - (void) page; - (void) frame; - (void) data; - uzbl.gui.sbar.load_progress = 0; - if (uzbl.behave.load_start_handler) - run_handler(uzbl.behave.load_start_handler, ""); - - send_event(LOAD_START, uzbl.state.uri); -} - -void -load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer web_err, gpointer ud) { - (void) page; - (void) frame; - (void) ud; - GError *err = web_err; - gchar *details; - - details = g_strdup_printf("%s %d:%s", uri, err->code, err->message); - send_event(LOAD_ERROR, details); - g_free(details); -} - -void -load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { - (void) page; - (void) data; - g_free (uzbl.state.uri); - GString* newuri = g_string_new (webkit_web_frame_get_uri (frame)); - uzbl.state.uri = g_string_free (newuri, FALSE); - if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) { - set_insert_mode(uzbl.behave.always_insert_mode); - update_title(); - } - if (uzbl.behave.load_commit_handler) - run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri); - - /* event message */ - send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame)); -} - -void -destroy_cb (GtkWidget* widget, gpointer data) { - (void) widget; - (void) data; - gtk_main_quit (); -} - - -/* VIEW funcs (little webkit wrappers) */ -#define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);} -VIEWFUNC(reload) -VIEWFUNC(reload_bypass_cache) -VIEWFUNC(stop_loading) -VIEWFUNC(zoom_in) -VIEWFUNC(zoom_out) -VIEWFUNC(go_back) -VIEWFUNC(go_forward) -#undef VIEWFUNC - -/* -- command to callback/function map for things we cannot attach to any signals */ -struct {const char *key; CommandInfo value;} cmdlist[] = -{ /* 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} } -}; - -void -commands_hash(void) -{ - unsigned int i; - uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal); - - for (i = 0; i < LENGTH(cmdlist); i++) - g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value); -} - -/* -- CORE FUNCTIONS -- */ - -void -free_action(gpointer act) { - Action *action = (Action*)act; - g_free(action->name); - if (action->param) - g_free(action->param); - g_free(action); -} - -Action* -new_action(const gchar *name, const gchar *param) { - Action *action = g_new(Action, 1); - - action->name = g_strdup(name); - if (param) - action->param = g_strdup(param); - else - action->param = NULL; - - return action; -} - -bool -file_exists (const char * filename) { - return (access(filename, F_OK) == 0); -} - -void -set_var(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); - if (split[0] != NULL) { - gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); - set_var_value(g_strstrip(split[0]), value); - g_free(value); - } - g_strfreev(split); -} - -void -update_gui(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) argv; (void) result; - - update_title(); -} - -void -print(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - gchar* buf; - - buf = expand(argv_idx(argv, 0), 0); - g_string_assign(result, buf); - g_free(buf); -} - -void -act_bind(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2); - gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " ")); - add_binding(g_strstrip(split[0]), value); - g_free(value); - g_strfreev(split); -} - - -void -act_dump_config() { - dump_config(); -} - -void -set_keycmd() { - run_keycmd(FALSE); - update_title(); -} - -void -set_mode_indicator() { - uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ? - uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator); -} - -void -update_indicator() { - set_mode_indicator(); - update_title(); -} - -void -set_insert_mode(gboolean mode) { - uzbl.behave.insert_mode = mode; - set_mode_indicator(); -} - -void -toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - - if (argv_idx(argv, 0)) { - if (strcmp (argv_idx(argv, 0), "0") == 0) { - set_insert_mode(FALSE); - } else { - set_insert_mode(TRUE); - } - } else { - set_insert_mode( !uzbl.behave.insert_mode ); - } - - update_title(); -} - -void -load_uri (WebKitWebView *web_view, GArray *argv, GString *result) { - (void) result; - - if (argv_idx(argv, 0)) { - GString* newuri = g_string_new (argv_idx(argv, 0)); - if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) { - run_js(web_view, argv, NULL); - return; - } - if (!soup_uri_new(argv_idx(argv, 0))) - g_string_prepend (newuri, "http://"); - /* if we do handle cookies, ask our handler for them */ - webkit_web_view_load_uri (web_view, newuri->str); - g_string_free (newuri, TRUE); - } -} - -/* Javascript*/ - -JSValueRef -js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, - size_t argumentCount, const JSValueRef arguments[], - JSValueRef* exception) { - (void) function; - (void) thisObject; - (void) exception; - - JSStringRef js_result_string; - GString *result = g_string_new(""); - - if (argumentCount >= 1) { - JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL); - size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg); - char ctl_line[arg_size]; - JSStringGetUTF8CString(arg, ctl_line, arg_size); - - parse_cmd_line(ctl_line, result); - - JSStringRelease(arg); - } - js_result_string = JSStringCreateWithUTF8CString(result->str); - - g_string_free(result, TRUE); - - return JSValueMakeString(ctx, js_result_string); -} - -JSStaticFunction js_static_functions[] = { - {"run", js_run_command, kJSPropertyAttributeNone}, -}; - -void -js_init() { - /* This function creates the class and its definition, only once */ - if (!uzbl.js.initialized) { - /* it would be pretty cool to make this dynamic */ - uzbl.js.classdef = kJSClassDefinitionEmpty; - uzbl.js.classdef.staticFunctions = js_static_functions; - - uzbl.js.classref = JSClassCreate(&uzbl.js.classdef); - } -} - - -void -eval_js(WebKitWebView * web_view, gchar *script, GString *result) { - WebKitWebFrame *frame; - JSGlobalContextRef context; - JSObjectRef globalobject; - JSStringRef var_name; - - JSStringRef js_script; - JSValueRef js_result; - JSStringRef js_result_string; - size_t js_result_size; - - js_init(); - - frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view)); - context = webkit_web_frame_get_global_context(frame); - globalobject = JSContextGetGlobalObject(context); - - /* uzbl javascript namespace */ - var_name = JSStringCreateWithUTF8CString("Uzbl"); - JSObjectSetProperty(context, globalobject, var_name, - JSObjectMake(context, uzbl.js.classref, NULL), - kJSClassAttributeNone, NULL); - - /* evaluate the script and get return value*/ - js_script = JSStringCreateWithUTF8CString(script); - js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL); - if (js_result && !JSValueIsUndefined(context, js_result)) { - js_result_string = JSValueToStringCopy(context, js_result, NULL); - js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string); - - if (js_result_size) { - char js_result_utf8[js_result_size]; - JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size); - g_string_assign(result, js_result_utf8); - } - - JSStringRelease(js_result_string); - } - - /* cleanup */ - JSObjectDeleteProperty(context, globalobject, var_name, NULL); - - JSStringRelease(var_name); - JSStringRelease(js_script); -} - -void -run_js (WebKitWebView * web_view, GArray *argv, GString *result) { - if (argv_idx(argv, 0)) - eval_js(web_view, argv_idx(argv, 0), result); -} - -void -run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) { - (void) result; - if (argv_idx(argv, 0)) { - GArray* lines = read_file_by_line (argv_idx (argv, 0)); - gchar* js = NULL; - int i = 0; - gchar* line; - - while ((line = g_array_index(lines, gchar*, i))) { - if (js == NULL) { - js = g_strdup (line); - } else { - gchar* newjs = g_strconcat (js, line, NULL); - js = newjs; - } - i ++; - g_free (line); - } - - if (uzbl.state.verbose) - printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0)); - - if (argv_idx (argv, 1)) { - gchar* newjs = str_replace("%s", argv_idx (argv, 1), js); - g_free (js); - js = newjs; - } - eval_js (web_view, js, result); - g_free (js); - g_array_free (lines, TRUE); - } -} - -void -search_text (WebKitWebView *page, GArray *argv, const gboolean forward) { - if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) { - if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) { - webkit_web_view_unmark_text_matches (page); - webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0); - uzbl.state.searchtx = g_strdup(argv_idx(argv, 0)); - } - } - - if (uzbl.state.searchtx) { - if (uzbl.state.verbose) - printf ("Searching: %s\n", uzbl.state.searchtx); - webkit_web_view_set_highlight_text_matches (page, TRUE); - webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE); - } -} - -void -search_forward_text (WebKitWebView *page, GArray *argv, GString *result) { - (void) result; - search_text(page, argv, TRUE); -} - -void -search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) { - (void) result; - search_text(page, argv, FALSE); -} - -void -dehilight (WebKitWebView *page, GArray *argv, GString *result) { - (void) argv; (void) result; - webkit_web_view_set_highlight_text_matches (page, FALSE); -} - - -void -new_window_load_uri (const gchar * uri) { - if (uzbl.behave.new_window) { - GString *s = g_string_new (""); - g_string_printf(s, "'%s'", uri); - run_handler(uzbl.behave.new_window, s->str); - send_event(NEW_WINDOW, s->str); - return; - } - GString* to_execute = g_string_new (""); - g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri); - int i; - for (i = 0; entries[i].long_name != NULL; i++) { - if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) { - gchar** str = (gchar**)entries[i].arg_data; - if (*str!=NULL) { - g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str); - } - } - } - if (uzbl.state.verbose) - printf("\n%s\n", to_execute->str); - g_spawn_command_line_async (to_execute->str, NULL); - /* TODO: should we just report the uri as event detail? */ - send_event(NEW_WINDOW, to_execute->str); - g_string_free (to_execute, TRUE); -} - -void -chain (WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - gchar *a = NULL; - gchar **parts = NULL; - guint i = 0; - while ((a = argv_idx(argv, i++))) { - parts = g_strsplit (a, " ", 2); - if (parts[0]) - parse_command(parts[0], parts[1], result); - g_strfreev (parts); - } -} - -void -keycmd (WebKitWebView *page, GArray *argv, GString *result) { - (void)page; - (void)argv; - (void)result; - uzbl.state.keycmd = g_strdup(argv_idx(argv, 0)); - run_keycmd(FALSE); - update_title(); -} - -void -keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) { - (void)page; - (void)argv; - (void)result; - uzbl.state.keycmd = g_strdup(argv_idx(argv, 0)); - run_keycmd(TRUE); - update_title(); -} - -void -keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) { - gchar *prev; - (void)page; - (void)argv; - (void)result; - int len = strlen(uzbl.state.keycmd); - prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len); - if (prev) - uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0'; - update_title(); -} - -void -close_uzbl (WebKitWebView *page, GArray *argv, GString *result) { - (void)page; - (void)argv; - (void)result; - gtk_main_quit (); -} - -/* --Statusbar functions-- */ -char* -build_progressbar_ascii(int percent) { - int width=uzbl.gui.sbar.progress_w; - int i; - double l; - GString *bar = g_string_new(""); - - l = (double)percent*((double)width/100.); - l = (int)(l+.5)>=(int)l ? l+.5 : l; - - for(i=0; i<(int)l; i++) - g_string_append(bar, uzbl.gui.sbar.progress_s); - - for(; i [args] - GError *err = NULL; - - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - gchar *pid = itos(getpid()); - gchar *xwin = itos(uzbl.xwin); - guint i; - sharg_append(a, command); - for (i = 0; i < npre; i++) /* add n args before the default vars */ - sharg_append(a, args[i]); - sharg_append(a, uzbl.state.config_file); - sharg_append(a, pid); - sharg_append(a, xwin); - sharg_append(a, uzbl.comm.fifo_path); - sharg_append(a, uzbl.comm.socket_path); - sharg_append(a, uzbl.state.uri); - sharg_append(a, uzbl.gui.main_title); - - for (i = npre; i < g_strv_length((gchar**)args); i++) - sharg_append(a, args[i]); - - gboolean result; - if (sync) { - if (*output_stdout) *output_stdout = strfree(*output_stdout); - - result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, output_stdout, NULL, NULL, &err); - } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, - NULL, NULL, NULL, &err); - - if (uzbl.state.verbose) { - GString *s = g_string_new("spawned:"); - for (i = 0; i < (a->len); i++) { - gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i)); - g_string_append_printf(s, " %s", qarg); - g_free (qarg); - } - g_string_append_printf(s, " -- result: %s", (result ? "true" : "false")); - printf("%s\n", s->str); - g_string_free(s, TRUE); - if(output_stdout) { - printf("Stdout: %s\n", *output_stdout); - } - } - if (err) { - g_printerr("error on run_command: %s\n", err->message); - g_error_free (err); - } - g_free (pid); - g_free (xwin); - g_array_free (a, TRUE); - return result; -} - -/*@null@*/ gchar** -split_quoted(const gchar* src, const gboolean unquote) { - /* split on unquoted space, return array of strings; - remove a layer of quotes and backslashes if unquote */ - if (!src) return NULL; - - gboolean dq = FALSE; - gboolean sq = FALSE; - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - GString *s = g_string_new (""); - const gchar *p; - gchar **ret; - gchar *dup; - for (p = src; *p != '\0'; p++) { - if ((*p == '\\') && unquote) g_string_append_c(s, *++p); - else if (*p == '\\') { g_string_append_c(s, *p++); - g_string_append_c(s, *p); } - else if ((*p == '"') && unquote && !sq) dq = !dq; - else if (*p == '"' && !sq) { g_string_append_c(s, *p); - dq = !dq; } - else if ((*p == '\'') && unquote && !dq) sq = !sq; - else if (*p == '\'' && !dq) { g_string_append_c(s, *p); - sq = ! sq; } - else if ((*p == ' ') && !dq && !sq) { - dup = g_strdup(s->str); - g_array_append_val(a, dup); - g_string_truncate(s, 0); - } else g_string_append_c(s, *p); - } - dup = g_strdup(s->str); - g_array_append_val(a, dup); - ret = (gchar**)a->data; - g_array_free (a, FALSE); - g_string_free (s, TRUE); - return ret; -} - -void -spawn(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after - if (argv_idx(argv, 0)) - run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL); -} - -void -spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - - if (argv_idx(argv, 0)) - run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), - TRUE, &uzbl.comm.sync_stdout); -} - -void -spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - if (!uzbl.behave.shell_cmd) { - g_printerr ("spawn_sh: shell_cmd is not set!\n"); - return; - } - - guint i; - gchar *spacer = g_strdup(""); - g_array_insert_val(argv, 1, spacer); - gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); - - for (i = 1; i < g_strv_length(cmd); i++) - g_array_prepend_val(argv, cmd[i]); - - if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL); - g_free (spacer); - g_strfreev (cmd); -} - -void -spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - if (!uzbl.behave.shell_cmd) { - g_printerr ("spawn_sh_sync: shell_cmd is not set!\n"); - return; - } - - guint i; - gchar *spacer = g_strdup(""); - g_array_insert_val(argv, 1, spacer); - gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); - - for (i = 1; i < g_strv_length(cmd); i++) - g_array_prepend_val(argv, cmd[i]); - - if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, - TRUE, &uzbl.comm.sync_stdout); - g_free (spacer); - g_strfreev (cmd); -} - -void -talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - - int fd, len; - struct sockaddr_un sa; - char* sockpath; - ssize_t ret; - struct pollfd pfd; - struct iovec* iov; - guint i; - - if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - - /* This function could be optimised by storing a hash table of socket paths - and associated connected file descriptors rather than closing and - re-opening for every call. Also we could launch a script if socket connect - fails. */ - - /* First element argv[0] is path to socket. Following elements are tokens to - write to the socket. We write them as a single packet with each token - separated by an ASCII nul (\0). */ - if(argv->len < 2) { - g_printerr("talk_to_socket called with only %d args (need at least two).\n", - (int)argv->len); - return; - } - - /* copy socket path, null terminate result */ - sockpath = g_array_index(argv, char*, 0); - g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path)); - sa.sun_family = AF_UNIX; - - /* create socket file descriptor and connect it to path */ - fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if(fd == -1) { - g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno)); - return; - } - if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) { - g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* build request vector */ - iov = g_malloc(sizeof(struct iovec) * (argv->len - 1)); - if(!iov) { - g_printerr("talk_to_socket: unable to allocated memory for token vector\n"); - close(fd); - return; - } - for(i = 1; i < argv->len; ++i) { - iov[i - 1].iov_base = g_array_index(argv, char*, i); - iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */ - } - - /* write request */ - ret = writev(fd, iov, argv->len - 1); - g_free(iov); - if(ret == -1) { - g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* wait for a response, with a 500ms timeout */ - pfd.fd = fd; - pfd.events = POLLIN; - while(1) { - ret = poll(&pfd, 1, 500); - if(ret == 1) break; - if(ret == 0) errno = ETIMEDOUT; - if(errno == EINTR) continue; - g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n", - strerror(errno)); - close(fd); - return; - } - - /* get length of response */ - if(ioctl(fd, FIONREAD, &len) == -1) { - g_printerr("talk_to_socket: cannot find daemon response length, " - "ioctl failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* if there is a response, read it */ - if(len) { - uzbl.comm.sync_stdout = g_malloc(len + 1); - if(!uzbl.comm.sync_stdout) { - g_printerr("talk_to_socket: failed to allocate %d bytes\n", len); - close(fd); - return; - } - uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */ - - ret = read(fd, uzbl.comm.sync_stdout, len); - if(ret == -1) { - g_printerr("talk_to_socket: failed to read from socket (%s)\n", - strerror(errno)); - close(fd); - return; - } - } - - /* clean up */ - close(fd); - return; -} - -void -parse_command(const char *cmd, const char *param, GString *result) { - CommandInfo *c; - - if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) { - guint i; - gchar **par = split_quoted(param, TRUE); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - - if (c->no_split) { /* don't split */ - sharg_append(a, param); - } else if (par) { - for (i = 0; i < g_strv_length(par); i++) - sharg_append(a, par[i]); - } - - if (result == NULL) { - GString *result_print = g_string_new(""); - - c->function(uzbl.gui.web_view, a, result_print); - if (result_print->len) - printf("%*s\n", (int)result_print->len, result_print->str); - - g_string_free(result_print, TRUE); - } else { - c->function(uzbl.gui.web_view, a, result); - } - g_strfreev (par); - g_array_free (a, TRUE); - - } else - g_printerr ("command \"%s\" not understood. ignoring.\n", cmd); -} - -void -set_proxy_url() { - SoupURI *suri; - - if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') { - soup_session_remove_feature_by_type(uzbl.net.soup_session, - (GType) SOUP_SESSION_PROXY_URI); - } - else { - suri = soup_uri_new(uzbl.net.proxy_url); - g_object_set(G_OBJECT(uzbl.net.soup_session), - SOUP_SESSION_PROXY_URI, - suri, NULL); - soup_uri_free(suri); - } - return; -} - -void -set_icon() { - if(file_exists(uzbl.gui.icon)) { - if (uzbl.gui.main_window) - gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL); - } else { - g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon); - } -} - -void -cmd_load_uri() { - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); - g_array_append_val (a, uzbl.state.uri); - load_uri(uzbl.gui.web_view, a, NULL); - g_array_free (a, TRUE); -} - -void -cmd_always_insert_mode() { - set_insert_mode(uzbl.behave.always_insert_mode); - update_title(); -} - -void -cmd_max_conns() { - g_object_set(G_OBJECT(uzbl.net.soup_session), - SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL); -} - -void -cmd_max_conns_host() { - g_object_set(G_OBJECT(uzbl.net.soup_session), - SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL); -} - -void -cmd_http_debug() { - soup_session_remove_feature - (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); - /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */ - /*g_free(uzbl.net.soup_logger);*/ - - uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1); - soup_session_add_feature(uzbl.net.soup_session, - SOUP_SESSION_FEATURE(uzbl.net.soup_logger)); -} - -WebKitWebSettings* -view_settings() { - return webkit_web_view_get_settings(uzbl.gui.web_view); -} - -void -cmd_font_size() { - WebKitWebSettings *ws = view_settings(); - if (uzbl.behave.font_size > 0) { - g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL); - } - - if (uzbl.behave.monospace_size > 0) { - g_object_set (G_OBJECT(ws), "default-monospace-font-size", - uzbl.behave.monospace_size, NULL); - } else { - g_object_set (G_OBJECT(ws), "default-monospace-font-size", - uzbl.behave.font_size, NULL); - } -} - -void -cmd_default_font_family() { - g_object_set (G_OBJECT(view_settings()), "default-font-family", - uzbl.behave.default_font_family, NULL); -} - -void -cmd_monospace_font_family() { - g_object_set (G_OBJECT(view_settings()), "monospace-font-family", - uzbl.behave.monospace_font_family, NULL); -} - -void -cmd_sans_serif_font_family() { - g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family", - uzbl.behave.sans_serif_font_family, NULL); -} - -void -cmd_serif_font_family() { - g_object_set (G_OBJECT(view_settings()), "serif-font-family", - uzbl.behave.serif_font_family, NULL); -} - -void -cmd_cursive_font_family() { - g_object_set (G_OBJECT(view_settings()), "cursive-font-family", - uzbl.behave.cursive_font_family, NULL); -} - -void -cmd_fantasy_font_family() { - g_object_set (G_OBJECT(view_settings()), "fantasy-font-family", - uzbl.behave.fantasy_font_family, NULL); -} - -void -cmd_zoom_level() { - webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level); -} - -void -cmd_disable_plugins() { - g_object_set (G_OBJECT(view_settings()), "enable-plugins", - !uzbl.behave.disable_plugins, NULL); -} - -void -cmd_disable_scripts() { - g_object_set (G_OBJECT(view_settings()), "enable-scripts", - !uzbl.behave.disable_scripts, NULL); -} - -void -cmd_minimum_font_size() { - g_object_set (G_OBJECT(view_settings()), "minimum-font-size", - uzbl.behave.minimum_font_size, NULL); -} -void -cmd_autoload_img() { - g_object_set (G_OBJECT(view_settings()), "auto-load-images", - uzbl.behave.autoload_img, NULL); -} - - -void -cmd_autoshrink_img() { - g_object_set (G_OBJECT(view_settings()), "auto-shrink-images", - uzbl.behave.autoshrink_img, NULL); -} - - -void -cmd_enable_spellcheck() { - g_object_set (G_OBJECT(view_settings()), "enable-spell-checking", - uzbl.behave.enable_spellcheck, NULL); -} - -void -cmd_enable_private() { - g_object_set (G_OBJECT(view_settings()), "enable-private-browsing", - uzbl.behave.enable_private, NULL); -} - -void -cmd_print_bg() { - g_object_set (G_OBJECT(view_settings()), "print-backgrounds", - uzbl.behave.print_bg, NULL); -} - -void -cmd_style_uri() { - g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri", - uzbl.behave.style_uri, NULL); -} - -void -cmd_resizable_txt() { - g_object_set (G_OBJECT(view_settings()), "resizable-text-areas", - uzbl.behave.resizable_txt, NULL); -} - -void -cmd_default_encoding() { - g_object_set (G_OBJECT(view_settings()), "default-encoding", - uzbl.behave.default_encoding, NULL); -} - -void -cmd_enforce_96dpi() { - g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi", - uzbl.behave.enforce_96dpi, NULL); -} - -void -cmd_caret_browsing() { - g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing", - uzbl.behave.caret_browsing, NULL); -} - -void -cmd_cookie_handler() { - gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); - /* pitfall: doesn't handle chain actions; must the sync_ action manually */ - if ((g_strcmp0(split[0], "sh") == 0) || - (g_strcmp0(split[0], "spawn") == 0)) { - g_free (uzbl.behave.cookie_handler); - uzbl.behave.cookie_handler = - g_strdup_printf("sync_%s %s", split[0], split[1]); - } - g_strfreev (split); -} - -void -cmd_scheme_handler() { - gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2); - /* pitfall: doesn't handle chain actions; must the sync_ action manually */ - if ((g_strcmp0(split[0], "sh") == 0) || - (g_strcmp0(split[0], "spawn") == 0)) { - g_free (uzbl.behave.scheme_handler); - uzbl.behave.scheme_handler = - g_strdup_printf("sync_%s %s", split[0], split[1]); - } - g_strfreev (split); -} - -void -cmd_fifo_dir() { - uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); -} - -void -cmd_socket_dir() { - uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir); -} - -void -cmd_inject_html() { - if(uzbl.behave.inject_html) { - webkit_web_view_load_html_string (uzbl.gui.web_view, - uzbl.behave.inject_html, NULL); - } -} - -void -cmd_modkey() { - int i; - char *buf; - - buf = g_utf8_strup(uzbl.behave.modkey, -1); - uzbl.behave.modmask = 0; - - if(uzbl.behave.modkey) - g_free(uzbl.behave.modkey); - uzbl.behave.modkey = buf; - - for (i = 0; modkeys[i].key != NULL; i++) { - if (g_strrstr(buf, modkeys[i].key)) - uzbl.behave.modmask |= modkeys[i].mask; - } -} - -void -cmd_useragent() { - if (*uzbl.net.useragent == ' ') { - g_free (uzbl.net.useragent); - uzbl.net.useragent = NULL; - } else { - g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, - uzbl.net.useragent, NULL); - } -} - -void -move_statusbar() { - if (!uzbl.gui.scrolled_win && - !uzbl.gui.mainbar) - return; - - gtk_widget_ref(uzbl.gui.scrolled_win); - gtk_widget_ref(uzbl.gui.mainbar); - gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win); - gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar); - - if(uzbl.behave.status_top) { - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); - } - else { - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); - } - gtk_widget_unref(uzbl.gui.scrolled_win); - gtk_widget_unref(uzbl.gui.mainbar); - gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); - return; -} - -gboolean -set_var_value(const gchar *name, gchar *val) { - uzbl_cmdprop *c = NULL; - char *endp = NULL; - char *buf = NULL; - char *invalid_chars = "^°!\"§$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]¹²³¼½"; - GString *msg; - - if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { - if(!c->writeable) return FALSE; - - /* 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); - } else if(c->type == TYPE_INT) { - buf = expand(val, 0); - *c->ptr.i = (int)strtoul(buf, &endp, 10); - g_free(buf); - } else if (c->type == TYPE_FLOAT) { - buf = expand(val, 0); - *c->ptr.f = strtod(buf, &endp); - g_free(buf); - } - - /* invoke a command specific function */ - if(c->func) c->func(); - } else { - /* check wether name violates our naming scheme */ - if(strpbrk(name, invalid_chars)) { - if (uzbl.state.verbose) - printf("Invalid variable name\n"); - return FALSE; - } - - /* custom vars */ - c = malloc(sizeof(uzbl_cmdprop)); - c->type = TYPE_STR; - c->dump = 0; - c->func = NULL; - c->writeable = 1; - buf = expand(val, 0); - c->ptr.s = malloc(sizeof(char *)); - *c->ptr.s = buf; - g_hash_table_insert(uzbl.comm.proto_var, - g_strdup(name), (gpointer) c); - } - return TRUE; -} - -enum {M_CMD, M_HTML}; -void -parse_cmd_line(const char *ctl_line, GString *result) { - size_t len=0; - - if((ctl_line[0] == '#') /* Comments */ - || (ctl_line[0] == ' ') - || (ctl_line[0] == '\n')) - ; /* ignore these lines */ - else { /* parse a command */ - gchar *ctlstrip; - gchar **tokens = NULL; - len = strlen(ctl_line); - - if (ctl_line[len - 1] == '\n') /* strip trailing newline */ - ctlstrip = g_strndup(ctl_line, len - 1); - else ctlstrip = g_strdup(ctl_line); - - tokens = g_strsplit(ctlstrip, " ", 2); - parse_command(tokens[0], tokens[1], result); - g_free(ctlstrip); - g_strfreev(tokens); - } -} - -/*@null@*/ gchar* -build_stream_name(int type, const gchar* dir) { - State *s = &uzbl.state; - gchar *str = NULL; - - if (type == FIFO) { - str = g_strdup_printf - ("%s/uzbl_fifo_%s", dir, s->instance_name); - } else if (type == SOCKET) { - str = g_strdup_printf - ("%s/uzbl_socket_%s", dir, s->instance_name); - } - return str; -} - -gboolean -control_fifo(GIOChannel *gio, GIOCondition condition) { - if (uzbl.state.verbose) - printf("triggered\n"); - gchar *ctl_line; - GIOStatus ret; - GError *err = NULL; - - if (condition & G_IO_HUP) - g_error ("Fifo: Read end of pipe died!\n"); - - if(!gio) - g_error ("Fifo: GIOChannel broke\n"); - - ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err); - if (ret == G_IO_STATUS_ERROR) { - g_error ("Fifo: Error reading: %s\n", err->message); - g_error_free (err); - } - - parse_cmd_line(ctl_line, NULL); - g_free(ctl_line); - - return TRUE; -} - -/*@null@*/ gchar* -init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ - if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */ - if (unlink(uzbl.comm.fifo_path) == -1) - g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path); - g_free(uzbl.comm.fifo_path); - uzbl.comm.fifo_path = NULL; - } - - GIOChannel *chan = NULL; - GError *error = NULL; - gchar *path = build_stream_name(FIFO, dir); - - if (!file_exists(path)) { - if (mkfifo (path, 0666) == 0) { - // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file. - chan = g_io_channel_new_file(path, "r+", &error); - if (chan) { - if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { - if (uzbl.state.verbose) - printf ("init_fifo: created successfully as %s\n", path); - send_event(FIFO_SET, path); - uzbl.comm.fifo_path = path; - return dir; - } else g_warning ("init_fifo: could not add watch on %s\n", path); - } else g_warning ("init_fifo: can't open: %s\n", error->message); - } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno)); - } else g_warning ("init_fifo: can't create %s: file exists\n", path); - - /* if we got this far, there was an error; cleanup */ - if (error) g_error_free (error); - g_free(dir); - g_free(path); - return NULL; -} - -gboolean -control_stdin(GIOChannel *gio, GIOCondition condition) { - (void) condition; - gchar *ctl_line = NULL; - GIOStatus ret; - - ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL); - if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) - return FALSE; - - parse_cmd_line(ctl_line, NULL); - g_free(ctl_line); - - return TRUE; -} - -void -create_stdin () { - GIOChannel *chan = NULL; - GError *error = NULL; - - chan = g_io_channel_unix_new(fileno(stdin)); - if (chan) { - if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) { - g_error ("Stdin: could not add watch\n"); - } else { - if (uzbl.state.verbose) - printf ("Stdin: watch added successfully\n"); - } - } else { - g_error ("Stdin: Error while opening: %s\n", error->message); - } - if (error) g_error_free (error); -} - -gboolean -control_socket(GIOChannel *chan) { - struct sockaddr_un remote; - unsigned int t = sizeof(remote); - int clientsock; - GIOChannel *clientchan; - - clientsock = accept (g_io_channel_unix_get_fd(chan), - (struct sockaddr *) &remote, &t); - - if ((clientchan = g_io_channel_unix_new(clientsock))) { - g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP, - (GIOFunc) control_client_socket, clientchan); - } - - return TRUE; -} - -gboolean -control_client_socket(GIOChannel *clientchan) { - char *ctl_line; - GString *result = g_string_new(""); - GError *error = NULL; - GIOStatus ret; - gsize len; - - ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error reading: %s\n", error->message); - g_io_channel_shutdown(clientchan, TRUE, &error); - return FALSE; - } else if (ret == G_IO_STATUS_EOF) { - /* shutdown and remove channel watch from main loop */ - g_io_channel_shutdown(clientchan, TRUE, &error); - return FALSE; - } - - if (ctl_line) { - parse_cmd_line (ctl_line, result); - g_string_append_c(result, '\n'); - ret = g_io_channel_write_chars (clientchan, result->str, result->len, - &len, &error); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error writing: %s", error->message); - } - g_io_channel_flush(clientchan, &error); - } - - if (error) g_error_free (error); - g_string_free(result, TRUE); - g_free(ctl_line); - return TRUE; -} - -/*@null@*/ gchar* -init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */ - if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */ - if (unlink(uzbl.comm.socket_path) == -1) - g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path); - g_free(uzbl.comm.socket_path); - uzbl.comm.socket_path = NULL; - } - - if (*dir == ' ') { - g_free(dir); - return NULL; - } - - GIOChannel *chan = NULL; - int sock, len; - struct sockaddr_un local; - gchar *path = build_stream_name(SOCKET, dir); - - sock = socket (AF_UNIX, SOCK_STREAM, 0); - - local.sun_family = AF_UNIX; - strcpy (local.sun_path, path); - unlink (local.sun_path); - - len = strlen (local.sun_path) + sizeof (local.sun_family); - if (bind (sock, (struct sockaddr *) &local, len) != -1) { - if (uzbl.state.verbose) - printf ("init_socket: opened in %s\n", path); - listen (sock, 5); - - 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; - return dir; - } - } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno)); - - /* if we got this far, there was an error; cleanup */ - g_free(path); - g_free(dir); - return NULL; -} - -/* - NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state - it will probably improve performance if we would "cache" the processed variant, but for now it works well enough... -*/ -// this function may be called very early when the templates are not set (yet), hence the checks -void -update_title (void) { - Behaviour *b = &uzbl.behave; - gchar *parsed; - - if (b->show_status) { - if (b->title_format_short) { - parsed = expand(b->title_format_short, 0); - if (uzbl.gui.main_window) - gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); - g_free(parsed); - } - if (b->status_format) { - parsed = expand(b->status_format, 0); - gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed); - g_free(parsed); - } - if (b->status_background) { - GdkColor color; - gdk_color_parse (b->status_background, &color); - //labels and hboxes do not draw their own background. applying this on the vbox/main_window is ok as the statusbar is the only affected widget. (if not, we could also use GtkEventBox) - if (uzbl.gui.main_window) - gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color); - else if (uzbl.gui.plug) - gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color); - } - } else { - if (b->title_format_long) { - parsed = expand(b->title_format_long, 0); - if (uzbl.gui.main_window) - gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed); - g_free(parsed); - } - } -} - -gboolean -configure_event_cb(GtkWidget* window, GdkEventConfigure* event) { - (void) window; - (void) event; - - retrieve_geometry(); - send_event(GEOMETRY_CHANGED, uzbl.gui.geometry); - return FALSE; -} - -gboolean -key_press_cb (GtkWidget* window, GdkEventKey* event) -{ - //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further. - - (void) window; - - if(event->type == GDK_KEY_PRESS) - send_event(KEY_PRESS, gdk_keyval_name(event->keyval) ); - - if (event->type != GDK_KEY_PRESS || - event->keyval == GDK_Page_Up || - event->keyval == GDK_Page_Down || - event->keyval == GDK_Home || - event->keyval == GDK_End || - event->keyval == GDK_Up || - event->keyval == GDK_Down || - event->keyval == GDK_Left || - event->keyval == GDK_Right || - event->keyval == GDK_Shift_L || - event->keyval == GDK_Shift_R) - return FALSE; - - if (uzbl.behave.insert_mode && - ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || - (!uzbl.behave.modmask) - ) - ) - return FALSE; - - return TRUE; -} - -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; - - if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) { - clear_keycmd(); - parse_command(act->name, act->param, NULL); - - tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); - send_event(COMMAND_EXECUTED, tmp); - g_free(tmp); - return; - } - - /* try if it's an incremental keycmd or one that takes args, and run it */ - GString* short_keys = g_string_new (""); - GString* short_keys_inc = g_string_new (""); - guint i; - guint len = strlen(uzbl.state.keycmd); - for (i=0; istr); - g_string_append_c(short_keys, '_'); - g_string_append_c(short_keys_inc, '*'); - - if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) { - /* run normal cmds only if return was pressed */ - exec_paramcmd(act, i); - clear_keycmd(); - tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); - send_event(COMMAND_EXECUTED, tmp); - g_free(tmp); - break; - } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) { - if (key_ret) /* just quit the incremental command on return */ - clear_keycmd(); - else { - exec_paramcmd(act, i); /* otherwise execute the incremental */ - tmp = g_strdup_printf("%s %s", act->name, act->param?act->param:""); - send_event(COMMAND_EXECUTED, tmp); - g_free(tmp); - } - break; - } - - g_string_truncate(short_keys, short_keys->len - 1); - } - g_string_free (short_keys, TRUE); - g_string_free (short_keys_inc, TRUE); -} - -void -exec_paramcmd(const Action *act, const guint i) { - GString *parampart = g_string_new (uzbl.state.keycmd); - GString *actionname = g_string_new (""); - GString *actionparam = g_string_new (""); - g_string_erase (parampart, 0, i+1); - if (act->name) - g_string_printf (actionname, act->name, parampart->str); - if (act->param) - g_string_printf (actionparam, act->param, parampart->str); - parse_command(actionname->str, actionparam->str, NULL); - g_string_free(actionname, TRUE); - g_string_free(actionparam, TRUE); - g_string_free(parampart, TRUE); -} - - -void -create_browser () { - GUI *g = &uzbl.gui; - - g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); - - g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL); - g_signal_connect (G_OBJECT (g->web_view), "selection-changed", G_CALLBACK (selection_changed_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "load-error", G_CALLBACK (load_error_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view); - g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view); -} - -GtkWidget* -create_mainbar () { - GUI *g = &uzbl.gui; - - g->mainbar = gtk_hbox_new (FALSE, 0); - - /* keep a reference to the bar so we can re-pack it at runtime*/ - //sbar_ref = g_object_ref(g->mainbar); - - g->mainbar_label = gtk_label_new (""); - gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE); - gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END); - gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0); - gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2); - gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0); - g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL); - return g->mainbar; -} - -GtkWidget* -create_window () { - GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); - gtk_widget_set_name (window, "Uzbl browser"); - g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL); - g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL); - g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL); - - return window; -} - -GtkPlug* -create_plug () { - GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id)); - g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL); - g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL); - - return plug; -} - - -gchar** -inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) { - /* - If actname is one that calls an external command, this function will inject - newargs in front of the user-provided args in that command line. They will - come become after the body of the script (in sh) or after the name of - the command to execute (in spawn). - i.e. sh becomes sh and - spawn becomes spawn . - - The return value consist of two strings: the action (sh, ...) and its args. - - If act is not one that calls an external command, then the given action merely - gets duplicated. - */ - GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*)); - /* Arrr! Here be memory leaks */ - gchar *actdup = g_strdup(actname); - g_array_append_val(rets, actdup); - - if ((g_strcmp0(actname, "spawn") == 0) || - (g_strcmp0(actname, "sh") == 0) || - (g_strcmp0(actname, "sync_spawn") == 0) || - (g_strcmp0(actname, "sync_sh") == 0) || - (g_strcmp0(actname, "talk_to_socket") == 0)) { - guint i; - GString *a = g_string_new(""); - gchar **spawnparts = split_quoted(origargs, FALSE); - g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */ - if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */ - - for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ - if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]); - - g_array_append_val(rets, a->str); - g_string_free(a, FALSE); - g_strfreev(spawnparts); - } else { - gchar *origdup = g_strdup(origargs); - g_array_append_val(rets, origdup); - } - return (gchar**)g_array_free(rets, FALSE); -} - -void -run_handler (const gchar *act, const gchar *args) { - /* Consider this code a temporary hack to make the handlers usable. - In practice, all this splicing, injection, and reconstruction is - inefficient, annoying and hard to manage. Potential pitfalls arise - when the handler specific args 1) are not quoted (the handler - callbacks should take care of this) 2) are quoted but interfere - with the users' own quotation. A more ideal solution is - to refactor parse_command so that it doesn't just take a string - and execute it; rather than that, we should have a function which - returns the argument vector parsed from the string. This vector - could be modified (e.g. insert additional args into it) before - passing it to the next function that actually executes it. Though - it still isn't perfect for chain actions.. will reconsider & re- - factor when I have the time. -duc */ - - char **parts = g_strsplit(act, " ", 2); - if (!parts) return; - if (g_strcmp0(parts[0], "chain") == 0) { - GString *newargs = g_string_new(""); - gchar **chainparts = split_quoted(parts[1], FALSE); - - /* for every argument in the chain, inject the handler args - and make sure the new parts are wrapped in quotes */ - gchar **cp = chainparts; - gchar quot = '\''; - gchar *quotless = NULL; - gchar **spliced_quotless = NULL; // sigh -_-; - gchar **inpart = NULL; - - while (*cp) { - if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */ - quot = **cp; - quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2); - } else quotless = g_strdup(*cp); - - spliced_quotless = g_strsplit(quotless, " ", 2); - inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args); - g_strfreev(spliced_quotless); - - g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot); - g_free(quotless); - g_strfreev(inpart); - cp++; - } - - parse_command(parts[0], &(newargs->str[1]), NULL); - g_string_free(newargs, TRUE); - g_strfreev(chainparts); - - } else { - gchar **inparts = inject_handler_args(parts[0], parts[1], args); - parse_command(inparts[0], inparts[1], NULL); - g_free(inparts[0]); - g_free(inparts[1]); - } - g_strfreev(parts); -} - -void -add_binding (const gchar *key, const gchar *act) { - char **parts = g_strsplit(act, " ", 2); - Action *action; - - if (!parts) - return; - - //Debug: - if (uzbl.state.verbose) - printf ("Binding %-10s : %s\n", key, act); - action = new_action(parts[0], parts[1]); - - if (g_hash_table_remove (uzbl.bindings, key)) - g_warning ("Overwriting existing binding for \"%s\"", key); - g_hash_table_replace(uzbl.bindings, g_strdup(key), action); - g_strfreev(parts); -} - -/*@null@*/ gchar* -get_xdg_var (XDG_Var xdg) { - const gchar* actual_value = getenv (xdg.environmental); - const gchar* home = getenv ("HOME"); - gchar* return_value; - - if (! actual_value || strcmp (actual_value, "") == 0) { - if (xdg.default_value) { - return_value = str_replace ("~", home, xdg.default_value); - } else { - return_value = NULL; - } - } else { - return_value = str_replace("~", home, actual_value); - } - - return return_value; -} - -/*@null@*/ gchar* -find_xdg_file (int xdg_type, const char* filename) { - /* xdg_type = 0 => config - xdg_type = 1 => data - xdg_type = 2 => cache*/ - - gchar* xdgv = get_xdg_var (XDG[xdg_type]); - gchar* temporary_file = g_strconcat (xdgv, filename, NULL); - g_free (xdgv); - - gchar* temporary_string; - char* saveptr; - char* buf; - - if (! file_exists (temporary_file) && xdg_type != 2) { - buf = get_xdg_var (XDG[3 + xdg_type]); - temporary_string = (char *) strtok_r (buf, ":", &saveptr); - g_free(buf); - - while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) { - g_free (temporary_file); - temporary_file = g_strconcat (temporary_string, filename, NULL); - } - } - - //g_free (temporary_string); - segfaults. - - if (file_exists (temporary_file)) { - return temporary_file; - } else { - g_free(temporary_file); - return NULL; - } -} -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); - } - - if (g_strcmp0(s->config_file, "-") == 0) { - s->config_file = NULL; - create_stdin(); - } - - else if (!s->config_file) { - s->config_file = find_xdg_file (0, "/uzbl/config"); - } - - if (s->config_file) { - GArray* lines = read_file_by_line (s->config_file); - int i = 0; - gchar* line; - - while ((line = g_array_index(lines, gchar*, i))) { - parse_cmd_line (line, NULL); - i ++; - g_free (line); - } - g_array_free (lines, TRUE); - } else { - if (uzbl.state.verbose) - printf ("No configuration file loaded.\n"); - } - - g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL); -} - -void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ - (void) session; - (void) user_data; - //if (!uzbl.behave.cookie_handler) - // return; - - soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); - GString *s = g_string_new (""); - SoupURI * soup_uri = soup_message_get_uri(msg); - 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) { - char *p = strchr(uzbl.comm.sync_stdout, '\n' ); - if ( p != NULL ) *p = '\0'; - soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout); - - } - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - - g_string_free(s, TRUE); -} - -void -save_cookies (SoupMessage *msg, gpointer user_data){ - (void) user_data; - GSList *ck; - char *cookie; - for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ - cookie = soup_cookie_to_set_cookie_header(ck->data); - SoupURI * soup_uri = soup_message_get_uri(msg); - 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); - } - g_slist_free(ck); -} - -/* --- WEBINSPECTOR --- */ -void -hide_window_cb(GtkWidget *widget, gpointer data) { - (void) data; - - gtk_widget_hide(widget); -} - -WebKitWebView* -create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){ - (void) data; - (void) page; - (void) web_inspector; - GtkWidget* scrolled_window; - GtkWidget* new_web_view; - GUI *g = &uzbl.gui; - - g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_signal_connect(G_OBJECT(g->inspector_window), "delete-event", - G_CALLBACK(hide_window_cb), NULL); - - gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector"); - gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300); - gtk_widget_show(g->inspector_window); - - scrolled_window = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window); - gtk_widget_show(scrolled_window); - - new_web_view = webkit_web_view_new(); - gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view); - - return WEBKIT_WEB_VIEW(new_web_view); -} - -gboolean -inspector_show_window_cb (WebKitWebInspector* inspector){ - (void) inspector; - gtk_widget_show(uzbl.gui.inspector_window); - - send_event(WEBINSPECTOR, "open"); - return TRUE; -} - -/* TODO: Add variables and code to make use of these functions */ -gboolean -inspector_close_window_cb (WebKitWebInspector* inspector){ - (void) inspector; - send_event(WEBINSPECTOR, "close"); - return TRUE; -} - -gboolean -inspector_attach_window_cb (WebKitWebInspector* inspector){ - (void) inspector; - return FALSE; -} - -gboolean -inspector_detach_window_cb (WebKitWebInspector* inspector){ - (void) inspector; - return FALSE; -} - -gboolean -inspector_uri_changed_cb (WebKitWebInspector* inspector){ - (void) inspector; - return FALSE; -} - -gboolean -inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){ - (void) inspector; - return FALSE; -} - -void -set_up_inspector() { - GUI *g = &uzbl.gui; - WebKitWebSettings *settings = view_settings(); - g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL); - - uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view); - g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL); - g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL); - g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL); - g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL); - g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL); - g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL); - - g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL); -} - -void -dump_var_hash(gpointer k, gpointer v, gpointer ud) { - (void) ud; - uzbl_cmdprop *c = v; - - if(!c->dump) - return; - - if(c->type == TYPE_STR) - printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " "); - else if(c->type == TYPE_INT) - printf("set %s = %d\n", (char *)k, *c->ptr.i); - else if(c->type == TYPE_FLOAT) - printf("set %s = %f\n", (char *)k, *c->ptr.f); -} - -void -dump_key_hash(gpointer k, gpointer v, gpointer ud) { - (void) ud; - Action *a = v; - - printf("bind %s = %s %s\n", (char *)k , - (char *)a->name, a->param?(char *)a->param:""); -} - -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); -} - -void -retrieve_geometry() { - int w, h, x, y; - GString *buf = g_string_new(""); - - gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h); - gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y); - - g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y); - - if(uzbl.gui.geometry) - g_free(uzbl.gui.geometry); - uzbl.gui.geometry = g_string_free(buf, FALSE); -} - -/* set up gtk, gobject, variable defaults and other things that tests and other - * external applications need to do anyhow */ -void -initialize(int argc, char *argv[]) { - if (!g_thread_supported ()) - g_thread_init (NULL); - uzbl.state.executable_path = g_strdup(argv[0]); - uzbl.state.selected_url = NULL; - uzbl.state.searchtx = NULL; - - GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default"); - g_option_context_add_main_entries (context, entries, NULL); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - g_option_context_parse (context, &argc, &argv, NULL); - g_option_context_free(context); - - if (uzbl.behave.print_version) { - printf("Commit: %s\n", COMMIT); - exit(EXIT_SUCCESS); - } - - /* initialize hash table */ - uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); - - uzbl.net.soup_session = webkit_get_default_session(); - uzbl.state.keycmd = g_strdup(""); - - if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR) - fprintf(stderr, "uzbl: error hooking SIGTERM\n"); - if(setup_signal(SIGINT, catch_sigint) == SIG_ERR) - fprintf(stderr, "uzbl: error hooking SIGINT\n"); - - uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h - uzbl.gui.sbar.progress_u = g_strdup("·"); - uzbl.gui.sbar.progress_w = 10; - - /* default mode indicators */ - uzbl.behave.insert_indicator = g_strdup("I"); - uzbl.behave.cmd_indicator = g_strdup("C"); - - uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION; - uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION; - uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION; - uzbl.info.arch = ARCH; - uzbl.info.commit = COMMIT; - - commands_hash (); - create_var_to_name_hash(); - - create_browser(); -} - -#ifndef UZBL_LIBRARY -/** -- MAIN -- **/ -int -main (int argc, char* argv[]) { - initialize(argc, argv); - - gtk_init (&argc, &argv); - - uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL); - //main_window_ref = g_object_ref(scrolled_window); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win), - GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does - - gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win), - GTK_WIDGET (uzbl.gui.web_view)); - - uzbl.gui.vbox = gtk_vbox_new (FALSE, 0); - - create_mainbar(); - - /* initial packing */ - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); - - if (uzbl.state.socket_id) { - uzbl.gui.plug = create_plug (); - gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox); - gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug)); - } else { - uzbl.gui.main_window = create_window (); - gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); - gtk_widget_show_all (uzbl.gui.main_window); - uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window); - } - - if(!uzbl.state.instance_name) - uzbl.state.instance_name = itos((int)uzbl.xwin); - - gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); - - if (uzbl.state.verbose) { - printf("Uzbl start location: %s\n", argv[0]); - if (uzbl.state.socket_id) - printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug)); - else - printf("window_id %i\n",(int) uzbl.xwin); - printf("pid %i\n", getpid ()); - printf("name: %s\n", uzbl.state.instance_name); - printf("commit: %s\n", uzbl.info.commit); - } - - uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); - uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v); - uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); - uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h); - gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v); - - /* Check uzbl is in window mode before getting/setting geometry */ - if (uzbl.gui.main_window) { - if(uzbl.gui.geometry) - cmd_set_geometry(); - else - retrieve_geometry(); - } - - gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL); - if (argc > 1 && !uzbl.state.uri) - uri_override = g_strdup(argv[1]); - gboolean verbose_override = uzbl.state.verbose; - - settings_init (); - - if (!uzbl.behave.always_insert_mode) - set_insert_mode(FALSE); - - if (!uzbl.behave.show_status) - gtk_widget_hide(uzbl.gui.mainbar); - else - update_title(); - - /* WebInspector */ - set_up_inspector(); - - if (verbose_override > uzbl.state.verbose) - uzbl.state.verbose = verbose_override; - - if (uri_override) { - set_var_value("uri", uri_override); - g_free(uri_override); - } else if (uzbl.state.uri) - cmd_load_uri(); - - gtk_main (); - clean_up(); - - return EXIT_SUCCESS; -} -#endif - -/* vi: set et ts=4: */ diff --git a/uzbl.h b/uzbl.h deleted file mode 100644 index 8be3a1c..0000000 --- a/uzbl.h +++ /dev/null @@ -1,607 +0,0 @@ -/* -*- c-basic-offset: 4; -*- - - * See LICENSE for license details - * - * Changelog: - * --------- - * - * (c) 2009 by Robert Manea - * - introduced struct concept - * - statusbar template - * - */ - -/* status bar elements */ -typedef struct { - gint load_progress; - gchar *msg; - gchar *progress_s, *progress_u; - int progress_w; - gchar *progress_bar; - gchar *mode_indicator; -} StatusBar; - - -/* gui elements */ -typedef struct { - GtkWidget* main_window; - gchar* geometry; - GtkPlug* plug; - GtkWidget* scrolled_win; - GtkWidget* vbox; - GtkWidget* mainbar; - GtkWidget* mainbar_label; - GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar - GtkScrollbar* scbar_h; // (These are still hidden) - GtkAdjustment* bar_v; // Information about document length - GtkAdjustment* bar_h; // and scrolling position - WebKitWebView* web_view; - gchar* main_title; - gchar* icon; - - /* WebInspector */ - GtkWidget *inspector_window; - WebKitWebInspector *inspector; - - StatusBar sbar; -} GUI; - - -/* external communication*/ -enum { FIFO, SOCKET}; -typedef struct { - gchar *fifo_path; - gchar *socket_path; - /* stores (key)"variable name" -> (value)"pointer to this var*/ - GHashTable *proto_var; - - gchar *sync_stdout; -} Communication; - - -/* internal state */ -typedef struct { - gchar *uri; - gchar *config_file; - int socket_id; - char *instance_name; - gchar *selected_url; - gchar *executable_path; - gchar* keycmd; - gchar* searchtx; - gboolean verbose; -} State; - - -/* networking */ -typedef struct { - SoupSession *soup_session; - SoupLogger *soup_logger; - char *proxy_url; - char *useragent; - gint max_conns; - gint max_conns_host; -} Network; - - -/* behaviour */ -typedef struct { - gchar* load_finish_handler; - gchar* load_start_handler; - gchar* load_commit_handler; - gchar* status_format; - gchar* title_format_short; - gchar* title_format_long; - gchar* status_background; - gchar* fifo_dir; - gchar* socket_dir; - gchar* download_handler; - gchar* cookie_handler; - gchar* new_window; - gchar* default_font_family; - gchar* monospace_font_family; - gchar* sans_serif_font_family; - gchar* serif_font_family; - gchar* fantasy_font_family; - gchar* cursive_font_family; - gchar* scheme_handler; - gboolean always_insert_mode; - gboolean show_status; - gboolean insert_mode; - gboolean status_top; - gboolean reset_command_mode; - gchar* modkey; - guint modmask; - guint http_debug; - gchar* shell_cmd; - /* WebKitWebSettings exports */ - guint font_size; - guint monospace_size; - guint minimum_font_size; - gfloat zoom_level; - guint disable_plugins; - guint disable_scripts; - guint autoload_img; - guint autoshrink_img; - guint enable_spellcheck; - guint enable_private; - guint print_bg; - gchar* style_uri; - guint resizable_txt; - gchar* default_encoding; - guint enforce_96dpi; - gchar *inject_html; - guint caret_browsing; - guint mode; - gchar* base_url; - gchar* insert_indicator; - gchar* cmd_indicator; - gboolean print_version; - - /* command list: (key)name -> (value)Command */ - GHashTable* commands; - /* event lookup: (key)event_id -> (value)event_name */ - GHashTable *event_lookup; -} Behaviour; - -/* javascript */ -typedef struct { - gboolean initialized; - JSClassDefinition classdef; - JSClassRef classref; -} Javascript; - -/* static information */ -typedef struct { - int webkit_major; - int webkit_minor; - int webkit_micro; - gchar *arch; - gchar *commit; -} Info; - -/* main uzbl data structure */ -typedef struct { - GUI gui; - State state; - Network net; - Behaviour behave; - Communication comm; - Javascript js; - Info info; - - Window xwin; - - /* group bindings: key -> action */ - GHashTable* bindings; -} Uzbl; - - -typedef struct { - char* name; - char* param; -} Action; - -typedef void sigfunc(int); - -/* Event system */ -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, - - /* must be last entry */ - LAST_EVENT -}; - -/* XDG Stuff */ -typedef struct { - gchar* environmental; - gchar* default_value; -} XDG_Var; - -XDG_Var XDG[] = -{ - { "XDG_CONFIG_HOME", "~/.config" }, - { "XDG_DATA_HOME", "~/.local/share" }, - { "XDG_CACHE_HOME", "~/.cache" }, - { "XDG_CONFIG_DIRS", "/etc/xdg" }, - { "XDG_DATA_DIRS", "/usr/local/share/:/usr/share/" }, -}; - -/* Functions */ -char * -itos(int val); - -char * -str_replace (const char* search, const char* replace, const char* string); - -GArray* -read_file_by_line (const gchar *path); - -gchar* -parseenv (char* string); - -void -clean_up(void); - -void -catch_sigterm(int s); - -sigfunc * -setup_signal(int signe, sigfunc *shandler); - -gboolean -set_var_value(const gchar *name, gchar *val); - -void -print(WebKitWebView *page, GArray *argv, GString *result); - -gboolean -navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); - -gboolean -new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data); - -gboolean -mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data); - -/*@null@*/ WebKitWebView* -create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data); - -gboolean -download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data); - -void -toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result); - -void -toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result); - -void -link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data); - -void -title_change_cb (WebKitWebView* web_view, GParamSpec param_spec); - -void -progress_change_cb (WebKitWebView* page, gint progress, gpointer data); - -void -load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); - -void -load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); - -void -load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data); - -void -selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud); - -void -destroy_cb (GtkWidget* widget, gpointer data); - -void -commands_hash(void); - -void -free_action(gpointer act); - -Action* -new_action(const gchar *name, const gchar *param); - -bool -file_exists (const char * filename); - -void -set_keycmd(); - -void -set_mode_indicator(); - -void -update_indicator(); - -void -set_insert_mode(gboolean mode); - -void -toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result); - -void -load_uri (WebKitWebView * web_view, GArray *argv, GString *result); - -void -new_window_load_uri (const gchar * uri); - -void -chain (WebKitWebView *page, GArray *argv, GString *result); - -void -keycmd (WebKitWebView *page, GArray *argv, GString *result); - -void -keycmd_nl (WebKitWebView *page, GArray *argv, GString *result); - -void -keycmd_bs (WebKitWebView *page, GArray *argv, GString *result); - -void -close_uzbl (WebKitWebView *page, GArray *argv, GString *result); - -gboolean -run_command(const gchar *command, const guint npre, - const gchar **args, const gboolean sync, char **output_stdout); - -char* -build_progressbar_ascii(int percent); - -void -talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result); - -void -parse_command(const char *cmd, const char *param, GString *result); - -void -parse_cmd_line(const char *ctl_line, GString *result); - -/*@null@*/ gchar* -build_stream_name(int type, const gchar *dir); - -gboolean -control_fifo(GIOChannel *gio, GIOCondition condition); - -/*@null@*/ gchar* -init_fifo(gchar *dir); - -gboolean -control_stdin(GIOChannel *gio, GIOCondition condition); - -void -create_stdin(); - -/*@null@*/ gchar* -init_socket(gchar *dir); - -gboolean -control_socket(GIOChannel *chan); - -gboolean -control_client_socket(GIOChannel *chan); - -void -update_title (void); - -gboolean -key_press_cb (GtkWidget* window, GdkEventKey* event); - -void -run_keycmd(const gboolean key_ret); - -void -exec_paramcmd(const Action* act, const guint i); - -void -initialize (int argc, char *argv[]); - -void -create_browser (); - -GtkWidget* -create_mainbar (); - -GtkWidget* -create_window (); - -GtkPlug* -create_plug (); - -void -run_handler (const gchar *act, const gchar *args); - -void -add_binding (const gchar *key, const gchar *act); - -/*@null@*/ gchar* -get_xdg_var (XDG_Var xdg); - -/*@null@*/ gchar* -find_xdg_file (int xdg_type, const char* filename); - -void -settings_init (); - -void -search_text (WebKitWebView *page, GArray *argv, const gboolean forward); - -void -search_forward_text (WebKitWebView *page, GArray *argv, GString *result); - -void -search_reverse_text (WebKitWebView *page, GArray *argv, GString *result); - -void -dehilight (WebKitWebView *page, GArray *argv, GString *result); - -void -run_js (WebKitWebView * web_view, GArray *argv, GString *result); - -void -run_external_js (WebKitWebView * web_view, GArray *argv, GString *result); - -void -eval_js(WebKitWebView * web_view, gchar *script, GString *result); - -void handle_cookies (SoupSession *session, - SoupMessage *msg, - gpointer user_data); -void -save_cookies (SoupMessage *msg, - gpointer user_data); - -void -set_var(WebKitWebView *page, GArray *argv, GString *result); - -void -act_bind(WebKitWebView *page, GArray *argv, GString *result); - -void -act_dump_config(); - -void -dump_var_hash(gpointer k, gpointer v, gpointer ud); - -void -dump_key_hash(gpointer k, gpointer v, gpointer ud); - -void -dump_config(); - -void -retrieve_geometry(); - -void -update_gui(WebKitWebView *page, GArray *argv, GString *result); - -gboolean -configure_event_cb(GtkWidget* window, GdkEventConfigure* event); - -typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result); -typedef struct { - Command function; - gboolean no_split; -} CommandInfo; - -/* Command callbacks */ -void -cmd_load_uri(); - -void -cmd_set_status(); - -void -set_proxy_url(); - -void -set_icon(); - -void -cmd_cookie_handler(); - -void -cmd_scheme_handler(); - -void -move_statusbar(); - -void -cmd_always_insert_mode(); - -void -cmd_http_debug(); - -void -cmd_max_conns(); - -void -cmd_max_conns_host(); - -/* exported WebKitWebSettings properties */ - -void -cmd_font_size(); - -void -cmd_default_font_family(); - -void -cmd_monospace_font_family(); - -void -cmd_sans_serif_font_family(); - -void -cmd_serif_font_family(); - -void -cmd_cursive_font_family(); - -void -cmd_fantasy_font_family(); - -void -cmd_zoom_level(); - -void -cmd_disable_plugins(); - -void -cmd_disable_scripts(); - -void -cmd_minimum_font_size(); - -void -cmd_fifo_dir(); - -void -cmd_socket_dir(); - -void -cmd_modkey(); - -void -cmd_useragent() ; - -void -cmd_autoload_img(); - -void -cmd_autoshrink_img(); - -void -cmd_enable_spellcheck(); - -void -cmd_enable_private(); - -void -cmd_print_bg(); - -void -cmd_style_uri(); - -void -cmd_resizable_txt(); - -void -cmd_default_encoding(); - -void -cmd_enforce_96dpi(); - -void -cmd_inject_html(); - -void -cmd_caret_browsing(); - -void -cmd_set_geometry(); - -/* vi: set et ts=4: */ -- cgit v1.2.3 From aa600e2b7611e9c81ced9b405ecd1b2dc14a1ff2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Sep 2009 01:33:36 +0800 Subject: event_messages.py rewrite with plugin support and two example plugins. --- examples/data/uzbl/scripts/event_manager.py | 523 +++++++++++++++++++--- examples/data/uzbl/scripts/plugins/dump_config.py | 11 + examples/data/uzbl/scripts/plugins/echo_keys.py | 16 + 3 files changed, 487 insertions(+), 63 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/dump_config.py create mode 100644 examples/data/uzbl/scripts/plugins/echo_keys.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index d6f4a36..65089c1 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -1,55 +1,90 @@ #!/usr/bin/env python -# Uzbl sample event manager +# Event Manager for Uzbl +# Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Dieter Plaetinck # # 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 . ''' -The Python Event Manager -======================== -Sample event manager written in python +E V E N T _ M A N A G E R . P Y +=============================== + +Some descriptive text here. Usage +===== + + uzbl | $XDG_DATA_HOME/uzbl/scripts/event_manager.py + +Todo ==== -uzbl | + + - 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 pprint +import socket +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.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] -} # End of config dictionary. + return os.path.join(os.environ['HOME'], default) -# buffer for building up commands -keycmd = '' +# 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]) + + def echo(msg): '''Prints only if the verbose flag has been set.''' @@ -57,57 +92,419 @@ def echo(msg): sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) -def error(msg): - '''Prints error message and exits.''' +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) + + # Load all plugins in the 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: + # Now remove bytecode. + pyc = os.path.join(self.plugin_dir, '%s.pyc' % plugin) + if os.path.exists(pyc): + os.remove(pyc) + + + def load_plugins(self): + + # Get a list of python files in the plugin_dir. + pluginlist = self._find_plugins() + + # Load the 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.') + + print "Loaded plugin: %r" % name + + except: + print_exc() + self._unload_plugin(name) + + + 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() + + +class UzblInstance: + '''Event manager for a uzbl instance.''' + + # Singleton plugin manager. + plugins = None + + def __init__(self): + '''Initialise event manager.''' + + 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.''' + + self._setcmd(key, value) + dict.__setitem__(self, key, value) + + self._config = ConfigDict(self.set) + + # Keep track of keys typed. + self.cmdbuffer = "" + + # Keep track of non-meta keys held. + self.heldkeys = [] + + # Keep track of meta keys held. + self.metaheld = [] + + # Hold classic bind commands. + self.binds = {} + + # Keep track of the mode. + self.mode = "command" + + # Event handlers + self.handlers = {} + + # Handler object id generator + self.nextid = counter().next + + # Fifo socket and socket file locations. + self.fifo_socket = None + self.socket_file = None + + # Outgoing socket + self._socketout = [] + self._socket = None + + # Outgoing fifo + self._fifoout = [] + + # Default send method + self.send = self._send_socket + + # Running flag + self._running = None + + # Incoming message buffer + self._buffer = "" + + # Initialise plugin manager + if not self.plugins: + self.plugins = PluginManager() - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - sys.exit(1) + # Call the init() function in every plugin. + self._init_plugins() -def fifo(msg): - '''Writes commands to uzbl's fifo, if the fifo path is known''' - 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 _get_config(self): + '''Return the uzbl config dictionary.''' -def submit_keycmd(): - '''Sends the updated keycmd to uzbl, which can render it and stuff''' + return self._config - fifo ('set keycmd = ' + keycmd) + # Set read-only config dict getter. + config = property(_get_config) -def main(): - '''Main function.''' + def _init_plugins(self): + '''Call the init() function in every plugin.''' - echo ("Init eventhandler") + pprint.pprint(self.plugins) + + for plugin in self.plugins.keys(): + try: + self.plugins[plugin].init(self) + + except: + print_exc() + + + def _flush(self): + '''Flush messages from the outgoing queue to the uzbl instance.''' + + if len(self._fifoout) and self.fifo_socket: + if os.path.exists(self.fifo_socket): + h = open(self.fifo_socket, 'w') + while len(self._fifoout): + msg = self._fifoout.pop(0) + print "Sending via fifo: %r" % msg + h.write("%s\n" % msg) + h.close() + + if len(self._socketout) and self.socket_file: + if not self._socket and os.path.exists(self.socket_file): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.socket_file) + self._socket = sock + + if self._socket: + while len(self._socketout): + msg = self._socketout.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._fifoout.append(msg) + self._flush() + + + def _send_socket(self, msg): + '''Send a command to the uzbl instance via the socket file.''' + + self._socketout.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.nextid() + d = {'handler': handler, 'args': args, 'kargs': kargs} + + self.handlers[event][id] = d + print "Added handler:", event, d + + # The unique id is returned so that the newly created event handler can + # be destroyed if need be. + 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(): + print "Removed handler:", self.handlers[event][id] + del self.handlers[event][id] + + + def bind(self, glob, cmd=None): + '''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) + + NOTE: This wont work yet but the groundwork has been layed out. + ''' + + if not cmd: + if glob in self.binds.keys(): + print "Deleted bind:", self.binds[glob] + del self.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 + + self.binds[glob] = d + print "Added bind:", d + + + 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 + try: + while self._running: + + # Poll for reading & errors from fd. + if select.select([fd,], [], [], 1)[0]: + self.read_from_fd(fd) + continue + + # Check that all messages have been purged from the out queue. + self._flush() + + except KeyboardInterrupt: + print + + + 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.''' + + if event == 'VARIABLE_SET': + l = args.split(' ', 1) + if len(l) == 1: + l.append("") + + key, value = l + dict.__setitem__(self._config, key, value) + + elif event == 'FIFO_SET': + self.fifo_socket = args + + # Workaround until SOCKET_SET is implemented. + self.socket_file = args.replace("fifo", "socket") + + elif event == 'SOCKET_SET': + self.socket_file = args + + # Now dispatch event to plugin's event handlers. + 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.''' + unhandled = True + + if event in self.handlers.keys(): + for hid in self.handlers[event]: + try: + unhandled = False + handler = self.handlers[event][hid] + print "Executing handler:", event, handler + self.exc_handler(handler, args) + + except: + print_exc() + + if unhandled: + print "Unhandled event:", event, args + + + 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/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) -- cgit v1.2.3 From 53ad9e51bbb04c3de86046663a81a43e2aba95cd Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Sep 2009 20:41:54 +0800 Subject: Config type checking, events +SOCKET_SET -COOKIE & dump config on load. --- examples/data/uzbl/scripts/event_manager.py | 48 +++++++++-------- uzbl-core.c | 84 ++++++++++++++++++----------- uzbl-core.h | 9 ++-- 3 files changed, 83 insertions(+), 58 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 65089c1..0332178 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -45,7 +45,6 @@ import sys import select import re import types -import pprint import socket from traceback import print_exc @@ -83,13 +82,13 @@ config = { # 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(): @@ -177,12 +176,13 @@ class PluginManager(dict): if not hasattr(plugin, 'init'): raise ImportError('plugin missing main "init" function.') - print "Loaded plugin: %r" % name - 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. @@ -214,6 +214,16 @@ class UzblInstance: '''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) @@ -280,8 +290,6 @@ class UzblInstance: def _init_plugins(self): '''Call the init() function in every plugin.''' - pprint.pprint(self.plugins) - for plugin in self.plugins.keys(): try: self.plugins[plugin].init(self) @@ -344,7 +352,7 @@ class UzblInstance: d = {'handler': handler, 'args': args, 'kargs': kargs} self.handlers[event][id] = d - print "Added handler:", event, d + echo("added handler for %s: %r" % (event, d)) # The unique id is returned so that the newly created event handler can # be destroyed if need be. @@ -356,7 +364,7 @@ class UzblInstance: for event in self.handlers.keys(): if id in self.handlers[event].keys(): - print "Removed handler:", self.handlers[event][id] + echo("removed handler %d" % id) del self.handlers[event][id] @@ -377,7 +385,7 @@ class UzblInstance: if not cmd: if glob in self.binds.keys(): - print "Deleted bind:", self.binds[glob] + echo("deleted bind: %r" % self.binds[glob]) del self.binds[glob] d = {'glob': glob, 'once': True, 'hasargs': True, 'cmd': cmd} @@ -394,7 +402,7 @@ class UzblInstance: d['hasargs'] = False self.binds[glob] = d - print "Added bind:", d + echo("added bind: %r" % d) def set(self, key, value): @@ -453,20 +461,19 @@ class UzblInstance: def handle_event(self, event, args): '''Handle uzbl events internally before dispatch.''' + print event, args + if event == 'VARIABLE_SET': - l = args.split(' ', 1) - if len(l) == 1: + l = args.split(' ', 2) + if len(l) == 2: l.append("") - key, value = l - dict.__setitem__(self._config, key, value) + key, type, value = l + dict.__setitem__(self._config, key, _TYPECONVERT[type](value)) elif event == 'FIFO_SET': self.fifo_socket = args - # Workaround until SOCKET_SET is implemented. - self.socket_file = args.replace("fifo", "socket") - elif event == 'SOCKET_SET': self.socket_file = args @@ -477,12 +484,10 @@ class UzblInstance: 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.''' - unhandled = True if event in self.handlers.keys(): for hid in self.handlers[event]: try: - unhandled = False handler = self.handlers[event][hid] print "Executing handler:", event, handler self.exc_handler(handler, args) @@ -490,9 +495,6 @@ class UzblInstance: except: print_exc() - if unhandled: - print "Unhandled event:", event, args - def exc_handler(self, d, args): '''Handle handler.''' diff --git a/uzbl-core.c b/uzbl-core.c index ad7dd56..9541cfa 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" }; @@ -1966,23 +1966,35 @@ set_var_value(const gchar *name, gchar *val) { if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { if(!c->writeable) return FALSE; + if (uzbl.state.config_loaded) + 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); + if (uzbl.state.config_loaded) + 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); + if (uzbl.state.config_loaded) + 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); + if (uzbl.state.config_loaded) + g_string_append_printf(msg, " float %f", *c->ptr.f); + } + + if (uzbl.state.config_loaded) { + send_event(VARIABLE_SET, msg->str); + g_string_free(msg,TRUE); } /* invoke a command specific function */ @@ -2006,6 +2018,13 @@ 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); + + if (uzbl.state.config_loaded) { + 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 +2254,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 +2312,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; } @@ -2331,7 +2351,7 @@ key_press_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; @@ -2641,6 +2661,8 @@ void settings_init () { State *s = &uzbl.state; Network *n = &uzbl.net; + uzbl.state.config_loaded = FALSE; + int i; for (i = 0; default_config[i].command != NULL; i++) { parse_cmd_line(default_config[i].command, NULL); @@ -2671,6 +2693,11 @@ settings_init () { printf ("No configuration file loaded.\n"); } + /* The config has now been loaded so dump the complete hash table for the + * event manager to parse */ + uzbl.state.config_loaded = TRUE; + dump_config(); + g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL); } @@ -2686,7 +2713,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) { @@ -2712,7 +2738,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); } @@ -2818,31 +2843,28 @@ void dump_var_hash(gpointer k, gpointer v, gpointer ud) { (void) ud; uzbl_cmdprop *c = v; + GString *msg; if(!c->dump) return; - if(c->type == TYPE_STR) - printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " "); - else if(c->type == TYPE_INT) - printf("set %s = %d\n", (char *)k, *c->ptr.i); - else if(c->type == TYPE_FLOAT) - printf("set %s = %f\n", (char *)k, *c->ptr.f); -} - -void -dump_key_hash(gpointer k, gpointer v, gpointer ud) { - (void) ud; - Action *a = v; + /* 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); } void diff --git a/uzbl-core.h b/uzbl-core.h index 010cbe5..bde1e43 100644 --- a/uzbl-core.h +++ b/uzbl-core.h @@ -70,6 +70,7 @@ typedef struct { gchar* keycmd; gchar* searchtx; gboolean verbose; + gboolean config_loaded; } State; @@ -188,10 +189,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 }; -- cgit v1.2.3 From d42e8ce6f1cc882b23cbc548f6112a1a050805c2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Sep 2009 22:34:37 +0800 Subject: Removed useless code comments & renamed ambiguous variable names. --- examples/data/uzbl/scripts/event_manager.py | 102 ++++++++++------------------ 1 file changed, 36 insertions(+), 66 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 0332178..1da4d58 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -22,7 +22,7 @@ E V E N T _ M A N A G E R . P Y =============================== -Some descriptive text here. +Event manager for uzbl written in python. Usage ===== @@ -108,7 +108,6 @@ class PluginManager(dict): if not os.path.exists(self.plugin_dir): os.makedirs(self.plugin_dir) - # Load all plugins in the plugin_dir. self.load_plugins() @@ -147,7 +146,6 @@ class PluginManager(dict): dict.__delitem__(self, plugin) if remove_pyc: - # Now remove bytecode. pyc = os.path.join(self.plugin_dir, '%s.pyc' % plugin) if os.path.exists(pyc): os.remove(pyc) @@ -155,10 +153,8 @@ class PluginManager(dict): def load_plugins(self): - # Get a list of python files in the plugin_dir. pluginlist = self._find_plugins() - # Load the plugins for name in pluginlist: try: # Make sure the plugin isn't already loaded. @@ -228,53 +224,30 @@ class UzblInstance: dict.__setitem__(self, key, value) self._config = ConfigDict(self.set) + self._running = None - # Keep track of keys typed. - self.cmdbuffer = "" - - # Keep track of non-meta keys held. - self.heldkeys = [] - - # Keep track of meta keys held. + self._cmdbuffer = [] + self.keysheld = [] self.metaheld = [] - - # Hold classic bind commands. - self.binds = {} - - # Keep track of the mode. self.mode = "command" - # Event handlers + self.binds = {} self.handlers = {} + self.nexthid = counter().next - # Handler object id generator - self.nextid = counter().next - - # Fifo socket and socket file locations. - self.fifo_socket = None - self.socket_file = None - - # Outgoing socket - self._socketout = [] + # 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 - - # Outgoing fifo - self._fifoout = [] - - # Default send method self.send = self._send_socket - # Running flag - self._running = None - - # Incoming message buffer - self._buffer = "" - - # Initialise plugin manager if not self.plugins: self.plugins = PluginManager() - # Call the init() function in every plugin. + # Call the init() function in every plugin which then setup their + # respective hooks (event handlers, binds or timers). self._init_plugins() @@ -283,7 +256,6 @@ class UzblInstance: return self._config - # Set read-only config dict getter. config = property(_get_config) @@ -301,24 +273,24 @@ class UzblInstance: def _flush(self): '''Flush messages from the outgoing queue to the uzbl instance.''' - if len(self._fifoout) and self.fifo_socket: - if os.path.exists(self.fifo_socket): - h = open(self.fifo_socket, 'w') - while len(self._fifoout): - msg = self._fifoout.pop(0) + 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._socketout) and self.socket_file: - if not self._socket and os.path.exists(self.socket_file): + 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.socket_file) + sock.connect(self.uzbl_socket) self._socket = sock if self._socket: - while len(self._socketout): - msg = self._socketout.pop(0) + 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) @@ -326,14 +298,14 @@ class UzblInstance: def _send_fifo(self, msg): '''Send a command to the uzbl instance via the fifo socket.''' - self._fifoout.append(msg) + 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._socketout.append(msg) + self._socket_cmd_queue.append(msg) self._flush() @@ -348,14 +320,12 @@ class UzblInstance: if event not in self.handlers.keys(): self.handlers[event] = {} - id = self.nextid() + id = self.nexthid() d = {'handler': handler, 'args': args, 'kargs': kargs} self.handlers[event][id] = d echo("added handler for %s: %r" % (event, d)) - # The unique id is returned so that the newly created event handler can - # be destroyed if need be. return id @@ -424,19 +394,20 @@ class UzblInstance: '''Main loop reading event messages from stdin.''' self._running = True - try: - while self._running: - - # Poll for reading & errors from fd. + while self._running: + try: if select.select([fd,], [], [], 1)[0]: self.read_from_fd(fd) continue - # Check that all messages have been purged from the out queue. self._flush() - except KeyboardInterrupt: - print + except KeyboardInterrupt: + self._running = False + print + + except: + print_exc() def read_from_fd(self, fd): @@ -472,12 +443,11 @@ class UzblInstance: dict.__setitem__(self._config, key, _TYPECONVERT[type](value)) elif event == 'FIFO_SET': - self.fifo_socket = args + self.uzbl_fifo = args elif event == 'SOCKET_SET': - self.socket_file = args + self.uzbl_socket = args - # Now dispatch event to plugin's event handlers. self.dispatch_event(event, args) -- cgit v1.2.3 From 556038dbc8dc48388c8a9e8d47bdfdd963565d96 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 7 Sep 2009 01:08:25 +0800 Subject: Added flush commands to internal event handlers FIFO_SET and SOCKET_SET --- examples/data/uzbl/scripts/event_manager.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 1da4d58..e293002 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -444,9 +444,11 @@ class UzblInstance: elif event == 'FIFO_SET': self.uzbl_fifo = args + self._flush() elif event == 'SOCKET_SET': self.uzbl_socket = args + self._flush() self.dispatch_event(event, args) -- cgit v1.2.3 From 97f12f6eee2c7ae24ac195b9cb76e41e86f58863 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 7 Sep 2009 04:31:26 +0800 Subject: Functions in plugins that look like "export_" become uzbl. --- examples/data/uzbl/scripts/event_manager.py | 96 +++++++++++++++++------------ examples/data/uzbl/scripts/plugins/bind.py | 49 +++++++++++++++ 2 files changed, 104 insertions(+), 41 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/bind.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index e293002..5145653 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -46,6 +46,7 @@ import select import re import types import socket +import pprint from traceback import print_exc @@ -193,7 +194,22 @@ class PluginManager(dict): self.load_plugins() -class UzblInstance: +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. @@ -202,6 +218,9 @@ class UzblInstance: def __init__(self): '''Initialise event manager.''' + # Hold functions exported by plugins. + self._exports = {} + class ConfigDict(dict): def __init__(self, setcmd): self._setcmd = setcmd @@ -251,6 +270,17 @@ class UzblInstance: self._init_plugins() + def __getattribute__(self, name): + '''Expose any exported functions before class functions.''' + + if not name.startswith('_'): + exports = object.__getattribute__(self, '_exports') + if name in exports: + return exports[name] + + return object.__getattribute__(self, name) + + def _get_config(self): '''Return the uzbl config dictionary.''' @@ -260,11 +290,27 @@ class UzblInstance: def _init_plugins(self): - '''Call the init() function in every plugin.''' + '''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 - for plugin in self.plugins.keys(): + 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: - self.plugins[plugin].init(self) + plugin.init(self) except: print_exc() @@ -338,43 +384,6 @@ class UzblInstance: del self.handlers[event][id] - def bind(self, glob, cmd=None): - '''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) - - NOTE: This wont work yet but the groundwork has been layed out. - ''' - - if not cmd: - if glob in self.binds.keys(): - echo("deleted bind: %r" % self.binds[glob]) - del self.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 - - self.binds[glob] = d - echo("added bind: %r" % d) - - def set(self, key, value): '''Sets key "key" with value "value" in the uzbl instance.''' @@ -450,6 +459,11 @@ class UzblInstance: 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) 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 -- cgit v1.2.3 From 16a17e589de1698929707abce828a9e8354b2b08 Mon Sep 17 00:00:00 2001 From: Jake Probst Date: Mon, 7 Sep 2009 19:59:27 +0800 Subject: Multiline tablist patch. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 44 ++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index b3a8053..40e03e5 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -37,6 +37,10 @@ # # Romain Bignon # Fix for session restoration code. +# +# Jake Probst +# Wrote a patch that overflows tabs in the tablist on to new lines when +# running of room. # Dependencies: @@ -65,6 +69,7 @@ # gtk_tab_pos = (top|left|bottom|right) # switch_to_new_tabs = 1 # capture_new_windows = 1 +# multiline_tabs = 1 # # Tab title options: # tab_titles = 1 @@ -207,6 +212,7 @@ if not os.path.exists(UZBL_CONFIG): # All of these settings can be inherited from your uzbl config file. config = { + 'multiline_tabs': True, # tabs wrap to the window # Tab options 'show_tablist': True, # Show text uzbl like statusbar tab-list 'show_gtk_tabs': False, # Show gtk notebook tabs @@ -535,6 +541,7 @@ class UzblTabbed: self.window.add(vbox) ebox = gtk.EventBox() self.tablist = gtk.Label() + self.tablist.set_use_markup(True) self.tablist.set_justify(gtk.JUSTIFY_LEFT) self.tablist.set_line_wrap(False) @@ -584,7 +591,6 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Generate the fifo socket filename. fifo_filename = 'uzbltabbed_%d' % os.getpid() self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) @@ -1147,6 +1153,7 @@ class UzblTabbed: return True + pangols = [] def update_tablist(self, curpage=None): '''Upate tablist status bar.''' @@ -1169,6 +1176,10 @@ class UzblTabbed: normal = (config['tab_colours'], config['tab_text_colours']) selected = (config['selected_tab'], config['selected_tab_text']) if tab_titles: + # ok this kinda shits itself when it truncates multibyte utf8 + # characters so heres a cheap fix: + tabtitle = unicode(tabtitle,"utf-8", "ignore").encode('utf-8') + tab_format = " [ %d %s ] " else: tab_format = " [ %d ] " @@ -1198,14 +1209,35 @@ class UzblTabbed: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style - if tab_titles: - pango += tab_format % (tabc, index, textc,\ - escape(tabtitle)) + if config['multiline_tabs']: + opango = pango + + if tab_titles: + pango += tab_format % (tabc, index, textc,\ + escape(tabtitle)) + else: + pango += tab_format % (tabc, textc, index) + self.tablist.set_markup(pango) + w = self.tablist.get_layout().get_pixel_size()[0] + ww = self.window.get_size()[0] + if w > ww-20: # 20 seems to be a good number + pangols.append(opango) + pango = tab_format % (tabc, index, textc,\ + escape(tabtitle)) else: - pango += tab_format % (tabc, textc, index) + if tab_titles: + pango += tab_format % (tabc, index, textc,\ + escape(tabtitle)) + else: + pango += tab_format % (tabc, textc, index) + if show_tablist: - self.tablist.set_markup(pango) + if config['multiline_tabs']: + pangols.append(pango) + self.tablist.set_markup(' '.join(pangols)) + else: + self.tablist.set_markup(pango) return True -- cgit v1.2.3 From a2e0e583fdd524a8865847555816d15175333e0c Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 7 Sep 2009 20:01:42 +0800 Subject: Fixed wonky patch & added in gtk_refresh option. --- examples/data/uzbl/scripts/uzbl_tabbed.py | 87 +++++++++++++++++++------------ 1 file changed, 53 insertions(+), 34 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index 40e03e5..f04b677 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -67,6 +67,7 @@ # show_gtk_tabs = 0 # tablist_top = 1 # gtk_tab_pos = (top|left|bottom|right) +# gtk_refresh = 1000 # switch_to_new_tabs = 1 # capture_new_windows = 1 # multiline_tabs = 1 @@ -169,6 +170,7 @@ import socket import random import hashlib import atexit +import types from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP from signal import signal, SIGTERM, SIGINT @@ -212,14 +214,15 @@ if not os.path.exists(UZBL_CONFIG): # All of these settings can be inherited from your uzbl config file. config = { - 'multiline_tabs': True, # tabs wrap to the window # Tab options 'show_tablist': True, # Show text uzbl like statusbar tab-list 'show_gtk_tabs': False, # Show gtk notebook tabs 'tablist_top': True, # Display tab-list at top of window 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) + 'gtk_refresh': 1000, # Tablist refresh millisecond interval 'switch_to_new_tabs': True, # Upon opening a new tab switch to it 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows + 'multiline_tabs': True, # Tabs overflow onto new tablist lines. # Tab title options 'tab_titles': True, # Display tab titles (else only tab-nums) @@ -609,15 +612,17 @@ class UzblTabbed: if not len(self.tabs): self.new_tab() + gtk_refresh = int(config['gtk_refresh']) + if gtk_refresh < 100: + gtk_refresh = 100 + # Update tablist timer - #timer = "update-tablist" - #timerid = timeout_add(500, self.update_tablist,timer) - #self._timers[timer] = timerid + timerid = timeout_add(gtk_refresh, self.update_tablist) + self._timers["update-tablist"] = timerid # Probe clients every second for window titles and location - timer = "probe-clients" - timerid = timeout_add(1000, self.probe_clients, timer) - self._timers[timer] = timerid + timerid = timeout_add(gtk_refresh, self.probe_clients) + self._timers["probe-clients"] = timerid # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) @@ -761,7 +766,7 @@ class UzblTabbed: return True - def probe_clients(self, timer_call): + def probe_clients(self): '''Probe all uzbl clients for up-to-date window titles and uri's.''' save_session = config['save_session'] @@ -1153,7 +1158,6 @@ class UzblTabbed: return True - pangols = [] def update_tablist(self, curpage=None): '''Upate tablist status bar.''' @@ -1161,6 +1165,11 @@ class UzblTabbed: show_gtk_tabs = config['show_gtk_tabs'] tab_titles = config['tab_titles'] show_ellipsis = config['show_ellipsis'] + multiline_tabs = config['multiline_tabs'] + + if multiline_tabs: + multiline = [] + if not show_tablist and not show_gtk_tabs: return True @@ -1175,12 +1184,10 @@ class UzblTabbed: pango = "" normal = (config['tab_colours'], config['tab_text_colours']) selected = (config['selected_tab'], config['selected_tab_text']) - if tab_titles: - # ok this kinda shits itself when it truncates multibyte utf8 - # characters so heres a cheap fix: - tabtitle = unicode(tabtitle,"utf-8", "ignore").encode('utf-8') + if tab_titles: tab_format = " [ %d %s ] " + else: tab_format = " [ %d ] " @@ -1194,14 +1201,22 @@ class UzblTabbed: if index == curpage: self.window.set_title(title_format % uzbl.title) - tabtitle = uzbl.title[:max_title_len] + # Unicode heavy strings do not like being truncated/sliced so by + # re-encoding the string sliced of limbs are removed. + tabtitle = uzbl.title[:max_title_len + int(show_ellipsis)] + if type(tabtitle) != types.UnicodeType: + tabtitle = unicode(tabtitle, 'utf-8', 'ignore') + + tabtitle = tabtitle.encode('utf-8', 'ignore').strip() + if show_ellipsis and len(tabtitle) != len(uzbl.title): - tabtitle = "%s\xe2\x80\xa6" % tabtitle[:-1] # Show Ellipsis + tabtitle += "\xe2\x80\xa6" if show_gtk_tabs: if tab_titles: - self.notebook.set_tab_label_text(tab,\ + self.notebook.set_tab_label_text(tab, gtk_tab_format % (index, tabtitle)) + else: self.notebook.set_tab_label_text(tab, str(index)) @@ -1209,33 +1224,37 @@ class UzblTabbed: style = colour_selector(index, curpage, uzbl) (tabc, textc) = style - if config['multiline_tabs']: + if multiline_tabs: opango = pango if tab_titles: - pango += tab_format % (tabc, index, textc,\ - escape(tabtitle)) + pango += tab_format % (tabc, index, textc, + escape(tabtitle)) + else: pango += tab_format % (tabc, textc, index) + self.tablist.set_markup(pango) - w = self.tablist.get_layout().get_pixel_size()[0] - ww = self.window.get_size()[0] - if w > ww-20: # 20 seems to be a good number - pangols.append(opango) - pango = tab_format % (tabc, index, textc,\ - escape(tabtitle)) - else: - if tab_titles: - pango += tab_format % (tabc, index, textc,\ - escape(tabtitle)) - else: - pango += tab_format % (tabc, textc, index) + listwidth = self.tablist.get_layout().get_pixel_size()[0] + winwidth = self.window.get_size()[0] + + if listwidth > (winwidth - 20): + multiline.append(opango) + pango = tab_format % (tabc, index, textc, + escape(tabtitle)) + elif tab_titles: + pango += tab_format % (tabc, index, textc, + escape(tabtitle)) + + else: + pango += tab_format % (tabc, textc, index) if show_tablist: - if config['multiline_tabs']: - pangols.append(pango) - self.tablist.set_markup(' '.join(pangols)) + if multiline_tabs: + multiline.append(pango) + self.tablist.set_markup(' '.join(multiline)) + else: self.tablist.set_markup(pango) -- cgit v1.2.3 From bb6d7ea31a56ebd43eb5e820877edad56f91b9b2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 00:41:56 +0800 Subject: Custom event raising, added keycmd plugin & made handler class. --- examples/data/uzbl/scripts/event_manager.py | 228 +++++++++++++++------- examples/data/uzbl/scripts/plugins/dump_config.py | 13 +- examples/data/uzbl/scripts/plugins/echo_keys.py | 7 +- examples/data/uzbl/scripts/plugins/keycmd.py | 97 +++++++++ 4 files changed, 261 insertions(+), 84 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/keycmd.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 5145653..967fe39 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -101,6 +101,18 @@ def counter(): yield i +def iscallable(obj): + '''Return true if the object is callable.''' + + return hasattr(obj, "__call__") + + +def isiterable(obj): + '''Return true if you can iterate over the item.''' + + return hasattr(obj, "__iter__") + + class PluginManager(dict): def __init__(self): @@ -194,19 +206,83 @@ class PluginManager(dict): 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 CallPrepender(object): + '''Execution argument modifier. Takes (arg, function) then modifies the + function call: + + -> function(*args, **kargs) -> function(arg, *args, **kargs) ->''' + + def __init__(self, uzbl, function): + self.function = function + self.uzbl = uzbl + + def call(self, *args, **kargs): + return self.function(self.uzbl, *args, **kargs) + + +class Handler(object): + + nexthid = counter().next + + def __init__(self, uzbl, event, handler, *args, **kargs): + self._callable = iscallable(handler) + if self._callable: + self._function = handler + self._args = args + self._kargs = kargs + + elif kargs: + raise ArgumentError("cannot supply kargs with a uzbl command") + + elif isiterable(handler): + self._commands = handler + + else: + self._commands = [handler,] + list(args) + + self._uzbl = uzbl + self.event = event + self.hid = self.nexthid() + + + def exec_handler(self, *args, **kargs): + '''Execute either the handler function or send the uzbl commands to + the socket.''' + + if self._callable: + args = args + self._args + kargs = dict(self._kargs.items()+kargs.items()) + self._function(self._uzbl, *args, **kargs) + + else: + for command in self._commands: + if '%s' in command and len(args) == 1: + command.replace('%s', args[0]) + + elif '%s' in command: + for arg in args: + command.replace('%s', arg, 1) + + self._uzbl.send(command) - 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) + def __repr__(self): + args = ["event=%s" % self.event, "hid=%d" % self.hid] - return Export(uzbl, function).call + if self._callable: + args.append("function=%r" % self._function) + if self._args: + args.append("args=%r" % self.args) + + if self._kargs: + args.append("kargs=%r" % self.kargs) + + else: + cmdlen = len(self._commands) + cmds = self._commands[0] if cmdlen == 1 else self._commands + args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) + + return "" % ', '.join(args) class UzblInstance(object): @@ -215,44 +291,38 @@ class UzblInstance(object): # Singleton plugin manager. plugins = None - def __init__(self): - '''Initialise event manager.''' + # Internal uzbl config dict. + class ConfigDict(dict): + def __init__(self, setcmd): + self._setcmd = setcmd - # Hold functions exported by plugins. - self._exports = {} + def __setitem__(self, key, value): + '''Updates the config dict and relays any changes back to the + uzbl instance via the set function.''' - class ConfigDict(dict): - def __init__(self, setcmd): - self._setcmd = setcmd + if type(value) == types.BooleanType: + value = int(value) - def __setitem__(self, key, value): - '''Updates the config dict and relays any changes back to the - uzbl instance via the set function.''' + if key in self.keys() and type(value) != type(self[key]): + raise TypeError("%r for %r" % (type(value), key)) - if type(value) == types.BooleanType: - value = int(value) + else: + # All custom variables are strings. + value = "" if value is None else str(value) - if key in self.keys() and type(value) != type(self[key]): - raise TypeError("%r for %r" % (type(value), key)) + self._setcmd(key, value) + dict.__setitem__(self, key, value) - else: - # All custom variables are strings. - value = "" if value is None else str(value) - self._setcmd(key, value) - dict.__setitem__(self, key, value) + def __init__(self): + '''Initialise event manager.''' - self._config = ConfigDict(self.set) + # Hold functions exported by plugins. + self._exports = {} + self._config = self.ConfigDict(self.set) self._running = None - self._cmdbuffer = [] - self.keysheld = [] - self.metaheld = [] - self.mode = "command" - - self.binds = {} - self.handlers = {} - self.nexthid = counter().next + self._handlers = {} # Variables needed for fifo & socket communication with uzbl. self.uzbl_fifo = None @@ -300,8 +370,10 @@ class UzblInstance(object): continue obj = getattr(plugin, attr) - if type(obj) in [types.LambdaType, types.FunctionType]: - obj = export_wrapper(self, obj) + if iscallable(obj): + # Wrap the function in the CallPrepender object to make + # the exposed functions act like instance methods. + obj = CallPrepender(self, obj).call self._exports[attr[7:]] = obj @@ -356,32 +428,44 @@ class UzblInstance(object): 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. + '''Connect event with handler and return the newly created handler. + Handlers can either be a function or a uzbl command string.''' + + if event not in self._handlers.keys(): + self._handlers[event] = [] + + handler = Handler(self, event, handler, *args, **kargs) + self._handlers[event].append(handler) - 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.''' + print "New event handler:", handler + return handler - if event not in self.handlers.keys(): - self.handlers[event] = {} - id = self.nexthid() - d = {'handler': handler, 'args': args, 'kargs': kargs} + def remove_by_id(self, hid): + '''Remove connected event handler by unique handler id.''' - self.handlers[event][id] = d - echo("added handler for %s: %r" % (event, d)) + for (event, handlers) in self._handlers.items(): + for handler in list(handlers): + if hid != handler.hid: + continue - return id + echo("removed %r" % handler) + handlers.remove(handler) + return + echo('unable to find & remove handler with id: %d' % handler.hid) - 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 remove(self, handler): + '''Remove connected event handler.''' + + for (event, handlers) in self._handlers.items(): + if handler in handlers: + echo("removed %r" % handler) + handlers.remove(handler) + return + + echo('unable to find & remove handler: %r' % handler) def set(self, key, value): @@ -432,6 +516,7 @@ class UzblInstance(object): if not msg or msg[0] != "EVENT": # Not an event message + print raw.rstrip() return event, args = msg[1], msg[3] @@ -464,6 +549,7 @@ class UzblInstance(object): if hasattr(plugin, "cleanup"): plugin.cleanup(uzbl) + # Now handle the event "publically". self.dispatch_event(event, args) @@ -471,27 +557,27 @@ class UzblInstance(object): '''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]: + if event in self._handlers: + for handler in self._handlers[event]: try: - handler = self.handlers[event][hid] - print "Executing handler:", event, handler - self.exc_handler(handler, args) + handler.exec_handler(args) except: print_exc() - def exc_handler(self, d, args): - '''Handle handler.''' + def event(self, event, *args, **kargs): + '''Raise a custom event.''' - if type(d['handler']) == types.FunctionType: - handler = d['handler'] - handler(self, args, *d['args'], **d['kargs']) + print "Got custom event:", event, args, kargs - else: - cmd = d['handler'] - self.send(cmd) + if event in self._handlers: + for handler in self._handlers[event]: + try: + handler.exec_handler(*args, **kargs) + + except: + print_ext() if __name__ == "__main__": diff --git a/examples/data/uzbl/scripts/plugins/dump_config.py b/examples/data/uzbl/scripts/plugins/dump_config.py index 381dbf2..ba6543a 100644 --- a/examples/data/uzbl/scripts/plugins/dump_config.py +++ b/examples/data/uzbl/scripts/plugins/dump_config.py @@ -1,11 +1,4 @@ -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 + commands = ['dump_config', 'dump_config_as_events'] + handler = uzbl.connect('LOAD_FINISH', commands) + print "Added handler with id", handler.hid diff --git a/examples/data/uzbl/scripts/plugins/echo_keys.py b/examples/data/uzbl/scripts/plugins/echo_keys.py index e1a1850..b76a80f 100644 --- a/examples/data/uzbl/scripts/plugins/echo_keys.py +++ b/examples/data/uzbl/scripts/plugins/echo_keys.py @@ -2,7 +2,7 @@ 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 + print "Total keys pressed:", keys_pressed uzbl.config['keys_pressed'] = str(keys_pressed) @@ -10,7 +10,8 @@ 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.connect('KEY_PRESS', echo_keys) + uzbl.connect('KEY_PRESS', "sh %r" % ("echo %r" % "You just pressed %s")) + # Start a running counter of all keys pressed. uzbl.config['keys_pressed'] = str(0) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py new file mode 100644 index 0000000..d634f32 --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -0,0 +1,97 @@ +class Keylet(object): + def __init__(self): + self.cmd = "" + self.held = [] + self.modfirst = False + + def __repr__(self): + fmt = "" + if not self.cmd and not self.held: + return fmt % "" + + elif not len(self.held): + return fmt % self.cmd + + helds = '+'.join(["<%s>" % key for key in self.held]) + if not self.cmd: + return fmt % helds + + else: + return fmt % ("%s+%s" % (helds, self.cmd)) + + +class KeycmdTracker(dict): + def get_cmd(self, uzbl): + '''Returns a tuple of the form (keys held, cmdstr)''' + + if uzbl not in self: + return ([], []) + + return self[uzbl] + + + def key_press(self, uzbl, key): + + if key.startswith('Shift_'): + return + + t = self.get_keylet(uzbl) + if key not in t.held: + if not t.held and not t.cmd and len(key) != 1: + t.modfirst = True + + t.held.append(key) + + self.raise_event(uzbl) + + + def key_release(self, uzbl, key): + + t = self.get_keylet(uzbl) + if key in t.held: + t.held.remove(key) + if len(key) == 1: + t.cmd += key + + elif t.modfirst and not len(t.held): + self.clear(uzbl) + + self.raise_event(uzbl) + + + def get_keylet(self, uzbl): + if uzbl not in self: + self.add_instance(uzbl) + + return self[uzbl] + + + def clear(self, uzbl): + t = self.get_keylet(uzbl) + t.cmd = "" + t.modfirst = False + + + def add_instance(self, uzbl): + self[uzbl] = Keylet() + + + def del_instance(self, uzbl): + if uzbl in self: + del uzbl + + + def raise_event(self, uzbl): + '''Raise a custom event.''' + + uzbl.event('KEYCMD_UPDATE', self.get_keylet(uzbl)) + + +keycmd = KeycmdTracker() + +def init(uzbl): + + uzbl.connect('INSTANCE_START', keycmd.add_instance) + uzbl.connect('INSTANCE_STOP', keycmd.del_instance) + uzbl.connect('KEY_PRESS', keycmd.key_press) + uzbl.connect('KEY_RELEASE', keycmd.key_release) -- cgit v1.2.3 From 8d49ebef2d0ea1cefe8d269e0f07c8775a3d6494 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 01:16:37 +0800 Subject: Update keycmd in uzbl on keycmd raise event. --- examples/data/uzbl/scripts/plugins/keycmd.py | 37 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index d634f32..edfe673 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -20,6 +20,8 @@ class Keylet(object): return fmt % ("%s+%s" % (helds, self.cmd)) +keymap = {'period': '.'} + class KeycmdTracker(dict): def get_cmd(self, uzbl): '''Returns a tuple of the form (keys held, cmdstr)''' @@ -32,11 +34,28 @@ class KeycmdTracker(dict): def key_press(self, uzbl, key): - if key.startswith('Shift_'): + if key.startswith("Shift_"): return t = self.get_keylet(uzbl) - if key not in t.held: + if key == "BackSpace": + if t.cmd: + t.cmd = t.cmd[:-1] + + elif key == "Escape": + self.clear(uzbl) + + elif key == "space": + if t.cmd: + t.cmd += " " + + elif key in keymap: + t.cmd += keymap[key] + + elif len(key) == 1: + t.cmd += key + + elif key not in t.held: if not t.held and not t.cmd and len(key) != 1: t.modfirst = True @@ -47,14 +66,18 @@ class KeycmdTracker(dict): def key_release(self, uzbl, key): + #if key == "Return": + # TODO: Something here + t = self.get_keylet(uzbl) if key in t.held: t.held.remove(key) - if len(key) == 1: - t.cmd += key - elif t.modfirst and not len(t.held): - self.clear(uzbl) + if key == "Return": + self.clear(uzbl) + + if t.modfirst and not len(t.held): + self.clear(uzbl) self.raise_event(uzbl) @@ -84,6 +107,8 @@ class KeycmdTracker(dict): def raise_event(self, uzbl): '''Raise a custom event.''' + keylet = self.get_keylet(uzbl) + uzbl.config['keycmd'] = keylet.cmd uzbl.event('KEYCMD_UPDATE', self.get_keylet(uzbl)) -- cgit v1.2.3 From d8d817cb4438f4663cbf8f8a733ab984f517a864 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 01:29:28 +0800 Subject: Forgot to reassign commmand variable. --- examples/data/uzbl/scripts/event_manager.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 967fe39..914d793 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -256,12 +256,13 @@ class Handler(object): else: for command in self._commands: - if '%s' in command and len(args) == 1: - command.replace('%s', args[0]) + if '%s' in command: + if len(args) > 1: + for arg in args: + command = command.replace('%s', arg, 1) - elif '%s' in command: - for arg in args: - command.replace('%s', arg, 1) + elif len(args) == 1: + command = command.replace('%s', args[0]) self._uzbl.send(command) -- cgit v1.2.3 From acfcf6debead488696bb742e33908c1c20373a55 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 18:46:35 +0800 Subject: Spell Dieter's name correctly. --- examples/data/uzbl/scripts/event_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 914d793..3dc4987 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -2,7 +2,7 @@ # Event Manager for Uzbl # Copyright (c) 2009, Mason Larobina -# Copyright (c) 2009, Dieter Plaetinck +# Copyright (c) 2009, Dieter Plaetinck # # 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 -- cgit v1.2.3 From b369300a66eafe19f3d731023e1bd69ef2c40a45 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 22:35:40 +0800 Subject: Deleted plugins: dump_config & echo_keys. Reason: messy & useless. --- examples/data/uzbl/scripts/plugins/dump_config.py | 4 ---- examples/data/uzbl/scripts/plugins/echo_keys.py | 17 ----------------- 2 files changed, 21 deletions(-) delete mode 100644 examples/data/uzbl/scripts/plugins/dump_config.py delete mode 100644 examples/data/uzbl/scripts/plugins/echo_keys.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/dump_config.py b/examples/data/uzbl/scripts/plugins/dump_config.py deleted file mode 100644 index ba6543a..0000000 --- a/examples/data/uzbl/scripts/plugins/dump_config.py +++ /dev/null @@ -1,4 +0,0 @@ -def init(uzbl): - commands = ['dump_config', 'dump_config_as_events'] - handler = uzbl.connect('LOAD_FINISH', commands) - print "Added handler with id", handler.hid diff --git a/examples/data/uzbl/scripts/plugins/echo_keys.py b/examples/data/uzbl/scripts/plugins/echo_keys.py deleted file mode 100644 index b76a80f..0000000 --- a/examples/data/uzbl/scripts/plugins/echo_keys.py +++ /dev/null @@ -1,17 +0,0 @@ -def echo_keys(uzbl, key, print_meta=True): - '''Prints key-presses to the terminal.''' - - keys_pressed = int(uzbl.config['keys_pressed']) + 1 - print "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.''' - - uzbl.connect('KEY_PRESS', echo_keys) - uzbl.connect('KEY_PRESS', "sh %r" % ("echo %r" % "You just pressed %s")) - - # Start a running counter of all keys pressed. - uzbl.config['keys_pressed'] = str(0) -- cgit v1.2.3 From 604f1d4c1e94ed226d118607b105e52cb189626b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 22:53:35 +0800 Subject: Improved key/command/mod-command handling in keycmd.py plugin. --- examples/data/uzbl/scripts/event_manager.py | 4 +- examples/data/uzbl/scripts/plugins/keycmd.py | 212 +++++++++++++++++++-------- 2 files changed, 152 insertions(+), 64 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 3dc4987..7f3ffce 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -527,7 +527,9 @@ class UzblInstance(object): def handle_event(self, event, args): '''Handle uzbl events internally before dispatch.''' - print event, args + # Silence _printing_ of geo events while still debugging. + if event != "GEOMETRY_CHANGED": + print event, args if event == 'VARIABLE_SET': l = args.split(' ', 2) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index edfe673..b96546d 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -1,118 +1,204 @@ +#TODO: Comment code. + +import re + +# Regex build cache. +_RE_CACHE = {} + +def get_regex(regex): + if regex not in _RE_CACHE: + _RE_CACHE[regex] = re.compile(regex).match + + return _RE_CACHE[regex] + + class Keylet(object): def __init__(self): self.cmd = "" self.held = [] - self.modfirst = False + + # to_string() string building cache. + self._to_string = None + + self._modcmd = False + self._wasmod = True + def __repr__(self): - fmt = "" - if not self.cmd and not self.held: - return fmt % "" + return "" % self.to_string() - elif not len(self.held): - return fmt % self.cmd - helds = '+'.join(["<%s>" % key for key in self.held]) - if not self.cmd: - return fmt % helds + def _clear(self): + self.cmd = "" + self._to_string = None + if self._modcmd: + self._wasmod = True - else: - return fmt % ("%s+%s" % (helds, self.cmd)) + self._modcmd = False -keymap = {'period': '.'} + def to_string(self): + '''Always of the form +command''' -class KeycmdTracker(dict): - def get_cmd(self, uzbl): - '''Returns a tuple of the form (keys held, cmdstr)''' + if self._to_string is not None: + return self._to_string - if uzbl not in self: - return ([], []) + if not self.held: + self._to_string = self.cmd - return self[uzbl] + else: + self._to_string = ''.join(["<%s>" % key for key in self.held]) + if self.cmd: + self._to_string += "+%s" % self.cmd + return self._to_string - def key_press(self, uzbl, key): - if key.startswith("Shift_"): - return + def match(self, regex): + return bool(get_regex(regex)(self.to_string())) - t = self.get_keylet(uzbl) - if key == "BackSpace": - if t.cmd: - t.cmd = t.cmd[:-1] - elif key == "Escape": - self.clear(uzbl) +_SIMPLEKEYS = {'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab',} - elif key == "space": - if t.cmd: - t.cmd += " " +def makesimple(key): + if key.endswith("_L") or key.endswith("_R"): + key = key[:-2] - elif key in keymap: - t.cmd += keymap[key] + if key in _SIMPLEKEYS: + key = _SIMPLEKEYS[key] - elif len(key) == 1: - t.cmd += key + return key - elif key not in t.held: - if not t.held and not t.cmd and len(key) != 1: - t.modfirst = True - t.held.append(key) +class KeycmdTracker(dict): + def key_press(self, uzbl, key): + if key.startswith("Shift_"): + return - self.raise_event(uzbl) + if len(key) > 1: + key = makesimple(key) + + k = self.get_keylet(uzbl) + cmdmod = False + + if k.held and k._wasmod: + k._modcmd = True + k._wasmod = False + cmdmod = True + + if key == "space": + if k.cmd: + k.cmd += " " + cmdmod = True + + elif not k._modcmd and key in ['BackSpace', 'Return', 'Escape']: + if key == "BackSpace": + if k.cmd: + k.cmd = k.cmd[:-1] + if not k.cmd: + self.clear(uzbl) + + else: + cmdmod = True + + elif key == "Return": + uzbl.event("KEYCMD_EXEC", k) + self.clear(uzbl) + + elif key == "Escape": + self.clear(uzbl) + + elif not k.held and not k.cmd: + k._modcmd = True if len(key) > 1 else False + k.held.append(key) + k.held.sort() + cmdmod = True + if not k._modcmd: + k.cmd += key + + elif k._modcmd: + cmdmod = True + if len(key) > 1: + if key not in k.held: + k.held.append(key) + k.held.sort() + + else: + k.cmd += key + else: + cmdmod = True + if len(key) == 1: + if key not in k.held: + k.held.append(key) + k.held.sort() - def key_release(self, uzbl, key): + k.cmd += key - #if key == "Return": - # TODO: Something here + if cmdmod: + self.update(uzbl, k) - t = self.get_keylet(uzbl) - if key in t.held: - t.held.remove(key) - if key == "Return": + def key_release(self, uzbl, key): + if len(key) > 1: + key = makesimple(key) + + k = self.get_keylet(uzbl) + cmdmod = False + if k._modcmd and key in k.held: + uzbl.event("MODCMD_EXEC", k) + k.held.remove(key) + k.held.sort() self.clear(uzbl) - if t.modfirst and not len(t.held): - self.clear(uzbl) + elif not k._modcmd and key in k.held: + k.held.remove(key) + k.held.sort() + cmdmod = True + + if not k.held and not k.cmd and k._wasmod: + k._wasmod = False - self.raise_event(uzbl) + if cmdmod: + self.update(uzbl, k) + + + def update(self, uzbl, keylet): + if keylet._modcmd: + uzbl.config['keycmd'] = keylet.to_string() + uzbl.event("MODCMD_UPDATE", keylet) + + else: + uzbl.config['keycmd'] = keylet.cmd + uzbl.event("KEYCMD_UPDATE", keylet) def get_keylet(self, uzbl): if uzbl not in self: self.add_instance(uzbl) - + keylet = self[uzbl] + keylet._to_string = None return self[uzbl] def clear(self, uzbl): - t = self.get_keylet(uzbl) - t.cmd = "" - t.modfirst = False + self.get_keylet(uzbl)._clear() + uzbl.config['keycmd'] = "" + uzbl.event("KEYCMD_CLEAR") - def add_instance(self, uzbl): + def add_instance(self, uzbl, *args): self[uzbl] = Keylet() - def del_instance(self, uzbl): + def del_instance(self, uzbl, *args): if uzbl in self: del uzbl - def raise_event(self, uzbl): - '''Raise a custom event.''' - - keylet = self.get_keylet(uzbl) - uzbl.config['keycmd'] = keylet.cmd - uzbl.event('KEYCMD_UPDATE', self.get_keylet(uzbl)) - - keycmd = KeycmdTracker() +export_clear_keycmd = keycmd.clear + def init(uzbl): -- cgit v1.2.3 From c2097174b0ca36f5279f4278b3673f3bdbd02ff6 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 8 Sep 2009 23:11:13 +0800 Subject: 80 character line limit enforcement. --- examples/data/uzbl/scripts/cookie_daemon.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py index a47a663..87a2e87 100755 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ b/examples/data/uzbl/scripts/cookie_daemon.py @@ -645,7 +645,9 @@ def main(): import pprint sys.stderr.write("%s\n" % pprint.pformat(config)) - # it would be better if we didn't need to start this python process just to send a command to the socket, but unfortunately socat doesn't seem to support SEQPACKET + # It would be better if we didn't need to start this python process just + # to send a command to the socket, but unfortunately socat doesn't seem + # to support SEQPACKET. if action == "reload": send_command(config['cookie_socket'], "RELOAD") -- cgit v1.2.3 From 09cb17496ce37b96898eb6a4246aa9e6603222a8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 10 Sep 2009 22:15:23 +0800 Subject: Added listen_from_uzbl_socket added various command line options. --- examples/data/uzbl/scripts/event_manager.py | 267 +++++++++++++++++++++++----- 1 file changed, 223 insertions(+), 44 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 7f3ffce..e131306 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -47,6 +47,8 @@ import re import types import socket import pprint +import time +from optparse import OptionParser from traceback import print_exc @@ -70,8 +72,10 @@ 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/" + 'verbose': False, + 'plugin_dir': "$XDG_DATA_HOME/uzbl/scripts/plugins/", + 'plugins_load': [], + 'plugins_ignore': [], } @@ -92,6 +96,12 @@ def echo(msg): sys.stdout.write("%s: %s\n" % (_SCRIPTNAME, msg)) +def error(msg): + '''Prints error messages to stderr.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + + def counter(): '''Generate unique object id's.''' @@ -124,7 +134,7 @@ class PluginManager(dict): self.load_plugins() - def _find_plugins(self): + def _find_all_plugins(self): '''Find all python scripts in plugin dir and return a list of locations and imp moduleinfo's.''' @@ -139,7 +149,7 @@ class PluginManager(dict): return plugins - def _unload_plugin(self, plugin, remove_pyc=True): + def _unload_plugin(self, name, 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 @@ -147,49 +157,47 @@ class PluginManager(dict): this allows us to implement a reload plugins function.''' allmodules = sys.modules.keys() - allrefs = filter(lambda s: s.startswith("%s." % plugin), allmodules) + allrefs = filter(lambda s: s.startswith("%s." % name), allmodules) for ref in allrefs: del sys.modules[ref] - if plugin in sys.modules.keys(): - del sys.modules[plugin] + if name in sys.modules.keys(): + del sys.modules[name] - if plugin in self.keys(): - dict.__delitem__(self, plugin) + if name in self: + del self[name] if remove_pyc: - pyc = os.path.join(self.plugin_dir, '%s.pyc' % plugin) + pyc = os.path.join(self.plugin_dir, '%s.pyc' % name) if os.path.exists(pyc): os.remove(pyc) def load_plugins(self): - pluginlist = self._find_plugins() + if config['plugins_load']: + pluginlist = config['plugins_load'] - for name in pluginlist: - try: - # Make sure the plugin isn't already loaded. - self._unload_plugin(name) + else: + pluginlist = self._find_all_plugins() + for name in config['plugins_ignore']: + if name in pluginlist: + pluginlist.remove(name) - except: - print_exc() + for name in pluginlist: + # Make sure the plugin isn't already loaded. + self._unload_plugin(name) 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.') + self[name] = plugin except: - print_exc() - self._unload_plugin(name) + raise - if len(self.keys()): + if self.keys(): echo("loaded plugin(s): %s" % ', '.join(self.keys())) @@ -322,6 +330,7 @@ class UzblInstance(object): self._exports = {} self._config = self.ConfigDict(self.set) self._running = None + self._buffer = '' self._handlers = {} @@ -386,7 +395,37 @@ class UzblInstance(object): plugin.init(self) except: - print_exc() + #print_exc() + raise + + + def _init_uzbl_socket(self, uzbl_socket=None, timeout=None): + '''Store socket location and open socket connection to uzbl socket.''' + + if uzbl_socket is None: + uzbl_socket = self.uzbl_socket + + if not uzbl_socket: + error("no socket location.") + return + + if not os.path.exists(uzbl_socket): + if timeout is None: + error("uzbl socket doesn't exist: %r" % uzbl_socket) + return + + waitlimit = time.time() + timeout + echo("waiting for uzbl socket: %r" % uzbl_socket) + while not os.path.exists(uzbl_socket): + time.sleep(0.25) + if time.time() > waitlimit: + error("timed out waiting for socket: %r" % uzbl_socket) + return + + self.uzbl_socket = uzbl_socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.uzbl_socket) + self._socket = sock def _flush(self): @@ -403,9 +442,7 @@ class UzblInstance(object): 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 + self._init_uzbl_socket() if self._socket: while len(self._socket_cmd_queue): @@ -485,27 +522,27 @@ class UzblInstance(object): def listen_from_fd(self, fd): - '''Main loop reading event messages from stdin.''' + '''Polls for event messages from fd.''' - self._running = True - while self._running: - try: + try: + self._running = True + while self._running: if select.select([fd,], [], [], 1)[0]: self.read_from_fd(fd) continue self._flush() - except KeyboardInterrupt: - self._running = False - print + except KeyboardInterrupt: + print - except: - print_exc() + except: + #print_exc() + raise def read_from_fd(self, fd): - '''Reads incoming event messages from fd.''' + '''Reads event messages from a single fd.''' raw = fd.readline() if not raw: @@ -524,6 +561,66 @@ class UzblInstance(object): self.handle_event(event, args) + def listen_from_uzbl_socket(self, uzbl_socket): + '''Polls for event messages from a single uzbl socket.''' + + self._init_uzbl_socket(uzbl_socket, 10) + + if not self._socket: + error("failed to init socket: %r" % uzbl_socket) + return + + self._flush() + try: + self._running = True + while self._running: + if select.select([self._socket], [], [], 1): + self.read_from_uzbl_socket() + continue + + self._flush() + + except KeyboardInterrupt: + print + + except: + #print_exc() + raise + + + def read_from_uzbl_socket(self): + '''Reads event messages from a uzbl socket.''' + + raw = self._socket.recv(1024) + if not raw: + # Read null byte + self._running = False + return + + self._buffer += raw + msgs = self._buffer.split("\n") + self._buffer = msgs.pop() + + for msg in msgs: + msg = msg.rstrip() + if not msg: + continue + + cmd = msg.strip().split(' ', 3) + if not cmd or cmd[0] != "EVENT": + # Not an event message + print msg.rstrip() + continue + + event, args = cmd[1], cmd[3] + try: + self.handle_event(event, args) + + except: + #print_exc() + raise + + def handle_event(self, event, args): '''Handle uzbl events internally before dispatch.''' @@ -544,8 +641,9 @@ class UzblInstance(object): self._flush() elif event == 'SOCKET_SET': - self.uzbl_socket = args - self._flush() + if not self.uzbl_socket or not self._socket: + self._init_uzbl_socket(args) + self._flush() elif event == 'SHUTDOWN': for (name, plugin) in self.plugins.items(): @@ -566,7 +664,8 @@ class UzblInstance(object): handler.exec_handler(args) except: - print_exc() + #print_exc() + raise def event(self, event, *args, **kargs): @@ -580,8 +679,88 @@ class UzblInstance(object): handler.exec_handler(*args, **kargs) except: - print_ext() + #print_ext() + raise if __name__ == "__main__": - uzbl = UzblInstance().listen_from_fd(sys.stdin) + #uzbl = UzblInstance().listen_from_fd(sys.stdin) + + parser = OptionParser() + parser.add_option('-s', '--uzbl-socket', dest='socket', + action="store", metavar="SOCKET", + help="read event messages from uzbl socket.") + + parser.add_option('-v', '--verbose', dest='verbose', action="store_true", + help="print verbose output.") + + parser.add_option('-d', '--plugin-dir', dest='plugin_dir', action="store", + metavar="FILE", help="change plugin directory.") + + parser.add_option('-p', '--load-plugins', dest="load", action="store", + metavar="PLUGINS", help="comma separated list of plugins to load") + + parser.add_option('-i', '--ignore-plugins', dest="ignore", action="store", + metavar="PLUGINS", help="comma separated list of plugins to ignore") + + parser.add_option('-l', '--list-plugins', dest='list', action='store_true', + help="list all the plugins in the plugin dir.") + + (options, args) = parser.parse_args() + + if len(args): + for arg in args: + error("unknown argument: %r" % arg) + + raise ArgumentError + + if options.verbose: + config['verbose'] = True + + if options.plugin_dir: + plugin_dir = os.path.expandvars(options.plugin_dir) + if not os.path.isdir(plugin_dir): + error("%r is not a directory" % plugin_dir) + sys.exit(1) + + config['plugin_dir'] = plugin_dir + echo("changed plugin dir: %r" % plugin_dir) + + if options.load and options.ignore: + error("you can't load and ignore at the same time.") + sys.exit(1) + + elif options.load: + plugins_load = config['plugins_load'] + for plugin in options.load.split(','): + if plugin.strip(): + plugins_load.append(plugin.strip()) + + echo('only loading plugin(s): %s' % ', '.join(plugins_load)) + + elif options.ignore: + plugins_ignore = config['plugins_ignore'] + for plugin in options.ignore.split(','): + if plugin.strip(): + plugins_ignore.append(plugin.strip()) + + echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) + + + if options.list: + plugin_dir = os.path.expandvars(config['plugin_dir']) + if not os.path.isdir(plugin_dir): + error("not a directory: %r" % plugin_dir) + sys.exit(1) + + dirlist = filter(lambda p: p.endswith('.py'), os.listdir(plugin_dir)) + print ', '.join([p[:-3] for p in dirlist]) + + else: + uzbl = UzblInstance() + if options.socket: + echo("listen from uzbl socket: %r" % options.socket) + uzbl.listen_from_uzbl_socket(options.socket) + + else: + uzbl.listen_from_fd(sys.stdin) -- cgit v1.2.3 From 8cbb509588d97513ced7e89601903e9678d7ace5 Mon Sep 17 00:00:00 2001 From: Devon Jones Date: Thu, 10 Sep 2009 23:40:19 +0800 Subject: New fifo command bring_to_front brings window to focus (uzbl_tabbed.py) --- examples/data/uzbl/scripts/uzbl_tabbed.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py index f04b677..cd5ef4f 100755 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ b/examples/data/uzbl/scripts/uzbl_tabbed.py @@ -41,6 +41,9 @@ # Jake Probst # Wrote a patch that overflows tabs in the tablist on to new lines when # running of room. +# +# Devon Jones +# Fifo command bring_to_front which brings the gtk window to focus. # Dependencies: @@ -825,6 +828,8 @@ class UzblTabbed: # updates tablist title. # uri {pid} {document-location} # updates tablist uri + # bring_to_front + # brings the gtk window to focus. # exit # exits uzbl_tabbed.py @@ -924,6 +929,9 @@ class UzblTabbed: 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() -- cgit v1.2.3 From a4c2f07ca5dad85f8f965dd1462703c5a3f4e1b8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 11 Sep 2009 02:59:07 +0800 Subject: Removed "def export_name(..):" in favour of "__export__ = ['name',]" --- examples/data/uzbl/scripts/event_manager.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index e131306..927b515 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -375,17 +375,21 @@ class UzblInstance(object): # 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 + if not hasattr(plugin, '__export__'): + continue + + for export in plugin.__export__: + if export in self._exports: + orig = self._exports[export] + raise KeyError("already exported attribute: %r" % export) - obj = getattr(plugin, attr) + obj = getattr(plugin, export) if iscallable(obj): # Wrap the function in the CallPrepender object to make # the exposed functions act like instance methods. obj = CallPrepender(self, obj).call - self._exports[attr[7:]] = obj + self._exports[export] = obj echo("exposed attribute(s): %s" % ', '.join(self._exports.keys())) -- cgit v1.2.3 From 8d310055087fc84b33f07031ed1853279c4ff4a2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 11 Sep 2009 03:01:39 +0800 Subject: Removed unnecessary class & commented code in the keycmd plugin. --- examples/data/uzbl/scripts/plugins/keycmd.py | 283 ++++++++++++++++----------- 1 file changed, 169 insertions(+), 114 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index b96546d..bd38e25 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -1,11 +1,22 @@ -#TODO: Comment code. - import re -# Regex build cache. +# Map these functions/variables in the plugins namespace to the uzbl object. +__export__ = ['clear_keycmd',] + +# Regular expression compile cache. _RE_CACHE = {} +# Hold the keylets. +_UZBLS = {} + +# Simple key names map. +_SIMPLEKEYS = {'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab',} + + def get_regex(regex): + '''Compiling regular expressions is a very time consuming so return a + pre-compiled regex match object if possible.''' + if regex not in _RE_CACHE: _RE_CACHE[regex] = re.compile(regex).match @@ -13,6 +24,9 @@ def get_regex(regex): class Keylet(object): + '''Small per-instance object that tracks all the keys held and characters + typed.''' + def __init__(self): self.cmd = "" self.held = [] @@ -28,19 +42,12 @@ class Keylet(object): return "" % self.to_string() - def _clear(self): - self.cmd = "" - self._to_string = None - if self._modcmd: - self._wasmod = True - - self._modcmd = False - - def to_string(self): - '''Always of the form +command''' + '''Return a string representation of the keys held and pressed that + have been recorded.''' if self._to_string is not None: + # Return cached keycmd string. return self._to_string if not self.held: @@ -55,12 +62,15 @@ class Keylet(object): def match(self, regex): + '''See if the keycmd string matches the given regex.''' + return bool(get_regex(regex)(self.to_string())) -_SIMPLEKEYS = {'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab',} +def make_simple(key): + '''Make some obscure names for some keys friendlier.''' -def makesimple(key): + # Remove left-right discrimination. if key.endswith("_L") or key.endswith("_R"): key = key[:-2] @@ -70,139 +80,184 @@ def makesimple(key): return key -class KeycmdTracker(dict): - def key_press(self, uzbl, key): - if key.startswith("Shift_"): - return +def add_instance(uzbl, *args): + '''Create the Keylet object for this uzbl instance.''' - if len(key) > 1: - key = makesimple(key) + _UZBLS[uzbl] = Keylet() - k = self.get_keylet(uzbl) - cmdmod = False - if k.held and k._wasmod: - k._modcmd = True - k._wasmod = False - cmdmod = True +def del_instance(uzbl, *args): + '''Delete the Keylet object for this uzbl instance.''' - if key == "space": - if k.cmd: - k.cmd += " " - cmdmod = True + if uzbl in _UZBLS: + del _UZBLS[uzbl] - elif not k._modcmd and key in ['BackSpace', 'Return', 'Escape']: - if key == "BackSpace": - if k.cmd: - k.cmd = k.cmd[:-1] - if not k.cmd: - self.clear(uzbl) - else: - cmdmod = True +def get_keylet(uzbl): + '''Return the corresponding keylet for this uzbl instance.''' - elif key == "Return": - uzbl.event("KEYCMD_EXEC", k) - self.clear(uzbl) + # Startup events are not correctly captured and sent over the uzbl socket + # yet so this line is needed because the INSTANCE_START event is lost. + if uzbl not in _UZBLS: + add_instance(uzbl) - elif key == "Escape": - self.clear(uzbl) + keylet = _UZBLS[uzbl] + keylet._to_string = None + return keylet - elif not k.held and not k.cmd: - k._modcmd = True if len(key) > 1 else False - k.held.append(key) - k.held.sort() - cmdmod = True - if not k._modcmd: - k.cmd += key - elif k._modcmd: - cmdmod = True - if len(key) > 1: - if key not in k.held: - k.held.append(key) - k.held.sort() +def clear_keycmd(uzbl): + '''Clear the keycmd for this uzbl instance.''' - else: - k.cmd += key + k = get_keylet(uzbl) + if not k: + return - else: - cmdmod = True - if len(key) == 1: - if key not in k.held: - k.held.append(key) - k.held.sort() + k.cmd = "" + k._to_string = None - k.cmd += key + if k._modcmd: + k._wasmod = True - if cmdmod: - self.update(uzbl, k) + k._modcmd = False + uzbl.config['keycmd'] = "" + uzbl.event("KEYCMD_CLEAR") - def key_release(self, uzbl, key): - if len(key) > 1: - key = makesimple(key) - - k = self.get_keylet(uzbl) - cmdmod = False - if k._modcmd and key in k.held: - uzbl.event("MODCMD_EXEC", k) - k.held.remove(key) - k.held.sort() - self.clear(uzbl) - - elif not k._modcmd and key in k.held: - k.held.remove(key) - k.held.sort() +def update_event(uzbl, keylet): + '''Raise keycmd/modcmd update events.''' + + if keylet._modcmd: + uzbl.config['keycmd'] = keylet.to_string() + uzbl.event("MODCMD_UPDATE", keylet) + + else: + uzbl.config['keycmd'] = keylet.cmd + uzbl.event("KEYCMD_UPDATE", keylet) + + +def key_press(uzbl, key): + '''Handle KEY_PRESS events. Things done by this function include: + + 1. Ignore all shift key presses (shift can be detected by capital chars) + 2. Re-enable modcmd var if the user presses another key with at least one + modkey still held from the previous modcmd (I.e. +t, clear & + +o without having to re-press ) + 3. In non-modcmd mode: + a. BackSpace deletes the last character in the keycmd. + b. Return raises a KEYCMD_EXEC event then clears the keycmd. + c. Escape clears the keycmd. + d. Normal keys are added to held keys list (I.e. +c). + 4. If keycmd and held keys are both empty/null and a modkey was pressed + set modcmd mode. + 5. If in modcmd mode only mod keys are added to the held keys list. + 6. Keycmd is updated and events raised if anything is changed.''' + + if key.startswith("Shift_"): + return + + if len(key) > 1: + key = make_simple(key) + + k = get_keylet(uzbl) + if not k: + return + + cmdmod = False + if k.held and k._wasmod: + k._modcmd = True + k._wasmod = False + cmdmod = True + + if key == "space": + if k.cmd: + k.cmd += " " cmdmod = True - if not k.held and not k.cmd and k._wasmod: - k._wasmod = False + elif not k._modcmd and key == 'BackSpace': + if k.cmd: + k.cmd = k.cmd[:-1] + if not k.cmd: + clear_keycmd(uzbl) + + else: + cmdmod = True - if cmdmod: - self.update(uzbl, k) + elif not k._modcmd and key == 'Return': + uzbl.event("KEYCMD_EXEC", k) + clear_keycmd(uzbl) + elif not k.held and not k.cmd: + k._modcmd = True if len(key) > 1 else False + k.held.append(key) + k.held.sort() + cmdmod = True + if not k._modcmd: + k.cmd += key - def update(self, uzbl, keylet): - if keylet._modcmd: - uzbl.config['keycmd'] = keylet.to_string() - uzbl.event("MODCMD_UPDATE", keylet) + elif k._modcmd: + cmdmod = True + if len(key) > 1: + if key not in k.held: + k.held.append(key) + k.held.sort() else: - uzbl.config['keycmd'] = keylet.cmd - uzbl.event("KEYCMD_UPDATE", keylet) + k.cmd += key + + else: + cmdmod = True + if len(key) == 1: + if key not in k.held: + k.held.append(key) + k.held.sort() + + k.cmd += key + if cmdmod: + update_event(uzbl, k) - def get_keylet(self, uzbl): - if uzbl not in self: - self.add_instance(uzbl) - keylet = self[uzbl] - keylet._to_string = None - return self[uzbl] +def key_release(uzbl, key): + '''Respond to KEY_RELEASE event. Things done by this function include: - def clear(self, uzbl): - self.get_keylet(uzbl)._clear() - uzbl.config['keycmd'] = "" - uzbl.event("KEYCMD_CLEAR") + 1. Remove the key from the keylet held list. + 2. If the key removed was a mod key and it was in a mod-command then + raise a MODCMD_EXEC event then clear the keycmd. + 3. Stop trying to restore mod-command status with _wasmod if both the + keycmd and held list are empty/null. + 4. Update the keycmd uzbl variable if anything changed.''' + if len(key) > 1: + key = make_simple(key) - def add_instance(self, uzbl, *args): - self[uzbl] = Keylet() + k = get_keylet(uzbl) + if not k: + return + cmdmod = False + if k._modcmd and key in k.held: + uzbl.event("MODCMD_EXEC", k) + k.held.remove(key) + k.held.sort() + clear_keycmd(uzbl) - def del_instance(self, uzbl, *args): - if uzbl in self: - del uzbl + elif not k._modcmd and key in k.held: + k.held.remove(key) + k.held.sort() + cmdmod = True + if not k.held and not k.cmd and k._wasmod: + k._wasmod = False -keycmd = KeycmdTracker() -export_clear_keycmd = keycmd.clear + if cmdmod: + update_event(uzbl, k) def init(uzbl): + '''Connect handlers to uzbl events.''' - uzbl.connect('INSTANCE_START', keycmd.add_instance) - uzbl.connect('INSTANCE_STOP', keycmd.del_instance) - uzbl.connect('KEY_PRESS', keycmd.key_press) - uzbl.connect('KEY_RELEASE', keycmd.key_release) + uzbl.connect('INSTANCE_START', add_instance) + uzbl.connect('INSTANCE_STOP', del_instance) + uzbl.connect('KEY_PRESS', key_press) + uzbl.connect('KEY_RELEASE', key_release) -- cgit v1.2.3 From 654435bb4b85acd4c9ec8c0c44b0b8d89e63fc3d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 11 Sep 2009 03:06:20 +0800 Subject: Use new __export__ variable to set the bind export. --- examples/data/uzbl/scripts/plugins/bind.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index cf2a1ab..b44f706 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -10,9 +10,12 @@ And it is also possible to execute a function on activation: bind('DD', myhandler) ''' +__export__ = ['bind',] + uzbls = {} -def export_bind(uzbl, glob, cmd=None): + +def bind(uzbl, glob, cmd=None): if uzbl not in uzbls: uzbls[uzbl] = {} -- cgit v1.2.3 From 980dc1d7b30924fad2464c5fc1ad2801c67c670f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 11 Sep 2009 19:36:59 +0800 Subject: Moved Handler's handler_exec function to the uzbl instance class. --- examples/data/uzbl/scripts/event_manager.py | 84 +++++++++++++++-------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 927b515..018c066 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -232,63 +232,40 @@ class Handler(object): nexthid = counter().next - def __init__(self, uzbl, event, handler, *args, **kargs): - self._callable = iscallable(handler) - if self._callable: - self._function = handler - self._args = args - self._kargs = kargs + def __init__(self, event, handler, *args, **kargs): + self.callable = iscallable(handler) + if self.callable: + self.function = handler + self.args = args + self.kargs = kargs elif kargs: raise ArgumentError("cannot supply kargs with a uzbl command") elif isiterable(handler): - self._commands = handler + self.commands = handler else: - self._commands = [handler,] + list(args) + self.commands = [handler,] + list(args) - self._uzbl = uzbl self.event = event self.hid = self.nexthid() - def exec_handler(self, *args, **kargs): - '''Execute either the handler function or send the uzbl commands to - the socket.''' - - if self._callable: - args = args + self._args - kargs = dict(self._kargs.items()+kargs.items()) - self._function(self._uzbl, *args, **kargs) - - else: - for command in self._commands: - if '%s' in command: - if len(args) > 1: - for arg in args: - command = command.replace('%s', arg, 1) - - elif len(args) == 1: - command = command.replace('%s', args[0]) - - self._uzbl.send(command) - - def __repr__(self): args = ["event=%s" % self.event, "hid=%d" % self.hid] - if self._callable: - args.append("function=%r" % self._function) - if self._args: + if self.callable: + args.append("function=%r" % self.function) + if self.args: args.append("args=%r" % self.args) - if self._kargs: + if self.kargs: args.append("kargs=%r" % self.kargs) else: - cmdlen = len(self._commands) - cmds = self._commands[0] if cmdlen == 1 else self._commands + cmdlen = len(self.commands) + cmds = self.commands[0] if cmdlen == 1 else self.commands args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) return "" % ', '.join(args) @@ -476,7 +453,7 @@ class UzblInstance(object): if event not in self._handlers.keys(): self._handlers[event] = [] - handler = Handler(self, event, handler, *args, **kargs) + handler = Handler(event, handler, *args, **kargs) self._handlers[event].append(handler) print "New event handler:", handler @@ -658,6 +635,31 @@ class UzblInstance(object): self.dispatch_event(event, args) + def exec_handler(self, handler, *args, **kargs): + '''Execute either the handler function or send the handlers uzbl + commands via the socket.''' + + if handler.callable: + args = args + handler.args + kargs = dict(handler.kargs.items()+kargs.items()) + handler.function(uzbl, *args, **kargs) + + else: + if kargs: + raise ArgumentError('cannot supply kargs for uzbl commands') + + for command in handler.commands: + if '%s' in command: + if len(args) > 1: + for arg in args: + command = command.replace('%s', arg, 1) + + elif len(args) == 1: + command = command.replace('%s', args[0]) + + uzbl.send(command) + + 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.''' @@ -665,7 +667,7 @@ class UzblInstance(object): if event in self._handlers: for handler in self._handlers[event]: try: - handler.exec_handler(args) + self.exec_handler(handler, args) except: #print_exc() @@ -680,10 +682,10 @@ class UzblInstance(object): if event in self._handlers: for handler in self._handlers[event]: try: - handler.exec_handler(*args, **kargs) + self.exec_handler(handler, *args, **kargs) except: - #print_ext() + #print_exc() raise -- cgit v1.2.3 From bdbd00854e36785c9d660e66180211b2b4d6fd73 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 11 Sep 2009 19:39:21 +0800 Subject: Working bind plugin re-write & bindable space in keycmd plugin. --- examples/data/uzbl/scripts/plugins/bind.py | 266 ++++++++++++++++++++++++--- examples/data/uzbl/scripts/plugins/keycmd.py | 51 ++--- 2 files changed, 266 insertions(+), 51 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index b44f706..98f7d4c 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -1,52 +1,260 @@ -'''Plugin provides support for classic uzbl binds. +'''Plugin provides support for binds in uzbl. 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*') + event BIND ZZ = exit -> bind('ZZ', 'exit') + event BIND o _ = uri %s -> bind('o _', 'uri %s') + event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") And it is also possible to execute a function on activation: bind('DD', myhandler) ''' -__export__ = ['bind',] +import sys +import re +from event_manager import config, counter, iscallable, isiterable -uzbls = {} +# Export these variables/functions to uzbl. +__export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] +# Hold the bind lists per uzbl instance. +_UZBLS = {} -def bind(uzbl, glob, cmd=None): +# Commonly used regular expressions. +starts_with_mod = re.compile('^<([A-Za-z0-9-_]+|.)>') - 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] +def echo(msg): + if config['verbose']: + print "plugin: bind:", msg - d = {'glob': glob, 'once': True, 'hasargs': True, 'cmd': cmd} - if glob.endswith('*'): - d['pre'] = glob.rstrip('*') - d['once'] = False +def error(msg): + sys.stderr.write("plugin: bind: error: %s" % msg) - elif glob.endswith('_'): - d['pre'] = glob.rstrip('_') + +def ismodbind(glob): + '''Return True if the glob specifies a modbind.''' + + return bool(starts_with_mod.match(glob)) + + +def sort_mods(glob): + '''Mods are sorted in the keylet.to_string() result so make sure that + bind commands also have their mod keys sorted.''' + + mods = [] + while True: + match = starts_with_mod.match(glob) + if not match: + break + + end = match.span()[1] + mods.append(glob[:end]) + glob = glob[end:] + + return "%s%s" % (''.join(sorted(mods)), glob) + + +def add_instance(uzbl, *args): + _UZBLS[uzbl] = [] + + # Until the inital event messages over socket bug is resolved put your + # bind events here: + uzbl.event("BIND", "ZZ = exit") + uzbl.event("BIND", "q = exit") + uzbl.event("BIND", "h = uri http://uzbl.org/") + uzbl.event("BIND", "rr = uri http://reddit.com") + + +def del_instance(uzbl, *args): + if uzbl in _UZBLS: + del _UZBLS[uzbl] + + +def get_binds(uzbl): + '''Return the bind list for the uzbl instance.''' + + if uzbl not in _UZBLS: + add_instance(uzbl) + + return _UZBLS[uzbl] + + +def del_bind(uzbl, bind): + '''Delete bind object if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + if bind in binds: + binds.remove(bind) + uzbl.event("DELETED_BIND", bind) + return True + + return False + + +def del_bind_by_glob(uzbl, glob): + '''Delete bind by glob if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + for bind in list(binds): + if bind.glob == glob: + binds.remove(bind) + uzbl.event("DELETED_BIND", bind) + return True + + return False + + +class Bind(object): + + nextbid = counter().next + + def __init__(self, glob, handler, *args, **kargs): + self.callable = iscallable(handler) + + if not glob: + raise ArgumentError('glob cannot be blank') + + if self.callable: + self.function = handler + self.args = args + self.kargs = kargs + + elif kargs: + raise ArgumentError("cannot supply kargs for uzbl commands") + + elif isiterable(handler): + self.commands = handler + + else: + self.commands = [handler,] + list(args) + + self.glob = glob + self.bid = self.nextbid() + + # Is the binding a MODCMD or KEYCMD. + self.mod_bind = ismodbind(glob) + + # Execute the command on UPDATES or EXEC's. + self.on_exec = True if glob.endswith('_') else False + + if glob[-1] in ['*', '_']: + self.has_args = True + glob = glob[:-1] + + else: + self.has_args = False + + self.match = glob + + + def __repr__(self): + args = ["glob=%r" % self.glob, "bid=%d" % self.bid] + + if self.callable: + args.append("function=%r" % self.function) + if self.args: + args.append("args=%r" % self.args) + + if self.kargs: + args.append("kargs=%r" % self.kargs) + + else: + cmdlen = len(self.commands) + cmds = self.commands[0] if cmdlen == 1 else self.commands + args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) + + return "" % ', '.join(args) + + +def bind(uzbl, glob, handler, *args, **kargs): + '''Add a bind handler object.''' + + # Mods come from the keycmd sorted so make sure the modkeys in the bind + # command are sorted too. + glob = sort_mods(glob) + + del_bind_by_glob(uzbl, glob) + binds = get_binds(uzbl) + + bind = Bind(glob, handler, *args, **kargs) + binds.append(bind) + + uzbl.event('ADDED_BIND', bind) + + +def parse_bind_event(uzbl, args): + '''Parse "event BIND fl* = js follownums.js" commands.''' + + if len(args.split('=', 1)) != 2: + error('invalid bind format: %r' % args) + + glob, command = map(str.strip, args.split('=', 1)) + bind(uzbl, glob, command) + + +def match_and_exec(uzbl, bind, keylet): + + keycmd = keylet.to_string() + if bind.has_args: + if not keycmd.startswith(bind.match): + return False + + args = [keycmd[len(bind.match):],] + + elif keycmd != bind.match: + return False else: - d['pre'] = glob - d['hasargs'] = False + args = [] + + uzbl.exec_handler(bind, *args) + + if not bind.has_args: + uzbl.clear_keycmd() + + return True + + +def keycmd_update(uzbl, keylet): + for bind in get_binds(uzbl): + if bind.mod_bind or bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def keycmd_exec(uzbl, keylet): + for bind in get_binds(uzbl): + if bind.mod_bind or not bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def modcmd_update(uzbl, keylet): + for bind in get_binds(uzbl): + if not bind.mod_bind or bind.on_exec: + continue + + match_and_exec(uzbl, bind, keylet) + + +def modcmd_exec(uzbl, keylet): + for bind in get_binds(uzbl): + if not bind.mod_bind or not bind.on_exec: + continue - binds[glob] = d - print "added bind: %r" % d + match_and_exec(uzbl, bind, keylet) def init(uzbl): - uzbl.bind("test", lambda _: True) + connects = {'BIND': parse_bind_event, + 'KEYCMD_UPDATE': keycmd_update, + 'MODCMD_UPDATE': modcmd_update, + 'KEYCMD_EXEC': keycmd_exec, + 'MODCMD_EXEC': modcmd_exec} -def cleanup(uzbl): - if uzbl in uzbls: - del uzbl + for (event, handler) in connects.items(): + uzbl.connect(event, handler) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index bd38e25..7d835d8 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -10,7 +10,11 @@ _RE_CACHE = {} _UZBLS = {} # Simple key names map. -_SIMPLEKEYS = {'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab',} +_SIMPLEKEYS = { + 'Control': 'Ctrl', + 'ISO_Left_Tab': 'Shift-Tab', + 'space':'Space', +} def get_regex(regex): @@ -34,8 +38,8 @@ class Keylet(object): # to_string() string building cache. self._to_string = None - self._modcmd = False - self._wasmod = True + self.modcmd = False + self.wasmod = True def __repr__(self): @@ -56,7 +60,7 @@ class Keylet(object): else: self._to_string = ''.join(["<%s>" % key for key in self.held]) if self.cmd: - self._to_string += "+%s" % self.cmd + self._to_string += "%s" % self.cmd return self._to_string @@ -116,10 +120,10 @@ def clear_keycmd(uzbl): k.cmd = "" k._to_string = None - if k._modcmd: - k._wasmod = True + if k.modcmd: + k.wasmod = True - k._modcmd = False + k.modcmd = False uzbl.config['keycmd'] = "" uzbl.event("KEYCMD_CLEAR") @@ -127,7 +131,7 @@ def clear_keycmd(uzbl): def update_event(uzbl, keylet): '''Raise keycmd/modcmd update events.''' - if keylet._modcmd: + if keylet.modcmd: uzbl.config['keycmd'] = keylet.to_string() uzbl.event("MODCMD_UPDATE", keylet) @@ -164,17 +168,17 @@ def key_press(uzbl, key): return cmdmod = False - if k.held and k._wasmod: - k._modcmd = True - k._wasmod = False + if k.held and k.wasmod: + k.modcmd = True + k.wasmod = False cmdmod = True - if key == "space": + if k.cmd and key == "Space": if k.cmd: k.cmd += " " cmdmod = True - elif not k._modcmd and key == 'BackSpace': + elif not k.modcmd and key == 'BackSpace': if k.cmd: k.cmd = k.cmd[:-1] if not k.cmd: @@ -183,19 +187,22 @@ def key_press(uzbl, key): else: cmdmod = True - elif not k._modcmd and key == 'Return': + elif not k.modcmd and key == 'Return': uzbl.event("KEYCMD_EXEC", k) clear_keycmd(uzbl) + elif not k.modcmd and key == 'Escape': + clear_keycmd(uzbl) + elif not k.held and not k.cmd: - k._modcmd = True if len(key) > 1 else False + k.modcmd = True if len(key) > 1 else False k.held.append(key) k.held.sort() cmdmod = True - if not k._modcmd: + if not k.modcmd: k.cmd += key - elif k._modcmd: + elif k.modcmd: cmdmod = True if len(key) > 1: if key not in k.held: @@ -224,7 +231,7 @@ def key_release(uzbl, key): 1. Remove the key from the keylet held list. 2. If the key removed was a mod key and it was in a mod-command then raise a MODCMD_EXEC event then clear the keycmd. - 3. Stop trying to restore mod-command status with _wasmod if both the + 3. Stop trying to restore mod-command status with wasmod if both the keycmd and held list are empty/null. 4. Update the keycmd uzbl variable if anything changed.''' @@ -236,19 +243,19 @@ def key_release(uzbl, key): return cmdmod = False - if k._modcmd and key in k.held: + if k.modcmd and key in k.held: uzbl.event("MODCMD_EXEC", k) k.held.remove(key) k.held.sort() clear_keycmd(uzbl) - elif not k._modcmd and key in k.held: + elif not k.modcmd and key in k.held: k.held.remove(key) k.held.sort() cmdmod = True - if not k.held and not k.cmd and k._wasmod: - k._wasmod = False + if not k.held and not k.cmd and k.wasmod: + k.wasmod = False if cmdmod: update_event(uzbl, k) -- cgit v1.2.3 From 1431c68c54b95a3da923e491eb4b38cc00b0a89e Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 12 Sep 2009 11:26:44 +0200 Subject: dont put too specific system details in useragent by default --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index efc4780..47d8839 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -22,7 +22,7 @@ set status_format = Date: Sun, 13 Sep 2009 12:54:00 +0200 Subject: sample wmii integration script --- examples/data/uzbl/scripts/instance-select-wmii.sh | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100755 examples/data/uzbl/scripts/instance-select-wmii.sh (limited to 'examples') diff --git a/examples/data/uzbl/scripts/instance-select-wmii.sh b/examples/data/uzbl/scripts/instance-select-wmii.sh new file mode 100755 index 0000000..2c77600 --- /dev/null +++ b/examples/data/uzbl/scripts/instance-select-wmii.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# This script lists all uzbl instances in the current wmii tag +# You can select one of them, and it will focus that window +# It does not change the layout (stacked/tiled/floating) nor does it +# changes the size or viewing mode of a uzbl window +# When your current uzbl window is maximized, the one you change to +# will be maximized as well. +# See http://www.uzbl.org/wiki/wmii for more info + +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" + +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch +else + DMENU="dmenu -i" +fi + +list= +# get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky +for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) +do + label=$(wmiir read /client/$i/label) + list="$list$i : $label\n" +done +window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) +echo "focusing window $window" +wmiir xwrite /tag/sel/ctl "select client $window" -- cgit v1.2.3 From 6b74aab3622fc1a403e72d555836203bb926d0bc Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 13 Sep 2009 13:51:40 +0200 Subject: support focusing next/prev window --- examples/data/uzbl/scripts/instance-select-wmii.sh | 43 +++++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/instance-select-wmii.sh b/examples/data/uzbl/scripts/instance-select-wmii.sh index 2c77600..566c103 100755 --- a/examples/data/uzbl/scripts/instance-select-wmii.sh +++ b/examples/data/uzbl/scripts/instance-select-wmii.sh @@ -7,6 +7,7 @@ # When your current uzbl window is maximized, the one you change to # will be maximized as well. # See http://www.uzbl.org/wiki/wmii for more info +# $1 must be one of 'list', 'next', 'prev' COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" @@ -17,13 +18,35 @@ else DMENU="dmenu -i" fi -list= -# get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky -for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) -do - label=$(wmiir read /client/$i/label) - list="$list$i : $label\n" -done -window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) -echo "focusing window $window" -wmiir xwrite /tag/sel/ctl "select client $window" +if [ "$1" == 'list' ] +then + list= + # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky + for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) + do + label=$(wmiir read /client/$i/label) + list="$list$i : $label\n" + done + window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) + wmiir xwrite /tag/sel/ctl "select client $window" +elif [ "$1" == 'next' ] +then + current=$(wmiir read /client/sel/ctl | head -n 1) + # find the next uzbl window and focus it + next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2) + if [ x"$next" != "x" ] + then + wmiir xwrite /tag/sel/ctl "select client $next" + fi +elif [ "$1" == 'prev' ] +then + current=$(wmiir read /client/sel/ctl | head -n 1) + prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2) + if [ x"$prev" != "x" ] + then + wmiir xwrite /tag/sel/ctl "select client $prev" + fi +else + echo "\$1 not valid" >&2 + exit 2 +fi -- cgit v1.2.3 From 1048a492a7b5c8772c80c3c6530a89df34556235 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 13 Sep 2009 13:57:29 +0200 Subject: comment update --- examples/data/uzbl/scripts/instance-select-wmii.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/instance-select-wmii.sh b/examples/data/uzbl/scripts/instance-select-wmii.sh index 566c103..2bf13ba 100755 --- a/examples/data/uzbl/scripts/instance-select-wmii.sh +++ b/examples/data/uzbl/scripts/instance-select-wmii.sh @@ -1,7 +1,9 @@ #!/bin/sh -# This script lists all uzbl instances in the current wmii tag -# You can select one of them, and it will focus that window + +# This script allows you to focus another uzbl window +# It considers all uzbl windows in the current tag +# you can select one from a list, or go to the next/previous one # It does not change the layout (stacked/tiled/floating) nor does it # changes the size or viewing mode of a uzbl window # When your current uzbl window is maximized, the one you change to -- cgit v1.2.3 From 8f45d7851c39a225e51976e00308daaa92cb3194 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 15 Sep 2009 16:08:17 +0800 Subject: Socket communication bug resolved so remove test binds. --- examples/data/uzbl/scripts/plugins/bind.py | 7 ------- 1 file changed, 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 98f7d4c..a3618ca 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -58,13 +58,6 @@ def sort_mods(glob): def add_instance(uzbl, *args): _UZBLS[uzbl] = [] - # Until the inital event messages over socket bug is resolved put your - # bind events here: - uzbl.event("BIND", "ZZ = exit") - uzbl.event("BIND", "q = exit") - uzbl.event("BIND", "h = uri http://uzbl.org/") - uzbl.event("BIND", "rr = uri http://reddit.com") - def del_instance(uzbl, *args): if uzbl in _UZBLS: -- cgit v1.2.3 From 2166c29233835fc2e51b37fd63921c6f3bb333ca Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 15 Sep 2009 16:58:45 +0800 Subject: Moved the uzbl config dict into its own config.py plugin. --- examples/data/uzbl/scripts/event_manager.py | 59 +-------------------- examples/data/uzbl/scripts/plugins/config.py | 79 ++++++++++++++++++++++++++++ examples/data/uzbl/scripts/plugins/keycmd.py | 10 ++-- 3 files changed, 86 insertions(+), 62 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/config.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 018c066..1e97b8f 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -85,9 +85,7 @@ config = { # 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.''' @@ -277,35 +275,11 @@ class UzblInstance(object): # Singleton plugin manager. plugins = None - # Internal uzbl config dict. - 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) - - def __init__(self): '''Initialise event manager.''' # Hold functions exported by plugins. self._exports = {} - self._config = self.ConfigDict(self.set) self._running = None self._buffer = '' @@ -338,14 +312,6 @@ class UzblInstance(object): return object.__getattribute__(self, name) - 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.''' @@ -487,21 +453,6 @@ class UzblInstance(object): echo('unable to find & remove handler: %r' % handler) - 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): '''Polls for event messages from fd.''' @@ -609,15 +560,7 @@ class UzblInstance(object): if event != "GEOMETRY_CHANGED": 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': + if event == 'FIFO_SET': self.uzbl_fifo = args self._flush() diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py new file mode 100644 index 0000000..dfa920e --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -0,0 +1,79 @@ +import re +import types + +__export__ = ['set', 'get_config'] + +_VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match +_TYPECONVERT = {'int': int, 'float': float, 'str': str} + +UZBLS = {} + + +def escape(value): + '''A real escaping function may be required.''' + + return str(value) + + +def set(uzbl, key, value): + '''Sends a: "set key = value" command to the uzbl instance.''' + + if type(value) == types.BooleanType: + value = int(value) + + if not _VALIDSETKEY(key): + raise KeyError("%r" % key) + + if '\n' in value: + value = value.replace("\n", "\\n") + + uzbl.send('set %s = %s' % (key, escape(value))) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = ConfigDict(uzbl) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del uzbl + + +def get_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +class ConfigDict(dict): + def __init__(self, uzbl): + self._uzbl = uzbl + + def __setitem__(self, key, value): + '''Makes "config[key] = value" a wrapper for the set function.''' + + set(self._uzbl, key, value) + + +def variable_set(uzbl, args): + config = get_config(uzbl) + + key, type, value = list(args.split(' ', 2) + ['',])[:3] + old = config[key] if key in config else None + value = _TYPECONVERT[type](value) + + dict.__setitem__(config, key, value) + + if old != value: + uzbl.event("CONFIG_CHANGED", key, value) + + +def init(uzbl): + + connects = {'VARIABLE_SET': variable_set, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance} + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 7d835d8..10c7b5d 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -124,19 +124,21 @@ def clear_keycmd(uzbl): k.wasmod = True k.modcmd = False - uzbl.config['keycmd'] = "" + uzbl.get_config()['keycmd'] = "" uzbl.event("KEYCMD_CLEAR") def update_event(uzbl, keylet): '''Raise keycmd/modcmd update events.''' + config = uzbl.get_config() + if keylet.modcmd: - uzbl.config['keycmd'] = keylet.to_string() + config['keycmd'] = keylet.to_string() uzbl.event("MODCMD_UPDATE", keylet) else: - uzbl.config['keycmd'] = keylet.cmd + config['keycmd'] = keylet.cmd uzbl.event("KEYCMD_UPDATE", keylet) @@ -265,6 +267,6 @@ def init(uzbl): '''Connect handlers to uzbl events.''' uzbl.connect('INSTANCE_START', add_instance) - uzbl.connect('INSTANCE_STOP', del_instance) + uzbl.connect('INSTANCE_EXIT', del_instance) uzbl.connect('KEY_PRESS', key_press) uzbl.connect('KEY_RELEASE', key_release) -- cgit v1.2.3 From 5e8224c60e887253669cd72ae0df5c343825c221 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 15 Sep 2009 22:42:37 +0800 Subject: Event message format changed to "EVENT [12345] name args" --- examples/data/uzbl/scripts/event_manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 1e97b8f..b3d5ea2 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -86,6 +86,7 @@ config = { # Define some globals. _SCRIPTNAME = os.path.basename(sys.argv[0]) +_RE_FINDSPACES = re.compile("\s+") def echo(msg): '''Prints only if the verbose flag has been set.''' @@ -538,13 +539,13 @@ class UzblInstance(object): if not msg: continue - cmd = msg.strip().split(' ', 3) + cmd = _RE_FINDSPACES.split(msg, 3) if not cmd or cmd[0] != "EVENT": # Not an event message print msg.rstrip() continue - event, args = cmd[1], cmd[3] + event, args = cmd[2], cmd[3] try: self.handle_event(event, args) -- cgit v1.2.3 From 3702a07d3bdbc45f6bc31a70b528a9c51d82929b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 16 Sep 2009 14:00:25 +0800 Subject: Removed "c" binding ability after horrifing bug discovered. --- examples/data/uzbl/scripts/event_manager.py | 1 + examples/data/uzbl/scripts/plugins/bind.py | 33 ++++++------- examples/data/uzbl/scripts/plugins/keycmd.py | 71 ++++++++++++++-------------- 3 files changed, 54 insertions(+), 51 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index b3d5ea2..0bb4876 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -386,6 +386,7 @@ class UzblInstance(object): 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: diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index a3618ca..2321679 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -20,16 +20,16 @@ __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] _UZBLS = {} # Commonly used regular expressions. -starts_with_mod = re.compile('^<([A-Za-z0-9-_]+|.)>') +starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') def echo(msg): if config['verbose']: - print "plugin: bind:", msg + print 'bind plugin:', msg def error(msg): - sys.stderr.write("plugin: bind: error: %s" % msg) + sys.stderr.write('bind plugin: error: %s\n' % msg) def ismodbind(glob): @@ -52,7 +52,7 @@ def sort_mods(glob): mods.append(glob[:end]) glob = glob[end:] - return "%s%s" % (''.join(sorted(mods)), glob) + return '%s%s' % (''.join(sorted(mods)), glob) def add_instance(uzbl, *args): @@ -79,7 +79,7 @@ def del_bind(uzbl, bind): binds = get_binds(uzbl) if bind in binds: binds.remove(bind) - uzbl.event("DELETED_BIND", bind) + uzbl.event('DELETED_BIND', bind) return True return False @@ -92,7 +92,7 @@ def del_bind_by_glob(uzbl, glob): for bind in list(binds): if bind.glob == glob: binds.remove(bind) - uzbl.event("DELETED_BIND", bind) + uzbl.event('DELETED_BIND', bind) return True return False @@ -114,7 +114,7 @@ class Bind(object): self.kargs = kargs elif kargs: - raise ArgumentError("cannot supply kargs for uzbl commands") + raise ArgumentError('cannot supply kargs for uzbl commands') elif isiterable(handler): self.commands = handler @@ -142,22 +142,22 @@ class Bind(object): def __repr__(self): - args = ["glob=%r" % self.glob, "bid=%d" % self.bid] + args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] if self.callable: - args.append("function=%r" % self.function) + args.append('function=%r' % self.function) if self.args: - args.append("args=%r" % self.args) + args.append('args=%r' % self.args) if self.kargs: - args.append("kargs=%r" % self.kargs) + args.append('kargs=%r' % self.kargs) else: cmdlen = len(self.commands) cmds = self.commands[0] if cmdlen == 1 else self.commands - args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) + args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) - return "" % ', '.join(args) + return '' % ', '.join(args) def bind(uzbl, glob, handler, *args, **kargs): @@ -179,10 +179,11 @@ def bind(uzbl, glob, handler, *args, **kargs): def parse_bind_event(uzbl, args): '''Parse "event BIND fl* = js follownums.js" commands.''' - if len(args.split('=', 1)) != 2: - error('invalid bind format: %r' % args) + split = map(str.strip, args.split('=', 1)) + if len(split) != 2: + return error('missing "=" in bind definition: %r' % args) - glob, command = map(str.strip, args.split('=', 1)) + glob, command = split bind(uzbl, glob, command) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 10c7b5d..67ab6c2 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -32,7 +32,7 @@ class Keylet(object): typed.''' def __init__(self): - self.cmd = "" + self.cmd = '' self.held = [] # to_string() string building cache. @@ -43,7 +43,7 @@ class Keylet(object): def __repr__(self): - return "" % self.to_string() + return '' % self.to_string() def to_string(self): @@ -58,9 +58,9 @@ class Keylet(object): self._to_string = self.cmd else: - self._to_string = ''.join(["<%s>" % key for key in self.held]) + self._to_string = ''.join(['<%s>' % key for key in self.held]) if self.cmd: - self._to_string += "%s" % self.cmd + self._to_string += '%s' % self.cmd return self._to_string @@ -75,7 +75,7 @@ def make_simple(key): '''Make some obscure names for some keys friendlier.''' # Remove left-right discrimination. - if key.endswith("_L") or key.endswith("_R"): + if key.endswith('_L') or key.endswith('_R'): key = key[:-2] if key in _SIMPLEKEYS: @@ -117,15 +117,18 @@ def clear_keycmd(uzbl): if not k: return - k.cmd = "" + k.cmd = '' k._to_string = None if k.modcmd: k.wasmod = True k.modcmd = False - uzbl.get_config()['keycmd'] = "" - uzbl.event("KEYCMD_CLEAR") + config = uzbl.get_config() + if config['keycmd'] != '': + config['keycmd'] = '' + + uzbl.event('KEYCMD_CLEAR') def update_event(uzbl, keylet): @@ -134,12 +137,16 @@ def update_event(uzbl, keylet): config = uzbl.get_config() if keylet.modcmd: - config['keycmd'] = keylet.to_string() - uzbl.event("MODCMD_UPDATE", keylet) + keycmd = keylet.to_string() + uzbl.event('MODCMD_UPDATE', keylet) + if keycmd == keylet.to_string(): + config['keycmd'] = keylet.to_string() else: - config['keycmd'] = keylet.cmd - uzbl.event("KEYCMD_UPDATE", keylet) + keycmd = keylet.cmd + uzbl.event('KEYCMD_UPDATE', keylet) + if keycmd == keylet.cmd: + config['keycmd'] = keylet.cmd def key_press(uzbl, key): @@ -153,13 +160,12 @@ def key_press(uzbl, key): a. BackSpace deletes the last character in the keycmd. b. Return raises a KEYCMD_EXEC event then clears the keycmd. c. Escape clears the keycmd. - d. Normal keys are added to held keys list (I.e. +c). 4. If keycmd and held keys are both empty/null and a modkey was pressed set modcmd mode. 5. If in modcmd mode only mod keys are added to the held keys list. 6. Keycmd is updated and events raised if anything is changed.''' - if key.startswith("Shift_"): + if key.startswith('Shift_'): return if len(key) > 1: @@ -175,9 +181,9 @@ def key_press(uzbl, key): k.wasmod = False cmdmod = True - if k.cmd and key == "Space": + if k.cmd and key == 'Space': if k.cmd: - k.cmd += " " + k.cmd += ' ' cmdmod = True elif not k.modcmd and key == 'BackSpace': @@ -190,23 +196,23 @@ def key_press(uzbl, key): cmdmod = True elif not k.modcmd and key == 'Return': - uzbl.event("KEYCMD_EXEC", k) + uzbl.event('KEYCMD_EXEC', k) clear_keycmd(uzbl) elif not k.modcmd and key == 'Escape': clear_keycmd(uzbl) - elif not k.held and not k.cmd: - k.modcmd = True if len(key) > 1 else False + elif not k.held and not k.cmd and len(key) > 1: + k.modcmd = True k.held.append(key) - k.held.sort() cmdmod = True - if not k.modcmd: - k.cmd += key elif k.modcmd: cmdmod = True if len(key) > 1: + if key == 'Shift-Tab' and 'Tab' in k.held: + k.held.remove('Tab') + if key not in k.held: k.held.append(key) k.held.sort() @@ -215,12 +221,8 @@ def key_press(uzbl, key): k.cmd += key else: - cmdmod = True if len(key) == 1: - if key not in k.held: - k.held.append(key) - k.held.sort() - + cmdmod = True k.cmd += key if cmdmod: @@ -245,16 +247,15 @@ def key_release(uzbl, key): return cmdmod = False - if k.modcmd and key in k.held: - uzbl.event("MODCMD_EXEC", k) - k.held.remove(key) - k.held.sort() - clear_keycmd(uzbl) + if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: + key = 'Shift-Tab' + + if key in k.held: + if k.modcmd: + uzbl.event('MODCMD_EXEC', k) - elif not k.modcmd and key in k.held: k.held.remove(key) - k.held.sort() - cmdmod = True + clear_keycmd(uzbl) if not k.held and not k.cmd and k.wasmod: k.wasmod = False -- cgit v1.2.3 From 9196f4de2571fdf2d5f900b1b978ed09a75fd7b9 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 16 Sep 2009 21:01:03 +0800 Subject: Check 'keycmd' key exists before referencing. --- examples/data/uzbl/scripts/plugins/keycmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 67ab6c2..9d98cea 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -125,7 +125,7 @@ def clear_keycmd(uzbl): k.modcmd = False config = uzbl.get_config() - if config['keycmd'] != '': + if 'keycmd' not in config or config['keycmd'] != '': config['keycmd'] = '' uzbl.event('KEYCMD_CLEAR') -- cgit v1.2.3 From 760aab1d3d4711eab5b7feafa1fd788f0fde8a1f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 17 Sep 2009 19:57:14 +0800 Subject: Ensure the value is a string before checking for newline characters. --- examples/data/uzbl/scripts/plugins/config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py index dfa920e..cdf203f 100644 --- a/examples/data/uzbl/scripts/plugins/config.py +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -24,10 +24,11 @@ def set(uzbl, key, value): if not _VALIDSETKEY(key): raise KeyError("%r" % key) + value = escape(value) if '\n' in value: value = value.replace("\n", "\\n") - uzbl.send('set %s = %s' % (key, escape(value))) + uzbl.send('set %s = %s' % (key, value)) def add_instance(uzbl, *args): -- cgit v1.2.3 From 0a216341c42744720990140a4ca1d42decab2ccd Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 18 Sep 2009 18:23:11 +0200 Subject: apply new binds syntax --- docs/TODO | 1 - examples/config/uzbl/config | 111 +++++++++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 55 deletions(-) (limited to 'examples') diff --git a/docs/TODO b/docs/TODO index 091fe96..06f5d84 100644 --- a/docs/TODO +++ b/docs/TODO @@ -10,7 +10,6 @@ what if fifo/socket doesn't exist, or exists but nothing working behind it (anym == event-messages specific == * throw out all old code * document the event handling mechanism, all events, how to get started with sample event handler -* remove all binding ('bind = ' etc.) stuff and port to new system * VARIABLE_SET for all types (but probably not useful for custom vars) * port keycmd to evt handler. we can now more cleanly send BackSpace instead of keycmd_bs and so on * port the concept of modes and all related variables diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 47d8839..71593e0 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,6 +1,10 @@ # example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) +# set some shortcuts +set bind = request BIND +set shell_cmd = sh -c + # keyboard behavior in this sample config is sort of vimstyle # Handlers @@ -26,63 +30,62 @@ set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@ set fifo_dir = /tmp set socket_dir = /tmp -set shell_cmd = sh -c # Keyboard interface set modkey = Mod1 # like this you can enter any command at runtime, interactively. prefixed by ':' -bind :_ = chain '%s' +@bind :_ = chain '%s' -bind j = scroll_vert 20 -bind k = scroll_vert -20 -bind h = scroll_horz -20 -bind l = scroll_horz 20 -bind << = scroll_begin -bind >> = scroll_end -bind b = back -bind m = forward -bind S = stop -bind r = reload -bind R = reload_ign_cache -bind + = zoom_in -bind - = zoom_out -bind T = toggle_zoom_type -bind 1 = sh "echo set zoom_level = 1.0 > $4" -bind 2 = sh "echo set zoom_level = 2.0 > $4" -bind t = toggle_status -bind /* = search %s -bind ?* = search_reverse %s +@bind j = scroll_vert 20 +@bind k = scroll_vert -20 +@bind h = scroll_horz -20 +@bind l = scroll_horz 20 +@bind << = scroll_begin +@bind >> = scroll_end +@bind b = back +@bind m = forward +@bind S = stop +@bind r = reload +@bind R = reload_ign_cache +@bind + = zoom_in +@bind - = zoom_out +@bind T = toggle_zoom_type +@bind 1 = sh "echo set zoom_level = 1.0 > $4" +@bind 2 = sh "echo set zoom_level = 2.0 > $4" +@bind t = toggle_status +@bind /* = search %s +@bind ?* = search_reverse %s #jump to next -bind n = search -bind N = search_reverse -bind gh = uri http://www.uzbl.org +@bind n = search +@bind N = search_reverse +@bind gh = uri http://www.uzbl.org # shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..' -bind o _ = uri %s +@bind o _ = uri %s # shortcut to set variables -bind s _ = set %s -bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -bind gg _ = uri http://www.google.com/search?q=%s -bind i = toggle_insert_mode +@bind s _ = set %s +@bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +@bind gg _ = uri http://www.google.com/search?q=%s +@bind i = toggle_insert_mode # disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting -bind I = toggle_insert_mode 0 +@bind I = toggle_insert_mode 0 # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh -bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh -bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh +@bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh +@bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh +@bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -bind yurl = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 6 primary -bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard +@bind yurl = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 6 primary +@bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard # does the same as yurl but without needing a script -bind y2url = sh 'echo -n $6 | xclip' +@bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection -bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' +@bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # go to the page in clipboard -bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' +@bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' # start a new uzbl instance from the page in primary selection -bind 'p = sh 'exec uzbl --uri $(xclip -o)' -bind ZZ = exit -bind Xs = js alert("hi"); +@bind 'p = sh 'exec uzbl --uri $(xclip -o)' +@bind ZZ = exit +@bind Xs = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -90,31 +93,31 @@ bind Xs = js alert("hi"); # you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' +@bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -bind !dump = sh "echo dump_config > $4" -bind !reload = sh 'cat $1 > $4' +@bind !dump = sh "echo dump_config > $4" +@bind !reload = sh 'cat $1 > $4' # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically -bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh -bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit -bind zn = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh new -bind zl = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh load +@bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh +@bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit +@bind zn = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh new +@bind zl = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh load # other - more advanced - implementation using perl: (could not get this to run - Dieter ) -bind LL = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl load -bind LN = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl new -bind LE = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl edit +@bind LL = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl load +@bind LN = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl new +@bind LE = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl edit # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) # TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? #hit F to toggle the Hints (now in form of link numbering) -bind F = script $XDG_DATA_HOME/uzbl/scripts/hint.js +@bind F = script $XDG_DATA_HOME/uzbl/scripts/hint.js # the most stable version: -bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s +@bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s # using strings, not polished yet: -bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s +@bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s # "home" page if you will -- cgit v1.2.3 From afe6eea69f73a8af2880389c2639afd690989450 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 19 Sep 2009 20:02:00 +0800 Subject: Finished alpha mode plugin. --- examples/data/uzbl/scripts/plugins/config.py | 11 +- examples/data/uzbl/scripts/plugins/keycmd.py | 18 +-- examples/data/uzbl/scripts/plugins/mode.py | 158 +++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/mode.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py index cdf203f..5ce614a 100644 --- a/examples/data/uzbl/scripts/plugins/config.py +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -15,6 +15,13 @@ def escape(value): return str(value) +def get_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + def set(uzbl, key, value): '''Sends a: "set key = value" command to the uzbl instance.''' @@ -28,7 +35,9 @@ def set(uzbl, key, value): if '\n' in value: value = value.replace("\n", "\\n") - uzbl.send('set %s = %s' % (key, value)) + config = get_config(uzbl) + if key not in config or str(config[key]) != str(value): + uzbl.send('set %s = %s' % (key, value)) def add_instance(uzbl, *args): diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 9d98cea..e263e9d 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -142,7 +142,7 @@ def update_event(uzbl, keylet): if keycmd == keylet.to_string(): config['keycmd'] = keylet.to_string() - else: + elif 'keycmd_events' not in config or config['keycmd_events'] == '1': keycmd = keylet.cmd uzbl.event('KEYCMD_UPDATE', keylet) if keycmd == keylet.cmd: @@ -195,13 +195,10 @@ def key_press(uzbl, key): else: cmdmod = True - elif not k.modcmd and key == 'Return': + elif not k.modcmd and key == 'Return' and k.cmd or k.held: uzbl.event('KEYCMD_EXEC', k) clear_keycmd(uzbl) - elif not k.modcmd and key == 'Escape': - clear_keycmd(uzbl) - elif not k.held and not k.cmd and len(key) > 1: k.modcmd = True k.held.append(key) @@ -267,7 +264,10 @@ def key_release(uzbl, key): def init(uzbl): '''Connect handlers to uzbl events.''' - uzbl.connect('INSTANCE_START', add_instance) - uzbl.connect('INSTANCE_EXIT', del_instance) - uzbl.connect('KEY_PRESS', key_press) - uzbl.connect('KEY_RELEASE', key_release) + connects = {'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'KEY_PRESS': key_press, + 'KEY_RELEASE': key_release} + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py new file mode 100644 index 0000000..72c4158 --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -0,0 +1,158 @@ +import sys +import re + +__export__ = ['set_mode', 'get_mode'] + +UZBLS = {} + +DEFAULTS = { + 'mode': '', + 'default': '', + 'modes': { + 'insert': { + 'forward_keys': True, + 'keycmd_events': False, + 'indicator': 'I'}, + 'command': { + 'forward_keys': False, + 'keycmd_events': True, + 'indicator': 'C'}}} + +_RE_FINDSPACES = re.compile("\s+") + + +def error(msg): + sys.stderr.write("mode plugin: error: %s\n" % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_mode_dict(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_mode_config(uzbl, mode): + modes = get_mode_dict(uzbl)['modes'] + if mode not in modes: + modes[mode] = {} + + return modes[mode] + + +def get_mode(uzbl): + return get_mode_dict(uzbl)['mode'] + + +def key_press(uzbl, key): + if key != "Escape": + return + + set_mode(uzbl) + + +def set_mode(uzbl, mode=None): + mode_dict = get_mode_dict(uzbl) + if mode is None: + if not mode_dict['default']: + return error("no default mode to fallback on") + + mode = mode_dict['default'] + + config = uzbl.get_config() + if 'mode' not in config or config['mode'] != mode: + config['mode'] = mode + + mode_dict['mode'] = mode + mode_config = get_mode_config(uzbl, mode) + + for (key, value) in mode_config.items(): + if key not in config: + config[key] = value + + elif config[key] != value: + config[key] = value + + if 'indicator' not in mode_config: + config['indicator'] = mode + + uzbl.clear_keycmd() + uzbl.send('update_gui') + uzbl.event("MODE_CHANGED", mode) + + +def config_changed(uzbl, key, value): + if key == 'default_mode': + mode_dict = get_mode_dict(uzbl) + mode_dict['default'] = value + if value and not mode_dict['mode']: + set_mode(uzbl, value) + + elif key == 'mode': + if not value: + value = None + + set_mode(uzbl, value) + + +def mode_config(uzbl, args): + + split = map(str.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) + if len(split) != 2: + return error("invalid MODE_CONFIG syntax: %r" % args) + + mode, set = split + split = map(str.strip, set.split('=', 1)) + if len(split) != 2: + return error("invalid MODE_CONFIG set command: %r" % args) + + key, value = split + mode_config = get_mode_config(uzbl, mode) + mode_config[key] = value + + if get_mode(uzbl) == mode: + uzbl.set(key, value) + + +def commit_reset(uzbl, *args): + config = uzbl.get_config() + if 'reset_on_commit' not in config or config['reset_on_commit'] == '1': + set_mode(uzbl) + + +def toggle_modes(uzbl, modes): + + modelist = [s.strip() for s in modes.split(' ') if s] + if not len(modelist): + return error("no modes specified to toggle") + + mode_dict = get_mode_dict(uzbl) + oldmode = mode_dict['mode'] + if oldmode not in modelist: + return set_mode(uzbl, modelist[0]) + + newmode = modelist[(modelist.index(oldmode)+1) % len(modelist)] + set_mode(uzbl, newmode) + + +def init(uzbl): + + connects = {'CONFIG_CHANGED': config_changed, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEY_PRESS': key_press, + 'MODE_CONFIG': mode_config, + 'LOAD_COMMIT': commit_reset, + 'TOGGLE_MODES': toggle_modes} + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) -- cgit v1.2.3 From aa2c224e5742730539cf6a27b3455b308842e95c Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 19 Sep 2009 20:12:46 +0800 Subject: Fixed keycmd modification. --- examples/data/uzbl/scripts/plugins/keycmd.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index e263e9d..6377905 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -195,8 +195,10 @@ def key_press(uzbl, key): else: cmdmod = True - elif not k.modcmd and key == 'Return' and k.cmd or k.held: - uzbl.event('KEYCMD_EXEC', k) + elif not k.modcmd and key == 'Return': + if k.cmd: + uzbl.event('KEYCMD_EXEC', k) + clear_keycmd(uzbl) elif not k.held and not k.cmd and len(key) > 1: @@ -247,6 +249,9 @@ def key_release(uzbl, key): if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: key = 'Shift-Tab' + elif key in ['Shift', 'Alt'] and 'Meta' in k.held: + key = 'Meta' + if key in k.held: if k.modcmd: uzbl.event('MODCMD_EXEC', k) -- cgit v1.2.3 From 68eb932d7ce492c68af2ddf41e66765e0907e054 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 01:06:55 +0800 Subject: Use mode_indicator instead of indicator. --- examples/data/uzbl/scripts/plugins/mode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py index 72c4158..c2c3bbb 100644 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -82,8 +82,8 @@ def set_mode(uzbl, mode=None): elif config[key] != value: config[key] = value - if 'indicator' not in mode_config: - config['indicator'] = mode + if 'mode_indicator' not in mode_config: + config['mode_indicator'] = mode uzbl.clear_keycmd() uzbl.send('update_gui') -- cgit v1.2.3 From c0e0ed3fe7af41cec1d6d5427fcc581e68743add Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 01:23:34 +0800 Subject: Clear keycmd on load_start not load_commit --- examples/data/uzbl/scripts/plugins/mode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py index c2c3bbb..2befbf9 100644 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -123,7 +123,7 @@ def mode_config(uzbl, args): uzbl.set(key, value) -def commit_reset(uzbl, *args): +def load_reset(uzbl, *args): config = uzbl.get_config() if 'reset_on_commit' not in config or config['reset_on_commit'] == '1': set_mode(uzbl) @@ -151,7 +151,7 @@ def init(uzbl): 'INSTANCE_START': add_instance, 'KEY_PRESS': key_press, 'MODE_CONFIG': mode_config, - 'LOAD_COMMIT': commit_reset, + 'LOAD_START': load_reset, 'TOGGLE_MODES': toggle_modes} for (event, handler) in connects.items(): -- cgit v1.2.3 From d53b2b5c3ab74c0eac3b6aee04981eaf8c34ed57 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 07:59:46 +0800 Subject: Updated sample config with mode plugin config examples. --- examples/config/uzbl/config | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 71593e0..2825c1f 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -13,26 +13,22 @@ set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py -set load_start_handler = chain 'set keycmd = ' 'set status_message = wait' +set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv set load_finish_handler = chain 'set status_message = done' 'spawn $XDG_DATA_HOME/uzbl/scripts/history.sh' - # Behaviour and appearance set show_status = 1 set status_background = #303030 -set status_format = [\@[\@MODE]\@] [\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ +set keycmd_style = weight="bold" foreground="red" +set status_format = [\@[\@mode_indicator]\@] [\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ set status_top = 0 -set insert_indicator = I -set command_indicator = C set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp set socket_dir = /tmp -# Keyboard interface -set modkey = Mod1 # like this you can enter any command at runtime, interactively. prefixed by ':' @bind :_ = chain '%s' @@ -120,5 +116,34 @@ set modkey = Mod1 @bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s +### Mode config + +set default_mode = command + +# Define some mode specific uzbl configurations. +set mode_config = request MODE_CONFIG +set command = @mode_config command +set insert = @mode_config insert + +@command keycmd_style = weight="bold" foreground="red" +@command status_background = #202020 +@command mode_indicator = Cmd + +@insert keycmd_style = foreground="green" +@insert status_background = #303030 +@insert mode_indicator = Ins + +# Changing mode method via set. +set set_mode = set mode = +@bind I = @set_mode insert + +# Or toggle between modes by rasing request events. +set toggle_modes = request TOGGLE_MODES +set toggle_cmd_ins = @toggle_modes command insert + +@bind i = @toggle_cmd_ins +@bind i = @toggle_cmd_ins + + # "home" page if you will set uri = uzbl.org -- cgit v1.2.3 From 7bf1a47b724da9af77bff073705d2c3161754643 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 08:50:07 +0800 Subject: Use the one event dispatching function. --- examples/data/uzbl/scripts/event_manager.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 0bb4876..c9be9bb 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -577,7 +577,7 @@ class UzblInstance(object): plugin.cleanup(uzbl) # Now handle the event "publically". - self.dispatch_event(event, args) + self.event(event, args) def exec_handler(self, handler, *args, **kargs): @@ -605,25 +605,9 @@ class UzblInstance(object): uzbl.send(command) - 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: - for handler in self._handlers[event]: - try: - self.exec_handler(handler, args) - - except: - #print_exc() - raise - - def event(self, event, *args, **kargs): '''Raise a custom event.''' - print "Got custom event:", event, args, kargs - if event in self._handlers: for handler in self._handlers[event]: try: -- cgit v1.2.3 From 41540a5e1085c50fc3c6b5a7fab51ce4d1234926 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 10:44:08 +0800 Subject: Use uzbl-browser and cookie daemon by default in the sample config. --- examples/config/uzbl/config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 2825c1f..363e163 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -9,9 +9,10 @@ set shell_cmd = sh -c # Handlers set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh -set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py +#set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py +set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket #set new_window = sh 'echo uri "$8" > $4' # open in same window -set new_window = sh 'uzbl -u $8' # equivalent to the default behaviour +set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv -- cgit v1.2.3 From 5de17212ff77e1021e2a87b528b51bab173efd8d Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 18:51:44 +0800 Subject: Added new binding syntax which allows setting a customisable prompt mid-bind. --- examples/config/uzbl/config | 26 +++- examples/data/uzbl/scripts/event_manager.py | 33 +++-- examples/data/uzbl/scripts/plugins/bind.py | 200 +++++++++++++++++++++------ examples/data/uzbl/scripts/plugins/keycmd.py | 10 +- 4 files changed, 212 insertions(+), 57 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 363e163..c6b9a6e 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -23,7 +23,8 @@ set load_finish_handler = chain 'set status_message = do set show_status = 1 set status_background = #303030 set keycmd_style = weight="bold" foreground="red" -set status_format = [\@[\@mode_indicator]\@] [\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ +set prompt_style = foreground="grey" +set status_format = [\@[\@mode_indicator]\@] [\@[\@keycmd_prompt]\@\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ set status_top = 0 set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) @@ -57,7 +58,7 @@ set socket_dir = /tmp @bind N = search_reverse @bind gh = uri http://www.uzbl.org # shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..' -@bind o _ = uri %s +#@bind o _ = uri %s # shortcut to set variables @bind s _ = set %s @bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go @@ -67,7 +68,7 @@ set socket_dir = /tmp @bind I = toggle_insert_mode 0 # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -@bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh +#@bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh @bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh @bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection @@ -117,6 +118,16 @@ set socket_dir = /tmp @bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s +# Examples using multi-stage-bindings with text prompts +@bind o_ = uri %s + +# Prints tab separated "uri title keyword tags" to the bookmarks file. +@bind b__ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' + +@bind a<:>q = exit +@bind a<:>h = uri http://uzbl.org/ + + ### Mode config set default_mode = command @@ -134,6 +145,14 @@ set insert = @mode_config insert @insert status_background = #303030 @insert mode_indicator = Ins +# Multi-stage-binding mode config. +set stack = @mode_config stack +@stack keycmd_events = 1 +@stack prompt_style = foreground="#888" weight="light" +@stack status_background = #202020 +@stack mode_indicator = Bnd + + # Changing mode method via set. set set_mode = set mode = @bind I = @set_mode insert @@ -145,6 +164,5 @@ set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins @bind i = @toggle_cmd_ins - # "home" page if you will set uri = uzbl.org diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index c9be9bb..c5f2eda 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -376,6 +376,17 @@ class UzblInstance(object): self._socket = sock + def _close_socket(self): + '''Close the socket used for communication with the uzbl instance. + This function is normally called upon receiving the INSTANCE_EXIT + event.''' + + if self._socket: + self._socket.close() + + self.uzbl_socket = self._socket = None + + def _flush(self): '''Flush messages from the outgoing queue to the uzbl instance.''' @@ -384,7 +395,7 @@ class UzblInstance(object): 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 + print '<-- %s' % msg h.write("%s\n" % msg) h.close() @@ -396,7 +407,7 @@ class UzblInstance(object): if self._socket: while len(self._socket_cmd_queue): msg = self._socket_cmd_queue.pop(0) - print "Sending via socket: %r" % msg + print '<-- %s' % msg self._socket.send("%s\n" % msg) @@ -424,7 +435,7 @@ class UzblInstance(object): handler = Handler(event, handler, *args, **kargs) self._handlers[event].append(handler) - print "New event handler:", handler + print handler return handler @@ -488,7 +499,7 @@ class UzblInstance(object): if not msg or msg[0] != "EVENT": # Not an event message - print raw.rstrip() + print "---", raw.rstrip() return event, args = msg[1], msg[3] @@ -558,10 +569,6 @@ class UzblInstance(object): def handle_event(self, event, args): '''Handle uzbl events internally before dispatch.''' - # Silence _printing_ of geo events while still debugging. - if event != "GEOMETRY_CHANGED": - print event, args - if event == 'FIFO_SET': self.uzbl_fifo = args self._flush() @@ -571,7 +578,9 @@ class UzblInstance(object): self._init_uzbl_socket(args) self._flush() - elif event == 'SHUTDOWN': + elif event == 'INSTANCE_EXIT': + self._close_socket() + self._running = False for (name, plugin) in self.plugins.items(): if hasattr(plugin, "cleanup"): plugin.cleanup(uzbl) @@ -608,6 +617,10 @@ class UzblInstance(object): def event(self, event, *args, **kargs): '''Raise a custom event.''' + # Silence _printing_ of geo events while still debugging. + if event != "GEOMETRY_CHANGED": + print "--> %s %s %s" % (event, args, '' if not kargs else kargs) + if event in self._handlers: for handler in self._handlers[event]: try: @@ -630,7 +643,7 @@ if __name__ == "__main__": help="print verbose output.") parser.add_option('-d', '--plugin-dir', dest='plugin_dir', action="store", - metavar="FILE", help="change plugin directory.") + metavar="DIR", help="change plugin directory.") parser.add_option('-p', '--load-plugins', dest="load", action="store", metavar="PLUGINS", help="comma separated list of plugins to load") diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 2321679..eaa1d40 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -17,10 +17,18 @@ from event_manager import config, counter, iscallable, isiterable __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] # Hold the bind lists per uzbl instance. -_UZBLS = {} +UZBLS = {} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') +find_prompts = re.compile('<([^:>]*):>').split + +# For accessing a bind glob stack. +MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) + + +class BindParseError(Exception): + pass def echo(msg): @@ -56,21 +64,45 @@ def sort_mods(glob): def add_instance(uzbl, *args): - _UZBLS[uzbl] = [] + UZBLS[uzbl] = {'binds': [], 'depth': 0, 'filter': [], + 'args': [], 'last_mode': ''} def del_instance(uzbl, *args): - if uzbl in _UZBLS: - del _UZBLS[uzbl] + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_bind_dict(uzbl): + '''Return the bind dict for the uzbl instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] def get_binds(uzbl): '''Return the bind list for the uzbl instance.''' - if uzbl not in _UZBLS: - add_instance(uzbl) + return get_bind_dict(uzbl)['binds'] + + +def get_stack_depth(uzbl): + '''Return the stack for the uzbl instance.''' + + return get_bind_dict(uzbl)['depth'] - return _UZBLS[uzbl] + +def get_filtered_binds(uzbl): + '''Return the bind list for the uzbl instance or return the filtered + bind list thats on the current stack.''' + + bind_dict = get_bind_dict(uzbl) + if bind_dict['depth']: + return list(bind_dict['filter']) + + return list(bind_dict['binds']) def del_bind(uzbl, bind): @@ -125,20 +157,35 @@ class Bind(object): self.glob = glob self.bid = self.nextbid() - # Is the binding a MODCMD or KEYCMD. - self.mod_bind = ismodbind(glob) + self.split = split = find_prompts(glob) + self.prompts = split[1::2] - # Execute the command on UPDATES or EXEC's. - self.on_exec = True if glob.endswith('_') else False + # Check that there is nothing like: fl** + for glob in split[:-1:2]: + if glob.endswith('*'): + msg = "token '*' not at the end of a prompt bind: %r" % split + raise BindParseError(msg) - if glob[-1] in ['*', '_']: - self.has_args = True - glob = glob[:-1] + # Check that there is nothing like: fl_ + for glob in split[2::2]: + if not glob: + msg = 'found null segment after first prompt: %r' % split + raise BindParseError(msg) - else: - self.has_args = False + self.stack = [] + + for glob in split[::2]: + # Is the binding a MODCMD or KEYCMD: + mod_cmd = ismodbind(glob) + + # Execute the command on UPDATES or EXEC's: + on_exec = True if glob.endswith('_') else False - self.match = glob + # Does the command store arguments: + has_args = True if glob[-1] in ['*', '_'] else False + glob = glob[:-1] if has_args else glob + + self.stack.append((mod_cmd, on_exec, has_args, glob)) def __repr__(self): @@ -173,11 +220,12 @@ def bind(uzbl, glob, handler, *args, **kargs): bind = Bind(glob, handler, *args, **kargs) binds.append(bind) + print bind uzbl.event('ADDED_BIND', bind) def parse_bind_event(uzbl, args): - '''Parse "event BIND fl* = js follownums.js" commands.''' + '''Break "event BIND fl* = js follownums.js" into (glob, command).''' split = map(str.strip, args.split('=', 1)) if len(split) != 2: @@ -187,68 +235,138 @@ def parse_bind_event(uzbl, args): bind(uzbl, glob, command) -def match_and_exec(uzbl, bind, keylet): +def set_stack_mode(uzbl, prompt): + if uzbl.get_mode() != 'stack': + uzbl.set_mode('stack') - keycmd = keylet.to_string() - if bind.has_args: - if not keycmd.startswith(bind.match): + if prompt: + prompt = "%s: " % prompt + + uzbl.set('keycmd_prompt', prompt) + + +def clear_stack(uzbl, mode): + bind_dict = get_bind_dict(uzbl) + if mode != "stack" and bind_dict['last_mode'] == "stack": + uzbl.set('keycmd_prompt', '') + + if mode != "stack": + bind_dict = get_bind_dict(uzbl) + bind_dict['filter'] = [] + bind_dict['depth'] = 0 + bind_dict['args'] = [] + + bind_dict['last_mode'] = mode + + +def filter_bind(uzbl, bind_dict, bind): + '''Remove a bind from the stack filter list.''' + + if bind in bind_dict['filter']: + bind_dict['filter'].remove(bind) + + if not bind_dict['filter']: + uzbl.set_mode() + + +def match_and_exec(uzbl, bind, depth, keycmd): + bind_dict = get_bind_dict(uzbl) + mode_cmd, on_exec, has_args, glob = bind.stack[depth] + + if has_args: + if not keycmd.startswith(glob): + filter_bind(uzbl, bind_dict, bind) return False - args = [keycmd[len(bind.match):],] + args = [keycmd[len(glob):],] - elif keycmd != bind.match: + elif keycmd != glob: + filter_bind(uzbl, bind_dict, bind) return False else: args = [] - uzbl.exec_handler(bind, *args) + execindex = len(bind.stack)-1 + if execindex == depth == 0: + uzbl.exec_handler(bind, *args) + if not has_args: + uzbl.clear_keycmd() + + return True - if not bind.has_args: - uzbl.clear_keycmd() + elif depth != execindex: + if bind_dict['depth'] == depth: + bind_dict['filter'] = [bind,] + bind_dict['args'] += args + bind_dict['depth'] = depth + 1 + + else: + if bind not in bind_dict['filter']: + bind_dict['filter'].append(bind) + + set_stack_mode(uzbl, bind.prompts[depth]) + return False + + args = bind_dict['args'] + args + uzbl.exec_handler(bind, *args) + if on_exec: + uzbl.set_mode() return True def keycmd_update(uzbl, keylet): - for bind in get_binds(uzbl): - if bind.mod_bind or bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def keycmd_exec(uzbl, keylet): - for bind in get_binds(uzbl): - if bind.mod_bind or not bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def modcmd_update(uzbl, keylet): - for bind in get_binds(uzbl): - if not bind.mod_bind or bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def modcmd_exec(uzbl, keylet): - for bind in get_binds(uzbl): - if not bind.mod_bind or not bind.on_exec: + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, keylet) + match_and_exec(uzbl, bind, depth, keycmd) def init(uzbl): - connects = {'BIND': parse_bind_event, 'KEYCMD_UPDATE': keycmd_update, 'MODCMD_UPDATE': modcmd_update, 'KEYCMD_EXEC': keycmd_exec, - 'MODCMD_EXEC': modcmd_exec} + 'MODCMD_EXEC': modcmd_exec, + 'MODE_CHANGED': clear_stack} for (event, handler) in connects.items(): uzbl.connect(event, handler) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 6377905..886f38f 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -220,9 +220,15 @@ def key_press(uzbl, key): k.cmd += key else: - if len(key) == 1: + config = uzbl.get_config() + if 'keycmd_events' not in config or config['keycmd_events'] == '1': + if len(key) == 1: + cmdmod = True + k.cmd += key + + elif k.cmd: cmdmod = True - k.cmd += key + k.cmd = '' if cmdmod: update_event(uzbl, k) -- cgit v1.2.3 From 4ce8efcfc0ae5762cf046286ebb58550980f3033 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 23:19:52 +0800 Subject: Broke up status_format in the config into manageable pieces. --- examples/config/uzbl/config | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index c6b9a6e..b611aa3 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -2,9 +2,11 @@ # all settings are optional. you can use uzbl without any config at all (but it won't do much) # set some shortcuts -set bind = request BIND -set shell_cmd = sh -c - +set bind = request BIND +set mode_config = request MODE_CONFIG +set toggle_modes = request TOGGLE_MODES +set set_mode = set mode = +set shell_cmd = sh -c # keyboard behavior in this sample config is sort of vimstyle # Handlers @@ -13,6 +15,7 @@ set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour + set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py set load_start_handler = set status_message = wait set load_commit_handler = set status_message = recv @@ -21,16 +24,28 @@ set load_finish_handler = chain 'set status_message = do # Behaviour and appearance set show_status = 1 +set status_top = 0 set status_background = #303030 + set keycmd_style = weight="bold" foreground="red" set prompt_style = foreground="grey" -set status_format = [\@[\@mode_indicator]\@] [\@[\@keycmd_prompt]\@\@[\@keycmd]\@] \@[\@LOAD_PROGRESSBAR]\@ \@[\@uri]\@ \@[\@NAME]\@ \@status_message \@[\@SELECTED_URI]\@ -set status_top = 0 -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) +set mode_section = [\@[\@mode_indicator]\@] +set keycmd_section = [\@[\@keycmd_prompt]\@\@[\@keycmd]\@] +set progress_section = \@[\@LOAD_PROGRESSBAR]\@ +set uri_section = \@[\@uri]\@ +set name_section = \@[\@NAME]\@ +set status_section = \@status_message +set selected_section = \@[\@SELECTED_URI]\@ + +set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @selected_section + +# Core settings +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp set socket_dir = /tmp + # like this you can enter any command at runtime, interactively. prefixed by ':' @bind :_ = chain '%s' @@ -133,20 +148,21 @@ set socket_dir = /tmp set default_mode = command # Define some mode specific uzbl configurations. -set mode_config = request MODE_CONFIG -set command = @mode_config command -set insert = @mode_config insert +set command = @mode_config command +set insert = @mode_config insert +set stack = @mode_config stack +# Command mode config. @command keycmd_style = weight="bold" foreground="red" @command status_background = #202020 @command mode_indicator = Cmd +# Insert mode config. @insert keycmd_style = foreground="green" @insert status_background = #303030 @insert mode_indicator = Ins # Multi-stage-binding mode config. -set stack = @mode_config stack @stack keycmd_events = 1 @stack prompt_style = foreground="#888" weight="light" @stack status_background = #202020 @@ -154,11 +170,9 @@ set stack = @mode_config stack # Changing mode method via set. -set set_mode = set mode = @bind I = @set_mode insert # Or toggle between modes by rasing request events. -set toggle_modes = request TOGGLE_MODES set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins -- cgit v1.2.3 From e734b9feff889a5dc4cc78388b018e6891ea5d4f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 20 Sep 2009 23:25:45 +0800 Subject: Naming consistency fix. --- examples/data/uzbl/scripts/plugins/keycmd.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 886f38f..7abb042 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -7,7 +7,7 @@ __export__ = ['clear_keycmd',] _RE_CACHE = {} # Hold the keylets. -_UZBLS = {} +UZBLS = {} # Simple key names map. _SIMPLEKEYS = { @@ -87,14 +87,14 @@ def make_simple(key): def add_instance(uzbl, *args): '''Create the Keylet object for this uzbl instance.''' - _UZBLS[uzbl] = Keylet() + UZBLS[uzbl] = Keylet() def del_instance(uzbl, *args): '''Delete the Keylet object for this uzbl instance.''' - if uzbl in _UZBLS: - del _UZBLS[uzbl] + if uzbl in UZBLS: + del UZBLS[uzbl] def get_keylet(uzbl): @@ -102,10 +102,10 @@ def get_keylet(uzbl): # Startup events are not correctly captured and sent over the uzbl socket # yet so this line is needed because the INSTANCE_START event is lost. - if uzbl not in _UZBLS: + if uzbl not in UZBLS: add_instance(uzbl) - keylet = _UZBLS[uzbl] + keylet = UZBLS[uzbl] keylet._to_string = None return keylet -- cgit v1.2.3 From 1b8df44d31a47354148cb82948b5ad6011a44168 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 21 Sep 2009 17:34:17 +0800 Subject: Added on_event plugin and replaced the load_{start|commit|finish}_handler's --- examples/config/uzbl/config | 50 ++++++++---- examples/data/uzbl/scripts/plugins/on_event.py | 109 +++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/on_event.py (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index b611aa3..9ff27bc 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -2,24 +2,41 @@ # all settings are optional. you can use uzbl without any config at all (but it won't do much) # set some shortcuts + +# request BIND = set bind = request BIND +# request MODE_CONFIG = ... set toggle_modes = request TOGGLE_MODES +# request ON_EVENT +set on_event = request ON_EVENT + + set set_mode = set mode = +set set_status = set status_message = set shell_cmd = sh -c -# keyboard behavior in this sample config is sort of vimstyle + # Handlers -set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh -#set cookie_handler = spawn $XDG_DATA_HOME/uzbl/scripts/cookies.py -set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket -#set new_window = sh 'echo uri "$8" > $4' # open in same window -set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour +set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh +set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket +set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py + +# New window handler options +#set new_window = sh 'echo uri "$8" > $4' # open in same window +set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour -set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py -set load_start_handler = set status_message = wait -set load_commit_handler = set status_message = recv -set load_finish_handler = chain 'set status_message = done' 'spawn $XDG_DATA_HOME/uzbl/scripts/history.sh' + +# Load start handler +@on_event LOAD_START @set_status wait + +# Load commit handler +@on_event LOAD_COMMIT @set_status recv + +# Load finish handlers +@on_event LOAD_FINISH @set_status done +@on_event LOAD_FINISH spawn $XDG_DATA_HOME/uzbl/scripts/history.sh # Behaviour and appearance @@ -41,10 +58,12 @@ set selected_section = \@[\@SELECTED_URI]\@ set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @selected_section # Core settings -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) -set fifo_dir = /tmp -set socket_dir = /tmp +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) +set fifo_dir = /tmp +set socket_dir = /tmp + +### Keyboard binding section: # like this you can enter any command at runtime, interactively. prefixed by ':' @bind :_ = chain '%s' @@ -78,9 +97,6 @@ set socket_dir = /tmp @bind s _ = set %s @bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go @bind gg _ = uri http://www.google.com/search?q=%s -@bind i = toggle_insert_mode -# disable insert mode (1 to enable). note that Esc works to disable, regardless of this setting -@bind I = toggle_insert_mode 0 # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters #@bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh @@ -143,7 +159,7 @@ set socket_dir = /tmp @bind a<:>h = uri http://uzbl.org/ -### Mode config +### Mode config section: set default_mode = command diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py new file mode 100644 index 0000000..ccfab4c --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -0,0 +1,109 @@ +'''Plugin provides arbitrarily binding uzbl events to uzbl commands. + You can use $1,$2 to refer to the arguments appearing in the relevant event messages + +For example: + request ON_EVENT LINK_HOVER 'set SELECTED_URI = $1' + this will set the SELECTED_URI variable which you can display in your statusbar +''' + +import sys +import re +from event_manager import config + +__export__ = ['get_on_events', 'on_event'] + +UZBLS = {} + +def echo(msg): + if config['verbose']: + print 'on_event plugin:', msg + + +def error(msg): + sys.stderr.write('on_event plugin: error: %s\n' % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = {} + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_on_events(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def expand(cmd, args): + '''Replaces "%s %s %s.." with "arg1 arg2 arg3..". + + This could be improved by specifing explicitly which argument to substitue + for what by parsing "$@ $0 $1 $2 $3.." found in the command string.''' + + if '%s' not in cmd or not len(args): + return cmd + + if len(args) > 1: + for arg in args: + cmd = cmd.replace('%s', str(arg), 1) + + else: + cmd = cmd.replace('%s', str(args[0])) + + return cmd + + +def event_handler(uzbl, *args, **kargs): + '''This function handles all the events being watched by various + on_event definitions and responds accordingly.''' + + events = get_on_events(uzbl) + event = kargs['on_event'] + if event not in events: + return + + commands = events[event] + for cmd in commands: + cmd = expand(cmd, args) + uzbl.send(cmd) + + +def on_event(uzbl, event, cmd): + '''Add a new event to watch and respond to.''' + + events = get_on_events(uzbl) + if event not in events: + uzbl.connect(event, event_handler, on_event=event) + events[event] = [] + + cmds = events[event] + if cmd not in cmds: + cmds.append(cmd) + + +def parse_on_event(uzbl, args): + '''Parse ON_EVENT events and pass them to the on_event function. + + Syntax: "event ON_EVENT commands" + ''' + + split = args.split(' ', 1) + if len(split) != 2: + return error("invalid ON_EVENT syntax: %r" % args) + + event, cmd = split + on_event(uzbl, event, cmd) + + +def init(uzbl): + connects = {'ON_EVENT': parse_on_event, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance} + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) -- cgit v1.2.3 From 472d31cc7d43b90f9b9cf7e039beb4ec64adbee0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 21 Sep 2009 17:49:27 +0800 Subject: Allow events received from uzbl-core to contain no arguments. --- examples/data/uzbl/scripts/event_manager.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index c5f2eda..a4be6b5 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -557,6 +557,9 @@ class UzblInstance(object): print msg.rstrip() continue + if len(cmd) < 4: + cmd.append('') + event, args = cmd[2], cmd[3] try: self.handle_event(event, args) -- cgit v1.2.3 From 99742e877c6b97bd29c4f47f4c79f6565b4699a0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 21 Sep 2009 23:30:40 +0800 Subject: Added progress_bar plugin and updated config with examples. --- examples/config/uzbl/config | 22 +++- examples/data/uzbl/scripts/plugins/progress_bar.py | 142 +++++++++++++++++++++ 2 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 examples/data/uzbl/scripts/plugins/progress_bar.py (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9ff27bc..9c690ed 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -11,7 +11,8 @@ set mode_config = request MODE_CONFIG set toggle_modes = request TOGGLE_MODES # request ON_EVENT set on_event = request ON_EVENT - +# request PROGRESS_CONFIG = +set progress = request PROGRESS_CONFIG set set_mode = set mode = set set_status = set status_message = @@ -49,14 +50,29 @@ set prompt_style = foreground="grey" set mode_section = [\@[\@mode_indicator]\@] set keycmd_section = [\@[\@keycmd_prompt]\@\@[\@keycmd]\@] -set progress_section = \@[\@LOAD_PROGRESSBAR]\@ +set progress_section = \@[\@progress_format]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ set status_section = \@status_message -set selected_section = \@[\@SELECTED_URI]\@ +set selected_section = \@[\@SELECTED_URI]\@ set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @selected_section +# Progress bar config +@progress width = 8 +# %d = done, %p = pending, %a = arrow, %c = percent done, %i = int done, +# %s = spinner, %t = percent pending, %o = int pending. +@progress format = [%d>%p]%c +@progress spinner = -\\|/ +@progress arrow = > +@progress done = = +@progress pending = . + +# Or ride those spinnas' +#@progress format = [%d%s%p] +#@progress done = - +#@progress pending = + # Core settings set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp diff --git a/examples/data/uzbl/scripts/plugins/progress_bar.py b/examples/data/uzbl/scripts/plugins/progress_bar.py new file mode 100644 index 0000000..450e972 --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/progress_bar.py @@ -0,0 +1,142 @@ +import sys + +UZBLS = {} + + +DEFAULTS = {'width': 8, + 'done': '=', + 'pending': '.', + 'arrow': '>', + 'format': '[%d%a%p]%c', + 'spinner': '-\\|/', + 'updates': 0, + 'progress': 100} + + +def error(msg): + sys.stderr.write("progress_bar plugin: error: %s\n" % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_progress_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def update_progress(uzbl, prog=None): + '''Updates the progress_format variable on LOAD_PROGRESS update. + + The current substitution options are: + %d = done char * done + %p = pending char * remaining + %a = arrow + %c = percent done + %i = int done + %s = -\|/ spinner + %t = percent pending + %o = int pending + ''' + + prog_config = get_progress_config(uzbl) + config = uzbl.get_config() + + if prog is None: + prog = prog_config['progress'] + + prog = int(prog) + if prog < prog_config['progress']: + prog_config['updates'] = 0 + + prog_config['updates'] += 1 + prog_config['progress'] = prog + format = prog_config['format'] + width = prog_config['width'] + + # Inflate the done and pending bars to stop the progress bar + # jumping around. + if '%c' in format or '%i' in format: + count = format.count('%c') + format.count('%i') + width += (3-len(str(prog))) * count + + if '%t' in format or '%o' in format: + count = format.count('%t') + format.count('%o') + width += (3-len(str(100-prog))) * count + + done = int(((prog/100.0)*width)+0.5) + pending = width - done + + if '%d' in format: + format = format.replace('%d', prog_config['done']*done) + + if '%p' in format: + format = format.replace('%p', prog_config['pending']*pending) + + if '%a' in format: + format = format.replace('%a', prog_config['arrow']) + + if '%c' in format: + format = format.replace('%c', '%d%%' % prog) + + if '%i' in format: + format = format.replace('%i', '%d' % prog) + + if '%t' in format: + format = format.replace('%t', '%d%%' % (100-prog)) + + if '%o' in format: + format = format.replace('%o', '%d' % (100-prog)) + + if '%s' in format: + spin = '-' if not prog_config['spinner'] else prog_config['spinner'] + index = 0 if prog == 100 else prog_config['updates'] % len(spin) + char = '\\\\' if spin[index] == '\\' else spin[index] + format = format.replace('%s', char) + + if 'progress_format' not in config or config['progress_format'] != format: + config['progress_format'] = format + + +def progress_config(uzbl, args): + split = args.split('=', 1) + if len(split) != 2: + return error("invalid syntax: %r" % args) + + key, value = map(str.strip, split) + prog_config = get_progress_config(uzbl) + + if key not in prog_config: + return error("key error: %r" % args) + + if type(prog_config[key]) == type(1): + try: + value = int(value) + + except: + return error("invalid type: %r" % args) + + elif not value: + value = ' ' + + prog_config[key] = value + update_progress(uzbl) + + +def init(uzbl): + + connects = {'LOAD_PROGRESS': update_progress, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'PROGRESS_CONFIG': progress_config} + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) -- cgit v1.2.3 From a02795da7fc3996ea6fe01d451b09668b38d1a76 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 21 Sep 2009 23:40:20 +0800 Subject: Reset progress bar on LOAD_COMMIT --- examples/config/uzbl/config | 2 +- examples/data/uzbl/scripts/plugins/progress_bar.py | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9c690ed..4a9182d 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -66,7 +66,7 @@ set status_format = @mode_section @keycmd_sect @progress spinner = -\\|/ @progress arrow = > @progress done = = -@progress pending = . +@progress pending = # Or ride those spinnas' #@progress format = [%d%s%p] diff --git a/examples/data/uzbl/scripts/plugins/progress_bar.py b/examples/data/uzbl/scripts/plugins/progress_bar.py index 450e972..fd77810 100644 --- a/examples/data/uzbl/scripts/plugins/progress_bar.py +++ b/examples/data/uzbl/scripts/plugins/progress_bar.py @@ -2,7 +2,6 @@ import sys UZBLS = {} - DEFAULTS = {'width': 8, 'done': '=', 'pending': '.', @@ -54,9 +53,6 @@ def update_progress(uzbl, prog=None): prog = prog_config['progress'] prog = int(prog) - if prog < prog_config['progress']: - prog_config['updates'] = 0 - prog_config['updates'] += 1 prog_config['progress'] = prog format = prog_config['format'] @@ -107,6 +103,11 @@ def update_progress(uzbl, prog=None): def progress_config(uzbl, args): + '''Parse PROGRESS_CONFIG events from the uzbl instance. + + Syntax: event PROGRESS_CONFIG = + ''' + split = args.split('=', 1) if len(split) != 2: return error("invalid syntax: %r" % args) @@ -131,12 +132,21 @@ def progress_config(uzbl, args): update_progress(uzbl) -def init(uzbl): +def reset_progress(uzbl, args): + '''Reset the spinner counter, reset the progress int and re-draw the + progress bar on LOAD_COMMIT.''' + + prog_dict = get_progress_config(uzbl) + prog_dict['updates'] = prog_dict['progress'] = 0 + update_progress(uzbl) + +def init(uzbl): connects = {'LOAD_PROGRESS': update_progress, 'INSTANCE_START': add_instance, 'INSTANCE_EXIT': del_instance, - 'PROGRESS_CONFIG': progress_config} + 'PROGRESS_CONFIG': progress_config, + 'LOAD_COMMIT': reset_progress} for (event, handler) in connects.items(): uzbl.connect(event, handler) -- cgit v1.2.3 From 7c6c7933718950b00346c223f965fc28e8cdacea Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 01:29:24 +0800 Subject: Unicode support for the EM and sprite option for the progress plugin. --- examples/config/uzbl/config | 8 +++---- examples/data/uzbl/scripts/event_manager.py | 6 +++--- examples/data/uzbl/scripts/plugins/bind.py | 2 +- examples/data/uzbl/scripts/plugins/config.py | 6 +++--- examples/data/uzbl/scripts/plugins/mode.py | 4 ++-- examples/data/uzbl/scripts/plugins/on_event.py | 4 ++-- examples/data/uzbl/scripts/plugins/progress_bar.py | 25 ++++++++++++++-------- 7 files changed, 31 insertions(+), 24 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 4a9182d..1d45247 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -60,19 +60,19 @@ set status_format = @mode_section @keycmd_sect # Progress bar config @progress width = 8 -# %d = done, %p = pending, %a = arrow, %c = percent done, %i = int done, -# %s = spinner, %t = percent pending, %o = int pending. +# %d = done, %p = pending %c = percent done, %i = int done, %s = spinner, +# %t = percent pending, %o = int pending, %r = sprite scroll @progress format = [%d>%p]%c -@progress spinner = -\\|/ -@progress arrow = > @progress done = = @progress pending = # Or ride those spinnas' #@progress format = [%d%s%p] +#@progress spinner = -\\|/ #@progress done = - #@progress pending = + # Core settings set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index a4be6b5..18a6d54 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -396,7 +396,7 @@ class UzblInstance(object): while len(self._fifo_cmd_queue): msg = self._fifo_cmd_queue.pop(0) print '<-- %s' % msg - h.write("%s\n" % msg) + h.write(("%s\n" % msg).encode('utf-8')) h.close() @@ -408,7 +408,7 @@ class UzblInstance(object): while len(self._socket_cmd_queue): msg = self._socket_cmd_queue.pop(0) print '<-- %s' % msg - self._socket.send("%s\n" % msg) + self._socket.send(("%s\n" % msg).encode('utf-8')) def _send_fifo(self, msg): @@ -536,7 +536,7 @@ class UzblInstance(object): def read_from_uzbl_socket(self): '''Reads event messages from a uzbl socket.''' - raw = self._socket.recv(1024) + raw = unicode(self._socket.recv(8192), 'utf-8', 'ignore') if not raw: # Read null byte self._running = False diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index eaa1d40..2175da0 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -227,7 +227,7 @@ def bind(uzbl, glob, handler, *args, **kargs): def parse_bind_event(uzbl, args): '''Break "event BIND fl* = js follownums.js" into (glob, command).''' - split = map(str.strip, args.split('=', 1)) + split = map(unicode.strip, args.split('=', 1)) if len(split) != 2: return error('missing "=" in bind definition: %r' % args) diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py index 5ce614a..32114e9 100644 --- a/examples/data/uzbl/scripts/plugins/config.py +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -4,7 +4,7 @@ import types __export__ = ['set', 'get_config'] _VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match -_TYPECONVERT = {'int': int, 'float': float, 'str': str} +_TYPECONVERT = {'int': int, 'float': float, 'str': unicode} UZBLS = {} @@ -12,7 +12,7 @@ UZBLS = {} def escape(value): '''A real escaping function may be required.''' - return str(value) + return unicode(value) def get_config(uzbl): @@ -36,7 +36,7 @@ def set(uzbl, key, value): value = value.replace("\n", "\\n") config = get_config(uzbl) - if key not in config or str(config[key]) != str(value): + if key not in config or unicode(config[key]) != unicode(value): uzbl.send('set %s = %s' % (key, value)) diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py index 2befbf9..debaba6 100644 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -106,12 +106,12 @@ def config_changed(uzbl, key, value): def mode_config(uzbl, args): - split = map(str.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) + split = map(unicode.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) if len(split) != 2: return error("invalid MODE_CONFIG syntax: %r" % args) mode, set = split - split = map(str.strip, set.split('=', 1)) + split = map(unicode.strip, set.split('=', 1)) if len(split) != 2: return error("invalid MODE_CONFIG set command: %r" % args) diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py index ccfab4c..a05d91a 100644 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -50,10 +50,10 @@ def expand(cmd, args): if len(args) > 1: for arg in args: - cmd = cmd.replace('%s', str(arg), 1) + cmd = cmd.replace('%s', unicode(arg), 1) else: - cmd = cmd.replace('%s', str(args[0])) + cmd = cmd.replace('%s', unicode(args[0])) return cmd diff --git a/examples/data/uzbl/scripts/plugins/progress_bar.py b/examples/data/uzbl/scripts/plugins/progress_bar.py index fd77810..c9f8a36 100644 --- a/examples/data/uzbl/scripts/plugins/progress_bar.py +++ b/examples/data/uzbl/scripts/plugins/progress_bar.py @@ -5,9 +5,9 @@ UZBLS = {} DEFAULTS = {'width': 8, 'done': '=', 'pending': '.', - 'arrow': '>', 'format': '[%d%a%p]%c', 'spinner': '-\\|/', + 'sprites': 'loading', 'updates': 0, 'progress': 100} @@ -38,12 +38,12 @@ def update_progress(uzbl, prog=None): The current substitution options are: %d = done char * done %p = pending char * remaining - %a = arrow %c = percent done %i = int done %s = -\|/ spinner %t = percent pending %o = int pending + %r = sprites ''' prog_config = get_progress_config(uzbl) @@ -52,9 +52,11 @@ def update_progress(uzbl, prog=None): if prog is None: prog = prog_config['progress'] - prog = int(prog) + else: + prog = int(prog) + prog_config['progress'] = prog + prog_config['updates'] += 1 - prog_config['progress'] = prog format = prog_config['format'] width = prog_config['width'] @@ -77,9 +79,6 @@ def update_progress(uzbl, prog=None): if '%p' in format: format = format.replace('%p', prog_config['pending']*pending) - if '%a' in format: - format = format.replace('%a', prog_config['arrow']) - if '%c' in format: format = format.replace('%c', '%d%%' % prog) @@ -93,11 +92,19 @@ def update_progress(uzbl, prog=None): format = format.replace('%o', '%d' % (100-prog)) if '%s' in format: - spin = '-' if not prog_config['spinner'] else prog_config['spinner'] + spinner = prog_config['spinner'] + spin = '-' if not spinner else spinner index = 0 if prog == 100 else prog_config['updates'] % len(spin) char = '\\\\' if spin[index] == '\\' else spin[index] format = format.replace('%s', char) + if '%r' in format: + sprites = prog_config['sprites'] + sprites = '-' if not sprites else sprites + index = int(((prog/100.0)*len(sprites))+0.5)-1 + sprite = '\\\\' if sprites[index] == '\\' else sprites[index] + format = format.replace('%r', sprite) + if 'progress_format' not in config or config['progress_format'] != format: config['progress_format'] = format @@ -112,7 +119,7 @@ def progress_config(uzbl, args): if len(split) != 2: return error("invalid syntax: %r" % args) - key, value = map(str.strip, split) + key, value = map(unicode.strip, split) prog_config = get_progress_config(uzbl) if key not in prog_config: -- cgit v1.2.3 From d122dfcde37a2c24af29bddc031da6189b63a34e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 15:45:28 +0800 Subject: Added a plugin template for the event manager. --- .../data/uzbl/scripts/plugins/plugin_template.py | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/data/uzbl/scripts/plugins/plugin_template.py (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/plugin_template.py b/examples/data/uzbl/scripts/plugins/plugin_template.py new file mode 100644 index 0000000..55bb62a --- /dev/null +++ b/examples/data/uzbl/scripts/plugins/plugin_template.py @@ -0,0 +1,69 @@ +'''Plugin template.''' + +# A list of functions this plugin exports to be used via uzbl object. +__export__ = ['myplugin_function',] + +# Holds the per-instance data dict. +UZBLS = {} + +# The default instance dict. +DEFAULTS = {} + + +def add_instance(uzbl, pid): + '''Add a new instance with default config options.''' + + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, pid): + '''Delete data stored for an instance.''' + + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_myplugin_dict(uzbl): + '''Get data stored for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def myplugin_function(uzbl, *args, **kargs): + '''Custom plugin function which is exported by the __export__ list at the + top of the file for use by other functions/callbacks.''' + + print "My plugin function arguments:", args, kargs + + # Get the per-instance data object. + data = get_myplugin_dict(uzbl) + + # Function logic goes here. + + +def myplugin_event_parser(uzbl, args): + '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' + + print "Got MYPLUGIN_EVENT with arguments: %r" % args + + # Parsing logic goes here. + + +def init(uzbl): + '''The main function of the plugin which is used to attach all the event + hooks that are going to be used throughout the plugins life. This function + is called each time a UzblInstance() object is created in the event + manager.''' + + connects = { + # EVENT_NAME HANDLER_FUNCTION + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'MYPLUGIN_EVENT': myplugin_event_parser, + } + + for (event, handler) in connects.items(): + uzbl.connect(event, handler) -- cgit v1.2.3 From 568e2e24a7bbaf2ba279aaa5ddcd3c25e5902ec8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 16:41:09 +0800 Subject: on_event now transforms "%@ %1 %2.." into " .." --- examples/config/uzbl/config | 3 ++ examples/data/uzbl/scripts/plugins/on_event.py | 41 +++++++++++++++----------- 2 files changed, 26 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 1d45247..64ece70 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -39,6 +39,9 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh @on_event LOAD_FINISH @set_status done @on_event LOAD_FINISH spawn $XDG_DATA_HOME/uzbl/scripts/history.sh +# Misc on_event handlers +#@on_event CONFIG_CHANGED print Config changed: %1 = %2 + # Behaviour and appearance set show_status = 1 diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py index a05d91a..dc81fcc 100644 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -1,9 +1,19 @@ -'''Plugin provides arbitrarily binding uzbl events to uzbl commands. - You can use $1,$2 to refer to the arguments appearing in the relevant event messages - -For example: - request ON_EVENT LINK_HOVER 'set SELECTED_URI = $1' - this will set the SELECTED_URI variable which you can display in your statusbar +'''Plugin provides arbitrary binding of uzbl events to uzbl commands. + +Formatting options: + %@ = space separated string of the arguments + %1 = argument 1 + %2 = argument 2 + %n = argument n + +Usage: + request ON_EVENT LINK_HOVER set selected_uri = $1 + --> LINK_HOVER http://uzbl.org/ + <-- set selected_uri = http://uzbl.org/ + + request ON_EVENT CONFIG_CHANGED print Config changed: %1 = %2 + --> CONFIG_CHANGED selected_uri http://uzbl.org/ + <-- print Config changed: selected_uri = http://uzbl.org/ ''' import sys @@ -40,20 +50,15 @@ def get_on_events(uzbl): def expand(cmd, args): - '''Replaces "%s %s %s.." with "arg1 arg2 arg3..". - - This could be improved by specifing explicitly which argument to substitue - for what by parsing "$@ $0 $1 $2 $3.." found in the command string.''' - - if '%s' not in cmd or not len(args): - return cmd + '''Replaces "%@ %1 %2 %3..." with " ...".''' - if len(args) > 1: - for arg in args: - cmd = cmd.replace('%s', unicode(arg), 1) + if '%@' in cmd: + cmd = cmd.replace('%@', ' '.join(map(unicode, args))) - else: - cmd = cmd.replace('%s', unicode(args[0])) + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) return cmd -- cgit v1.2.3 From 28315daa6ba4096a6a4965ea9f0a706ee521e360 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 17:16:49 +0800 Subject: Made modcmd updating optional. Used when in insert mode. --- examples/config/uzbl/config | 1 + examples/data/uzbl/scripts/plugins/keycmd.py | 18 +++++++++++++++--- examples/data/uzbl/scripts/plugins/mode.py | 2 ++ 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 64ece70..fb1adbc 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -199,6 +199,7 @@ set stack = @mode_config stack # Multi-stage-binding mode config. @stack keycmd_events = 1 +@stack modcmd_updates = 1 @stack prompt_style = foreground="#888" weight="light" @stack status_background = #202020 @stack mode_indicator = Bnd diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 7abb042..4e67a50 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -17,6 +17,17 @@ _SIMPLEKEYS = { } +def keycmd_escape(keycmd): + '''Prevent outgoing keycmd values from expanding inside the + status_format.''' + + for char in ['\\', '@']: + if char in keycmd: + keycmd = keycmd.replace(char, '\\'+char) + + return keycmd + + def get_regex(regex): '''Compiling regular expressions is a very time consuming so return a pre-compiled regex match object if possible.''' @@ -139,14 +150,15 @@ def update_event(uzbl, keylet): if keylet.modcmd: keycmd = keylet.to_string() uzbl.event('MODCMD_UPDATE', keylet) - if keycmd == keylet.to_string(): - config['keycmd'] = keylet.to_string() + if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': + if keycmd == keylet.to_string(): + config['keycmd'] = keycmd_escape(keycmd) elif 'keycmd_events' not in config or config['keycmd_events'] == '1': keycmd = keylet.cmd uzbl.event('KEYCMD_UPDATE', keylet) if keycmd == keylet.cmd: - config['keycmd'] = keylet.cmd + config['keycmd'] = keycmd_escape(keycmd) def key_press(uzbl, key): diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py index debaba6..f8464e7 100644 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -12,10 +12,12 @@ DEFAULTS = { 'insert': { 'forward_keys': True, 'keycmd_events': False, + 'modcmd_updates': False, 'indicator': 'I'}, 'command': { 'forward_keys': False, 'keycmd_events': True, + 'modcmd_updates': True, 'indicator': 'C'}}} _RE_FINDSPACES = re.compile("\s+") -- cgit v1.2.3 From 12a23eb6a95ddb65173d547f5ee74da979a51f38 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 17:17:26 +0800 Subject: Make sure event name is capitalised. --- examples/data/uzbl/scripts/plugins/on_event.py | 1 + 1 file changed, 1 insertion(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py index dc81fcc..33039cb 100644 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -81,6 +81,7 @@ def event_handler(uzbl, *args, **kargs): def on_event(uzbl, event, cmd): '''Add a new event to watch and respond to.''' + event = event.upper() events = get_on_events(uzbl) if event not in events: uzbl.connect(event, event_handler, on_event=event) -- cgit v1.2.3 From 62a70a38d8d62e46d8b8b1d9442a0b8ea2e7c0a2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 17:55:20 +0800 Subject: Fixed "config[key] = value" and "uzbl.set(key, value)" behaviour. --- examples/data/uzbl/scripts/plugins/config.py | 7 +++---- examples/data/uzbl/scripts/plugins/keycmd.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py index 32114e9..dc2070a 100644 --- a/examples/data/uzbl/scripts/plugins/config.py +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -35,9 +35,7 @@ def set(uzbl, key, value): if '\n' in value: value = value.replace("\n", "\\n") - config = get_config(uzbl) - if key not in config or unicode(config[key]) != unicode(value): - uzbl.send('set %s = %s' % (key, value)) + uzbl.send('set %s = %s' % (key, value)) def add_instance(uzbl, *args): @@ -63,7 +61,8 @@ class ConfigDict(dict): def __setitem__(self, key, value): '''Makes "config[key] = value" a wrapper for the set function.''' - set(self._uzbl, key, value) + if key not in self or unicode(self[key]) != unicode(value): + set(self._uzbl, key, value) def variable_set(uzbl, args): diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 4e67a50..4b243a7 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -150,15 +150,19 @@ def update_event(uzbl, keylet): if keylet.modcmd: keycmd = keylet.to_string() uzbl.event('MODCMD_UPDATE', keylet) - if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': - if keycmd == keylet.to_string(): - config['keycmd'] = keycmd_escape(keycmd) + if keycmd != keylet.to_string(): + return + + if 'modcmd_updates' in config and config['modcmd_updates'] != '1': + return + + uzbl.set('keycmd', keycmd_escape(keycmd)) elif 'keycmd_events' not in config or config['keycmd_events'] == '1': keycmd = keylet.cmd uzbl.event('KEYCMD_UPDATE', keylet) if keycmd == keylet.cmd: - config['keycmd'] = keycmd_escape(keycmd) + uzbl.set('keycmd', keycmd_escape(keycmd)) def key_press(uzbl, key): -- cgit v1.2.3 From 720c54b26e0cdee7b9777d0dc97bc3dc480b66d8 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 17:57:14 +0800 Subject: Update config as insert mode no longer updates modcmd's. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index fb1adbc..cc2f8cb 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -193,13 +193,13 @@ set stack = @mode_config stack @command mode_indicator = Cmd # Insert mode config. -@insert keycmd_style = foreground="green" @insert status_background = #303030 @insert mode_indicator = Ins # Multi-stage-binding mode config. @stack keycmd_events = 1 @stack modcmd_updates = 1 +@stack keycmd_style = foreground="red" @stack prompt_style = foreground="#888" weight="light" @stack status_background = #202020 @stack mode_indicator = Bnd -- cgit v1.2.3 From 6579d4f7449b9baf60696ef1a9d5641ce59fe4e4 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Sep 2009 18:04:05 +0800 Subject: Raise errors on null arguments to bind and on_event parsers. --- examples/data/uzbl/scripts/plugins/bind.py | 3 +++ examples/data/uzbl/scripts/plugins/on_event.py | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 2175da0..b7a6e9b 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -227,6 +227,9 @@ def bind(uzbl, glob, handler, *args, **kargs): def parse_bind_event(uzbl, args): '''Break "event BIND fl* = js follownums.js" into (glob, command).''' + if not args: + return error('missing bind arguments') + split = map(unicode.strip, args.split('=', 1)) if len(split) != 2: return error('missing "=" in bind definition: %r' % args) diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py index 33039cb..fbbc75d 100644 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -95,8 +95,10 @@ def on_event(uzbl, event, cmd): def parse_on_event(uzbl, args): '''Parse ON_EVENT events and pass them to the on_event function. - Syntax: "event ON_EVENT commands" - ''' + Syntax: "event ON_EVENT commands".''' + + if not args: + return error("missing on_event arguments") split = args.split(' ', 1) if len(split) != 2: -- cgit v1.2.3 From 0aa4a6de044fe26c92f36871236749d6b6f3b4f1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 25 Sep 2009 20:49:45 +0800 Subject: Updated config with new $PATH-like "dir1:dir2:dir3:script" spawn format --- examples/config/uzbl/config | 80 +++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 35 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index cc2f8cb..ba684a0 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,7 +1,7 @@ # example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) -# set some shortcuts +# === Shortcuts ============================================================== # request BIND = set bind = request BIND @@ -18,17 +18,20 @@ set set_mode = set mode = set set_status = set status_message = set shell_cmd = sh -c +# Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" +set scripts_dir = $XDG_DATA_HOME/uzbl:/usr/local/share/uzbl/examples/data/uzbl:scripts -# Handlers -set download_handler = spawn $XDG_DATA_HOME/uzbl/scripts/download.sh + +# === Handlers =============================================================== + +set download_handler = spawn @scripts_dir/download.sh set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket -set scheme_handler = spawn $XDG_DATA_HOME/uzbl/scripts/scheme.py +set scheme_handler = spawn @scripts_dir/scheme.py # New window handler options #set new_window = sh 'echo uri "$8" > $4' # open in same window set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour - # Load start handler @on_event LOAD_START @set_status wait @@ -37,13 +40,14 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh # Load finish handlers @on_event LOAD_FINISH @set_status done -@on_event LOAD_FINISH spawn $XDG_DATA_HOME/uzbl/scripts/history.sh +@on_event LOAD_FINISH spawn @scripts_dir/history.sh # Misc on_event handlers #@on_event CONFIG_CHANGED print Config changed: %1 = %2 -# Behaviour and appearance +# === Behaviour and appearance =============================================== + set show_status = 1 set status_top = 0 set status_background = #303030 @@ -76,15 +80,17 @@ set status_format = @mode_section @keycmd_sect #@progress pending = -# Core settings +# === Core settings ========================================================== + set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp set socket_dir = /tmp -### Keyboard binding section: +# === Keyboard bindings ====================================================== -# like this you can enter any command at runtime, interactively. prefixed by ':' +# With this command you can enter in any command at runtime when prefixed with +# a colon. @bind :_ = chain '%s' @bind j = scroll_vert 20 @@ -110,20 +116,18 @@ set socket_dir = /tmp @bind n = search @bind N = search_reverse @bind gh = uri http://www.uzbl.org -# shortcut to set the uri. TODO: i think we can abandon the uri command in favor of 'set uri = ..' -#@bind o _ = uri %s # shortcut to set variables @bind s _ = set %s @bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go @bind gg _ = uri http://www.google.com/search?q=%s # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -#@bind B = spawn $XDG_DATA_HOME/uzbl/scripts/insert_bookmark.sh -@bind U = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_history.sh -@bind u = spawn $XDG_DATA_HOME/uzbl/scripts/load_url_from_bookmarks.sh +#@bind B = spawn @scripts_dir}/insert_bookmark.sh +@bind U = spawn @scripts_dir/load_url_from_history.sh +@bind u = spawn @scripts_dir/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection -@bind yurl = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 6 primary -@bind ytitle = spawn $XDG_DATA_HOME/uzbl/scripts/yank.sh 7 clipboard +@bind yurl = spawn @scripts_dir/yank.sh 6 primary +@bind ytitle = spawn @scripts_dir/yank.sh 7 clipboard # does the same as yurl but without needing a script @bind y2url = sh 'echo -n $6 | xclip' # go the page from primary selection @@ -133,7 +137,7 @@ set socket_dir = /tmp # start a new uzbl instance from the page in primary selection @bind 'p = sh 'exec uzbl --uri $(xclip -o)' @bind ZZ = exit -@bind Xs = js alert("hi"); +@bind Xs = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -147,40 +151,41 @@ set socket_dir = /tmp @bind !reload = sh 'cat $1 > $4' # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically -@bind za = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh -@bind ze = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh edit -@bind zn = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh new -@bind zl = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.sh load +set formfiller = spawn @scripts_dir/formfiller +@bind za = @{formfiller}.sh +@bind ze = @{formfiller}.sh edit +@bind zn = @{formfiller}.sh new +@bind zl = @{formfiller}.sh load -# other - more advanced - implementation using perl: (could not get this to run - Dieter ) -@bind LL = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl load -@bind LN = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl new -@bind LE = spawn $XDG_DATA_HOME/uzbl/scripts/formfiller.pl edit +# Or the more advanced implementation using perl: (could not get this to run - Dieter) +@bind LL = @{formfiller}.pl load +@bind LN = @{formfiller}.pl new +@bind LE = @{formfiller}.pl edit # we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) # this is similar to how it works in vimperator (and konqueror) # TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? #hit F to toggle the Hints (now in form of link numbering) -@bind F = script $XDG_DATA_HOME/uzbl/scripts/hint.js +@bind F = script @scripts_dir/hint.js # the most stable version: -@bind fl* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers.js %s +@bind fl* = script @scripts_dir/follow_Numbers.js %s # using strings, not polished yet: -@bind fL* = script $XDG_DATA_HOME/uzbl/scripts/follow_Numbers_Strings.js %s +@bind fL* = script @scripts_dir/follow_Numbers_Strings.js %s -# Examples using multi-stage-bindings with text prompts +# Examples using multi-stage-bindings with text prompts. @bind o_ = uri %s # Prints tab separated "uri title keyword tags" to the bookmarks file. -@bind b__ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +# TODO: Improve bookmarks script to handle this format & include date in bookmark format. +@bind b__ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +# Multi-stage bindings with blank prompts (similar behaviour to emacs M-c M-s bindings?) @bind a<:>q = exit @bind a<:>h = uri http://uzbl.org/ -### Mode config section: - -set default_mode = command +# === Mode configuration ===================================================== # Define some mode specific uzbl configurations. set command = @mode_config command @@ -204,7 +209,9 @@ set stack = @mode_config stack @stack status_background = #202020 @stack mode_indicator = Bnd +set default_mode = command +# Mode bindings: # Changing mode method via set. @bind I = @set_mode insert @@ -214,5 +221,8 @@ set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins @bind i = @toggle_cmd_ins -# "home" page if you will + +# === Post-load misc commands =============================================== + +# Set the "home" page. set uri = uzbl.org -- cgit v1.2.3 From 69cc7552aa64e0e64f5f4df751871eb9ae663e28 Mon Sep 17 00:00:00 2001 From: keis Date: Tue, 22 Sep 2009 20:52:23 +0200 Subject: add simple commandline-ish editing --- examples/data/uzbl/scripts/plugins/keycmd.py | 96 ++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 7d835d8..218681c 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -32,15 +32,15 @@ class Keylet(object): typed.''' def __init__(self): - self.cmd = "" + self.cmd = '' + self.cmd_s = '' self.held = [] # to_string() string building cache. self._to_string = None self.modcmd = False - self.wasmod = True - + self.wasmod = False def __repr__(self): return "" % self.to_string() @@ -55,12 +55,12 @@ class Keylet(object): return self._to_string if not self.held: - self._to_string = self.cmd + self._to_string = self.cmd + self.cmd_s else: - self._to_string = ''.join(["<%s>" % key for key in self.held]) - if self.cmd: - self._to_string += "%s" % self.cmd + self._to_string = ''.join(['<%s>' % key for key in self.held]) + if self.cmd or self.cmd_s: + self._to_string += '%s%s' % (self.cmd, self.cmd_s) return self._to_string @@ -117,7 +117,7 @@ def clear_keycmd(uzbl): if not k: return - k.cmd = "" + k.cmd = k.cmd_s = '' k._to_string = None if k.modcmd: @@ -135,9 +135,11 @@ def update_event(uzbl, keylet): uzbl.config['keycmd'] = keylet.to_string() uzbl.event("MODCMD_UPDATE", keylet) - else: - uzbl.config['keycmd'] = keylet.cmd - uzbl.event("KEYCMD_UPDATE", keylet) + elif 'keycmd_events' not in uzbl.config or uzbl.config['keycmd_events'] == '1': + keycmd = keylet.cmd + keylet.cmd_s + uzbl.event('KEYCMD_UPDATE', keylet) + if keycmd == (keylet.cmd + keylet.cmd_s): + uzbl.config['keycmd'] = keylet.cmd + keylet.cmd_s def key_press(uzbl, key): @@ -167,16 +169,16 @@ def key_press(uzbl, key): if not k: return + print k.held, k.modcmd, k.wasmod, k.cmd, k.cmd_s cmdmod = False if k.held and k.wasmod: k.modcmd = True k.wasmod = False cmdmod = True - if k.cmd and key == "Space": - if k.cmd: - k.cmd += " " - cmdmod = True + if (k.cmd or k.cmd_s) and key == 'Space': + k.cmd += ' ' + cmdmod = True elif not k.modcmd and key == 'BackSpace': if k.cmd: @@ -187,6 +189,18 @@ def key_press(uzbl, key): else: cmdmod = True + elif not k.modcmd and key == 'Left': + if k.cmd: + k.cmd_s = k.cmd[-1] + k.cmd_s + k.cmd = k.cmd[:-1] + cmdmod = True + + elif not k.modcmd and key == 'Right': + if k.cmd_s: + k.cmd = k.cmd + k.cmd_s[0] + k.cmd_s = k.cmd_s[1:] + cmdmod = True + elif not k.modcmd and key == 'Return': uzbl.event("KEYCMD_EXEC", k) clear_keycmd(uzbl) @@ -194,8 +208,22 @@ def key_press(uzbl, key): elif not k.modcmd and key == 'Escape': clear_keycmd(uzbl) - elif not k.held and not k.cmd: - k.modcmd = True if len(key) > 1 else False + elif not k.modcmd and key == 'Ctrl': + k.held.append(key) + + elif not k.modcmd and k.held and len(key) == 1: + if key == 'w': + cmdmod = True + k.cmd = ' '.join(k.cmd.split(' ')[:-1]) + elif key == 'a': + k.cmd_s = k.cmd + k.cmd_s + k.cmd = '' + elif key == 'e': + k.cmd = k.cmd + k.cmd_s + k.cmd_s = '' + + elif not k.held and not k.cmd and len(key) > 1: + k.modcmd = True k.held.append(key) k.held.sort() cmdmod = True @@ -213,13 +241,14 @@ def key_press(uzbl, key): k.cmd += key else: - cmdmod = True - if len(key) == 1: - if key not in k.held: - k.held.append(key) - k.held.sort() + if 'keycmd_events' not in uzbl.config or uzbl.config['keycmd_events'] == '1': + if len(key) == 1: + cmdmod = True + k.cmd += key - k.cmd += key + elif k.cmd or k.cmd_s: + cmdmod = True + k.cmd = k.cmd_s = '' if cmdmod: update_event(uzbl, k) @@ -243,11 +272,18 @@ def key_release(uzbl, key): return cmdmod = False - if k.modcmd and key in k.held: - uzbl.event("MODCMD_EXEC", k) + if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: + key = 'Shift-Tab' + + elif key in ['Shift', 'Alt'] and 'Meta' in k.held: + key = 'Meta' + + if key in k.held: + if k.modcmd: + uzbl.event('MODCMD_EXEC', k) + clear_keycmd(uzbl) + k.held.remove(key) - k.held.sort() - clear_keycmd(uzbl) elif not k.modcmd and key in k.held: k.held.remove(key) @@ -260,6 +296,11 @@ def key_release(uzbl, key): if cmdmod: update_event(uzbl, k) +def config_changed(uzbl, k, v): + if k == 'keycmd': + keylet = get_keylet(uzbl) + if v != keylet.cmd + keylet.cmd_s: + keylet.cmd,keylet.cmd_s = v,'' def init(uzbl): '''Connect handlers to uzbl events.''' @@ -268,3 +309,4 @@ def init(uzbl): uzbl.connect('INSTANCE_STOP', del_instance) uzbl.connect('KEY_PRESS', key_press) uzbl.connect('KEY_RELEASE', key_release) + uzbl.connect('CONFIG_CHANGED', config_changed) -- cgit v1.2.3 From 901bb596d61f6450225515a538409e7fa4e33dc1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 30 Sep 2009 18:39:14 +0800 Subject: Use the cleaner connect_dict function for adding multiple events. --- examples/data/uzbl/scripts/event_manager.py | 11 +++++++++++ examples/data/uzbl/scripts/plugins/bind.py | 3 +-- examples/data/uzbl/scripts/plugins/config.py | 3 +-- examples/data/uzbl/scripts/plugins/keycmd.py | 3 +-- examples/data/uzbl/scripts/plugins/mode.py | 3 +-- examples/data/uzbl/scripts/plugins/on_event.py | 4 ++-- examples/data/uzbl/scripts/plugins/plugin_template.py | 16 +++++++++++----- examples/data/uzbl/scripts/plugins/progress_bar.py | 3 +-- 8 files changed, 29 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 18a6d54..2e84ded 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -439,6 +439,17 @@ class UzblInstance(object): return handler + def connect_dict(self, connect_dict): + '''Connect a dictionary comprising of {"EVENT_NAME": handler, ..} to + the event handler stack. + + If you need to supply args or kargs to an event use the normal connect + function.''' + + for (event, handler) in connect_dict.items(): + self.connect(event, handler) + + def remove_by_id(self, hid): '''Remove connected event handler by unique handler id.''' diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index b7a6e9b..15f6f8e 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -371,5 +371,4 @@ def init(uzbl): 'MODCMD_EXEC': modcmd_exec, 'MODE_CHANGED': clear_stack} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py index dc2070a..22803b4 100644 --- a/examples/data/uzbl/scripts/plugins/config.py +++ b/examples/data/uzbl/scripts/plugins/config.py @@ -84,5 +84,4 @@ def init(uzbl): 'INSTANCE_START': add_instance, 'INSTANCE_EXIT': del_instance} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 4b243a7..fcf70c8 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -296,5 +296,4 @@ def init(uzbl): 'KEY_PRESS': key_press, 'KEY_RELEASE': key_release} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py index f8464e7..ad0d9a8 100644 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ b/examples/data/uzbl/scripts/plugins/mode.py @@ -156,5 +156,4 @@ def init(uzbl): 'LOAD_START': load_reset, 'TOGGLE_MODES': toggle_modes} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py index fbbc75d..242f9b0 100644 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ b/examples/data/uzbl/scripts/plugins/on_event.py @@ -109,9 +109,9 @@ def parse_on_event(uzbl, args): def init(uzbl): + connects = {'ON_EVENT': parse_on_event, 'INSTANCE_START': add_instance, 'INSTANCE_EXIT': del_instance} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/plugin_template.py b/examples/data/uzbl/scripts/plugins/plugin_template.py index 55bb62a..03cb748 100644 --- a/examples/data/uzbl/scripts/plugins/plugin_template.py +++ b/examples/data/uzbl/scripts/plugins/plugin_template.py @@ -10,13 +10,13 @@ UZBLS = {} DEFAULTS = {} -def add_instance(uzbl, pid): +def add_instance(uzbl, *args): '''Add a new instance with default config options.''' UZBLS[uzbl] = dict(DEFAULTS) -def del_instance(uzbl, pid): +def del_instance(uzbl, *args): '''Delete data stored for an instance.''' if uzbl in UZBLS: @@ -58,12 +58,18 @@ def init(uzbl): is called each time a UzblInstance() object is created in the event manager.''' + # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event + # handler stack: connects = { - # EVENT_NAME HANDLER_FUNCTION 'INSTANCE_START': add_instance, 'INSTANCE_EXIT': del_instance, 'MYPLUGIN_EVENT': myplugin_event_parser, } - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + # And connect the dicts event handlers to the handler stack. + uzbl.connect_dict(connects) + + # Or connect a handler to an event manually and supply additional optional + # arguments: + + #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) diff --git a/examples/data/uzbl/scripts/plugins/progress_bar.py b/examples/data/uzbl/scripts/plugins/progress_bar.py index c9f8a36..b6fcb1b 100644 --- a/examples/data/uzbl/scripts/plugins/progress_bar.py +++ b/examples/data/uzbl/scripts/plugins/progress_bar.py @@ -155,5 +155,4 @@ def init(uzbl): 'PROGRESS_CONFIG': progress_config, 'LOAD_COMMIT': reset_progress} - for (event, handler) in connects.items(): - uzbl.connect(event, handler) + uzbl.connect_dict(connects) -- cgit v1.2.3 From 925a20268e793f38b043b5b8dc2670a732c18f36 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 30 Sep 2009 22:40:51 +0800 Subject: Use a cursor instead of split cmd strings & new keycmd events. --- examples/config/uzbl/config | 3 +- examples/data/uzbl/scripts/plugins/keycmd.py | 193 ++++++++++++++++----------- 2 files changed, 120 insertions(+), 76 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index ba684a0..fd5fe52 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -54,9 +54,10 @@ set status_background = #303030 set keycmd_style = weight="bold" foreground="red" set prompt_style = foreground="grey" +set cursor_style = underline="single" set mode_section = [\@[\@mode_indicator]\@] -set keycmd_section = [\@[\@keycmd_prompt]\@\@[\@keycmd]\@] +set keycmd_section = [\@[\@keycmd_prompt]\@\@keycmd] set progress_section = \@[\@progress_format]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 96e61b4..3dd6f37 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -1,7 +1,7 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. -__export__ = ['clear_keycmd',] +__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet'] # Regular expression compile cache. _RE_CACHE = {} @@ -16,16 +16,22 @@ _SIMPLEKEYS = { 'space':'Space', } +# Keycmd format which includes the markup for the cursor. +KEYCMD_FORMAT = "%s%s%s" -def keycmd_escape(keycmd): + +def escape(str): '''Prevent outgoing keycmd values from expanding inside the status_format.''' + if not str: + return '' + for char in ['\\', '@']: - if char in keycmd: - keycmd = keycmd.replace(char, '\\'+char) + if char in str: + str = str.replace(char, '\\'+char) - return keycmd + return "@[%s]@" % str def get_regex(regex): @@ -44,7 +50,7 @@ class Keylet(object): def __init__(self): self.cmd = '' - self.cmd_s = '' + self.cursor = 0 self.held = [] # to_string() string building cache. @@ -66,12 +72,12 @@ class Keylet(object): return self._to_string if not self.held: - self._to_string = self.cmd + self.cmd_s + self._to_string = self.cmd else: self._to_string = ''.join(['<%s>' % key for key in self.held]) - if self.cmd or self.cmd_s: - self._to_string += '%s%s' % (self.cmd, self.cmd_s) + if self.cmd: + self._to_string += self.cmd return self._to_string @@ -125,10 +131,8 @@ def clear_keycmd(uzbl): '''Clear the keycmd for this uzbl instance.''' k = get_keylet(uzbl) - if not k: - return - - k.cmd = k.cmd_s = '' + k.cmd = '' + k.cursor = 0 k._to_string = None if k.modcmd: @@ -142,27 +146,41 @@ def clear_keycmd(uzbl): uzbl.event('KEYCMD_CLEAR') -def update_event(uzbl, keylet): - '''Raise keycmd/modcmd update events.''' +def update_event(uzbl, k): + '''Raise keycmd & modcmd update events.''' config = uzbl.get_config() - - if keylet.modcmd: - keycmd = keylet.to_string() - uzbl.event('MODCMD_UPDATE', keylet) - if keycmd != keylet.to_string(): + if k.modcmd: + keycmd = k.to_string() + uzbl.event('MODCMD_UPDATE', k) + if keycmd != k.to_string(): return if 'modcmd_updates' in config and config['modcmd_updates'] != '1': return - elif 'keycmd_events' not in config or config['keycmd_events'] == '1': - keycmd = keylet.cmd + keylet.cmd_s - uzbl.event('KEYCMD_UPDATE', keylet) - if keycmd != (keylet.cmd + keylet.cmd_s): - return + return uzbl.set('keycmd', escape(keycmd)) - uzbl.set('keycmd', keycmd_escape(keycmd)) + if 'keycmd_events' in config and config['keycmd_events'] != '1': + return + + keycmd = k.cmd + uzbl.event('KEYCMD_UPDATE', k) + if keycmd != k.cmd: + return + + if not k.cmd: + return uzbl.set('keycmd', '') + + # Generate the pango markup for the cursor in the keycmd. + if k.cursor < len(k.cmd): + cursor = k.cmd[k.cursor] + + else: + cursor = ' ' + + chunks = map(escape, [k.cmd[:k.cursor], cursor, k.cmd[k.cursor+1:]]) + uzbl.set('keycmd', KEYCMD_FORMAT % tuple(chunks)) def key_press(uzbl, key): @@ -173,9 +191,12 @@ def key_press(uzbl, key): modkey still held from the previous modcmd (I.e. +t, clear & +o without having to re-press ) 3. In non-modcmd mode: - a. BackSpace deletes the last character in the keycmd. - b. Return raises a KEYCMD_EXEC event then clears the keycmd. - c. Escape clears the keycmd. + a. BackSpace deletes the character before the cursor position. + b. Delete deletes the character at the cursor position. + c. End moves the cursor to the end of the keycmd. + d. Home moves the cursor to the beginning of the keycmd. + e. Return raises a KEYCMD_EXEC event then clears the keycmd. + f. Escape clears the keycmd. 4. If keycmd and held keys are both empty/null and a modkey was pressed set modcmd mode. 5. If in modcmd mode only mod keys are added to the held keys list. @@ -188,39 +209,32 @@ def key_press(uzbl, key): key = make_simple(key) k = get_keylet(uzbl) - if not k: - return - - print k.held, k.modcmd, k.wasmod, k.cmd, k.cmd_s cmdmod = False if k.held and k.wasmod: k.modcmd = True k.wasmod = False cmdmod = True - if (k.cmd or k.cmd_s) and key == 'Space': - k.cmd += ' ' + if k.cmd and key == 'Space': + k.cmd = "%s %s" % (k.cmd[:k.cursor], k.cmd[k.cursor:]) + k.cursor += 1 cmdmod = True - elif not k.modcmd and key == 'BackSpace': - if k.cmd: - k.cmd = k.cmd[:-1] - if not k.cmd: - clear_keycmd(uzbl) + elif not k.modcmd and k.cmd and key in ['BackSpace', 'Delete']: + if key == 'BackSpace' and k.cursor > 0: + k.cursor -= 1 + k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] - else: + elif key == 'Delete': + cmd = k.cmd + k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] + if k.cmd != cmd: cmdmod = True - elif not k.modcmd and key == 'Left': - if k.cmd: - k.cmd_s = k.cmd[-1] + k.cmd_s - k.cmd = k.cmd[:-1] - cmdmod = True + if not k.cmd: + clear_keycmd(uzbl) - elif not k.modcmd and key == 'Right': - if k.cmd_s: - k.cmd = k.cmd + k.cmd_s[0] - k.cmd_s = k.cmd_s[1:] + elif key == 'BackSpace': cmdmod = True elif not k.modcmd and key == 'Return': @@ -232,19 +246,25 @@ def key_press(uzbl, key): elif not k.modcmd and key == 'Escape': clear_keycmd(uzbl) - elif not k.modcmd and key == 'Ctrl': - k.held.append(key) + elif not k.modcmd and k.cmd and key == 'Left': + if k.cursor > 0: + k.cursor -= 1 + cmdmod = True - elif not k.modcmd and k.held and len(key) == 1: - if key == 'w': + elif not k.modcmd and k.cmd and key == 'Right': + if k.cursor < len(k.cmd): + k.cursor += 1 + cmdmod = True + + elif not k.modcmd and k.cmd and key == 'End': + if k.cursor != len(k.cmd): + k.cursor = len(k.cmd) + cmdmod = True + + elif not k.modcmd and k.cmd and key == 'Home': + if k.cursor: + k.cursor = 0 cmdmod = True - k.cmd = ' '.join(k.cmd.split(' ')[:-1]) - elif key == 'a': - k.cmd_s = k.cmd + k.cmd_s - k.cmd = '' - elif key == 'e': - k.cmd = k.cmd + k.cmd_s - k.cmd_s = '' elif not k.held and not k.cmd and len(key) > 1: k.modcmd = True @@ -262,18 +282,21 @@ def key_press(uzbl, key): k.held.sort() else: - k.cmd += key + k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) + k.cursor += 1 else: config = uzbl.get_config() if 'keycmd_events' not in config or config['keycmd_events'] == '1': if len(key) == 1: cmdmod = True - k.cmd += key + k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) + k.cursor += 1 - elif k.cmd or k.cmd_s: + elif k.cmd: cmdmod = True - k.cmd = k.cmd_s = '' + k.cmd = '' + k.cursor = 0 if cmdmod: update_event(uzbl, k) @@ -293,8 +316,6 @@ def key_release(uzbl, key): key = make_simple(key) k = get_keylet(uzbl) - if not k: - return cmdmod = False if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: @@ -317,14 +338,35 @@ def key_release(uzbl, key): update_event(uzbl, k) -def config_changed(uzbl, key, value): - '''Check for external keycmd updates and update the keylet accordingly.''' +def set_keycmd(uzbl, keycmd): + '''Allow setting of the keycmd externally.''' + + k = get_keylet(uzbl) + k.wasmod = k.modcmd = False + k._to_string = None + k.cmd = keycmd + k.cursor = len(keycmd) + update_event(uzbl, k) + + +def set_cursor_pos(uzbl, index): + '''Allow setting of the cursor position externally. Supports negative + indexing.''' + + cursor = int(index.strip()) + k = get_keylet(uzbl) + + if cursor < 0: + cursor = len(k.cmd) + cursor + + if cursor < 0: + cursor = 0 + + if cursor > len(k.cmd): + cursor = len(k.cmd) - if key == 'keycmd': - k = get_keylet(uzbl) - if value != k.cmd + k.cmd_s: - k.cmd = value - k.cmd_s = '' + k.cursor = cursor + update_event(uzbl, k) def init(uzbl): @@ -334,6 +376,7 @@ def init(uzbl): 'INSTANCE_EXIT': del_instance, 'KEY_PRESS': key_press, 'KEY_RELEASE': key_release, - 'CONFIG_CHANGED': config_changed} + 'SET_KEYCMD': set_keycmd, + 'SET_CURSOR_POS': set_cursor_pos} uzbl.connect_dict(connects) -- cgit v1.2.3 From e0f17a169a571ce06492910a8c7504684e81c899 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 6 Oct 2009 20:11:52 +0200 Subject: misc --- examples/config/uzbl/config | 2 +- uzbl-browser | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index fd5fe52..e002178 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -123,7 +123,7 @@ set socket_dir = /tmp @bind gg _ = uri http://www.google.com/search?q=%s # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -#@bind B = spawn @scripts_dir}/insert_bookmark.sh +#@bind B = spawn @scripts_dir/insert_bookmark.sh @bind U = spawn @scripts_dir/load_url_from_history.sh @bind u = spawn @scripts_dir/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection diff --git a/uzbl-browser b/uzbl-browser index f5ad14b..202db11 100755 --- a/uzbl-browser +++ b/uzbl-browser @@ -31,6 +31,7 @@ SOCKET_PATH="$SOCKET_DIR/uzbl_socket_$SOCKET_ID" uzbl-core "$@" -n $SOCKET_ID & $XDG_DATA_HOME/uzbl/scripts/event_manager.py -vs $SOCKET_PATH +# TODO: make posix sh compliant. [ -S ] is said to not work. what about test -S ? if [[ -S $SOCKETPATH ]] then rm $SOCKET_PATH -- cgit v1.2.3 From 073131be290fa955b9d8913a5387b07aa297d8f1 Mon Sep 17 00:00:00 2001 From: keis Date: Tue, 13 Oct 2009 01:40:41 +0200 Subject: default values for prompts. --- examples/data/uzbl/scripts/plugins/bind.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 15f6f8e..16c8148 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -21,7 +21,7 @@ UZBLS = {} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') -find_prompts = re.compile('<([^:>]*):>').split +find_prompts = re.compile('<([^:>]*):(\"[^>]*\"|)>').split # For accessing a bind glob stack. MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) @@ -158,23 +158,23 @@ class Bind(object): self.bid = self.nextbid() self.split = split = find_prompts(glob) - self.prompts = split[1::2] + self.prompts = zip(split[1::3],[x.strip('"') for x in split[2::3]]) # Check that there is nothing like: fl** - for glob in split[:-1:2]: + for glob in split[:-1:3]: if glob.endswith('*'): msg = "token '*' not at the end of a prompt bind: %r" % split raise BindParseError(msg) # Check that there is nothing like: fl_ - for glob in split[2::2]: + for glob in split[3::3]: if not glob: msg = 'found null segment after first prompt: %r' % split raise BindParseError(msg) self.stack = [] - for glob in split[::2]: + for glob in split[::3]: # Is the binding a MODCMD or KEYCMD: mod_cmd = ismodbind(glob) @@ -239,6 +239,7 @@ def parse_bind_event(uzbl, args): def set_stack_mode(uzbl, prompt): + prompt,data = prompt if uzbl.get_mode() != 'stack': uzbl.set_mode('stack') @@ -247,6 +248,10 @@ def set_stack_mode(uzbl, prompt): uzbl.set('keycmd_prompt', prompt) + if data: + # go through uzbl-core to expand potential @-variables + uzbl.send('event SET_KEYCMD %s' % data) + def clear_stack(uzbl, mode): bind_dict = get_bind_dict(uzbl) -- cgit v1.2.3 From fdca08d7d7ae0d6ec41cc23220f8cdd89785e370 Mon Sep 17 00:00:00 2001 From: keis Date: Tue, 13 Oct 2009 05:12:18 +0200 Subject: show-off new prompt feature. --- examples/config/uzbl/config | 1 + 1 file changed, 1 insertion(+) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e002178..fae36a2 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -176,6 +176,7 @@ set formfiller = spawn @scripts_dir/formfiller # Examples using multi-stage-bindings with text prompts. @bind o_ = uri %s +@bind O_ = uri %s # Prints tab separated "uri title keyword tags" to the bookmarks file. # TODO: Improve bookmarks script to handle this format & include date in bookmark format. -- cgit v1.2.3 From acb12604a047515b34cd443db00ba389c69a47b2 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 01:04:01 +0200 Subject: Allow single char modkeys. --- examples/data/uzbl/scripts/plugins/bind.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 15f6f8e..bcfaa9f 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -20,7 +20,7 @@ __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] UZBLS = {} # Commonly used regular expressions. -starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') +starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') find_prompts = re.compile('<([^:>]*):>').split # For accessing a bind glob stack. -- cgit v1.2.3 From fdd8d07eba9e483baf618b6d8fd928fefb8465f3 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 15 Oct 2009 00:08:45 +0800 Subject: Added multi-instance managing to event_manager.py 1. Moved plugin directory from './examples/data/scripts/plugins' to './examples/data/'. 2. Broke up the plugin manager class into two small functions. 3. Removed the handler objects ability to have non-callable handlers given that there is a perfectly good on_event.py plugin which can do exactly the same. 4. Gave event_manager daemon abilities similar to the cookie_daemon. 5. Using pid to track the event manager daemons running status. 6. Added the ability to load plugins from multiple locations. 7. Removed all outgoing message queues as this work-around is no longer required after the newly added --connect-socket uzbl-core ability. 8. Removed native stdin/fifo reading ability. Use socat if required. 9. Updated uzbl-browser script to load example cookie_daemon if cookie_daemon is not in $XDG_DATA_HOME/uzbl/scripts/ 10. Added a new event_manager.py launcher uzbl-daemon. 11. Updated make test-dev-browser target to test uzbl-daemon also. 12. Added init like {start|stop|restart} to the event manager. 13. Added a fourth 'list' option to {start|stop|..} to list the plugins and dirs of each plugin that would be loaded by the event manager. --- Makefile | 5 +- examples/data/uzbl/plugins/bind.py | 400 ++++++++++ examples/data/uzbl/plugins/config.py | 87 +++ examples/data/uzbl/plugins/keycmd.py | 382 +++++++++ examples/data/uzbl/plugins/mode.py | 159 ++++ examples/data/uzbl/plugins/on_event.py | 117 +++ examples/data/uzbl/plugins/plugin_template.py | 75 ++ examples/data/uzbl/plugins/progress_bar.py | 158 ++++ examples/data/uzbl/scripts/event_manager.py | 865 ++++++++++++--------- examples/data/uzbl/scripts/plugins/bind.py | 374 --------- examples/data/uzbl/scripts/plugins/config.py | 87 --- examples/data/uzbl/scripts/plugins/keycmd.py | 382 --------- examples/data/uzbl/scripts/plugins/mode.py | 159 ---- examples/data/uzbl/scripts/plugins/on_event.py | 117 --- .../data/uzbl/scripts/plugins/plugin_template.py | 75 -- examples/data/uzbl/scripts/plugins/progress_bar.py | 158 ---- uzbl-browser | 31 +- uzbl-daemon | 20 + 18 files changed, 1902 insertions(+), 1749 deletions(-) create mode 100644 examples/data/uzbl/plugins/bind.py create mode 100644 examples/data/uzbl/plugins/config.py create mode 100644 examples/data/uzbl/plugins/keycmd.py create mode 100644 examples/data/uzbl/plugins/mode.py create mode 100644 examples/data/uzbl/plugins/on_event.py create mode 100644 examples/data/uzbl/plugins/plugin_template.py create mode 100644 examples/data/uzbl/plugins/progress_bar.py delete mode 100644 examples/data/uzbl/scripts/plugins/bind.py delete mode 100644 examples/data/uzbl/scripts/plugins/config.py delete mode 100644 examples/data/uzbl/scripts/plugins/keycmd.py delete mode 100644 examples/data/uzbl/scripts/plugins/mode.py delete mode 100644 examples/data/uzbl/scripts/plugins/on_event.py delete mode 100644 examples/data/uzbl/scripts/plugins/plugin_template.py delete mode 100644 examples/data/uzbl/scripts/plugins/progress_bar.py create mode 100755 uzbl-daemon (limited to 'examples') diff --git a/Makefile b/Makefile index 167881f..65a2760 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,6 @@ uzbl-core: ${OBJ} @echo ... done. - uzbl-browser: uzbl-core PREFIX?=$(DESTDIR)/usr/local @@ -58,8 +57,10 @@ test-dev: uzbl-core test-dev-browser: uzbl-browser XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py start -nv & + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./uzbl-daemon start -nv & XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./uzbl-browser --uri http://www.uzbl.org --verbose XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py stop -v + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./uzbl-daemon stop -v test-share: uzbl-core XDG_DATA_HOME=${PREFIX}/share/uzbl/examples/data XDG_CONFIG_HOME=${PREFIX}/share/uzbl/examples/config ./uzbl-core --uri http://www.uzbl.org --verbose @@ -84,6 +85,7 @@ install: all cp -rp examples $(PREFIX)/share/uzbl/ install -m755 uzbl-core $(PREFIX)/bin/uzbl-core install -m755 uzbl-browser $(PREFIX)/bin/uzbl-browser + install -m755 uzbl-daemon $(PREFIX)/bin/uzbl-daemon install -m644 AUTHORS $(PREFIX)/share/uzbl/docs install -m644 README $(PREFIX)/share/uzbl/docs @@ -91,4 +93,3 @@ install: all uninstall: rm -rf $(PREFIX)/bin/uzbl-* rm -rf $(PREFIX)/share/uzbl - diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py new file mode 100644 index 0000000..d62872f --- /dev/null +++ b/examples/data/uzbl/plugins/bind.py @@ -0,0 +1,400 @@ +'''Plugin provides support for binds in uzbl. + +For example: + event BIND ZZ = exit -> bind('ZZ', 'exit') + event BIND o _ = uri %s -> bind('o _', 'uri %s') + event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") + +And it is also possible to execute a function on activation: + bind('DD', myhandler) +''' + +import sys +import re +from event_manager import config, counter, iscallable, isiterable + +# Export these variables/functions to uzbl. +__export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] + +# Hold the bind lists per uzbl instance. +UZBLS = {} + +# Commonly used regular expressions. +starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') +find_prompts = re.compile('<([^:>]*):>').split + +# For accessing a bind glob stack. +MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) + + +class BindParseError(Exception): + pass + + +def echo(msg): + if config['verbose']: + print 'bind plugin:', msg + + +def error(msg): + sys.stderr.write('bind plugin: error: %s\n' % msg) + + +def ismodbind(glob): + '''Return True if the glob specifies a modbind.''' + + return bool(starts_with_mod.match(glob)) + + +def sort_mods(glob): + '''Mods are sorted in the keylet.to_string() result so make sure that + bind commands also have their mod keys sorted.''' + + mods = [] + while True: + match = starts_with_mod.match(glob) + if not match: + break + + end = match.span()[1] + mods.append(glob[:end]) + glob = glob[end:] + + return '%s%s' % (''.join(sorted(mods)), glob) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = {'binds': [], 'depth': 0, 'filter': [], + 'args': [], 'last_mode': ''} + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_bind_dict(uzbl): + '''Return the bind dict for the uzbl instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_binds(uzbl): + '''Return the bind list for the uzbl instance.''' + + return get_bind_dict(uzbl)['binds'] + + +def get_stack_depth(uzbl): + '''Return the stack for the uzbl instance.''' + + return get_bind_dict(uzbl)['depth'] + + +def get_filtered_binds(uzbl): + '''Return the bind list for the uzbl instance or return the filtered + bind list thats on the current stack.''' + + bind_dict = get_bind_dict(uzbl) + if bind_dict['depth']: + return list(bind_dict['filter']) + + return list(bind_dict['binds']) + + +def del_bind(uzbl, bind): + '''Delete bind object if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + if bind in binds: + binds.remove(bind) + uzbl.event('DELETED_BIND', bind) + return True + + return False + + +def del_bind_by_glob(uzbl, glob): + '''Delete bind by glob if bind in the uzbl binds.''' + + binds = get_binds(uzbl) + for bind in list(binds): + if bind.glob == glob: + binds.remove(bind) + uzbl.event('DELETED_BIND', bind) + return True + + return False + + +class Bind(object): + + nextbid = counter().next + + def __init__(self, glob, handler, *args, **kargs): + self.callable = iscallable(handler) + + if not glob: + raise ArgumentError('glob cannot be blank') + + if self.callable: + self.function = handler + self.args = args + self.kargs = kargs + + elif kargs: + raise ArgumentError('cannot supply kargs for uzbl commands') + + elif isiterable(handler): + self.commands = handler + + else: + self.commands = [handler,] + list(args) + + self.glob = glob + self.bid = self.nextbid() + + self.split = split = find_prompts(glob) + self.prompts = split[1::2] + + # Check that there is nothing like: fl** + for glob in split[:-1:2]: + if glob.endswith('*'): + msg = "token '*' not at the end of a prompt bind: %r" % split + raise BindParseError(msg) + + # Check that there is nothing like: fl_ + for glob in split[2::2]: + if not glob: + msg = 'found null segment after first prompt: %r' % split + raise BindParseError(msg) + + self.stack = [] + + for glob in split[::2]: + # Is the binding a MODCMD or KEYCMD: + mod_cmd = ismodbind(glob) + + # Execute the command on UPDATES or EXEC's: + on_exec = True if glob.endswith('_') else False + + # Does the command store arguments: + has_args = True if glob[-1] in ['*', '_'] else False + glob = glob[:-1] if has_args else glob + + self.stack.append((mod_cmd, on_exec, has_args, glob)) + + + def __repr__(self): + args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] + + if self.callable: + args.append('function=%r' % self.function) + if self.args: + args.append('args=%r' % self.args) + + if self.kargs: + args.append('kargs=%r' % self.kargs) + + else: + cmdlen = len(self.commands) + cmds = self.commands[0] if cmdlen == 1 else self.commands + args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) + + return '' % ', '.join(args) + + +def exec_bind(uzbl, bind, *args, **kargs): + '''Execute bind objects.''' + + if bind.callable: + args += bind.args + kargs = dict(bind.kargs.items()+kargs.items()) + bind.function(uzbl, *args, **kargs) + return + + if kargs: + raise ArgumentError('cannot supply kargs for uzbl commands') + + commands = [] + + for cmd in bind.commands: + if '%s' in cmd: + if len(args) > 1: + for arg in args: + cmd = cmd.replace('%s', arg, 1) + + elif len(args) == 1: + cmd = cmd.replace('%s', args[0]) + + uzbl.send(cmd) + + +def bind(uzbl, glob, handler, *args, **kargs): + '''Add a bind handler object.''' + + # Mods come from the keycmd sorted so make sure the modkeys in the bind + # command are sorted too. + glob = sort_mods(glob) + + del_bind_by_glob(uzbl, glob) + binds = get_binds(uzbl) + + bind = Bind(glob, handler, *args, **kargs) + binds.append(bind) + + print bind + uzbl.event('ADDED_BIND', bind) + + +def parse_bind_event(uzbl, args): + '''Break "event BIND fl* = js follownums.js" into (glob, command).''' + + if not args: + return error('missing bind arguments') + + split = map(unicode.strip, args.split('=', 1)) + if len(split) != 2: + return error('missing "=" in bind definition: %r' % args) + + glob, command = split + bind(uzbl, glob, command) + + +def set_stack_mode(uzbl, prompt): + if uzbl.get_mode() != 'stack': + uzbl.set_mode('stack') + + if prompt: + prompt = "%s: " % prompt + + uzbl.set('keycmd_prompt', prompt) + + +def clear_stack(uzbl, mode): + bind_dict = get_bind_dict(uzbl) + if mode != "stack" and bind_dict['last_mode'] == "stack": + uzbl.set('keycmd_prompt', '') + + if mode != "stack": + bind_dict = get_bind_dict(uzbl) + bind_dict['filter'] = [] + bind_dict['depth'] = 0 + bind_dict['args'] = [] + + bind_dict['last_mode'] = mode + + +def filter_bind(uzbl, bind_dict, bind): + '''Remove a bind from the stack filter list.''' + + if bind in bind_dict['filter']: + bind_dict['filter'].remove(bind) + + if not bind_dict['filter']: + uzbl.set_mode() + + +def match_and_exec(uzbl, bind, depth, keycmd): + bind_dict = get_bind_dict(uzbl) + mode_cmd, on_exec, has_args, glob = bind.stack[depth] + + if has_args: + if not keycmd.startswith(glob): + filter_bind(uzbl, bind_dict, bind) + return False + + args = [keycmd[len(glob):],] + + elif keycmd != glob: + filter_bind(uzbl, bind_dict, bind) + return False + + else: + args = [] + + execindex = len(bind.stack)-1 + if execindex == depth == 0: + exec_bind(uzbl, bind, *args) + if not has_args: + uzbl.clear_keycmd() + + return True + + elif depth != execindex: + if bind_dict['depth'] == depth: + bind_dict['filter'] = [bind,] + bind_dict['args'] += args + bind_dict['depth'] = depth + 1 + + else: + if bind not in bind_dict['filter']: + bind_dict['filter'].append(bind) + + set_stack_mode(uzbl, bind.prompts[depth]) + return False + + args = bind_dict['args'] + args + exec_bind(uzbl, bind, *args) + if on_exec: + uzbl.set_mode() + + return True + + +def keycmd_update(uzbl, keylet): + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or t[ON_EXEC]: + continue + + match_and_exec(uzbl, bind, depth, keycmd) + + +def keycmd_exec(uzbl, keylet): + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if t[MOD_CMD] or not t[ON_EXEC]: + continue + + match_and_exec(uzbl, bind, depth, keycmd) + + +def modcmd_update(uzbl, keylet): + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or t[ON_EXEC]: + continue + + match_and_exec(uzbl, bind, depth, keycmd) + + +def modcmd_exec(uzbl, keylet): + depth = get_stack_depth(uzbl) + keycmd = keylet.to_string() + for bind in get_filtered_binds(uzbl): + t = bind.stack[depth] + if not t[MOD_CMD] or not t[ON_EXEC]: + continue + + match_and_exec(uzbl, bind, depth, keycmd) + + +def init(uzbl): + connects = {'BIND': parse_bind_event, + 'KEYCMD_UPDATE': keycmd_update, + 'MODCMD_UPDATE': modcmd_update, + 'KEYCMD_EXEC': keycmd_exec, + 'MODCMD_EXEC': modcmd_exec, + 'MODE_CHANGED': clear_stack} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py new file mode 100644 index 0000000..22803b4 --- /dev/null +++ b/examples/data/uzbl/plugins/config.py @@ -0,0 +1,87 @@ +import re +import types + +__export__ = ['set', 'get_config'] + +_VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match +_TYPECONVERT = {'int': int, 'float': float, 'str': unicode} + +UZBLS = {} + + +def escape(value): + '''A real escaping function may be required.''' + + return unicode(value) + + +def get_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def set(uzbl, key, value): + '''Sends a: "set key = value" command to the uzbl instance.''' + + if type(value) == types.BooleanType: + value = int(value) + + if not _VALIDSETKEY(key): + raise KeyError("%r" % key) + + value = escape(value) + if '\n' in value: + value = value.replace("\n", "\\n") + + uzbl.send('set %s = %s' % (key, value)) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = ConfigDict(uzbl) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del uzbl + + +def get_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +class ConfigDict(dict): + def __init__(self, uzbl): + self._uzbl = uzbl + + def __setitem__(self, key, value): + '''Makes "config[key] = value" a wrapper for the set function.''' + + if key not in self or unicode(self[key]) != unicode(value): + set(self._uzbl, key, value) + + +def variable_set(uzbl, args): + config = get_config(uzbl) + + key, type, value = list(args.split(' ', 2) + ['',])[:3] + old = config[key] if key in config else None + value = _TYPECONVERT[type](value) + + dict.__setitem__(config, key, value) + + if old != value: + uzbl.event("CONFIG_CHANGED", key, value) + + +def init(uzbl): + + connects = {'VARIABLE_SET': variable_set, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py new file mode 100644 index 0000000..3dd6f37 --- /dev/null +++ b/examples/data/uzbl/plugins/keycmd.py @@ -0,0 +1,382 @@ +import re + +# Map these functions/variables in the plugins namespace to the uzbl object. +__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet'] + +# Regular expression compile cache. +_RE_CACHE = {} + +# Hold the keylets. +UZBLS = {} + +# Simple key names map. +_SIMPLEKEYS = { + 'Control': 'Ctrl', + 'ISO_Left_Tab': 'Shift-Tab', + 'space':'Space', +} + +# Keycmd format which includes the markup for the cursor. +KEYCMD_FORMAT = "%s%s%s" + + +def escape(str): + '''Prevent outgoing keycmd values from expanding inside the + status_format.''' + + if not str: + return '' + + for char in ['\\', '@']: + if char in str: + str = str.replace(char, '\\'+char) + + return "@[%s]@" % str + + +def get_regex(regex): + '''Compiling regular expressions is a very time consuming so return a + pre-compiled regex match object if possible.''' + + if regex not in _RE_CACHE: + _RE_CACHE[regex] = re.compile(regex).match + + return _RE_CACHE[regex] + + +class Keylet(object): + '''Small per-instance object that tracks all the keys held and characters + typed.''' + + def __init__(self): + self.cmd = '' + self.cursor = 0 + self.held = [] + + # to_string() string building cache. + self._to_string = None + + self.modcmd = False + self.wasmod = False + + def __repr__(self): + return '' % self.to_string() + + + def to_string(self): + '''Return a string representation of the keys held and pressed that + have been recorded.''' + + if self._to_string is not None: + # Return cached keycmd string. + return self._to_string + + if not self.held: + self._to_string = self.cmd + + else: + self._to_string = ''.join(['<%s>' % key for key in self.held]) + if self.cmd: + self._to_string += self.cmd + + return self._to_string + + + def match(self, regex): + '''See if the keycmd string matches the given regex.''' + + return bool(get_regex(regex)(self.to_string())) + + +def make_simple(key): + '''Make some obscure names for some keys friendlier.''' + + # Remove left-right discrimination. + if key.endswith('_L') or key.endswith('_R'): + key = key[:-2] + + if key in _SIMPLEKEYS: + key = _SIMPLEKEYS[key] + + return key + + +def add_instance(uzbl, *args): + '''Create the Keylet object for this uzbl instance.''' + + UZBLS[uzbl] = Keylet() + + +def del_instance(uzbl, *args): + '''Delete the Keylet object for this uzbl instance.''' + + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_keylet(uzbl): + '''Return the corresponding keylet for this uzbl instance.''' + + # Startup events are not correctly captured and sent over the uzbl socket + # yet so this line is needed because the INSTANCE_START event is lost. + if uzbl not in UZBLS: + add_instance(uzbl) + + keylet = UZBLS[uzbl] + keylet._to_string = None + return keylet + + +def clear_keycmd(uzbl): + '''Clear the keycmd for this uzbl instance.''' + + k = get_keylet(uzbl) + k.cmd = '' + k.cursor = 0 + k._to_string = None + + if k.modcmd: + k.wasmod = True + + k.modcmd = False + config = uzbl.get_config() + if 'keycmd' not in config or config['keycmd'] != '': + config['keycmd'] = '' + + uzbl.event('KEYCMD_CLEAR') + + +def update_event(uzbl, k): + '''Raise keycmd & modcmd update events.''' + + config = uzbl.get_config() + if k.modcmd: + keycmd = k.to_string() + uzbl.event('MODCMD_UPDATE', k) + if keycmd != k.to_string(): + return + + if 'modcmd_updates' in config and config['modcmd_updates'] != '1': + return + + return uzbl.set('keycmd', escape(keycmd)) + + if 'keycmd_events' in config and config['keycmd_events'] != '1': + return + + keycmd = k.cmd + uzbl.event('KEYCMD_UPDATE', k) + if keycmd != k.cmd: + return + + if not k.cmd: + return uzbl.set('keycmd', '') + + # Generate the pango markup for the cursor in the keycmd. + if k.cursor < len(k.cmd): + cursor = k.cmd[k.cursor] + + else: + cursor = ' ' + + chunks = map(escape, [k.cmd[:k.cursor], cursor, k.cmd[k.cursor+1:]]) + uzbl.set('keycmd', KEYCMD_FORMAT % tuple(chunks)) + + +def key_press(uzbl, key): + '''Handle KEY_PRESS events. Things done by this function include: + + 1. Ignore all shift key presses (shift can be detected by capital chars) + 2. Re-enable modcmd var if the user presses another key with at least one + modkey still held from the previous modcmd (I.e. +t, clear & + +o without having to re-press ) + 3. In non-modcmd mode: + a. BackSpace deletes the character before the cursor position. + b. Delete deletes the character at the cursor position. + c. End moves the cursor to the end of the keycmd. + d. Home moves the cursor to the beginning of the keycmd. + e. Return raises a KEYCMD_EXEC event then clears the keycmd. + f. Escape clears the keycmd. + 4. If keycmd and held keys are both empty/null and a modkey was pressed + set modcmd mode. + 5. If in modcmd mode only mod keys are added to the held keys list. + 6. Keycmd is updated and events raised if anything is changed.''' + + if key.startswith('Shift_'): + return + + if len(key) > 1: + key = make_simple(key) + + k = get_keylet(uzbl) + cmdmod = False + if k.held and k.wasmod: + k.modcmd = True + k.wasmod = False + cmdmod = True + + if k.cmd and key == 'Space': + k.cmd = "%s %s" % (k.cmd[:k.cursor], k.cmd[k.cursor:]) + k.cursor += 1 + cmdmod = True + + elif not k.modcmd and k.cmd and key in ['BackSpace', 'Delete']: + if key == 'BackSpace' and k.cursor > 0: + k.cursor -= 1 + k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] + + elif key == 'Delete': + cmd = k.cmd + k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] + if k.cmd != cmd: + cmdmod = True + + if not k.cmd: + clear_keycmd(uzbl) + + elif key == 'BackSpace': + cmdmod = True + + elif not k.modcmd and key == 'Return': + if k.cmd: + uzbl.event('KEYCMD_EXEC', k) + + clear_keycmd(uzbl) + + elif not k.modcmd and key == 'Escape': + clear_keycmd(uzbl) + + elif not k.modcmd and k.cmd and key == 'Left': + if k.cursor > 0: + k.cursor -= 1 + cmdmod = True + + elif not k.modcmd and k.cmd and key == 'Right': + if k.cursor < len(k.cmd): + k.cursor += 1 + cmdmod = True + + elif not k.modcmd and k.cmd and key == 'End': + if k.cursor != len(k.cmd): + k.cursor = len(k.cmd) + cmdmod = True + + elif not k.modcmd and k.cmd and key == 'Home': + if k.cursor: + k.cursor = 0 + cmdmod = True + + elif not k.held and not k.cmd and len(key) > 1: + k.modcmd = True + k.held.append(key) + cmdmod = True + + elif k.modcmd: + cmdmod = True + if len(key) > 1: + if key == 'Shift-Tab' and 'Tab' in k.held: + k.held.remove('Tab') + + if key not in k.held: + k.held.append(key) + k.held.sort() + + else: + k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) + k.cursor += 1 + + else: + config = uzbl.get_config() + if 'keycmd_events' not in config or config['keycmd_events'] == '1': + if len(key) == 1: + cmdmod = True + k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) + k.cursor += 1 + + elif k.cmd: + cmdmod = True + k.cmd = '' + k.cursor = 0 + + if cmdmod: + update_event(uzbl, k) + + +def key_release(uzbl, key): + '''Respond to KEY_RELEASE event. Things done by this function include: + + 1. Remove the key from the keylet held list. + 2. If the key removed was a mod key and it was in a mod-command then + raise a MODCMD_EXEC event then clear the keycmd. + 3. Stop trying to restore mod-command status with wasmod if both the + keycmd and held list are empty/null. + 4. Update the keycmd uzbl variable if anything changed.''' + + if len(key) > 1: + key = make_simple(key) + + k = get_keylet(uzbl) + + cmdmod = False + if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: + key = 'Shift-Tab' + + elif key in ['Shift', 'Alt'] and 'Meta' in k.held: + key = 'Meta' + + if key in k.held: + if k.modcmd: + uzbl.event('MODCMD_EXEC', k) + + k.held.remove(key) + clear_keycmd(uzbl) + + if not k.held and not k.cmd and k.wasmod: + k.wasmod = False + + if cmdmod: + update_event(uzbl, k) + + +def set_keycmd(uzbl, keycmd): + '''Allow setting of the keycmd externally.''' + + k = get_keylet(uzbl) + k.wasmod = k.modcmd = False + k._to_string = None + k.cmd = keycmd + k.cursor = len(keycmd) + update_event(uzbl, k) + + +def set_cursor_pos(uzbl, index): + '''Allow setting of the cursor position externally. Supports negative + indexing.''' + + cursor = int(index.strip()) + k = get_keylet(uzbl) + + if cursor < 0: + cursor = len(k.cmd) + cursor + + if cursor < 0: + cursor = 0 + + if cursor > len(k.cmd): + cursor = len(k.cmd) + + k.cursor = cursor + update_event(uzbl, k) + + +def init(uzbl): + '''Connect handlers to uzbl events.''' + + connects = {'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'KEY_PRESS': key_press, + 'KEY_RELEASE': key_release, + 'SET_KEYCMD': set_keycmd, + 'SET_CURSOR_POS': set_cursor_pos} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py new file mode 100644 index 0000000..ad0d9a8 --- /dev/null +++ b/examples/data/uzbl/plugins/mode.py @@ -0,0 +1,159 @@ +import sys +import re + +__export__ = ['set_mode', 'get_mode'] + +UZBLS = {} + +DEFAULTS = { + 'mode': '', + 'default': '', + 'modes': { + 'insert': { + 'forward_keys': True, + 'keycmd_events': False, + 'modcmd_updates': False, + 'indicator': 'I'}, + 'command': { + 'forward_keys': False, + 'keycmd_events': True, + 'modcmd_updates': True, + 'indicator': 'C'}}} + +_RE_FINDSPACES = re.compile("\s+") + + +def error(msg): + sys.stderr.write("mode plugin: error: %s\n" % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_mode_dict(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_mode_config(uzbl, mode): + modes = get_mode_dict(uzbl)['modes'] + if mode not in modes: + modes[mode] = {} + + return modes[mode] + + +def get_mode(uzbl): + return get_mode_dict(uzbl)['mode'] + + +def key_press(uzbl, key): + if key != "Escape": + return + + set_mode(uzbl) + + +def set_mode(uzbl, mode=None): + mode_dict = get_mode_dict(uzbl) + if mode is None: + if not mode_dict['default']: + return error("no default mode to fallback on") + + mode = mode_dict['default'] + + config = uzbl.get_config() + if 'mode' not in config or config['mode'] != mode: + config['mode'] = mode + + mode_dict['mode'] = mode + mode_config = get_mode_config(uzbl, mode) + + for (key, value) in mode_config.items(): + if key not in config: + config[key] = value + + elif config[key] != value: + config[key] = value + + if 'mode_indicator' not in mode_config: + config['mode_indicator'] = mode + + uzbl.clear_keycmd() + uzbl.send('update_gui') + uzbl.event("MODE_CHANGED", mode) + + +def config_changed(uzbl, key, value): + if key == 'default_mode': + mode_dict = get_mode_dict(uzbl) + mode_dict['default'] = value + if value and not mode_dict['mode']: + set_mode(uzbl, value) + + elif key == 'mode': + if not value: + value = None + + set_mode(uzbl, value) + + +def mode_config(uzbl, args): + + split = map(unicode.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) + if len(split) != 2: + return error("invalid MODE_CONFIG syntax: %r" % args) + + mode, set = split + split = map(unicode.strip, set.split('=', 1)) + if len(split) != 2: + return error("invalid MODE_CONFIG set command: %r" % args) + + key, value = split + mode_config = get_mode_config(uzbl, mode) + mode_config[key] = value + + if get_mode(uzbl) == mode: + uzbl.set(key, value) + + +def load_reset(uzbl, *args): + config = uzbl.get_config() + if 'reset_on_commit' not in config or config['reset_on_commit'] == '1': + set_mode(uzbl) + + +def toggle_modes(uzbl, modes): + + modelist = [s.strip() for s in modes.split(' ') if s] + if not len(modelist): + return error("no modes specified to toggle") + + mode_dict = get_mode_dict(uzbl) + oldmode = mode_dict['mode'] + if oldmode not in modelist: + return set_mode(uzbl, modelist[0]) + + newmode = modelist[(modelist.index(oldmode)+1) % len(modelist)] + set_mode(uzbl, newmode) + + +def init(uzbl): + + connects = {'CONFIG_CHANGED': config_changed, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEY_PRESS': key_press, + 'MODE_CONFIG': mode_config, + 'LOAD_START': load_reset, + 'TOGGLE_MODES': toggle_modes} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py new file mode 100644 index 0000000..242f9b0 --- /dev/null +++ b/examples/data/uzbl/plugins/on_event.py @@ -0,0 +1,117 @@ +'''Plugin provides arbitrary binding of uzbl events to uzbl commands. + +Formatting options: + %@ = space separated string of the arguments + %1 = argument 1 + %2 = argument 2 + %n = argument n + +Usage: + request ON_EVENT LINK_HOVER set selected_uri = $1 + --> LINK_HOVER http://uzbl.org/ + <-- set selected_uri = http://uzbl.org/ + + request ON_EVENT CONFIG_CHANGED print Config changed: %1 = %2 + --> CONFIG_CHANGED selected_uri http://uzbl.org/ + <-- print Config changed: selected_uri = http://uzbl.org/ +''' + +import sys +import re +from event_manager import config + +__export__ = ['get_on_events', 'on_event'] + +UZBLS = {} + +def echo(msg): + if config['verbose']: + print 'on_event plugin:', msg + + +def error(msg): + sys.stderr.write('on_event plugin: error: %s\n' % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = {} + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_on_events(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def expand(cmd, args): + '''Replaces "%@ %1 %2 %3..." with " ...".''' + + if '%@' in cmd: + cmd = cmd.replace('%@', ' '.join(map(unicode, args))) + + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) + + return cmd + + +def event_handler(uzbl, *args, **kargs): + '''This function handles all the events being watched by various + on_event definitions and responds accordingly.''' + + events = get_on_events(uzbl) + event = kargs['on_event'] + if event not in events: + return + + commands = events[event] + for cmd in commands: + cmd = expand(cmd, args) + uzbl.send(cmd) + + +def on_event(uzbl, event, cmd): + '''Add a new event to watch and respond to.''' + + event = event.upper() + events = get_on_events(uzbl) + if event not in events: + uzbl.connect(event, event_handler, on_event=event) + events[event] = [] + + cmds = events[event] + if cmd not in cmds: + cmds.append(cmd) + + +def parse_on_event(uzbl, args): + '''Parse ON_EVENT events and pass them to the on_event function. + + Syntax: "event ON_EVENT commands".''' + + if not args: + return error("missing on_event arguments") + + split = args.split(' ', 1) + if len(split) != 2: + return error("invalid ON_EVENT syntax: %r" % args) + + event, cmd = split + on_event(uzbl, event, cmd) + + +def init(uzbl): + + connects = {'ON_EVENT': parse_on_event, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/plugins/plugin_template.py b/examples/data/uzbl/plugins/plugin_template.py new file mode 100644 index 0000000..03cb748 --- /dev/null +++ b/examples/data/uzbl/plugins/plugin_template.py @@ -0,0 +1,75 @@ +'''Plugin template.''' + +# A list of functions this plugin exports to be used via uzbl object. +__export__ = ['myplugin_function',] + +# Holds the per-instance data dict. +UZBLS = {} + +# The default instance dict. +DEFAULTS = {} + + +def add_instance(uzbl, *args): + '''Add a new instance with default config options.''' + + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + '''Delete data stored for an instance.''' + + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_myplugin_dict(uzbl): + '''Get data stored for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def myplugin_function(uzbl, *args, **kargs): + '''Custom plugin function which is exported by the __export__ list at the + top of the file for use by other functions/callbacks.''' + + print "My plugin function arguments:", args, kargs + + # Get the per-instance data object. + data = get_myplugin_dict(uzbl) + + # Function logic goes here. + + +def myplugin_event_parser(uzbl, args): + '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' + + print "Got MYPLUGIN_EVENT with arguments: %r" % args + + # Parsing logic goes here. + + +def init(uzbl): + '''The main function of the plugin which is used to attach all the event + hooks that are going to be used throughout the plugins life. This function + is called each time a UzblInstance() object is created in the event + manager.''' + + # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event + # handler stack: + connects = { + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'MYPLUGIN_EVENT': myplugin_event_parser, + } + + # And connect the dicts event handlers to the handler stack. + uzbl.connect_dict(connects) + + # Or connect a handler to an event manually and supply additional optional + # arguments: + + #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) diff --git a/examples/data/uzbl/plugins/progress_bar.py b/examples/data/uzbl/plugins/progress_bar.py new file mode 100644 index 0000000..b6fcb1b --- /dev/null +++ b/examples/data/uzbl/plugins/progress_bar.py @@ -0,0 +1,158 @@ +import sys + +UZBLS = {} + +DEFAULTS = {'width': 8, + 'done': '=', + 'pending': '.', + 'format': '[%d%a%p]%c', + 'spinner': '-\\|/', + 'sprites': 'loading', + 'updates': 0, + 'progress': 100} + + +def error(msg): + sys.stderr.write("progress_bar plugin: error: %s\n" % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_progress_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def update_progress(uzbl, prog=None): + '''Updates the progress_format variable on LOAD_PROGRESS update. + + The current substitution options are: + %d = done char * done + %p = pending char * remaining + %c = percent done + %i = int done + %s = -\|/ spinner + %t = percent pending + %o = int pending + %r = sprites + ''' + + prog_config = get_progress_config(uzbl) + config = uzbl.get_config() + + if prog is None: + prog = prog_config['progress'] + + else: + prog = int(prog) + prog_config['progress'] = prog + + prog_config['updates'] += 1 + format = prog_config['format'] + width = prog_config['width'] + + # Inflate the done and pending bars to stop the progress bar + # jumping around. + if '%c' in format or '%i' in format: + count = format.count('%c') + format.count('%i') + width += (3-len(str(prog))) * count + + if '%t' in format or '%o' in format: + count = format.count('%t') + format.count('%o') + width += (3-len(str(100-prog))) * count + + done = int(((prog/100.0)*width)+0.5) + pending = width - done + + if '%d' in format: + format = format.replace('%d', prog_config['done']*done) + + if '%p' in format: + format = format.replace('%p', prog_config['pending']*pending) + + if '%c' in format: + format = format.replace('%c', '%d%%' % prog) + + if '%i' in format: + format = format.replace('%i', '%d' % prog) + + if '%t' in format: + format = format.replace('%t', '%d%%' % (100-prog)) + + if '%o' in format: + format = format.replace('%o', '%d' % (100-prog)) + + if '%s' in format: + spinner = prog_config['spinner'] + spin = '-' if not spinner else spinner + index = 0 if prog == 100 else prog_config['updates'] % len(spin) + char = '\\\\' if spin[index] == '\\' else spin[index] + format = format.replace('%s', char) + + if '%r' in format: + sprites = prog_config['sprites'] + sprites = '-' if not sprites else sprites + index = int(((prog/100.0)*len(sprites))+0.5)-1 + sprite = '\\\\' if sprites[index] == '\\' else sprites[index] + format = format.replace('%r', sprite) + + if 'progress_format' not in config or config['progress_format'] != format: + config['progress_format'] = format + + +def progress_config(uzbl, args): + '''Parse PROGRESS_CONFIG events from the uzbl instance. + + Syntax: event PROGRESS_CONFIG = + ''' + + split = args.split('=', 1) + if len(split) != 2: + return error("invalid syntax: %r" % args) + + key, value = map(unicode.strip, split) + prog_config = get_progress_config(uzbl) + + if key not in prog_config: + return error("key error: %r" % args) + + if type(prog_config[key]) == type(1): + try: + value = int(value) + + except: + return error("invalid type: %r" % args) + + elif not value: + value = ' ' + + prog_config[key] = value + update_progress(uzbl) + + +def reset_progress(uzbl, args): + '''Reset the spinner counter, reset the progress int and re-draw the + progress bar on LOAD_COMMIT.''' + + prog_dict = get_progress_config(uzbl) + prog_dict['updates'] = prog_dict['progress'] = 0 + update_progress(uzbl) + + +def init(uzbl): + connects = {'LOAD_PROGRESS': update_progress, + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'PROGRESS_CONFIG': progress_config, + 'LOAD_COMMIT': reset_progress} + + uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 2e84ded..271c65e 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -24,30 +24,19 @@ 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 -==== - - - 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 imp import os import sys -import select import re import types import socket import pprint import time +import atexit +from select import select +from signal import signal, SIGTERM from optparse import OptionParser from traceback import print_exc @@ -69,13 +58,21 @@ def xdghome(key, default): # Setup xdg paths. DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') # Config dict (NOT the same as the uzbl.config). config = { - 'verbose': False, - 'plugin_dir': "$XDG_DATA_HOME/uzbl/scripts/plugins/", - 'plugins_load': [], - 'plugins_ignore': [], + 'verbose': False, + 'daemon_mode': True, + + 'plugins_load': [], + 'plugins_ignore': [], + + 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), + '/usr/local/share/uzbl/examples/data/uzbl/plugins/'], + + 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), + 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), } @@ -122,223 +119,265 @@ def isiterable(obj): return hasattr(obj, "__iter__") -class PluginManager(dict): - def __init__(self): +def find_plugins(plugin_dirs): + '''Find all event manager plugins in the plugin dirs and return a + dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' - 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) + plugins = {} + + for plugin_dir in plugin_dirs: + plugin_dir = os.path.realpath(os.path.expandvars(plugin_dir)) + if not os.path.isdir(plugin_dir): + continue - self.load_plugins() + for file in os.listdir(plugin_dir): + if not file.lower().endswith('.py'): + continue + path = os.path.join(plugin_dir, file) + if not os.path.isfile(path): + continue - def _find_all_plugins(self): - '''Find all python scripts in plugin dir and return a list of - locations and imp moduleinfo's.''' + if file not in plugins: + plugins[file] = plugin_dir - dirlist = os.listdir(self.plugin_dir) - pythonfiles = filter(lambda s: s.endswith('.py'), dirlist) + return plugins - plugins = [] - for filename in pythonfiles: - plugins.append(filename[:-3]) +def load_plugins(plugin_dirs, load=[], ignore=[]): + '''Load event manager plugins found in the plugin_dirs.''' - return plugins + # Find the plugins in the plugin_dirs. + found = find_plugins(plugin_dirs) + if load: + # Ignore anything not in the load list. + for plugin in found.keys(): + if plugin not in load: + del found[plugin] - def _unload_plugin(self, name, remove_pyc=True): - '''Unload specific plugin and remove all waste in sys.modules + if ignore: + # Ignore anything in the ignore list. + for plugin in found.keys(): + if plugin in ignore: + del found[plugin] - 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.''' + # Print plugin list to be loaded. + pprint.pprint(found) - allmodules = sys.modules.keys() - allrefs = filter(lambda s: s.startswith("%s." % name), allmodules) + loaded = {} + # Load all found plugins into the loaded dict. + for (filename, dir) in found.items(): + name = filename[:-3] + info = imp.find_module(name, [dir,]) + plugin = imp.load_module(name, *info) + loaded[(dir, filename)] = plugin - for ref in allrefs: - del sys.modules[ref] + return loaded - if name in sys.modules.keys(): - del sys.modules[name] - if name in self: - del self[name] +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' - if remove_pyc: - pyc = os.path.join(self.plugin_dir, '%s.pyc' % name) - if os.path.exists(pyc): - os.remove(pyc) + try: + if os.fork(): + os._exit(0) + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) - def load_plugins(self): + os.chdir('/') + os.setsid() + os.umask(0) - if config['plugins_load']: - pluginlist = config['plugins_load'] + try: + if os.fork(): + os._exit(0) - else: - pluginlist = self._find_all_plugins() - for name in config['plugins_ignore']: - if name in pluginlist: - pluginlist.remove(name) + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) - for name in pluginlist: - # Make sure the plugin isn't already loaded. - self._unload_plugin(name) + sys.stdout.flush() + sys.stderr.flush() - try: - moduleinfo = imp.find_module(name, [self.plugin_dir,]) - plugin = imp.load_module(name, *moduleinfo) - self[name] = plugin + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) - except: - raise + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) - if self.keys(): - echo("loaded plugin(s): %s" % ', '.join(self.keys())) +def make_dirs(path): + '''Make all basedirs recursively as required.''' - def reload_plugins(self): - '''Unload all loaded plugins then run load_plugins() again. + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) - 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) +def make_pid_file(pid_file): + '''Make pid file at given pid_file location.''' - self.load_plugins() + make_dirs(pid_file) + file = open(pid_file, 'w') + file.write('%d' % os.getpid()) + file.close() -class CallPrepender(object): - '''Execution argument modifier. Takes (arg, function) then modifies the - function call: +def del_pid_file(pid_file): + '''Delete pid file at given pid_file location.''' - -> function(*args, **kargs) -> function(arg, *args, **kargs) ->''' + if os.path.isfile(pid_file): + os.remove(pid_file) - def __init__(self, uzbl, function): - self.function = function - self.uzbl = uzbl - def call(self, *args, **kargs): - return self.function(self.uzbl, *args, **kargs) +def get_pid(pid_file): + '''Read pid from pid_file.''' + try: + file = open(pid_file, 'r') + strpid = file.read() + file.close() + pid = int(strpid.strip()) + return pid -class Handler(object): + except: + print_exc() + return None - nexthid = counter().next - def __init__(self, event, handler, *args, **kargs): - self.callable = iscallable(handler) - if self.callable: - self.function = handler - self.args = args - self.kargs = kargs +def pid_running(pid): + '''Returns True if a process with the given pid is running.''' - elif kargs: - raise ArgumentError("cannot supply kargs with a uzbl command") + try: + os.kill(pid, 0) - elif isiterable(handler): - self.commands = handler + except OSError: + return False - else: - self.commands = [handler,] + list(args) + else: + return True + + +def term_process(pid): + '''Send a SIGTERM signal to the process with the given pid.''' + + if not pid_running(pid): + return False + + os.kill(pid, SIGTERM) + + start = time.time() + while True: + if not pid_running(pid): + return True + + if time.time() - start > 5: + raise OSError('failed to stop process with pid: %d' % pid) + + time.sleep(0.25) + + +def prepender(function, *pre_args): + '''Creates a wrapper around a callable object injecting a list of + arguments before the called arguments.''' + locals = (function, pre_args) + def _prepender(*args, **kargs): + (function, pre_args) = locals + return function(*(pre_args + args), **kargs) + + return _prepender + + +class EventHandler(object): + + nexthid = counter().next + + def __init__(self, event, handler, *args, **kargs): + if not iscallable(handler): + raise ArgumentError("EventHandler object requires a callable " + "object function for the handler argument not: %r" % handler) + + self.function = handler + self.args = args + self.kargs = kargs self.event = event self.hid = self.nexthid() def __repr__(self): - args = ["event=%s" % self.event, "hid=%d" % self.hid] + args = ["event=%s" % self.event, "hid=%d" % self.hid, + "function=%r" % self.function] - if self.callable: - args.append("function=%r" % self.function) - if self.args: - args.append("args=%r" % self.args) + if self.args: + args.append("args=%r" % self.args) - if self.kargs: - args.append("kargs=%r" % self.kargs) - - else: - cmdlen = len(self.commands) - cmds = self.commands[0] if cmdlen == 1 else self.commands - args.append("command%s=%r" % ("s" if cmdlen-1 else "", cmds)) + if self.kargs: + args.append("kargs=%r" % self.kargs) return "" % ', '.join(args) class UzblInstance(object): - '''Event manager for a uzbl instance.''' - - # Singleton plugin manager. - plugins = None + def __init__(self, parent, client_socket): - def __init__(self): - '''Initialise event manager.''' - - # Hold functions exported by plugins. + # Internal variables. self._exports = {} - self._running = None - self._buffer = '' - self._handlers = {} + self._parent = parent + self._client_socket = client_socket - # 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 + self.buffer = '' - if not self.plugins: - self.plugins = PluginManager() - - # Call the init() function in every plugin which then setup their - # respective hooks (event handlers, binds or timers). + # Call the init() function in every plugin. Inside the init function + # is where the plugins insert the hooks into the event system. self._init_plugins() - def __getattribute__(self, name): + def __getattribute__(self, attr): '''Expose any exported functions before class functions.''' - if not name.startswith('_'): + if not attr.startswith('_'): exports = object.__getattribute__(self, '_exports') - if name in exports: - return exports[name] + if attr in exports: + return exports[attr] - return object.__getattribute__(self, name) + return object.__getattribute__(self, attr) def _init_plugins(self): '''Call the init() function in every plugin and expose all exposable functions in the plugins root namespace.''' + plugins = self._parent['plugins'] + # Map all plugin exports - for (name, plugin) in self.plugins.items(): + for (name, plugin) in plugins.items(): if not hasattr(plugin, '__export__'): continue for export in plugin.__export__: if export in self._exports: - orig = self._exports[export] - raise KeyError("already exported attribute: %r" % export) + raise KeyError("conflicting export: %r" % export) obj = getattr(plugin, export) if iscallable(obj): - # Wrap the function in the CallPrepender object to make - # the exposed functions act like instance methods. - obj = CallPrepender(self, obj).call + obj = prepender(obj, self) self._exports[export] = 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(): + for (name, plugin) in plugins.items(): try: plugin.init(self) @@ -347,82 +386,15 @@ class UzblInstance(object): raise - def _init_uzbl_socket(self, uzbl_socket=None, timeout=None): - '''Store socket location and open socket connection to uzbl socket.''' - - if uzbl_socket is None: - uzbl_socket = self.uzbl_socket - - if not uzbl_socket: - error("no socket location.") - return - - if not os.path.exists(uzbl_socket): - if timeout is None: - error("uzbl socket doesn't exist: %r" % uzbl_socket) - return - - waitlimit = time.time() + timeout - echo("waiting for uzbl socket: %r" % uzbl_socket) - while not os.path.exists(uzbl_socket): - time.sleep(0.25) - if time.time() > waitlimit: - error("timed out waiting for socket: %r" % uzbl_socket) - return - - self.uzbl_socket = uzbl_socket - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(self.uzbl_socket) - self._socket = sock - - - def _close_socket(self): - '''Close the socket used for communication with the uzbl instance. - This function is normally called upon receiving the INSTANCE_EXIT - event.''' - - if self._socket: - self._socket.close() - - self.uzbl_socket = self._socket = None - - - 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 '<-- %s' % msg - h.write(("%s\n" % msg).encode('utf-8')) - - h.close() - - if len(self._socket_cmd_queue) and self.uzbl_socket: - if not self._socket and os.path.exists(self.uzbl_socket): - self._init_uzbl_socket() - - if self._socket: - while len(self._socket_cmd_queue): - msg = self._socket_cmd_queue.pop(0) - print '<-- %s' % msg - self._socket.send(("%s\n" % msg).encode('utf-8')) - - - 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): + def send(self, msg): '''Send a command to the uzbl instance via the socket file.''' - self._socket_cmd_queue.append(msg) - self._flush() + if self._client_socket: + print '<-- %s' % msg + self._client_socket.send(("%s\n" % msg).encode('utf-8')) + + else: + print '!-- %s' % msg def connect(self, event, handler, *args, **kargs): @@ -432,11 +404,9 @@ class UzblInstance(object): if event not in self._handlers.keys(): self._handlers[event] = [] - handler = Handler(event, handler, *args, **kargs) - self._handlers[event].append(handler) - - print handler - return handler + handlerobj = EventHandler(event, handler, *args, **kargs) + self._handlers[event].append(handlerobj) + print handlerobj def connect_dict(self, connect_dict): @@ -477,216 +447,356 @@ class UzblInstance(object): echo('unable to find & remove handler: %r' % handler) - def listen_from_fd(self, fd): - '''Polls for event messages from fd.''' + def exec_handler(self, handler, *args, **kargs): + '''Execute event handler function.''' + + args += handler.args + kargs = dict(handler.kargs.items()+kargs.items()) + handler.function(self, *args, **kargs) + + + def event(self, event, *args, **kargs): + '''Raise a custom event.''' + + # Silence _printing_ of geo events while debugging. + if event != "GEOMETRY_CHANGED": + print "--> %s %s %s" % (event, args, '' if not kargs else kargs) + + if event not in self._handlers: + return + + for handler in self._handlers[event]: + try: + self.exec_handler(handler, *args, **kargs) + + except: + print_exc() + + + def close(self): + '''Close the client socket and clean up.''' try: - self._running = True - while self._running: - if select.select([fd,], [], [], 1)[0]: - self.read_from_fd(fd) - continue + self._client_socket.close() - self._flush() + except: + pass - except KeyboardInterrupt: - print + for (name, plugin) in self._parent['plugins'].items(): + if hasattr(plugin, 'cleanup'): + plugin.cleanup(self) + + del self._exports + del self._handlers + del self._client_socket + + +class UzblEventDaemon(dict): + def __init__(self): + + # Init variables and dict keys. + dict.__init__(self, {'uzbls': {}}) + self.running = None + self.server_socket = None + self.socket_location = None + + # Register that the event daemon server has started by creating the + # pid file. + make_pid_file(config['pid_file']) + + # Register a function to clean up the socket and pid file on exit. + atexit.register(self.quit) + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + # Load plugins, first-build of the plugins may be a costly operation. + self['plugins'] = load_plugins(config['plugin_dirs'], + config['plugins_load'], config['plugins_ignore']) + + + def _create_server_socket(self): + '''Create the event manager daemon socket for uzbl instance duplex + communication.''' + + server_socket = config['server_socket'] + server_socket = os.path.realpath(os.path.expandvars(server_socket)) + self.socket_location = server_socket + + # Delete socket if it exists. + if os.path.exists(server_socket): + os.remove(server_socket) + + self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.server_socket.bind(server_socket) + self.server_socket.listen(5) + + + def _close_server_socket(self): + '''Close and delete the server socket.''' + + try: + self.server_socket.close() + self.server_socket = None + + if os.path.exists(self.socket_location): + os.remove(self.socket_location) except: - #print_exc() - raise + pass - def read_from_fd(self, fd): - '''Reads event messages from a single fd.''' + def run(self): + '''Main event daemon loop.''' - raw = fd.readline() - if not raw: - # Read null byte (i.e. uzbl closed). - self._running = False - return + if config['daemon_mode']: + echo('entering daemon mode.') + daemonize() + # The pid has changed so update the pid file. + make_pid_file(config['pid_file']) - msg = raw.strip().split(' ', 3) + # Create event daemon socket. + self._create_server_socket() + echo('listening on: %s' % self.socket_location) - if not msg or msg[0] != "EVENT": - # Not an event message - print "---", raw.rstrip() - return + # Now listen for incoming connections and or data. + self.listen() - event, args = msg[1], msg[3] - self.handle_event(event, args) + # Clean up. + self.quit() - def listen_from_uzbl_socket(self, uzbl_socket): - '''Polls for event messages from a single uzbl socket.''' + def listen(self): + '''Accept incoming connections and constantly poll instance sockets + for incoming data.''' - self._init_uzbl_socket(uzbl_socket, 10) + self.running = True + while self.running: - if not self._socket: - error("failed to init socket: %r" % uzbl_socket) - return + sockets = [self.server_socket,] + self['uzbls'].keys() + + read, _, error = select(sockets, [], sockets, 1) + + if self.server_socket in read: + self.accept_connection() + read.remove(self.server_socket) + + for client in read: + self.read_socket(client) + + for client in error: + error('Unknown error on socket: %r' % client) + self.close_connection(client) + + + def read_socket(self, client): + '''Read data from an instance socket and pass to the uzbl objects + event handler function.''' - self._flush() try: - self._running = True - while self._running: - if select.select([self._socket], [], [], 1): - self.read_from_uzbl_socket() - continue + uzbl = self['uzbls'][client] + raw = unicode(client.recv(8192), 'utf-8', 'ignore') + if not raw: + # Read null byte, close socket. + return self.close_connection(client) - self._flush() + uzbl.buffer += raw + msgs = uzbl.buffer.split('\n') + uzbl.buffer = msgs.pop() - except KeyboardInterrupt: - print + for msg in msgs: + self.parse_msg(uzbl, msg) except: - #print_exc() raise - def read_from_uzbl_socket(self): - '''Reads event messages from a uzbl socket.''' + def parse_msg(self, uzbl, msg): + '''Parse an incoming msg from a uzbl instance. All non-event messages + will be printed here and not be passed to the uzbl instance event + handler function.''' - raw = unicode(self._socket.recv(8192), 'utf-8', 'ignore') - if not raw: - # Read null byte - self._running = False + msg = msg.strip() + if not msg: return - self._buffer += raw - msgs = self._buffer.split("\n") - self._buffer = msgs.pop() + cmd = _RE_FINDSPACES.split(msg, 3) + if not cmd or cmd[0] != 'EVENT': + # Not an event message. + print '---', msg + return - for msg in msgs: - msg = msg.rstrip() - if not msg: - continue + if len(cmd) < 4: + cmd.append('') - cmd = _RE_FINDSPACES.split(msg, 3) - if not cmd or cmd[0] != "EVENT": - # Not an event message - print msg.rstrip() - continue + event, args = cmd[2], cmd[3] - if len(cmd) < 4: - cmd.append('') + try: + uzbl.event(event, args) - event, args = cmd[2], cmd[3] - try: - self.handle_event(event, args) + except: + print_exc() - except: - #print_exc() - raise + def accept_connection(self): + '''Accept incoming connection to the server socket.''' - def handle_event(self, event, args): - '''Handle uzbl events internally before dispatch.''' + client_socket = self.server_socket.accept()[0] - if event == 'FIFO_SET': - self.uzbl_fifo = args - self._flush() + uzbl = UzblInstance(self, client_socket) + self['uzbls'][client_socket] = uzbl - elif event == 'SOCKET_SET': - if not self.uzbl_socket or not self._socket: - self._init_uzbl_socket(args) - self._flush() - elif event == 'INSTANCE_EXIT': - self._close_socket() - self._running = False - for (name, plugin) in self.plugins.items(): - if hasattr(plugin, "cleanup"): - plugin.cleanup(uzbl) + def close_connection(self, client): + '''Clean up after instance close.''' - # Now handle the event "publically". - self.event(event, args) + try: + if client not in self['uzbls']: + return + uzbl = self['uzbls'][client] + uzbl.close() + del self['uzbls'][client] - def exec_handler(self, handler, *args, **kargs): - '''Execute either the handler function or send the handlers uzbl - commands via the socket.''' + except: + print_exc() - if handler.callable: - args = args + handler.args - kargs = dict(handler.kargs.items()+kargs.items()) - handler.function(uzbl, *args, **kargs) - else: - if kargs: - raise ArgumentError('cannot supply kargs for uzbl commands') + def quit(self): + '''Close all instance socket objects, server socket and delete the + pid file.''' - for command in handler.commands: - if '%s' in command: - if len(args) > 1: - for arg in args: - command = command.replace('%s', arg, 1) + echo('shutting down event manager.') - elif len(args) == 1: - command = command.replace('%s', args[0]) + for client in self['uzbls'].keys(): + self.close_connection(client) - uzbl.send(command) + echo('unlinking: %r' % self.socket_location) + self._close_server_socket() + echo('deleting pid file: %r' % config['pid_file']) + del_pid_file(config['pid_file']) - def event(self, event, *args, **kargs): - '''Raise a custom event.''' - # Silence _printing_ of geo events while still debugging. - if event != "GEOMETRY_CHANGED": - print "--> %s %s %s" % (event, args, '' if not kargs else kargs) +def stop(): + '''Stop the event manager daemon.''' - if event in self._handlers: - for handler in self._handlers[event]: - try: - self.exec_handler(handler, *args, **kargs) + pid_file = config['pid_file'] + if not os.path.isfile(pid_file): + return echo('no running daemon found.') - except: - #print_exc() - raise + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if not pid_running(pid): + echo('no process with pid: %d' % pid) + return os.remove(pid_file) + echo("terminating process with pid: %d" % pid) + term_process(pid) + if os.path.isfile(pid_file): + os.remove(pid_file) -if __name__ == "__main__": - #uzbl = UzblInstance().listen_from_fd(sys.stdin) + echo('stopped event daemon.') + + +def start(): + '''Start the event manager daemon.''' + + pid_file = config['pid_file'] + if os.path.isfile(pid_file): + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if pid_running(pid): + return echo('event daemon already started with pid: %d' % pid) + + echo('no process with pid: %d' % pid) + os.remove(pid_file) + + echo('starting event manager.') + UzblEventDaemon().run() + + +def restart(): + '''Restart the event manager daemon.''' + + echo('restarting event manager daemon.') + stop() + start() + + +def list_plugins(): + '''List all the plugins being loaded by the event daemon.''' - parser = OptionParser() - parser.add_option('-s', '--uzbl-socket', dest='socket', - action="store", metavar="SOCKET", - help="read event messages from uzbl socket.") + plugins = find_plugins(config['plugin_dirs']) + dirs = {} + for (plugin, dir) in plugins.items(): + if dir not in dirs: + dirs[dir] = [] + + dirs[dir].append(plugin) + + for (index, (dir, plugin_list)) in enumerate(sorted(dirs.items())): + if index: + print + + print "%s:" % dir + for plugin in sorted(plugin_list): + print " %s" % plugin + + +if __name__ == "__main__": + usage = "usage: %prog [options] {start|stop|restart|list}" + parser = OptionParser(usage=usage) parser.add_option('-v', '--verbose', dest='verbose', action="store_true", help="print verbose output.") - parser.add_option('-d', '--plugin-dir', dest='plugin_dir', action="store", - metavar="DIR", help="change plugin directory.") + parser.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", + metavar="DIRS", help="Specify plugin directories in the form of "\ + "'dir1:dir2:dir3'.") - parser.add_option('-p', '--load-plugins', dest="load", action="store", + parser.add_option('-l', '--load-plugins', dest="load", action="store", metavar="PLUGINS", help="comma separated list of plugins to load") parser.add_option('-i', '--ignore-plugins', dest="ignore", action="store", metavar="PLUGINS", help="comma separated list of plugins to ignore") - parser.add_option('-l', '--list-plugins', dest='list', action='store_true', - help="list all the plugins in the plugin dir.") + parser.add_option('-p', '--pid-file', dest='pid', action='store', + metavar='FILE', help="specify pid file location") + + parser.add_option('-s', '--server-socket', dest='socket', action='store', + metavar='SOCKET', help="specify the daemon socket location") + + parser.add_option('-n', '--no-daemon', dest="daemon", + action="store_true", help="don't enter daemon mode.") (options, args) = parser.parse_args() - if len(args): - for arg in args: - error("unknown argument: %r" % arg) + # init like {start|stop|..} daemon control section. + daemon_controls = {'start': start, 'stop': stop, 'restart': restart, + 'list': list_plugins} + + if len(args) == 1: + action = args[0] + if action not in daemon_controls: + error('unknown action: %r' % action) + sys.exit(1) + + elif len(args) > 1: + error("too many arguments: %r" % args) + sys.exit(1) - raise ArgumentError + else: + action = 'start' + # parse other flags & options. if options.verbose: config['verbose'] = True - if options.plugin_dir: - plugin_dir = os.path.expandvars(options.plugin_dir) - if not os.path.isdir(plugin_dir): - error("%r is not a directory" % plugin_dir) - sys.exit(1) - - config['plugin_dir'] = plugin_dir - echo("changed plugin dir: %r" % plugin_dir) + if options.plugin_dirs: + plugin_dirs = map(str.strip, options.plugin_dirs.split(':')) + config['plugin_dirs'] = plugin_dirs + echo("plugin search dirs: %r" % plugin_dirs) if options.load and options.ignore: error("you can't load and ignore at the same time.") @@ -708,21 +818,16 @@ if __name__ == "__main__": echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) + if options.pid: + config['pid_file'] = options.pid + echo("pid file location: %r" % config['pid_file']) - if options.list: - plugin_dir = os.path.expandvars(config['plugin_dir']) - if not os.path.isdir(plugin_dir): - error("not a directory: %r" % plugin_dir) - sys.exit(1) + if options.socket: + config['server_socket'] = options.socket + echo("daemon socket location: %s" % config['server_socket']) - dirlist = filter(lambda p: p.endswith('.py'), os.listdir(plugin_dir)) - print ', '.join([p[:-3] for p in dirlist]) + if options.daemon: + config['daemon_mode'] = False - else: - uzbl = UzblInstance() - if options.socket: - echo("listen from uzbl socket: %r" % options.socket) - uzbl.listen_from_uzbl_socket(options.socket) - - else: - uzbl.listen_from_fd(sys.stdin) + # Now {start|stop|...} + daemon_controls[action]() diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py deleted file mode 100644 index 15f6f8e..0000000 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ /dev/null @@ -1,374 +0,0 @@ -'''Plugin provides support for binds in uzbl. - -For example: - event BIND ZZ = exit -> bind('ZZ', 'exit') - event BIND o _ = uri %s -> bind('o _', 'uri %s') - event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") - -And it is also possible to execute a function on activation: - bind('DD', myhandler) -''' - -import sys -import re -from event_manager import config, counter, iscallable, isiterable - -# Export these variables/functions to uzbl. -__export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] - -# Hold the bind lists per uzbl instance. -UZBLS = {} - -# Commonly used regular expressions. -starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]+)>') -find_prompts = re.compile('<([^:>]*):>').split - -# For accessing a bind glob stack. -MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) - - -class BindParseError(Exception): - pass - - -def echo(msg): - if config['verbose']: - print 'bind plugin:', msg - - -def error(msg): - sys.stderr.write('bind plugin: error: %s\n' % msg) - - -def ismodbind(glob): - '''Return True if the glob specifies a modbind.''' - - return bool(starts_with_mod.match(glob)) - - -def sort_mods(glob): - '''Mods are sorted in the keylet.to_string() result so make sure that - bind commands also have their mod keys sorted.''' - - mods = [] - while True: - match = starts_with_mod.match(glob) - if not match: - break - - end = match.span()[1] - mods.append(glob[:end]) - glob = glob[end:] - - return '%s%s' % (''.join(sorted(mods)), glob) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = {'binds': [], 'depth': 0, 'filter': [], - 'args': [], 'last_mode': ''} - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_bind_dict(uzbl): - '''Return the bind dict for the uzbl instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def get_binds(uzbl): - '''Return the bind list for the uzbl instance.''' - - return get_bind_dict(uzbl)['binds'] - - -def get_stack_depth(uzbl): - '''Return the stack for the uzbl instance.''' - - return get_bind_dict(uzbl)['depth'] - - -def get_filtered_binds(uzbl): - '''Return the bind list for the uzbl instance or return the filtered - bind list thats on the current stack.''' - - bind_dict = get_bind_dict(uzbl) - if bind_dict['depth']: - return list(bind_dict['filter']) - - return list(bind_dict['binds']) - - -def del_bind(uzbl, bind): - '''Delete bind object if bind in the uzbl binds.''' - - binds = get_binds(uzbl) - if bind in binds: - binds.remove(bind) - uzbl.event('DELETED_BIND', bind) - return True - - return False - - -def del_bind_by_glob(uzbl, glob): - '''Delete bind by glob if bind in the uzbl binds.''' - - binds = get_binds(uzbl) - for bind in list(binds): - if bind.glob == glob: - binds.remove(bind) - uzbl.event('DELETED_BIND', bind) - return True - - return False - - -class Bind(object): - - nextbid = counter().next - - def __init__(self, glob, handler, *args, **kargs): - self.callable = iscallable(handler) - - if not glob: - raise ArgumentError('glob cannot be blank') - - if self.callable: - self.function = handler - self.args = args - self.kargs = kargs - - elif kargs: - raise ArgumentError('cannot supply kargs for uzbl commands') - - elif isiterable(handler): - self.commands = handler - - else: - self.commands = [handler,] + list(args) - - self.glob = glob - self.bid = self.nextbid() - - self.split = split = find_prompts(glob) - self.prompts = split[1::2] - - # Check that there is nothing like: fl** - for glob in split[:-1:2]: - if glob.endswith('*'): - msg = "token '*' not at the end of a prompt bind: %r" % split - raise BindParseError(msg) - - # Check that there is nothing like: fl_ - for glob in split[2::2]: - if not glob: - msg = 'found null segment after first prompt: %r' % split - raise BindParseError(msg) - - self.stack = [] - - for glob in split[::2]: - # Is the binding a MODCMD or KEYCMD: - mod_cmd = ismodbind(glob) - - # Execute the command on UPDATES or EXEC's: - on_exec = True if glob.endswith('_') else False - - # Does the command store arguments: - has_args = True if glob[-1] in ['*', '_'] else False - glob = glob[:-1] if has_args else glob - - self.stack.append((mod_cmd, on_exec, has_args, glob)) - - - def __repr__(self): - args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] - - if self.callable: - args.append('function=%r' % self.function) - if self.args: - args.append('args=%r' % self.args) - - if self.kargs: - args.append('kargs=%r' % self.kargs) - - else: - cmdlen = len(self.commands) - cmds = self.commands[0] if cmdlen == 1 else self.commands - args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) - - return '' % ', '.join(args) - - -def bind(uzbl, glob, handler, *args, **kargs): - '''Add a bind handler object.''' - - # Mods come from the keycmd sorted so make sure the modkeys in the bind - # command are sorted too. - glob = sort_mods(glob) - - del_bind_by_glob(uzbl, glob) - binds = get_binds(uzbl) - - bind = Bind(glob, handler, *args, **kargs) - binds.append(bind) - - print bind - uzbl.event('ADDED_BIND', bind) - - -def parse_bind_event(uzbl, args): - '''Break "event BIND fl* = js follownums.js" into (glob, command).''' - - if not args: - return error('missing bind arguments') - - split = map(unicode.strip, args.split('=', 1)) - if len(split) != 2: - return error('missing "=" in bind definition: %r' % args) - - glob, command = split - bind(uzbl, glob, command) - - -def set_stack_mode(uzbl, prompt): - if uzbl.get_mode() != 'stack': - uzbl.set_mode('stack') - - if prompt: - prompt = "%s: " % prompt - - uzbl.set('keycmd_prompt', prompt) - - -def clear_stack(uzbl, mode): - bind_dict = get_bind_dict(uzbl) - if mode != "stack" and bind_dict['last_mode'] == "stack": - uzbl.set('keycmd_prompt', '') - - if mode != "stack": - bind_dict = get_bind_dict(uzbl) - bind_dict['filter'] = [] - bind_dict['depth'] = 0 - bind_dict['args'] = [] - - bind_dict['last_mode'] = mode - - -def filter_bind(uzbl, bind_dict, bind): - '''Remove a bind from the stack filter list.''' - - if bind in bind_dict['filter']: - bind_dict['filter'].remove(bind) - - if not bind_dict['filter']: - uzbl.set_mode() - - -def match_and_exec(uzbl, bind, depth, keycmd): - bind_dict = get_bind_dict(uzbl) - mode_cmd, on_exec, has_args, glob = bind.stack[depth] - - if has_args: - if not keycmd.startswith(glob): - filter_bind(uzbl, bind_dict, bind) - return False - - args = [keycmd[len(glob):],] - - elif keycmd != glob: - filter_bind(uzbl, bind_dict, bind) - return False - - else: - args = [] - - execindex = len(bind.stack)-1 - if execindex == depth == 0: - uzbl.exec_handler(bind, *args) - if not has_args: - uzbl.clear_keycmd() - - return True - - elif depth != execindex: - if bind_dict['depth'] == depth: - bind_dict['filter'] = [bind,] - bind_dict['args'] += args - bind_dict['depth'] = depth + 1 - - else: - if bind not in bind_dict['filter']: - bind_dict['filter'].append(bind) - - set_stack_mode(uzbl, bind.prompts[depth]) - return False - - args = bind_dict['args'] + args - uzbl.exec_handler(bind, *args) - if on_exec: - uzbl.set_mode() - - return True - - -def keycmd_update(uzbl, keylet): - depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() - for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] - if t[MOD_CMD] or t[ON_EXEC]: - continue - - match_and_exec(uzbl, bind, depth, keycmd) - - -def keycmd_exec(uzbl, keylet): - depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() - for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] - if t[MOD_CMD] or not t[ON_EXEC]: - continue - - match_and_exec(uzbl, bind, depth, keycmd) - - -def modcmd_update(uzbl, keylet): - depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() - for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] - if not t[MOD_CMD] or t[ON_EXEC]: - continue - - match_and_exec(uzbl, bind, depth, keycmd) - - -def modcmd_exec(uzbl, keylet): - depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() - for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] - if not t[MOD_CMD] or not t[ON_EXEC]: - continue - - match_and_exec(uzbl, bind, depth, keycmd) - - -def init(uzbl): - connects = {'BIND': parse_bind_event, - 'KEYCMD_UPDATE': keycmd_update, - 'MODCMD_UPDATE': modcmd_update, - 'KEYCMD_EXEC': keycmd_exec, - 'MODCMD_EXEC': modcmd_exec, - 'MODE_CHANGED': clear_stack} - - uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/config.py b/examples/data/uzbl/scripts/plugins/config.py deleted file mode 100644 index 22803b4..0000000 --- a/examples/data/uzbl/scripts/plugins/config.py +++ /dev/null @@ -1,87 +0,0 @@ -import re -import types - -__export__ = ['set', 'get_config'] - -_VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match -_TYPECONVERT = {'int': int, 'float': float, 'str': unicode} - -UZBLS = {} - - -def escape(value): - '''A real escaping function may be required.''' - - return unicode(value) - - -def get_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def set(uzbl, key, value): - '''Sends a: "set key = value" command to the uzbl instance.''' - - if type(value) == types.BooleanType: - value = int(value) - - if not _VALIDSETKEY(key): - raise KeyError("%r" % key) - - value = escape(value) - if '\n' in value: - value = value.replace("\n", "\\n") - - uzbl.send('set %s = %s' % (key, value)) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = ConfigDict(uzbl) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del uzbl - - -def get_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -class ConfigDict(dict): - def __init__(self, uzbl): - self._uzbl = uzbl - - def __setitem__(self, key, value): - '''Makes "config[key] = value" a wrapper for the set function.''' - - if key not in self or unicode(self[key]) != unicode(value): - set(self._uzbl, key, value) - - -def variable_set(uzbl, args): - config = get_config(uzbl) - - key, type, value = list(args.split(' ', 2) + ['',])[:3] - old = config[key] if key in config else None - value = _TYPECONVERT[type](value) - - dict.__setitem__(config, key, value) - - if old != value: - uzbl.event("CONFIG_CHANGED", key, value) - - -def init(uzbl): - - connects = {'VARIABLE_SET': variable_set, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance} - - uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py deleted file mode 100644 index 3dd6f37..0000000 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ /dev/null @@ -1,382 +0,0 @@ -import re - -# Map these functions/variables in the plugins namespace to the uzbl object. -__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet'] - -# Regular expression compile cache. -_RE_CACHE = {} - -# Hold the keylets. -UZBLS = {} - -# Simple key names map. -_SIMPLEKEYS = { - 'Control': 'Ctrl', - 'ISO_Left_Tab': 'Shift-Tab', - 'space':'Space', -} - -# Keycmd format which includes the markup for the cursor. -KEYCMD_FORMAT = "%s%s%s" - - -def escape(str): - '''Prevent outgoing keycmd values from expanding inside the - status_format.''' - - if not str: - return '' - - for char in ['\\', '@']: - if char in str: - str = str.replace(char, '\\'+char) - - return "@[%s]@" % str - - -def get_regex(regex): - '''Compiling regular expressions is a very time consuming so return a - pre-compiled regex match object if possible.''' - - if regex not in _RE_CACHE: - _RE_CACHE[regex] = re.compile(regex).match - - return _RE_CACHE[regex] - - -class Keylet(object): - '''Small per-instance object that tracks all the keys held and characters - typed.''' - - def __init__(self): - self.cmd = '' - self.cursor = 0 - self.held = [] - - # to_string() string building cache. - self._to_string = None - - self.modcmd = False - self.wasmod = False - - def __repr__(self): - return '' % self.to_string() - - - def to_string(self): - '''Return a string representation of the keys held and pressed that - have been recorded.''' - - if self._to_string is not None: - # Return cached keycmd string. - return self._to_string - - if not self.held: - self._to_string = self.cmd - - else: - self._to_string = ''.join(['<%s>' % key for key in self.held]) - if self.cmd: - self._to_string += self.cmd - - return self._to_string - - - def match(self, regex): - '''See if the keycmd string matches the given regex.''' - - return bool(get_regex(regex)(self.to_string())) - - -def make_simple(key): - '''Make some obscure names for some keys friendlier.''' - - # Remove left-right discrimination. - if key.endswith('_L') or key.endswith('_R'): - key = key[:-2] - - if key in _SIMPLEKEYS: - key = _SIMPLEKEYS[key] - - return key - - -def add_instance(uzbl, *args): - '''Create the Keylet object for this uzbl instance.''' - - UZBLS[uzbl] = Keylet() - - -def del_instance(uzbl, *args): - '''Delete the Keylet object for this uzbl instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_keylet(uzbl): - '''Return the corresponding keylet for this uzbl instance.''' - - # Startup events are not correctly captured and sent over the uzbl socket - # yet so this line is needed because the INSTANCE_START event is lost. - if uzbl not in UZBLS: - add_instance(uzbl) - - keylet = UZBLS[uzbl] - keylet._to_string = None - return keylet - - -def clear_keycmd(uzbl): - '''Clear the keycmd for this uzbl instance.''' - - k = get_keylet(uzbl) - k.cmd = '' - k.cursor = 0 - k._to_string = None - - if k.modcmd: - k.wasmod = True - - k.modcmd = False - config = uzbl.get_config() - if 'keycmd' not in config or config['keycmd'] != '': - config['keycmd'] = '' - - uzbl.event('KEYCMD_CLEAR') - - -def update_event(uzbl, k): - '''Raise keycmd & modcmd update events.''' - - config = uzbl.get_config() - if k.modcmd: - keycmd = k.to_string() - uzbl.event('MODCMD_UPDATE', k) - if keycmd != k.to_string(): - return - - if 'modcmd_updates' in config and config['modcmd_updates'] != '1': - return - - return uzbl.set('keycmd', escape(keycmd)) - - if 'keycmd_events' in config and config['keycmd_events'] != '1': - return - - keycmd = k.cmd - uzbl.event('KEYCMD_UPDATE', k) - if keycmd != k.cmd: - return - - if not k.cmd: - return uzbl.set('keycmd', '') - - # Generate the pango markup for the cursor in the keycmd. - if k.cursor < len(k.cmd): - cursor = k.cmd[k.cursor] - - else: - cursor = ' ' - - chunks = map(escape, [k.cmd[:k.cursor], cursor, k.cmd[k.cursor+1:]]) - uzbl.set('keycmd', KEYCMD_FORMAT % tuple(chunks)) - - -def key_press(uzbl, key): - '''Handle KEY_PRESS events. Things done by this function include: - - 1. Ignore all shift key presses (shift can be detected by capital chars) - 2. Re-enable modcmd var if the user presses another key with at least one - modkey still held from the previous modcmd (I.e. +t, clear & - +o without having to re-press ) - 3. In non-modcmd mode: - a. BackSpace deletes the character before the cursor position. - b. Delete deletes the character at the cursor position. - c. End moves the cursor to the end of the keycmd. - d. Home moves the cursor to the beginning of the keycmd. - e. Return raises a KEYCMD_EXEC event then clears the keycmd. - f. Escape clears the keycmd. - 4. If keycmd and held keys are both empty/null and a modkey was pressed - set modcmd mode. - 5. If in modcmd mode only mod keys are added to the held keys list. - 6. Keycmd is updated and events raised if anything is changed.''' - - if key.startswith('Shift_'): - return - - if len(key) > 1: - key = make_simple(key) - - k = get_keylet(uzbl) - cmdmod = False - if k.held and k.wasmod: - k.modcmd = True - k.wasmod = False - cmdmod = True - - if k.cmd and key == 'Space': - k.cmd = "%s %s" % (k.cmd[:k.cursor], k.cmd[k.cursor:]) - k.cursor += 1 - cmdmod = True - - elif not k.modcmd and k.cmd and key in ['BackSpace', 'Delete']: - if key == 'BackSpace' and k.cursor > 0: - k.cursor -= 1 - k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] - - elif key == 'Delete': - cmd = k.cmd - k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] - if k.cmd != cmd: - cmdmod = True - - if not k.cmd: - clear_keycmd(uzbl) - - elif key == 'BackSpace': - cmdmod = True - - elif not k.modcmd and key == 'Return': - if k.cmd: - uzbl.event('KEYCMD_EXEC', k) - - clear_keycmd(uzbl) - - elif not k.modcmd and key == 'Escape': - clear_keycmd(uzbl) - - elif not k.modcmd and k.cmd and key == 'Left': - if k.cursor > 0: - k.cursor -= 1 - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'Right': - if k.cursor < len(k.cmd): - k.cursor += 1 - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'End': - if k.cursor != len(k.cmd): - k.cursor = len(k.cmd) - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'Home': - if k.cursor: - k.cursor = 0 - cmdmod = True - - elif not k.held and not k.cmd and len(key) > 1: - k.modcmd = True - k.held.append(key) - cmdmod = True - - elif k.modcmd: - cmdmod = True - if len(key) > 1: - if key == 'Shift-Tab' and 'Tab' in k.held: - k.held.remove('Tab') - - if key not in k.held: - k.held.append(key) - k.held.sort() - - else: - k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) - k.cursor += 1 - - else: - config = uzbl.get_config() - if 'keycmd_events' not in config or config['keycmd_events'] == '1': - if len(key) == 1: - cmdmod = True - k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) - k.cursor += 1 - - elif k.cmd: - cmdmod = True - k.cmd = '' - k.cursor = 0 - - if cmdmod: - update_event(uzbl, k) - - -def key_release(uzbl, key): - '''Respond to KEY_RELEASE event. Things done by this function include: - - 1. Remove the key from the keylet held list. - 2. If the key removed was a mod key and it was in a mod-command then - raise a MODCMD_EXEC event then clear the keycmd. - 3. Stop trying to restore mod-command status with wasmod if both the - keycmd and held list are empty/null. - 4. Update the keycmd uzbl variable if anything changed.''' - - if len(key) > 1: - key = make_simple(key) - - k = get_keylet(uzbl) - - cmdmod = False - if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: - key = 'Shift-Tab' - - elif key in ['Shift', 'Alt'] and 'Meta' in k.held: - key = 'Meta' - - if key in k.held: - if k.modcmd: - uzbl.event('MODCMD_EXEC', k) - - k.held.remove(key) - clear_keycmd(uzbl) - - if not k.held and not k.cmd and k.wasmod: - k.wasmod = False - - if cmdmod: - update_event(uzbl, k) - - -def set_keycmd(uzbl, keycmd): - '''Allow setting of the keycmd externally.''' - - k = get_keylet(uzbl) - k.wasmod = k.modcmd = False - k._to_string = None - k.cmd = keycmd - k.cursor = len(keycmd) - update_event(uzbl, k) - - -def set_cursor_pos(uzbl, index): - '''Allow setting of the cursor position externally. Supports negative - indexing.''' - - cursor = int(index.strip()) - k = get_keylet(uzbl) - - if cursor < 0: - cursor = len(k.cmd) + cursor - - if cursor < 0: - cursor = 0 - - if cursor > len(k.cmd): - cursor = len(k.cmd) - - k.cursor = cursor - update_event(uzbl, k) - - -def init(uzbl): - '''Connect handlers to uzbl events.''' - - connects = {'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'KEY_PRESS': key_press, - 'KEY_RELEASE': key_release, - 'SET_KEYCMD': set_keycmd, - 'SET_CURSOR_POS': set_cursor_pos} - - uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/mode.py b/examples/data/uzbl/scripts/plugins/mode.py deleted file mode 100644 index ad0d9a8..0000000 --- a/examples/data/uzbl/scripts/plugins/mode.py +++ /dev/null @@ -1,159 +0,0 @@ -import sys -import re - -__export__ = ['set_mode', 'get_mode'] - -UZBLS = {} - -DEFAULTS = { - 'mode': '', - 'default': '', - 'modes': { - 'insert': { - 'forward_keys': True, - 'keycmd_events': False, - 'modcmd_updates': False, - 'indicator': 'I'}, - 'command': { - 'forward_keys': False, - 'keycmd_events': True, - 'modcmd_updates': True, - 'indicator': 'C'}}} - -_RE_FINDSPACES = re.compile("\s+") - - -def error(msg): - sys.stderr.write("mode plugin: error: %s\n" % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_mode_dict(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def get_mode_config(uzbl, mode): - modes = get_mode_dict(uzbl)['modes'] - if mode not in modes: - modes[mode] = {} - - return modes[mode] - - -def get_mode(uzbl): - return get_mode_dict(uzbl)['mode'] - - -def key_press(uzbl, key): - if key != "Escape": - return - - set_mode(uzbl) - - -def set_mode(uzbl, mode=None): - mode_dict = get_mode_dict(uzbl) - if mode is None: - if not mode_dict['default']: - return error("no default mode to fallback on") - - mode = mode_dict['default'] - - config = uzbl.get_config() - if 'mode' not in config or config['mode'] != mode: - config['mode'] = mode - - mode_dict['mode'] = mode - mode_config = get_mode_config(uzbl, mode) - - for (key, value) in mode_config.items(): - if key not in config: - config[key] = value - - elif config[key] != value: - config[key] = value - - if 'mode_indicator' not in mode_config: - config['mode_indicator'] = mode - - uzbl.clear_keycmd() - uzbl.send('update_gui') - uzbl.event("MODE_CHANGED", mode) - - -def config_changed(uzbl, key, value): - if key == 'default_mode': - mode_dict = get_mode_dict(uzbl) - mode_dict['default'] = value - if value and not mode_dict['mode']: - set_mode(uzbl, value) - - elif key == 'mode': - if not value: - value = None - - set_mode(uzbl, value) - - -def mode_config(uzbl, args): - - split = map(unicode.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) - if len(split) != 2: - return error("invalid MODE_CONFIG syntax: %r" % args) - - mode, set = split - split = map(unicode.strip, set.split('=', 1)) - if len(split) != 2: - return error("invalid MODE_CONFIG set command: %r" % args) - - key, value = split - mode_config = get_mode_config(uzbl, mode) - mode_config[key] = value - - if get_mode(uzbl) == mode: - uzbl.set(key, value) - - -def load_reset(uzbl, *args): - config = uzbl.get_config() - if 'reset_on_commit' not in config or config['reset_on_commit'] == '1': - set_mode(uzbl) - - -def toggle_modes(uzbl, modes): - - modelist = [s.strip() for s in modes.split(' ') if s] - if not len(modelist): - return error("no modes specified to toggle") - - mode_dict = get_mode_dict(uzbl) - oldmode = mode_dict['mode'] - if oldmode not in modelist: - return set_mode(uzbl, modelist[0]) - - newmode = modelist[(modelist.index(oldmode)+1) % len(modelist)] - set_mode(uzbl, newmode) - - -def init(uzbl): - - connects = {'CONFIG_CHANGED': config_changed, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'KEY_PRESS': key_press, - 'MODE_CONFIG': mode_config, - 'LOAD_START': load_reset, - 'TOGGLE_MODES': toggle_modes} - - uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/on_event.py b/examples/data/uzbl/scripts/plugins/on_event.py deleted file mode 100644 index 242f9b0..0000000 --- a/examples/data/uzbl/scripts/plugins/on_event.py +++ /dev/null @@ -1,117 +0,0 @@ -'''Plugin provides arbitrary binding of uzbl events to uzbl commands. - -Formatting options: - %@ = space separated string of the arguments - %1 = argument 1 - %2 = argument 2 - %n = argument n - -Usage: - request ON_EVENT LINK_HOVER set selected_uri = $1 - --> LINK_HOVER http://uzbl.org/ - <-- set selected_uri = http://uzbl.org/ - - request ON_EVENT CONFIG_CHANGED print Config changed: %1 = %2 - --> CONFIG_CHANGED selected_uri http://uzbl.org/ - <-- print Config changed: selected_uri = http://uzbl.org/ -''' - -import sys -import re -from event_manager import config - -__export__ = ['get_on_events', 'on_event'] - -UZBLS = {} - -def echo(msg): - if config['verbose']: - print 'on_event plugin:', msg - - -def error(msg): - sys.stderr.write('on_event plugin: error: %s\n' % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = {} - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_on_events(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def expand(cmd, args): - '''Replaces "%@ %1 %2 %3..." with " ...".''' - - if '%@' in cmd: - cmd = cmd.replace('%@', ' '.join(map(unicode, args))) - - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - -def event_handler(uzbl, *args, **kargs): - '''This function handles all the events being watched by various - on_event definitions and responds accordingly.''' - - events = get_on_events(uzbl) - event = kargs['on_event'] - if event not in events: - return - - commands = events[event] - for cmd in commands: - cmd = expand(cmd, args) - uzbl.send(cmd) - - -def on_event(uzbl, event, cmd): - '''Add a new event to watch and respond to.''' - - event = event.upper() - events = get_on_events(uzbl) - if event not in events: - uzbl.connect(event, event_handler, on_event=event) - events[event] = [] - - cmds = events[event] - if cmd not in cmds: - cmds.append(cmd) - - -def parse_on_event(uzbl, args): - '''Parse ON_EVENT events and pass them to the on_event function. - - Syntax: "event ON_EVENT commands".''' - - if not args: - return error("missing on_event arguments") - - split = args.split(' ', 1) - if len(split) != 2: - return error("invalid ON_EVENT syntax: %r" % args) - - event, cmd = split - on_event(uzbl, event, cmd) - - -def init(uzbl): - - connects = {'ON_EVENT': parse_on_event, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance} - - uzbl.connect_dict(connects) diff --git a/examples/data/uzbl/scripts/plugins/plugin_template.py b/examples/data/uzbl/scripts/plugins/plugin_template.py deleted file mode 100644 index 03cb748..0000000 --- a/examples/data/uzbl/scripts/plugins/plugin_template.py +++ /dev/null @@ -1,75 +0,0 @@ -'''Plugin template.''' - -# A list of functions this plugin exports to be used via uzbl object. -__export__ = ['myplugin_function',] - -# Holds the per-instance data dict. -UZBLS = {} - -# The default instance dict. -DEFAULTS = {} - - -def add_instance(uzbl, *args): - '''Add a new instance with default config options.''' - - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - '''Delete data stored for an instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_myplugin_dict(uzbl): - '''Get data stored for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def myplugin_function(uzbl, *args, **kargs): - '''Custom plugin function which is exported by the __export__ list at the - top of the file for use by other functions/callbacks.''' - - print "My plugin function arguments:", args, kargs - - # Get the per-instance data object. - data = get_myplugin_dict(uzbl) - - # Function logic goes here. - - -def myplugin_event_parser(uzbl, args): - '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' - - print "Got MYPLUGIN_EVENT with arguments: %r" % args - - # Parsing logic goes here. - - -def init(uzbl): - '''The main function of the plugin which is used to attach all the event - hooks that are going to be used throughout the plugins life. This function - is called each time a UzblInstance() object is created in the event - manager.''' - - # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event - # handler stack: - connects = { - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'MYPLUGIN_EVENT': myplugin_event_parser, - } - - # And connect the dicts event handlers to the handler stack. - uzbl.connect_dict(connects) - - # Or connect a handler to an event manually and supply additional optional - # arguments: - - #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) diff --git a/examples/data/uzbl/scripts/plugins/progress_bar.py b/examples/data/uzbl/scripts/plugins/progress_bar.py deleted file mode 100644 index b6fcb1b..0000000 --- a/examples/data/uzbl/scripts/plugins/progress_bar.py +++ /dev/null @@ -1,158 +0,0 @@ -import sys - -UZBLS = {} - -DEFAULTS = {'width': 8, - 'done': '=', - 'pending': '.', - 'format': '[%d%a%p]%c', - 'spinner': '-\\|/', - 'sprites': 'loading', - 'updates': 0, - 'progress': 100} - - -def error(msg): - sys.stderr.write("progress_bar plugin: error: %s\n" % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_progress_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def update_progress(uzbl, prog=None): - '''Updates the progress_format variable on LOAD_PROGRESS update. - - The current substitution options are: - %d = done char * done - %p = pending char * remaining - %c = percent done - %i = int done - %s = -\|/ spinner - %t = percent pending - %o = int pending - %r = sprites - ''' - - prog_config = get_progress_config(uzbl) - config = uzbl.get_config() - - if prog is None: - prog = prog_config['progress'] - - else: - prog = int(prog) - prog_config['progress'] = prog - - prog_config['updates'] += 1 - format = prog_config['format'] - width = prog_config['width'] - - # Inflate the done and pending bars to stop the progress bar - # jumping around. - if '%c' in format or '%i' in format: - count = format.count('%c') + format.count('%i') - width += (3-len(str(prog))) * count - - if '%t' in format or '%o' in format: - count = format.count('%t') + format.count('%o') - width += (3-len(str(100-prog))) * count - - done = int(((prog/100.0)*width)+0.5) - pending = width - done - - if '%d' in format: - format = format.replace('%d', prog_config['done']*done) - - if '%p' in format: - format = format.replace('%p', prog_config['pending']*pending) - - if '%c' in format: - format = format.replace('%c', '%d%%' % prog) - - if '%i' in format: - format = format.replace('%i', '%d' % prog) - - if '%t' in format: - format = format.replace('%t', '%d%%' % (100-prog)) - - if '%o' in format: - format = format.replace('%o', '%d' % (100-prog)) - - if '%s' in format: - spinner = prog_config['spinner'] - spin = '-' if not spinner else spinner - index = 0 if prog == 100 else prog_config['updates'] % len(spin) - char = '\\\\' if spin[index] == '\\' else spin[index] - format = format.replace('%s', char) - - if '%r' in format: - sprites = prog_config['sprites'] - sprites = '-' if not sprites else sprites - index = int(((prog/100.0)*len(sprites))+0.5)-1 - sprite = '\\\\' if sprites[index] == '\\' else sprites[index] - format = format.replace('%r', sprite) - - if 'progress_format' not in config or config['progress_format'] != format: - config['progress_format'] = format - - -def progress_config(uzbl, args): - '''Parse PROGRESS_CONFIG events from the uzbl instance. - - Syntax: event PROGRESS_CONFIG = - ''' - - split = args.split('=', 1) - if len(split) != 2: - return error("invalid syntax: %r" % args) - - key, value = map(unicode.strip, split) - prog_config = get_progress_config(uzbl) - - if key not in prog_config: - return error("key error: %r" % args) - - if type(prog_config[key]) == type(1): - try: - value = int(value) - - except: - return error("invalid type: %r" % args) - - elif not value: - value = ' ' - - prog_config[key] = value - update_progress(uzbl) - - -def reset_progress(uzbl, args): - '''Reset the spinner counter, reset the progress int and re-draw the - progress bar on LOAD_COMMIT.''' - - prog_dict = get_progress_config(uzbl) - prog_dict['updates'] = prog_dict['progress'] = 0 - update_progress(uzbl) - - -def init(uzbl): - connects = {'LOAD_PROGRESS': update_progress, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'PROGRESS_CONFIG': progress_config, - 'LOAD_COMMIT': reset_progress} - - uzbl.connect_dict(connects) diff --git a/uzbl-browser b/uzbl-browser index 202db11..02ea6c9 100755 --- a/uzbl-browser +++ b/uzbl-browser @@ -1,5 +1,5 @@ #!/bin/sh -# this script implements are more useful "browsing experience". +# this script implements are more useful "browsing experience". # We are assuming you want to use the event_manager.py and cookie_daemon.py. # So, you must have them in the appropriate place, and cookie_daemon_socket must be configured in the default location @@ -10,29 +10,30 @@ if [ -z "$XDG_DATA_HOME" ] then - XDG_DATA_HOME=$HOME/.local/share + export XDG_DATA_HOME=$HOME/.local/share fi if [ -z "$XDG_CACHE_HOME" ] then - XDG_CACHE_HOME=$HOME/.cache + export XDG_CACHE_HOME=$HOME/.cache fi if [ ! -S $XDG_CACHE_HOME/uzbl/cookie_daemon_socket ] then - $XDG_DATA_HOME/uzbl/scripts/cookie_daemon.py + if [ -f "$XDG_DATA_HOME/uzbl/scripts/cookie_daemon.py" ] + then + $XDG_DATA_HOME/uzbl/scripts/cookie_daemon.py + else + /usr/local/share/uzbl/examples/data/uzbl/scripts/cookie_daemon.py + fi fi +DAEMON_SOCKET=$XDG_CACHE_HOME/uzbl/event_daemon +DAEMON_PID=$XDG_CACHE_HOME/uzbl/event_daemon.pid -SOCKET_ID="$RANDOM$RANDOM" -SOCKET_DIR="/tmp" -SOCKET_PATH="$SOCKET_DIR/uzbl_socket_$SOCKET_ID" +#if [ -f "$DAEMON_PID" ] +#then + uzbl-daemon start +#fi -uzbl-core "$@" -n $SOCKET_ID & -$XDG_DATA_HOME/uzbl/scripts/event_manager.py -vs $SOCKET_PATH - -# TODO: make posix sh compliant. [ -S ] is said to not work. what about test -S ? -if [[ -S $SOCKETPATH ]] -then - rm $SOCKET_PATH -fi +uzbl-core "$@" --connect-socket $DAEMON_SOCKET diff --git a/uzbl-daemon b/uzbl-daemon new file mode 100755 index 0000000..0e4c0e1 --- /dev/null +++ b/uzbl-daemon @@ -0,0 +1,20 @@ +#!/bin/sh + +# TODO: Fix up the launcher to check the following paths in order to find the +# correct event_manager.py to run: +# 1. $XDG_DATA_HOME/uzbl/scripts/event_manager.py +# 2. /usr/local/share/uzbl/examples/data/uzbl/scripts/event_manager.py + +if [ -z "$XDG_DATA_HOME" ] +then + XDG_DATA_HOME=$HOME/.local/share +fi + +if [ -z "$XDG_CACHE_HOME" ] +then + XDG_CACHE_HOME=$HOME/.cache +fi + +EVENT_MANAGER=/usr/local/share/uzbl/examples/data/uzbl/scripts/event_manager.py + +$EVENT_MANAGER -v "$@" -- cgit v1.2.3 From 4dc8ae0bad20df99c4e1fbf7df698133679a811e Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 01:06:04 +0200 Subject: track all keys in held, remove hardcoded bindings. --- examples/data/uzbl/scripts/plugins/keycmd.py | 91 +++++----------------------- 1 file changed, 16 insertions(+), 75 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 3dd6f37..e8d68e9 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -57,8 +57,10 @@ class Keylet(object): self._to_string = None self.modcmd = False - self.wasmod = False + def mod_held(self): + return any([len(x) != 1 for x in self.held]) + def __repr__(self): return '' % self.to_string() @@ -135,10 +137,7 @@ def clear_keycmd(uzbl): k.cursor = 0 k._to_string = None - if k.modcmd: - k.wasmod = True - - k.modcmd = False + k.modcmd = k.mod_held() config = uzbl.get_config() if 'keycmd' not in config or config['keycmd'] != '': config['keycmd'] = '' @@ -210,80 +209,18 @@ def key_press(uzbl, key): k = get_keylet(uzbl) cmdmod = False - if k.held and k.wasmod: - k.modcmd = True - k.wasmod = False - cmdmod = True - if k.cmd and key == 'Space': + if k.cmd and not k.modcmd and key == 'Space': k.cmd = "%s %s" % (k.cmd[:k.cursor], k.cmd[k.cursor:]) k.cursor += 1 cmdmod = True - elif not k.modcmd and k.cmd and key in ['BackSpace', 'Delete']: - if key == 'BackSpace' and k.cursor > 0: - k.cursor -= 1 - k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] - - elif key == 'Delete': - cmd = k.cmd - k.cmd = k.cmd[:k.cursor] + k.cmd[k.cursor+1:] - if k.cmd != cmd: - cmdmod = True - - if not k.cmd: - clear_keycmd(uzbl) - - elif key == 'BackSpace': - cmdmod = True - - elif not k.modcmd and key == 'Return': - if k.cmd: - uzbl.event('KEYCMD_EXEC', k) - - clear_keycmd(uzbl) - - elif not k.modcmd and key == 'Escape': - clear_keycmd(uzbl) - - elif not k.modcmd and k.cmd and key == 'Left': - if k.cursor > 0: - k.cursor -= 1 - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'Right': - if k.cursor < len(k.cmd): - k.cursor += 1 - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'End': - if k.cursor != len(k.cmd): - k.cursor = len(k.cmd) - cmdmod = True - - elif not k.modcmd and k.cmd and key == 'Home': - if k.cursor: - k.cursor = 0 - cmdmod = True - - elif not k.held and not k.cmd and len(key) > 1: + elif len(key) > 1: k.modcmd = True - k.held.append(key) cmdmod = True elif k.modcmd: cmdmod = True - if len(key) > 1: - if key == 'Shift-Tab' and 'Tab' in k.held: - k.held.remove('Tab') - - if key not in k.held: - k.held.append(key) - k.held.sort() - - else: - k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) - k.cursor += 1 else: config = uzbl.get_config() @@ -298,6 +235,13 @@ def key_press(uzbl, key): k.cmd = '' k.cursor = 0 + if key == 'Shift-Tab' and 'Tab' in k.held: + k.held.remove('Tab') + + if key not in k.held: + k.held.append(key) + k.held.sort() + if cmdmod: update_event(uzbl, k) @@ -325,14 +269,11 @@ def key_release(uzbl, key): key = 'Meta' if key in k.held: + cmdmod = True if k.modcmd: uzbl.event('MODCMD_EXEC', k) - k.held.remove(key) - clear_keycmd(uzbl) - - if not k.held and not k.cmd and k.wasmod: - k.wasmod = False + k.modcmd = k.mod_held() if cmdmod: update_event(uzbl, k) @@ -342,7 +283,7 @@ def set_keycmd(uzbl, keycmd): '''Allow setting of the keycmd externally.''' k = get_keylet(uzbl) - k.wasmod = k.modcmd = False + k.modcmd = False k._to_string = None k.cmd = keycmd k.cursor = len(keycmd) -- cgit v1.2.3 From 0b993cff1b50de7e40ca8d4ea8f87052e8e99ea5 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 17:42:44 +0200 Subject: add keyword to update_event to update the keycommand without executing the command. --- examples/data/uzbl/scripts/plugins/keycmd.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index e8d68e9..18d2e32 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -145,13 +145,14 @@ def clear_keycmd(uzbl): uzbl.event('KEYCMD_CLEAR') -def update_event(uzbl, k): +def update_event(uzbl, k, execute=True): '''Raise keycmd & modcmd update events.''' config = uzbl.get_config() if k.modcmd: keycmd = k.to_string() - uzbl.event('MODCMD_UPDATE', k) + if execute: + uzbl.event('MODCMD_UPDATE', k) if keycmd != k.to_string(): return @@ -164,7 +165,8 @@ def update_event(uzbl, k): return keycmd = k.cmd - uzbl.event('KEYCMD_UPDATE', k) + if execute: + uzbl.event('KEYCMD_UPDATE', k) if keycmd != k.cmd: return @@ -270,10 +272,10 @@ def key_release(uzbl, key): if key in k.held: cmdmod = True - if k.modcmd: - uzbl.event('MODCMD_EXEC', k) k.held.remove(key) k.modcmd = k.mod_held() + if k.modcmd: + uzbl.event('MODCMD_EXEC', k) if cmdmod: update_event(uzbl, k) @@ -287,7 +289,8 @@ def set_keycmd(uzbl, keycmd): k._to_string = None k.cmd = keycmd k.cursor = len(keycmd) - update_event(uzbl, k) + + update_event(uzbl, k, False) def set_cursor_pos(uzbl, index): @@ -307,7 +310,7 @@ def set_cursor_pos(uzbl, index): cursor = len(k.cmd) k.cursor = cursor - update_event(uzbl, k) + update_event(uzbl, k, False) def init(uzbl): -- cgit v1.2.3 From c7a4e5d5d26f59d7d0f0b40f4d69fa8560bf5454 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 04:07:45 +0200 Subject: add methods to KeyLet to extract mod and key -cmd parts. --- examples/data/uzbl/scripts/plugins/bind.py | 12 ++++++------ examples/data/uzbl/scripts/plugins/keycmd.py | 20 +++++++++----------- 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index bcfaa9f..6b1c727 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -274,7 +274,7 @@ def filter_bind(uzbl, bind_dict, bind): def match_and_exec(uzbl, bind, depth, keycmd): bind_dict = get_bind_dict(uzbl) - mode_cmd, on_exec, has_args, glob = bind.stack[depth] + mod_cmd, on_exec, has_args, glob = bind.stack[depth] if has_args: if not keycmd.startswith(glob): @@ -293,7 +293,7 @@ def match_and_exec(uzbl, bind, depth, keycmd): execindex = len(bind.stack)-1 if execindex == depth == 0: uzbl.exec_handler(bind, *args) - if not has_args: + if not has_args and not mod_cmd: uzbl.clear_keycmd() return True @@ -321,7 +321,7 @@ def match_and_exec(uzbl, bind, depth, keycmd): def keycmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() + keycmd = keylet.key_cmd() for bind in get_filtered_binds(uzbl): t = bind.stack[depth] if t[MOD_CMD] or t[ON_EXEC]: @@ -332,7 +332,7 @@ def keycmd_update(uzbl, keylet): def keycmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() + keycmd = keylet.key_cmd() for bind in get_filtered_binds(uzbl): t = bind.stack[depth] if t[MOD_CMD] or not t[ON_EXEC]: @@ -343,7 +343,7 @@ def keycmd_exec(uzbl, keylet): def modcmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() + keycmd = keylet.mod_cmd() for bind in get_filtered_binds(uzbl): t = bind.stack[depth] if not t[MOD_CMD] or t[ON_EXEC]: @@ -354,7 +354,7 @@ def modcmd_update(uzbl, keylet): def modcmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.to_string() + keycmd = keylet.mod_cmd() for bind in get_filtered_binds(uzbl): t = bind.stack[depth] if not t[MOD_CMD] or not t[ON_EXEC]: diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 18d2e32..c423ab2 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -60,11 +60,16 @@ class Keylet(object): def mod_held(self): return any([len(x) != 1 for x in self.held]) - + + def key_cmd(self): + return self.cmd + + def mod_cmd(self): + return ''.join(['<%s>' % key for key in self.held]) + def __repr__(self): return '' % self.to_string() - def to_string(self): '''Return a string representation of the keys held and pressed that have been recorded.''' @@ -72,15 +77,8 @@ class Keylet(object): if self._to_string is not None: # Return cached keycmd string. return self._to_string - - if not self.held: - self._to_string = self.cmd - - else: - self._to_string = ''.join(['<%s>' % key for key in self.held]) - if self.cmd: - self._to_string += self.cmd - + + self._to_string = self.mod_cmd() + self.key_cmd() return self._to_string -- cgit v1.2.3 From 02aa78b2d2e8117de894ea75d87f437d94458738 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 17:56:12 +0200 Subject: add event to strip last word from keycmd. --- examples/data/uzbl/scripts/plugins/keycmd.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index c423ab2..565d054 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -291,6 +291,25 @@ def set_keycmd(uzbl, keycmd): update_event(uzbl, k, False) +def keycmd_strip_word(uzbl, sep): + sep = sep or ' ' + k = get_keylet(uzbl) + cmd = k.cmd[:k.cursor] + tail = len(k.cmd) - k.cursor + + if sep in cmd: + tmp = cmd.rstrip(sep).rsplit(sep, 1) + else: + tmp = ('',) + + k.cmd = tmp[0] + (sep if len(tmp) == 2 else '') + k.cmd[k.cursor:] + k.cursor = len(tmp[0]) + (len(tmp) - 1) + + assert len(k.cmd) - k.cursor == tail, "tail size changed (%s) (%s - %s)" % (tail, len(k.cmd), k.cursor) + + update_event(uzbl, k, False) + + def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative indexing.''' @@ -319,6 +338,7 @@ def init(uzbl): 'KEY_PRESS': key_press, 'KEY_RELEASE': key_release, 'SET_KEYCMD': set_keycmd, + 'KEYCMD_STRIP_WORD': keycmd_strip_word, 'SET_CURSOR_POS': set_cursor_pos} uzbl.connect_dict(connects) -- cgit v1.2.3 From 3be7f04d436a7a08ae0ea33d73cc4c73173ae63b Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 18:00:17 +0200 Subject: add backspace event. --- examples/data/uzbl/scripts/plugins/keycmd.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 565d054..467053b 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -310,6 +310,14 @@ def keycmd_strip_word(uzbl, sep): update_event(uzbl, k, False) +def keycmd_backspace(uzbl, _foo): + k = get_keylet(uzbl) + k.cmd = k.cmd[:k.cursor-1] + k.cmd[k.cursor:] + k.cursor -= 1 + + update_event(uzbl, k, False) + + def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative indexing.''' @@ -339,6 +347,7 @@ def init(uzbl): 'KEY_RELEASE': key_release, 'SET_KEYCMD': set_keycmd, 'KEYCMD_STRIP_WORD': keycmd_strip_word, + 'KEYCMD_BACKSPACE': keycmd_backspace, 'SET_CURSOR_POS': set_cursor_pos} uzbl.connect_dict(connects) -- cgit v1.2.3 From 7ed6303f3d5dd02ec900fc5dcad4c977c465b0c6 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 18:20:02 +0200 Subject: add event to execute current keycmd. --- examples/data/uzbl/scripts/plugins/keycmd.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 467053b..c5a8f93 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -318,6 +318,12 @@ def keycmd_backspace(uzbl, _foo): update_event(uzbl, k, False) +def keycmd_exec_current(uzbl, _foo): + k = get_keylet(uzbl) + uzbl.event('KEYCMD_EXEC', k) + clear_keycmd(uzbl) + + def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative indexing.''' @@ -348,6 +354,7 @@ def init(uzbl): 'SET_KEYCMD': set_keycmd, 'KEYCMD_STRIP_WORD': keycmd_strip_word, 'KEYCMD_BACKSPACE': keycmd_backspace, + 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, 'SET_CURSOR_POS': set_cursor_pos} uzbl.connect_dict(connects) -- cgit v1.2.3 From 8f881188ce26d9bfbaed86b0dd76391b7fc77ef4 Mon Sep 17 00:00:00 2001 From: keis Date: Thu, 15 Oct 2009 03:53:48 +0200 Subject: Make prompts work again. For now treats all single-depth modcmds as commands that should be executed regardless of context, global commands. globalness should perhaps by expressed in the bind event instead. --- examples/data/uzbl/scripts/plugins/bind.py | 35 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 6b1c727..16834a7 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -172,7 +172,7 @@ class Bind(object): msg = 'found null segment after first prompt: %r' % split raise BindParseError(msg) - self.stack = [] + self._stack = [] for glob in split[::2]: # Is the binding a MODCMD or KEYCMD: @@ -185,8 +185,15 @@ class Bind(object): has_args = True if glob[-1] in ['*', '_'] else False glob = glob[:-1] if has_args else glob - self.stack.append((mod_cmd, on_exec, has_args, glob)) + self._stack.append((mod_cmd, on_exec, has_args, glob)) + def is_global(self): + return len(self._stack) == 1 and self._stack[0][MOD_CMD] + + def __getitem__(self, depth): + if self.is_global(): + return self._stack[0], False + return self._stack[depth], depth - len(self._stack) + 1 def __repr__(self): args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] @@ -274,33 +281,35 @@ def filter_bind(uzbl, bind_dict, bind): def match_and_exec(uzbl, bind, depth, keycmd): bind_dict = get_bind_dict(uzbl) - mod_cmd, on_exec, has_args, glob = bind.stack[depth] + (mod_cmd, on_exec, has_args, glob), more = bind[depth] if has_args: if not keycmd.startswith(glob): - filter_bind(uzbl, bind_dict, bind) + if not mod_cmd: + filter_bind(uzbl, bind_dict, bind) return False args = [keycmd[len(glob):],] elif keycmd != glob: - filter_bind(uzbl, bind_dict, bind) + if not mod_cmd: + filter_bind(uzbl, bind_dict, bind) return False else: args = [] - execindex = len(bind.stack)-1 - if execindex == depth == 0: + if bind.is_global() or (not more and depth == 0): uzbl.exec_handler(bind, *args) if not has_args and not mod_cmd: uzbl.clear_keycmd() return True - elif depth != execindex: + elif more: if bind_dict['depth'] == depth: - bind_dict['filter'] = [bind,] + globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global()] + bind_dict['filter'] = [bind,] + globalcmds bind_dict['args'] += args bind_dict['depth'] = depth + 1 @@ -323,7 +332,7 @@ def keycmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) keycmd = keylet.key_cmd() for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] + (t,more) = bind[depth] if t[MOD_CMD] or t[ON_EXEC]: continue @@ -334,7 +343,7 @@ def keycmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) keycmd = keylet.key_cmd() for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] + (t,more) = bind[depth] if t[MOD_CMD] or not t[ON_EXEC]: continue @@ -345,7 +354,7 @@ def modcmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) keycmd = keylet.mod_cmd() for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] + (t,more) = bind[depth] if not t[MOD_CMD] or t[ON_EXEC]: continue @@ -356,7 +365,7 @@ def modcmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) keycmd = keylet.mod_cmd() for bind in get_filtered_binds(uzbl): - t = bind.stack[depth] + (t,more) = bind[depth] if not t[MOD_CMD] or not t[ON_EXEC]: continue -- cgit v1.2.3 From e5cbab2ad66c5dc30068a22026dd789131effe31 Mon Sep 17 00:00:00 2001 From: keis Date: Wed, 14 Oct 2009 01:21:59 +0200 Subject: add symolic indexes to set_cursor_pos --- examples/data/uzbl/scripts/plugins/keycmd.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index c5a8f93..9943cbc 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -328,11 +328,16 @@ def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative indexing.''' - cursor = int(index.strip()) k = get_keylet(uzbl) - if cursor < 0: - cursor = len(k.cmd) + cursor + if index == '-': + cursor = k.cursor - 1 + elif index == '+': + cursor = k.cursor + 1 + else: + cursor = int(index.strip()) + if cursor < 0: + cursor = len(k.cmd) + cursor + 1 if cursor < 0: cursor = 0 -- cgit v1.2.3 From 34ebf07579990039dcdd4f271e0b4a4d2e4a2726 Mon Sep 17 00:00:00 2001 From: keis Date: Thu, 15 Oct 2009 04:24:28 +0200 Subject: Update documentation strings and minor changes. --- examples/data/uzbl/scripts/plugins/bind.py | 5 +-- examples/data/uzbl/scripts/plugins/keycmd.py | 52 ++++++++++++++-------------- 2 files changed, 29 insertions(+), 28 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/plugins/bind.py b/examples/data/uzbl/scripts/plugins/bind.py index 16834a7..6a05caa 100644 --- a/examples/data/uzbl/scripts/plugins/bind.py +++ b/examples/data/uzbl/scripts/plugins/bind.py @@ -188,9 +188,11 @@ class Bind(object): self._stack.append((mod_cmd, on_exec, has_args, glob)) def is_global(self): + ''' Returns True if this Bind should be applied in all depths ''' return len(self._stack) == 1 and self._stack[0][MOD_CMD] def __getitem__(self, depth): + ''' get bind info at a depth ''' if self.is_global(): return self._stack[0], False return self._stack[depth], depth - len(self._stack) + 1 @@ -322,8 +324,7 @@ def match_and_exec(uzbl, bind, depth, keycmd): args = bind_dict['args'] + args uzbl.exec_handler(bind, *args) - if on_exec: - uzbl.set_mode() + uzbl.set_mode() return True diff --git a/examples/data/uzbl/scripts/plugins/keycmd.py b/examples/data/uzbl/scripts/plugins/keycmd.py index 9943cbc..79a96e4 100644 --- a/examples/data/uzbl/scripts/plugins/keycmd.py +++ b/examples/data/uzbl/scripts/plugins/keycmd.py @@ -59,12 +59,15 @@ class Keylet(object): self.modcmd = False def mod_held(self): + ''' returns true if any modkey is held. ''' return any([len(x) != 1 for x in self.held]) def key_cmd(self): + ''' get the keycmd-part of the keylet. ''' return self.cmd def mod_cmd(self): + ''' get the modcmd-part of the keylet. ''' return ''.join(['<%s>' % key for key in self.held]) def __repr__(self): @@ -186,19 +189,10 @@ def key_press(uzbl, key): '''Handle KEY_PRESS events. Things done by this function include: 1. Ignore all shift key presses (shift can be detected by capital chars) - 2. Re-enable modcmd var if the user presses another key with at least one - modkey still held from the previous modcmd (I.e. +t, clear & - +o without having to re-press ) 3. In non-modcmd mode: - a. BackSpace deletes the character before the cursor position. - b. Delete deletes the character at the cursor position. - c. End moves the cursor to the end of the keycmd. - d. Home moves the cursor to the beginning of the keycmd. - e. Return raises a KEYCMD_EXEC event then clears the keycmd. - f. Escape clears the keycmd. - 4. If keycmd and held keys are both empty/null and a modkey was pressed - set modcmd mode. - 5. If in modcmd mode only mod keys are added to the held keys list. + a. append char to keycmd + 4. If not in modcmd mode and a modkey was pressed set modcmd mode. + 5. If in modcmd mode the pressed key is added to the held keys list. 6. Keycmd is updated and events raised if anything is changed.''' if key.startswith('Shift_'): @@ -219,10 +213,7 @@ def key_press(uzbl, key): k.modcmd = True cmdmod = True - elif k.modcmd: - cmdmod = True - - else: + elif not k.modcmd: config = uzbl.get_config() if 'keycmd_events' not in config or config['keycmd_events'] == '1': if len(key) == 1: @@ -235,12 +226,14 @@ def key_press(uzbl, key): k.cmd = '' k.cursor = 0 - if key == 'Shift-Tab' and 'Tab' in k.held: - k.held.remove('Tab') + if k.modcmd: + if key == 'Shift-Tab' and 'Tab' in k.held: + k.held.remove('Tab') - if key not in k.held: - k.held.append(key) - k.held.sort() + if key not in k.held: + k.held.append(key) + k.held.sort() + cmdmod = True if cmdmod: update_event(uzbl, k) @@ -250,10 +243,8 @@ def key_release(uzbl, key): '''Respond to KEY_RELEASE event. Things done by this function include: 1. Remove the key from the keylet held list. - 2. If the key removed was a mod key and it was in a mod-command then - raise a MODCMD_EXEC event then clear the keycmd. - 3. Stop trying to restore mod-command status with wasmod if both the - keycmd and held list are empty/null. + 2. If in a mod-command then raise a MODCMD_EXEC. + 3. Check if any modkey is held, if so set modcmd mode. 4. Update the keycmd uzbl variable if anything changed.''' if len(key) > 1: @@ -292,8 +283,12 @@ def set_keycmd(uzbl, keycmd): def keycmd_strip_word(uzbl, sep): + ''' Removes the last word from the keycmd, similar to readline ^W ''' sep = sep or ' ' k = get_keylet(uzbl) + if not k.cmd: + return + cmd = k.cmd[:k.cursor] tail = len(k.cmd) - k.cursor @@ -311,7 +306,11 @@ def keycmd_strip_word(uzbl, sep): def keycmd_backspace(uzbl, _foo): + ''' Removes the last char of the keycmd ''' k = get_keylet(uzbl) + if not k.cmd: + return + k.cmd = k.cmd[:k.cursor-1] + k.cmd[k.cursor:] k.cursor -= 1 @@ -319,6 +318,7 @@ def keycmd_backspace(uzbl, _foo): def keycmd_exec_current(uzbl, _foo): + ''' Raise a KEYCMD_EXEC with the current keylet and then clear the keycmd ''' k = get_keylet(uzbl) uzbl.event('KEYCMD_EXEC', k) clear_keycmd(uzbl) @@ -326,7 +326,7 @@ def keycmd_exec_current(uzbl, _foo): def set_cursor_pos(uzbl, index): '''Allow setting of the cursor position externally. Supports negative - indexing.''' + indexing and relative stepping with '+' and '-'.''' k = get_keylet(uzbl) -- cgit v1.2.3 From 4ec1c9c63c6b06657d515e03fcf9df05c4232dcc Mon Sep 17 00:00:00 2001 From: keis Date: Fri, 16 Oct 2009 19:07:22 +0200 Subject: Update example config with cmd-edit bindings. --- examples/config/uzbl/config | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e002178..d3f7cca 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -179,11 +179,30 @@ set formfiller = spawn @scripts_dir/formfiller # Prints tab separated "uri title keyword tags" to the bookmarks file. # TODO: Improve bookmarks script to handle this format & include date in bookmark format. -@bind b__ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +@bind __ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' # Multi-stage bindings with blank prompts (similar behaviour to emacs M-c M-s bindings?) -@bind a<:>q = exit -@bind a<:>h = uri http://uzbl.org/ +@bind <:> = exit +@bind <:> = uri http://uzbl.org/ + + +# === command editing configuration ========================================== + +# you'll want this at the very least +@bind = request KEYCMD_EXEC_CURRENT + +# basic searching +@bind = request SET_CURSOR_POS 0 +@bind = request SET_CURSOR_POS -1 +@bind = request SET_CURSOR_POS - +@bind = request SET_CURSOR_POS + +@bind = request KEYCMD_BACKSPACE + +# readline-ish bindings +@bind = request KEYCMD_STRIP_WORD +@bind = request SET_KEYCMD +@bind = request SET_CURSOR_POS 0 +@bind = request SET_CURSOR_POS -1 # === Mode configuration ===================================================== @@ -220,7 +239,7 @@ set default_mode = command set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins -@bind i = @toggle_cmd_ins +@bind = @toggle_cmd_ins # === Post-load misc commands =============================================== -- cgit v1.2.3 From c8797e514f62c745ea97638d4749924f34ade2cf Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Sun, 18 Oct 2009 18:26:28 +0200 Subject: added menu_add examples to config --- callbacks.c | 5 +++++ examples/config/uzbl/config | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'examples') diff --git a/callbacks.c b/callbacks.c index b462c09..12bf288 100644 --- a/callbacks.c +++ b/callbacks.c @@ -609,6 +609,11 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) { if(!uzbl.gui.menu_items) return; + /* Separate custom entries from default ones */ + item = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(m), item); + gtk_widget_show(item); + for(i=0; i < uzbl.gui.menu_items->len; i++) { mi = g_ptr_array_index(uzbl.gui.menu_items, i); diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e002178..519b7a0 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -186,6 +186,13 @@ set formfiller = spawn @scripts_dir/formfiller @bind a<:>h = uri http://uzbl.org/ +# === Context menu items ===================================================== + +menu_add Google 'set uri = http://google.com' +menu_add 'Go Home' 'set uri = http://uzbl.org' +menu_add 'Quit uzbl' exit + + # === Mode configuration ===================================================== # Define some mode specific uzbl configurations. -- cgit v1.2.3 From 1df3cf4d7d823216b80fff40e8cf701599482c0d Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Sun, 18 Oct 2009 19:56:21 +0200 Subject: added menu_add_separator command --- callbacks.c | 17 ++++++++++++----- examples/config/uzbl/config | 1 + uzbl-core.c | 32 +++++++++++++++++++++++++++++--- uzbl-core.h | 4 ++++ 4 files changed, 46 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/callbacks.c b/callbacks.c index 12bf288..d841fbe 100644 --- a/callbacks.c +++ b/callbacks.c @@ -617,11 +617,18 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) { for(i=0; i < uzbl.gui.menu_items->len; i++) { mi = g_ptr_array_index(uzbl.gui.menu_items, i); - item = gtk_menu_item_new_with_label(mi->name); - g_signal_connect(item, "activate", - G_CALLBACK(run_menu_command), mi->cmd); - gtk_menu_append(GTK_MENU(m), item); - gtk_widget_show(item); + if(mi->issep) { + item = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(m), item); + gtk_widget_show(item); + } + else { + item = gtk_menu_item_new_with_label(mi->name); + g_signal_connect(item, "activate", + G_CALLBACK(run_menu_command), mi->cmd); + gtk_menu_append(GTK_MENU(m), item); + gtk_widget_show(item); + } } } diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 519b7a0..78c7bec 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -190,6 +190,7 @@ set formfiller = spawn @scripts_dir/formfiller menu_add Google 'set uri = http://google.com' menu_add 'Go Home' 'set uri = http://uzbl.org' +menu_add_separator menu_add 'Quit uzbl' exit diff --git a/uzbl-core.c b/uzbl-core.c index 94641ff..ee4b1c3 100644 --- a/uzbl-core.c +++ b/uzbl-core.c @@ -624,6 +624,7 @@ struct {const char *key; CommandInfo value;} cmdlist[] = { "request", {event, TRUE} }, { "update_gui", {update_gui, TRUE} }, { "menu_add", {menu_add, 0} }, + { "menu_add_separator", {menu_add_separator, TRUE} }, { "menu_remove", {menu_remove, 0} } }; @@ -702,6 +703,7 @@ menu_add(WebKitWebView *page, GArray *argv, GString *result) { m = malloc(sizeof(MenuItem)); m->name = g_strdup(argv_idx(argv, 0)); m->cmd = g_strdup(item_cmd?item_cmd:""); + m->issep = FALSE; g_ptr_array_add(uzbl.gui.menu_items, m); } else @@ -709,6 +711,30 @@ menu_add(WebKitWebView *page, GArray *argv, GString *result) { } +void +menu_add_separator(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + (void) argv; + MenuItem *m; + gchar *sep_name; + + if(!uzbl.gui.menu_items) + uzbl.gui.menu_items = g_ptr_array_new(); + + if(!argv_idx(argv, 0)) + return; + else + sep_name = argv_idx(argv, 0); + + m = malloc(sizeof(MenuItem)); + m->name = g_strdup(sep_name); + m->cmd = NULL; + m->issep = TRUE; + g_ptr_array_add(uzbl.gui.menu_items, m); +} + + void menu_remove(WebKitWebView *page, GArray *argv, GString *result) { (void) page; @@ -720,10 +746,10 @@ menu_remove(WebKitWebView *page, GArray *argv, GString *result) { if(!uzbl.gui.menu_items) return; - if(argv_idx(argv, 0)) - name = argv_idx(argv, 0); - else + if(!argv_idx(argv, 0)) return; + else + name = argv_idx(argv, 0); for(i=0; i < uzbl.gui.menu_items->len; i++) { mi = g_ptr_array_index(uzbl.gui.menu_items, i); diff --git a/uzbl-core.h b/uzbl-core.h index 2cfedcc..63df588 100644 --- a/uzbl-core.h +++ b/uzbl-core.h @@ -434,6 +434,9 @@ init_connect_socket(); void menu_add(WebKitWebView *page, GArray *argv, GString *result); +void +menu_add_separator(WebKitWebView *page, GArray *argv, GString *result); + void menu_remove(WebKitWebView *page, GArray *argv, GString *result); @@ -446,6 +449,7 @@ typedef struct { typedef struct { gchar *name; gchar *cmd; + gboolean issep; } MenuItem; -- cgit v1.2.3 From 5578476f343cd4323f42ca24813ad307aae1f817 Mon Sep 17 00:00:00 2001 From: Robert Manea Date: Sun, 18 Oct 2009 23:17:41 +0200 Subject: changed menu_add syntay to: menu_add <:> = exit -@bind <:> = uri http://uzbl.org/ +@bind a<:>q = exit +@bind a<:>h = uri http://uzbl.org/ # === command editing configuration ========================================== # you'll want this at the very least -@bind = request KEYCMD_EXEC_CURRENT +@bind = event KEYCMD_EXEC_CURRENT +@bind = event @set_mode # basic searching -@bind = request SET_CURSOR_POS 0 -@bind = request SET_CURSOR_POS -1 -@bind = request SET_CURSOR_POS - -@bind = request SET_CURSOR_POS + -@bind = request KEYCMD_BACKSPACE +@bind = event SET_CURSOR_POS 0 +@bind = event SET_CURSOR_POS -1 +@bind = event SET_CURSOR_POS - +@bind = event SET_CURSOR_POS + +@bind = event KEYCMD_BACKSPACE +@bind = event KEYCMD_DELETE # readline-ish bindings -@bind = request KEYCMD_STRIP_WORD -@bind = request SET_KEYCMD -@bind = request SET_CURSOR_POS 0 -@bind = request SET_CURSOR_POS -1 +@bind w = event KEYCMD_STRIP_WORD +@bind u = event SET_KEYCMD +@bind a = event SET_CURSOR_POS 0 +@bind e = event SET_CURSOR_POS -1 # === Context menu items ===================================================== @@ -235,7 +238,7 @@ set insert = @mode_config insert set stack = @mode_config stack # Command mode config. -@command keycmd_style = weight="bold" foreground="red" +@command keycmd_style = foreground="red" @command status_background = #202020 @command mode_indicator = Cmd diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 7a2d1cc..fe017eb 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -135,12 +135,13 @@ class Bind(object): nextbid = counter().next def __init__(self, glob, handler, *args, **kargs): - self.callable = iscallable(handler) + self.is_callable = iscallable(handler) + self._repr_cache = None if not glob: raise ArgumentError('glob cannot be blank') - if self.callable: + if self.is_callable: self.function = handler self.args = args self.kargs = kargs @@ -172,9 +173,8 @@ class Bind(object): msg = 'found null segment after first prompt: %r' % split raise BindParseError(msg) - self._stack = [] - - for glob in split[::2]: + stack = [] + for (index, glob) in enumerate(reversed(split[::2])): # Is the binding a MODCMD or KEYCMD: mod_cmd = ismodbind(glob) @@ -185,22 +185,28 @@ class Bind(object): has_args = True if glob[-1] in ['*', '_'] else False glob = glob[:-1] if has_args else glob - self._stack.append((mod_cmd, on_exec, has_args, glob)) + stack.append((mod_cmd, on_exec, has_args, glob, index)) + + self.stack = list(reversed(stack)) + self.is_global = len(self.stack) == 1 - def is_global(self): - ''' Returns True if this Bind should be applied in all depths ''' - return len(self._stack) == 1 and self._stack[0][MOD_CMD] def __getitem__(self, depth): - ''' get bind info at a depth ''' - if self.is_global(): - return self._stack[0], False - return self._stack[depth], depth - len(self._stack) + 1 + '''Get bind info at a depth.''' + + if self.is_global: + return self.stack[0] + + return self.stack[depth] + def __repr__(self): + if self._repr_cache: + return self._repr_cache + args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] - if self.callable: + if self.is_callable: args.append('function=%r' % self.function) if self.args: args.append('args=%r' % self.args) @@ -213,13 +219,16 @@ class Bind(object): cmds = self.commands[0] if cmdlen == 1 else self.commands args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) - return '' % ', '.join(args) + self._repr_cache = '' % ', '.join(args) + return self._repr_cache def exec_bind(uzbl, bind, *args, **kargs): '''Execute bind objects.''' - if bind.callable: + uzbl.event("EXEC_BIND", bind, args, kargs) + + if bind.is_callable: args += bind.args kargs = dict(bind.kargs.items()+kargs.items()) bind.function(uzbl, *args, **kargs) @@ -229,7 +238,6 @@ def exec_bind(uzbl, bind, *args, **kargs): raise ArgumentError('cannot supply kargs for uzbl commands') commands = [] - for cmd in bind.commands: if '%s' in cmd: if len(args) > 1: @@ -309,12 +317,13 @@ def filter_bind(uzbl, bind_dict, bind): def match_and_exec(uzbl, bind, depth, keycmd): bind_dict = get_bind_dict(uzbl) - (mod_cmd, on_exec, has_args, glob), more = bind[depth] + (mod_cmd, on_exec, has_args, glob, more) = bind[depth] if has_args: if not keycmd.startswith(glob): if not mod_cmd: filter_bind(uzbl, bind_dict, bind) + return False args = [keycmd[len(glob):],] @@ -322,28 +331,28 @@ def match_and_exec(uzbl, bind, depth, keycmd): elif keycmd != glob: if not mod_cmd: filter_bind(uzbl, bind_dict, bind) + return False else: args = [] - if bind.is_global() or (not more and depth == 0): + if bind.is_global or (not more and depth == 0): exec_bind(uzbl, bind, *args) - if not has_args and not mod_cmd: - uzbl.clear_keycmd() + if not has_args: + uzbl.clear_current() return True elif more: if bind_dict['depth'] == depth: - globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global()] + globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] bind_dict['filter'] = [bind,] + globalcmds bind_dict['args'] += args bind_dict['depth'] = depth + 1 - else: - if bind not in bind_dict['filter']: - bind_dict['filter'].append(bind) + elif bind not in bind_dict['filter']: + bind_dict['filter'].append(bind) set_stack_mode(uzbl, bind.prompts[depth]) return False @@ -351,52 +360,58 @@ def match_and_exec(uzbl, bind, depth, keycmd): args = bind_dict['args'] + args exec_bind(uzbl, bind, *args) uzbl.set_mode() + if not has_args: + uzbl.clear_current() return True def keycmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.key_cmd() + keycmd = keylet.get_keycmd() for bind in get_filtered_binds(uzbl): - (t,more) = bind[depth] + t = bind[depth] if t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, depth, keycmd) + if match_and_exec(uzbl, bind, depth, keycmd): + return def keycmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.key_cmd() + keycmd = keylet.get_keycmd() for bind in get_filtered_binds(uzbl): - (t,more) = bind[depth] + t = bind[depth] if t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, depth, keycmd) + if match_and_exec(uzbl, bind, depth, keycmd): + return uzbl.clear_keycmd() def modcmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.mod_cmd() + keycmd = keylet.get_modcmd() for bind in get_filtered_binds(uzbl): - (t,more) = bind[depth] + t = bind[depth] if not t[MOD_CMD] or t[ON_EXEC]: continue - match_and_exec(uzbl, bind, depth, keycmd) + if match_and_exec(uzbl, bind, depth, keycmd): + return def modcmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.mod_cmd() + keycmd = keylet.get_modcmd() for bind in get_filtered_binds(uzbl): - (t,more) = bind[depth] + t = bind[depth] if not t[MOD_CMD] or not t[ON_EXEC]: continue - match_and_exec(uzbl, bind, depth, keycmd) + if match_and_exec(uzbl, bind, depth, keycmd): + return uzbl.clear_modcmd() def init(uzbl): diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 79a96e4..109bb38 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -1,16 +1,14 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. -__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet'] - -# Regular expression compile cache. -_RE_CACHE = {} +__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', + 'clear_current', 'clear_modcmd'] # Hold the keylets. UZBLS = {} # Simple key names map. -_SIMPLEKEYS = { +SIMPLEKEYS = { 'Control': 'Ctrl', 'ISO_Left_Tab': 'Shift-Tab', 'space':'Space', @@ -20,7 +18,7 @@ _SIMPLEKEYS = { KEYCMD_FORMAT = "%s%s%s" -def escape(str): +def uzbl_escape(str): '''Prevent outgoing keycmd values from expanding inside the status_format.''' @@ -34,61 +32,57 @@ def escape(str): return "@[%s]@" % str -def get_regex(regex): - '''Compiling regular expressions is a very time consuming so return a - pre-compiled regex match object if possible.''' - - if regex not in _RE_CACHE: - _RE_CACHE[regex] = re.compile(regex).match - - return _RE_CACHE[regex] - - class Keylet(object): '''Small per-instance object that tracks all the keys held and characters typed.''' def __init__(self): - self.cmd = '' - self.cursor = 0 + # Modcmd tracking self.held = [] + self.modcmd = '' + self.is_modcmd = False + + # Keycmd tracking + self.keycmd = '' + self.cursor = 0 - # to_string() string building cache. - self._to_string = None + # Keylet string repr cache. + self._repr_cache = None - self.modcmd = False - def mod_held(self): - ''' returns true if any modkey is held. ''' - return any([len(x) != 1 for x in self.held]) + def get_keycmd(self): + '''Get the keycmd-part of the keylet.''' - def key_cmd(self): - ''' get the keycmd-part of the keylet. ''' - return self.cmd + return self.keycmd + + + def get_modcmd(self): + '''Get the modcmd-part of the keylet.''' + + if not self.is_modcmd: + return '' + + return ''.join(['<%s>' % key for key in self.held]) + self.modcmd - def mod_cmd(self): - ''' get the modcmd-part of the keylet. ''' - return ''.join(['<%s>' % key for key in self.held]) def __repr__(self): - return '' % self.to_string() + '''Return a string representation of the keylet.''' - def to_string(self): - '''Return a string representation of the keys held and pressed that - have been recorded.''' + if self._repr_cache: + return self._repr_cache - if self._to_string is not None: - # Return cached keycmd string. - return self._to_string - - self._to_string = self.mod_cmd() + self.key_cmd() - return self._to_string + l = [] + if self.is_modcmd: + l.append('modcmd=%r' % self.get_modcmd()) + elif self.held: + l.append('held=%r' % ''.join(['<%s>'%key for key in self.held])) - def match(self, regex): - '''See if the keycmd string matches the given regex.''' + if self.keycmd: + l.append('keycmd=%r' % self.get_keycmd()) - return bool(get_regex(regex)(self.to_string())) + self._repr_cache = '' % ', '.join(l) + return self._repr_cache def make_simple(key): @@ -98,8 +92,8 @@ def make_simple(key): if key.endswith('_L') or key.endswith('_R'): key = key[:-2] - if key in _SIMPLEKEYS: - key = _SIMPLEKEYS[key] + if key in SIMPLEKEYS: + key = SIMPLEKEYS[key] return key @@ -126,7 +120,7 @@ def get_keylet(uzbl): add_instance(uzbl) keylet = UZBLS[uzbl] - keylet._to_string = None + keylet._repr_cache = False return keylet @@ -134,55 +128,92 @@ def clear_keycmd(uzbl): '''Clear the keycmd for this uzbl instance.''' k = get_keylet(uzbl) - k.cmd = '' + k.keycmd = '' k.cursor = 0 - k._to_string = None - - k.modcmd = k.mod_held() + k._repr_cache = False config = uzbl.get_config() if 'keycmd' not in config or config['keycmd'] != '': - config['keycmd'] = '' + uzbl.set('keycmd', '') + uzbl.send('update_gui') uzbl.event('KEYCMD_CLEAR') +def clear_modcmd(uzbl, clear_held=False): + '''Clear the modcmd for this uzbl instance.''' + + k = get_keylet(uzbl) + k.modcmd = '' + k.is_modcmd = False + k._repr_cache = False + if clear_held: + k.held = [] + + config = uzbl.get_config() + if 'modcmd' not in config or config['modcmd'] != '': + uzbl.set('modcmd', '') + uzbl.send('update_gui') + + uzbl.event('MODCMD_CLEAR') + + +def clear_current(uzbl): + '''Clear the modcmd if is_modcmd else clear keycmd.''' + + k = get_keylet(uzbl) + if k.is_modcmd: + clear_modcmd(uzbl) + + else: + clear_keycmd(uzbl) + + +def focus_changed(uzbl, *args): + '''Focus to the uzbl instance has now been lost which means all currently + held keys in the held list will not get a KEY_RELEASE event so clear the + entire held list.''' + + clear_modcmd(uzbl, clear_held=True) + + def update_event(uzbl, k, execute=True): '''Raise keycmd & modcmd update events.''' config = uzbl.get_config() - if k.modcmd: - keycmd = k.to_string() - if execute: - uzbl.event('MODCMD_UPDATE', k) - if keycmd != k.to_string(): - return + keycmd, modcmd = k.get_keycmd(), k.get_modcmd() - if 'modcmd_updates' in config and config['modcmd_updates'] != '1': - return + if k.is_modcmd: + uzbl.event('MODCMD_UPDATE', k) - return uzbl.set('keycmd', escape(keycmd)) + else: + uzbl.event('KEYCMD_UPDATE', k) + + if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': + new_modcmd = k.get_modcmd() + if not new_modcmd or new_modcmd == modcmd: + uzbl.set('modcmd', uzbl_escape(new_modcmd)) if 'keycmd_events' in config and config['keycmd_events'] != '1': - return + return uzbl.send('update_gui') - keycmd = k.cmd - if execute: - uzbl.event('KEYCMD_UPDATE', k) - if keycmd != k.cmd: - return + new_keycmd = k.get_keycmd() + if not new_keycmd or new_keycmd != keycmd: + uzbl.set('keycmd', '') + return uzbl.send('update_gui') - if not k.cmd: - return uzbl.set('keycmd', '') # Generate the pango markup for the cursor in the keycmd. - if k.cursor < len(k.cmd): - cursor = k.cmd[k.cursor] + curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' + chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] + uzbl.set('keycmd', KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks))) + uzbl.send('update_gui') - else: - cursor = ' ' - chunks = map(escape, [k.cmd[:k.cursor], cursor, k.cmd[k.cursor+1:]]) - uzbl.set('keycmd', KEYCMD_FORMAT % tuple(chunks)) +def inject_char(str, index, char): + '''Inject character into string at at given index.''' + + assert len(char) == 1 + return "%s%s%s" % (str[:index], char, str[index:]) def key_press(uzbl, key): @@ -202,41 +233,34 @@ def key_press(uzbl, key): key = make_simple(key) k = get_keylet(uzbl) - cmdmod = False - - if k.cmd and not k.modcmd and key == 'Space': - k.cmd = "%s %s" % (k.cmd[:k.cursor], k.cmd[k.cursor:]) + if key == 'Space' and not k.held and k.keycmd: + k.keycmd = inject_char(k.keycmd, k.cursor, ' ') k.cursor += 1 - cmdmod = True - elif len(key) > 1: - k.modcmd = True - cmdmod = True - - elif not k.modcmd: + elif not k.held and len(key) == 1: config = uzbl.get_config() if 'keycmd_events' not in config or config['keycmd_events'] == '1': - if len(key) == 1: - cmdmod = True - k.cmd = "%s%s%s" % (k.cmd[:k.cursor], key, k.cmd[k.cursor:]) - k.cursor += 1 - - elif k.cmd: - cmdmod = True - k.cmd = '' + k.keycmd = inject_char(k.keycmd, k.cursor, key) + k.cursor += 1 + + elif k.keycmd: + k.keycmd = '' k.cursor = 0 - if k.modcmd: + elif len(key) > 1: + k.is_modcmd = True if key == 'Shift-Tab' and 'Tab' in k.held: k.held.remove('Tab') if key not in k.held: k.held.append(key) k.held.sort() - cmdmod = True - if cmdmod: - update_event(uzbl, k) + else: + k.is_modcmd = True + k.modcmd += key + + update_event(uzbl, k) def key_release(uzbl, key): @@ -251,8 +275,6 @@ def key_release(uzbl, key): key = make_simple(key) k = get_keylet(uzbl) - - cmdmod = False if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: key = 'Shift-Tab' @@ -260,65 +282,69 @@ def key_release(uzbl, key): key = 'Meta' if key in k.held: - cmdmod = True - k.held.remove(key) - k.modcmd = k.mod_held() - if k.modcmd: + if k.is_modcmd: uzbl.event('MODCMD_EXEC', k) - if cmdmod: - update_event(uzbl, k) + k.held.remove(key) + #k.is_modcmd = False + #k.modcmd = '' + #update_event(uzbl, k) + clear_modcmd(uzbl) def set_keycmd(uzbl, keycmd): '''Allow setting of the keycmd externally.''' k = get_keylet(uzbl) - k.modcmd = False - k._to_string = None - k.cmd = keycmd + k.keycmd = keycmd + k._repr_cache = None k.cursor = len(keycmd) - update_event(uzbl, k, False) def keycmd_strip_word(uzbl, sep): ''' Removes the last word from the keycmd, similar to readline ^W ''' + sep = sep or ' ' k = get_keylet(uzbl) - if not k.cmd: + if not k.keycmd: return - cmd = k.cmd[:k.cursor] - tail = len(k.cmd) - k.cursor + head, tail = k.keycmd[:k.cursor].rstrip(sep), k.keycmd[k.cursor:] + rfind = head.rfind(sep) + head = head[:rfind] if rfind + 1 else '' + k.keycmd = head + tail + k.cursor = len(head) + update_event(uzbl, k, False) - if sep in cmd: - tmp = cmd.rstrip(sep).rsplit(sep, 1) - else: - tmp = ('',) - k.cmd = tmp[0] + (sep if len(tmp) == 2 else '') + k.cmd[k.cursor:] - k.cursor = len(tmp[0]) + (len(tmp) - 1) +def keycmd_backspace(uzbl, *args): + '''Removes the character at the cursor position in the keycmd.''' - assert len(k.cmd) - k.cursor == tail, "tail size changed (%s) (%s - %s)" % (tail, len(k.cmd), k.cursor) + k = get_keylet(uzbl) + if not k.keycmd: + return + k.keycmd = k.keycmd[:k.cursor-1] + k.keycmd[k.cursor:] + k.cursor -= 1 update_event(uzbl, k, False) -def keycmd_backspace(uzbl, _foo): - ''' Removes the last char of the keycmd ''' +def keycmd_delete(uzbl, *args): + '''Removes the character after the cursor position in the keycmd.''' + k = get_keylet(uzbl) - if not k.cmd: + if not k.keycmd: return - k.cmd = k.cmd[:k.cursor-1] + k.cmd[k.cursor:] - k.cursor -= 1 - + k.keycmd = k.keycmd[:k.cursor] + k.keycmd[k.cursor+1:] update_event(uzbl, k, False) -def keycmd_exec_current(uzbl, _foo): - ''' Raise a KEYCMD_EXEC with the current keylet and then clear the keycmd ''' +def keycmd_exec_current(uzbl, *args): + '''Raise a KEYCMD_EXEC with the current keylet and then clear the + keycmd.''' + k = get_keylet(uzbl) uzbl.event('KEYCMD_EXEC', k) clear_keycmd(uzbl) @@ -329,21 +355,22 @@ def set_cursor_pos(uzbl, index): indexing and relative stepping with '+' and '-'.''' k = get_keylet(uzbl) - if index == '-': cursor = k.cursor - 1 + elif index == '+': cursor = k.cursor + 1 + else: cursor = int(index.strip()) if cursor < 0: - cursor = len(k.cmd) + cursor + 1 + cursor = len(k.keycmd) + cursor + 1 if cursor < 0: cursor = 0 - if cursor > len(k.cmd): - cursor = len(k.cmd) + if cursor > len(k.keycmd): + cursor = len(k.keycmd) k.cursor = cursor update_event(uzbl, k, False) @@ -359,7 +386,10 @@ def init(uzbl): 'SET_KEYCMD': set_keycmd, 'KEYCMD_STRIP_WORD': keycmd_strip_word, 'KEYCMD_BACKSPACE': keycmd_backspace, + 'KEYCMD_DELETE': keycmd_delete, 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, - 'SET_CURSOR_POS': set_cursor_pos} + 'SET_CURSOR_POS': set_cursor_pos, + 'FOCUS_LOST': focus_changed, + 'FOCUS_GAINED': focus_changed} uzbl.connect_dict(connects) -- cgit v1.2.3 From 75c771ecf35605045dd7760269395ca276e8d989 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 25 Oct 2009 03:24:16 +0800 Subject: Catch attempts to write to a closed socket in the EM. --- examples/data/uzbl/scripts/event_manager.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 271c65e..391fb84 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -595,7 +595,13 @@ class UzblEventDaemon(dict): try: uzbl = self['uzbls'][client] - raw = unicode(client.recv(8192), 'utf-8', 'ignore') + try: + raw = unicode(client.recv(8192), 'utf-8', 'ignore') + + except: + print_exc() + raw = None + if not raw: # Read null byte, close socket. return self.close_connection(client) -- cgit v1.2.3 From ebc330e5be2df3805fc39534ed9eb036c5e85dd3 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 26 Oct 2009 00:09:24 +0800 Subject: Only make a bind global if its a mod-bind. --- examples/data/uzbl/plugins/bind.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index fe017eb..8c932be 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -24,7 +24,7 @@ starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') find_prompts = re.compile('<([^:>]*):>').split # For accessing a bind glob stack. -MOD_CMD, ON_EXEC, HAS_ARGS, GLOB = range(4) +MOD_CMD, ON_EXEC, HAS_ARGS, GLOB, MORE = range(5) class BindParseError(Exception): @@ -188,7 +188,7 @@ class Bind(object): stack.append((mod_cmd, on_exec, has_args, glob, index)) self.stack = list(reversed(stack)) - self.is_global = len(self.stack) == 1 + self.is_global = (len(self.stack) == 1 and self.stack[0][MOD_CMD]) def __getitem__(self, depth): -- cgit v1.2.3 From bb8678cb4ea1de030037409b0d2fcf819b4362bd Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 26 Oct 2009 02:01:58 +0800 Subject: Replaced make_simple function with mod-mapping ability in keycmd plugin. --- examples/config/uzbl/config | 14 ++++++- examples/data/uzbl/plugins/keycmd.py | 74 +++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 28 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 7d05e9e..55267fd 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -13,6 +13,8 @@ set toggle_modes = request TOGGLE_MODES set on_event = request ON_EVENT # request PROGRESS_CONFIG = set progress = request PROGRESS_CONFIG +# request MODMAP From To +set modmap = request MODMAP set set_mode = set mode = set set_status = set status_message = @@ -42,8 +44,8 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh @on_event LOAD_FINISH @set_status done @on_event LOAD_FINISH spawn @scripts_dir/history.sh -# Generate a FORM_ACTIVE event if an editable -# element on the loaded site has initial focus +# Generate a FORM_ACTIVE event if an editable +# element on the loaded site has initial focus @on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} # Switch to insert mode if a (editable) html form is clicked @@ -98,6 +100,14 @@ set fifo_dir = /tmp set socket_dir = /tmp +# === Binding modmaps ======================================================== + +#modmap from to +@modmap Control Ctrl +@modmap ISO_Left_Tab Shift-Tab +@modmap space Space + + # === Keyboard bindings ====================================================== # With this command you can enter in any command at runtime when prefixed with diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 109bb38..c3dec05 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -2,18 +2,11 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. __export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', - 'clear_current', 'clear_modcmd'] + 'clear_current', 'clear_modcmd', 'add_modmap'] # Hold the keylets. UZBLS = {} -# Simple key names map. -SIMPLEKEYS = { - 'Control': 'Ctrl', - 'ISO_Left_Tab': 'Shift-Tab', - 'space':'Space', -} - # Keycmd format which includes the markup for the cursor. KEYCMD_FORMAT = "%s%s%s" @@ -46,6 +39,9 @@ class Keylet(object): self.keycmd = '' self.cursor = 0 + # Key modmaps. + self.modmap = {} + # Keylet string repr cache. self._repr_cache = None @@ -65,6 +61,20 @@ class Keylet(object): return ''.join(['<%s>' % key for key in self.held]) + self.modcmd + def key_modmap(self, key): + '''Make some obscure names for some keys friendlier.''' + + if key in self.modmap: + return self.modmap[key] + + elif key.endswith('_L') or key.endswith('_R'): + # Remove left-right discrimination and try again. + return self.key_modmap(key[:-2]) + + else: + return key + + def __repr__(self): '''Return a string representation of the keylet.''' @@ -85,17 +95,30 @@ class Keylet(object): return self._repr_cache -def make_simple(key): - '''Make some obscure names for some keys friendlier.''' +def add_modmap(uzbl, key, map=None): + '''Add modmaps.''' - # Remove left-right discrimination. - if key.endswith('_L') or key.endswith('_R'): - key = key[:-2] + keylet = get_keylet(uzbl) + if not map: + if key in keylet.modmap: + map = keylet.modmap[key] + del keylet.modmap[key] + uzbl.event("DEL_MODMAP", key, map) + + else: + keylet.modmap[key] = map + uzbl.event("NEW_MODMAP", key, map) - if key in SIMPLEKEYS: - key = SIMPLEKEYS[key] - return key +def modmap_parse(uzbl, map): + '''Parse a modmap definiton.''' + + split = [s.strip() for s in map.split(' ') if s.split()] + + if not split or len(split) > 2: + raise Exception('Invalid modmap arugments: %r' % map) + + add_modmap(uzbl, *split) def add_instance(uzbl, *args): @@ -229,10 +252,12 @@ def key_press(uzbl, key): if key.startswith('Shift_'): return - if len(key) > 1: - key = make_simple(key) - k = get_keylet(uzbl) + key = k.key_modmap(key.strip()) + print 'KEY', key + if key.startswith(" 1: - key = make_simple(key) - k = get_keylet(uzbl) + key = k.key_modmap(key) + if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: key = 'Shift-Tab' @@ -286,9 +310,6 @@ def key_release(uzbl, key): uzbl.event('MODCMD_EXEC', k) k.held.remove(key) - #k.is_modcmd = False - #k.modcmd = '' - #update_event(uzbl, k) clear_modcmd(uzbl) @@ -390,6 +411,7 @@ def init(uzbl): 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, 'SET_CURSOR_POS': set_cursor_pos, 'FOCUS_LOST': focus_changed, - 'FOCUS_GAINED': focus_changed} + 'FOCUS_GAINED': focus_changed, + 'MODMAP': modmap_parse} uzbl.connect_dict(connects) -- cgit v1.2.3 From 3e0fb515663178f9a06a0928fd9ddab13d702e20 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 26 Oct 2009 02:54:07 +0800 Subject: Fix key filtering. --- examples/data/uzbl/plugins/keycmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index c3dec05..311684b 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -255,7 +255,7 @@ def key_press(uzbl, key): k = get_keylet(uzbl) key = k.key_modmap(key.strip()) print 'KEY', key - if key.startswith(" Date: Sun, 25 Oct 2009 20:29:26 +0100 Subject: re-enable bookmarks script, make builtin-bookmarking compatible + allow reloading config without reloading home page --- examples/config/uzbl/config | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 7d05e9e..52de5e5 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -133,7 +133,8 @@ set socket_dir = /tmp @bind gg _ = uri http://www.google.com/search?q=%s # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -#@bind B = spawn @scripts_dir/insert_bookmark.sh +# use a script to insert bookmarks. or use the EM/keycmd technique a bit further down +@bind B = spawn @scripts_dir/insert_bookmark.sh @bind U = spawn @scripts_dir/load_url_from_history.sh @bind u = spawn @scripts_dir/load_url_from_bookmarks.sh # with the sample yank script, you can yank one of the arguments into clipboard/selection @@ -159,7 +160,7 @@ set socket_dir = /tmp @bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' @bind !dump = sh "echo dump_config > $4" -@bind !reload = sh 'cat $1 > $4' +@bind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" # this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically set formfiller = spawn @scripts_dir/formfiller @@ -187,9 +188,8 @@ set formfiller = spawn @scripts_dir/formfiller # Examples using multi-stage-bindings with text prompts. @bind o_ = uri %s -# Prints tab separated "uri title keyword tags" to the bookmarks file. -# TODO: Improve bookmarks script to handle this format & include date in bookmark format. -@bind b__ = sh 'echo -e "$6 $7 %s %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +# multi-stage binding way to write bookmarks to file from inside uzbl. +@bind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' # Multi-stage bindings with blank prompts (similar behaviour to emacs M-c M-s bindings?) @bind a<:>q = exit -- cgit v1.2.3 From 9d294e7578e09951c7f0a4ee28d268c2bb3ebe32 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 26 Oct 2009 03:34:24 +0800 Subject: Remove useless update_gui commands in the EM plugins. --- examples/data/uzbl/plugins/keycmd.py | 9 ++------- examples/data/uzbl/plugins/mode.py | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 311684b..9696521 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -157,7 +157,6 @@ def clear_keycmd(uzbl): config = uzbl.get_config() if 'keycmd' not in config or config['keycmd'] != '': uzbl.set('keycmd', '') - uzbl.send('update_gui') uzbl.event('KEYCMD_CLEAR') @@ -175,7 +174,6 @@ def clear_modcmd(uzbl, clear_held=False): config = uzbl.get_config() if 'modcmd' not in config or config['modcmd'] != '': uzbl.set('modcmd', '') - uzbl.send('update_gui') uzbl.event('MODCMD_CLEAR') @@ -217,19 +215,16 @@ def update_event(uzbl, k, execute=True): uzbl.set('modcmd', uzbl_escape(new_modcmd)) if 'keycmd_events' in config and config['keycmd_events'] != '1': - return uzbl.send('update_gui') + return new_keycmd = k.get_keycmd() if not new_keycmd or new_keycmd != keycmd: - uzbl.set('keycmd', '') - return uzbl.send('update_gui') - + return uzbl.set('keycmd', '') # Generate the pango markup for the cursor in the keycmd. curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] uzbl.set('keycmd', KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks))) - uzbl.send('update_gui') def inject_char(str, index, char): diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index ad0d9a8..e7705a0 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -88,7 +88,6 @@ def set_mode(uzbl, mode=None): config['mode_indicator'] = mode uzbl.clear_keycmd() - uzbl.send('update_gui') uzbl.event("MODE_CHANGED", mode) -- cgit v1.2.3 From 341ce1071948ebd97bf2172f65e95e545627d96b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 26 Oct 2009 03:52:43 +0800 Subject: Remove debug print. --- examples/data/uzbl/plugins/keycmd.py | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 9696521..d01d2ac 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -249,7 +249,6 @@ def key_press(uzbl, key): k = get_keylet(uzbl) key = k.key_modmap(key.strip()) - print 'KEY', key if key.startswith("ISO_"): return -- cgit v1.2.3 From 1c28354f0e6e54395f494a79b4a43285f0dfa71f Mon Sep 17 00:00:00 2001 From: Brendan Taylor Date: Sun, 25 Oct 2009 14:08:35 -0600 Subject: remove pointless cmd_{cookie,scheme}_handler() --- callbacks.c | 26 -------------------------- callbacks.h | 6 ------ examples/config/uzbl/config | 2 +- uzbl-core.c | 4 ++-- 4 files changed, 3 insertions(+), 35 deletions(-) (limited to 'examples') diff --git a/callbacks.c b/callbacks.c index 175f4a3..b986172 100644 --- a/callbacks.c +++ b/callbacks.c @@ -230,32 +230,6 @@ cmd_caret_browsing() { uzbl.behave.caret_browsing, NULL); } -void -cmd_cookie_handler() { - gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2); - /* pitfall: doesn't handle chain actions; must the sync_ action manually */ - if ((g_strcmp0(split[0], "sh") == 0) || - (g_strcmp0(split[0], "spawn") == 0)) { - g_free (uzbl.behave.cookie_handler); - uzbl.behave.cookie_handler = - g_strdup_printf("sync_%s %s", split[0], split[1]); - } - g_strfreev (split); -} - -void -cmd_scheme_handler() { - gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2); - /* pitfall: doesn't handle chain actions; must the sync_ action manually */ - if ((g_strcmp0(split[0], "sh") == 0) || - (g_strcmp0(split[0], "spawn") == 0)) { - g_free (uzbl.behave.scheme_handler); - uzbl.behave.scheme_handler = - g_strdup_printf("sync_%s %s", split[0], split[1]); - } - g_strfreev (split); -} - void cmd_fifo_dir() { uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir); diff --git a/callbacks.h b/callbacks.h index 72361ba..05dc618 100644 --- a/callbacks.h +++ b/callbacks.h @@ -15,12 +15,6 @@ set_proxy_url(); void set_icon(); -void -cmd_cookie_handler(); - -void -cmd_scheme_handler(); - void move_statusbar(); diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 07bf69a..d72be2c 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -28,7 +28,7 @@ set scripts_dir = $XDG_DATA_HOME/uzbl:/usr/local/share/uzbl/examples/data/uzb set download_handler = spawn @scripts_dir/download.sh set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket -set scheme_handler = spawn @scripts_dir/scheme.py +set scheme_handler = sync_spawn @scripts_dir/scheme.py # New window handler options #set new_window = sh 'echo uri "$8" > $4' # open in same window diff --git a/uzbl-core.c b/uzbl-core.c index 3ece965..b09b727 100644 --- a/uzbl-core.c +++ b/uzbl-core.c @@ -103,9 +103,9 @@ const struct var_name_to_ptr_t { { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)}, { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)}, { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, - { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)}, + { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, NULL)}, { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)}, - { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, cmd_scheme_handler)}, + { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)}, { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)}, { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)}, -- cgit v1.2.3 From 01d254637ee0f49f797b15f65d99325405fa580b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 27 Oct 2009 03:03:17 +0800 Subject: Remove the hard-coded /usr/local/.. path in event_manager.py --- Makefile | 1 + examples/data/uzbl/scripts/event_manager.py | 9 ++++++++- uzbl-browser | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/Makefile b/Makefile index 99affde..ca066e7 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,7 @@ install-uzbl-browser: all install -m755 examples/data/uzbl/scripts/cookie_daemon.py $(PREFIX)/bin/cookie_daemon.py install -m755 examples/data/uzbl/scripts/event_manager.py $(PREFIX)/bin/event_manager.py sed -i 's#^PREFIX=.*#PREFIX=$(PREFIX)#' $(PREFIX)/bin/uzbl-browser + sed -i "s#^PREFIX = None#PREFIX = '$(PREFIX)'#" $(PREFIX)/bin/event_manager.py install-uzbl-tabbed: all install -d $(PREFIX)/bin diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 391fb84..aaf3295 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -45,6 +45,12 @@ from traceback import print_exc # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ +# Automagically set during `make install` +PREFIX = None + +# Check if PREFIX not set and set to default /usr/local/ +if not PREFIX: + PREFIX = '/usr/local/' def xdghome(key, default): '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise @@ -60,6 +66,7 @@ def xdghome(key, default): DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') + # Config dict (NOT the same as the uzbl.config). config = { 'verbose': False, @@ -69,7 +76,7 @@ config = { 'plugins_ignore': [], 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), - '/usr/local/share/uzbl/examples/data/uzbl/plugins/'], + os.path.join(PREFIX, 'share/uzbl/examples/data/uzbl/plugins/')], 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), diff --git a/uzbl-browser b/uzbl-browser index 1084291..94c2c2a 100755 --- a/uzbl-browser +++ b/uzbl-browser @@ -54,7 +54,7 @@ then fi DAEMON_SOCKET=$XDG_CACHE_HOME/uzbl/event_daemon -DAEMON_PID=$XDG_CACHE_HOME/uzbl/event_daemon.pid +DAEMON_PID=${DAEMON_SOCKET}.pid #if [ -f "$DAEMON_PID" ] #then -- cgit v1.2.3 From a20a442bd3f486955d124ed3a664e24fa0dacbce Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 27 Oct 2009 03:59:10 +0800 Subject: Added --auto-close option to the event manager. --- Makefile | 2 +- examples/data/uzbl/scripts/event_manager.py | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/Makefile b/Makefile index ca066e7..ba65d7a 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ test-dev: uzbl-core test-dev-browser: uzbl-browser XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py start -nv & XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/event_manager.py start -nv & - XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH:`pwd`/examples/data/uzbl/scripts/" ./uzbl-browser --uri http://www.uzbl.org --verbose + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:`pwd`/examples/data/uzbl/scripts/:$$PATH" ./uzbl-browser --uri http://www.uzbl.org --verbose XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py stop -v XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/event_manager.py stop -v diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index aaf3295..9c269c7 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -71,6 +71,7 @@ CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') config = { 'verbose': False, 'daemon_mode': True, + 'auto_close': False, 'plugins_load': [], 'plugins_ignore': [], @@ -664,16 +665,18 @@ class UzblEventDaemon(dict): '''Clean up after instance close.''' try: - if client not in self['uzbls']: - return - - uzbl = self['uzbls'][client] - uzbl.close() - del self['uzbls'][client] + if client in self['uzbls']: + uzbl = self['uzbls'][client] + uzbl.close() + del self['uzbls'][client] except: print_exc() + if not len(self['uzbls']) and config['auto_close']: + echo('auto closing event manager.') + self.running = False + def quit(self): '''Close all instance socket objects, server socket and delete the @@ -783,6 +786,9 @@ if __name__ == "__main__": parser.add_option('-n', '--no-daemon', dest="daemon", action="store_true", help="don't enter daemon mode.") + parser.add_option('-a', '--auto-close', dest='autoclose', + action='store_true', help='auto close after all instances disconnect.') + (options, args) = parser.parse_args() # init like {start|stop|..} daemon control section. @@ -831,6 +837,10 @@ if __name__ == "__main__": echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) + if options.autoclose: + config['auto_close'] = True + echo('will auto close.') + if options.pid: config['pid_file'] = options.pid echo("pid file location: %r" % config['pid_file']) -- cgit v1.2.3 From 346e5afc22321589d54bff9c3e3971c8392cf168 Mon Sep 17 00:00:00 2001 From: Nicolas Pouillard Date: Mon, 2 Nov 2009 10:51:23 +0100 Subject: Update docs about scrolling --- README | 10 ++++------ examples/config/uzbl/config | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/README b/README index cd3e8db..816fff4 100644 --- a/README +++ b/README @@ -111,12 +111,10 @@ The following commands are recognized: * `back` * `forward` -* `scroll_vert ` -* `scroll_horz ` - - amount is given in pixels(?) or as a percentage of the size of the view - - set amount to 100% to scroll a whole page -* `scroll_begin` -* `scroll_end` +* `scroll ` + - argument can be `begin`, `end`, or an amount given in pixels(?) + or as a percentage of the size of the view + - set the amount to 100% to scroll a whole page * `reload` * `reload_ign_cache` * `stop` diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index d72be2c..fffc8b6 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -113,13 +113,22 @@ set socket_dir = /tmp # With this command you can enter in any command at runtime when prefixed with # a colon. @bind :_ = chain '%s' - -@bind j = scroll_vert 20 -@bind k = scroll_vert -20 -@bind h = scroll_horz -20 -@bind l = scroll_horz 20 -@bind << = scroll_begin -@bind >> = scroll_end +@bind j = scroll vertical 20 +@bind = scroll vertical 20 +@bind = scroll vertical 500 +@bind k = scroll vertical -20 +@bind = scroll vertical -20 +@bind = scroll vertical -500 +@bind h = scroll horizontal -20 +@bind = scroll horizontal -20 +@bind l = scroll horizontal 20 +@bind = scroll horizontal 20 +@bind << = scroll vertical begin +@bind = scroll vertical begin +@bind >> = scroll vertical end +@bind = scroll vertical end +@bind ^ = scroll horizontal begin +@bind $ = scroll horizontal end @bind b = back @bind m = forward @bind S = stop -- cgit v1.2.3 From cec85a1e2907ddefbbbe105456d234beeb513bf7 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 3 Nov 2009 21:27:02 +0800 Subject: Always convert relative paths to full paths in the EM. --- examples/data/uzbl/scripts/event_manager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py index 9c269c7..dee42c5 100755 --- a/examples/data/uzbl/scripts/event_manager.py +++ b/examples/data/uzbl/scripts/event_manager.py @@ -813,7 +813,8 @@ if __name__ == "__main__": config['verbose'] = True if options.plugin_dirs: - plugin_dirs = map(str.strip, options.plugin_dirs.split(':')) + plugin_dirs = map(os.path.realpath, map(str.strip, + options.plugin_dirs.split(':'))) config['plugin_dirs'] = plugin_dirs echo("plugin search dirs: %r" % plugin_dirs) @@ -842,11 +843,11 @@ if __name__ == "__main__": echo('will auto close.') if options.pid: - config['pid_file'] = options.pid + config['pid_file'] = os.path.realpath(options.pid) echo("pid file location: %r" % config['pid_file']) if options.socket: - config['server_socket'] = options.socket + config['server_socket'] = os.path.realpath(options.socket) echo("daemon socket location: %s" % config['server_socket']) if options.daemon: -- cgit v1.2.3 From 2dcf30f60e9e8381fc7ccca92dbf4490e33d55ed Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 3 Nov 2009 22:42:57 +0800 Subject: Improved support for prompts with default values in bind plugin. --- examples/config/uzbl/config | 2 +- examples/data/uzbl/plugins/bind.py | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 4b04d7a..57d1ea5 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -197,7 +197,7 @@ set formfiller = spawn @scripts_dir/formfiller # Examples using multi-stage-bindings with text prompts. @bind o_ = uri %s -@bind O_ = uri %s +@bind O_ = uri %s # multi-stage binding way to write bookmarks to file from inside uzbl. @bind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 356b6bd..b8494fe 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -21,7 +21,7 @@ UZBLS = {} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') -find_prompts = re.compile('<([^:>]*):(\"[^>]*\"|)>').split +find_prompts = re.compile('<([^:>]*):(\"[^\"]*\"|\'[^\']*\'|[^>]*)>').split # For accessing a bind glob stack. MOD_CMD, ON_EXEC, HAS_ARGS, GLOB, MORE = range(5) @@ -159,7 +159,13 @@ class Bind(object): self.bid = self.nextbid() self.split = split = find_prompts(glob) - self.prompts = zip(split[1::3],[x.strip('"') for x in split[2::3]]) + self.prompts = [] + for (prompt, set) in zip(split[1::3], split[2::3]): + if set and set[0] == set[-1] and set[0] in ['"', "'"]: + # Remove quotes around set. + set = set[1:-1] + + self.prompts.append((prompt, set)) # Check that there is nothing like: fl** for glob in split[:-1:3]: @@ -282,7 +288,7 @@ def parse_bind_event(uzbl, args): def set_stack_mode(uzbl, prompt): - prompt,data = prompt + prompt, set = prompt if uzbl.get_mode() != 'stack': uzbl.set_mode('stack') @@ -291,9 +297,9 @@ def set_stack_mode(uzbl, prompt): uzbl.set('keycmd_prompt', prompt) - if data: - # go through uzbl-core to expand potential @-variables - uzbl.send('event SET_KEYCMD %s' % data) + if set: + # Go through uzbl-core to expand potential @-variables + uzbl.send('event SET_KEYCMD %s' % set) def clear_stack(uzbl, mode): -- cgit v1.2.3 From 35c1e804e1dc1204f6e9ffe5942123b0f11eb59a Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 4 Nov 2009 21:31:03 +0800 Subject: Fixed binding. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 57d1ea5..7547dbe 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -211,7 +211,7 @@ set formfiller = spawn @scripts_dir/formfiller # you'll want this at the very least @bind = event KEYCMD_EXEC_CURRENT -@bind = event @set_mode +@bind = @set_mode # basic searching @bind = event SET_CURSOR_POS 0 -- cgit v1.2.3 From 32c2a87c3206565f0d0d14a6b707d82b0b693116 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 4 Nov 2009 23:01:06 +0800 Subject: Added INJECT_KEYCMD and APPEND_KEYCMD events in keycmd.py --- examples/config/uzbl/config | 7 +++++++ examples/data/uzbl/plugins/keycmd.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 7547dbe..8a2ad87 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -206,6 +206,13 @@ set formfiller = spawn @scripts_dir/formfiller @bind a<:>q = exit @bind a<:>h = uri http://uzbl.org/ +# Inject handy values into the keycmd. +@bind su = event INJECT_KEYCMD \@uri +@bind st = event INJECT_KEYCMD \@TITLE +# Or append. +@bind du = event APPEND_KEYCMD \@uri +@bind dt = event APPEND_KEYCMD \@TITLE + # === command editing configuration ========================================== diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index d01d2ac..8961f74 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -227,11 +227,10 @@ def update_event(uzbl, k, execute=True): uzbl.set('keycmd', KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks))) -def inject_char(str, index, char): - '''Inject character into string at at given index.''' +def inject_str(str, index, inj): + '''Inject a string into string at at given index.''' - assert len(char) == 1 - return "%s%s%s" % (str[:index], char, str[index:]) + return "%s%s%s" % (str[:index], inj, str[index:]) def key_press(uzbl, key): @@ -253,13 +252,13 @@ def key_press(uzbl, key): return if key == 'Space' and not k.held and k.keycmd: - k.keycmd = inject_char(k.keycmd, k.cursor, ' ') + k.keycmd = inject_str(k.keycmd, k.cursor, ' ') k.cursor += 1 elif not k.held and len(key) == 1: config = uzbl.get_config() if 'keycmd_events' not in config or config['keycmd_events'] == '1': - k.keycmd = inject_char(k.keycmd, k.cursor, key) + k.keycmd = inject_str(k.keycmd, k.cursor, key) k.cursor += 1 elif k.keycmd: @@ -317,6 +316,26 @@ def set_keycmd(uzbl, keycmd): update_event(uzbl, k, False) +def inject_keycmd(uzbl, keycmd): + '''Allow injecting of a string into the keycmd at the cursor position.''' + + k = get_keylet(uzbl) + k.keycmd = inject_str(k.keycmd, k.cursor, keycmd) + k._repr_cache = None + k.cursor += len(keycmd) + update_event(uzbl, k, False) + + +def append_keycmd(uzbl, keycmd): + '''Allow appening of a string to the keycmd.''' + + k = get_keylet(uzbl) + k.keycmd += keycmd + k._repr_cache = None + k.cursor = len(k.keycmd) + update_event(uzbl, k, False) + + def keycmd_strip_word(uzbl, sep): ''' Removes the last word from the keycmd, similar to readline ^W ''' @@ -406,6 +425,8 @@ def init(uzbl): 'SET_CURSOR_POS': set_cursor_pos, 'FOCUS_LOST': focus_changed, 'FOCUS_GAINED': focus_changed, - 'MODMAP': modmap_parse} + 'MODMAP': modmap_parse, + 'APPEND_KEYCMD': append_keycmd, + 'INJECT_KEYCMD': inject_keycmd} uzbl.connect_dict(connects) -- cgit v1.2.3 From 9dbcd20a5c3c788e4e9fcaefa01fc7cbaafd7c68 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 8 Nov 2009 16:11:39 +0100 Subject: scroll stuff: update unit tests + remove bindings that (may) conflict with keycmd or are not needed + better default behavior for pageup and pagedown --- examples/config/uzbl/config | 10 ++-------- tests/test-command.c | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 19 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 7668963..32bb13c 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -114,19 +114,13 @@ set socket_dir = /tmp # a colon. @bind :_ = chain '%s' @bind j = scroll vertical 20 -@bind = scroll vertical 20 -@bind = scroll vertical 500 +@bind = scroll vertical 100% @bind k = scroll vertical -20 -@bind = scroll vertical -20 -@bind = scroll vertical -500 +@bind = scroll vertical -100% @bind h = scroll horizontal -20 -@bind = scroll horizontal -20 @bind l = scroll horizontal 20 -@bind = scroll horizontal 20 @bind << = scroll vertical begin -@bind = scroll vertical begin @bind >> = scroll vertical end -@bind = scroll vertical end @bind ^ = scroll horizontal begin @bind $ = scroll horizontal end @bind b = back diff --git a/tests/test-command.c b/tests/test-command.c index 9275d68..769a1a9 100644 --- a/tests/test-command.c +++ b/tests/test-command.c @@ -250,27 +250,27 @@ test_scroll (void) { gtk_adjustment_set_upper(uzbl.gui.bar_v, 100); gtk_adjustment_set_page_size(uzbl.gui.bar_v, 5); - /* scroll_end should scroll it to upper - page_size */ - parse_cmd_line("scroll_end", NULL); + /* scroll vertical end should scroll it to upper - page_size */ + parse_cmd_line("scroll vertical end", NULL); g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 95); - /* scroll_begin should scroll it to lower */ - parse_cmd_line("scroll_begin", NULL); + /* scroll vertical begin should scroll it to lower */ + parse_cmd_line("scroll vertical begin", NULL); g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 0); - /* scroll_vert can scroll by pixels */ - parse_cmd_line("scroll_vert 15", NULL); + /* scroll vertical can scroll by pixels */ + parse_cmd_line("scroll vertical 15", NULL); g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 15); - parse_cmd_line("scroll_vert -10", NULL); + parse_cmd_line("scroll vertical -10", NULL); g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 5); - /* scroll_vert can scroll by a percentage of the page size */ - parse_cmd_line("scroll_vert 100%", NULL); + /* scroll vertical can scroll by a percentage of the page size */ + parse_cmd_line("scroll vertical 100%", NULL); g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 10); - parse_cmd_line("scroll_vert -150%", NULL); - g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 2.5); + parse_cmd_line("scroll vertical 150%", NULL); + g_assert_cmpfloat(gtk_adjustment_get_value(uzbl.gui.bar_v), ==, 17.5); /* scroll_horz behaves basically the same way. */ } -- cgit v1.2.3 From 0e0fba1fcf5372cf67d9dfa5d6817b2e225709d7 Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 10 Nov 2009 17:27:41 +0100 Subject: added mouse binding example to config --- examples/config/uzbl/config | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 32bb13c..090ebd2 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -108,11 +108,17 @@ set socket_dir = /tmp @modmap space Space -# === Keyboard bindings ====================================================== +# === Keyboard & Mouse bindings ====================================================== # With this command you can enter in any command at runtime when prefixed with # a colon. @bind :_ = chain '%s' + +# Middle click +# if clicked on a link open the link in a new uzbl window +# otherwise open the selection in the current window +@bind = sh 'if [ "\@SELECTED_URI" ]; then uzbl-browser -u \@SELECTED_URI; else echo "uri $(xclip -o)" > $4; fi' + @bind j = scroll vertical 20 @bind = scroll vertical 100% @bind k = scroll vertical -20 -- cgit v1.2.3 From ee46be0cc3dd981dcfe1ac1b13ab5b6c3194f841 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 11 Nov 2009 10:27:18 +0100 Subject: uniformize naming of helper python scripts --- Makefile | 18 +- examples/data/uzbl/scripts/cookie_daemon.py | 662 ----------- examples/data/uzbl/scripts/event_manager.py | 857 -------------- examples/data/uzbl/scripts/uzbl-cookie-daemon | 662 +++++++++++ examples/data/uzbl/scripts/uzbl-event-manager | 857 ++++++++++++++ examples/data/uzbl/scripts/uzbl-tabbed | 1474 +++++++++++++++++++++++++ examples/data/uzbl/scripts/uzbl_tabbed.py | 1474 ------------------------- uzbl-browser | 4 +- 8 files changed, 3003 insertions(+), 3005 deletions(-) delete mode 100755 examples/data/uzbl/scripts/cookie_daemon.py delete mode 100755 examples/data/uzbl/scripts/event_manager.py create mode 100755 examples/data/uzbl/scripts/uzbl-cookie-daemon create mode 100755 examples/data/uzbl/scripts/uzbl-event-manager create mode 100755 examples/data/uzbl/scripts/uzbl-tabbed delete mode 100755 examples/data/uzbl/scripts/uzbl_tabbed.py (limited to 'examples') diff --git a/Makefile b/Makefile index 93e70e8..b0cb868 100644 --- a/Makefile +++ b/Makefile @@ -62,11 +62,11 @@ test-dev: uzbl-core XDG_DATA_HOME=./examples/data XDG_CONFIG_HOME=./examples/config ./uzbl-core --uri http://www.uzbl.org --verbose test-dev-browser: uzbl-browser - XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py start -nv & - XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/event_manager.py start -nv & + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/uzbl-cookie-daemon start -nv & + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/uzbl-event-manager start -nv & XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:`pwd`/examples/data/uzbl/scripts/:$$PATH" ./uzbl-browser --uri http://www.uzbl.org --verbose - XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/cookie_daemon.py stop -v - XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/event_manager.py stop -v + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/uzbl-cookie-daemon stop -v + XDG_DATA_HOME=./examples/data XDG_CACHE_HOME=./examples/cache XDG_CONFIG_HOME=./examples/config PATH="`pwd`:$$PATH" ./examples/data/uzbl/scripts/uzbl-event-manager stop -v test-share: uzbl-core XDG_DATA_HOME=${INSTALLDIR}/share/uzbl/examples/data XDG_CONFIG_HOME=${INSTALLDIR}/share/uzbl/examples/config ./uzbl-core --uri http://www.uzbl.org --verbose @@ -98,17 +98,15 @@ install-uzbl-core: all install-uzbl-browser: all install -d $(INSTALLDIR)/bin install -m755 uzbl-browser $(INSTALLDIR)/bin/uzbl-browser - install -m755 examples/data/uzbl/scripts/cookie_daemon.py $(INSTALLDIR)/bin/cookie_daemon.py - install -m755 examples/data/uzbl/scripts/event_manager.py $(INSTALLDIR)/bin/event_manager.py + install -m755 examples/data/uzbl/scripts/uzbl-cookie-daemon $(INSTALLDIR)/bin/uzbl-cookie-daemon + install -m755 examples/data/uzbl/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager sed -i 's#^PREFIX=.*#PREFIX=$(PREFIX)#' $(INSTALLDIR)/bin/uzbl-browser - sed -i "s#^PREFIX = None#PREFIX = '$(PREFIX)'#" $(INSTALLDIR)/bin/event_manager.py + sed -i "s#^PREFIX = None#PREFIX = '$(PREFIX)'#" $(INSTALLDIR)/bin/uzbl-event-manager install-uzbl-tabbed: all install -d $(INSTALLDIR)/bin - install -m755 examples/data/uzbl/scripts/uzbl_tabbed.py $(INSTALLDIR)/bin/uzbl-tabbed + install -m755 examples/data/uzbl/scripts/uzbl-tabbed $(INSTALLDIR)/bin/uzbl-tabbed uninstall: rm -rf $(INSTALLDIR)/bin/uzbl-* - rm -rf $(INSTALLDIR)/bin/cookie_daemon.py - rm -rf $(INSTALLDIR)/bin/event_manager.py rm -rf $(INSTALLDIR)/share/uzbl diff --git a/examples/data/uzbl/scripts/cookie_daemon.py b/examples/data/uzbl/scripts/cookie_daemon.py deleted file mode 100755 index 87a2e87..0000000 --- a/examples/data/uzbl/scripts/cookie_daemon.py +++ /dev/null @@ -1,662 +0,0 @@ -#!/usr/bin/env python - -# The Python Cookie Daemon for Uzbl. -# Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, Dieter Plaetinck -# Copyright (c) 2009, Mason Larobina -# Copyright (c) 2009, Michael Fiano -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -''' -The Python Cookie Daemon -======================== - -This daemon is a re-write of the original cookies.py script found in uzbl's -master branch. This script provides more functionality than the original -cookies.py by adding numerous command line options to specify different cookie -jar locations, socket locations, verbose output, etc. This functionality is -very useful as it allows you to run multiple daemons at once serving cookies -to different groups of uzbl instances as required. - -Keeping up to date -================== - -Check the cookie daemon uzbl-wiki page for more information on where to -find the latest version of the cookie_daemon.py - - http://www.uzbl.org/wiki/cookie_daemon.py - -Command line options -==================== - -Use the following command to get a full list of the cookie_daemon.py command -line options: - - ./cookie_daemon.py --help - -Talking with uzbl -================= - -In order to get uzbl to talk to a running cookie daemon you add the following -to your uzbl config: - - set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket - -Or if you prefer using the $HOME variable: - - set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket - -Todo list -========= - - - Use a pid file to make force killing a running daemon possible. - -Reporting bugs / getting help -============================= - -The best way to report bugs and or get help with the cookie daemon is to -contact the maintainers it the #uzbl irc channel found on the Freenode IRC -network (irc.freenode.org). -''' - -import cookielib -import os -import sys -import urllib2 -import select -import socket -import time -import atexit -from traceback import print_exc -from signal import signal, SIGTERM -from optparse import OptionParser -from os.path import join - -try: - import cStringIO as StringIO - -except ImportError: - import StringIO - - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return join(os.environ['HOME'], default) - -# Setup xdg paths. -CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/') -DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/') -CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/') - -# Ensure data paths exist. -for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]: - if not os.path.exists(path): - os.makedirs(path) - -# Default config -config = { - - # Default cookie jar, whitelist, and daemon socket locations. - 'cookie_jar': join(DATA_DIR, 'cookies.txt'), - 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), - 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), - - # Don't use a cookie whitelist policy by default. - 'use_whitelist': False, - - # Time out after x seconds of inactivity (set to 0 for never time out). - # WARNING: Do not use this option if you are manually launching the daemon. - 'daemon_timeout': 0, - - # Daemonise by default. - 'daemon_mode': True, - - # Optionally print helpful debugging messages to the terminal. - 'verbose': False, - -} # End of config dictionary. - - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - - -_SCRIPTNAME = os.path.basename(sys.argv[0]) -def echo(msg): - '''Prints only if the verbose flag has been set.''' - - if config['verbose']: - sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) - - -def error(msg): - '''Prints error message and exits.''' - - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - sys.exit(1) - - -def mkbasedir(filepath): - '''Create the base directories of the file in the file-path if the dirs - don't exist.''' - - dirname = os.path.dirname(filepath) - if not os.path.exists(dirname): - echo("creating dirs: %r" % dirname) - os.makedirs(dirname) - - -def daemon_running(cookie_socket): - '''Check if another process (hopefully a cookie_daemon.py) is listening - on the cookie daemon socket. If another process is found to be - listening on the socket exit the daemon immediately and leave the - socket alone. If the connect fails assume the socket has been abandoned - and delete it (to be re-created in the create socket function).''' - - if not os.path.exists(cookie_socket): - return False - - if os.path.isfile(cookie_socket): - raise Exception("regular file at %r is not a socket" % cookie_socket) - - - if os.path.isdir(cookie_socket): - raise Exception("directory at %r is not a socket" % cookie_socket) - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(cookie_socket) - sock.close() - echo("detected daemon listening on %r" % cookie_socket) - return True - - except socket.error: - # Failed to connect to cookie_socket so assume it has been - # abandoned by another cookie daemon process. - if os.path.exists(cookie_socket): - echo("deleting abandoned socket at %r" % cookie_socket) - os.remove(cookie_socket) - - return False - - -def send_command(cookie_socket, cmd): - '''Send a command to a running cookie daemon.''' - - if not daemon_running(cookie_socket): - return False - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(cookie_socket) - sock.send(cmd) - sock.close() - echo("sent command %r to %r" % (cmd, cookie_socket)) - return True - - except socket.error: - print_exc() - error("failed to send message %r to %r" % (cmd, cookie_socket)) - return False - - -def kill_daemon(cookie_socket): - '''Send the "EXIT" command to running cookie_daemon.''' - - if send_command(cookie_socket, "EXIT"): - # Now ensure the cookie_socket is cleaned up. - start = time.time() - while os.path.exists(cookie_socket): - time.sleep(0.1) - if (time.time() - start) > 5: - error("force deleting socket %r" % cookie_socket) - os.remove(cookie_socket) - return - - echo("stopped daemon listening on %r"% cookie_socket) - - else: - if os.path.exists(cookie_socket): - os.remove(cookie_socket) - echo("removed abandoned/broken socket %r" % cookie_socket) - - -def daemonize(): - '''Daemonize the process using the Stevens' double-fork magic.''' - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #1 failed") - sys.exit(1) - - os.chdir('/') - os.setsid() - os.umask(0) - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #2 failed") - sys.exit(1) - - sys.stdout.flush() - sys.stderr.flush() - - devnull = '/dev/null' - stdin = file(devnull, 'r') - stdout = file(devnull, 'a+') - stderr = file(devnull, 'a+', 0) - - os.dup2(stdin.fileno(), sys.stdin.fileno()) - os.dup2(stdout.fileno(), sys.stdout.fileno()) - os.dup2(stderr.fileno(), sys.stderr.fileno()) - - -class CookieMonster: - '''The uzbl cookie daemon class.''' - - def __init__(self): - '''Initialise class variables.''' - - self.server_socket = None - self.jar = None - self.last_request = time.time() - self._running = False - - - def run(self): - '''Start the daemon.''' - - # The check healthy function will exit if another daemon is detected - # listening on the cookie socket and remove the abandoned socket if - # there isnt. - if os.path.exists(config['cookie_socket']): - if daemon_running(config['cookie_socket']): - sys.exit(1) - - # Daemonize process. - if config['daemon_mode']: - echo("entering daemon mode") - daemonize() - - # Register a function to cleanup on exit. - atexit.register(self.quit) - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - - # Create cookie jar object from file. - self.open_cookie_jar() - - # Create a way to exit nested loops by setting a running flag. - self._running = True - - while self._running: - # Create cookie daemon socket. - self.create_socket() - - try: - # Enter main listen loop. - self.listen() - - except KeyboardInterrupt: - self._running = False - print - - except socket.error: - print_exc() - - except: - # Clean up - self.del_socket() - - # Raise exception - raise - - # Always delete the socket before calling create again. - self.del_socket() - - - def load_whitelist(self): - '''Load the cookie jar whitelist policy.''' - - cookie_whitelist = config['cookie_whitelist'] - - if cookie_whitelist: - mkbasedir(cookie_whitelist) - - # Create cookie whitelist file if it does not exist. - if not os.path.exists(cookie_whitelist): - open(cookie_whitelist, 'w').close() - - # Read cookie whitelist file into list. - file = open(cookie_whitelist,'r') - domain_list = [line.rstrip('\n') for line in file] - file.close() - - # Define policy of allowed domains - policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) - self.jar.set_policy(policy) - - # Save the last modified time of the whitelist. - self._whitelistmtime = os.stat(cookie_whitelist).st_mtime - - - def open_cookie_jar(self): - '''Open the cookie jar.''' - - cookie_jar = config['cookie_jar'] - cookie_whitelist = config['cookie_whitelist'] - - if cookie_jar: - mkbasedir(cookie_jar) - - # Create cookie jar object from file. - self.jar = cookielib.MozillaCookieJar(cookie_jar) - - # Load cookie whitelist policy. - if config['use_whitelist']: - self.load_whitelist() - - if cookie_jar: - try: - # Attempt to load cookies from the cookie jar. - self.jar.load(ignore_discard=True) - - # Ensure restrictive permissions are set on the cookie jar - # to prevent other users on the system from hi-jacking your - # authenticated sessions simply by copying your cookie jar. - os.chmod(cookie_jar, 0600) - - except: - pass - - - def reload_whitelist(self): - '''Reload the cookie whitelist.''' - - cookie_whitelist = config['cookie_whitelist'] - if os.path.exists(cookie_whitelist): - echo("reloading whitelist %r" % cookie_whitelist) - self.open_cookie_jar() - - - def create_socket(self): - '''Create AF_UNIX socket for communication with uzbl instances.''' - - cookie_socket = config['cookie_socket'] - mkbasedir(cookie_socket) - - self.server_socket = socket.socket(socket.AF_UNIX, - socket.SOCK_SEQPACKET) - - self.server_socket.bind(cookie_socket) - - # Set restrictive permissions on the cookie socket to prevent other - # users on the system from data-mining your cookies. - os.chmod(cookie_socket, 0600) - - - def listen(self): - '''Listen for incoming cookie PUT and GET requests.''' - - daemon_timeout = config['daemon_timeout'] - echo("listening on %r" % config['cookie_socket']) - - while self._running: - # This line tells the socket how many pending incoming connections - # to enqueue at once. Raising this number may or may not increase - # performance. - self.server_socket.listen(1) - - if bool(select.select([self.server_socket], [], [], 1)[0]): - client_socket, _ = self.server_socket.accept() - self.handle_request(client_socket) - self.last_request = time.time() - client_socket.close() - continue - - if daemon_timeout: - # Checks if the daemon has been idling for too long. - idle = time.time() - self.last_request - if idle > daemon_timeout: - self._running = False - - - def handle_request(self, client_socket): - '''Connection made, now to serve a cookie PUT or GET request.''' - - # Receive cookie request from client. - data = client_socket.recv(8192) - if not data: - return - - # Cookie argument list in packet is null separated. - argv = data.split("\0") - action = argv[0].upper().strip() - - # Catch the EXIT command sent to kill running daemons. - if action == "EXIT": - self._running = False - return - - # Catch whitelist RELOAD command. - elif action == "RELOAD": - self.reload_whitelist() - return - - # Return if command unknown. - elif action not in ['GET', 'PUT']: - error("unknown command %r." % argv) - return - - # Determine whether or not to print cookie data to terminal. - print_cookie = (config['verbose'] and not config['daemon_mode']) - if print_cookie: - print ' '.join(argv[:4]) - - uri = urllib2.urlparse.ParseResult( - scheme=argv[1], - netloc=argv[2], - path=argv[3], - params='', - query='', - fragment='').geturl() - - req = urllib2.Request(uri) - - if action == "GET": - self.jar.add_cookie_header(req) - if req.has_header('Cookie'): - cookie = req.get_header('Cookie') - client_socket.send(cookie) - if print_cookie: - print cookie - - else: - client_socket.send("\0") - - elif action == "PUT": - cookie = argv[4] if len(argv) > 3 else None - if print_cookie: - print cookie - - self.put_cookie(req, cookie) - - if print_cookie: - print - - - def put_cookie(self, req, cookie=None): - '''Put a cookie in the cookie jar.''' - - hdr = urllib2.httplib.HTTPMessage(\ - StringIO.StringIO('Set-Cookie: %s' % cookie)) - res = urllib2.addinfourl(StringIO.StringIO(), hdr, - req.get_full_url()) - self.jar.extract_cookies(res, req) - if config['cookie_jar']: - self.jar.save(ignore_discard=True) - - - def del_socket(self): - '''Remove the cookie_socket file on exit. In a way the cookie_socket - is the daemons pid file equivalent.''' - - if self.server_socket: - try: - self.server_socket.close() - - except: - pass - - self.server_socket = None - - cookie_socket = config['cookie_socket'] - if os.path.exists(cookie_socket): - echo("deleting socket %r" % cookie_socket) - os.remove(cookie_socket) - - - def quit(self): - '''Called on exit to make sure all loose ends are tied up.''' - - self.del_socket() - sys.exit(0) - - -def main(): - '''Main function.''' - - # Define command line parameters. - usage = "usage: %prog [options] {start|stop|restart|reload}" - parser = OptionParser(usage=usage) - parser.add_option('-n', '--no-daemon', dest='no_daemon', - action='store_true', help="don't daemonise the process.") - - parser.add_option('-v', '--verbose', dest="verbose", - action='store_true', help="print verbose output.") - - parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout', - action="store", metavar="SECONDS", help="shutdown the daemon after x "\ - "seconds inactivity. WARNING: Do not use this when launching the "\ - "cookie daemon manually.") - - parser.add_option('-s', '--cookie-socket', dest="cookie_socket", - metavar="SOCKET", help="manually specify the socket location.") - - parser.add_option('-j', '--cookie-jar', dest='cookie_jar', - metavar="FILE", help="manually specify the cookie jar location.") - - parser.add_option('-m', '--memory', dest='memory', action='store_true', - help="store cookies in memory only - do not write to disk") - - parser.add_option('-u', '--use-whitelist', dest='usewhitelist', - action='store_true', help="use cookie whitelist policy") - - parser.add_option('-w', '--cookie-whitelist', dest='whitelist', - action='store', help="manually specify whitelist location", - metavar='FILE') - - # Parse the command line arguments. - (options, args) = parser.parse_args() - - expand = lambda p: os.path.realpath(os.path.expandvars(p)) - - initcommands = ['start', 'stop', 'restart', 'reload'] - for arg in args: - if arg not in initcommands: - error("unknown argument %r" % args[0]) - sys.exit(1) - - if len(args) > 1: - error("the daemon only accepts one {%s} action at a time." - % '|'.join(initcommands)) - sys.exit(1) - - if len(args): - action = args[0] - - else: - action = "start" - - if options.no_daemon: - config['daemon_mode'] = False - - if options.cookie_socket: - config['cookie_socket'] = expand(options.cookie_socket) - - if options.cookie_jar: - config['cookie_jar'] = expand(options.cookie_jar) - - if options.memory: - config['cookie_jar'] = None - - if options.whitelist: - config['cookie_whitelist'] = expand(options.whitelist) - - if options.whitelist or options.usewhitelist: - config['use_whitelist'] = True - - if options.daemon_timeout: - try: - config['daemon_timeout'] = int(options.daemon_timeout) - - except ValueError: - error("expected int argument for -t, --daemon-timeout") - - # Expand $VAR's in config keys that relate to paths. - for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']: - if config[key]: - config[key] = os.path.expandvars(config[key]) - - if options.verbose: - config['verbose'] = True - import pprint - sys.stderr.write("%s\n" % pprint.pformat(config)) - - # It would be better if we didn't need to start this python process just - # to send a command to the socket, but unfortunately socat doesn't seem - # to support SEQPACKET. - if action == "reload": - send_command(config['cookie_socket'], "RELOAD") - - if action in ['stop', 'restart']: - kill_daemon(config['cookie_socket']) - - if action in ['start', 'restart']: - CookieMonster().run() - - -if __name__ == "__main__": - main() diff --git a/examples/data/uzbl/scripts/event_manager.py b/examples/data/uzbl/scripts/event_manager.py deleted file mode 100755 index dee42c5..0000000 --- a/examples/data/uzbl/scripts/event_manager.py +++ /dev/null @@ -1,857 +0,0 @@ -#!/usr/bin/env python - -# Event Manager for Uzbl -# Copyright (c) 2009, Mason Larobina -# Copyright (c) 2009, Dieter Plaetinck -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -''' - -E V E N T _ M A N A G E R . P Y -=============================== - -Event manager for uzbl written in python. - -''' - -import imp -import os -import sys -import re -import types -import socket -import pprint -import time -import atexit -from select import select -from signal import signal, SIGTERM -from optparse import OptionParser -from traceback import print_exc - - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -# Automagically set during `make install` -PREFIX = None - -# Check if PREFIX not set and set to default /usr/local/ -if not PREFIX: - PREFIX = '/usr/local/' - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return os.path.join(os.environ['HOME'], default) - -# Setup xdg paths. -DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') -CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') - - -# Config dict (NOT the same as the uzbl.config). -config = { - 'verbose': False, - 'daemon_mode': True, - 'auto_close': False, - - 'plugins_load': [], - 'plugins_ignore': [], - - 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), - os.path.join(PREFIX, 'share/uzbl/examples/data/uzbl/plugins/')], - - 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), - 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), -} - - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - - -# Define some globals. -_SCRIPTNAME = os.path.basename(sys.argv[0]) -_RE_FINDSPACES = re.compile("\s+") - -def echo(msg): - '''Prints only if the verbose flag has been set.''' - - if config['verbose']: - sys.stdout.write("%s: %s\n" % (_SCRIPTNAME, msg)) - - -def error(msg): - '''Prints error messages to stderr.''' - - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - - -def counter(): - '''Generate unique object id's.''' - - i = 0 - while True: - i += 1 - yield i - - -def iscallable(obj): - '''Return true if the object is callable.''' - - return hasattr(obj, "__call__") - - -def isiterable(obj): - '''Return true if you can iterate over the item.''' - - return hasattr(obj, "__iter__") - - -def find_plugins(plugin_dirs): - '''Find all event manager plugins in the plugin dirs and return a - dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' - - plugins = {} - - for plugin_dir in plugin_dirs: - plugin_dir = os.path.realpath(os.path.expandvars(plugin_dir)) - if not os.path.isdir(plugin_dir): - continue - - for file in os.listdir(plugin_dir): - if not file.lower().endswith('.py'): - continue - - path = os.path.join(plugin_dir, file) - if not os.path.isfile(path): - continue - - if file not in plugins: - plugins[file] = plugin_dir - - return plugins - - -def load_plugins(plugin_dirs, load=[], ignore=[]): - '''Load event manager plugins found in the plugin_dirs.''' - - # Find the plugins in the plugin_dirs. - found = find_plugins(plugin_dirs) - - if load: - # Ignore anything not in the load list. - for plugin in found.keys(): - if plugin not in load: - del found[plugin] - - if ignore: - # Ignore anything in the ignore list. - for plugin in found.keys(): - if plugin in ignore: - del found[plugin] - - # Print plugin list to be loaded. - pprint.pprint(found) - - loaded = {} - # Load all found plugins into the loaded dict. - for (filename, dir) in found.items(): - name = filename[:-3] - info = imp.find_module(name, [dir,]) - plugin = imp.load_module(name, *info) - loaded[(dir, filename)] = plugin - - return loaded - - -def daemonize(): - '''Daemonize the process using the Stevens' double-fork magic.''' - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #1 failed") - sys.exit(1) - - os.chdir('/') - os.setsid() - os.umask(0) - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #2 failed") - sys.exit(1) - - sys.stdout.flush() - sys.stderr.flush() - - devnull = '/dev/null' - stdin = file(devnull, 'r') - stdout = file(devnull, 'a+') - stderr = file(devnull, 'a+', 0) - - os.dup2(stdin.fileno(), sys.stdin.fileno()) - os.dup2(stdout.fileno(), sys.stdout.fileno()) - os.dup2(stderr.fileno(), sys.stderr.fileno()) - - -def make_dirs(path): - '''Make all basedirs recursively as required.''' - - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - - -def make_pid_file(pid_file): - '''Make pid file at given pid_file location.''' - - make_dirs(pid_file) - file = open(pid_file, 'w') - file.write('%d' % os.getpid()) - file.close() - - -def del_pid_file(pid_file): - '''Delete pid file at given pid_file location.''' - - if os.path.isfile(pid_file): - os.remove(pid_file) - - -def get_pid(pid_file): - '''Read pid from pid_file.''' - - try: - file = open(pid_file, 'r') - strpid = file.read() - file.close() - pid = int(strpid.strip()) - return pid - - except: - print_exc() - return None - - -def pid_running(pid): - '''Returns True if a process with the given pid is running.''' - - try: - os.kill(pid, 0) - - except OSError: - return False - - else: - return True - - -def term_process(pid): - '''Send a SIGTERM signal to the process with the given pid.''' - - if not pid_running(pid): - return False - - os.kill(pid, SIGTERM) - - start = time.time() - while True: - if not pid_running(pid): - return True - - if time.time() - start > 5: - raise OSError('failed to stop process with pid: %d' % pid) - - time.sleep(0.25) - - -def prepender(function, *pre_args): - '''Creates a wrapper around a callable object injecting a list of - arguments before the called arguments.''' - - locals = (function, pre_args) - def _prepender(*args, **kargs): - (function, pre_args) = locals - return function(*(pre_args + args), **kargs) - - return _prepender - - -class EventHandler(object): - - nexthid = counter().next - - def __init__(self, event, handler, *args, **kargs): - if not iscallable(handler): - raise ArgumentError("EventHandler object requires a callable " - "object function for the handler argument not: %r" % handler) - - self.function = handler - self.args = args - self.kargs = kargs - self.event = event - self.hid = self.nexthid() - - - def __repr__(self): - args = ["event=%s" % self.event, "hid=%d" % self.hid, - "function=%r" % self.function] - - if self.args: - args.append("args=%r" % self.args) - - if self.kargs: - args.append("kargs=%r" % self.kargs) - - return "" % ', '.join(args) - - -class UzblInstance(object): - def __init__(self, parent, client_socket): - - # Internal variables. - self._exports = {} - self._handlers = {} - self._parent = parent - self._client_socket = client_socket - - self.buffer = '' - - # Call the init() function in every plugin. Inside the init function - # is where the plugins insert the hooks into the event system. - self._init_plugins() - - - def __getattribute__(self, attr): - '''Expose any exported functions before class functions.''' - - if not attr.startswith('_'): - exports = object.__getattribute__(self, '_exports') - if attr in exports: - return exports[attr] - - return object.__getattribute__(self, attr) - - - def _init_plugins(self): - '''Call the init() function in every plugin and expose all exposable - functions in the plugins root namespace.''' - - plugins = self._parent['plugins'] - - # Map all plugin exports - for (name, plugin) in plugins.items(): - if not hasattr(plugin, '__export__'): - continue - - for export in plugin.__export__: - if export in self._exports: - raise KeyError("conflicting export: %r" % export) - - obj = getattr(plugin, export) - if iscallable(obj): - obj = prepender(obj, self) - - self._exports[export] = obj - - echo("exposed attribute(s): %s" % ', '.join(self._exports.keys())) - - # Now call the init function in all plugins. - for (name, plugin) in plugins.items(): - try: - plugin.init(self) - - except: - #print_exc() - raise - - - def send(self, msg): - '''Send a command to the uzbl instance via the socket file.''' - - if self._client_socket: - print '<-- %s' % msg - self._client_socket.send(("%s\n" % msg).encode('utf-8')) - - else: - print '!-- %s' % msg - - - def connect(self, event, handler, *args, **kargs): - '''Connect event with handler and return the newly created handler. - Handlers can either be a function or a uzbl command string.''' - - if event not in self._handlers.keys(): - self._handlers[event] = [] - - handlerobj = EventHandler(event, handler, *args, **kargs) - self._handlers[event].append(handlerobj) - print handlerobj - - - def connect_dict(self, connect_dict): - '''Connect a dictionary comprising of {"EVENT_NAME": handler, ..} to - the event handler stack. - - If you need to supply args or kargs to an event use the normal connect - function.''' - - for (event, handler) in connect_dict.items(): - self.connect(event, handler) - - - def remove_by_id(self, hid): - '''Remove connected event handler by unique handler id.''' - - for (event, handlers) in self._handlers.items(): - for handler in list(handlers): - if hid != handler.hid: - continue - - echo("removed %r" % handler) - handlers.remove(handler) - return - - echo('unable to find & remove handler with id: %d' % handler.hid) - - - def remove(self, handler): - '''Remove connected event handler.''' - - for (event, handlers) in self._handlers.items(): - if handler in handlers: - echo("removed %r" % handler) - handlers.remove(handler) - return - - echo('unable to find & remove handler: %r' % handler) - - - def exec_handler(self, handler, *args, **kargs): - '''Execute event handler function.''' - - args += handler.args - kargs = dict(handler.kargs.items()+kargs.items()) - handler.function(self, *args, **kargs) - - - def event(self, event, *args, **kargs): - '''Raise a custom event.''' - - # Silence _printing_ of geo events while debugging. - if event != "GEOMETRY_CHANGED": - print "--> %s %s %s" % (event, args, '' if not kargs else kargs) - - if event not in self._handlers: - return - - for handler in self._handlers[event]: - try: - self.exec_handler(handler, *args, **kargs) - - except: - print_exc() - - - def close(self): - '''Close the client socket and clean up.''' - - try: - self._client_socket.close() - - except: - pass - - for (name, plugin) in self._parent['plugins'].items(): - if hasattr(plugin, 'cleanup'): - plugin.cleanup(self) - - del self._exports - del self._handlers - del self._client_socket - - -class UzblEventDaemon(dict): - def __init__(self): - - # Init variables and dict keys. - dict.__init__(self, {'uzbls': {}}) - self.running = None - self.server_socket = None - self.socket_location = None - - # Register that the event daemon server has started by creating the - # pid file. - make_pid_file(config['pid_file']) - - # Register a function to clean up the socket and pid file on exit. - atexit.register(self.quit) - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - - # Load plugins, first-build of the plugins may be a costly operation. - self['plugins'] = load_plugins(config['plugin_dirs'], - config['plugins_load'], config['plugins_ignore']) - - - def _create_server_socket(self): - '''Create the event manager daemon socket for uzbl instance duplex - communication.''' - - server_socket = config['server_socket'] - server_socket = os.path.realpath(os.path.expandvars(server_socket)) - self.socket_location = server_socket - - # Delete socket if it exists. - if os.path.exists(server_socket): - os.remove(server_socket) - - self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.server_socket.bind(server_socket) - self.server_socket.listen(5) - - - def _close_server_socket(self): - '''Close and delete the server socket.''' - - try: - self.server_socket.close() - self.server_socket = None - - if os.path.exists(self.socket_location): - os.remove(self.socket_location) - - except: - pass - - - def run(self): - '''Main event daemon loop.''' - - if config['daemon_mode']: - echo('entering daemon mode.') - daemonize() - # The pid has changed so update the pid file. - make_pid_file(config['pid_file']) - - # Create event daemon socket. - self._create_server_socket() - echo('listening on: %s' % self.socket_location) - - # Now listen for incoming connections and or data. - self.listen() - - # Clean up. - self.quit() - - - def listen(self): - '''Accept incoming connections and constantly poll instance sockets - for incoming data.''' - - self.running = True - while self.running: - - sockets = [self.server_socket,] + self['uzbls'].keys() - - read, _, error = select(sockets, [], sockets, 1) - - if self.server_socket in read: - self.accept_connection() - read.remove(self.server_socket) - - for client in read: - self.read_socket(client) - - for client in error: - error('Unknown error on socket: %r' % client) - self.close_connection(client) - - - def read_socket(self, client): - '''Read data from an instance socket and pass to the uzbl objects - event handler function.''' - - try: - uzbl = self['uzbls'][client] - try: - raw = unicode(client.recv(8192), 'utf-8', 'ignore') - - except: - print_exc() - raw = None - - if not raw: - # Read null byte, close socket. - return self.close_connection(client) - - uzbl.buffer += raw - msgs = uzbl.buffer.split('\n') - uzbl.buffer = msgs.pop() - - for msg in msgs: - self.parse_msg(uzbl, msg) - - except: - raise - - - def parse_msg(self, uzbl, msg): - '''Parse an incoming msg from a uzbl instance. All non-event messages - will be printed here and not be passed to the uzbl instance event - handler function.''' - - msg = msg.strip() - if not msg: - return - - cmd = _RE_FINDSPACES.split(msg, 3) - if not cmd or cmd[0] != 'EVENT': - # Not an event message. - print '---', msg - return - - if len(cmd) < 4: - cmd.append('') - - event, args = cmd[2], cmd[3] - - try: - uzbl.event(event, args) - - except: - print_exc() - - - def accept_connection(self): - '''Accept incoming connection to the server socket.''' - - client_socket = self.server_socket.accept()[0] - - uzbl = UzblInstance(self, client_socket) - self['uzbls'][client_socket] = uzbl - - - def close_connection(self, client): - '''Clean up after instance close.''' - - try: - if client in self['uzbls']: - uzbl = self['uzbls'][client] - uzbl.close() - del self['uzbls'][client] - - except: - print_exc() - - if not len(self['uzbls']) and config['auto_close']: - echo('auto closing event manager.') - self.running = False - - - def quit(self): - '''Close all instance socket objects, server socket and delete the - pid file.''' - - echo('shutting down event manager.') - - for client in self['uzbls'].keys(): - self.close_connection(client) - - echo('unlinking: %r' % self.socket_location) - self._close_server_socket() - - echo('deleting pid file: %r' % config['pid_file']) - del_pid_file(config['pid_file']) - - -def stop(): - '''Stop the event manager daemon.''' - - pid_file = config['pid_file'] - if not os.path.isfile(pid_file): - return echo('no running daemon found.') - - echo('found pid file: %r' % pid_file) - pid = get_pid(pid_file) - if not pid_running(pid): - echo('no process with pid: %d' % pid) - return os.remove(pid_file) - - echo("terminating process with pid: %d" % pid) - term_process(pid) - if os.path.isfile(pid_file): - os.remove(pid_file) - - echo('stopped event daemon.') - - -def start(): - '''Start the event manager daemon.''' - - pid_file = config['pid_file'] - if os.path.isfile(pid_file): - echo('found pid file: %r' % pid_file) - pid = get_pid(pid_file) - if pid_running(pid): - return echo('event daemon already started with pid: %d' % pid) - - echo('no process with pid: %d' % pid) - os.remove(pid_file) - - echo('starting event manager.') - UzblEventDaemon().run() - - -def restart(): - '''Restart the event manager daemon.''' - - echo('restarting event manager daemon.') - stop() - start() - - -def list_plugins(): - '''List all the plugins being loaded by the event daemon.''' - - plugins = find_plugins(config['plugin_dirs']) - dirs = {} - - for (plugin, dir) in plugins.items(): - if dir not in dirs: - dirs[dir] = [] - - dirs[dir].append(plugin) - - for (index, (dir, plugin_list)) in enumerate(sorted(dirs.items())): - if index: - print - - print "%s:" % dir - for plugin in sorted(plugin_list): - print " %s" % plugin - - -if __name__ == "__main__": - usage = "usage: %prog [options] {start|stop|restart|list}" - parser = OptionParser(usage=usage) - parser.add_option('-v', '--verbose', dest='verbose', action="store_true", - help="print verbose output.") - - parser.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", - metavar="DIRS", help="Specify plugin directories in the form of "\ - "'dir1:dir2:dir3'.") - - parser.add_option('-l', '--load-plugins', dest="load", action="store", - metavar="PLUGINS", help="comma separated list of plugins to load") - - parser.add_option('-i', '--ignore-plugins', dest="ignore", action="store", - metavar="PLUGINS", help="comma separated list of plugins to ignore") - - parser.add_option('-p', '--pid-file', dest='pid', action='store', - metavar='FILE', help="specify pid file location") - - parser.add_option('-s', '--server-socket', dest='socket', action='store', - metavar='SOCKET', help="specify the daemon socket location") - - parser.add_option('-n', '--no-daemon', dest="daemon", - action="store_true", help="don't enter daemon mode.") - - parser.add_option('-a', '--auto-close', dest='autoclose', - action='store_true', help='auto close after all instances disconnect.') - - (options, args) = parser.parse_args() - - # init like {start|stop|..} daemon control section. - daemon_controls = {'start': start, 'stop': stop, 'restart': restart, - 'list': list_plugins} - - if len(args) == 1: - action = args[0] - if action not in daemon_controls: - error('unknown action: %r' % action) - sys.exit(1) - - elif len(args) > 1: - error("too many arguments: %r" % args) - sys.exit(1) - - else: - action = 'start' - - # parse other flags & options. - if options.verbose: - config['verbose'] = True - - if options.plugin_dirs: - plugin_dirs = map(os.path.realpath, map(str.strip, - options.plugin_dirs.split(':'))) - config['plugin_dirs'] = plugin_dirs - echo("plugin search dirs: %r" % plugin_dirs) - - if options.load and options.ignore: - error("you can't load and ignore at the same time.") - sys.exit(1) - - elif options.load: - plugins_load = config['plugins_load'] - for plugin in options.load.split(','): - if plugin.strip(): - plugins_load.append(plugin.strip()) - - echo('only loading plugin(s): %s' % ', '.join(plugins_load)) - - elif options.ignore: - plugins_ignore = config['plugins_ignore'] - for plugin in options.ignore.split(','): - if plugin.strip(): - plugins_ignore.append(plugin.strip()) - - echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) - - if options.autoclose: - config['auto_close'] = True - echo('will auto close.') - - if options.pid: - config['pid_file'] = os.path.realpath(options.pid) - echo("pid file location: %r" % config['pid_file']) - - if options.socket: - config['server_socket'] = os.path.realpath(options.socket) - echo("daemon socket location: %s" % config['server_socket']) - - if options.daemon: - config['daemon_mode'] = False - - # Now {start|stop|...} - daemon_controls[action]() diff --git a/examples/data/uzbl/scripts/uzbl-cookie-daemon b/examples/data/uzbl/scripts/uzbl-cookie-daemon new file mode 100755 index 0000000..87a2e87 --- /dev/null +++ b/examples/data/uzbl/scripts/uzbl-cookie-daemon @@ -0,0 +1,662 @@ +#!/usr/bin/env python + +# The Python Cookie Daemon for Uzbl. +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, Dieter Plaetinck +# Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Michael Fiano +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +''' +The Python Cookie Daemon +======================== + +This daemon is a re-write of the original cookies.py script found in uzbl's +master branch. This script provides more functionality than the original +cookies.py by adding numerous command line options to specify different cookie +jar locations, socket locations, verbose output, etc. This functionality is +very useful as it allows you to run multiple daemons at once serving cookies +to different groups of uzbl instances as required. + +Keeping up to date +================== + +Check the cookie daemon uzbl-wiki page for more information on where to +find the latest version of the cookie_daemon.py + + http://www.uzbl.org/wiki/cookie_daemon.py + +Command line options +==================== + +Use the following command to get a full list of the cookie_daemon.py command +line options: + + ./cookie_daemon.py --help + +Talking with uzbl +================= + +In order to get uzbl to talk to a running cookie daemon you add the following +to your uzbl config: + + set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket + +Or if you prefer using the $HOME variable: + + set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket + +Todo list +========= + + - Use a pid file to make force killing a running daemon possible. + +Reporting bugs / getting help +============================= + +The best way to report bugs and or get help with the cookie daemon is to +contact the maintainers it the #uzbl irc channel found on the Freenode IRC +network (irc.freenode.org). +''' + +import cookielib +import os +import sys +import urllib2 +import select +import socket +import time +import atexit +from traceback import print_exc +from signal import signal, SIGTERM +from optparse import OptionParser +from os.path import join + +try: + import cStringIO as StringIO + +except ImportError: + import StringIO + + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return join(os.environ['HOME'], default) + +# Setup xdg paths. +CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/') +DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/') +CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/') + +# Ensure data paths exist. +for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]: + if not os.path.exists(path): + os.makedirs(path) + +# Default config +config = { + + # Default cookie jar, whitelist, and daemon socket locations. + 'cookie_jar': join(DATA_DIR, 'cookies.txt'), + 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), + 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), + + # Don't use a cookie whitelist policy by default. + 'use_whitelist': False, + + # Time out after x seconds of inactivity (set to 0 for never time out). + # WARNING: Do not use this option if you are manually launching the daemon. + 'daemon_timeout': 0, + + # Daemonise by default. + 'daemon_mode': True, + + # Optionally print helpful debugging messages to the terminal. + 'verbose': False, + +} # End of config dictionary. + + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +_SCRIPTNAME = os.path.basename(sys.argv[0]) +def echo(msg): + '''Prints only if the verbose flag has been set.''' + + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error message and exits.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + sys.exit(1) + + +def mkbasedir(filepath): + '''Create the base directories of the file in the file-path if the dirs + don't exist.''' + + dirname = os.path.dirname(filepath) + if not os.path.exists(dirname): + echo("creating dirs: %r" % dirname) + os.makedirs(dirname) + + +def daemon_running(cookie_socket): + '''Check if another process (hopefully a cookie_daemon.py) is listening + on the cookie daemon socket. If another process is found to be + listening on the socket exit the daemon immediately and leave the + socket alone. If the connect fails assume the socket has been abandoned + and delete it (to be re-created in the create socket function).''' + + if not os.path.exists(cookie_socket): + return False + + if os.path.isfile(cookie_socket): + raise Exception("regular file at %r is not a socket" % cookie_socket) + + + if os.path.isdir(cookie_socket): + raise Exception("directory at %r is not a socket" % cookie_socket) + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.close() + echo("detected daemon listening on %r" % cookie_socket) + return True + + except socket.error: + # Failed to connect to cookie_socket so assume it has been + # abandoned by another cookie daemon process. + if os.path.exists(cookie_socket): + echo("deleting abandoned socket at %r" % cookie_socket) + os.remove(cookie_socket) + + return False + + +def send_command(cookie_socket, cmd): + '''Send a command to a running cookie daemon.''' + + if not daemon_running(cookie_socket): + return False + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.send(cmd) + sock.close() + echo("sent command %r to %r" % (cmd, cookie_socket)) + return True + + except socket.error: + print_exc() + error("failed to send message %r to %r" % (cmd, cookie_socket)) + return False + + +def kill_daemon(cookie_socket): + '''Send the "EXIT" command to running cookie_daemon.''' + + if send_command(cookie_socket, "EXIT"): + # Now ensure the cookie_socket is cleaned up. + start = time.time() + while os.path.exists(cookie_socket): + time.sleep(0.1) + if (time.time() - start) > 5: + error("force deleting socket %r" % cookie_socket) + os.remove(cookie_socket) + return + + echo("stopped daemon listening on %r"% cookie_socket) + + else: + if os.path.exists(cookie_socket): + os.remove(cookie_socket) + echo("removed abandoned/broken socket %r" % cookie_socket) + + +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + +class CookieMonster: + '''The uzbl cookie daemon class.''' + + def __init__(self): + '''Initialise class variables.''' + + self.server_socket = None + self.jar = None + self.last_request = time.time() + self._running = False + + + def run(self): + '''Start the daemon.''' + + # The check healthy function will exit if another daemon is detected + # listening on the cookie socket and remove the abandoned socket if + # there isnt. + if os.path.exists(config['cookie_socket']): + if daemon_running(config['cookie_socket']): + sys.exit(1) + + # Daemonize process. + if config['daemon_mode']: + echo("entering daemon mode") + daemonize() + + # Register a function to cleanup on exit. + atexit.register(self.quit) + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + # Create cookie jar object from file. + self.open_cookie_jar() + + # Create a way to exit nested loops by setting a running flag. + self._running = True + + while self._running: + # Create cookie daemon socket. + self.create_socket() + + try: + # Enter main listen loop. + self.listen() + + except KeyboardInterrupt: + self._running = False + print + + except socket.error: + print_exc() + + except: + # Clean up + self.del_socket() + + # Raise exception + raise + + # Always delete the socket before calling create again. + self.del_socket() + + + def load_whitelist(self): + '''Load the cookie jar whitelist policy.''' + + cookie_whitelist = config['cookie_whitelist'] + + if cookie_whitelist: + mkbasedir(cookie_whitelist) + + # Create cookie whitelist file if it does not exist. + if not os.path.exists(cookie_whitelist): + open(cookie_whitelist, 'w').close() + + # Read cookie whitelist file into list. + file = open(cookie_whitelist,'r') + domain_list = [line.rstrip('\n') for line in file] + file.close() + + # Define policy of allowed domains + policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) + self.jar.set_policy(policy) + + # Save the last modified time of the whitelist. + self._whitelistmtime = os.stat(cookie_whitelist).st_mtime + + + def open_cookie_jar(self): + '''Open the cookie jar.''' + + cookie_jar = config['cookie_jar'] + cookie_whitelist = config['cookie_whitelist'] + + if cookie_jar: + mkbasedir(cookie_jar) + + # Create cookie jar object from file. + self.jar = cookielib.MozillaCookieJar(cookie_jar) + + # Load cookie whitelist policy. + if config['use_whitelist']: + self.load_whitelist() + + if cookie_jar: + try: + # Attempt to load cookies from the cookie jar. + self.jar.load(ignore_discard=True) + + # Ensure restrictive permissions are set on the cookie jar + # to prevent other users on the system from hi-jacking your + # authenticated sessions simply by copying your cookie jar. + os.chmod(cookie_jar, 0600) + + except: + pass + + + def reload_whitelist(self): + '''Reload the cookie whitelist.''' + + cookie_whitelist = config['cookie_whitelist'] + if os.path.exists(cookie_whitelist): + echo("reloading whitelist %r" % cookie_whitelist) + self.open_cookie_jar() + + + def create_socket(self): + '''Create AF_UNIX socket for communication with uzbl instances.''' + + cookie_socket = config['cookie_socket'] + mkbasedir(cookie_socket) + + self.server_socket = socket.socket(socket.AF_UNIX, + socket.SOCK_SEQPACKET) + + self.server_socket.bind(cookie_socket) + + # Set restrictive permissions on the cookie socket to prevent other + # users on the system from data-mining your cookies. + os.chmod(cookie_socket, 0600) + + + def listen(self): + '''Listen for incoming cookie PUT and GET requests.''' + + daemon_timeout = config['daemon_timeout'] + echo("listening on %r" % config['cookie_socket']) + + while self._running: + # This line tells the socket how many pending incoming connections + # to enqueue at once. Raising this number may or may not increase + # performance. + self.server_socket.listen(1) + + if bool(select.select([self.server_socket], [], [], 1)[0]): + client_socket, _ = self.server_socket.accept() + self.handle_request(client_socket) + self.last_request = time.time() + client_socket.close() + continue + + if daemon_timeout: + # Checks if the daemon has been idling for too long. + idle = time.time() - self.last_request + if idle > daemon_timeout: + self._running = False + + + def handle_request(self, client_socket): + '''Connection made, now to serve a cookie PUT or GET request.''' + + # Receive cookie request from client. + data = client_socket.recv(8192) + if not data: + return + + # Cookie argument list in packet is null separated. + argv = data.split("\0") + action = argv[0].upper().strip() + + # Catch the EXIT command sent to kill running daemons. + if action == "EXIT": + self._running = False + return + + # Catch whitelist RELOAD command. + elif action == "RELOAD": + self.reload_whitelist() + return + + # Return if command unknown. + elif action not in ['GET', 'PUT']: + error("unknown command %r." % argv) + return + + # Determine whether or not to print cookie data to terminal. + print_cookie = (config['verbose'] and not config['daemon_mode']) + if print_cookie: + print ' '.join(argv[:4]) + + uri = urllib2.urlparse.ParseResult( + scheme=argv[1], + netloc=argv[2], + path=argv[3], + params='', + query='', + fragment='').geturl() + + req = urllib2.Request(uri) + + if action == "GET": + self.jar.add_cookie_header(req) + if req.has_header('Cookie'): + cookie = req.get_header('Cookie') + client_socket.send(cookie) + if print_cookie: + print cookie + + else: + client_socket.send("\0") + + elif action == "PUT": + cookie = argv[4] if len(argv) > 3 else None + if print_cookie: + print cookie + + self.put_cookie(req, cookie) + + if print_cookie: + print + + + def put_cookie(self, req, cookie=None): + '''Put a cookie in the cookie jar.''' + + hdr = urllib2.httplib.HTTPMessage(\ + StringIO.StringIO('Set-Cookie: %s' % cookie)) + res = urllib2.addinfourl(StringIO.StringIO(), hdr, + req.get_full_url()) + self.jar.extract_cookies(res, req) + if config['cookie_jar']: + self.jar.save(ignore_discard=True) + + + def del_socket(self): + '''Remove the cookie_socket file on exit. In a way the cookie_socket + is the daemons pid file equivalent.''' + + if self.server_socket: + try: + self.server_socket.close() + + except: + pass + + self.server_socket = None + + cookie_socket = config['cookie_socket'] + if os.path.exists(cookie_socket): + echo("deleting socket %r" % cookie_socket) + os.remove(cookie_socket) + + + def quit(self): + '''Called on exit to make sure all loose ends are tied up.''' + + self.del_socket() + sys.exit(0) + + +def main(): + '''Main function.''' + + # Define command line parameters. + usage = "usage: %prog [options] {start|stop|restart|reload}" + parser = OptionParser(usage=usage) + parser.add_option('-n', '--no-daemon', dest='no_daemon', + action='store_true', help="don't daemonise the process.") + + parser.add_option('-v', '--verbose', dest="verbose", + action='store_true', help="print verbose output.") + + parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout', + action="store", metavar="SECONDS", help="shutdown the daemon after x "\ + "seconds inactivity. WARNING: Do not use this when launching the "\ + "cookie daemon manually.") + + parser.add_option('-s', '--cookie-socket', dest="cookie_socket", + metavar="SOCKET", help="manually specify the socket location.") + + parser.add_option('-j', '--cookie-jar', dest='cookie_jar', + metavar="FILE", help="manually specify the cookie jar location.") + + parser.add_option('-m', '--memory', dest='memory', action='store_true', + help="store cookies in memory only - do not write to disk") + + parser.add_option('-u', '--use-whitelist', dest='usewhitelist', + action='store_true', help="use cookie whitelist policy") + + parser.add_option('-w', '--cookie-whitelist', dest='whitelist', + action='store', help="manually specify whitelist location", + metavar='FILE') + + # Parse the command line arguments. + (options, args) = parser.parse_args() + + expand = lambda p: os.path.realpath(os.path.expandvars(p)) + + initcommands = ['start', 'stop', 'restart', 'reload'] + for arg in args: + if arg not in initcommands: + error("unknown argument %r" % args[0]) + sys.exit(1) + + if len(args) > 1: + error("the daemon only accepts one {%s} action at a time." + % '|'.join(initcommands)) + sys.exit(1) + + if len(args): + action = args[0] + + else: + action = "start" + + if options.no_daemon: + config['daemon_mode'] = False + + if options.cookie_socket: + config['cookie_socket'] = expand(options.cookie_socket) + + if options.cookie_jar: + config['cookie_jar'] = expand(options.cookie_jar) + + if options.memory: + config['cookie_jar'] = None + + if options.whitelist: + config['cookie_whitelist'] = expand(options.whitelist) + + if options.whitelist or options.usewhitelist: + config['use_whitelist'] = True + + if options.daemon_timeout: + try: + config['daemon_timeout'] = int(options.daemon_timeout) + + except ValueError: + error("expected int argument for -t, --daemon-timeout") + + # Expand $VAR's in config keys that relate to paths. + for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']: + if config[key]: + config[key] = os.path.expandvars(config[key]) + + if options.verbose: + config['verbose'] = True + import pprint + sys.stderr.write("%s\n" % pprint.pformat(config)) + + # It would be better if we didn't need to start this python process just + # to send a command to the socket, but unfortunately socat doesn't seem + # to support SEQPACKET. + if action == "reload": + send_command(config['cookie_socket'], "RELOAD") + + if action in ['stop', 'restart']: + kill_daemon(config['cookie_socket']) + + if action in ['start', 'restart']: + CookieMonster().run() + + +if __name__ == "__main__": + main() diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager new file mode 100755 index 0000000..dee42c5 --- /dev/null +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -0,0 +1,857 @@ +#!/usr/bin/env python + +# Event Manager for Uzbl +# Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Dieter Plaetinck +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +''' + +E V E N T _ M A N A G E R . P Y +=============================== + +Event manager for uzbl written in python. + +''' + +import imp +import os +import sys +import re +import types +import socket +import pprint +import time +import atexit +from select import select +from signal import signal, SIGTERM +from optparse import OptionParser +from traceback import print_exc + + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# Automagically set during `make install` +PREFIX = None + +# Check if PREFIX not set and set to default /usr/local/ +if not PREFIX: + PREFIX = '/usr/local/' + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return os.path.join(os.environ['HOME'], default) + +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') + + +# Config dict (NOT the same as the uzbl.config). +config = { + 'verbose': False, + 'daemon_mode': True, + 'auto_close': False, + + 'plugins_load': [], + 'plugins_ignore': [], + + 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), + os.path.join(PREFIX, 'share/uzbl/examples/data/uzbl/plugins/')], + + 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), + 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), +} + + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +# Define some globals. +_SCRIPTNAME = os.path.basename(sys.argv[0]) +_RE_FINDSPACES = re.compile("\s+") + +def echo(msg): + '''Prints only if the verbose flag has been set.''' + + if config['verbose']: + sys.stdout.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error messages to stderr.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + + +def counter(): + '''Generate unique object id's.''' + + i = 0 + while True: + i += 1 + yield i + + +def iscallable(obj): + '''Return true if the object is callable.''' + + return hasattr(obj, "__call__") + + +def isiterable(obj): + '''Return true if you can iterate over the item.''' + + return hasattr(obj, "__iter__") + + +def find_plugins(plugin_dirs): + '''Find all event manager plugins in the plugin dirs and return a + dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' + + plugins = {} + + for plugin_dir in plugin_dirs: + plugin_dir = os.path.realpath(os.path.expandvars(plugin_dir)) + if not os.path.isdir(plugin_dir): + continue + + for file in os.listdir(plugin_dir): + if not file.lower().endswith('.py'): + continue + + path = os.path.join(plugin_dir, file) + if not os.path.isfile(path): + continue + + if file not in plugins: + plugins[file] = plugin_dir + + return plugins + + +def load_plugins(plugin_dirs, load=[], ignore=[]): + '''Load event manager plugins found in the plugin_dirs.''' + + # Find the plugins in the plugin_dirs. + found = find_plugins(plugin_dirs) + + if load: + # Ignore anything not in the load list. + for plugin in found.keys(): + if plugin not in load: + del found[plugin] + + if ignore: + # Ignore anything in the ignore list. + for plugin in found.keys(): + if plugin in ignore: + del found[plugin] + + # Print plugin list to be loaded. + pprint.pprint(found) + + loaded = {} + # Load all found plugins into the loaded dict. + for (filename, dir) in found.items(): + name = filename[:-3] + info = imp.find_module(name, [dir,]) + plugin = imp.load_module(name, *info) + loaded[(dir, filename)] = plugin + + return loaded + + +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + +def make_dirs(path): + '''Make all basedirs recursively as required.''' + + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + +def make_pid_file(pid_file): + '''Make pid file at given pid_file location.''' + + make_dirs(pid_file) + file = open(pid_file, 'w') + file.write('%d' % os.getpid()) + file.close() + + +def del_pid_file(pid_file): + '''Delete pid file at given pid_file location.''' + + if os.path.isfile(pid_file): + os.remove(pid_file) + + +def get_pid(pid_file): + '''Read pid from pid_file.''' + + try: + file = open(pid_file, 'r') + strpid = file.read() + file.close() + pid = int(strpid.strip()) + return pid + + except: + print_exc() + return None + + +def pid_running(pid): + '''Returns True if a process with the given pid is running.''' + + try: + os.kill(pid, 0) + + except OSError: + return False + + else: + return True + + +def term_process(pid): + '''Send a SIGTERM signal to the process with the given pid.''' + + if not pid_running(pid): + return False + + os.kill(pid, SIGTERM) + + start = time.time() + while True: + if not pid_running(pid): + return True + + if time.time() - start > 5: + raise OSError('failed to stop process with pid: %d' % pid) + + time.sleep(0.25) + + +def prepender(function, *pre_args): + '''Creates a wrapper around a callable object injecting a list of + arguments before the called arguments.''' + + locals = (function, pre_args) + def _prepender(*args, **kargs): + (function, pre_args) = locals + return function(*(pre_args + args), **kargs) + + return _prepender + + +class EventHandler(object): + + nexthid = counter().next + + def __init__(self, event, handler, *args, **kargs): + if not iscallable(handler): + raise ArgumentError("EventHandler object requires a callable " + "object function for the handler argument not: %r" % handler) + + self.function = handler + self.args = args + self.kargs = kargs + self.event = event + self.hid = self.nexthid() + + + def __repr__(self): + args = ["event=%s" % self.event, "hid=%d" % self.hid, + "function=%r" % self.function] + + if self.args: + args.append("args=%r" % self.args) + + if self.kargs: + args.append("kargs=%r" % self.kargs) + + return "" % ', '.join(args) + + +class UzblInstance(object): + def __init__(self, parent, client_socket): + + # Internal variables. + self._exports = {} + self._handlers = {} + self._parent = parent + self._client_socket = client_socket + + self.buffer = '' + + # Call the init() function in every plugin. Inside the init function + # is where the plugins insert the hooks into the event system. + self._init_plugins() + + + def __getattribute__(self, attr): + '''Expose any exported functions before class functions.''' + + if not attr.startswith('_'): + exports = object.__getattribute__(self, '_exports') + if attr in exports: + return exports[attr] + + return object.__getattribute__(self, attr) + + + def _init_plugins(self): + '''Call the init() function in every plugin and expose all exposable + functions in the plugins root namespace.''' + + plugins = self._parent['plugins'] + + # Map all plugin exports + for (name, plugin) in plugins.items(): + if not hasattr(plugin, '__export__'): + continue + + for export in plugin.__export__: + if export in self._exports: + raise KeyError("conflicting export: %r" % export) + + obj = getattr(plugin, export) + if iscallable(obj): + obj = prepender(obj, self) + + self._exports[export] = obj + + echo("exposed attribute(s): %s" % ', '.join(self._exports.keys())) + + # Now call the init function in all plugins. + for (name, plugin) in plugins.items(): + try: + plugin.init(self) + + except: + #print_exc() + raise + + + def send(self, msg): + '''Send a command to the uzbl instance via the socket file.''' + + if self._client_socket: + print '<-- %s' % msg + self._client_socket.send(("%s\n" % msg).encode('utf-8')) + + else: + print '!-- %s' % msg + + + def connect(self, event, handler, *args, **kargs): + '''Connect event with handler and return the newly created handler. + Handlers can either be a function or a uzbl command string.''' + + if event not in self._handlers.keys(): + self._handlers[event] = [] + + handlerobj = EventHandler(event, handler, *args, **kargs) + self._handlers[event].append(handlerobj) + print handlerobj + + + def connect_dict(self, connect_dict): + '''Connect a dictionary comprising of {"EVENT_NAME": handler, ..} to + the event handler stack. + + If you need to supply args or kargs to an event use the normal connect + function.''' + + for (event, handler) in connect_dict.items(): + self.connect(event, handler) + + + def remove_by_id(self, hid): + '''Remove connected event handler by unique handler id.''' + + for (event, handlers) in self._handlers.items(): + for handler in list(handlers): + if hid != handler.hid: + continue + + echo("removed %r" % handler) + handlers.remove(handler) + return + + echo('unable to find & remove handler with id: %d' % handler.hid) + + + def remove(self, handler): + '''Remove connected event handler.''' + + for (event, handlers) in self._handlers.items(): + if handler in handlers: + echo("removed %r" % handler) + handlers.remove(handler) + return + + echo('unable to find & remove handler: %r' % handler) + + + def exec_handler(self, handler, *args, **kargs): + '''Execute event handler function.''' + + args += handler.args + kargs = dict(handler.kargs.items()+kargs.items()) + handler.function(self, *args, **kargs) + + + def event(self, event, *args, **kargs): + '''Raise a custom event.''' + + # Silence _printing_ of geo events while debugging. + if event != "GEOMETRY_CHANGED": + print "--> %s %s %s" % (event, args, '' if not kargs else kargs) + + if event not in self._handlers: + return + + for handler in self._handlers[event]: + try: + self.exec_handler(handler, *args, **kargs) + + except: + print_exc() + + + def close(self): + '''Close the client socket and clean up.''' + + try: + self._client_socket.close() + + except: + pass + + for (name, plugin) in self._parent['plugins'].items(): + if hasattr(plugin, 'cleanup'): + plugin.cleanup(self) + + del self._exports + del self._handlers + del self._client_socket + + +class UzblEventDaemon(dict): + def __init__(self): + + # Init variables and dict keys. + dict.__init__(self, {'uzbls': {}}) + self.running = None + self.server_socket = None + self.socket_location = None + + # Register that the event daemon server has started by creating the + # pid file. + make_pid_file(config['pid_file']) + + # Register a function to clean up the socket and pid file on exit. + atexit.register(self.quit) + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + # Load plugins, first-build of the plugins may be a costly operation. + self['plugins'] = load_plugins(config['plugin_dirs'], + config['plugins_load'], config['plugins_ignore']) + + + def _create_server_socket(self): + '''Create the event manager daemon socket for uzbl instance duplex + communication.''' + + server_socket = config['server_socket'] + server_socket = os.path.realpath(os.path.expandvars(server_socket)) + self.socket_location = server_socket + + # Delete socket if it exists. + if os.path.exists(server_socket): + os.remove(server_socket) + + self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.server_socket.bind(server_socket) + self.server_socket.listen(5) + + + def _close_server_socket(self): + '''Close and delete the server socket.''' + + try: + self.server_socket.close() + self.server_socket = None + + if os.path.exists(self.socket_location): + os.remove(self.socket_location) + + except: + pass + + + def run(self): + '''Main event daemon loop.''' + + if config['daemon_mode']: + echo('entering daemon mode.') + daemonize() + # The pid has changed so update the pid file. + make_pid_file(config['pid_file']) + + # Create event daemon socket. + self._create_server_socket() + echo('listening on: %s' % self.socket_location) + + # Now listen for incoming connections and or data. + self.listen() + + # Clean up. + self.quit() + + + def listen(self): + '''Accept incoming connections and constantly poll instance sockets + for incoming data.''' + + self.running = True + while self.running: + + sockets = [self.server_socket,] + self['uzbls'].keys() + + read, _, error = select(sockets, [], sockets, 1) + + if self.server_socket in read: + self.accept_connection() + read.remove(self.server_socket) + + for client in read: + self.read_socket(client) + + for client in error: + error('Unknown error on socket: %r' % client) + self.close_connection(client) + + + def read_socket(self, client): + '''Read data from an instance socket and pass to the uzbl objects + event handler function.''' + + try: + uzbl = self['uzbls'][client] + try: + raw = unicode(client.recv(8192), 'utf-8', 'ignore') + + except: + print_exc() + raw = None + + if not raw: + # Read null byte, close socket. + return self.close_connection(client) + + uzbl.buffer += raw + msgs = uzbl.buffer.split('\n') + uzbl.buffer = msgs.pop() + + for msg in msgs: + self.parse_msg(uzbl, msg) + + except: + raise + + + def parse_msg(self, uzbl, msg): + '''Parse an incoming msg from a uzbl instance. All non-event messages + will be printed here and not be passed to the uzbl instance event + handler function.''' + + msg = msg.strip() + if not msg: + return + + cmd = _RE_FINDSPACES.split(msg, 3) + if not cmd or cmd[0] != 'EVENT': + # Not an event message. + print '---', msg + return + + if len(cmd) < 4: + cmd.append('') + + event, args = cmd[2], cmd[3] + + try: + uzbl.event(event, args) + + except: + print_exc() + + + def accept_connection(self): + '''Accept incoming connection to the server socket.''' + + client_socket = self.server_socket.accept()[0] + + uzbl = UzblInstance(self, client_socket) + self['uzbls'][client_socket] = uzbl + + + def close_connection(self, client): + '''Clean up after instance close.''' + + try: + if client in self['uzbls']: + uzbl = self['uzbls'][client] + uzbl.close() + del self['uzbls'][client] + + except: + print_exc() + + if not len(self['uzbls']) and config['auto_close']: + echo('auto closing event manager.') + self.running = False + + + def quit(self): + '''Close all instance socket objects, server socket and delete the + pid file.''' + + echo('shutting down event manager.') + + for client in self['uzbls'].keys(): + self.close_connection(client) + + echo('unlinking: %r' % self.socket_location) + self._close_server_socket() + + echo('deleting pid file: %r' % config['pid_file']) + del_pid_file(config['pid_file']) + + +def stop(): + '''Stop the event manager daemon.''' + + pid_file = config['pid_file'] + if not os.path.isfile(pid_file): + return echo('no running daemon found.') + + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if not pid_running(pid): + echo('no process with pid: %d' % pid) + return os.remove(pid_file) + + echo("terminating process with pid: %d" % pid) + term_process(pid) + if os.path.isfile(pid_file): + os.remove(pid_file) + + echo('stopped event daemon.') + + +def start(): + '''Start the event manager daemon.''' + + pid_file = config['pid_file'] + if os.path.isfile(pid_file): + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if pid_running(pid): + return echo('event daemon already started with pid: %d' % pid) + + echo('no process with pid: %d' % pid) + os.remove(pid_file) + + echo('starting event manager.') + UzblEventDaemon().run() + + +def restart(): + '''Restart the event manager daemon.''' + + echo('restarting event manager daemon.') + stop() + start() + + +def list_plugins(): + '''List all the plugins being loaded by the event daemon.''' + + plugins = find_plugins(config['plugin_dirs']) + dirs = {} + + for (plugin, dir) in plugins.items(): + if dir not in dirs: + dirs[dir] = [] + + dirs[dir].append(plugin) + + for (index, (dir, plugin_list)) in enumerate(sorted(dirs.items())): + if index: + print + + print "%s:" % dir + for plugin in sorted(plugin_list): + print " %s" % plugin + + +if __name__ == "__main__": + usage = "usage: %prog [options] {start|stop|restart|list}" + parser = OptionParser(usage=usage) + parser.add_option('-v', '--verbose', dest='verbose', action="store_true", + help="print verbose output.") + + parser.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", + metavar="DIRS", help="Specify plugin directories in the form of "\ + "'dir1:dir2:dir3'.") + + parser.add_option('-l', '--load-plugins', dest="load", action="store", + metavar="PLUGINS", help="comma separated list of plugins to load") + + parser.add_option('-i', '--ignore-plugins', dest="ignore", action="store", + metavar="PLUGINS", help="comma separated list of plugins to ignore") + + parser.add_option('-p', '--pid-file', dest='pid', action='store', + metavar='FILE', help="specify pid file location") + + parser.add_option('-s', '--server-socket', dest='socket', action='store', + metavar='SOCKET', help="specify the daemon socket location") + + parser.add_option('-n', '--no-daemon', dest="daemon", + action="store_true", help="don't enter daemon mode.") + + parser.add_option('-a', '--auto-close', dest='autoclose', + action='store_true', help='auto close after all instances disconnect.') + + (options, args) = parser.parse_args() + + # init like {start|stop|..} daemon control section. + daemon_controls = {'start': start, 'stop': stop, 'restart': restart, + 'list': list_plugins} + + if len(args) == 1: + action = args[0] + if action not in daemon_controls: + error('unknown action: %r' % action) + sys.exit(1) + + elif len(args) > 1: + error("too many arguments: %r" % args) + sys.exit(1) + + else: + action = 'start' + + # parse other flags & options. + if options.verbose: + config['verbose'] = True + + if options.plugin_dirs: + plugin_dirs = map(os.path.realpath, map(str.strip, + options.plugin_dirs.split(':'))) + config['plugin_dirs'] = plugin_dirs + echo("plugin search dirs: %r" % plugin_dirs) + + if options.load and options.ignore: + error("you can't load and ignore at the same time.") + sys.exit(1) + + elif options.load: + plugins_load = config['plugins_load'] + for plugin in options.load.split(','): + if plugin.strip(): + plugins_load.append(plugin.strip()) + + echo('only loading plugin(s): %s' % ', '.join(plugins_load)) + + elif options.ignore: + plugins_ignore = config['plugins_ignore'] + for plugin in options.ignore.split(','): + if plugin.strip(): + plugins_ignore.append(plugin.strip()) + + echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) + + if options.autoclose: + config['auto_close'] = True + echo('will auto close.') + + if options.pid: + config['pid_file'] = os.path.realpath(options.pid) + echo("pid file location: %r" % config['pid_file']) + + if options.socket: + config['server_socket'] = os.path.realpath(options.socket) + echo("daemon socket location: %s" % config['server_socket']) + + if options.daemon: + config['daemon_mode'] = False + + # Now {start|stop|...} + daemon_controls[action]() diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed new file mode 100755 index 0000000..bb9b9a2 --- /dev/null +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -0,0 +1,1474 @@ +#!/usr/bin/env python + +# Uzbl tabbing wrapper using a fifo socket interface +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, Chris van Dijk +# Copyright (c) 2009, Mason Larobina +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Author(s): +# Tom Adams +# Wrote the original uzbl_tabbed.py as a proof of concept. +# +# Chris van Dijk (quigybo) +# Made signifigant headway on the old uzbl_tabbing.py script on the +# uzbl wiki +# +# Mason Larobina +# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface +# and inherit configuration options from the user's uzbl config. +# +# Contributor(s): +# mxey +# uzbl_config path now honors XDG_CONFIG_HOME if it exists. +# +# Romain Bignon +# Fix for session restoration code. +# +# Jake Probst +# Wrote a patch that overflows tabs in the tablist on to new lines when +# running of room. +# +# Devon Jones +# Fifo command bring_to_front which brings the gtk window to focus. + + +# Dependencies: +# pygtk - python bindings for gtk. +# pango - python bindings needed for text rendering & layout in gtk widgets. +# pygobject - GLib's GObject bindings for python. +# +# Optional dependencies: +# simplejson - save uzbl_tabbed.py sessions & presets in json. +# +# Note: I haven't included version numbers with this dependency list because +# I've only ever tested uzbl_tabbed.py on the latest stable versions of these +# packages in Gentoo's portage. Package names may vary on different systems. + + +# Configuration: +# Because this version of uzbl_tabbed is able to inherit options from your main +# uzbl configuration file you may wish to configure uzbl tabbed from there. +# Here is a list of configuration options that can be customised and some +# example values for each: +# +# General tabbing options: +# show_tablist = 1 +# show_gtk_tabs = 0 +# tablist_top = 1 +# gtk_tab_pos = (top|left|bottom|right) +# gtk_refresh = 1000 +# switch_to_new_tabs = 1 +# capture_new_windows = 1 +# multiline_tabs = 1 +# +# Tab title options: +# tab_titles = 1 +# new_tab_title = Loading +# max_title_len = 50 +# show_ellipsis = 1 +# +# Session options: +# save_session = 1 +# json_session = 0 +# session_file = $HOME/.local/share/uzbl/session +# +# Inherited uzbl options: +# fifo_dir = /tmp +# socket_dir = /tmp +# icon_path = $HOME/.local/share/uzbl/uzbl.png +# status_background = #303030 +# +# Misc options: +# window_size = 800,800 +# verbose = 0 +# +# And the key bindings: +# bind_new_tab = gn +# bind_tab_from_clip = gY +# bind_tab_from_uri = go _ +# bind_close_tab = gC +# bind_next_tab = gt +# bind_prev_tab = gT +# bind_goto_tab = gi_ +# bind_goto_first = g< +# bind_goto_last = g> +# bind_clean_slate = gQ +# bind_exit = gZ +# +# Session preset key bindings: +# bind_save_preset = gsave _ +# bind_load_preset = gload _ +# bind_del_preset = gdel _ +# bind_list_presets = glist +# +# And uzbl_tabbed.py takes care of the actual binding of the commands via each +# instances fifo socket. +# +# Custom tab styling: +# tab_colours = foreground = "#888" background = "#303030" +# tab_text_colours = foreground = "#bbb" +# selected_tab = foreground = "#fff" +# selected_tab_text = foreground = "green" +# tab_indicate_https = 1 +# https_colours = foreground = "#888" +# https_text_colours = foreground = "#9c8e2d" +# selected_https = foreground = "#fff" +# selected_https_text = foreground = "gold" +# +# How these styling values are used are soley defined by the syling policy +# handler below (the function in the config section). So you can for example +# turn the tab text colour Firetruck-Red in the event "error" appears in the +# tab title or some other arbitrary event. You may wish to make a trusted +# hosts file and turn tab titles of tabs visiting trusted hosts purple. + + +# Issues: +# - new windows are not caught and opened in a new tab. +# - when uzbl_tabbed.py crashes it takes all the children with it. +# - when a new tab is opened when using gtk tabs the tab button itself +# grabs focus from its child for a few seconds. +# - when switch_to_new_tabs is not selected the notebook page is +# maintained but the new window grabs focus (try as I might to stop it). + + +# Todo: +# - add command line options to use a different session file, not use a +# session file and or open a uri on starup. +# - ellipsize individual tab titles when the tab-list becomes over-crowded +# - add "<" & ">" arrows to tablist to indicate that only a subset of the +# currently open tabs are being displayed on the tablist. +# - add the small tab-list display when both gtk tabs and text vim-like +# tablist are hidden (I.e. [ 1 2 3 4 5 ]) +# - check spelling. +# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into +# the collective. Resistance is futile! + + +import pygtk +import gtk +import subprocess +import os +import re +import time +import getopt +import pango +import select +import sys +import gobject +import socket +import random +import hashlib +import atexit +import types + +from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP +from signal import signal, SIGTERM, SIGINT +from optparse import OptionParser, OptionGroup + + +pygtk.require('2.0') + +_SCRIPTNAME = os.path.basename(sys.argv[0]) +def error(msg): + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return os.path.join(os.environ['HOME'], default) + +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +CONFIG_DIR = os.path.join(xdghome('CONFIG', '.config/'), 'uzbl/') + +# Ensure uzbl xdg paths exist +for path in [DATA_DIR, CONFIG_DIR]: + if not os.path.exists(path): + os.makedirs(path) + +# Path to uzbl config +UZBL_CONFIG = os.path.join(CONFIG_DIR, 'config') +if not os.path.exists(UZBL_CONFIG): + error("cannot find uzbl config file at %r" % UZBL_CONFIG) + sys.exit(1) + +# All of these settings can be inherited from your uzbl config file. +config = { + # Tab options + 'show_tablist': True, # Show text uzbl like statusbar tab-list + 'show_gtk_tabs': False, # Show gtk notebook tabs + 'tablist_top': True, # Display tab-list at top of window + 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) + 'gtk_refresh': 1000, # Tablist refresh millisecond interval + 'switch_to_new_tabs': True, # Upon opening a new tab switch to it + 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows + 'multiline_tabs': True, # Tabs overflow onto new tablist lines. + + # Tab title options + 'tab_titles': True, # Display tab titles (else only tab-nums) + 'new_tab_title': 'Loading', # New tab title + 'max_title_len': 50, # Truncate title at n characters + 'show_ellipsis': True, # Show ellipsis when truncating titles + + # Session options + 'save_session': True, # Save session in file when quit + 'json_session': False, # Use json to save session. + 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'), + 'session_file': os.path.join(DATA_DIR, 'session'), + + # Inherited uzbl options + 'fifo_dir': '/tmp', # Path to look for uzbl fifo. + 'socket_dir': '/tmp', # Path to look for uzbl socket. + 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'), + 'status_background': "#303030", # Default background for all panels. + + # Misc options + 'window_size': "800,800", # width,height in pixels. + 'verbose': False, # Print verbose output. + + # Key bindings + 'bind_new_tab': 'gn', # Open new tab. + 'bind_tab_from_clip': 'gY', # Open tab from clipboard. + 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. + 'bind_close_tab': 'gC', # Close tab. + 'bind_next_tab': 'gt', # Next tab. + 'bind_prev_tab': 'gT', # Prev tab. + 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title). + 'bind_goto_first': 'g<', # Goto first tab. + 'bind_goto_last': 'g>', # Goto last tab. + 'bind_clean_slate': 'gQ', # Close all tabs and open new tab. + 'bind_exit': 'gZ', # Exit nicely. + + # Session preset key bindings + 'bind_save_preset': 'gsave _', # Save session to file %s. + 'bind_load_preset': 'gload _', # Load preset session from file %s. + 'bind_del_preset': 'gdel _', # Delete preset session %s. + 'bind_list_presets': 'glist', # List all session presets. + + # Add custom tab style definitions to be used by the tab colour policy + # handler here. Because these are added to the config dictionary like + # any other uzbl_tabbed configuration option remember that they can + # be superseeded from your main uzbl config file. + 'tab_colours': 'foreground = "#888" background = "#303030"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"', + +} # End of config dict. + +# This is the tab style policy handler. Every time the tablist is updated +# this function is called to determine how to colourise that specific tab +# according the simple/complex rules as defined here. You may even wish to +# move this function into another python script and import it using: +# from mycustomtabbingconfig import colour_selector +# Remember to rename, delete or comment out this function if you do that. + +def colour_selector(tabindex, currentpage, uzbl): + '''Tablist styling policy handler. This function must return a tuple of + the form (tab style, text style).''' + + # Just as an example: + # if 'error' in uzbl.title: + # if tabindex == currentpage: + # return ('foreground="#fff"', 'foreground="red"') + # return ('foreground="#888"', 'foreground="red"') + + # Style tabs to indicate connected via https. + if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): + if tabindex == currentpage: + return (config['selected_https'], config['selected_https_text']) + return (config['https_colours'], config['https_text_colours']) + + # Style to indicate selected. + if tabindex == currentpage: + return (config['selected_tab'], config['selected_tab_text']) + + # Default tab style. + return (config['tab_colours'], config['tab_text_colours']) + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def echo(msg): + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def readconfig(uzbl_config, config): + '''Loads relevant config from the users uzbl config file into the global + config dictionary.''' + + if not os.path.exists(uzbl_config): + error("Unable to load config %r" % uzbl_config) + return None + + # Define parsing regular expressions + isint = re.compile("^(\-|)[0-9]+$").match + findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ + re.MULTILINE).findall + + h = open(os.path.expandvars(uzbl_config), 'r') + rawconfig = h.read() + h.close() + + configkeys, strip = config.keys(), str.strip + for (key, value) in findsets(rawconfig): + key, value = strip(key), strip(value) + if key not in configkeys: continue + if isint(value): value = int(value) + config[key] = value + + # Ensure that config keys that relate to paths are expanded. + pathkeys = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path', + 'saved_sessions_dir'] + for key in pathkeys: + config[key] = os.path.expandvars(config[key]) + + +def counter(): + '''To infinity and beyond!''' + + i = 0 + while True: + i += 1 + yield i + + +def escape(s): + '''Replaces html markup in tab titles that screw around with pango.''' + + for (split, glue) in [('&','&'), ('<', '<'), ('>', '>')]: + s = s.replace(split, glue) + return s + + +def gen_endmarker(): + '''Generates a random md5 for socket message-termination endmarkers.''' + + return hashlib.md5(str(random.random()*time.time())).hexdigest() + + +class UzblTabbed: + '''A tabbed version of uzbl using gtk.Notebook''' + + class UzblInstance: + '''Uzbl instance meta-data/meta-action object.''' + + def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ + uri, title, switch): + + self.parent = parent + self.tab = tab + self.fifo_socket = fifo_socket + self.socket_file = socket_file + self.pid = pid + self.title = title + self.uri = uri + self.timers = {} + self._lastprobe = 0 + self._fifoout = [] + self._socketout = [] + self._socket = None + self._buffer = "" + # Switch to tab after loading + self._switch = switch + # fifo/socket files exists and socket connected. + self._connected = False + # The kill switch + self._kill = False + + # Message termination endmarker. + self._marker = gen_endmarker() + + # Gen probe commands string + probes = [] + probe = probes.append + probe('print uri %d @uri %s' % (self.pid, self._marker)) + probe('print title %d @@ %s' % (self.pid,\ + self._marker)) + self._probecmds = '\n'.join(probes) + + # Enqueue keybinding config for child uzbl instance + self.parent.config_uzbl(self) + + + def flush(self, timer_call=False): + '''Flush messages from the socket-out and fifo-out queues.''' + + if self._kill: + if self._socket: + self._socket.close() + self._socket = None + + error("Flush called on dead tab.") + return False + + if len(self._fifoout): + if os.path.exists(self.fifo_socket): + h = open(self.fifo_socket, 'w') + while len(self._fifoout): + msg = self._fifoout.pop(0) + h.write("%s\n"%msg) + h.close() + + if len(self._socketout): + if not self._socket and os.path.exists(self.socket_file): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.socket_file) + self._socket = sock + + if self._socket: + while len(self._socketout): + msg = self._socketout.pop(0) + self._socket.send("%s\n"%msg) + + if not self._connected and timer_call: + if not len(self._fifoout + self._socketout): + self._connected = True + + if timer_call in self.timers.keys(): + source_remove(self.timers[timer_call]) + del self.timers[timer_call] + + if self._switch: + self.grabfocus() + + return len(self._fifoout + self._socketout) + + + def grabfocus(self): + '''Steal parent focus and switch the notebook to my own tab.''' + + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) + self.parent.goto_tab(tabid) + + + def probe(self): + '''Probes the client for information about its self.''' + + if self._connected: + self.send(self._probecmds) + self._lastprobe = time.time() + + + def write(self, msg): + '''Child fifo write function.''' + + self._fifoout.append(msg) + # Flush messages from the queue if able. + return self.flush() + + + def send(self, msg): + '''Child socket send function.''' + + self._socketout.append(msg) + # Flush messages from queue if able. + return self.flush() + + + def __init__(self): + '''Create tablist, window and notebook.''' + + # Store information about the applications fifo_socket. + self._fifo = None + + self._timers = {} + self._buffer = "" + self._killed = False + + # A list of the recently closed tabs + self._closed = [] + + # Holds metadata on the uzbl childen open. + self.tabs = {} + + # Generates a unique id for uzbl socket filenames. + self.next_pid = counter().next + + # Create main window + self.window = gtk.Window() + try: + window_size = map(int, config['window_size'].split(',')) + self.window.set_default_size(*window_size) + + except: + error("Invalid value for default_size in config file.") + + self.window.set_title("Uzbl Browser") + self.window.set_border_width(0) + + # Set main window icon + icon_path = config['icon_path'] + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + else: + icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + # Attach main window event handlers + self.window.connect("delete-event", self.quitrequest) + + # Create tab list + if config['show_tablist']: + vbox = gtk.VBox() + self.window.add(vbox) + ebox = gtk.EventBox() + self.tablist = gtk.Label() + + self.tablist.set_use_markup(True) + self.tablist.set_justify(gtk.JUSTIFY_LEFT) + self.tablist.set_line_wrap(False) + self.tablist.set_selectable(False) + self.tablist.set_padding(2,2) + self.tablist.set_alignment(0,0) + self.tablist.set_ellipsize(pango.ELLIPSIZE_END) + self.tablist.set_text(" ") + self.tablist.show() + ebox.add(self.tablist) + ebox.show() + bgcolor = gtk.gdk.color_parse(config['status_background']) + ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) + + # Create notebook + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(config['show_gtk_tabs']) + + # Set tab position + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} + if config['gtk_tab_pos'] in allposes.keys(): + self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + + self.notebook.set_show_border(False) + self.notebook.set_scrollable(True) + self.notebook.set_border_width(0) + + self.notebook.connect("page-removed", self.tab_closed) + self.notebook.connect("switch-page", self.tab_changed) + self.notebook.connect("page-added", self.tab_opened) + + self.notebook.show() + if config['show_tablist']: + if config['tablist_top']: + vbox.pack_start(ebox, False, False, 0) + vbox.pack_end(self.notebook, True, True, 0) + + else: + vbox.pack_start(self.notebook, True, True, 0) + vbox.pack_end(ebox, False, False, 0) + + vbox.show() + + else: + self.window.add(self.notebook) + + self.window.show() + self.wid = self.notebook.window.xid + # Generate the fifo socket filename. + fifo_filename = 'uzbltabbed_%d' % os.getpid() + self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + + # Now initialise the fifo socket at self.fifo_socket + self.init_fifo_socket() + + # If we are using sessions then load the last one if it exists. + if config['save_session']: + self.load_session() + + + def run(self): + '''UzblTabbed main function that calls the gtk loop.''' + + if not len(self.tabs): + self.new_tab() + + gtk_refresh = int(config['gtk_refresh']) + if gtk_refresh < 100: + gtk_refresh = 100 + + # Update tablist timer + timerid = timeout_add(gtk_refresh, self.update_tablist) + self._timers["update-tablist"] = timerid + + # Probe clients every second for window titles and location + timerid = timeout_add(gtk_refresh, self.probe_clients) + self._timers["probe-clients"] = timerid + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) + + # Catch keyboard interrupts + signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) + + try: + gtk.main() + + except: + error("encounted error %r" % sys.exc_info()[1]) + + # Unlink fifo socket + self.unlink_fifo_socket() + + # Attempt to close all uzbl instances nicely. + self.quitrequest() + + # Allow time for all the uzbl instances to quit. + time.sleep(1) + + raise + + + def terminate(self, termsig=None): + '''Handle termination signals and exit safely and cleanly.''' + + # Not required but at least it lets the user know what killed his + # browsing session. + if termsig == SIGTERM: + error("caught SIGTERM signal") + + elif termsig == SIGINT: + error("caught keyboard interrupt") + + else: + error("caught unknown signal") + + error("commencing infanticide!") + + # Sends the exit signal to all uzbl instances. + self.quitrequest() + + + def init_fifo_socket(self): + '''Create interprocess communication fifo socket.''' + + if os.path.exists(self.fifo_socket): + if not os.access(self.fifo_socket, os.F_OK | os.R_OK | os.W_OK): + os.mkfifo(self.fifo_socket) + + else: + basedir = os.path.dirname(self.fifo_socket) + if not os.path.exists(basedir): + os.makedirs(basedir) + + os.mkfifo(self.fifo_socket) + + # Add event handlers for IO_IN & IO_HUP events. + self.setup_fifo_watchers() + + echo("listening at %r" % self.fifo_socket) + + # Add atexit register to destroy the socket on program termination. + atexit.register(self.unlink_fifo_socket) + + + def unlink_fifo_socket(self): + '''Unlink the fifo socket. Note: This function is called automatically + on exit by an atexit register.''' + + # Make sure the fifo_socket fd is closed. + self.close_fifo() + + # And unlink if the real fifo_socket exists. + if os.path.exists(self.fifo_socket): + os.unlink(self.fifo_socket) + echo("unlinked %r" % self.fifo_socket) + + + 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_socket fd and kill all watchers + self.close_fifo() + + fd = os.open(self.fifo_socket, 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: + error("parse_command: invalid command %s" % ' '.join(cmd)) + raise + + return True + + + def probe_clients(self): + '''Probe all uzbl clients for up-to-date window titles and uri's.''' + + save_session = config['save_session'] + + sockd = {} + tabskeys = self.tabs.keys() + notebooklist = list(self.notebook) + + for tab in notebooklist: + if tab not in tabskeys: continue + uzbl = self.tabs[tab] + uzbl.probe() + if uzbl._socket: + sockd[uzbl._socket] = uzbl + + sockets = sockd.keys() + (reading, _, errors) = select.select(sockets, [], sockets, 0) + + for sock in reading: + uzbl = sockd[sock] + uzbl._buffer = sock.recv(1024).replace('\n',' ') + temp = uzbl._buffer.split(uzbl._marker) + 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: + 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. + # 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] == "newfromclip": + uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + stdout=subprocess.PIPE).communicate()[0] + if uri: + self.new_tab(uri) + + elif cmd[0] == "close": + if len(cmd) == 2: + self.close_tab(int(cmd[1])) + + else: + self.close_tab() + + elif cmd[0] == "next": + if len(cmd) == 2: + self.next_tab(int(cmd[1])) + + else: + self.next_tab() + + elif cmd[0] == "prev": + if len(cmd) == 2: + self.prev_tab(int(cmd[1])) + + else: + self.prev_tab() + + elif cmd[0] == "goto": + self.goto_tab(int(cmd[1])) + + elif cmd[0] == "first": + self.goto_tab(0) + + elif cmd[0] == "last": + self.goto_tab(-1) + + elif cmd[0] in ["title", "uri"]: + if len(cmd) > 2: + uzbl = self.get_tab_by_pid(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 pid %r" % int(cmd[1])) + + elif cmd[0] == "preset": + if len(cmd) < 3: + error("parse_command: invalid preset command") + + elif cmd[1] == "save": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.save_session(path) + + elif cmd[1] == "load": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.load_session(path) + + elif cmd[1] == "del": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + if os.path.isfile(path): + os.remove(path) + + else: + error("parse_command: preset %r does not exist." % path) + + elif cmd[1] == "list": + uzbl = self.get_tab_by_pid(int(cmd[2])) + if uzbl: + if not os.path.isdir(config['saved_sessions_dir']): + js = "js alert('No saved presets.');" + uzbl.send(js) + + else: + listdir = os.listdir(config['saved_sessions_dir']) + listdir = "\\n".join(listdir) + js = "js alert('Session presets:\\n\\n%s');" % listdir + uzbl.send(js) + + else: + error("parse_command: unknown tab pid.") + + else: + error("parse_command: unknown parse command %r"\ + % ' '.join(cmd)) + + elif cmd[0] == "bring_to_front": + self.window.present() + + elif cmd[0] == "clean": + self.clean_slate() + + elif cmd[0] == "exit": + self.quitrequest() + + else: + error("parse_command: unknown command %r" % ' '.join(cmd)) + + + def get_tab_by_pid(self, pid): + '''Return uzbl instance by pid.''' + + for (tab, uzbl) in self.tabs.items(): + if uzbl.pid == pid: + return uzbl + + return False + + + def new_tab(self, uri='', title='', switch=None): + '''Add a new tab to the notebook and start a new instance of uzbl. + Use the switch option to negate config['switch_to_new_tabs'] option + when you need to load multiple tabs at a time (I.e. like when + restoring a session from a file).''' + + pid = self.next_pid() + tab = gtk.Socket() + tab.show() + self.notebook.append_page(tab) + sid = tab.get_id() + uri = uri.strip() + + fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) + fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) + socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) + socket_file = os.path.join(config['socket_dir'], socket_filename) + + if switch is None: + switch = config['switch_to_new_tabs'] + + if not title: + title = config['new_tab_title'] + + uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ + uri, title, switch) + + if len(uri): + uri = "--uri %r" % uri + + self.tabs[tab] = uzbl + cmd = 'uzbl-browser -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) + subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? + + # Add gobject timer to make sure the config is pushed when fifo socket + # has been created. + timerid = timeout_add(100, uzbl.flush, "flush-initial-config") + uzbl.timers['flush-initial-config'] = timerid + + self.update_tablist() + + + def clean_slate(self): + '''Close all open tabs and open a fresh brand new one.''' + + self.new_tab() + tabs = self.tabs.keys() + for tab in list(self.notebook)[:-1]: + if tab not in tabs: continue + uzbl = self.tabs[tab] + uzbl.send("exit") + + + def config_uzbl(self, uzbl): + '''Send bind commands for tab new/close/next/prev to a uzbl + instance.''' + + binds = [] + bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""' + bind = lambda key, action: binds.append(bind_format % (key, action,\ + self.fifo_socket)) + + sets = [] + set_format = r'set %s = sh \"echo \\"%s\\" > \\"%s\\""' + set = lambda key, action: binds.append(set_format % (key, action,\ + self.fifo_socket)) + + # Bind definitions here + # bind(key, command back to fifo) + bind(config['bind_new_tab'], 'new') + bind(config['bind_tab_from_clip'], 'newfromclip') + bind(config['bind_tab_from_uri'], 'new %s') + bind(config['bind_close_tab'], 'close') + bind(config['bind_next_tab'], 'next') + bind(config['bind_prev_tab'], 'prev') + bind(config['bind_goto_tab'], 'goto %s') + bind(config['bind_goto_first'], 'goto 0') + bind(config['bind_goto_last'], 'goto -1') + bind(config['bind_clean_slate'], 'clean') + bind(config['bind_save_preset'], 'preset save %s') + bind(config['bind_load_preset'], 'preset load %s') + bind(config['bind_del_preset'], 'preset del %s') + bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid) + bind(config['bind_exit'], 'exit') + + # Set definitions here + # set(key, command back to fifo) + if config['capture_new_windows']: + set("new_window", r'new $8') + + # Send config to uzbl instance via its socket file. + uzbl.send("\n".join(binds+sets)) + + + def goto_tab(self, index): + '''Goto tab n (supports negative indexing).''' + + tabs = list(self.notebook) + if 0 <= index < len(tabs): + self.notebook.set_current_page(index) + self.update_tablist() + return None + + try: + tab = tabs[index] + # Update index because index might have previously been a + # negative index. + index = tabs.index(tab) + self.notebook.set_current_page(index) + self.update_tablist() + + except IndexError: + pass + + + def next_tab(self, step=1): + '''Switch to next tab or n tabs right.''' + + if step < 1: + error("next_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = (self.notebook.get_current_page() + step) % ntabs + self.notebook.set_current_page(tabn) + self.update_tablist() + + + def prev_tab(self, step=1): + '''Switch to prev tab or n tabs left.''' + + if step < 1: + error("prev_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() - step + while tabn < 0: tabn += ntabs + self.notebook.set_current_page(tabn) + self.update_tablist() + + + def close_tab(self, tabn=None): + '''Closes current tab. Supports negative indexing.''' + + if tabn is None: + tabn = self.notebook.get_current_page() + + else: + try: + tab = list(self.notebook)[tabn] + + except IndexError: + error("close_tab: invalid index %r" % tabn) + return None + + self.notebook.remove_page(tabn) + + + def tab_opened(self, notebook, tab, index): + '''Called upon tab creation. Called by page-added signal.''' + + if config['switch_to_new_tabs']: + self.notebook.set_focus_child(tab) + + else: + oldindex = self.notebook.get_current_page() + oldtab = self.notebook.get_nth_page(oldindex) + self.notebook.set_focus_child(oldtab) + + + def tab_closed(self, notebook, tab, index): + '''Close the window if no tabs are left. Called by page-removed + signal.''' + + if tab in self.tabs.keys(): + uzbl = self.tabs[tab] + for (timer, gid) in uzbl.timers.items(): + error("tab_closed: removing timer %r" % timer) + source_remove(gid) + del uzbl.timers[timer] + + if uzbl._socket: + uzbl._socket.close() + uzbl._socket = None + + uzbl._fifoout = [] + uzbl._socketout = [] + uzbl._kill = True + self._closed.append((uzbl.uri, uzbl.title)) + self._closed = self._closed[-10:] + del self.tabs[tab] + + if self.notebook.get_n_pages() == 0: + if not self._killed and config['save_session']: + if os.path.exists(config['session_file']): + os.remove(config['session_file']) + + self.quit() + + self.update_tablist() + + return True + + + def tab_changed(self, notebook, page, index): + '''Refresh tab list. Called by switch-page signal.''' + + tab = self.notebook.get_nth_page(index) + self.notebook.set_focus_child(tab) + self.update_tablist(index) + return True + + + def update_tablist(self, curpage=None): + '''Upate tablist status bar.''' + + show_tablist = config['show_tablist'] + show_gtk_tabs = config['show_gtk_tabs'] + tab_titles = config['tab_titles'] + show_ellipsis = config['show_ellipsis'] + multiline_tabs = config['multiline_tabs'] + + if multiline_tabs: + multiline = [] + + if not show_tablist and not show_gtk_tabs: + return True + + tabs = self.tabs.keys() + if curpage is None: + curpage = self.notebook.get_current_page() + + title_format = "%s - Uzbl Browser" + max_title_len = config['max_title_len'] + + if show_tablist: + pango = "" + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + + if tab_titles: + tab_format = " [ %d %s ] " + + else: + tab_format = " [ %d ] " + + if show_gtk_tabs: + gtk_tab_format = "%d %s" + + for index, tab in enumerate(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + + if index == curpage: + self.window.set_title(title_format % uzbl.title) + + # Unicode heavy strings do not like being truncated/sliced so by + # re-encoding the string sliced of limbs are removed. + tabtitle = uzbl.title[:max_title_len + int(show_ellipsis)] + if type(tabtitle) != types.UnicodeType: + tabtitle = unicode(tabtitle, 'utf-8', 'ignore') + + tabtitle = tabtitle.encode('utf-8', 'ignore').strip() + + if show_ellipsis and len(tabtitle) != len(uzbl.title): + tabtitle += "\xe2\x80\xa6" + + if show_gtk_tabs: + if tab_titles: + self.notebook.set_tab_label_text(tab, + gtk_tab_format % (index, tabtitle)) + + else: + self.notebook.set_tab_label_text(tab, str(index)) + + if show_tablist: + style = colour_selector(index, curpage, uzbl) + (tabc, textc) = style + + if multiline_tabs: + opango = pango + + if tab_titles: + pango += tab_format % (tabc, index, textc, + escape(tabtitle)) + + else: + pango += tab_format % (tabc, textc, index) + + self.tablist.set_markup(pango) + listwidth = self.tablist.get_layout().get_pixel_size()[0] + winwidth = self.window.get_size()[0] + + if listwidth > (winwidth - 20): + multiline.append(opango) + pango = tab_format % (tabc, index, textc, + escape(tabtitle)) + + elif tab_titles: + pango += tab_format % (tabc, index, textc, + escape(tabtitle)) + + else: + pango += tab_format % (tabc, textc, index) + + if show_tablist: + if multiline_tabs: + multiline.append(pango) + self.tablist.set_markup(' '.join(multiline)) + + else: + self.tablist.set_markup(pango) + + return True + + + def save_session(self, session_file=None): + '''Save the current session to file for restoration on next load.''' + + strip = str.strip + + if session_file is None: + session_file = config['session_file'] + + tabs = self.tabs.keys() + state = [] + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + if not uzbl.uri: continue + state += [(uzbl.uri, uzbl.title),] + + session = {'curtab': self.notebook.get_current_page(), + 'tabs': state} + + if config['json_session']: + raw = json.dumps(session) + + else: + lines = ["curtab = %d" % session['curtab'],] + for (uri, title) in session['tabs']: + lines += ["%s\t%s" % (strip(uri), strip(title)),] + + raw = "\n".join(lines) + + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + h = open(session_file, 'w') + h.write(raw) + h.close() + + + def load_session(self, session_file=None): + '''Load a saved session from file.''' + + default_path = False + strip = str.strip + json_session = config['json_session'] + delete_loaded = False + + if session_file is None: + default_path = True + delete_loaded = True + session_file = config['session_file'] + + if not os.path.isfile(session_file): + return False + + h = open(session_file, 'r') + raw = h.read() + h.close() + if json_session: + if sum([1 for s in raw.split("\n") if strip(s)]) != 1: + error("Warning: The session file %r does not look json. "\ + "Trying to load it as a non-json session file."\ + % session_file) + json_session = False + + if json_session: + try: + session = json.loads(raw) + curtab, tabs = session['curtab'], session['tabs'] + + except: + error("Failed to load jsonifed session from %r"\ + % session_file) + return None + + else: + tabs = [] + strip = str.strip + curtab, tabs = 0, [] + lines = [s for s in raw.split("\n") if strip(s)] + if len(lines) < 2: + error("Warning: The non-json session file %r looks invalid."\ + % session_file) + return None + + try: + for line in lines: + if line.startswith("curtab"): + curtab = int(line.split()[-1]) + + else: + uri, title = line.split("\t",1) + tabs += [(strip(uri), strip(title)),] + + except: + error("Warning: failed to load session file %r" % session_file) + return None + + session = {'curtab': curtab, 'tabs': tabs} + + # Now populate notebook with the loaded session. + for (index, (uri, title)) in enumerate(tabs): + self.new_tab(uri=uri, title=title, switch=(curtab==index)) + + # A saved session has been loaded now delete it. + if delete_loaded and os.path.exists(session_file): + os.remove(session_file) + + # There may be other state information in the session dict of use to + # other functions. Of course however the non-json session object is + # just a dummy object of no use to no one. + return session + + + def quitrequest(self, *args): + '''Attempt to close all uzbl instances nicely and exit.''' + + self._killed = True + + if config['save_session']: + if len(list(self.notebook)) > 1: + self.save_session() + + else: + # Notebook has one page open so delete the session file. + if os.path.isfile(config['session_file']): + os.remove(config['session_file']) + + for (tab, uzbl) in self.tabs.items(): + uzbl.send("exit") + + # Add a gobject timer to make sure the application force-quits after a + # reasonable period. Calling quit when all the tabs haven't had time to + # close should be a last resort. + timer = "force-quit" + timerid = timeout_add(5000, self.quit, timer) + self._timers[timer] = timerid + + + def quit(self, *args): + '''Cleanup and quit. Called by delete-event signal.''' + + # Close the fifo socket, remove any gobject io event handlers and + # delete socket. + self.unlink_fifo_socket() + + # Remove all gobject timers that are still ticking. + for (timerid, gid) in self._timers.items(): + source_remove(gid) + del self._timers[timerid] + + try: + gtk.main_quit() + + except: + pass + + +if __name__ == "__main__": + + # Read from the uzbl config into the global config dictionary. + readconfig(UZBL_CONFIG, config) + + # Build command line parser + usage = "usage: %prog [OPTIONS] {URIS}..." + parser = OptionParser(usage=usage) + parser.add_option('-n', '--no-session', dest='nosession', + action='store_true', help="ignore session saving a loading.") + parser.add_option('-v', '--verbose', dest='verbose', + action='store_true', help='print verbose output.') + + # Parse command line options + (options, uris) = parser.parse_args() + + if options.nosession: + config['save_session'] = False + + if options.verbose: + config['verbose'] = True + + if config['json_session']: + try: + import simplejson as json + + except: + error("Warning: json_session set but cannot import the python "\ + "module simplejson. Fix: \"set json_session = 0\" or "\ + "install the simplejson python module to remove this warning.") + config['json_session'] = False + + if config['verbose']: + import pprint + sys.stderr.write("%s\n" % pprint.pformat(config)) + + uzbl = UzblTabbed() + + # All extra arguments given to uzbl_tabbed.py are interpreted as + # web-locations to opened in new tabs. + lasturi = len(uris)-1 + for (index,uri) in enumerate(uris): + uzbl.new_tab(uri, switch=(index==lasturi)) + + uzbl.run() diff --git a/examples/data/uzbl/scripts/uzbl_tabbed.py b/examples/data/uzbl/scripts/uzbl_tabbed.py deleted file mode 100755 index bb9b9a2..0000000 --- a/examples/data/uzbl/scripts/uzbl_tabbed.py +++ /dev/null @@ -1,1474 +0,0 @@ -#!/usr/bin/env python - -# Uzbl tabbing wrapper using a fifo socket interface -# Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, Chris van Dijk -# Copyright (c) 2009, Mason Larobina -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# Author(s): -# Tom Adams -# Wrote the original uzbl_tabbed.py as a proof of concept. -# -# Chris van Dijk (quigybo) -# Made signifigant headway on the old uzbl_tabbing.py script on the -# uzbl wiki -# -# Mason Larobina -# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface -# and inherit configuration options from the user's uzbl config. -# -# Contributor(s): -# mxey -# uzbl_config path now honors XDG_CONFIG_HOME if it exists. -# -# Romain Bignon -# Fix for session restoration code. -# -# Jake Probst -# Wrote a patch that overflows tabs in the tablist on to new lines when -# running of room. -# -# Devon Jones -# Fifo command bring_to_front which brings the gtk window to focus. - - -# Dependencies: -# pygtk - python bindings for gtk. -# pango - python bindings needed for text rendering & layout in gtk widgets. -# pygobject - GLib's GObject bindings for python. -# -# Optional dependencies: -# simplejson - save uzbl_tabbed.py sessions & presets in json. -# -# Note: I haven't included version numbers with this dependency list because -# I've only ever tested uzbl_tabbed.py on the latest stable versions of these -# packages in Gentoo's portage. Package names may vary on different systems. - - -# Configuration: -# Because this version of uzbl_tabbed is able to inherit options from your main -# uzbl configuration file you may wish to configure uzbl tabbed from there. -# Here is a list of configuration options that can be customised and some -# example values for each: -# -# General tabbing options: -# show_tablist = 1 -# show_gtk_tabs = 0 -# tablist_top = 1 -# gtk_tab_pos = (top|left|bottom|right) -# gtk_refresh = 1000 -# switch_to_new_tabs = 1 -# capture_new_windows = 1 -# multiline_tabs = 1 -# -# Tab title options: -# tab_titles = 1 -# new_tab_title = Loading -# max_title_len = 50 -# show_ellipsis = 1 -# -# Session options: -# save_session = 1 -# json_session = 0 -# session_file = $HOME/.local/share/uzbl/session -# -# Inherited uzbl options: -# fifo_dir = /tmp -# socket_dir = /tmp -# icon_path = $HOME/.local/share/uzbl/uzbl.png -# status_background = #303030 -# -# Misc options: -# window_size = 800,800 -# verbose = 0 -# -# And the key bindings: -# bind_new_tab = gn -# bind_tab_from_clip = gY -# bind_tab_from_uri = go _ -# bind_close_tab = gC -# bind_next_tab = gt -# bind_prev_tab = gT -# bind_goto_tab = gi_ -# bind_goto_first = g< -# bind_goto_last = g> -# bind_clean_slate = gQ -# bind_exit = gZ -# -# Session preset key bindings: -# bind_save_preset = gsave _ -# bind_load_preset = gload _ -# bind_del_preset = gdel _ -# bind_list_presets = glist -# -# And uzbl_tabbed.py takes care of the actual binding of the commands via each -# instances fifo socket. -# -# Custom tab styling: -# tab_colours = foreground = "#888" background = "#303030" -# tab_text_colours = foreground = "#bbb" -# selected_tab = foreground = "#fff" -# selected_tab_text = foreground = "green" -# tab_indicate_https = 1 -# https_colours = foreground = "#888" -# https_text_colours = foreground = "#9c8e2d" -# selected_https = foreground = "#fff" -# selected_https_text = foreground = "gold" -# -# How these styling values are used are soley defined by the syling policy -# handler below (the function in the config section). So you can for example -# turn the tab text colour Firetruck-Red in the event "error" appears in the -# tab title or some other arbitrary event. You may wish to make a trusted -# hosts file and turn tab titles of tabs visiting trusted hosts purple. - - -# Issues: -# - new windows are not caught and opened in a new tab. -# - when uzbl_tabbed.py crashes it takes all the children with it. -# - when a new tab is opened when using gtk tabs the tab button itself -# grabs focus from its child for a few seconds. -# - when switch_to_new_tabs is not selected the notebook page is -# maintained but the new window grabs focus (try as I might to stop it). - - -# Todo: -# - add command line options to use a different session file, not use a -# session file and or open a uri on starup. -# - ellipsize individual tab titles when the tab-list becomes over-crowded -# - add "<" & ">" arrows to tablist to indicate that only a subset of the -# currently open tabs are being displayed on the tablist. -# - add the small tab-list display when both gtk tabs and text vim-like -# tablist are hidden (I.e. [ 1 2 3 4 5 ]) -# - check spelling. -# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into -# the collective. Resistance is futile! - - -import pygtk -import gtk -import subprocess -import os -import re -import time -import getopt -import pango -import select -import sys -import gobject -import socket -import random -import hashlib -import atexit -import types - -from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP -from signal import signal, SIGTERM, SIGINT -from optparse import OptionParser, OptionGroup - - -pygtk.require('2.0') - -_SCRIPTNAME = os.path.basename(sys.argv[0]) -def error(msg): - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return os.path.join(os.environ['HOME'], default) - -# Setup xdg paths. -DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') -CONFIG_DIR = os.path.join(xdghome('CONFIG', '.config/'), 'uzbl/') - -# Ensure uzbl xdg paths exist -for path in [DATA_DIR, CONFIG_DIR]: - if not os.path.exists(path): - os.makedirs(path) - -# Path to uzbl config -UZBL_CONFIG = os.path.join(CONFIG_DIR, 'config') -if not os.path.exists(UZBL_CONFIG): - error("cannot find uzbl config file at %r" % UZBL_CONFIG) - sys.exit(1) - -# All of these settings can be inherited from your uzbl config file. -config = { - # Tab options - 'show_tablist': True, # Show text uzbl like statusbar tab-list - 'show_gtk_tabs': False, # Show gtk notebook tabs - 'tablist_top': True, # Display tab-list at top of window - 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) - 'gtk_refresh': 1000, # Tablist refresh millisecond interval - 'switch_to_new_tabs': True, # Upon opening a new tab switch to it - 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows - 'multiline_tabs': True, # Tabs overflow onto new tablist lines. - - # Tab title options - 'tab_titles': True, # Display tab titles (else only tab-nums) - 'new_tab_title': 'Loading', # New tab title - 'max_title_len': 50, # Truncate title at n characters - 'show_ellipsis': True, # Show ellipsis when truncating titles - - # Session options - 'save_session': True, # Save session in file when quit - 'json_session': False, # Use json to save session. - 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'), - 'session_file': os.path.join(DATA_DIR, 'session'), - - # Inherited uzbl options - 'fifo_dir': '/tmp', # Path to look for uzbl fifo. - 'socket_dir': '/tmp', # Path to look for uzbl socket. - 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'), - 'status_background': "#303030", # Default background for all panels. - - # Misc options - 'window_size': "800,800", # width,height in pixels. - 'verbose': False, # Print verbose output. - - # Key bindings - 'bind_new_tab': 'gn', # Open new tab. - 'bind_tab_from_clip': 'gY', # Open tab from clipboard. - 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. - 'bind_close_tab': 'gC', # Close tab. - 'bind_next_tab': 'gt', # Next tab. - 'bind_prev_tab': 'gT', # Prev tab. - 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title). - 'bind_goto_first': 'g<', # Goto first tab. - 'bind_goto_last': 'g>', # Goto last tab. - 'bind_clean_slate': 'gQ', # Close all tabs and open new tab. - 'bind_exit': 'gZ', # Exit nicely. - - # Session preset key bindings - 'bind_save_preset': 'gsave _', # Save session to file %s. - 'bind_load_preset': 'gload _', # Load preset session from file %s. - 'bind_del_preset': 'gdel _', # Delete preset session %s. - 'bind_list_presets': 'glist', # List all session presets. - - # Add custom tab style definitions to be used by the tab colour policy - # handler here. Because these are added to the config dictionary like - # any other uzbl_tabbed configuration option remember that they can - # be superseeded from your main uzbl config file. - 'tab_colours': 'foreground = "#888" background = "#303030"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff"', - 'selected_tab_text': 'foreground = "green"', - 'tab_indicate_https': True, - 'https_colours': 'foreground = "#888"', - 'https_text_colours': 'foreground = "#9c8e2d"', - 'selected_https': 'foreground = "#fff"', - 'selected_https_text': 'foreground = "gold"', - -} # End of config dict. - -# This is the tab style policy handler. Every time the tablist is updated -# this function is called to determine how to colourise that specific tab -# according the simple/complex rules as defined here. You may even wish to -# move this function into another python script and import it using: -# from mycustomtabbingconfig import colour_selector -# Remember to rename, delete or comment out this function if you do that. - -def colour_selector(tabindex, currentpage, uzbl): - '''Tablist styling policy handler. This function must return a tuple of - the form (tab style, text style).''' - - # Just as an example: - # if 'error' in uzbl.title: - # if tabindex == currentpage: - # return ('foreground="#fff"', 'foreground="red"') - # return ('foreground="#888"', 'foreground="red"') - - # Style tabs to indicate connected via https. - if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): - if tabindex == currentpage: - return (config['selected_https'], config['selected_https_text']) - return (config['https_colours'], config['https_text_colours']) - - # Style to indicate selected. - if tabindex == currentpage: - return (config['selected_tab'], config['selected_tab_text']) - - # Default tab style. - return (config['tab_colours'], config['tab_text_colours']) - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def echo(msg): - if config['verbose']: - sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) - - -def readconfig(uzbl_config, config): - '''Loads relevant config from the users uzbl config file into the global - config dictionary.''' - - if not os.path.exists(uzbl_config): - error("Unable to load config %r" % uzbl_config) - return None - - # Define parsing regular expressions - isint = re.compile("^(\-|)[0-9]+$").match - findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ - re.MULTILINE).findall - - h = open(os.path.expandvars(uzbl_config), 'r') - rawconfig = h.read() - h.close() - - configkeys, strip = config.keys(), str.strip - for (key, value) in findsets(rawconfig): - key, value = strip(key), strip(value) - if key not in configkeys: continue - if isint(value): value = int(value) - config[key] = value - - # Ensure that config keys that relate to paths are expanded. - pathkeys = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path', - 'saved_sessions_dir'] - for key in pathkeys: - config[key] = os.path.expandvars(config[key]) - - -def counter(): - '''To infinity and beyond!''' - - i = 0 - while True: - i += 1 - yield i - - -def escape(s): - '''Replaces html markup in tab titles that screw around with pango.''' - - for (split, glue) in [('&','&'), ('<', '<'), ('>', '>')]: - s = s.replace(split, glue) - return s - - -def gen_endmarker(): - '''Generates a random md5 for socket message-termination endmarkers.''' - - return hashlib.md5(str(random.random()*time.time())).hexdigest() - - -class UzblTabbed: - '''A tabbed version of uzbl using gtk.Notebook''' - - class UzblInstance: - '''Uzbl instance meta-data/meta-action object.''' - - def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ - uri, title, switch): - - self.parent = parent - self.tab = tab - self.fifo_socket = fifo_socket - self.socket_file = socket_file - self.pid = pid - self.title = title - self.uri = uri - self.timers = {} - self._lastprobe = 0 - self._fifoout = [] - self._socketout = [] - self._socket = None - self._buffer = "" - # Switch to tab after loading - self._switch = switch - # fifo/socket files exists and socket connected. - self._connected = False - # The kill switch - self._kill = False - - # Message termination endmarker. - self._marker = gen_endmarker() - - # Gen probe commands string - probes = [] - probe = probes.append - probe('print uri %d @uri %s' % (self.pid, self._marker)) - probe('print title %d @@ %s' % (self.pid,\ - self._marker)) - self._probecmds = '\n'.join(probes) - - # Enqueue keybinding config for child uzbl instance - self.parent.config_uzbl(self) - - - def flush(self, timer_call=False): - '''Flush messages from the socket-out and fifo-out queues.''' - - if self._kill: - if self._socket: - self._socket.close() - self._socket = None - - error("Flush called on dead tab.") - return False - - if len(self._fifoout): - if os.path.exists(self.fifo_socket): - h = open(self.fifo_socket, 'w') - while len(self._fifoout): - msg = self._fifoout.pop(0) - h.write("%s\n"%msg) - h.close() - - if len(self._socketout): - if not self._socket and os.path.exists(self.socket_file): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(self.socket_file) - self._socket = sock - - if self._socket: - while len(self._socketout): - msg = self._socketout.pop(0) - self._socket.send("%s\n"%msg) - - if not self._connected and timer_call: - if not len(self._fifoout + self._socketout): - self._connected = True - - if timer_call in self.timers.keys(): - source_remove(self.timers[timer_call]) - del self.timers[timer_call] - - if self._switch: - self.grabfocus() - - return len(self._fifoout + self._socketout) - - - def grabfocus(self): - '''Steal parent focus and switch the notebook to my own tab.''' - - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) - self.parent.goto_tab(tabid) - - - def probe(self): - '''Probes the client for information about its self.''' - - if self._connected: - self.send(self._probecmds) - self._lastprobe = time.time() - - - def write(self, msg): - '''Child fifo write function.''' - - self._fifoout.append(msg) - # Flush messages from the queue if able. - return self.flush() - - - def send(self, msg): - '''Child socket send function.''' - - self._socketout.append(msg) - # Flush messages from queue if able. - return self.flush() - - - def __init__(self): - '''Create tablist, window and notebook.''' - - # Store information about the applications fifo_socket. - self._fifo = None - - self._timers = {} - self._buffer = "" - self._killed = False - - # A list of the recently closed tabs - self._closed = [] - - # Holds metadata on the uzbl childen open. - self.tabs = {} - - # Generates a unique id for uzbl socket filenames. - self.next_pid = counter().next - - # Create main window - self.window = gtk.Window() - try: - window_size = map(int, config['window_size'].split(',')) - self.window.set_default_size(*window_size) - - except: - error("Invalid value for default_size in config file.") - - self.window.set_title("Uzbl Browser") - self.window.set_border_width(0) - - # Set main window icon - icon_path = config['icon_path'] - if os.path.exists(icon_path): - self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) - - else: - icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' - if os.path.exists(icon_path): - self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) - - # Attach main window event handlers - self.window.connect("delete-event", self.quitrequest) - - # Create tab list - if config['show_tablist']: - vbox = gtk.VBox() - self.window.add(vbox) - ebox = gtk.EventBox() - self.tablist = gtk.Label() - - self.tablist.set_use_markup(True) - self.tablist.set_justify(gtk.JUSTIFY_LEFT) - self.tablist.set_line_wrap(False) - self.tablist.set_selectable(False) - self.tablist.set_padding(2,2) - self.tablist.set_alignment(0,0) - self.tablist.set_ellipsize(pango.ELLIPSIZE_END) - self.tablist.set_text(" ") - self.tablist.show() - ebox.add(self.tablist) - ebox.show() - bgcolor = gtk.gdk.color_parse(config['status_background']) - ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) - - # Create notebook - self.notebook = gtk.Notebook() - self.notebook.set_show_tabs(config['show_gtk_tabs']) - - # Set tab position - allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, - 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} - if config['gtk_tab_pos'] in allposes.keys(): - self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) - - self.notebook.set_show_border(False) - self.notebook.set_scrollable(True) - self.notebook.set_border_width(0) - - self.notebook.connect("page-removed", self.tab_closed) - self.notebook.connect("switch-page", self.tab_changed) - self.notebook.connect("page-added", self.tab_opened) - - self.notebook.show() - if config['show_tablist']: - if config['tablist_top']: - vbox.pack_start(ebox, False, False, 0) - vbox.pack_end(self.notebook, True, True, 0) - - else: - vbox.pack_start(self.notebook, True, True, 0) - vbox.pack_end(ebox, False, False, 0) - - vbox.show() - - else: - self.window.add(self.notebook) - - self.window.show() - self.wid = self.notebook.window.xid - # Generate the fifo socket filename. - fifo_filename = 'uzbltabbed_%d' % os.getpid() - self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - - # Now initialise the fifo socket at self.fifo_socket - self.init_fifo_socket() - - # If we are using sessions then load the last one if it exists. - if config['save_session']: - self.load_session() - - - def run(self): - '''UzblTabbed main function that calls the gtk loop.''' - - if not len(self.tabs): - self.new_tab() - - gtk_refresh = int(config['gtk_refresh']) - if gtk_refresh < 100: - gtk_refresh = 100 - - # Update tablist timer - timerid = timeout_add(gtk_refresh, self.update_tablist) - self._timers["update-tablist"] = timerid - - # Probe clients every second for window titles and location - timerid = timeout_add(gtk_refresh, self.probe_clients) - self._timers["probe-clients"] = timerid - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) - - # Catch keyboard interrupts - signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) - - try: - gtk.main() - - except: - error("encounted error %r" % sys.exc_info()[1]) - - # Unlink fifo socket - self.unlink_fifo_socket() - - # Attempt to close all uzbl instances nicely. - self.quitrequest() - - # Allow time for all the uzbl instances to quit. - time.sleep(1) - - raise - - - def terminate(self, termsig=None): - '''Handle termination signals and exit safely and cleanly.''' - - # Not required but at least it lets the user know what killed his - # browsing session. - if termsig == SIGTERM: - error("caught SIGTERM signal") - - elif termsig == SIGINT: - error("caught keyboard interrupt") - - else: - error("caught unknown signal") - - error("commencing infanticide!") - - # Sends the exit signal to all uzbl instances. - self.quitrequest() - - - def init_fifo_socket(self): - '''Create interprocess communication fifo socket.''' - - if os.path.exists(self.fifo_socket): - if not os.access(self.fifo_socket, os.F_OK | os.R_OK | os.W_OK): - os.mkfifo(self.fifo_socket) - - else: - basedir = os.path.dirname(self.fifo_socket) - if not os.path.exists(basedir): - os.makedirs(basedir) - - os.mkfifo(self.fifo_socket) - - # Add event handlers for IO_IN & IO_HUP events. - self.setup_fifo_watchers() - - echo("listening at %r" % self.fifo_socket) - - # Add atexit register to destroy the socket on program termination. - atexit.register(self.unlink_fifo_socket) - - - def unlink_fifo_socket(self): - '''Unlink the fifo socket. Note: This function is called automatically - on exit by an atexit register.''' - - # Make sure the fifo_socket fd is closed. - self.close_fifo() - - # And unlink if the real fifo_socket exists. - if os.path.exists(self.fifo_socket): - os.unlink(self.fifo_socket) - echo("unlinked %r" % self.fifo_socket) - - - 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_socket fd and kill all watchers - self.close_fifo() - - fd = os.open(self.fifo_socket, 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: - error("parse_command: invalid command %s" % ' '.join(cmd)) - raise - - return True - - - def probe_clients(self): - '''Probe all uzbl clients for up-to-date window titles and uri's.''' - - save_session = config['save_session'] - - sockd = {} - tabskeys = self.tabs.keys() - notebooklist = list(self.notebook) - - for tab in notebooklist: - if tab not in tabskeys: continue - uzbl = self.tabs[tab] - uzbl.probe() - if uzbl._socket: - sockd[uzbl._socket] = uzbl - - sockets = sockd.keys() - (reading, _, errors) = select.select(sockets, [], sockets, 0) - - for sock in reading: - uzbl = sockd[sock] - uzbl._buffer = sock.recv(1024).replace('\n',' ') - temp = uzbl._buffer.split(uzbl._marker) - 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: - 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. - # 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] == "newfromclip": - uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ - stdout=subprocess.PIPE).communicate()[0] - if uri: - self.new_tab(uri) - - elif cmd[0] == "close": - if len(cmd) == 2: - self.close_tab(int(cmd[1])) - - else: - self.close_tab() - - elif cmd[0] == "next": - if len(cmd) == 2: - self.next_tab(int(cmd[1])) - - else: - self.next_tab() - - elif cmd[0] == "prev": - if len(cmd) == 2: - self.prev_tab(int(cmd[1])) - - else: - self.prev_tab() - - elif cmd[0] == "goto": - self.goto_tab(int(cmd[1])) - - elif cmd[0] == "first": - self.goto_tab(0) - - elif cmd[0] == "last": - self.goto_tab(-1) - - elif cmd[0] in ["title", "uri"]: - if len(cmd) > 2: - uzbl = self.get_tab_by_pid(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 pid %r" % int(cmd[1])) - - elif cmd[0] == "preset": - if len(cmd) < 3: - error("parse_command: invalid preset command") - - elif cmd[1] == "save": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - self.save_session(path) - - elif cmd[1] == "load": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - self.load_session(path) - - elif cmd[1] == "del": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - if os.path.isfile(path): - os.remove(path) - - else: - error("parse_command: preset %r does not exist." % path) - - elif cmd[1] == "list": - uzbl = self.get_tab_by_pid(int(cmd[2])) - if uzbl: - if not os.path.isdir(config['saved_sessions_dir']): - js = "js alert('No saved presets.');" - uzbl.send(js) - - else: - listdir = os.listdir(config['saved_sessions_dir']) - listdir = "\\n".join(listdir) - js = "js alert('Session presets:\\n\\n%s');" % listdir - uzbl.send(js) - - else: - error("parse_command: unknown tab pid.") - - else: - error("parse_command: unknown parse command %r"\ - % ' '.join(cmd)) - - elif cmd[0] == "bring_to_front": - self.window.present() - - elif cmd[0] == "clean": - self.clean_slate() - - elif cmd[0] == "exit": - self.quitrequest() - - else: - error("parse_command: unknown command %r" % ' '.join(cmd)) - - - def get_tab_by_pid(self, pid): - '''Return uzbl instance by pid.''' - - for (tab, uzbl) in self.tabs.items(): - if uzbl.pid == pid: - return uzbl - - return False - - - def new_tab(self, uri='', title='', switch=None): - '''Add a new tab to the notebook and start a new instance of uzbl. - Use the switch option to negate config['switch_to_new_tabs'] option - when you need to load multiple tabs at a time (I.e. like when - restoring a session from a file).''' - - pid = self.next_pid() - tab = gtk.Socket() - tab.show() - self.notebook.append_page(tab) - sid = tab.get_id() - uri = uri.strip() - - fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) - fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) - socket_file = os.path.join(config['socket_dir'], socket_filename) - - if switch is None: - switch = config['switch_to_new_tabs'] - - if not title: - title = config['new_tab_title'] - - uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ - uri, title, switch) - - if len(uri): - uri = "--uri %r" % uri - - self.tabs[tab] = uzbl - cmd = 'uzbl-browser -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) - subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? - - # Add gobject timer to make sure the config is pushed when fifo socket - # has been created. - timerid = timeout_add(100, uzbl.flush, "flush-initial-config") - uzbl.timers['flush-initial-config'] = timerid - - self.update_tablist() - - - def clean_slate(self): - '''Close all open tabs and open a fresh brand new one.''' - - self.new_tab() - tabs = self.tabs.keys() - for tab in list(self.notebook)[:-1]: - if tab not in tabs: continue - uzbl = self.tabs[tab] - uzbl.send("exit") - - - def config_uzbl(self, uzbl): - '''Send bind commands for tab new/close/next/prev to a uzbl - instance.''' - - binds = [] - bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""' - bind = lambda key, action: binds.append(bind_format % (key, action,\ - self.fifo_socket)) - - sets = [] - set_format = r'set %s = sh \"echo \\"%s\\" > \\"%s\\""' - set = lambda key, action: binds.append(set_format % (key, action,\ - self.fifo_socket)) - - # Bind definitions here - # bind(key, command back to fifo) - bind(config['bind_new_tab'], 'new') - bind(config['bind_tab_from_clip'], 'newfromclip') - bind(config['bind_tab_from_uri'], 'new %s') - bind(config['bind_close_tab'], 'close') - bind(config['bind_next_tab'], 'next') - bind(config['bind_prev_tab'], 'prev') - bind(config['bind_goto_tab'], 'goto %s') - bind(config['bind_goto_first'], 'goto 0') - bind(config['bind_goto_last'], 'goto -1') - bind(config['bind_clean_slate'], 'clean') - bind(config['bind_save_preset'], 'preset save %s') - bind(config['bind_load_preset'], 'preset load %s') - bind(config['bind_del_preset'], 'preset del %s') - bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid) - bind(config['bind_exit'], 'exit') - - # Set definitions here - # set(key, command back to fifo) - if config['capture_new_windows']: - set("new_window", r'new $8') - - # Send config to uzbl instance via its socket file. - uzbl.send("\n".join(binds+sets)) - - - def goto_tab(self, index): - '''Goto tab n (supports negative indexing).''' - - tabs = list(self.notebook) - if 0 <= index < len(tabs): - self.notebook.set_current_page(index) - self.update_tablist() - return None - - try: - tab = tabs[index] - # Update index because index might have previously been a - # negative index. - index = tabs.index(tab) - self.notebook.set_current_page(index) - self.update_tablist() - - except IndexError: - pass - - - def next_tab(self, step=1): - '''Switch to next tab or n tabs right.''' - - if step < 1: - error("next_tab: invalid step %r" % step) - return None - - ntabs = self.notebook.get_n_pages() - tabn = (self.notebook.get_current_page() + step) % ntabs - self.notebook.set_current_page(tabn) - self.update_tablist() - - - def prev_tab(self, step=1): - '''Switch to prev tab or n tabs left.''' - - if step < 1: - error("prev_tab: invalid step %r" % step) - return None - - ntabs = self.notebook.get_n_pages() - tabn = self.notebook.get_current_page() - step - while tabn < 0: tabn += ntabs - self.notebook.set_current_page(tabn) - self.update_tablist() - - - def close_tab(self, tabn=None): - '''Closes current tab. Supports negative indexing.''' - - if tabn is None: - tabn = self.notebook.get_current_page() - - else: - try: - tab = list(self.notebook)[tabn] - - except IndexError: - error("close_tab: invalid index %r" % tabn) - return None - - self.notebook.remove_page(tabn) - - - def tab_opened(self, notebook, tab, index): - '''Called upon tab creation. Called by page-added signal.''' - - if config['switch_to_new_tabs']: - self.notebook.set_focus_child(tab) - - else: - oldindex = self.notebook.get_current_page() - oldtab = self.notebook.get_nth_page(oldindex) - self.notebook.set_focus_child(oldtab) - - - def tab_closed(self, notebook, tab, index): - '''Close the window if no tabs are left. Called by page-removed - signal.''' - - if tab in self.tabs.keys(): - uzbl = self.tabs[tab] - for (timer, gid) in uzbl.timers.items(): - error("tab_closed: removing timer %r" % timer) - source_remove(gid) - del uzbl.timers[timer] - - if uzbl._socket: - uzbl._socket.close() - uzbl._socket = None - - uzbl._fifoout = [] - uzbl._socketout = [] - uzbl._kill = True - self._closed.append((uzbl.uri, uzbl.title)) - self._closed = self._closed[-10:] - del self.tabs[tab] - - if self.notebook.get_n_pages() == 0: - if not self._killed and config['save_session']: - if os.path.exists(config['session_file']): - os.remove(config['session_file']) - - self.quit() - - self.update_tablist() - - return True - - - def tab_changed(self, notebook, page, index): - '''Refresh tab list. Called by switch-page signal.''' - - tab = self.notebook.get_nth_page(index) - self.notebook.set_focus_child(tab) - self.update_tablist(index) - return True - - - def update_tablist(self, curpage=None): - '''Upate tablist status bar.''' - - show_tablist = config['show_tablist'] - show_gtk_tabs = config['show_gtk_tabs'] - tab_titles = config['tab_titles'] - show_ellipsis = config['show_ellipsis'] - multiline_tabs = config['multiline_tabs'] - - if multiline_tabs: - multiline = [] - - if not show_tablist and not show_gtk_tabs: - return True - - tabs = self.tabs.keys() - if curpage is None: - curpage = self.notebook.get_current_page() - - title_format = "%s - Uzbl Browser" - max_title_len = config['max_title_len'] - - if show_tablist: - pango = "" - normal = (config['tab_colours'], config['tab_text_colours']) - selected = (config['selected_tab'], config['selected_tab_text']) - - if tab_titles: - tab_format = " [ %d %s ] " - - else: - tab_format = " [ %d ] " - - if show_gtk_tabs: - gtk_tab_format = "%d %s" - - for index, tab in enumerate(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - - if index == curpage: - self.window.set_title(title_format % uzbl.title) - - # Unicode heavy strings do not like being truncated/sliced so by - # re-encoding the string sliced of limbs are removed. - tabtitle = uzbl.title[:max_title_len + int(show_ellipsis)] - if type(tabtitle) != types.UnicodeType: - tabtitle = unicode(tabtitle, 'utf-8', 'ignore') - - tabtitle = tabtitle.encode('utf-8', 'ignore').strip() - - if show_ellipsis and len(tabtitle) != len(uzbl.title): - tabtitle += "\xe2\x80\xa6" - - if show_gtk_tabs: - if tab_titles: - self.notebook.set_tab_label_text(tab, - gtk_tab_format % (index, tabtitle)) - - else: - self.notebook.set_tab_label_text(tab, str(index)) - - if show_tablist: - style = colour_selector(index, curpage, uzbl) - (tabc, textc) = style - - if multiline_tabs: - opango = pango - - if tab_titles: - pango += tab_format % (tabc, index, textc, - escape(tabtitle)) - - else: - pango += tab_format % (tabc, textc, index) - - self.tablist.set_markup(pango) - listwidth = self.tablist.get_layout().get_pixel_size()[0] - winwidth = self.window.get_size()[0] - - if listwidth > (winwidth - 20): - multiline.append(opango) - pango = tab_format % (tabc, index, textc, - escape(tabtitle)) - - elif tab_titles: - pango += tab_format % (tabc, index, textc, - escape(tabtitle)) - - else: - pango += tab_format % (tabc, textc, index) - - if show_tablist: - if multiline_tabs: - multiline.append(pango) - self.tablist.set_markup(' '.join(multiline)) - - else: - self.tablist.set_markup(pango) - - return True - - - def save_session(self, session_file=None): - '''Save the current session to file for restoration on next load.''' - - strip = str.strip - - if session_file is None: - session_file = config['session_file'] - - tabs = self.tabs.keys() - state = [] - for tab in list(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - if not uzbl.uri: continue - state += [(uzbl.uri, uzbl.title),] - - session = {'curtab': self.notebook.get_current_page(), - 'tabs': state} - - if config['json_session']: - raw = json.dumps(session) - - else: - lines = ["curtab = %d" % session['curtab'],] - for (uri, title) in session['tabs']: - lines += ["%s\t%s" % (strip(uri), strip(title)),] - - raw = "\n".join(lines) - - if not os.path.isfile(session_file): - dirname = os.path.dirname(session_file) - if not os.path.isdir(dirname): - os.makedirs(dirname) - - h = open(session_file, 'w') - h.write(raw) - h.close() - - - def load_session(self, session_file=None): - '''Load a saved session from file.''' - - default_path = False - strip = str.strip - json_session = config['json_session'] - delete_loaded = False - - if session_file is None: - default_path = True - delete_loaded = True - session_file = config['session_file'] - - if not os.path.isfile(session_file): - return False - - h = open(session_file, 'r') - raw = h.read() - h.close() - if json_session: - if sum([1 for s in raw.split("\n") if strip(s)]) != 1: - error("Warning: The session file %r does not look json. "\ - "Trying to load it as a non-json session file."\ - % session_file) - json_session = False - - if json_session: - try: - session = json.loads(raw) - curtab, tabs = session['curtab'], session['tabs'] - - except: - error("Failed to load jsonifed session from %r"\ - % session_file) - return None - - else: - tabs = [] - strip = str.strip - curtab, tabs = 0, [] - lines = [s for s in raw.split("\n") if strip(s)] - if len(lines) < 2: - error("Warning: The non-json session file %r looks invalid."\ - % session_file) - return None - - try: - for line in lines: - if line.startswith("curtab"): - curtab = int(line.split()[-1]) - - else: - uri, title = line.split("\t",1) - tabs += [(strip(uri), strip(title)),] - - except: - error("Warning: failed to load session file %r" % session_file) - return None - - session = {'curtab': curtab, 'tabs': tabs} - - # Now populate notebook with the loaded session. - for (index, (uri, title)) in enumerate(tabs): - self.new_tab(uri=uri, title=title, switch=(curtab==index)) - - # A saved session has been loaded now delete it. - if delete_loaded and os.path.exists(session_file): - os.remove(session_file) - - # There may be other state information in the session dict of use to - # other functions. Of course however the non-json session object is - # just a dummy object of no use to no one. - return session - - - def quitrequest(self, *args): - '''Attempt to close all uzbl instances nicely and exit.''' - - self._killed = True - - if config['save_session']: - if len(list(self.notebook)) > 1: - self.save_session() - - else: - # Notebook has one page open so delete the session file. - if os.path.isfile(config['session_file']): - os.remove(config['session_file']) - - for (tab, uzbl) in self.tabs.items(): - uzbl.send("exit") - - # Add a gobject timer to make sure the application force-quits after a - # reasonable period. Calling quit when all the tabs haven't had time to - # close should be a last resort. - timer = "force-quit" - timerid = timeout_add(5000, self.quit, timer) - self._timers[timer] = timerid - - - def quit(self, *args): - '''Cleanup and quit. Called by delete-event signal.''' - - # Close the fifo socket, remove any gobject io event handlers and - # delete socket. - self.unlink_fifo_socket() - - # Remove all gobject timers that are still ticking. - for (timerid, gid) in self._timers.items(): - source_remove(gid) - del self._timers[timerid] - - try: - gtk.main_quit() - - except: - pass - - -if __name__ == "__main__": - - # Read from the uzbl config into the global config dictionary. - readconfig(UZBL_CONFIG, config) - - # Build command line parser - usage = "usage: %prog [OPTIONS] {URIS}..." - parser = OptionParser(usage=usage) - parser.add_option('-n', '--no-session', dest='nosession', - action='store_true', help="ignore session saving a loading.") - parser.add_option('-v', '--verbose', dest='verbose', - action='store_true', help='print verbose output.') - - # Parse command line options - (options, uris) = parser.parse_args() - - if options.nosession: - config['save_session'] = False - - if options.verbose: - config['verbose'] = True - - if config['json_session']: - try: - import simplejson as json - - except: - error("Warning: json_session set but cannot import the python "\ - "module simplejson. Fix: \"set json_session = 0\" or "\ - "install the simplejson python module to remove this warning.") - config['json_session'] = False - - if config['verbose']: - import pprint - sys.stderr.write("%s\n" % pprint.pformat(config)) - - uzbl = UzblTabbed() - - # All extra arguments given to uzbl_tabbed.py are interpreted as - # web-locations to opened in new tabs. - lasturi = len(uris)-1 - for (index,uri) in enumerate(uris): - uzbl.new_tab(uri, switch=(index==lasturi)) - - uzbl.run() diff --git a/uzbl-browser b/uzbl-browser index 5ff72e9..86da2e5 100755 --- a/uzbl-browser +++ b/uzbl-browser @@ -50,7 +50,7 @@ fi if [ ! -S $XDG_CACHE_HOME/uzbl/cookie_daemon_socket ] then # if you want to customize it, copy to your $XDG_DATA_HOME/uzbl/scripts/ and update $PATH - cookie_daemon.py + uzbl-cookie-daemon fi DAEMON_SOCKET=$XDG_CACHE_HOME/uzbl/event_daemon @@ -58,7 +58,7 @@ DAEMON_PID=${DAEMON_SOCKET}.pid #if [ -f "$DAEMON_PID" ] #then - event_manager.py -va start + uzbl-event-manager -va start #fi uzbl-core "$@" --connect-socket $DAEMON_SOCKET | grep -v ^EVENT -- cgit v1.2.3 From ce7554c5951526ab5a392bb4b384ec090cc24d15 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 11 Nov 2009 12:08:59 +0100 Subject: correctly handle potentially different prefix in sample/default config --- Makefile | 2 ++ examples/config/uzbl/config | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/Makefile b/Makefile index b0cb868..321ec82 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,7 @@ uzbl-core: ${OBJ} uzbl-browser: uzbl-core # packagers, set DESTDIR to your "package directory" and PREFIX to the prefix you want to have on the end-user system +# end-users who build from source: don't care about DESTDIR, update PREFIX if you want to PREFIX?=/usr/local INSTALLDIR?=$(DESTDIR)$(PREFIX) @@ -102,6 +103,7 @@ install-uzbl-browser: all install -m755 examples/data/uzbl/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager sed -i 's#^PREFIX=.*#PREFIX=$(PREFIX)#' $(INSTALLDIR)/bin/uzbl-browser sed -i "s#^PREFIX = None#PREFIX = '$(PREFIX)'#" $(INSTALLDIR)/bin/uzbl-event-manager + sed -i 's#^set prefix.*=.*#set prefix = $(PREFIX)#' $(INSTALLDIR)/share/uzbl/examples/config/uzbl/config install-uzbl-tabbed: all install -d $(INSTALLDIR)/bin diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 090ebd2..33783ac 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,6 +1,8 @@ # example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) +set prefix = /usr/local + # === Shortcuts ============================================================== # request BIND = @@ -21,7 +23,7 @@ set set_status = set status_message = set shell_cmd = sh -c # Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" -set scripts_dir = $XDG_DATA_HOME/uzbl:/usr/local/share/uzbl/examples/data/uzbl:scripts +set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts # === Handlers =============================================================== -- cgit v1.2.3 From c265d083baa9246f7b1ed425272187a91daa41e5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 11 Nov 2009 19:43:17 +0800 Subject: Give all instances access to the global config dict. --- examples/data/uzbl/scripts/uzbl-event-manager | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index dee42c5..eb4a470 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -335,6 +335,10 @@ class EventHandler(object): class UzblInstance(object): + + # Give all plugins access to the main config dict. + config = config + def __init__(self, parent, client_socket): # Internal variables. -- cgit v1.2.3 From 8fff4f72cd23a1881c8ee8d776a924acfb877955 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 11 Nov 2009 19:53:55 +0800 Subject: Remove useless echo command in on_event.py --- examples/data/uzbl/plugins/on_event.py | 5 ----- 1 file changed, 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index 242f9b0..3dfc3fa 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -18,16 +18,11 @@ Usage: import sys import re -from event_manager import config __export__ = ['get_on_events', 'on_event'] UZBLS = {} -def echo(msg): - if config['verbose']: - print 'on_event plugin:', msg - def error(msg): sys.stderr.write('on_event plugin: error: %s\n' % msg) -- cgit v1.2.3 From 2b74e733ba85215d8256c7dd573e16a6957196e5 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 11 Nov 2009 20:01:34 +0800 Subject: Remove useless event manager imports. --- examples/data/uzbl/plugins/bind.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index b8494fe..89b0831 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -11,7 +11,6 @@ And it is also possible to execute a function on activation: import sys import re -from event_manager import config, counter, iscallable, isiterable # Export these variables/functions to uzbl. __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] @@ -31,11 +30,6 @@ class BindParseError(Exception): pass -def echo(msg): - if config['verbose']: - print 'bind plugin:', msg - - def error(msg): sys.stderr.write('bind plugin: error: %s\n' % msg) @@ -132,10 +126,11 @@ def del_bind_by_glob(uzbl, glob): class Bind(object): - nextbid = counter().next + # Class attribute to hold the number of Bind classes created. + counter = [0,] def __init__(self, glob, handler, *args, **kargs): - self.is_callable = iscallable(handler) + self.is_callable = callable(handler) self._repr_cache = None if not glob: @@ -149,14 +144,17 @@ class Bind(object): elif kargs: raise ArgumentError('cannot supply kargs for uzbl commands') - elif isiterable(handler): + elif hasattr(handler, '__iter__'): self.commands = handler else: self.commands = [handler,] + list(args) self.glob = glob - self.bid = self.nextbid() + + # Assign unique id. + self.counter[0] += 1 + self.bid = self.counter[0] self.split = split = find_prompts(glob) self.prompts = [] -- cgit v1.2.3 From 788ef986832528a3f276beb906e7efeeec94b172 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Wed, 11 Nov 2009 15:31:20 +0100 Subject: simplify PREFIX logic in EM --- Makefile | 2 +- examples/data/uzbl/scripts/uzbl-event-manager | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/Makefile b/Makefile index 321ec82..0a4bd84 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ install-uzbl-browser: all install -m755 examples/data/uzbl/scripts/uzbl-cookie-daemon $(INSTALLDIR)/bin/uzbl-cookie-daemon install -m755 examples/data/uzbl/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager sed -i 's#^PREFIX=.*#PREFIX=$(PREFIX)#' $(INSTALLDIR)/bin/uzbl-browser - sed -i "s#^PREFIX = None#PREFIX = '$(PREFIX)'#" $(INSTALLDIR)/bin/uzbl-event-manager + sed -i "s#^PREFIX = .*#PREFIX = '$(PREFIX)'#" $(INSTALLDIR)/bin/uzbl-event-manager sed -i 's#^set prefix.*=.*#set prefix = $(PREFIX)#' $(INSTALLDIR)/share/uzbl/examples/config/uzbl/config install-uzbl-tabbed: all diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index eb4a470..8f43836 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -45,12 +45,8 @@ from traceback import print_exc # ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: # ============================================================================ -# Automagically set during `make install` -PREFIX = None - -# Check if PREFIX not set and set to default /usr/local/ -if not PREFIX: - PREFIX = '/usr/local/' +# `make install` will put the correct value here for your system +PREFIX = '/usr/local/' def xdghome(key, default): '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise -- cgit v1.2.3 From d23d26b84d76dcd0839d55602345e72a297d0049 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 19 Nov 2009 20:39:18 +0800 Subject: General bugfixes in the bind plugin. 1. Use sets in the keycmd plugin for the held list. 2. Remove the bind filter function in the bind plugin. 3. Compare the mod_cmd and keylet.held sets instead of using a string comparison to determine if the user is holding down the correct modkeys for any given bind. 4. Raise exceptions instead of printing errors in the bind plugin. 5. Raise the builtin SyntaxError exception for parsing failures. --- examples/data/uzbl/plugins/bind.py | 92 ++++++++++++++---------------------- examples/data/uzbl/plugins/keycmd.py | 7 ++- 2 files changed, 38 insertions(+), 61 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 89b0831..ea04af6 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -12,10 +12,10 @@ And it is also possible to execute a function on activation: import sys import re -# Export these variables/functions to uzbl. +# Export these functions to uzbl. __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] -# Hold the bind lists per uzbl instance. +# Hold the bind dicts for each uzbl instance. UZBLS = {} # Commonly used regular expressions. @@ -23,15 +23,7 @@ starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') find_prompts = re.compile('<([^:>]*):(\"[^\"]*\"|\'[^\']*\'|[^>]*)>').split # For accessing a bind glob stack. -MOD_CMD, ON_EXEC, HAS_ARGS, GLOB, MORE = range(5) - - -class BindParseError(Exception): - pass - - -def error(msg): - sys.stderr.write('bind plugin: error: %s\n' % msg) +ON_EXEC, HAS_ARGS, MOD_CMD, GLOB, MORE = range(5) def ismodbind(glob): @@ -40,25 +32,25 @@ def ismodbind(glob): return bool(starts_with_mod.match(glob)) -def sort_mods(glob): - '''Mods are sorted in the keylet.to_string() result so make sure that - bind commands also have their mod keys sorted.''' +def split_glob(glob): + '''Take a string of the form "cmd _" and return a list of the + modkeys in the glob and the command.''' - mods = [] + mods = set() while True: match = starts_with_mod.match(glob) if not match: break end = match.span()[1] - mods.append(glob[:end]) + mods.add(glob[:end].strip("<>")) glob = glob[end:] - return '%s%s' % (''.join(sorted(mods)), glob) + return (mods, glob) def add_instance(uzbl, *args): - UZBLS[uzbl] = {'binds': [], 'depth': 0, 'filter': [], + UZBLS[uzbl] = {'binds': [], 'depth': 0, 'stack': [], 'args': [], 'last_mode': ''} @@ -94,7 +86,7 @@ def get_filtered_binds(uzbl): bind_dict = get_bind_dict(uzbl) if bind_dict['depth']: - return list(bind_dict['filter']) + return list(bind_dict['stack']) return list(bind_dict['binds']) @@ -169,13 +161,13 @@ class Bind(object): for glob in split[:-1:3]: if glob.endswith('*'): msg = "token '*' not at the end of a prompt bind: %r" % split - raise BindParseError(msg) + raise SyntaxError(msg) # Check that there is nothing like: fl_ for glob in split[3::3]: if not glob: msg = 'found null segment after first prompt: %r' % split - raise BindParseError(msg) + raise SyntaxError(msg) stack = [] for (index, glob) in enumerate(reversed(split[::3])): @@ -189,7 +181,8 @@ class Bind(object): has_args = True if glob[-1] in ['*', '_'] else False glob = glob[:-1] if has_args else glob - stack.append((mod_cmd, on_exec, has_args, glob, index)) + mods, glob = split_glob(glob) + stack.append((on_exec, has_args, mods, glob, index)) self.stack = list(reversed(stack)) self.is_global = (len(self.stack) == 1 and self.stack[0][MOD_CMD]) @@ -259,7 +252,6 @@ def bind(uzbl, glob, handler, *args, **kargs): # Mods come from the keycmd sorted so make sure the modkeys in the bind # command are sorted too. - glob = sort_mods(glob) del_bind_by_glob(uzbl, glob) binds = get_binds(uzbl) @@ -275,11 +267,11 @@ def parse_bind_event(uzbl, args): '''Break "event BIND fl* = js follownums.js" into (glob, command).''' if not args: - return error('missing bind arguments') + raise ArgumentError('missing bind arguments') split = map(unicode.strip, args.split('=', 1)) if len(split) != 2: - return error('missing "=" in bind definition: %r' % args) + raise ArgumentError('missing delimiter in bind: %r' % args) glob, command = split bind(uzbl, glob, command) @@ -307,40 +299,30 @@ def clear_stack(uzbl, mode): if mode != "stack": bind_dict = get_bind_dict(uzbl) - bind_dict['filter'] = [] + bind_dict['stack'] = [] bind_dict['depth'] = 0 bind_dict['args'] = [] bind_dict['last_mode'] = mode -def filter_bind(uzbl, bind_dict, bind): - '''Remove a bind from the stack filter list.''' - - if bind in bind_dict['filter']: - bind_dict['filter'].remove(bind) - - if not bind_dict['filter']: - uzbl.set_mode() +def match_and_exec(uzbl, bind, depth, keylet, mod_event=False): + bind_dict = get_bind_dict(uzbl) + (on_exec, has_args, mod_cmd, glob, more) = bind[depth] + held = keylet.held + cmd = keylet.modcmd if mod_cmd else keylet.keycmd -def match_and_exec(uzbl, bind, depth, keycmd): - bind_dict = get_bind_dict(uzbl) - (mod_cmd, on_exec, has_args, glob, more) = bind[depth] + if mod_cmd and held != mod_cmd: + return False if has_args: - if not keycmd.startswith(glob): - if not mod_cmd: - filter_bind(uzbl, bind_dict, bind) - + if not cmd.startswith(glob): return False - args = [keycmd[len(glob):],] - - elif keycmd != glob: - if not mod_cmd: - filter_bind(uzbl, bind_dict, bind) + args = [cmd[len(glob):],] + elif cmd != glob: return False else: @@ -356,12 +338,12 @@ def match_and_exec(uzbl, bind, depth, keycmd): elif more: if bind_dict['depth'] == depth: globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] - bind_dict['filter'] = [bind,] + globalcmds + bind_dict['stack'] = [bind,] + globalcmds bind_dict['args'] += args bind_dict['depth'] = depth + 1 - elif bind not in bind_dict['filter']: - bind_dict['filter'].append(bind) + elif bind not in bind_dict['stack']: + bind_dict['stack'].append(bind) set_stack_mode(uzbl, bind.prompts[depth]) return False @@ -377,49 +359,45 @@ def match_and_exec(uzbl, bind, depth, keycmd): def keycmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.get_keycmd() for bind in get_filtered_binds(uzbl): t = bind[depth] if t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keycmd): + if match_and_exec(uzbl, bind, depth, keylet): return def keycmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.get_keycmd() for bind in get_filtered_binds(uzbl): t = bind[depth] if t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keycmd): + if match_and_exec(uzbl, bind, depth, keylet): return uzbl.clear_keycmd() def modcmd_update(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.get_modcmd() for bind in get_filtered_binds(uzbl): t = bind[depth] if not t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keycmd): + if match_and_exec(uzbl, bind, depth, keylet): return def modcmd_exec(uzbl, keylet): depth = get_stack_depth(uzbl) - keycmd = keylet.get_modcmd() for bind in get_filtered_binds(uzbl): t = bind[depth] if not t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keycmd): + if match_and_exec(uzbl, bind, depth, keylet): return uzbl.clear_modcmd() diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 8961f74..976eee7 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -31,7 +31,7 @@ class Keylet(object): def __init__(self): # Modcmd tracking - self.held = [] + self.held = set() self.modcmd = '' self.is_modcmd = False @@ -169,7 +169,7 @@ def clear_modcmd(uzbl, clear_held=False): k.is_modcmd = False k._repr_cache = False if clear_held: - k.held = [] + k.held = set() config = uzbl.get_config() if 'modcmd' not in config or config['modcmd'] != '': @@ -271,8 +271,7 @@ def key_press(uzbl, key): k.held.remove('Tab') if key not in k.held: - k.held.append(key) - k.held.sort() + k.held.add(key) else: k.is_modcmd = True -- cgit v1.2.3 From 59f9ed764aaf87a4fefaa5d4501b5b5ce215a723 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 19 Nov 2009 21:29:08 +0800 Subject: Allow single character modkeys using modmaps. Example: @modmap @modmap @bind q = exit --- examples/data/uzbl/plugins/bind.py | 2 +- examples/data/uzbl/plugins/keycmd.py | 40 +++++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index ea04af6..530cc80 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -43,7 +43,7 @@ def split_glob(glob): break end = match.span()[1] - mods.add(glob[:end].strip("<>")) + mods.add(glob[:end]) glob = glob[end:] return (mods, glob) diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 976eee7..0477303 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -58,7 +58,7 @@ class Keylet(object): if not self.is_modcmd: return '' - return ''.join(['<%s>' % key for key in self.held]) + self.modcmd + return ''.join(self.held) + self.modcmd def key_modmap(self, key): @@ -99,6 +99,10 @@ def add_modmap(uzbl, key, map=None): '''Add modmaps.''' keylet = get_keylet(uzbl) + + if key[0] == "<" and key[-1] == ">": + key = key[1:-1] + if not map: if key in keylet.modmap: map = keylet.modmap[key] @@ -233,6 +237,16 @@ def inject_str(str, index, inj): return "%s%s%s" % (str[:index], inj, str[index:]) +def chevronate(key): + '''If a modkey isn't already chevronated then chevronate it. Ignore all + other keys.''' + + if len(key) == 1: + return key + + return "<%s>" % key.strip("<>") + + def key_press(uzbl, key): '''Handle KEY_PRESS events. Things done by this function include: @@ -243,15 +257,13 @@ def key_press(uzbl, key): 5. If in modcmd mode the pressed key is added to the held keys list. 6. Keycmd is updated and events raised if anything is changed.''' - if key.startswith('Shift_'): - return - k = get_keylet(uzbl) - key = k.key_modmap(key.strip()) - if key.startswith("ISO_"): + key = chevronate(k.key_modmap(key.strip())) + + if key.startswith("': return - if key == 'Space' and not k.held and k.keycmd: + if key.lower() == '' and not k.held and k.keycmd: k.keycmd = inject_str(k.keycmd, k.cursor, ' ') k.cursor += 1 @@ -267,8 +279,8 @@ def key_press(uzbl, key): elif len(key) > 1: k.is_modcmd = True - if key == 'Shift-Tab' and 'Tab' in k.held: - k.held.remove('Tab') + if key == '' and '' in k.held: + k.held.remove('') if key not in k.held: k.held.add(key) @@ -289,13 +301,13 @@ def key_release(uzbl, key): 4. Update the keycmd uzbl variable if anything changed.''' k = get_keylet(uzbl) - key = k.key_modmap(key) + key = chevronate(k.key_modmap(key)) - if key in ['Shift', 'Tab'] and 'Shift-Tab' in k.held: - key = 'Shift-Tab' + if key in ['', ''] and '' in k.held: + key = '' - elif key in ['Shift', 'Alt'] and 'Meta' in k.held: - key = 'Meta' + elif key in ['', ''] and '' in k.held: + key = '' if key in k.held: if k.is_modcmd: -- cgit v1.2.3 From c65aa88f0a4065089a1a3cedd814dedde6254513 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 19 Nov 2009 22:50:11 +0800 Subject: Added key ignoring by glob pattern and modmapping cleanup. --- examples/config/uzbl/config | 17 ++++++---- examples/data/uzbl/plugins/keycmd.py | 63 +++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 28 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 33783ac..46b4998 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -17,6 +17,8 @@ set on_event = request ON_EVENT set progress = request PROGRESS_CONFIG # request MODMAP From To set modmap = request MODMAP +# request KEY_IGNORE +set ignore_key = request IGNORE_KEY set set_mode = set mode = set set_status = set status_message = @@ -102,15 +104,18 @@ set fifo_dir = /tmp set socket_dir = /tmp -# === Binding modmaps ======================================================== +# === Key modmapping and ignoring ============================================ -#modmap from to -@modmap Control Ctrl -@modmap ISO_Left_Tab Shift-Tab -@modmap space Space +#modmap from to +@modmap +@modmap +@modmap +#ignore_key +@ignore_key +@ignore_key -# === Keyboard & Mouse bindings ====================================================== +# === Keyboard & Mouse bindings ============================================== # With this command you can enter in any command at runtime when prefixed with # a colon. diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 0477303..1d263d3 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -2,7 +2,7 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. __export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', - 'clear_current', 'clear_modcmd', 'add_modmap'] + 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore'] # Hold the keylets. UZBLS = {} @@ -39,8 +39,8 @@ class Keylet(object): self.keycmd = '' self.cursor = 0 - # Key modmaps. - self.modmap = {} + self.modmaps = {} + self.ignores = {} # Keylet string repr cache. self._repr_cache = None @@ -61,20 +61,30 @@ class Keylet(object): return ''.join(self.held) + self.modcmd - def key_modmap(self, key): + def modmap_key(self, key): '''Make some obscure names for some keys friendlier.''' - if key in self.modmap: - return self.modmap[key] + if key in self.modmaps: + return self.modmaps[key] elif key.endswith('_L') or key.endswith('_R'): # Remove left-right discrimination and try again. - return self.key_modmap(key[:-2]) + return self.modmap_key(key[:-2]) else: return key + def key_ignored(self, key): + '''Check if the given key is ignored by any ignore rules.''' + + for (glob, match) in self.ignores.items(): + if match(key): + return True + + return False + + def __repr__(self): '''Return a string representation of the keylet.''' @@ -95,23 +105,17 @@ class Keylet(object): return self._repr_cache -def add_modmap(uzbl, key, map=None): +def add_modmap(uzbl, key, map): '''Add modmaps.''' - keylet = get_keylet(uzbl) + assert len(key) + modmaps = get_keylet(uzbl).modmaps if key[0] == "<" and key[-1] == ">": key = key[1:-1] - if not map: - if key in keylet.modmap: - map = keylet.modmap[key] - del keylet.modmap[key] - uzbl.event("DEL_MODMAP", key, map) - - else: - keylet.modmap[key] = map - uzbl.event("NEW_MODMAP", key, map) + modmaps[key] = map + uzbl.event("NEW_MODMAP", key, map) def modmap_parse(uzbl, map): @@ -125,6 +129,20 @@ def modmap_parse(uzbl, map): add_modmap(uzbl, *split) +def add_key_ignore(uzbl, glob): + '''Add an ignore definition.''' + + assert len(glob) > 1 + ignores = get_keylet(uzbl).ignores + + glob = "<%s>" % glob.strip("<> ") + restr = glob.replace('*', '[^\s]*') + match = re.compile(restr).match + + ignores[glob] = match + uzbl.event('NEW_KEY_IGNORE', glob) + + def add_instance(uzbl, *args): '''Create the Keylet object for this uzbl instance.''' @@ -258,9 +276,9 @@ def key_press(uzbl, key): 6. Keycmd is updated and events raised if anything is changed.''' k = get_keylet(uzbl) - key = chevronate(k.key_modmap(key.strip())) + key = chevronate(k.modmap_key(key.strip())) - if key.startswith("': + if k.key_ignored(key): return if key.lower() == '' and not k.held and k.keycmd: @@ -301,7 +319,7 @@ def key_release(uzbl, key): 4. Update the keycmd uzbl variable if anything changed.''' k = get_keylet(uzbl) - key = chevronate(k.key_modmap(key)) + key = chevronate(k.modmap_key(key)) if key in ['', ''] and '' in k.held: key = '' @@ -438,6 +456,7 @@ def init(uzbl): 'FOCUS_GAINED': focus_changed, 'MODMAP': modmap_parse, 'APPEND_KEYCMD': append_keycmd, - 'INJECT_KEYCMD': inject_keycmd} + 'INJECT_KEYCMD': inject_keycmd, + 'IGNORE_KEY': add_key_ignore} uzbl.connect_dict(connects) -- cgit v1.2.3 From ba0f52ab830159ca1d3d3ce92ff2f08ede8eca1c Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 19 Nov 2009 22:56:55 +0800 Subject: Remove test ignore from config. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 46b4998..5c51115 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -113,7 +113,7 @@ set socket_dir = /tmp #ignore_key @ignore_key -@ignore_key +@ignore_key # === Keyboard & Mouse bindings ============================================== -- cgit v1.2.3 From b788c11278eb77d5fe402fd7150794cac0a4948b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 19 Nov 2009 22:58:22 +0800 Subject: Fix comment in config. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 5c51115..a4151bb 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -17,7 +17,7 @@ set on_event = request ON_EVENT set progress = request PROGRESS_CONFIG # request MODMAP From To set modmap = request MODMAP -# request KEY_IGNORE +# request IGNORE_KEY set ignore_key = request IGNORE_KEY set set_mode = set mode = -- cgit v1.2.3 From 8a52115e7da225174a12f078fa593fd684115531 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 21 Nov 2009 00:43:40 +0800 Subject: Alpha keycmd completion plugin commit. A few bugs remaining. --- examples/config/uzbl/config | 3 +- examples/data/uzbl/plugins/completion.py | 175 +++++++++++++++++++++++++++++++ examples/data/uzbl/plugins/config.py | 2 +- examples/data/uzbl/plugins/keycmd.py | 3 +- 4 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 examples/data/uzbl/plugins/completion.py (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a4151bb..3dcc103 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -73,7 +73,7 @@ set prompt_style = foreground="grey" set cursor_style = underline="single" set mode_section = [\@[\@mode_indicator]\@] -set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd] +set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd] \@completion_list set progress_section = \@[\@progress_format]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ @@ -243,6 +243,7 @@ set formfiller = spawn @scripts_dir/formfiller @bind = event SET_CURSOR_POS + @bind = event KEYCMD_BACKSPACE @bind = event KEYCMD_DELETE +@bind = event START_COMPLETION # readline-ish bindings @bind w = event KEYCMD_STRIP_WORD diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py new file mode 100644 index 0000000..df3b139 --- /dev/null +++ b/examples/data/uzbl/plugins/completion.py @@ -0,0 +1,175 @@ +'''Keycmd completion.''' + +# A list of functions this plugin exports to be used via uzbl object. +__export__ = ['start_completion', 'get_completion_dict'] + +import re + +# Holds the per-instance completion dicts. +UZBLS = {} + +# Completion level +NONE, ONCE, LIST = range(3) + +# Default instance dict. +DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} + +# The reverse keyword finding re. +FIND_SEGMENT = re.compile("(\@[\w_]+|[\w_]+)$").findall + +# Formats +LIST_FORMAT = "[ %s ]" +ITEM_FORMAT = "%s%s" + + +def escape(str): + return str.replace("@", "\@") + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_completion_dict(uzbl): + '''Get data stored for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_incomplete_cmd(uzbl): + '''Gets the segment of the keycmd leading up to the cursor position and + uses a regular expression to search backwards finding parially completed + keywords or @variables. Returns a null string if the correct completion + conditions aren't met.''' + + keylet = uzbl.get_keylet() + left_segment = keylet.keycmd[:keylet.cursor] + return (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() + + +def stop_completion(uzbl, *args): + d = get_completion_dict(uzbl) + d['level'] = NONE + uzbl.set('completion_list') + + +def complete_completion(uzbl, partial, hint): + '''Inject the remaining porition of the keyword into the keycmd then stop + the completioning.''' + + remainder = "%s " % hint[len(partial):] + uzbl.inject_keycmd(remainder) + stop_completion(uzbl) + + +def partial_completion(uzbl, partial, hint): + '''Inject a common portion of the hints into the keycmd.''' + + remainder = hint[len(partial):] + uzbl.inject_keycmd(remainder) + + +def start_completion(uzbl, start=True): + + d = get_completion_dict(uzbl) + if d['lock'] or not start and not d['level']: + return + + partial = get_incomplete_cmd(uzbl) + if not partial: + return stop_completion(uzbl) + + if d['level'] < LIST: + d['level'] += 1 + + hints = [h for h in d['completions'] if h.startswith(partial)] + if not hints: + return + + elif len(hints) == 1: + d['lock'] = True + complete_completion(uzbl, partial, hints[0]) + d['lock'] = False + return + + elif partial in hints: + d['lock'] = True + complete_completion(uzbl, partial, partial) + d['lock'] = False + return + + smalllen, smallest = sorted([(len(h), h) for h in hints])[0] + common = '' + for i in range(len(partial), smalllen): + char, same = smallest[i], True + for hint in hints: + if hint[i] != char: + same = False + break + + if not same: + break + + common += char + + if common: + d['lock'] = True + partial_completion(uzbl, partial, partial+common) + d['lock'] = False + + partial += common + if d['level'] == LIST: + j = len(partial) + l = [ITEM_FORMAT % (h[:j], h[j:]) for h in sorted(hints)] + print l + uzbl.set('completion_list', escape(LIST_FORMAT % ' '.join(l))) + + +def add_builtins(uzbl, args): + '''Pump the space delimited list of builtin commands into the + builtin list.''' + + completions = get_completion_dict(uzbl)['completions'] + builtins = filter(None, map(unicode.strip, args.split(" "))) + for builtin in builtins: + if builtin not in completions: + completions.append(builtin) + + +def add_config_key(uzbl, key, value): + '''Listen on the CONFIG_CHANGED event and add config keys to the variable + list for @var like expansion support.''' + + completions = get_completion_dict(uzbl)['completions'] + key = "@%s" % key + if key not in completions: + completions.append(key) + + +def init(uzbl): + connects = { + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'BUILTINS': add_builtins, + 'CONFIG_CHANGED': add_config_key, + } + + # And connect the dicts event handlers to the handler stack. + uzbl.connect_dict(connects) + + for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEAR']: + uzbl.connect(event, stop_completion) + + uzbl.connect('START_COMPLETION', + lambda uzbl, args: start_completion(uzbl)) + + uzbl.connect('KEYCMD_UPDATE', + lambda uzbl, args: start_completion(uzbl, False)) diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py index 22803b4..57c2403 100644 --- a/examples/data/uzbl/plugins/config.py +++ b/examples/data/uzbl/plugins/config.py @@ -22,7 +22,7 @@ def get_config(uzbl): return UZBLS[uzbl] -def set(uzbl, key, value): +def set(uzbl, key, value=''): '''Sends a: "set key = value" command to the uzbl instance.''' if type(value) == types.BooleanType: diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 1d263d3..82c95f8 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -2,7 +2,8 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. __export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', - 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore'] + 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore', + 'append_keycmd', 'inject_keycmd'] # Hold the keylets. UZBLS = {} -- cgit v1.2.3 From b90611fc5bc3ab82b0d0255bbe942fe3c437d274 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 21 Nov 2009 06:19:06 +0800 Subject: Fixed keycmd blanking issue. --- examples/data/uzbl/plugins/keycmd.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 82c95f8..76f4463 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -240,9 +240,9 @@ def update_event(uzbl, k, execute=True): if 'keycmd_events' in config and config['keycmd_events'] != '1': return - new_keycmd = k.get_keycmd() - if not new_keycmd or new_keycmd != keycmd: - return uzbl.set('keycmd', '') + keycmd = k.get_keycmd() + if not keycmd: + return uzbl.set('keycmd') # Generate the pango markup for the cursor in the keycmd. curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' -- cgit v1.2.3 From bf33a2b30a69c7603db98f16542dd90a61e9c056 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Mon, 23 Nov 2009 11:24:10 +0000 Subject: Fix security holes * Please be careful when using eval, you rarely need it. * There might be more issues, I haven't checked any of the bigger python scripts, plugins, or the C code. Signed-off-by: Andy Spencer --- examples/data/uzbl/scripts/clipboard.sh | 2 +- examples/data/uzbl/scripts/download.sh | 4 ++-- examples/data/uzbl/scripts/scheme.py | 5 +++-- examples/data/uzbl/scripts/yank.sh | 7 ++----- 4 files changed, 8 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh index 60567d3..d493774 100755 --- a/examples/data/uzbl/scripts/clipboard.sh +++ b/examples/data/uzbl/scripts/clipboard.sh @@ -11,7 +11,7 @@ url="$7" selection=`$clip -o` case $action in - "yank" ) echo -n "$url" | eval "$clip";; + "yank" ) echo -n "$url" | $clip;; "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh index c8eb6ba..55b0cb2 100755 --- a/examples/data/uzbl/scripts/download.sh +++ b/examples/data/uzbl/scripts/download.sh @@ -16,7 +16,7 @@ test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } # only changes the dir for the $get sub process if echo "$url" | grep -E '.*\.torrent' >/dev/null; then - ( cd "$dest"; eval "$GET" "$url") + ( cd "$dest"; $GET "$url" ) else - ( cd "$dest"; eval "$GET" "$url") + ( cd "$dest"; $GET "$url" ) fi diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index 7286703..0916466 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -16,8 +16,9 @@ if __name__ == '__main__': uri = sys.argv[8] u = urlparse.urlparse(uri) if u.scheme == 'mailto': - detach_open(['xterm', '-e', 'mail %s' % u.path]) + detach_open(['xterm', '-e', 'mail', u.path]) elif u.scheme == 'xmpp': + # Someone check for safe arguments to gajim-remote detach_open(['gajim-remote', 'open_chat', uri]) elif u.scheme == 'git': - detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src')) + detach_open(['git', 'clone', '--', uri], cwd=os.path.expanduser('~/src')) diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh index 376b7e2..6785d64 100755 --- a/examples/data/uzbl/scripts/yank.sh +++ b/examples/data/uzbl/scripts/yank.sh @@ -9,9 +9,6 @@ clip=xclip which $clip &>/dev/null || exit 1 -[ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2 +[ "$9" = primary -o "$9" = secondary -o "$9" = clipboard ] || exit 2 -value=`eval "echo -n \\${$8}"` # bash: value = ${!8} - -echo "echo -n '${value}' | $clip -selection $9" -echo -n "'${value}' | $clip -selection $9" +echo -n "$8" | $clip -selection $9 -- cgit v1.2.3 From f12bfe4243e5b337033a555986db08a0ab2e6c29 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 23 Nov 2009 23:28:44 +0800 Subject: Respect the keycmd_updates var and don't raise KEYCMD_UPDATES at all. --- examples/data/uzbl/plugins/keycmd.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 76f4463..b1e8299 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -97,7 +97,7 @@ class Keylet(object): l.append('modcmd=%r' % self.get_modcmd()) elif self.held: - l.append('held=%r' % ''.join(['<%s>'%key for key in self.held])) + l.append('held=%r' % ''.join(sorted(self.held))) if self.keycmd: l.append('keycmd=%r' % self.get_keycmd()) @@ -178,8 +178,8 @@ def clear_keycmd(uzbl): k.cursor = 0 k._repr_cache = False config = uzbl.get_config() - if 'keycmd' not in config or config['keycmd'] != '': - uzbl.set('keycmd', '') + if 'keycmd' not in config or config['keycmd']: + uzbl.set('keycmd') uzbl.event('KEYCMD_CLEAR') @@ -195,8 +195,8 @@ def clear_modcmd(uzbl, clear_held=False): k.held = set() config = uzbl.get_config() - if 'modcmd' not in config or config['modcmd'] != '': - uzbl.set('modcmd', '') + if 'modcmd' not in config or config['modcmd']: + uzbl.set('modcmd') uzbl.event('MODCMD_CLEAR') @@ -288,13 +288,16 @@ def key_press(uzbl, key): elif not k.held and len(key) == 1: config = uzbl.get_config() - if 'keycmd_events' not in config or config['keycmd_events'] == '1': - k.keycmd = inject_str(k.keycmd, k.cursor, key) - k.cursor += 1 - - elif k.keycmd: + if 'keycmd_events' in config and config['keycmd_events'] != '1': k.keycmd = '' k.cursor = 0 + if config['keycmd']: + uzbl.set('keycmd') + + return + + k.keycmd = inject_str(k.keycmd, k.cursor, key) + k.cursor += 1 elif len(key) > 1: k.is_modcmd = True -- cgit v1.2.3 From 56fbba912984070b50cca1320e514e92cf834f43 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 00:17:41 +0800 Subject: Added in distinction between START_COMPLETION events and keycmd updates. --- examples/config/uzbl/config | 4 ++- examples/data/uzbl/plugins/completion.py | 50 ++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 19 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 3dcc103..8abe554 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -71,9 +71,11 @@ set modcmd_style = weight="bold" foreground="red" set keycmd_style = weight="light" foreground="red" set prompt_style = foreground="grey" set cursor_style = underline="single" +set completion_style = foreground="green" +set hint_style = weight="bold" set mode_section = [\@[\@mode_indicator]\@] -set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd] \@completion_list +set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd\@completion_list] set progress_section = \@[\@progress_format]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index df3b139..2da42ba 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -18,8 +18,8 @@ DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} FIND_SEGMENT = re.compile("(\@[\w_]+|[\w_]+)$").findall # Formats -LIST_FORMAT = "[ %s ]" -ITEM_FORMAT = "%s%s" +LIST_FORMAT = " %s " +ITEM_FORMAT = "%s%s" def escape(str): @@ -44,7 +44,7 @@ def get_completion_dict(uzbl): return UZBLS[uzbl] -def get_incomplete_cmd(uzbl): +def get_incomplete_keyword(uzbl): '''Gets the segment of the keycmd leading up to the cursor position and uses a regular expression to search backwards finding parially completed keywords or @variables. Returns a null string if the correct completion @@ -56,6 +56,8 @@ def get_incomplete_cmd(uzbl): def stop_completion(uzbl, *args): + '''Stop command completion and return the level to NONE.''' + d = get_completion_dict(uzbl) d['level'] = NONE uzbl.set('completion_list') @@ -77,13 +79,34 @@ def partial_completion(uzbl, partial, hint): uzbl.inject_keycmd(remainder) -def start_completion(uzbl, start=True): +def update_completion_list(uzbl, *args): + '''Checks if the user still has a partially completed keyword under his + cursor then update the completion hints list.''' + + partial = get_incomplete_keyword(uzbl) + if not partial: + return stop_completion(uzbl) d = get_completion_dict(uzbl) - if d['lock'] or not start and not d['level']: + if d['level'] != LIST: return - partial = get_incomplete_cmd(uzbl) + hints = [h for h in d['completions'] if h.startswith(partial)] + if not hints: + return uzbl.set('completion_list') + + j = len(partial) + l = [ITEM_FORMAT % (escape(h[:j]), h[j:]) for h in sorted(hints)] + uzbl.set('completion_list', LIST_FORMAT % ' '.join(l)) + + +def start_completion(uzbl, *args): + + d = get_completion_dict(uzbl) + if d['lock']: + return + + partial = get_incomplete_keyword(uzbl) if not partial: return stop_completion(uzbl) @@ -125,12 +148,7 @@ def start_completion(uzbl, start=True): partial_completion(uzbl, partial, partial+common) d['lock'] = False - partial += common - if d['level'] == LIST: - j = len(partial) - l = [ITEM_FORMAT % (h[:j], h[j:]) for h in sorted(hints)] - print l - uzbl.set('completion_list', escape(LIST_FORMAT % ' '.join(l))) + update_completion_list(uzbl) def add_builtins(uzbl, args): @@ -160,6 +178,8 @@ def init(uzbl): 'INSTANCE_EXIT': del_instance, 'BUILTINS': add_builtins, 'CONFIG_CHANGED': add_config_key, + 'KEYCMD_UPDATE': update_completion_list, + 'START_COMPLETION': start_completion, } # And connect the dicts event handlers to the handler stack. @@ -167,9 +187,3 @@ def init(uzbl): for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEAR']: uzbl.connect(event, stop_completion) - - uzbl.connect('START_COMPLETION', - lambda uzbl, args: start_completion(uzbl)) - - uzbl.connect('KEYCMD_UPDATE', - lambda uzbl, args: start_completion(uzbl, False)) -- cgit v1.2.3 From 7512da2ab5d2fd4e844879876ba7bbe447275f4f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 18:48:39 +0800 Subject: Put whitespace around modcmd. --- examples/data/uzbl/plugins/keycmd.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index b1e8299..8a509bb 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -234,8 +234,11 @@ def update_event(uzbl, k, execute=True): if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': new_modcmd = k.get_modcmd() - if not new_modcmd or new_modcmd == modcmd: - uzbl.set('modcmd', uzbl_escape(new_modcmd)) + if not new_modcmd: + uzbl.set('modcmd') + + elif new_modcmd == modcmd: + uzbl.set('modcmd', " %s " % uzbl_escape(new_modcmd)) if 'keycmd_events' in config and config['keycmd_events'] != '1': return -- cgit v1.2.3 From 0d0d5e42e4e94385e7fd16c4b7725e58b7985fa4 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 18:49:16 +0800 Subject: Remove redundant print in bind. --- examples/data/uzbl/plugins/bind.py | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 530cc80..5557aeb 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -259,7 +259,6 @@ def bind(uzbl, glob, handler, *args, **kargs): bind = Bind(glob, handler, *args, **kargs) binds.append(bind) - print bind uzbl.event('ADDED_BIND', bind) -- cgit v1.2.3 From 2c23115387a668eff89e7dc048f565a3971174e0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 18:50:27 +0800 Subject: Fixed ':_' binding in the config. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 8abe554..5945985 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -121,7 +121,7 @@ set socket_dir = /tmp # With this command you can enter in any command at runtime when prefixed with # a colon. -@bind :_ = chain '%s' +@bind :_ = %s # Middle click # if clicked on a link open the link in a new uzbl window -- cgit v1.2.3 From 0e7d35e4512bf576a2bd3096c24905a711ab2666 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 18:51:33 +0800 Subject: Mode plugin cleanup & removed hardcoded KEY_PRESS action. --- examples/data/uzbl/plugins/mode.py | 43 +++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index e7705a0..74e805a 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -7,7 +7,6 @@ UZBLS = {} DEFAULTS = { 'mode': '', - 'default': '', 'modes': { 'insert': { 'forward_keys': True, @@ -20,8 +19,8 @@ DEFAULTS = { 'modcmd_updates': True, 'indicator': 'C'}}} -_RE_FINDSPACES = re.compile("\s+") - +FINDSPACES = re.compile("\s+") +VALID_KEY = re.compile("^[\w_]+$").match def error(msg): sys.stderr.write("mode plugin: error: %s\n" % msg) @@ -55,24 +54,22 @@ def get_mode(uzbl): return get_mode_dict(uzbl)['mode'] -def key_press(uzbl, key): - if key != "Escape": - return - - set_mode(uzbl) - - def set_mode(uzbl, mode=None): mode_dict = get_mode_dict(uzbl) + config = uzbl.get_config() + if mode is None: - if not mode_dict['default']: - return error("no default mode to fallback on") + if 'default_mode' not in config: + return - mode = mode_dict['default'] + mode = config['default_mode'] + + if not VALID_KEY(mode): + raise KeyError("invalid mode name: %r" % mode) - config = uzbl.get_config() if 'mode' not in config or config['mode'] != mode: config['mode'] = mode + return mode_dict['mode'] = mode mode_config = get_mode_config(uzbl, mode) @@ -92,31 +89,30 @@ def set_mode(uzbl, mode=None): def config_changed(uzbl, key, value): + value = None if not value else value if key == 'default_mode': - mode_dict = get_mode_dict(uzbl) - mode_dict['default'] = value - if value and not mode_dict['mode']: + if not get_mode(uzbl): set_mode(uzbl, value) elif key == 'mode': - if not value: - value = None - set_mode(uzbl, value) def mode_config(uzbl, args): - split = map(unicode.strip, _RE_FINDSPACES.split(args.lstrip(), 1)) + split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1)) if len(split) != 2: - return error("invalid MODE_CONFIG syntax: %r" % args) + raise SyntaxError('invalid config syntax: %r' % args) mode, set = split split = map(unicode.strip, set.split('=', 1)) if len(split) != 2: - return error("invalid MODE_CONFIG set command: %r" % args) + raise SyntaxError('invalid set syntax: %r' % args) key, value = split + if not VALID_KEY(key): + raise KeyError('invalid config key: %r' % key) + mode_config = get_mode_config(uzbl, mode) mode_config[key] = value @@ -150,7 +146,6 @@ def init(uzbl): connects = {'CONFIG_CHANGED': config_changed, 'INSTANCE_EXIT': del_instance, 'INSTANCE_START': add_instance, - 'KEY_PRESS': key_press, 'MODE_CONFIG': mode_config, 'LOAD_START': load_reset, 'TOGGLE_MODES': toggle_modes} -- cgit v1.2.3 From 17fc947a49fd65adffd847628c4701e0bc10f965 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 18:54:02 +0800 Subject: Indent event printing & strip outgoing commands. --- examples/data/uzbl/scripts/uzbl-event-manager | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 8f43836..0054ff6 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -343,6 +343,7 @@ class UzblInstance(object): self._parent = parent self._client_socket = client_socket + self.depth = 0 self.buffer = '' # Call the init() function in every plugin. Inside the init function @@ -397,12 +398,13 @@ class UzblInstance(object): def send(self, msg): '''Send a command to the uzbl instance via the socket file.''' + msg = msg.strip() if self._client_socket: - print '<-- %s' % msg + print '%s<-- %s' % (' ' * self.depth, msg) self._client_socket.send(("%s\n" % msg).encode('utf-8')) else: - print '!-- %s' % msg + print '%s!-- %s' % (' ' * self.depth, msg) def connect(self, event, handler, *args, **kargs): @@ -468,18 +470,22 @@ class UzblInstance(object): # Silence _printing_ of geo events while debugging. if event != "GEOMETRY_CHANGED": - print "--> %s %s %s" % (event, args, '' if not kargs else kargs) + print "%s--> %s %s %s" % (' ' * self.depth, event, args, + '' if not kargs else kargs) if event not in self._handlers: return for handler in self._handlers[event]: + self.depth += 1 try: self.exec_handler(handler, *args, **kargs) except: print_exc() + self.depth -= 1 + def close(self): '''Close the client socket and clean up.''' -- cgit v1.2.3 From f7eeee9955f99d4acbfc90c7dc00b50767a15e07 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 21:09:36 +0800 Subject: Fixed extreme security hole in scheme.py allowing arbitrary command execution on the users pc. --- examples/data/uzbl/scripts/scheme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index 7286703..a54476f 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -16,7 +16,7 @@ if __name__ == '__main__': uri = sys.argv[8] u = urlparse.urlparse(uri) if u.scheme == 'mailto': - detach_open(['xterm', '-e', 'mail %s' % u.path]) + detach_open(['xterm', '-e', 'mail %r' % u.path]) elif u.scheme == 'xmpp': detach_open(['gajim-remote', 'open_chat', uri]) elif u.scheme == 'git': -- cgit v1.2.3 From 46005a341732359013572564f299901838eb7c2b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 24 Nov 2009 22:14:32 +0800 Subject: Revert stupid idea of using %@ instead of %s. --- examples/data/uzbl/plugins/on_event.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index 3dfc3fa..afee4e6 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -1,7 +1,7 @@ '''Plugin provides arbitrary binding of uzbl events to uzbl commands. Formatting options: - %@ = space separated string of the arguments + %s = space separated string of the arguments %1 = argument 1 %2 = argument 2 %n = argument n @@ -45,10 +45,10 @@ def get_on_events(uzbl): def expand(cmd, args): - '''Replaces "%@ %1 %2 %3..." with " ...".''' + '''Replaces "%s %1 %2 %3..." with " ...".''' - if '%@' in cmd: - cmd = cmd.replace('%@', ' '.join(map(unicode, args))) + if '%s' in cmd: + cmd = cmd.replace('%s', ' '.join(map(unicode, args))) for (index, arg) in enumerate(args): index += 1 -- cgit v1.2.3 From 2138add3e391bbc08b386fcfcb02ed6f4616248b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 25 Nov 2009 07:17:35 +0800 Subject: Use js for conditional binding & fix \wiki bind. --- examples/config/uzbl/config | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 5945985..ed522cc 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -125,8 +125,10 @@ set socket_dir = /tmp # Middle click # if clicked on a link open the link in a new uzbl window -# otherwise open the selection in the current window -@bind = sh 'if [ "\@SELECTED_URI" ]; then uzbl-browser -u \@SELECTED_URI; else echo "uri $(xclip -o)" > $4; fi' +# otherwise open the selection in the current window1 +set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' +set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' +@bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } @bind j = scroll vertical 20 @bind = scroll vertical 100% @@ -157,7 +159,7 @@ set socket_dir = /tmp @bind gh = uri http://www.uzbl.org # shortcut to set variables @bind s _ = set %s -@bind \wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +@bind \\wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go @bind gg _ = uri http://www.google.com/search?q=%s # Enclose the executable in quotes if it has spaces. Any additional parameters you use will # appear AFTER the default parameters -- cgit v1.2.3 From 940435ccef2ac6c129b4d999cc4f1d6e210beb54 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 25 Nov 2009 09:06:57 +0800 Subject: Complete partials as variables when preceded with 'set '. --- examples/data/uzbl/plugins/completion.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index 2da42ba..ee42b1f 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -15,7 +15,7 @@ NONE, ONCE, LIST = range(3) DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} # The reverse keyword finding re. -FIND_SEGMENT = re.compile("(\@[\w_]+|[\w_]+)$").findall +FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall # Formats LIST_FORMAT = " %s " @@ -52,7 +52,11 @@ def get_incomplete_keyword(uzbl): keylet = uzbl.get_keylet() left_segment = keylet.keycmd[:keylet.cursor] - return (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() + partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() + if partial.startswith('set '): + partial = '@%s' % partial[4:].lstrip() + + return partial def stop_completion(uzbl, *args): -- cgit v1.2.3 From c2d23b2fbbd8a930623efa907247ce1df5b8b4ec Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 25 Nov 2009 09:22:41 +0800 Subject: Set completions also complete the '='. --- examples/data/uzbl/plugins/completion.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index ee42b1f..cfdf901 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -54,9 +54,9 @@ def get_incomplete_keyword(uzbl): left_segment = keylet.keycmd[:keylet.cursor] partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() if partial.startswith('set '): - partial = '@%s' % partial[4:].lstrip() + return ('@%s' % partial[4:].lstrip(), True) - return partial + return (partial, False) def stop_completion(uzbl, *args): @@ -67,11 +67,16 @@ def stop_completion(uzbl, *args): uzbl.set('completion_list') -def complete_completion(uzbl, partial, hint): +def complete_completion(uzbl, partial, hint, set_completion=False): '''Inject the remaining porition of the keyword into the keycmd then stop the completioning.''' - remainder = "%s " % hint[len(partial):] + if set_completion: + remainder = "%s = " % hint[len(partial):] + + else: + remainder = "%s " % hint[len(partial):] + uzbl.inject_keycmd(remainder) stop_completion(uzbl) @@ -87,7 +92,7 @@ def update_completion_list(uzbl, *args): '''Checks if the user still has a partially completed keyword under his cursor then update the completion hints list.''' - partial = get_incomplete_keyword(uzbl) + partial = get_incomplete_keyword(uzbl)[0] if not partial: return stop_completion(uzbl) @@ -110,7 +115,7 @@ def start_completion(uzbl, *args): if d['lock']: return - partial = get_incomplete_keyword(uzbl) + (partial, set_completion) = get_incomplete_keyword(uzbl) if not partial: return stop_completion(uzbl) @@ -123,13 +128,13 @@ def start_completion(uzbl, *args): elif len(hints) == 1: d['lock'] = True - complete_completion(uzbl, partial, hints[0]) + complete_completion(uzbl, partial, hints[0], set_completion) d['lock'] = False return elif partial in hints: d['lock'] = True - complete_completion(uzbl, partial, partial) + complete_completion(uzbl, partial, partial, set_completion) d['lock'] = False return -- cgit v1.2.3 From c8c56da8799c25e787bcdcd1fdd7bdc33db6d204 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 25 Nov 2009 09:28:15 +0800 Subject: Show the completion list before completing when partial in hints list. --- examples/data/uzbl/plugins/completion.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index cfdf901..42e7e17 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -9,7 +9,7 @@ import re UZBLS = {} # Completion level -NONE, ONCE, LIST = range(3) +NONE, ONCE, LIST, COMPLETE = range(4) # Default instance dict. DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} @@ -97,7 +97,7 @@ def update_completion_list(uzbl, *args): return stop_completion(uzbl) d = get_completion_dict(uzbl) - if d['level'] != LIST: + if d['level'] < LIST: return hints = [h for h in d['completions'] if h.startswith(partial)] @@ -119,7 +119,7 @@ def start_completion(uzbl, *args): if not partial: return stop_completion(uzbl) - if d['level'] < LIST: + if d['level'] < COMPLETE: d['level'] += 1 hints = [h for h in d['completions'] if h.startswith(partial)] @@ -132,7 +132,7 @@ def start_completion(uzbl, *args): d['lock'] = False return - elif partial in hints: + elif partial in hints and d['level'] == COMPLETE: d['lock'] = True complete_completion(uzbl, partial, partial, set_completion) d['lock'] = False -- cgit v1.2.3 From 59f8345ba294b00db7ccb0b7fd3cbbdda6c26252 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 25 Nov 2009 19:01:32 +0800 Subject: Forgot to clear the keycmd if no default value being set. --- examples/data/uzbl/plugins/bind.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 5557aeb..509363d 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -290,6 +290,9 @@ def set_stack_mode(uzbl, prompt): # Go through uzbl-core to expand potential @-variables uzbl.send('event SET_KEYCMD %s' % set) + else: + uzbl.clear_keycmd() + def clear_stack(uzbl, mode): bind_dict = get_bind_dict(uzbl) -- cgit v1.2.3 From 780caeed5ecbf3d0b3fda7ec87c471bf50d6c777 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 26 Nov 2009 23:15:35 +0800 Subject: Removed stack mode requirement for stacked bindings in bind plugin. --- examples/config/uzbl/config | 9 ----- examples/data/uzbl/plugins/bind.py | 70 ++++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 43 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index ed522cc..62b5315 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -273,7 +273,6 @@ menu_link_add Print Link = print \@SELECTED_URI # Define some mode specific uzbl configurations. set command = @mode_config command set insert = @mode_config insert -set stack = @mode_config stack # Command mode config. @command keycmd_style = foreground="red" @@ -284,14 +283,6 @@ set stack = @mode_config stack @insert status_background = #303030 @insert mode_indicator = Ins -# Multi-stage-binding mode config. -@stack keycmd_events = 1 -@stack modcmd_updates = 1 -@stack keycmd_style = foreground="red" -@stack prompt_style = foreground="#888" weight="light" -@stack status_background = #202020 -@stack mode_indicator = Bnd - set default_mode = command # Mode bindings: diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 509363d..4976a80 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -17,6 +17,7 @@ __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] # Hold the bind dicts for each uzbl instance. UZBLS = {} +DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': []} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') @@ -50,8 +51,7 @@ def split_glob(glob): def add_instance(uzbl, *args): - UZBLS[uzbl] = {'binds': [], 'depth': 0, 'stack': [], - 'args': [], 'last_mode': ''} + UZBLS[uzbl] = dict(DEFAULTS) def del_instance(uzbl, *args): @@ -276,39 +276,50 @@ def parse_bind_event(uzbl, args): bind(uzbl, glob, command) -def set_stack_mode(uzbl, prompt): - prompt, set = prompt - if uzbl.get_mode() != 'stack': - uzbl.set_mode('stack') +def clear_stack(uzbl, mode): + '''Clear everything related to stacked binds.''' + + bind_dict = get_bind_dict(uzbl) + bind_dict['stack'] = [] + bind_dict['depth'] = 0 + bind_dict['args'] = [] + + uzbl.set('keycmd_prompt', '') + + +def stack_bind(uzbl, bind, args, depth): + '''Increment the stack depth in the bind dict, generate filtered bind + list for stack mode and set keycmd prompt.''' + + bind_dict = get_bind_dict(uzbl) + if bind_dict['depth'] != depth: + if bind not in bind_dict['stack']: + bind_dict['stack'].append(bind) + + return + + globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] + bind_dict['stack'] = [bind,] + globalcmds + bind_dict['args'] += args + bind_dict['depth'] = depth + 1 + uzbl.send('event BIND_STACK_LEVEL %d' % bind_dict['depth']) + + (prompt, set) = bind.prompts[depth] if prompt: - prompt = "%s: " % prompt + uzbl.set('keycmd_prompt', '%s:' % prompt) - uzbl.set('keycmd_prompt', prompt) + else: + uzbl.set('keycmd_prompt') if set: - # Go through uzbl-core to expand potential @-variables uzbl.send('event SET_KEYCMD %s' % set) else: uzbl.clear_keycmd() -def clear_stack(uzbl, mode): - bind_dict = get_bind_dict(uzbl) - if mode != "stack" and bind_dict['last_mode'] == "stack": - uzbl.set('keycmd_prompt', '') - - if mode != "stack": - bind_dict = get_bind_dict(uzbl) - bind_dict['stack'] = [] - bind_dict['depth'] = 0 - bind_dict['args'] = [] - - bind_dict['last_mode'] = mode - - -def match_and_exec(uzbl, bind, depth, keylet, mod_event=False): +def match_and_exec(uzbl, bind, depth, keylet): bind_dict = get_bind_dict(uzbl) (on_exec, has_args, mod_cmd, glob, more) = bind[depth] @@ -338,16 +349,7 @@ def match_and_exec(uzbl, bind, depth, keylet, mod_event=False): return True elif more: - if bind_dict['depth'] == depth: - globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] - bind_dict['stack'] = [bind,] + globalcmds - bind_dict['args'] += args - bind_dict['depth'] = depth + 1 - - elif bind not in bind_dict['stack']: - bind_dict['stack'].append(bind) - - set_stack_mode(uzbl, bind.prompts[depth]) + stack_bind(uzbl, bind, args, depth) return False args = bind_dict['args'] + args -- cgit v1.2.3 From 932d77bd50196a2c665e5d65de732b1349ed1925 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 28 Nov 2009 15:35:58 +0800 Subject: Added modkey addition to keycmd plugin. We are now able to remove the hardcoded "+ -> " and "+ -> " modkey transformations from the key_press and key_release functions. --- examples/config/uzbl/config | 9 ++- examples/data/uzbl/plugins/keycmd.py | 127 ++++++++++++++++++++++++++++------- 2 files changed, 111 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 62b5315..dc91e59 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -19,6 +19,8 @@ set progress = request PROGRESS_CONFIG set modmap = request MODMAP # request IGNORE_KEY set ignore_key = request IGNORE_KEY +# request MODKEY_ADDITION +set modkey_addition = request MODKEY_ADDITION set set_mode = set mode = set set_status = set status_message = @@ -108,15 +110,20 @@ set socket_dir = /tmp # === Key modmapping and ignoring ============================================ -#modmap from to +#modmap @modmap @modmap @modmap +#modkey_addition +@modkey_addition +@modkey_addition + #ignore_key @ignore_key @ignore_key + # === Keyboard & Mouse bindings ============================================== # With this command you can enter in any command at runtime when prefixed with diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 8a509bb..4c88fd8 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -3,7 +3,7 @@ import re # Map these functions/variables in the plugins namespace to the uzbl object. __export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore', - 'append_keycmd', 'inject_keycmd'] + 'append_keycmd', 'inject_keycmd', 'add_modkey_addition'] # Hold the keylets. UZBLS = {} @@ -42,6 +42,7 @@ class Keylet(object): self.modmaps = {} self.ignores = {} + self.additions = {} # Keylet string repr cache. self._repr_cache = None @@ -76,6 +77,25 @@ class Keylet(object): return key + def find_addition(self, modkey): + '''Key has just been pressed, check if this key + the held list + results in a modkey addition. Return that addition and remove all + modkeys that created it.''' + + already_added = self.held & set(self.additions.keys()) + for key in already_added: + if modkey in self.additions[key]: + return key + + modkeys = set(list(self.held) + [modkey,]) + for (key, value) in self.additions.items(): + if modkeys.issuperset(value): + self.held = modkeys ^ value + return key + + return modkey + + def key_ignored(self, key): '''Check if the given key is ignored by any ignore rules.''' @@ -107,7 +127,20 @@ class Keylet(object): def add_modmap(uzbl, key, map): - '''Add modmaps.''' + '''Add modmaps. + + Examples: + set modmap = request MODMAP + @modmap + @modmap + ... + + Then: + @bind = + @bind x = + ... + + ''' assert len(key) modmaps = get_keylet(uzbl).modmaps @@ -131,7 +164,14 @@ def modmap_parse(uzbl, map): def add_key_ignore(uzbl, glob): - '''Add an ignore definition.''' + '''Add an ignore definition. + + Examples: + set ignore_key = request IGNORE_KEY + @ignore_key + @ignore_key + ... + ''' assert len(glob) > 1 ignores = get_keylet(uzbl).ignores @@ -144,6 +184,45 @@ def add_key_ignore(uzbl, glob): uzbl.event('NEW_KEY_IGNORE', glob) +def add_modkey_addition(uzbl, modkeys, result): + '''Add a modkey addition definition. + + Examples: + set mod_addition = request MODKEY_ADDITION + @mod_addition + @mod_addition + @mod_addition + ... + + Then: + @bind = + @bind o = + ... + ''' + + additions = get_keylet(uzbl).additions + modkeys = set(modkeys) + + assert len(modkeys) and result and result not in modkeys + + for (existing_result, existing_modkeys) in additions.items(): + if existing_result != result: + assert modkeys != existing_modkeys + + additions[result] = modkeys + uzbl.event('NEW_MODKEY_ADDITION', modkeys, result) + + +def modkey_addition_parse(uzbl, modkeys): + '''Parse modkey addition definition.''' + + keys = filter(None, map(unicode.strip, modkeys.split(" "))) + keys = ['<%s>' % key.strip("<>") for key in keys if key.strip("<>")] + + assert len(keys) > 1 + add_modkey_addition(uzbl, keys[:-1], keys[-1]) + + def add_instance(uzbl, *args): '''Create the Keylet object for this uzbl instance.''' @@ -259,14 +338,23 @@ def inject_str(str, index, inj): return "%s%s%s" % (str[:index], inj, str[index:]) -def chevronate(key): - '''If a modkey isn't already chevronated then chevronate it. Ignore all - other keys.''' +def get_keylet_and_key(uzbl, key): + '''Return the keylet and apply any transformations to the key as defined + by the modmapping or modkey addition rules. Return None if the key is + ignored.''' + keylet = get_keylet(uzbl) + key = keylet.modmap_key(key) if len(key) == 1: - return key + return (keylet, key) + + modkey = "<%s>" % key.strip("<>") + modkey = keylet.find_addition(modkey) + + if keylet.key_ignored(modkey): + return (keylet, None) - return "<%s>" % key.strip("<>") + return (keylet, modkey) def key_press(uzbl, key): @@ -279,10 +367,8 @@ def key_press(uzbl, key): 5. If in modcmd mode the pressed key is added to the held keys list. 6. Keycmd is updated and events raised if anything is changed.''' - k = get_keylet(uzbl) - key = chevronate(k.modmap_key(key.strip())) - - if k.key_ignored(key): + (k, key) = get_keylet_and_key(uzbl, key.strip()) + if not key: return if key.lower() == '' and not k.held and k.keycmd: @@ -304,9 +390,6 @@ def key_press(uzbl, key): elif len(key) > 1: k.is_modcmd = True - if key == '' and '' in k.held: - k.held.remove('') - if key not in k.held: k.held.add(key) @@ -325,14 +408,9 @@ def key_release(uzbl, key): 3. Check if any modkey is held, if so set modcmd mode. 4. Update the keycmd uzbl variable if anything changed.''' - k = get_keylet(uzbl) - key = chevronate(k.modmap_key(key)) - - if key in ['', ''] and '' in k.held: - key = '' - - elif key in ['', ''] and '' in k.held: - key = '' + (k, key) = get_keylet_and_key(uzbl, key.strip()) + if not key: + return if key in k.held: if k.is_modcmd: @@ -464,6 +542,7 @@ def init(uzbl): 'MODMAP': modmap_parse, 'APPEND_KEYCMD': append_keycmd, 'INJECT_KEYCMD': inject_keycmd, - 'IGNORE_KEY': add_key_ignore} + 'IGNORE_KEY': add_key_ignore, + 'MODKEY_ADDITION': modkey_addition_parse} uzbl.connect_dict(connects) -- cgit v1.2.3 From e62c36c07d360e73543f864af69e97bd5d348e73 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 28 Nov 2009 17:35:52 +0800 Subject: Remove typo. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 62b5315..9820fda 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -125,7 +125,7 @@ set socket_dir = /tmp # Middle click # if clicked on a link open the link in a new uzbl window -# otherwise open the selection in the current window1 +# otherwise open the selection in the current window set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } -- cgit v1.2.3 From 6a33e0043932fbb2ab36d8e2557c5758d1f7004b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 12:24:29 +0800 Subject: Refactor mode plugin, remove load_reset function. --- examples/data/uzbl/plugins/mode.py | 116 +++++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 50 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index 74e805a..568abc1 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -1,7 +1,7 @@ import sys import re -__export__ = ['set_mode', 'get_mode'] +__export__ = ['set_mode', 'get_mode', 'set_mode_config', 'get_mode_config'] UZBLS = {} @@ -12,19 +12,16 @@ DEFAULTS = { 'forward_keys': True, 'keycmd_events': False, 'modcmd_updates': False, - 'indicator': 'I'}, + 'mode_indicator': 'I'}, 'command': { 'forward_keys': False, 'keycmd_events': True, 'modcmd_updates': True, - 'indicator': 'C'}}} + 'mode_indicator': 'C'}}} FINDSPACES = re.compile("\s+") VALID_KEY = re.compile("^[\w_]+$").match -def error(msg): - sys.stderr.write("mode plugin: error: %s\n" % msg) - def add_instance(uzbl, *args): UZBLS[uzbl] = dict(DEFAULTS) @@ -36,6 +33,8 @@ def del_instance(uzbl, *args): def get_mode_dict(uzbl): + '''Return the mode dict for an instance.''' + if uzbl not in UZBLS: add_instance(uzbl) @@ -43,6 +42,8 @@ def get_mode_dict(uzbl): def get_mode_config(uzbl, mode): + '''Return the mode config for a given mode.''' + modes = get_mode_dict(uzbl)['modes'] if mode not in modes: modes[mode] = {} @@ -54,26 +55,13 @@ def get_mode(uzbl): return get_mode_dict(uzbl)['mode'] -def set_mode(uzbl, mode=None): - mode_dict = get_mode_dict(uzbl) - config = uzbl.get_config() - - if mode is None: - if 'default_mode' not in config: - return - - mode = config['default_mode'] +def mode_changed(uzbl, mode): + '''The mode has just been changed, now set the per-mode config.''' - if not VALID_KEY(mode): - raise KeyError("invalid mode name: %r" % mode) - - if 'mode' not in config or config['mode'] != mode: - config['mode'] = mode - return + get_mode_dict(uzbl)['mode'] = mode - mode_dict['mode'] = mode + config = uzbl.get_config() mode_config = get_mode_config(uzbl, mode) - for (key, value) in mode_config.items(): if key not in config: config[key] = value @@ -84,11 +72,38 @@ def set_mode(uzbl, mode=None): if 'mode_indicator' not in mode_config: config['mode_indicator'] = mode - uzbl.clear_keycmd() + +def set_mode(uzbl, mode=None): + '''Set the mode and raise the MODE_CHANGED event if the mode has changed. + Fallback on the default mode if no mode argument was given and the default + mode is not null.''' + + config = uzbl.get_config() + mode_dict = get_mode_dict(uzbl) + if mode is None: + mode_dict['mode'] = '' + if 'default_mode' in config: + mode = config['default_mode'] + + else: + mode = 'command' + + if not VALID_KEY(mode): + raise KeyError("invalid mode name: %r" % mode) + + if 'mode' not in config or config['mode'] != mode: + config['mode'] = mode + return + + elif get_mode(uzbl) == mode: + return + uzbl.event("MODE_CHANGED", mode) def config_changed(uzbl, key, value): + '''Check for mode related config changes.''' + value = None if not value else value if key == 'default_mode': if not get_mode(uzbl): @@ -98,11 +113,25 @@ def config_changed(uzbl, key, value): set_mode(uzbl, value) +def set_mode_config(uzbl, mode, key, value): + '''Set mode specific configs. If the mode being modified is the current + mode then apply the changes on the go.''' + + assert VALID_KEY(mode) and VALID_KEY(key) + + mode_config = get_mode_config(uzbl, mode) + mode_config[key] = value + + if get_mode(uzbl) == mode: + uzbl.set(key, value) + + def mode_config(uzbl, args): + '''Parse mode config events.''' split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1)) if len(split) != 2: - raise SyntaxError('invalid config syntax: %r' % args) + raise SyntaxError('invalid mode config syntax: %r' % args) mode, set = split split = map(unicode.strip, set.split('=', 1)) @@ -110,35 +139,22 @@ def mode_config(uzbl, args): raise SyntaxError('invalid set syntax: %r' % args) key, value = split - if not VALID_KEY(key): - raise KeyError('invalid config key: %r' % key) - - mode_config = get_mode_config(uzbl, mode) - mode_config[key] = value - - if get_mode(uzbl) == mode: - uzbl.set(key, value) - - -def load_reset(uzbl, *args): - config = uzbl.get_config() - if 'reset_on_commit' not in config or config['reset_on_commit'] == '1': - set_mode(uzbl) + set_mode_config(uzbl, mode, key, value) def toggle_modes(uzbl, modes): + '''Toggle or cycle between or through a list of modes.''' - modelist = [s.strip() for s in modes.split(' ') if s] - if not len(modelist): - return error("no modes specified to toggle") + assert len(modes.strip()) - mode_dict = get_mode_dict(uzbl) - oldmode = mode_dict['mode'] - if oldmode not in modelist: - return set_mode(uzbl, modelist[0]) + modelist = filter(None, map(unicode.strip, modes.split(' '))) + mode = get_mode(uzbl) + + index = 0 + if mode in modelist: + index = (modelist.index(mode)+1) % len(modelist) - newmode = modelist[(modelist.index(oldmode)+1) % len(modelist)] - set_mode(uzbl, newmode) + set_mode(uzbl, modelist[index]) def init(uzbl): @@ -147,7 +163,7 @@ def init(uzbl): 'INSTANCE_EXIT': del_instance, 'INSTANCE_START': add_instance, 'MODE_CONFIG': mode_config, - 'LOAD_START': load_reset, - 'TOGGLE_MODES': toggle_modes} + 'TOGGLE_MODES': toggle_modes, + 'MODE_CHANGED': mode_changed} uzbl.connect_dict(connects) -- cgit v1.2.3 From 5cecb5d6570df33c2ce9c700c563fad8b787f13e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 18:27:07 +0800 Subject: Add force option to set in config plugin. --- examples/data/uzbl/plugins/config.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py index 57c2403..47b59f9 100644 --- a/examples/data/uzbl/plugins/config.py +++ b/examples/data/uzbl/plugins/config.py @@ -22,12 +22,16 @@ def get_config(uzbl): return UZBLS[uzbl] -def set(uzbl, key, value=''): - '''Sends a: "set key = value" command to the uzbl instance.''' +def set(uzbl, key, value='', force=True): + '''Sends a: "set key = value" command to the uzbl instance. If force is + False then only send a set command if the values aren't equal.''' if type(value) == types.BooleanType: value = int(value) + else: + value = unicode(value) + if not _VALIDSETKEY(key): raise KeyError("%r" % key) @@ -35,6 +39,11 @@ def set(uzbl, key, value=''): if '\n' in value: value = value.replace("\n", "\\n") + if not force: + config = get_config(uzbl) + if key in config and config[key] == value: + return + uzbl.send('set %s = %s' % (key, value)) @@ -61,8 +70,7 @@ class ConfigDict(dict): def __setitem__(self, key, value): '''Makes "config[key] = value" a wrapper for the set function.''' - if key not in self or unicode(self[key]) != unicode(value): - set(self._uzbl, key, value) + set(self._uzbl, key, value, force=False) def variable_set(uzbl, args): -- cgit v1.2.3 From 50d4c84aa7e28167cedbe14cd064d98a605ca1ea Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 18:41:56 +0800 Subject: Correctly implemented stack mode usage in the bind plugin. Using the stack mode in the bind plugin is required when using a stack bind in a mode with "set keycmd_events = 0" and "set forward_keys = 1" otherwise no keycmd input would work. --- examples/config/uzbl/config | 12 +++++++++++- examples/data/uzbl/plugins/bind.py | 23 +++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9820fda..5f70627 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -3,7 +3,7 @@ set prefix = /usr/local -# === Shortcuts ============================================================== +# === Shortcuts / Aliases =================================================== # request BIND = set bind = request BIND @@ -273,6 +273,7 @@ menu_link_add Print Link = print \@SELECTED_URI # Define some mode specific uzbl configurations. set command = @mode_config command set insert = @mode_config insert +set stack = @mode_config stack # Command mode config. @command keycmd_style = foreground="red" @@ -283,6 +284,15 @@ set insert = @mode_config insert @insert status_background = #303030 @insert mode_indicator = Ins +# Multi-stage-binding mode config. +@stack keycmd_events = 1 +@stack modcmd_updates = 1 +@stack forward_keys = 0 +@stack keycmd_style = foreground="red" +@stack prompt_style = foreground="#888" weight="light" +@stack status_background = #202020 +@stack mode_indicator = Bnd + set default_mode = command # Mode bindings: diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 4976a80..3169b15 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -17,7 +17,7 @@ __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] # Hold the bind dicts for each uzbl instance. UZBLS = {} -DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': []} +DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': [], 'last_mode': ''} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') @@ -276,15 +276,25 @@ def parse_bind_event(uzbl, args): bind(uzbl, glob, command) -def clear_stack(uzbl, mode): +def mode_changed(uzbl, mode): + '''Clear the stack on all non-stack mode changes.''' + + if mode != 'stack': + clear_stack(uzbl) + + +def clear_stack(uzbl): '''Clear everything related to stacked binds.''' bind_dict = get_bind_dict(uzbl) bind_dict['stack'] = [] bind_dict['depth'] = 0 bind_dict['args'] = [] + if bind_dict['last_mode']: + uzbl.set_mode(bind_dict['last_mode']) + bind_dict['last_mode'] = '' - uzbl.set('keycmd_prompt', '') + uzbl.set('keycmd_prompt', force=False) def stack_bind(uzbl, bind, args, depth): @@ -298,6 +308,10 @@ def stack_bind(uzbl, bind, args, depth): return + if uzbl.get_mode() != 'stack': + bind_dict['last_mode'] = uzbl.get_mode() + uzbl.set_mode('stack') + globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] bind_dict['stack'] = [bind,] + globalcmds bind_dict['args'] += args @@ -356,6 +370,7 @@ def match_and_exec(uzbl, bind, depth, keylet): exec_bind(uzbl, bind, *args) uzbl.set_mode() if not has_args: + clear_stack(uzbl) uzbl.clear_current() return True @@ -411,6 +426,6 @@ def init(uzbl): 'MODCMD_UPDATE': modcmd_update, 'KEYCMD_EXEC': keycmd_exec, 'MODCMD_EXEC': modcmd_exec, - 'MODE_CHANGED': clear_stack} + 'MODE_CHANGED': mode_changed} uzbl.connect_dict(connects) -- cgit v1.2.3 From 06dd36b6656e272c52b9628dfebc24d4c727b34a Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 18:50:44 +0800 Subject: Repair command insert toggle. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 7a2aaa0..29cb365 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -310,7 +310,7 @@ set default_mode = command set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins -@bind = @toggle_cmd_ins +@bind i = @toggle_cmd_ins # === Post-load misc commands =============================================== -- cgit v1.2.3 From 3eb6abf97a1e04a0c9102329b25b300fd484906b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 19:00:06 +0800 Subject: Revert "Merge branch 'security' of git://lug.rose-hulman.edu/~spenceal/uzbl into experimental" This reverts commit e1ffb7652d256efdbb7a145f39b0289ebb523d34, reversing changes made to f7eeee9955f99d4acbfc90c7dc00b50767a15e07. --- examples/data/uzbl/scripts/clipboard.sh | 2 +- examples/data/uzbl/scripts/download.sh | 4 ++-- examples/data/uzbl/scripts/scheme.py | 5 ++--- examples/data/uzbl/scripts/yank.sh | 7 +++++-- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh index d493774..60567d3 100755 --- a/examples/data/uzbl/scripts/clipboard.sh +++ b/examples/data/uzbl/scripts/clipboard.sh @@ -11,7 +11,7 @@ url="$7" selection=`$clip -o` case $action in - "yank" ) echo -n "$url" | $clip;; + "yank" ) echo -n "$url" | eval "$clip";; "goto" ) echo "uri $selection" > "$fifo";; * ) echo "clipboard.sh: invalid action";; esac diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh index 55b0cb2..c8eb6ba 100755 --- a/examples/data/uzbl/scripts/download.sh +++ b/examples/data/uzbl/scripts/download.sh @@ -16,7 +16,7 @@ test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } # only changes the dir for the $get sub process if echo "$url" | grep -E '.*\.torrent' >/dev/null; then - ( cd "$dest"; $GET "$url" ) + ( cd "$dest"; eval "$GET" "$url") else - ( cd "$dest"; $GET "$url" ) + ( cd "$dest"; eval "$GET" "$url") fi diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index 0916466..a54476f 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -16,9 +16,8 @@ if __name__ == '__main__': uri = sys.argv[8] u = urlparse.urlparse(uri) if u.scheme == 'mailto': - detach_open(['xterm', '-e', 'mail', u.path]) + detach_open(['xterm', '-e', 'mail %r' % u.path]) elif u.scheme == 'xmpp': - # Someone check for safe arguments to gajim-remote detach_open(['gajim-remote', 'open_chat', uri]) elif u.scheme == 'git': - detach_open(['git', 'clone', '--', uri], cwd=os.path.expanduser('~/src')) + detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src')) diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh index 6785d64..376b7e2 100755 --- a/examples/data/uzbl/scripts/yank.sh +++ b/examples/data/uzbl/scripts/yank.sh @@ -9,6 +9,9 @@ clip=xclip which $clip &>/dev/null || exit 1 -[ "$9" = primary -o "$9" = secondary -o "$9" = clipboard ] || exit 2 +[ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2 -echo -n "$8" | $clip -selection $9 +value=`eval "echo -n \\${$8}"` # bash: value = ${!8} + +echo "echo -n '${value}' | $clip -selection $9" +echo -n "'${value}' | $clip -selection $9" -- cgit v1.2.3 From efb04a3a19b026dc1a304f52c5e0351f84988dc2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 29 Nov 2009 19:05:02 +0800 Subject: Clear keycmd & modcmd on mode change. --- examples/data/uzbl/plugins/mode.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index 568abc1..52b104a 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -72,6 +72,9 @@ def mode_changed(uzbl, mode): if 'mode_indicator' not in mode_config: config['mode_indicator'] = mode + uzbl.clear_keycmd() + uzbl.clear_modcmd() + def set_mode(uzbl, mode=None): '''Set the mode and raise the MODE_CHANGED event if the mode has changed. -- cgit v1.2.3 From ec6eea0f30f08bc3cee252649f8b16d5c5abc67b Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 29 Nov 2009 15:49:36 +0100 Subject: remove old/deprecated scripts --- examples/config/uzbl/config | 7 ++----- examples/data/uzbl/scripts/clipboard.sh | 17 --------------- examples/data/uzbl/scripts/cookies.py | 37 --------------------------------- examples/data/uzbl/scripts/cookies.sh | 2 +- examples/data/uzbl/scripts/yank.sh | 17 --------------- 5 files changed, 3 insertions(+), 77 deletions(-) delete mode 100755 examples/data/uzbl/scripts/clipboard.sh delete mode 100755 examples/data/uzbl/scripts/cookies.py delete mode 100755 examples/data/uzbl/scripts/yank.sh (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 29cb365..f06bbc5 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -174,11 +174,8 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @bind B = spawn @scripts_dir/insert_bookmark.sh @bind U = spawn @scripts_dir/load_url_from_history.sh @bind u = spawn @scripts_dir/load_url_from_bookmarks.sh -# with the sample yank script, you can yank one of the arguments into clipboard/selection -@bind yurl = spawn @scripts_dir/yank.sh 6 primary -@bind ytitle = spawn @scripts_dir/yank.sh 7 clipboard -# does the same as yurl but without needing a script -@bind y2url = sh 'echo -n $6 | xclip' +@bind yurl = sh 'echo -n $6 | xclip' +@bind ytitle = sh 'echo -n $7 | xclip' # go the page from primary selection @bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # go to the page in clipboard diff --git a/examples/data/uzbl/scripts/clipboard.sh b/examples/data/uzbl/scripts/clipboard.sh deleted file mode 100755 index 60567d3..0000000 --- a/examples/data/uzbl/scripts/clipboard.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# with this script you can store the current url in the clipboard, or go to the url which is stored in the clipboard. - -clip=xclip - -fifo="$5" -action="$1" -url="$7" - -selection=`$clip -o` - -case $action in - "yank" ) echo -n "$url" | eval "$clip";; - "goto" ) echo "uri $selection" > "$fifo";; - * ) echo "clipboard.sh: invalid action";; -esac diff --git a/examples/data/uzbl/scripts/cookies.py b/examples/data/uzbl/scripts/cookies.py deleted file mode 100755 index 10f90fa..0000000 --- a/examples/data/uzbl/scripts/cookies.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -import StringIO, cookielib, os, sys, urllib2 - -if __name__ == '__main__': - action = sys.argv[8] - uri = urllib2.urlparse.ParseResult( - scheme=sys.argv[9], - netloc=sys.argv[10], - path=sys.argv[11], - params='', - query='', - fragment='').geturl() - set_cookie = sys.argv[12] if len(sys.argv)>12 else None - - if 'XDG_DATA_HOME' in os.environ.keys() and os.environ['XDG_DATA_HOME']: - f = os.path.join(os.environ['XDG_DATA_HOME'],'uzbl/cookies.txt') - else: - f = os.path.join(os.environ['HOME'],'.local/share/uzbl/cookies.txt') - jar = cookielib.MozillaCookieJar(f) - - try: - jar.load(ignore_discard=True) - except: - pass - - req = urllib2.Request(uri) - - if action == 'GET': - jar.add_cookie_header(req) - if req.has_header('Cookie'): - print req.get_header('Cookie') - elif action == 'PUT': - hdr = urllib2.httplib.HTTPMessage(StringIO.StringIO('Set-Cookie: %s' % set_cookie)) - res = urllib2.addinfourl(StringIO.StringIO(), hdr, req.get_full_url()) - jar.extract_cookies(res,req) - jar.save(ignore_discard=True) diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh index 339c6fc..ee2ce51 100755 --- a/examples/data/uzbl/scripts/cookies.sh +++ b/examples/data/uzbl/scripts/cookies.sh @@ -4,7 +4,7 @@ set -n; # THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! -# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as cookies.py +# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as uzbl-cookie-daemon # we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) # This is one textfile with entries like this: # kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 diff --git a/examples/data/uzbl/scripts/yank.sh b/examples/data/uzbl/scripts/yank.sh deleted file mode 100755 index 376b7e2..0000000 --- a/examples/data/uzbl/scripts/yank.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# use this script to pipe any variable to xclip, so you have it in your clipboard -# in your uzbl config, make the first argument the number of the (later) argument you want to use (see README for list of args) -# make the 2nd argument one of : primary, secondary, clipboard. -# examples: -# bind yurl = spawn ./examples/scripts/yank.sh 6 primary -# bind ytitle = spawn ./examples/scripts/yank.sh 7 clipboard - -clip=xclip - -which $clip &>/dev/null || exit 1 -[ "x$9" = xprimary -o "x$9" = xsecondary -o "x$9" = xclipboard ] || exit 2 - -value=`eval "echo -n \\${$8}"` # bash: value = ${!8} - -echo "echo -n '${value}' | $clip -selection $9" -echo -n "'${value}' | $clip -selection $9" -- cgit v1.2.3 From f4cdceb03e1ca1866f676a2e9e7a14025c448caf Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 29 Nov 2009 16:22:48 +0100 Subject: Fix security holes --- AUTHORS | 3 ++- examples/data/uzbl/scripts/download.sh | 4 ++-- examples/data/uzbl/scripts/scheme.py | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index 44e10f9..24076a2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,6 +20,7 @@ In alphabetical order: Aaron Griffin (phrakture) - Makefile patches to build on OSX Abel Camarillo (00z) - various portability fixes, such as BSD fixes for Makefile and posix shell scripts Andraž 'ruskie' Levstik - font_family patch + Andy Spencer - security fixes Barak A. Pearlmutter - typo fix Brendan Taylor (bct) - various bugfixes, making misc variables much better using expand(), refactoring some internal var stuff Chris Mason - code snippets such as basic cookie handler @@ -37,7 +38,7 @@ In alphabetical order: Jan Kolkmeier (jouz) - scrolling, link following Laurence Withers (lwithers) - talk_to_socket Mark Nevill - misc patches - Mason Larobina - os.environ.keys() & os.path.join fix in cookies.py, work on uzbl_tabbed.py, cookie_daemon.py + Mason Larobina - uzbl-tabbed.py, cookie-daemon, event-manager&plugins, ... Maximilian Gaß (mxey) - several small patches Michael Fiano (axionix) - added cookie_daemon.py whitelist Michael Walker (Barrucadu) - contributions to early uzbl diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh index c8eb6ba..1c7d039 100755 --- a/examples/data/uzbl/scripts/download.sh +++ b/examples/data/uzbl/scripts/download.sh @@ -16,7 +16,7 @@ test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } # only changes the dir for the $get sub process if echo "$url" | grep -E '.*\.torrent' >/dev/null; then - ( cd "$dest"; eval "$GET" "$url") + ( cd "$dest"; $GET "$url") else - ( cd "$dest"; eval "$GET" "$url") + ( cd "$dest"; $GET "$url") fi diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py index a54476f..0916466 100755 --- a/examples/data/uzbl/scripts/scheme.py +++ b/examples/data/uzbl/scripts/scheme.py @@ -16,8 +16,9 @@ if __name__ == '__main__': uri = sys.argv[8] u = urlparse.urlparse(uri) if u.scheme == 'mailto': - detach_open(['xterm', '-e', 'mail %r' % u.path]) + detach_open(['xterm', '-e', 'mail', u.path]) elif u.scheme == 'xmpp': + # Someone check for safe arguments to gajim-remote detach_open(['gajim-remote', 'open_chat', uri]) elif u.scheme == 'git': - detach_open(['git', 'clone', uri], cwd=os.path.expanduser('~/src')) + detach_open(['git', 'clone', '--', uri], cwd=os.path.expanduser('~/src')) -- cgit v1.2.3 From e2f5db0f3ce07808f7e59e70639ec52eedf65e0c Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 30 Nov 2009 14:11:30 +0100 Subject: added extedit.js and config examples for it --- examples/config/uzbl/config | 5 ++ examples/data/uzbl/scripts/extedit.js | 103 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 examples/data/uzbl/scripts/extedit.js (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index f06bbc5..24806db 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -137,6 +137,11 @@ set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } +# Edit HTML forms in external editor +set editor = gvim +@bind E = script @scripts_dir/extedit.js +menu_editable_add Open in @editor = script @scripts_dir/extedit.js + @bind j = scroll vertical 20 @bind = scroll vertical 100% @bind k = scroll vertical -20 diff --git a/examples/data/uzbl/scripts/extedit.js b/examples/data/uzbl/scripts/extedit.js new file mode 100644 index 0000000..9d409c3 --- /dev/null +++ b/examples/data/uzbl/scripts/extedit.js @@ -0,0 +1,103 @@ +/* + * Edit forms in external editor + * + * (c) 2009, Robert Manea + * utf8 functions are (c) by Webtoolkit.info (http://www.webtoolkit.info/) + * + * + * Installation: + * - Copy this script to $HOME/.local/share/uzbl/scripts + * - Add the following to $HOME/.config/uzbl/config: + * @bind E = script @scripts_dir/extedit.js + * - Set your preferred editor + * set editor = gvim + * - non-GUI editors + * set editor = xterm -e vim + * + * Usage: + * Select (click) an editable form, go to command mode and hit E + * +*/ + + +function utf8_decode ( str_data ) { +    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; +    +    str_data += ''; +    +    while ( i < str_data.length ) { +        c1 = str_data.charCodeAt(i); +        if (c1 < 128) { +            tmp_arr[ac++] = String.fromCharCode(c1); +            i++; +        } else if ((c1 > 191) && (c1 < 224)) { +            c2 = str_data.charCodeAt(i+1); +            tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); +            i += 2; +        } else { +            c2 = str_data.charCodeAt(i+1); +            c3 = str_data.charCodeAt(i+2); +            tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); +            i += 3; +        } +    } +  +    return tmp_arr.join(''); +} + + +function utf8_encode ( argString ) { +    var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); +  +    var utftext = ""; +    var start, end; +    var stringl = 0; +  +    start = end = 0; +    stringl = string.length; +    for (var n = 0; n < stringl; n++) { +        var c1 = string.charCodeAt(n); +        var enc = null; +  +        if (c1 < 128) { +            end++; +        } else if (c1 > 127 && c1 < 2048) { +            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128); +        } else { +            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128); +        } +        if (enc !== null) { +            if (end > start) { +                utftext += string.substring(start, end); +            } +            utftext += enc; +            start = end = n+1; +        } +    } +  +    if (end > start) { +        utftext += string.substring(start, string.length); +    } +  +    return utftext; +} + + +(function() { + var actelem = document.activeElement; + + if(actelem.type == 'text' || actelem.type == 'textarea') { + var editor = Uzbl.run("print @editor") || "gvim"; + var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit_@NAME.XXXXXX)@"); + + if(actelem.value) + Uzbl.run("sh 'echo " + window.btoa(utf8_encode(actelem.value)) + " | base64 -d > " + filename + "'"); + + Uzbl.run("sync_sh '" + editor + " " + filename + "'"); + actelem.value = utf8_decode(window.atob(Uzbl.run("print @(base64 -w 0 " + filename + ")@"))); + + Uzbl.run("sh 'rm -f " + filename + "'"); + } + + })(); + -- cgit v1.2.3 From 8d9f6fcd7eb87c87e295918d3d178c8ab7a52be8 Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 30 Nov 2009 14:23:52 +0100 Subject: rename editor var to external_editor --- examples/config/uzbl/config | 6 ++++-- examples/data/uzbl/scripts/extedit.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 24806db..35a051b 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -138,9 +138,11 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } # Edit HTML forms in external editor -set editor = gvim +# +set external_editor = gvim +#set external_editor = xterm -e vim @bind E = script @scripts_dir/extedit.js -menu_editable_add Open in @editor = script @scripts_dir/extedit.js +menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js @bind j = scroll vertical 20 @bind = scroll vertical 100% diff --git a/examples/data/uzbl/scripts/extedit.js b/examples/data/uzbl/scripts/extedit.js index 9d409c3..bf77c87 100644 --- a/examples/data/uzbl/scripts/extedit.js +++ b/examples/data/uzbl/scripts/extedit.js @@ -87,8 +87,8 @@ function utf8_encode ( argString ) { var actelem = document.activeElement; if(actelem.type == 'text' || actelem.type == 'textarea') { - var editor = Uzbl.run("print @editor") || "gvim"; - var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit_@NAME.XXXXXX)@"); + var editor = Uzbl.run("print @external_editor") || "gvim"; + var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit.XXXXXX)@"); if(actelem.value) Uzbl.run("sh 'echo " + window.btoa(utf8_encode(actelem.value)) + " | base64 -d > " + filename + "'"); -- cgit v1.2.3 From 0312191ab81e6eb51ca26a0a89d5168b284fdc7b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 30 Nov 2009 21:41:03 +0800 Subject: Stripped some weird utf8 characters (\xc2\xa0) from extedit.js --- examples/data/uzbl/scripts/extedit.js | 115 +++++++++++++++++----------------- 1 file changed, 57 insertions(+), 58 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/extedit.js b/examples/data/uzbl/scripts/extedit.js index bf77c87..8ed346d 100644 --- a/examples/data/uzbl/scripts/extedit.js +++ b/examples/data/uzbl/scripts/extedit.js @@ -1,4 +1,4 @@ -/* +/* * Edit forms in external editor * * (c) 2009, Robert Manea @@ -17,69 +17,69 @@ * Usage: * Select (click) an editable form, go to command mode and hit E * -*/ +*/ function utf8_decode ( str_data ) { -    var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; -    -    str_data += ''; -    -    while ( i < str_data.length ) { -        c1 = str_data.charCodeAt(i); -        if (c1 < 128) { -            tmp_arr[ac++] = String.fromCharCode(c1); -            i++; -        } else if ((c1 > 191) && (c1 < 224)) { -            c2 = str_data.charCodeAt(i+1); -            tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); -            i += 2; -        } else { -            c2 = str_data.charCodeAt(i+1); -            c3 = str_data.charCodeAt(i+2); -            tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); -            i += 3; -        } -    } -  -    return tmp_arr.join(''); + var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; + + str_data += ''; + + while ( i < str_data.length ) { + c1 = str_data.charCodeAt(i); + if (c1 < 128) { + tmp_arr[ac++] = String.fromCharCode(c1); + i++; + } else if ((c1 > 191) && (c1 < 224)) { + c2 = str_data.charCodeAt(i+1); + tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = str_data.charCodeAt(i+1); + c3 = str_data.charCodeAt(i+2); + tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return tmp_arr.join(''); } function utf8_encode ( argString ) { -    var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); -  -    var utftext = ""; -    var start, end; -    var stringl = 0; -  -    start = end = 0; -    stringl = string.length; -    for (var n = 0; n < stringl; n++) { -        var c1 = string.charCodeAt(n); -        var enc = null; -  -        if (c1 < 128) { -            end++; -        } else if (c1 > 127 && c1 < 2048) { -            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128); -        } else { -            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128); -        } -        if (enc !== null) { -            if (end > start) { -                utftext += string.substring(start, end); -            } -            utftext += enc; -            start = end = n+1; -        } -    } -  -    if (end > start) { -        utftext += string.substring(start, string.length); -    } -  -    return utftext; + var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + + var utftext = ""; + var start, end; + var stringl = 0; + + start = end = 0; + stringl = string.length; + for (var n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if (c1 > 127 && c1 < 2048) { + enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128); + } else { + enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128); + } + if (enc !== null) { + if (end > start) { + utftext += string.substring(start, end); + } + utftext += enc; + start = end = n+1; + } + } + + if (end > start) { + utftext += string.substring(start, string.length); + } + + return utftext; } @@ -100,4 +100,3 @@ function utf8_encode ( argString ) { } })(); - -- cgit v1.2.3 From 6c25bcb44b4f273b892a4c4bcc4ecb27d1a93d9b Mon Sep 17 00:00:00 2001 From: Rob Date: Mon, 30 Nov 2009 17:48:03 +0100 Subject: added scroll-percentage.js and config example --- examples/config/uzbl/config | 4 +- examples/data/uzbl/scripts/scroll-percentage.js | 68 +++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 examples/data/uzbl/scripts/scroll-percentage.js (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 35a051b..2f3218a 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -45,6 +45,7 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh # Load commit handler @on_event LOAD_COMMIT @set_status recv +@on_event LOAD_COMMIT script @scripts_dir/scroll-percentage.js # Load finish handlers @on_event LOAD_FINISH @set_status done @@ -79,12 +80,13 @@ set hint_style = weight="bold" set mode_section = [\@[\@mode_indicator]\@] set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd\@completion_list] set progress_section = \@[\@progress_format]\@ +set scroll_section = \@[[\@scroll_message]]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ set status_section = \@status_message set selected_section = \@[\@SELECTED_URI]\@ -set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @selected_section +set status_format = @mode_section @keycmd_section @progress_section @scroll_section @uri_section @name_section @status_section @selected_section # Progress bar config @progress width = 8 diff --git a/examples/data/uzbl/scripts/scroll-percentage.js b/examples/data/uzbl/scripts/scroll-percentage.js new file mode 100644 index 0000000..c9a51aa --- /dev/null +++ b/examples/data/uzbl/scripts/scroll-percentage.js @@ -0,0 +1,68 @@ +// VIM ruler style scroll message +(function() { + var run = Uzbl.run; + var update_message = function() { + var innerHeight = window.innerHeight; + var scrollY = window.scrollY; + var height = document.height; + var message; + + if (UzblZoom.type === "full") { + var zoom_level = UzblZoom.level; + innerHeight = Math.ceil(innerHeight * zoom_level); + scrollY = Math.ceil(scrollY * zoom_level); + height -= 1; + } + + if (! height) { + message = ""; + } + else if (height <= innerHeight) { + message = run("print @scroll_all_indicator") || "All"; + } + else if (scrollY === 0) { + message = run("print @scroll_top_indicator") || "Top"; + } + else if (scrollY + innerHeight >= height) { + message = run("print @scroll_bottom_indicator") || "Bot"; + } + else { + var percentage = Math.round(scrollY / (height - innerHeight) * 100); + message = percentage + "%"; + } + run("set scroll_message=" + message); + }; + + self.UzblZoom = { + get level() { + return Number(run("print @zoom_level")) || 1; + }, + set level(level) { + if (typeof level === "number" && level > 0) { + run("set zoom_level = " + level); + update_message(); + } + }, + get type() { + return run("print @zoom_type") || "text"; + }, + set type(type) { + if ((type === "text" || type === "full") && this.type != type) { + run("toggle_zoom_type"); + run("set zoom_type = " + type); + update_message(); + } + }, + toggle_type: function() { + this.type = (this.type === "text" ? "full" : "text"); + } + }; + + window.addEventListener("DOMContentLoaded", update_message, false); + window.addEventListener("load", update_message, false); + window.addEventListener("resize", update_message, false); + window.addEventListener("scroll", update_message, false); + update_message(); +})(); + +// vim: set noet ff=unix -- cgit v1.2.3 From 6e3e9c9c86580bc2fe8f093ecb432a38c0e1d009 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 02:13:35 +0800 Subject: Move @scroll_section to the end of the status_bar to make it less jumpy. --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 2f3218a..9fda268 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -80,13 +80,13 @@ set hint_style = weight="bold" set mode_section = [\@[\@mode_indicator]\@] set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd\@completion_list] set progress_section = \@[\@progress_format]\@ -set scroll_section = \@[[\@scroll_message]]\@ +set scroll_section = \@[\@scroll_message]\@ set uri_section = \@[\@uri]\@ set name_section = \@[\@NAME]\@ set status_section = \@status_message set selected_section = \@[\@SELECTED_URI]\@ -set status_format = @mode_section @keycmd_section @progress_section @scroll_section @uri_section @name_section @status_section @selected_section +set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section # Progress bar config @progress width = 8 -- cgit v1.2.3 From 4e9b6fad6b65f6ca107726e8819f0db73721aa3b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 15:24:06 +0800 Subject: Use builtin and default library functions over custom functions. --- examples/data/uzbl/scripts/uzbl-event-manager | 31 ++++----------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 0054ff6..e926643 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -39,6 +39,7 @@ from select import select from signal import signal, SIGTERM from optparse import OptionParser from traceback import print_exc +from functools import partial # ============================================================================ @@ -111,18 +112,6 @@ def counter(): yield i -def iscallable(obj): - '''Return true if the object is callable.''' - - return hasattr(obj, "__call__") - - -def isiterable(obj): - '''Return true if you can iterate over the item.''' - - return hasattr(obj, "__iter__") - - def find_plugins(plugin_dirs): '''Find all event manager plugins in the plugin dirs and return a dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' @@ -289,24 +278,12 @@ def term_process(pid): time.sleep(0.25) -def prepender(function, *pre_args): - '''Creates a wrapper around a callable object injecting a list of - arguments before the called arguments.''' - - locals = (function, pre_args) - def _prepender(*args, **kargs): - (function, pre_args) = locals - return function(*(pre_args + args), **kargs) - - return _prepender - - class EventHandler(object): nexthid = counter().next def __init__(self, event, handler, *args, **kargs): - if not iscallable(handler): + if not callable(handler): raise ArgumentError("EventHandler object requires a callable " "object function for the handler argument not: %r" % handler) @@ -378,8 +355,8 @@ class UzblInstance(object): raise KeyError("conflicting export: %r" % export) obj = getattr(plugin, export) - if iscallable(obj): - obj = prepender(obj, self) + if callable(obj): + obj = partial(obj, self) self._exports[export] = obj -- cgit v1.2.3 From 253f986e4be9dcfd496774cb325a4b7251254fc4 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 17:27:18 +0800 Subject: Made force default to False and added config attribute. --- examples/data/uzbl/plugins/config.py | 41 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py index 47b59f9..b43161b 100644 --- a/examples/data/uzbl/plugins/config.py +++ b/examples/data/uzbl/plugins/config.py @@ -3,8 +3,8 @@ import types __export__ = ['set', 'get_config'] -_VALIDSETKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match -_TYPECONVERT = {'int': int, 'float': float, 'str': unicode} +VALIDKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match +TYPECONVERT = {'int': int, 'float': float, 'str': unicode} UZBLS = {} @@ -15,14 +15,7 @@ def escape(value): return unicode(value) -def get_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def set(uzbl, key, value='', force=True): +def set(uzbl, key, value='', config=None, force=False): '''Sends a: "set key = value" command to the uzbl instance. If force is False then only send a set command if the values aren't equal.''' @@ -32,7 +25,7 @@ def set(uzbl, key, value='', force=True): else: value = unicode(value) - if not _VALIDSETKEY(key): + if not VALIDKEY(key): raise KeyError("%r" % key) value = escape(value) @@ -40,13 +33,25 @@ def set(uzbl, key, value='', force=True): value = value.replace("\n", "\\n") if not force: - config = get_config(uzbl) + if config is None: + config = get_config(uzbl) + if key in config and config[key] == value: return uzbl.send('set %s = %s' % (key, value)) +class ConfigDict(dict): + def __init__(self, uzbl): + self._uzbl = uzbl + + def __setitem__(self, key, value): + '''Makes "config[key] = value" a wrapper for the set function.''' + + set(self._uzbl, key, value, config=self) + + def add_instance(uzbl, *args): UZBLS[uzbl] = ConfigDict(uzbl) @@ -63,22 +68,12 @@ def get_config(uzbl): return UZBLS[uzbl] -class ConfigDict(dict): - def __init__(self, uzbl): - self._uzbl = uzbl - - def __setitem__(self, key, value): - '''Makes "config[key] = value" a wrapper for the set function.''' - - set(self._uzbl, key, value, force=False) - - def variable_set(uzbl, args): config = get_config(uzbl) key, type, value = list(args.split(' ', 2) + ['',])[:3] old = config[key] if key in config else None - value = _TYPECONVERT[type](value) + value = TYPECONVERT[type](value) dict.__setitem__(config, key, value) -- cgit v1.2.3 From efa8ee4e63d8c07130c6b02d93ab3cc46209e948 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 17:43:26 +0800 Subject: Added example in the config to reset the keycmd on page navigation. --- examples/config/uzbl/config | 5 +++-- examples/data/uzbl/plugins/bind.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9fda268..fa82fda 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -43,9 +43,11 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh # Load start handlers @on_event LOAD_START @set_status wait -# Load commit handler +# Load commit handlers @on_event LOAD_COMMIT @set_status recv @on_event LOAD_COMMIT script @scripts_dir/scroll-percentage.js +# Reset the keycmd on navigation +@on_event LOAD_COMMIT @set_mode # Load finish handlers @on_event LOAD_FINISH @set_status done @@ -63,7 +65,6 @@ set new_window = sh 'uzbl-browser -u $8' # equivalent to the default beh # Misc on_event handlers #@on_event CONFIG_CHANGED print Config changed: %1 = %2 - # === Behaviour and appearance =============================================== set show_status = 1 diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 3169b15..3e47e38 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -294,7 +294,7 @@ def clear_stack(uzbl): uzbl.set_mode(bind_dict['last_mode']) bind_dict['last_mode'] = '' - uzbl.set('keycmd_prompt', force=False) + uzbl.set('keycmd_prompt') def stack_bind(uzbl, bind, args, depth): -- cgit v1.2.3 From dbdd7053b19275fff29787f50855eca82921bccf Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 17:46:14 +0800 Subject: TOGGLE_MODES is not a configuration event so use the event function. --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index fa82fda..a9ae29a 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -10,7 +10,7 @@ set bind = request BIND # request MODE_CONFIG = ... -set toggle_modes = request TOGGLE_MODES +set toggle_modes = event TOGGLE_MODES # request ON_EVENT set on_event = request ON_EVENT # request PROGRESS_CONFIG = @@ -313,7 +313,7 @@ set default_mode = command # Changing mode method via set. @bind I = @set_mode insert -# Or toggle between modes by rasing request events. +# Or toggle between modes by rasing the toggle event. set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins -- cgit v1.2.3 From 1a109cb03c761cbeaa3bd81cb9f5f45953c7148e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 17:52:27 +0800 Subject: Keycmd and mode plugin config setting optimisations. --- examples/data/uzbl/plugins/keycmd.py | 35 +++++++++++++++-------------------- examples/data/uzbl/plugins/mode.py | 6 +----- 2 files changed, 16 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 4c88fd8..fd17363 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -256,10 +256,7 @@ def clear_keycmd(uzbl): k.keycmd = '' k.cursor = 0 k._repr_cache = False - config = uzbl.get_config() - if 'keycmd' not in config or config['keycmd']: - uzbl.set('keycmd') - + uzbl.set('keycmd') uzbl.event('KEYCMD_CLEAR') @@ -273,10 +270,7 @@ def clear_modcmd(uzbl, clear_held=False): if clear_held: k.held = set() - config = uzbl.get_config() - if 'modcmd' not in config or config['modcmd']: - uzbl.set('modcmd') - + uzbl.set('modcmd') uzbl.event('MODCMD_CLEAR') @@ -314,22 +308,25 @@ def update_event(uzbl, k, execute=True): if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': new_modcmd = k.get_modcmd() if not new_modcmd: - uzbl.set('modcmd') + uzbl.set('modcmd', config=config) elif new_modcmd == modcmd: - uzbl.set('modcmd', " %s " % uzbl_escape(new_modcmd)) + uzbl.set('modcmd', ' %s ' % uzbl_escape(new_modcmd), + config=config) if 'keycmd_events' in config and config['keycmd_events'] != '1': return - keycmd = k.get_keycmd() - if not keycmd: - return uzbl.set('keycmd') + new_keycmd = k.get_keycmd() + if not new_keycmd: + uzbl.set('keycmd', config=config) - # Generate the pango markup for the cursor in the keycmd. - curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' - chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] - uzbl.set('keycmd', KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks))) + elif new_keycmd == keycmd: + # Generate the pango markup for the cursor in the keycmd. + curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' + chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] + value = KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks)) + uzbl.set('keycmd', value, config=config) def inject_str(str, index, inj): @@ -380,9 +377,7 @@ def key_press(uzbl, key): if 'keycmd_events' in config and config['keycmd_events'] != '1': k.keycmd = '' k.cursor = 0 - if config['keycmd']: - uzbl.set('keycmd') - + uzbl.set('keycmd', config=config) return k.keycmd = inject_str(k.keycmd, k.cursor, key) diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index 52b104a..2b2579a 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -63,11 +63,7 @@ def mode_changed(uzbl, mode): config = uzbl.get_config() mode_config = get_mode_config(uzbl, mode) for (key, value) in mode_config.items(): - if key not in config: - config[key] = value - - elif config[key] != value: - config[key] = value + uzbl.set(key, value, config=config) if 'mode_indicator' not in mode_config: config['mode_indicator'] = mode -- cgit v1.2.3 From 585b542bd332284525ad5f4ce4a69b2880974a3f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 1 Dec 2009 18:10:33 +0800 Subject: Pylint rating of the EM raised to 9.38/10. --- examples/data/uzbl/scripts/uzbl-event-manager | 317 +++++++++++++------------- 1 file changed, 164 insertions(+), 153 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index e926643..6669282 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -30,7 +30,6 @@ import imp import os import sys import re -import types import socket import pprint import time @@ -64,8 +63,9 @@ DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') -# Config dict (NOT the same as the uzbl.config). -config = { +# Event manager config dictionary. This is not to be confused with the config +# dict that tracks variables in the uzbl instance. +CONFIG = { 'verbose': False, 'daemon_mode': True, 'auto_close': False, @@ -87,20 +87,25 @@ config = { # Define some globals. -_SCRIPTNAME = os.path.basename(sys.argv[0]) -_RE_FINDSPACES = re.compile("\s+") +SCRIPTNAME = os.path.basename(sys.argv[0]) +FINDSPACES = re.compile("\s+") + + +class ArgumentError(Exception): + pass + def echo(msg): '''Prints only if the verbose flag has been set.''' - if config['verbose']: - sys.stdout.write("%s: %s\n" % (_SCRIPTNAME, msg)) + if CONFIG['verbose']: + sys.stdout.write("%s: %s\n" % (SCRIPTNAME, msg)) def error(msg): '''Prints error messages to stderr.''' - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + sys.stderr.write("%s: error: %s\n" % (SCRIPTNAME, msg)) def counter(): @@ -123,23 +128,26 @@ def find_plugins(plugin_dirs): if not os.path.isdir(plugin_dir): continue - for file in os.listdir(plugin_dir): - if not file.lower().endswith('.py'): + for filename in os.listdir(plugin_dir): + if not filename.lower().endswith('.py'): continue - path = os.path.join(plugin_dir, file) + path = os.path.join(plugin_dir, filename) if not os.path.isfile(path): continue - if file not in plugins: - plugins[file] = plugin_dir + if filename not in plugins: + plugins[filename] = plugin_dir return plugins -def load_plugins(plugin_dirs, load=[], ignore=[]): +def load_plugins(plugin_dirs, load=None, ignore=None): '''Load event manager plugins found in the plugin_dirs.''' + load = [] if load is None else load + ignore = [] if ignore is None else ignore + # Find the plugins in the plugin_dirs. found = find_plugins(plugin_dirs) @@ -160,11 +168,11 @@ def load_plugins(plugin_dirs, load=[], ignore=[]): loaded = {} # Load all found plugins into the loaded dict. - for (filename, dir) in found.items(): + for (filename, plugin_dir) in found.items(): name = filename[:-3] - info = imp.find_module(name, [dir,]) + info = imp.find_module(name, [plugin_dir]) plugin = imp.load_module(name, *info) - loaded[(dir, filename)] = plugin + loaded[(plugin_dir, filename)] = plugin return loaded @@ -219,9 +227,9 @@ def make_pid_file(pid_file): '''Make pid file at given pid_file location.''' make_dirs(pid_file) - file = open(pid_file, 'w') - file.write('%d' % os.getpid()) - file.close() + fileobj = open(pid_file, 'w') + fileobj.write('%d' % os.getpid()) + fileobj.close() def del_pid_file(pid_file): @@ -235,13 +243,12 @@ def get_pid(pid_file): '''Read pid from pid_file.''' try: - file = open(pid_file, 'r') - strpid = file.read() - file.close() - pid = int(strpid.strip()) + fileobj = open(pid_file, 'r') + pid = int(fileobj.read()) + fileobj.close() return pid - except: + except IOError, ValueError: print_exc() return None @@ -278,6 +285,34 @@ def term_process(pid): time.sleep(0.25) +def parse_msg(uzbl, msg): + '''Parse an incoming msg from a uzbl instance. All non-event messages + will be printed here and not be passed to the uzbl instance event + handler function.''' + + if not msg: + return + + cmd = FINDSPACES.split(msg, 3) + if not cmd or cmd[0] != 'EVENT': + # Not an event message. + print '---', msg + return + + while len(cmd) < 4: + cmd.append('') + + event, args = cmd[2], cmd[3] + if not event: + return + + try: + uzbl.event(event, args) + + except: + print_exc() + + class EventHandler(object): nexthid = counter().next @@ -310,7 +345,7 @@ class EventHandler(object): class UzblInstance(object): # Give all plugins access to the main config dict. - config = config + config = CONFIG def __init__(self, parent, client_socket): @@ -419,7 +454,7 @@ class UzblInstance(object): handlers.remove(handler) return - echo('unable to find & remove handler with id: %d' % handler.hid) + echo('unable to find & remove handler with id: %d' % hid) def remove(self, handler): @@ -493,7 +528,7 @@ class UzblEventDaemon(dict): # Register that the event daemon server has started by creating the # pid file. - make_pid_file(config['pid_file']) + make_pid_file(CONFIG['pid_file']) # Register a function to clean up the socket and pid file on exit. atexit.register(self.quit) @@ -502,15 +537,15 @@ class UzblEventDaemon(dict): signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) # Load plugins, first-build of the plugins may be a costly operation. - self['plugins'] = load_plugins(config['plugin_dirs'], - config['plugins_load'], config['plugins_ignore']) + self['plugins'] = load_plugins(CONFIG['plugin_dirs'], + CONFIG['plugins_load'], CONFIG['plugins_ignore']) def _create_server_socket(self): '''Create the event manager daemon socket for uzbl instance duplex communication.''' - server_socket = config['server_socket'] + server_socket = CONFIG['server_socket'] server_socket = os.path.realpath(os.path.expandvars(server_socket)) self.socket_location = server_socket @@ -540,11 +575,11 @@ class UzblEventDaemon(dict): def run(self): '''Main event daemon loop.''' - if config['daemon_mode']: + if CONFIG['daemon_mode']: echo('entering daemon mode.') daemonize() # The pid has changed so update the pid file. - make_pid_file(config['pid_file']) + make_pid_file(CONFIG['pid_file']) # Create event daemon socket. self._create_server_socket() @@ -564,18 +599,18 @@ class UzblEventDaemon(dict): self.running = True while self.running: - sockets = [self.server_socket,] + self['uzbls'].keys() + sockets = [self.server_socket] + self['uzbls'].keys() - read, _, error = select(sockets, [], sockets, 1) + reads, _, errors = select(sockets, [], sockets, 1) - if self.server_socket in read: + if self.server_socket in reads: self.accept_connection() - read.remove(self.server_socket) + reads.remove(self.server_socket) - for client in read: + for client in reads: self.read_socket(client) - for client in error: + for client in errors: error('Unknown error on socket: %r' % client) self.close_connection(client) @@ -584,55 +619,28 @@ class UzblEventDaemon(dict): '''Read data from an instance socket and pass to the uzbl objects event handler function.''' + uzbl = self['uzbls'][client] try: - uzbl = self['uzbls'][client] - try: - raw = unicode(client.recv(8192), 'utf-8', 'ignore') - - except: - print_exc() - raw = None - - if not raw: - # Read null byte, close socket. - return self.close_connection(client) - - uzbl.buffer += raw - msgs = uzbl.buffer.split('\n') - uzbl.buffer = msgs.pop() - - for msg in msgs: - self.parse_msg(uzbl, msg) + raw = unicode(client.recv(8192), 'utf-8', 'ignore') except: - raise - - - def parse_msg(self, uzbl, msg): - '''Parse an incoming msg from a uzbl instance. All non-event messages - will be printed here and not be passed to the uzbl instance event - handler function.''' - - msg = msg.strip() - if not msg: - return - - cmd = _RE_FINDSPACES.split(msg, 3) - if not cmd or cmd[0] != 'EVENT': - # Not an event message. - print '---', msg - return + print_exc() + raw = None - if len(cmd) < 4: - cmd.append('') + if not raw: + # Read null byte, close socket. + return self.close_connection(client) - event, args = cmd[2], cmd[3] + uzbl.buffer += raw + msgs = uzbl.buffer.split('\n') + uzbl.buffer = msgs.pop() - try: - uzbl.event(event, args) + for msg in msgs: + try: + parse_msg(uzbl, msg.strip()) - except: - print_exc() + except: + print_exc() def accept_connection(self): @@ -656,7 +664,7 @@ class UzblEventDaemon(dict): except: print_exc() - if not len(self['uzbls']) and config['auto_close']: + if not len(self['uzbls']) and CONFIG['auto_close']: echo('auto closing event manager.') self.running = False @@ -673,14 +681,14 @@ class UzblEventDaemon(dict): echo('unlinking: %r' % self.socket_location) self._close_server_socket() - echo('deleting pid file: %r' % config['pid_file']) - del_pid_file(config['pid_file']) + echo('deleting pid file: %r' % CONFIG['pid_file']) + del_pid_file(CONFIG['pid_file']) -def stop(): +def stop_action(): '''Stop the event manager daemon.''' - pid_file = config['pid_file'] + pid_file = CONFIG['pid_file'] if not os.path.isfile(pid_file): return echo('no running daemon found.') @@ -698,10 +706,10 @@ def stop(): echo('stopped event daemon.') -def start(): +def start_action(): '''Start the event manager daemon.''' - pid_file = config['pid_file'] + pid_file = CONFIG['pid_file'] if os.path.isfile(pid_file): echo('found pid file: %r' % pid_file) pid = get_pid(pid_file) @@ -715,126 +723,129 @@ def start(): UzblEventDaemon().run() -def restart(): +def restart_action(): '''Restart the event manager daemon.''' echo('restarting event manager daemon.') - stop() - start() + stop_action() + start_action() -def list_plugins(): +def list_action(): '''List all the plugins being loaded by the event daemon.''' - plugins = find_plugins(config['plugin_dirs']) + plugins = find_plugins(CONFIG['plugin_dirs']) dirs = {} - for (plugin, dir) in plugins.items(): - if dir not in dirs: - dirs[dir] = [] + for (plugin, plugin_dir) in plugins.items(): + if plugin_dir not in dirs: + dirs[plugin_dir] = [] - dirs[dir].append(plugin) + dirs[plugin_dir].append(plugin) - for (index, (dir, plugin_list)) in enumerate(sorted(dirs.items())): + for (index, (plugin_dir, plugin_list)) in enumerate(sorted(dirs.items())): if index: print - print "%s:" % dir + print "%s:" % plugin_dir for plugin in sorted(plugin_list): print " %s" % plugin if __name__ == "__main__": - usage = "usage: %prog [options] {start|stop|restart|list}" - parser = OptionParser(usage=usage) - parser.add_option('-v', '--verbose', dest='verbose', action="store_true", + USAGE = "usage: %prog [options] {start|stop|restart|list}" + PARSER = OptionParser(usage=USAGE) + PARSER.add_option('-v', '--verbose', dest='verbose', action="store_true", help="print verbose output.") - parser.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", + PARSER.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", metavar="DIRS", help="Specify plugin directories in the form of "\ "'dir1:dir2:dir3'.") - parser.add_option('-l', '--load-plugins', dest="load", action="store", + PARSER.add_option('-l', '--load-plugins', dest="load", action="store", metavar="PLUGINS", help="comma separated list of plugins to load") - parser.add_option('-i', '--ignore-plugins', dest="ignore", action="store", + PARSER.add_option('-i', '--ignore-plugins', dest="ignore", action="store", metavar="PLUGINS", help="comma separated list of plugins to ignore") - parser.add_option('-p', '--pid-file', dest='pid', action='store', + PARSER.add_option('-p', '--pid-file', dest='pid', action='store', metavar='FILE', help="specify pid file location") - parser.add_option('-s', '--server-socket', dest='socket', action='store', + PARSER.add_option('-s', '--server-socket', dest='socket', action='store', metavar='SOCKET', help="specify the daemon socket location") - parser.add_option('-n', '--no-daemon', dest="daemon", + PARSER.add_option('-n', '--no-daemon', dest="daemon", action="store_true", help="don't enter daemon mode.") - parser.add_option('-a', '--auto-close', dest='autoclose', + PARSER.add_option('-a', '--auto-close', dest='autoclose', action='store_true', help='auto close after all instances disconnect.') - (options, args) = parser.parse_args() + (OPTIONS, ARGS) = PARSER.parse_args() - # init like {start|stop|..} daemon control section. - daemon_controls = {'start': start, 'stop': stop, 'restart': restart, - 'list': list_plugins} + # init like {start|stop|..} daemon actions dict. + DAEMON_ACTIONS = {'start': start_action, 'stop': stop_action, + 'restart': restart_action, 'list': list_action} - if len(args) == 1: - action = args[0] - if action not in daemon_controls: - error('unknown action: %r' % action) - sys.exit(1) + if not ARGS: + ACTION = 'start' - elif len(args) > 1: - error("too many arguments: %r" % args) - sys.exit(1) + elif len(ARGS) == 1: + ACTION = ARGS[0] + if ACTION not in DAEMON_ACTIONS: + raise ArgumentError("unknown argument: %r" % ACTION) else: - action = 'start' + raise ArgumentError("too many arguments: %r" % ARGS) # parse other flags & options. - if options.verbose: - config['verbose'] = True + if OPTIONS.verbose: + CONFIG['verbose'] = True + + if OPTIONS.plugin_dirs: + PLUGIN_DIRS = [] + for DIR in OPTIONS.plugin_dirs.split(':'): + if not DIR: + continue + + PLUGIN_DIRS.append(os.path.realpath(DIR)) - if options.plugin_dirs: - plugin_dirs = map(os.path.realpath, map(str.strip, - options.plugin_dirs.split(':'))) - config['plugin_dirs'] = plugin_dirs - echo("plugin search dirs: %r" % plugin_dirs) + CONFIG['plugin_dirs'] = PLUGIN_DIRS + echo("plugin search dirs: %r" % PLUGIN_DIRS) - if options.load and options.ignore: + if OPTIONS.load and OPTIONS.ignore: error("you can't load and ignore at the same time.") sys.exit(1) - elif options.load: - plugins_load = config['plugins_load'] - for plugin in options.load.split(','): - if plugin.strip(): - plugins_load.append(plugin.strip()) + elif OPTIONS.load: + LOAD = CONFIG['plugins_load'] + for PLUGIN in OPTIONS.load.split(','): + if PLUGIN.strip(): + LOAD.append(PLUGIN.strip()) - echo('only loading plugin(s): %s' % ', '.join(plugins_load)) + echo('only loading plugin(s): %s' % ', '.join(LOAD)) - elif options.ignore: - plugins_ignore = config['plugins_ignore'] - for plugin in options.ignore.split(','): - if plugin.strip(): - plugins_ignore.append(plugin.strip()) + elif OPTIONS.ignore: + IGNORE = CONFIG['plugins_ignore'] + for PLUGIN in OPTIONS.ignore.split(','): + if PLUGIN.strip(): + IGNORE.append(PLUGIN.strip()) - echo('ignoring plugin(s): %s' % ', '.join(plugins_ignore)) + echo('ignoring plugin(s): %s' % ', '.join(IGNORE)) - if options.autoclose: - config['auto_close'] = True + if OPTIONS.autoclose: + CONFIG['auto_close'] = True echo('will auto close.') - if options.pid: - config['pid_file'] = os.path.realpath(options.pid) - echo("pid file location: %r" % config['pid_file']) + if OPTIONS.pid: + CONFIG['pid_file'] = os.path.realpath(OPTIONS.pid) + echo("pid file location: %r" % CONFIG['pid_file']) - if options.socket: - config['server_socket'] = os.path.realpath(options.socket) - echo("daemon socket location: %s" % config['server_socket']) + if OPTIONS.socket: + CONFIG['server_socket'] = os.path.realpath(OPTIONS.socket) + echo("daemon socket location: %s" % CONFIG['server_socket']) - if options.daemon: - config['daemon_mode'] = False + if OPTIONS.daemon: + CONFIG['daemon_mode'] = False # Now {start|stop|...} - daemon_controls[action]() + DAEMON_ACTIONS[ACTION]() -- cgit v1.2.3 From 2ca39207613d6cbb78991baf4d6102fecabeb50f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 3 Dec 2009 14:56:10 +0800 Subject: Was raising an exception that didn't exist. --- examples/data/uzbl/plugins/bind.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 3e47e38..517bf98 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -27,6 +27,10 @@ find_prompts = re.compile('<([^:>]*):(\"[^\"]*\"|\'[^\']*\'|[^>]*)>').split ON_EXEC, HAS_ARGS, MOD_CMD, GLOB, MORE = range(5) +class ArgumentError(Exception): + pass + + def ismodbind(glob): '''Return True if the glob specifies a modbind.''' -- cgit v1.2.3 From 1cc25d8c1c98dd2c301984a2487b0d817dc96eba Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 3 Dec 2009 22:02:17 +0800 Subject: The MODE_CONFIG event was triggering itself in the bind plugin. --- examples/data/uzbl/plugins/bind.py | 3 ++- examples/data/uzbl/plugins/mode.py | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 517bf98..10cce6a 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -295,8 +295,9 @@ def clear_stack(uzbl): bind_dict['depth'] = 0 bind_dict['args'] = [] if bind_dict['last_mode']: - uzbl.set_mode(bind_dict['last_mode']) + mode = bind_dict['last_mode'] bind_dict['last_mode'] = '' + uzbl.set_mode(mode) uzbl.set('keycmd_prompt') diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index 2b2579a..f85d999 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -58,7 +58,8 @@ def get_mode(uzbl): def mode_changed(uzbl, mode): '''The mode has just been changed, now set the per-mode config.''' - get_mode_dict(uzbl)['mode'] = mode + if get_mode(uzbl) != mode: + return config = uzbl.get_config() mode_config = get_mode_config(uzbl, mode) @@ -92,12 +93,10 @@ def set_mode(uzbl, mode=None): if 'mode' not in config or config['mode'] != mode: config['mode'] = mode - return - - elif get_mode(uzbl) == mode: - return - uzbl.event("MODE_CHANGED", mode) + elif mode_dict['mode'] != mode: + mode_dict['mode'] = mode + uzbl.event("MODE_CHANGED", mode) def config_changed(uzbl, key, value): -- cgit v1.2.3 From 5f5ffd41a76a9ef6bf09e5fd5737ea1e2b2cd471 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 4 Dec 2009 01:20:06 +0800 Subject: Renamed {MOD,KEY}CMD_CLEAR to {MOD,KEY}CMD_CLEARED to reduce confusion. --- examples/data/uzbl/plugins/completion.py | 2 +- examples/data/uzbl/plugins/keycmd.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index 42e7e17..770f310 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -194,5 +194,5 @@ def init(uzbl): # And connect the dicts event handlers to the handler stack. uzbl.connect_dict(connects) - for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEAR']: + for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEARED']: uzbl.connect(event, stop_completion) diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index fd17363..0f5bb9b 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -257,7 +257,7 @@ def clear_keycmd(uzbl): k.cursor = 0 k._repr_cache = False uzbl.set('keycmd') - uzbl.event('KEYCMD_CLEAR') + uzbl.event('KEYCMD_CLEARED') def clear_modcmd(uzbl, clear_held=False): @@ -271,7 +271,7 @@ def clear_modcmd(uzbl, clear_held=False): k.held = set() uzbl.set('modcmd') - uzbl.event('MODCMD_CLEAR') + uzbl.event('MODCMD_CLEARED') def clear_current(uzbl): -- cgit v1.2.3 From 0061e5afefebcba68f5922e5d9d97ff6852788f3 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 4 Dec 2009 21:36:51 +0800 Subject: Fixed problem with keys persisting after their release events. --- examples/data/uzbl/plugins/keycmd.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 0f5bb9b..af6beff 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -33,6 +33,7 @@ class Keylet(object): def __init__(self): # Modcmd tracking self.held = set() + self.ignored = set() self.modcmd = '' self.is_modcmd = False @@ -82,15 +83,18 @@ class Keylet(object): results in a modkey addition. Return that addition and remove all modkeys that created it.''' - already_added = self.held & set(self.additions.keys()) - for key in already_added: - if modkey in self.additions[key]: + # Intersection of (held list + modkey) and additions. + added = (self.held | set([modkey])) & set(self.additions.keys()) + for key in added: + if key == modkey or modkey in self.additions[key]: + self.held -= self.additions[key] return key - modkeys = set(list(self.held) + [modkey,]) + # Held list + ignored list + modkey. + modkeys = self.held | self.ignored | set([modkey]) for (key, value) in self.additions.items(): if modkeys.issuperset(value): - self.held = modkeys ^ value + self.held -= value return key return modkey @@ -268,6 +272,7 @@ def clear_modcmd(uzbl, clear_held=False): k.is_modcmd = False k._repr_cache = False if clear_held: + k.ignored = set() k.held = set() uzbl.set('modcmd') @@ -335,7 +340,7 @@ def inject_str(str, index, inj): return "%s%s%s" % (str[:index], inj, str[index:]) -def get_keylet_and_key(uzbl, key): +def get_keylet_and_key(uzbl, key, add=True): '''Return the keylet and apply any transformations to the key as defined by the modmapping or modkey addition rules. Return None if the key is ignored.''' @@ -346,6 +351,14 @@ def get_keylet_and_key(uzbl, key): return (keylet, key) modkey = "<%s>" % key.strip("<>") + + if keylet.key_ignored(modkey): + if add: + keylet.ignored.add(modkey) + + elif modkey in keylet.ignored: + keylet.ignored.remove(modkey) + modkey = keylet.find_addition(modkey) if keylet.key_ignored(modkey): @@ -403,9 +416,7 @@ def key_release(uzbl, key): 3. Check if any modkey is held, if so set modcmd mode. 4. Update the keycmd uzbl variable if anything changed.''' - (k, key) = get_keylet_and_key(uzbl, key.strip()) - if not key: - return + (k, key) = get_keylet_and_key(uzbl, key.strip(), add=False) if key in k.held: if k.is_modcmd: -- cgit v1.2.3 From 4ba53742159e166fd25cc5c83a953bc1e39c81d9 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 5 Dec 2009 17:12:59 +0800 Subject: Added @jsh JavaScript helper variable. --- examples/config/uzbl/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a9ae29a..54de972 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -29,6 +29,8 @@ set shell_cmd = sh -c # Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts +# Javascipt helpers. +set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; # === Handlers =============================================================== @@ -141,7 +143,6 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } # Edit HTML forms in external editor -# set external_editor = gvim #set external_editor = xterm -e vim @bind E = script @scripts_dir/extedit.js -- cgit v1.2.3 From 5c514a0d42324efbb60c657d171e93720ba422b1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 5 Dec 2009 18:19:55 +0800 Subject: Updated binding to use the new @jsh helper. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 54de972..69a211c 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -140,7 +140,7 @@ set socket_dir = /tmp # otherwise open the selection in the current window set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' -@bind = js if("\@SELECTED_URI") { Uzbl.run("\@open_new_window"); } else { Uzbl.run("\\\@load_from_xclip"); } +@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } # Edit HTML forms in external editor set external_editor = gvim -- cgit v1.2.3 From 436c319e2e2543a04c34e1f79b2ab10bc391c927 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 5 Dec 2009 21:56:39 +0100 Subject: fix deprecated command. fixes FS#139 --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9fda268..f3e9f6a 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -190,7 +190,7 @@ menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js # go to the page in clipboard @bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' # start a new uzbl instance from the page in primary selection -@bind 'p = sh 'exec uzbl --uri $(xclip -o)' +@bind 'p = sh 'exec uzbl-browser --uri $(xclip -o)' @bind ZZ = exit @bind Xs = js alert("hi"); # example showing how to use sh -- cgit v1.2.3 From ff64a2d37fa68015e70928a9dc7867c8d1c3815e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Dec 2009 16:21:12 +0800 Subject: Standardise expansion across plugins. --- examples/data/uzbl/plugins/bind.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 10cce6a..076d712 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -224,6 +224,20 @@ class Bind(object): return self._repr_cache +def expand(cmd, args): + '''Replaces "%s %1 %2 %3..." with " ...".''' + + if '%s' in cmd: + cmd = cmd.replace('%s', ' '.join(map(unicode, args))) + + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) + + return cmd + + def exec_bind(uzbl, bind, *args, **kargs): '''Execute bind objects.''' @@ -240,14 +254,7 @@ def exec_bind(uzbl, bind, *args, **kargs): commands = [] for cmd in bind.commands: - if '%s' in cmd: - if len(args) > 1: - for arg in args: - cmd = cmd.replace('%s', arg, 1) - - elif len(args) == 1: - cmd = cmd.replace('%s', args[0]) - + cmd = expand(cmd, args) uzbl.send(cmd) -- cgit v1.2.3 From 3d2043d8f46855e8c3724e65bd5848c06ed27069 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Dec 2009 17:26:48 +0800 Subject: Multiple stack binds that have the same prefix now work. --- examples/data/uzbl/plugins/bind.py | 113 +++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 50 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 076d712..9702434 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -11,13 +11,15 @@ And it is also possible to execute a function on activation: import sys import re +import pprint # Export these functions to uzbl. __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] # Hold the bind dicts for each uzbl instance. UZBLS = {} -DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': [], 'last_mode': ''} +DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': [], + 'last_mode': '', 'after': None} # Commonly used regular expressions. starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') @@ -78,21 +80,11 @@ def get_binds(uzbl): return get_bind_dict(uzbl)['binds'] -def get_stack_depth(uzbl): - '''Return the stack for the uzbl instance.''' - - return get_bind_dict(uzbl)['depth'] - - -def get_filtered_binds(uzbl): +def get_filtered_binds(uzbl, bd): '''Return the bind list for the uzbl instance or return the filtered bind list thats on the current stack.''' - bind_dict = get_bind_dict(uzbl) - if bind_dict['depth']: - return list(bind_dict['stack']) - - return list(bind_dict['binds']) + return bd['stack'] if bd['depth'] else bd['binds'] def del_bind(uzbl, bind): @@ -294,44 +286,51 @@ def mode_changed(uzbl, mode): clear_stack(uzbl) -def clear_stack(uzbl): +def clear_stack(uzbl, bd=None): '''Clear everything related to stacked binds.''' - bind_dict = get_bind_dict(uzbl) - bind_dict['stack'] = [] - bind_dict['depth'] = 0 - bind_dict['args'] = [] - if bind_dict['last_mode']: - mode = bind_dict['last_mode'] - bind_dict['last_mode'] = '' + if bd is None: + bd = get_bind_dict(uzbl) + + bd['stack'] = [] + bd['depth'] = 0 + bd['args'] = [] + bd['after'] = None + if bd['last_mode']: + mode, bd['last_mode'] = bd['last_mode'], '' uzbl.set_mode(mode) uzbl.set('keycmd_prompt') -def stack_bind(uzbl, bind, args, depth): +def stack_bind(uzbl, bind, args, depth, bd): '''Increment the stack depth in the bind dict, generate filtered bind list for stack mode and set keycmd prompt.''' - bind_dict = get_bind_dict(uzbl) - if bind_dict['depth'] != depth: - if bind not in bind_dict['stack']: - bind_dict['stack'].append(bind) + if bd['depth'] != depth: + if bind not in bd['stack']: + bd['stack'].append(bind) return if uzbl.get_mode() != 'stack': - bind_dict['last_mode'] = uzbl.get_mode() + bd['last_mode'] = uzbl.get_mode() uzbl.set_mode('stack') - globalcmds = [cmd for cmd in bind_dict['binds'] if cmd.is_global] - bind_dict['stack'] = [bind,] + globalcmds - bind_dict['args'] += args - bind_dict['depth'] = depth + 1 + globalcmds = [cmd for cmd in bd['binds'] if cmd.is_global] + bd['stack'] = [bind,] + globalcmds + bd['args'] += args + bd['depth'] = depth + 1 + bd['after'] = bind.prompts[depth] + - uzbl.send('event BIND_STACK_LEVEL %d' % bind_dict['depth']) +def after_bind(uzbl, bd): + '''Check if there are afte-actions to perform.''' + + if bd['after'] is None: + return - (prompt, set) = bind.prompts[depth] + (prompt, set), bd['after'] = bd['after'], None if prompt: uzbl.set('keycmd_prompt', '%s:' % prompt) @@ -344,9 +343,11 @@ def stack_bind(uzbl, bind, args, depth): else: uzbl.clear_keycmd() + uzbl.send('event BIND_STACK_LEVEL %d' % bd['depth']) + + +def match_and_exec(uzbl, bind, depth, keylet, bd): -def match_and_exec(uzbl, bind, depth, keylet): - bind_dict = get_bind_dict(uzbl) (on_exec, has_args, mod_cmd, glob, more) = bind[depth] held = keylet.held @@ -375,62 +376,74 @@ def match_and_exec(uzbl, bind, depth, keylet): return True elif more: - stack_bind(uzbl, bind, args, depth) + stack_bind(uzbl, bind, args, depth, bd) return False - args = bind_dict['args'] + args + args = bd['args'] + args exec_bind(uzbl, bind, *args) uzbl.set_mode() if not has_args: - clear_stack(uzbl) + clear_stack(uzbl, bd) uzbl.clear_current() return True def keycmd_update(uzbl, keylet): - depth = get_stack_depth(uzbl) - for bind in get_filtered_binds(uzbl): + bd = get_bind_dict(uzbl) + depth = bd['depth'] + for bind in get_filtered_binds(uzbl, bd): t = bind[depth] if t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet): + if match_and_exec(uzbl, bind, depth, keylet, bd): return + after_bind(uzbl, bd) + def keycmd_exec(uzbl, keylet): - depth = get_stack_depth(uzbl) - for bind in get_filtered_binds(uzbl): + bd = get_bind_dict(uzbl) + depth = bd['depth'] + for bind in get_filtered_binds(uzbl, bd): t = bind[depth] if t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet): + if match_and_exec(uzbl, bind, depth, keylet, bd): return uzbl.clear_keycmd() + after_bind(uzbl, bd) + def modcmd_update(uzbl, keylet): - depth = get_stack_depth(uzbl) - for bind in get_filtered_binds(uzbl): + bd = get_bind_dict(uzbl) + depth = bd['depth'] + for bind in get_filtered_binds(uzbl, bd): t = bind[depth] if not t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet): + if match_and_exec(uzbl, bind, depth, keylet, bd): return + after_bind(uzbl, bd) + def modcmd_exec(uzbl, keylet): - depth = get_stack_depth(uzbl) - for bind in get_filtered_binds(uzbl): + bd = get_bind_dict(uzbl) + depth = bd['depth'] + for bind in get_filtered_binds(uzbl, bd): t = bind[depth] if not t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet): + if match_and_exec(uzbl, bind, depth, keylet, bd): return uzbl.clear_modcmd() + after_bind(uzbl, bd) + def init(uzbl): connects = {'BIND': parse_bind_event, -- cgit v1.2.3 From 019e0daa88065c23491d9104a07590f97f5c7337 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 6 Dec 2009 17:35:50 +0800 Subject: Left in unused pprint lib. --- examples/data/uzbl/plugins/bind.py | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 9702434..3dedf16 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -11,7 +11,6 @@ And it is also possible to execute a function on activation: import sys import re -import pprint # Export these functions to uzbl. __export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] -- cgit v1.2.3 From c419594e8aff0fdc17c21e9313169e08f3050a73 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 6 Dec 2009 18:46:57 +0100 Subject: support executing commands both through shell and directly --- README | 13 +++++++++++-- examples/config/uzbl/config | 2 +- uzbl-core.c | 29 ++++++++++++++++++----------- 3 files changed, 30 insertions(+), 14 deletions(-) (limited to 'examples') diff --git a/README b/README index 23b0f4e..1ac42a8 100644 --- a/README +++ b/README @@ -291,12 +291,21 @@ The above example demonstrates two things: Command substitution will launch any commands and substitute the call with the return value of the command. +There are two methods: -Uzbl will substitute any commands enclosed within @( )@: + * through a shell: enclose commands with @( )@ (quotes escaping is handled by uzbl): print Command substitution: @(uname -a)@ -You can access any uzbl variable from within a command substitution: +This method allows you to use posix shell syntax in your commands + + * directly: + + print Command substitution: @(+uname -a)@ + +This example will execute uname directly + +Note that you can access any uzbl variable from within a command substitution: print @(echo -n 'Accessing the show_status var from an external script, value: @show_status')@ diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 5585195..94b1e73 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -108,7 +108,7 @@ set status_format = @mode_section @keycmd_sect # === Core settings ========================================================== -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(uname -o)@ @(uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(+uname -o)@ @(+uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) set fifo_dir = /tmp set socket_dir = /tmp diff --git a/uzbl-core.c b/uzbl-core.c index 42e274e..01d0803 100644 --- a/uzbl-core.c +++ b/uzbl-core.c @@ -266,17 +266,24 @@ expand(const char *s, guint recurse) { } else if(recurse != 1 && etype == EXP_EXPR) { - - mycmd = expand(ret, 1); - gchar *quoted = g_shell_quote(mycmd); - gchar *tmp = g_strdup_printf("%s %s", - uzbl.behave.shell_cmd?uzbl.behave.shell_cmd:"/bin/sh -c", - quoted); - g_spawn_command_line_sync(tmp, &cmd_stdout, NULL, NULL, &err); - g_free(mycmd); - g_free(quoted); - g_free(tmp); - + /* execute program directly */ + if(ret[0] == '+') { + mycmd = expand(ret+1, 1); + g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err); + g_free(mycmd); + } + /* execute program through shell, quote it first */ + else { + mycmd = expand(ret, 1); + gchar *quoted = g_shell_quote(mycmd); + gchar *tmp = g_strdup_printf("%s %s", + uzbl.behave.shell_cmd?uzbl.behave.shell_cmd:"/bin/sh -c", + quoted); + g_spawn_command_line_sync(tmp, &cmd_stdout, NULL, NULL, &err); + g_free(mycmd); + g_free(quoted); + g_free(tmp); + } if (err) { g_printerr("error on running command: %s\n", err->message); g_error_free (err); -- cgit v1.2.3 From 8a342efb325d682fdfbb4a2ba07e98dfd53c1f2f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 12 Dec 2009 17:34:28 +0800 Subject: Initial commit of mode binding support. Summary of changes: 1. Use an object to track the per instance bind status/state instead of a dict. 2. Added support for stack syntax. 3. Stack finding regex now supports dumb-quoting of prompt also. 4. Mode bind event syntax is "MODE_BIND = " 4. Added legacy support for BIND event and bind function. 5. Mode binds can be bound to multiple modes at once. 6. Mode exclusion supported (i.e. "MODE_BIND global,-insert ..."). 7. Fixed keycmd ghosting after entering stack mode. 8. Added examples to bind functions. --- examples/data/uzbl/plugins/bind.py | 381 ++++++++++++++++++++++--------------- 1 file changed, 228 insertions(+), 153 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 3dedf16..6d08555 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -11,52 +11,145 @@ And it is also possible to execute a function on activation: import sys import re +import pprint # Export these functions to uzbl. -__export__ = ['bind', 'del_bind', 'del_bind_by_glob', 'get_binds'] +__export__ = ['bind', 'mode_bind', 'get_bindlet'] # Hold the bind dicts for each uzbl instance. UZBLS = {} -DEFAULTS = {'binds': [], 'depth': 0, 'stack': [], 'args': [], - 'last_mode': '', 'after': None} # Commonly used regular expressions. -starts_with_mod = re.compile('^<([A-Z][A-Za-z0-9-_]*)>') -find_prompts = re.compile('<([^:>]*):(\"[^\"]*\"|\'[^\']*\'|[^>]*)>').split +MOD_START = re.compile('^<([A-Z][A-Za-z0-9-_]*)>').match +# Matches , <'x':y>, <:'y'>, , <'x'!y>, ... +PROMPTS = '<(\"[^\"]*\"|\'[^\']*\'|[^:!>]*)(:|!)(\"[^\"]*\"|\'[^\']*\'|[^>]*)>' +FIND_PROMPTS = re.compile(PROMPTS).split +VALID_MODE = re.compile('^(-|)[A-Za-z0-9][A-Za-z0-9_]*$').match # For accessing a bind glob stack. ON_EXEC, HAS_ARGS, MOD_CMD, GLOB, MORE = range(5) -class ArgumentError(Exception): - pass +# Custom errors. +class ArgumentError(Exception): pass -def ismodbind(glob): - '''Return True if the glob specifies a modbind.''' +class Bindlet(object): + '''Per-instance bind status/state tracker.''' - return bool(starts_with_mod.match(glob)) + def __init__(self, uzbl): + self.binds = {'global': {}} + self.uzbl = uzbl + self.depth = 0 + self.args = [] + self.last_mode = None + self.after_cmds = None + self.stack_binds = [] + # A subset of the global mode binds containing non-stack and modkey + # activiated binds for use in the stack mode. + self.globals = [] -def split_glob(glob): - '''Take a string of the form "cmd _" and return a list of the - modkeys in the glob and the command.''' - mods = set() - while True: - match = starts_with_mod.match(glob) - if not match: - break + def __getitem__(self, key): + return self.get_binds(key) - end = match.span()[1] - mods.add(glob[:end]) - glob = glob[end:] - return (mods, glob) + def reset(self): + '''Reset the tracker state and return to last mode.''' + + self.depth = 0 + self.args = [] + self.after_cmds = None + self.stack_binds = [] + + if self.last_mode: + mode, self.last_mode = self.last_mode, None + self.uzbl.set_mode(mode) + + self.uzbl.set('keycmd_prompt') + + + def stack(self, bind, args, depth): + '''Enter or add new bind in the next stack level.''' + + if self.depth != depth: + if bind not in self.stack_binds: + self.stack_binds.append(bind) + + return + + current_mode = self.uzbl.get_mode() + if current_mode != 'stack': + self.last_mode = current_mode + self.uzbl.set_mode('stack') + + self.stack_binds = [bind,] + self.args += args + self.depth += 1 + self.after_cmds = bind.prompts[depth] + + + def after(self): + '''If a stack was triggered then set the prompt and default value.''' + + if self.after_cmds is None: + return + + (prompt, cmd, set), self.after_cmds = self.after_cmds, None + + self.uzbl.clear_keycmd() + if prompt: + self.uzbl.set('keycmd_prompt', prompt) + + if set and cmd: + self.uzbl.send(cmd) + + elif set and not cmd: + self.uzbl.send('event SET_KEYCMD %s' % set) + + + def get_binds(self, mode=None): + '''Return the mode binds + globals. If we are stacked then return + the filtered stack list and modkey & non-stack globals.''' + + if mode is None: + mode = self.uzbl.get_mode() + + if not mode: + mode = 'global' + + if self.depth: + return self.stack_binds + self.globals + + globals = self.binds['global'] + if mode not in self.binds or mode == 'global': + return filter(None, globals.values()) + + binds = dict(globals.items() + self.binds[mode].items()) + return filter(None, binds.values()) + + + def add_bind(self, mode, glob, bind=None): + '''Insert (or override) a bind into the mode bind dict.''' + + if mode not in self.binds: + self.binds[mode] = {glob: bind} + return + + binds = self.binds[mode] + binds[glob] = bind + + if mode == 'global': + # Regen the global-globals list. + self.globals = [] + for bind in binds.values(): + if bind is not None and bind.is_global: + self.globals.append(bind) def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) + UZBLS[uzbl] = Bindlet(uzbl) def del_instance(uzbl, *args): @@ -64,8 +157,8 @@ def del_instance(uzbl, *args): del UZBLS[uzbl] -def get_bind_dict(uzbl): - '''Return the bind dict for the uzbl instance.''' +def get_bindlet(uzbl): + '''Return the bind tracklet for the given uzbl instance.''' if uzbl not in UZBLS: add_instance(uzbl) @@ -73,42 +166,36 @@ def get_bind_dict(uzbl): return UZBLS[uzbl] -def get_binds(uzbl): - '''Return the bind list for the uzbl instance.''' - - return get_bind_dict(uzbl)['binds'] - +def ismodbind(glob): + '''Return True if the glob specifies a modbind.''' -def get_filtered_binds(uzbl, bd): - '''Return the bind list for the uzbl instance or return the filtered - bind list thats on the current stack.''' + return bool(MOD_START(glob)) - return bd['stack'] if bd['depth'] else bd['binds'] +def split_glob(glob): + '''Take a string of the form "cmd _" and return a list of the + modkeys in the glob and the command.''' -def del_bind(uzbl, bind): - '''Delete bind object if bind in the uzbl binds.''' + mods = set() + while True: + match = MOD_START(glob) + if not match: + break - binds = get_binds(uzbl) - if bind in binds: - binds.remove(bind) - uzbl.event('DELETED_BIND', bind) - return True + end = match.span()[1] + mods.add(glob[:end]) + glob = glob[end:] - return False + return (mods, glob) -def del_bind_by_glob(uzbl, glob): - '''Delete bind by glob if bind in the uzbl binds.''' +def unquote(str): + '''Remove quotation marks around string.''' - binds = get_binds(uzbl) - for bind in list(binds): - if bind.glob == glob: - binds.remove(bind) - uzbl.event('DELETED_BIND', bind) - return True + if str and str[0] == str[-1] and str[0] in ['"', "'"]: + str = str[1:-1] - return False + return str class Bind(object): @@ -143,29 +230,30 @@ class Bind(object): self.counter[0] += 1 self.bid = self.counter[0] - self.split = split = find_prompts(glob) + self.split = split = FIND_PROMPTS(glob) self.prompts = [] - for (prompt, set) in zip(split[1::3], split[2::3]): - if set and set[0] == set[-1] and set[0] in ['"', "'"]: - # Remove quotes around set. - set = set[1:-1] + for (prompt, cmd, set) in zip(split[1::4], split[2::4], split[3::4]): + prompt, set = map(unquote, [prompt, set]) + cmd = True if cmd == '!' else False + if prompt and prompt[-1] != ":": + prompt = "%s:" % prompt - self.prompts.append((prompt, set)) + self.prompts.append((prompt, cmd, set)) # Check that there is nothing like: fl** - for glob in split[:-1:3]: + for glob in split[:-1:4]: if glob.endswith('*'): msg = "token '*' not at the end of a prompt bind: %r" % split raise SyntaxError(msg) # Check that there is nothing like: fl_ - for glob in split[3::3]: + for glob in split[4::4]: if not glob: msg = 'found null segment after first prompt: %r' % split raise SyntaxError(msg) stack = [] - for (index, glob) in enumerate(reversed(split[::3])): + for (index, glob) in enumerate(reversed(split[::4])): # Is the binding a MODCMD or KEYCMD: mod_cmd = ismodbind(glob) @@ -249,103 +337,89 @@ def exec_bind(uzbl, bind, *args, **kargs): uzbl.send(cmd) -def bind(uzbl, glob, handler, *args, **kargs): - '''Add a bind handler object.''' - - # Mods come from the keycmd sorted so make sure the modkeys in the bind - # command are sorted too. - - del_bind_by_glob(uzbl, glob) - binds = get_binds(uzbl) +def mode_bind(uzbl, modes, glob, handler=None, *args, **kargs): + '''Add a mode bind.''' - bind = Bind(glob, handler, *args, **kargs) - binds.append(bind) + bindlet = get_bindlet(uzbl) - uzbl.event('ADDED_BIND', bind) + if not hasattr(modes, '__iter__'): + modes = unicode(modes).split(',') + # Sort and filter binds. + modes = filter(None, map(unicode.strip, modes)) -def parse_bind_event(uzbl, args): - '''Break "event BIND fl* = js follownums.js" into (glob, command).''' + if callable(handler) or (handler is not None and handler.strip()): + bind = Bind(glob, handler, *args, **kargs) - if not args: - raise ArgumentError('missing bind arguments') - - split = map(unicode.strip, args.split('=', 1)) - if len(split) != 2: - raise ArgumentError('missing delimiter in bind: %r' % args) - - glob, command = split - bind(uzbl, glob, command) - - -def mode_changed(uzbl, mode): - '''Clear the stack on all non-stack mode changes.''' + else: + bind = None - if mode != 'stack': - clear_stack(uzbl) + for mode in modes: + if not VALID_MODE(mode): + raise NameError('invalid mode name: %r' % mode) + for mode in modes: + if mode[0] == '-': + mode, bind = mode[1:], None -def clear_stack(uzbl, bd=None): - '''Clear everything related to stacked binds.''' + bindlet.add_bind(mode, glob, bind) + uzbl.event('ADDED_MODE_BIND', mode, glob, bind) - if bd is None: - bd = get_bind_dict(uzbl) - bd['stack'] = [] - bd['depth'] = 0 - bd['args'] = [] - bd['after'] = None - if bd['last_mode']: - mode, bd['last_mode'] = bd['last_mode'], '' - uzbl.set_mode(mode) +def bind(uzbl, glob, handler, *args, **kargs): + '''Legacy bind function.''' - uzbl.set('keycmd_prompt') + mode_bind(uzbl, 'global', glob, handler, *args, **kargs) -def stack_bind(uzbl, bind, args, depth, bd): - '''Increment the stack depth in the bind dict, generate filtered bind - list for stack mode and set keycmd prompt.''' +def parse_mode_bind(uzbl, args): + '''Parser for the MODE_BIND event. - if bd['depth'] != depth: - if bind not in bd['stack']: - bd['stack'].append(bind) + Example events: + MODE_BIND = + MODE_BIND command o_ = uri %s + MODE_BIND insert,command = ... + MODE_BIND global ... = ... + MODE_BIND global,-insert ... = ... + ''' - return + if not args: + raise ArgumentError('missing bind arguments') - if uzbl.get_mode() != 'stack': - bd['last_mode'] = uzbl.get_mode() - uzbl.set_mode('stack') + split = map(unicode.strip, args.split(' ', 1)) + if len(split) != 2: + raise ArgumentError('missing mode or bind section: %r' % args) - globalcmds = [cmd for cmd in bd['binds'] if cmd.is_global] - bd['stack'] = [bind,] + globalcmds - bd['args'] += args - bd['depth'] = depth + 1 - bd['after'] = bind.prompts[depth] + modes, args = split[0].split(','), split[1] + split = map(unicode.strip, args.split('=', 1)) + if len(split) != 2: + raise ArgumentError('missing delimiter in bind section: %r' % args) + glob, command = split + mode_bind(uzbl, modes, glob, command) -def after_bind(uzbl, bd): - '''Check if there are afte-actions to perform.''' - if bd['after'] is None: - return +def parse_bind(uzbl, args): + '''Legacy parsing of the BIND event and conversion to the new format. - (prompt, set), bd['after'] = bd['after'], None - if prompt: - uzbl.set('keycmd_prompt', '%s:' % prompt) + Example events: + request BIND = + request BIND o_ = uri %s + request BIND = ... + request BIND ... = ... + ''' - else: - uzbl.set('keycmd_prompt') + parse_mode_bind(uzbl, "global %s" % args) - if set: - uzbl.send('event SET_KEYCMD %s' % set) - else: - uzbl.clear_keycmd() +def mode_changed(uzbl, mode): + '''Clear the stack on all non-stack mode changes.''' - uzbl.send('event BIND_STACK_LEVEL %d' % bd['depth']) + if mode != 'stack': + get_bindlet(uzbl).reset() -def match_and_exec(uzbl, bind, depth, keylet, bd): +def match_and_exec(uzbl, bind, depth, keylet, bindlet): (on_exec, has_args, mod_cmd, glob, more) = bind[depth] @@ -375,10 +449,10 @@ def match_and_exec(uzbl, bind, depth, keylet, bd): return True elif more: - stack_bind(uzbl, bind, args, depth, bd) + bindlet.stack(bind, args, depth) return False - args = bd['args'] + args + args = bindlet.args + args exec_bind(uzbl, bind, *args) uzbl.set_mode() if not has_args: @@ -389,63 +463,64 @@ def match_and_exec(uzbl, bind, depth, keylet, bd): def keycmd_update(uzbl, keylet): - bd = get_bind_dict(uzbl) - depth = bd['depth'] - for bind in get_filtered_binds(uzbl, bd): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): t = bind[depth] if t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet, bd): + if match_and_exec(uzbl, bind, depth, keylet, bindlet): return - after_bind(uzbl, bd) + bindlet.after() def keycmd_exec(uzbl, keylet): - bd = get_bind_dict(uzbl) - depth = bd['depth'] - for bind in get_filtered_binds(uzbl, bd): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): t = bind[depth] if t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet, bd): + if match_and_exec(uzbl, bind, depth, keylet, bindlet): return uzbl.clear_keycmd() - after_bind(uzbl, bd) + bindlet.after() def modcmd_update(uzbl, keylet): - bd = get_bind_dict(uzbl) - depth = bd['depth'] - for bind in get_filtered_binds(uzbl, bd): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): t = bind[depth] if not t[MOD_CMD] or t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet, bd): + if match_and_exec(uzbl, bind, depth, keylet, bindlet): return - after_bind(uzbl, bd) + bindlet.after() def modcmd_exec(uzbl, keylet): - bd = get_bind_dict(uzbl) - depth = bd['depth'] - for bind in get_filtered_binds(uzbl, bd): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): t = bind[depth] if not t[MOD_CMD] or not t[ON_EXEC]: continue - if match_and_exec(uzbl, bind, depth, keylet, bd): + if match_and_exec(uzbl, bind, depth, keylet, bindlet): return uzbl.clear_modcmd() - after_bind(uzbl, bd) + bindlet.after() def init(uzbl): - connects = {'BIND': parse_bind_event, + connects = {'BIND': parse_bind, + 'MODE_BIND': parse_mode_bind, 'KEYCMD_UPDATE': keycmd_update, 'MODCMD_UPDATE': modcmd_update, 'KEYCMD_EXEC': keycmd_exec, -- cgit v1.2.3 From b64ddd7bce761b53839f981949fce6fd6daa855c Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 12 Dec 2009 17:57:56 +0800 Subject: Unbreak stack binds. --- examples/data/uzbl/plugins/bind.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 6d08555..0f0d0ce 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -96,16 +96,16 @@ class Bindlet(object): if self.after_cmds is None: return - (prompt, cmd, set), self.after_cmds = self.after_cmds, None + (prompt, is_cmd, set), self.after_cmds = self.after_cmds, None self.uzbl.clear_keycmd() if prompt: self.uzbl.set('keycmd_prompt', prompt) - if set and cmd: - self.uzbl.send(cmd) + if set and is_cmd: + self.uzbl.send(set) - elif set and not cmd: + elif set and not is_cmd: self.uzbl.send('event SET_KEYCMD %s' % set) -- cgit v1.2.3 From f75a2b19017778a8dace0a8004d2a7cf10323bfd Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 13 Dec 2009 04:32:38 +0800 Subject: Removing call to deprecated function. --- examples/data/uzbl/plugins/bind.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 0f0d0ce..8d9bc91 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -456,7 +456,7 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): exec_bind(uzbl, bind, *args) uzbl.set_mode() if not has_args: - clear_stack(uzbl, bd) + bindlet.reset() uzbl.clear_current() return True -- cgit v1.2.3 From 00de6ef299fb3aedc8a0dc56a799e547f481dd68 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 13 Dec 2009 05:10:39 +0800 Subject: Print all events, store the instance pid and check event name. --- examples/data/uzbl/scripts/uzbl-event-manager | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 6669282..7a02da9 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -357,6 +357,7 @@ class UzblInstance(object): self.depth = 0 self.buffer = '' + self.pid = None # Call the init() function in every plugin. Inside the init function # is where the plugins insert the hooks into the event system. @@ -423,6 +424,9 @@ class UzblInstance(object): '''Connect event with handler and return the newly created handler. Handlers can either be a function or a uzbl command string.''' + event = event.upper().strip() + assert event and ' ' not in event + if event not in self._handlers.keys(): self._handlers[event] = [] @@ -478,12 +482,16 @@ class UzblInstance(object): def event(self, event, *args, **kargs): - '''Raise a custom event.''' + '''Raise an event.''' + + event = event.upper() + elems = [event,] + if args: elems.append(unicode(args)) + if kargs: elems.append(unicode(kargs)) + print "%s--> %s" % (' ' * self.depth, ' '.join(elems)) - # Silence _printing_ of geo events while debugging. - if event != "GEOMETRY_CHANGED": - print "%s--> %s %s %s" % (' ' * self.depth, event, args, - '' if not kargs else kargs) + if event == "INSTANCE_START" and args: + self.pid = int(args[0]) if event not in self._handlers: return -- cgit v1.2.3 From 77e2678988494be1146ab6141f547fa64b8401b7 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 13 Dec 2009 21:28:12 +0800 Subject: Clear the keycmd after link follow. --- examples/data/uzbl/scripts/follow_Numbers.js | 5 +++++ examples/data/uzbl/scripts/follow_Numbers_Strings.js | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow_Numbers.js b/examples/data/uzbl/scripts/follow_Numbers.js index efde4d7..00b279e 100644 --- a/examples/data/uzbl/scripts/follow_Numbers.js +++ b/examples/data/uzbl/scripts/follow_Numbers.js @@ -17,6 +17,10 @@ var doc = document; var win = window; var links = document.links; var forms = document.forms; + +//Reset keycmd, modcmd and return to default mode. +function clearKeycmd() { Uzbl.run('set mode ='); } + //Make onlick-links "clickable" try { HTMLElement.prototype.click = function() { @@ -123,6 +127,7 @@ function generateHint(el, label) { //but at least set the href of the link. (needs some improvements) function clickElem(item) { removeAllHints(); + clearKeycmd(); if (item) { var name = item.tagName; if (name == 'A') { diff --git a/examples/data/uzbl/scripts/follow_Numbers_Strings.js b/examples/data/uzbl/scripts/follow_Numbers_Strings.js index 67da2f9..e50da5d 100644 --- a/examples/data/uzbl/scripts/follow_Numbers_Strings.js +++ b/examples/data/uzbl/scripts/follow_Numbers_Strings.js @@ -4,6 +4,10 @@ var doc = document; var win = window; var links = document.links; var forms = document.forms; + +//Reset keycmd, modcmd and return to default mode. +function clearKeycmd() { Uzbl.run('set mode ='); } + try { HTMLElement.prototype.click = function() { if (typeof this.onclick == 'function') { @@ -93,8 +97,10 @@ function generateHint(el, label) { hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; return hint; } + function clickElem(item) { removeAllHints(); + clearKeycmd(); if (item) { var name = item.tagName; if (name == 'A') { @@ -117,6 +123,7 @@ function clickElem(item) { } } } + function addLinks() { res = [[], []]; for (var l = 0; l < links.length; l++) { -- cgit v1.2.3 From 1c0e3e17db56de531feaac089f7744284b747243 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 14 Dec 2009 00:00:19 +0800 Subject: Make sure the config keys for all possible completions are known. --- examples/data/uzbl/plugins/completion.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index 770f310..8e055e1 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -29,6 +29,9 @@ def escape(str): def add_instance(uzbl, *args): UZBLS[uzbl] = dict(DEFAULTS) + # Make sure the config keys for all possible completions are known. + uzbl.send('dump_config_as_events') + def del_instance(uzbl, *args): if uzbl in UZBLS: -- cgit v1.2.3 From 3261368285832a1efc552a8be4dfd7e6f53b5505 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 14 Dec 2009 03:00:19 +0800 Subject: Fix some comments, orders and alignments in the example config. --- examples/config/uzbl/config | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 5585195..d627059 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -1,33 +1,36 @@ # example uzbl config. # all settings are optional. you can use uzbl without any config at all (but it won't do much) -set prefix = /usr/local +set prefix = /usr/local # === Shortcuts / Aliases =================================================== +# Config related events (use the request function): # request BIND = -set bind = request BIND +set bind = request BIND # request MODE_CONFIG = ... -set toggle_modes = event TOGGLE_MODES +set mode_config = request MODE_CONFIG # request ON_EVENT -set on_event = request ON_EVENT +set on_event = request ON_EVENT # request PROGRESS_CONFIG = -set progress = request PROGRESS_CONFIG +set progress = request PROGRESS_CONFIG # request MODMAP From To -set modmap = request MODMAP +set modmap = request MODMAP # request IGNORE_KEY -set ignore_key = request IGNORE_KEY +set ignore_key = request IGNORE_KEY # request MODKEY_ADDITION set modkey_addition = request MODKEY_ADDITION -set set_mode = set mode = -set set_status = set status_message = -set shell_cmd = sh -c +# Action related events (use the event function): +# event TOGGLE_MODES ... +set toggle_modes = event TOGGLE_MODES + +set set_mode = set mode = +set set_status = set status_message = +set shell_cmd = sh -c # Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" -set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts +set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts # Javascipt helpers. set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; @@ -231,15 +234,15 @@ set formfiller = spawn @scripts_dir/formfiller # Examples using multi-stage-bindings with text prompts. -@bind o_ = uri %s -@bind O_ = uri %s +@bind o_ = uri %s +@bind O_ = uri %s # multi-stage binding way to write bookmarks to file from inside uzbl. -@bind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +@bind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' # Multi-stage bindings with blank prompts (similar behaviour to emacs M-c M-s bindings?) -@bind a<:>q = exit -@bind a<:>h = uri http://uzbl.org/ +@bind a<:>q = exit +@bind a<:>h = uri http://uzbl.org/ # Inject handy values into the keycmd. @bind su = event INJECT_KEYCMD \@uri -- cgit v1.2.3 From 8e8f511e8cf207f6ef84820300d7c6a728fc16ae Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 17 Dec 2009 17:33:31 +0800 Subject: No need to localise the held variable. --- examples/data/uzbl/plugins/bind.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 3dedf16..ee1e0c4 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -348,11 +348,9 @@ def after_bind(uzbl, bd): def match_and_exec(uzbl, bind, depth, keylet, bd): (on_exec, has_args, mod_cmd, glob, more) = bind[depth] - - held = keylet.held cmd = keylet.modcmd if mod_cmd else keylet.keycmd - if mod_cmd and held != mod_cmd: + if mod_cmd and keylet.held != mod_cmd: return False if has_args: -- cgit v1.2.3 From fab8c948215ed46cf78bd7a58b803efddb13dd0e Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 17 Dec 2009 19:58:36 +0800 Subject: Create sockets before daemonising in uzbl-{cookie-daemon,event-manager}. --- examples/data/uzbl/scripts/uzbl-cookie-daemon | 8 +++++--- examples/data/uzbl/scripts/uzbl-event-manager | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-cookie-daemon b/examples/data/uzbl/scripts/uzbl-cookie-daemon index 87a2e87..fde8b8e 100755 --- a/examples/data/uzbl/scripts/uzbl-cookie-daemon +++ b/examples/data/uzbl/scripts/uzbl-cookie-daemon @@ -304,6 +304,9 @@ class CookieMonster: if daemon_running(config['cookie_socket']): sys.exit(1) + # Create cookie daemon socket. + self.create_socket() + # Daemonize process. if config['daemon_mode']: echo("entering daemon mode") @@ -322,9 +325,6 @@ class CookieMonster: self._running = True while self._running: - # Create cookie daemon socket. - self.create_socket() - try: # Enter main listen loop. self.listen() @@ -345,6 +345,8 @@ class CookieMonster: # Always delete the socket before calling create again. self.del_socket() + # Create cookie daemon socket. + self.create_socket() def load_whitelist(self): diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 7a02da9..916259a 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -583,16 +583,16 @@ class UzblEventDaemon(dict): def run(self): '''Main event daemon loop.''' + # Create event daemon socket. + self._create_server_socket() + echo('listening on: %s' % self.socket_location) + if CONFIG['daemon_mode']: echo('entering daemon mode.') daemonize() # The pid has changed so update the pid file. make_pid_file(CONFIG['pid_file']) - # Create event daemon socket. - self._create_server_socket() - echo('listening on: %s' % self.socket_location) - # Now listen for incoming connections and or data. self.listen() -- cgit v1.2.3 From 227ea04a300da1d0f721721a213ae76632443b90 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 17 Dec 2009 19:29:36 +0800 Subject: New bind class that's onexec & nonarg when a bind ends in a '!'. --- examples/data/uzbl/plugins/bind.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index ee1e0c4..969dd18 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -169,13 +169,13 @@ class Bind(object): # Is the binding a MODCMD or KEYCMD: mod_cmd = ismodbind(glob) - # Execute the command on UPDATES or EXEC's: - on_exec = True if glob.endswith('_') else False + # Do we execute on UPDATES or EXEC events? + on_exec = True if glob[-1] in ['!', '_'] else False - # Does the command store arguments: + # Does the command take arguments? has_args = True if glob[-1] in ['*', '_'] else False - glob = glob[:-1] if has_args else glob + glob = glob[:-1] if has_args or on_exec else glob mods, glob = split_glob(glob) stack.append((on_exec, has_args, mods, glob, index)) -- cgit v1.2.3 From 17aeebf82b466f3190adf4fe07a82ea684b48b39 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 20 Dec 2009 16:07:45 +0100 Subject: set default page to a "welcome" page --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 94b1e73..092a369 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -324,4 +324,4 @@ set toggle_cmd_ins = @toggle_modes command insert # === Post-load misc commands =============================================== # Set the "home" page. -set uri = uzbl.org +set uri = uzbl.org/doesitwork/@COMMIT -- cgit v1.2.3 From f7b2c85cd6ff8048c1bed1410c9005ee5fe90515 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 20 Dec 2009 18:37:53 +0100 Subject: typo --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 33e074f..7c78ead 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -317,7 +317,7 @@ set default_mode = command # Changing mode method via set. @bind I = @set_mode insert -# Or toggle between modes by rasing the toggle event. +# Or toggle between modes by raising the toggle event. set toggle_cmd_ins = @toggle_modes command insert @bind i = @toggle_cmd_ins -- cgit v1.2.3 From 210c8591a81a12fb0fc5a2b40d4091a4903f63e6 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 21 Dec 2009 20:12:36 +0100 Subject: more documentation + MODE_BIND example in config --- README | 16 ++++++++++++---- examples/config/uzbl/config | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/README b/README index 64aace4..7b1bcc3 100644 --- a/README +++ b/README @@ -94,7 +94,6 @@ The following commands are recognized: - if you want to unset a string, use `set` with one space after the equals sign * `print @` - use this to print the value of a variable. - * `back` * `forward` * `scroll ` @@ -484,8 +483,8 @@ Basically all events have this format: - `EVENT [uzbl_instance_name] BUILTINS command_list`: shows a list of all uzbl commands, whitespace separated, on startup * Events/requests which the EM and its plugins listens for: - - `BIND` and `MODE_BIND`: define global resp. per-mode keybinds. - `request BIND = ` # set global keybinding (this is a shortcut for `request MODE_BIND global = `) + - `BIND` and `MODE_BIND`: define global resp. per-mode key/button binds. + `request BIND = ` # set global binding (this is a shortcut for `request MODE_BIND global = `) `request MODE_BIND = ` The `` can be anything like 'command', 'insert,command', 'global', 'global,-insert'. The `` has a special syntax: @@ -493,7 +492,8 @@ Basically all events have this format: * `` ends with an asterisk: similar behavior as with an underscore, but also makes the binding incremental (i.e. the command will be invoked on every keystroke). * `` ends with an '!': the command will only be invoked after pressing return/enter, no replacement happens. this is useful for preventing 'x' to match when you want to bind 'xx' also. * `` ends on a different character: you need to type the full string, which will trigger the command immediately, without pressing enter/return. - * TODO explain stacked bindings and what else am i missing? + * TODO explain stacked bindings and multi-stage (is that the same?) and what else am i missing? modkeys, showing a prompt mid-bind. + The `` can be any representation of a key on your keyboard or a mousebutton. (note: not all mousebuttons work correctly yet) examples: * `event BIND o _ = uri %s` - uzbl will load the url when you type: 'o ' @@ -516,6 +516,14 @@ Basically all events have this format: request MODKEY_ADDITION - `TOGGLE_MODES` event TOGGLE_MODES ... + - `APPEND_KEYCMD`: append ` to keycmd + - `INJECT_KEYCMD `: replace keycmd by `` + - `KEYCMD_DELETE` + - `KEYCMD_STRIP_WORD` + - `KEYCMD_EXEC_CURRENT`: (tries to) execute whatever is in the keycmd + - `SET_KEYCMD` + - `SET_CURSOR_POS` + - `START_COMPLETION`: TODO explain completion diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 33e074f..93002bf 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -8,6 +8,8 @@ set prefix = /usr/local # Config related events (use the request function): # request BIND = set bind = request BIND +# request MODE_BIND = +set mode_bind = request MODE_BIND # request MODE_CONFIG = @@ -161,6 +163,7 @@ menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js @bind >> = scroll vertical end @bind ^ = scroll horizontal begin @bind $ = scroll horizontal end +@mode_bind global,-insert = scroll vertical end @bind b = back @bind m = forward @bind S = stop -- cgit v1.2.3 From f2cf5d4ecfdc85b9830ce1f2d78044d2419374b0 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 22 Dec 2009 15:40:03 +0800 Subject: First commit of modified example config to make use of mode-binds. --- examples/config/uzbl/config | 312 +++++++++++++++++++++++++------------------- 1 file changed, 176 insertions(+), 136 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 0fa7434..ce75ecd 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -6,17 +6,17 @@ set prefix = /usr/local # === Shortcuts / Aliases =================================================== # Config related events (use the request function): -# request BIND = +# request BIND = set bind = request BIND -# request MODE_BIND = +# request MODE_BIND = set mode_bind = request MODE_BIND -# request MODE_CONFIG = = set mode_config = request MODE_CONFIG # request ON_EVENT set on_event = request ON_EVENT # request PROGRESS_CONFIG = set progress = request PROGRESS_CONFIG -# request MODMAP From To +# request MODMAP set modmap = request MODMAP # request IGNORE_KEY set ignore_key = request IGNORE_KEY @@ -134,73 +134,159 @@ set socket_dir = /tmp @ignore_key -# === Keyboard & Mouse bindings ============================================== +# === Mode bind aliases ====================================================== -# With this command you can enter in any command at runtime when prefixed with -# a colon. -@bind :_ = %s +# Global binding alias (this is done automatically inside the bind plugin). +#set bind = @mode_bind global + +# Insert mode binding alias +set ibind = @mode_bind insert + +# Command mode binding alias +set cbind = @mode_bind command + +# Non-insert mode bindings alias (ebind for edit-bind). +set ebind = @mode_bind global,-insert + + +# === Global & keycmd editing binds ========================================== + +# Resets keycmd and returns to default mode. +@bind = @set_mode + +# Commands for editing and traversing the keycmd. +@ebind = event KEYCMD_EXEC_CURRENT +@ebind = event SET_CURSOR_POS +@ebind = event SET_CURSOR_POS -1 +@ebind = event SET_CURSOR_POS - +@ebind = event SET_CURSOR_POS + +@ebind = event KEYCMD_BACKSPACE +@ebind = event KEYCMD_DELETE +@ebind = event START_COMPLETION +# Readline-ish bindings. +@ebind w = event KEYCMD_STRIP_WORD +@ebind u = event SET_KEYCMD +@ebind a = event SET_CURSOR_POS 0 +@ebind e = event SET_CURSOR_POS -1 + +# Keycmd injection/append examples. +#@ebind su = event INJECT_KEYCMD \@uri +#@ebind st = event INJECT_KEYCMD \@title +#@ebind du = event APPEND_KEYCMD \@uri +#@ebind dt = event APPEND_KEYCMD \@title + + +# === Mouse bindings ========================================================= # Middle click # if clicked on a link open the link in a new uzbl window # otherwise open the selection in the current window set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' -@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } +@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } -# Edit HTML forms in external editor -set external_editor = gvim -#set external_editor = xterm -e vim -@bind E = script @scripts_dir/extedit.js -menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js -@bind j = scroll vertical 20 -@bind = scroll vertical 100% -@bind k = scroll vertical -20 -@bind = scroll vertical -100% -@bind h = scroll horizontal -20 -@bind l = scroll horizontal 20 -@bind << = scroll vertical begin -@bind >> = scroll vertical end -@bind ^ = scroll horizontal begin -@bind $ = scroll horizontal end -@mode_bind global,-insert = scroll vertical end -@bind b = back -@bind m = forward -@bind S = stop -@bind r = reload -@bind R = reload_ign_cache -@bind + = zoom_in -@bind - = zoom_out -@bind T = toggle_zoom_type -@bind 1 = sh "echo set zoom_level = 1.0 > $4" -@bind 2 = sh "echo set zoom_level = 2.0 > $4" -@bind t = toggle_status -@bind /* = search %s -@bind ?* = search_reverse %s -#jump to next -@bind n = search -@bind N = search_reverse -@bind gh = uri http://www.uzbl.org -# shortcut to set variables -@bind s _ = set %s -@bind \\wiki _ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -@bind gg _ = uri http://www.google.com/search?q=%s -# Enclose the executable in quotes if it has spaces. Any additional parameters you use will -# appear AFTER the default parameters -# use a script to insert bookmarks. or use the EM/keycmd technique a bit further down -@bind B = spawn @scripts_dir/insert_bookmark.sh -@bind U = spawn @scripts_dir/load_url_from_history.sh -@bind u = spawn @scripts_dir/load_url_from_bookmarks.sh -@bind yurl = sh 'echo -n $6 | xclip' -@bind ytitle = sh 'echo -n $7 | xclip' -# go the page from primary selection -@bind p = sh 'echo "uri `xclip -selection primary -o`" > $4' -# go to the page in clipboard -@bind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' -# start a new uzbl instance from the page in primary selection -@bind 'p = sh 'exec uzbl-browser --uri $(xclip -o)' -@bind ZZ = exit -@bind Xs = js alert("hi"); +# === Keyboard bindings ====================================================== + +# With this command you can enter in any command at runtime when prefixed with +# a colon. +@cbind :_ = %s + +# --- Page movement binds --- +@cbind j = scroll vertical 20 +@cbind k = scroll vertical -20 +@cbind h = scroll horizontal -20 +@cbind l = scroll horizontal 20 +@cbind = scroll vertical -100% +@cbind = scroll vertical 100% +@cbind << = scroll vertical begin +@cbind >> = scroll vertical end +@cbind ^ = scroll horizontal begin +@cbind $ = scroll horizontal end +@cbind = scroll vertical end + +# --- Navigation binds --- +@cbind b = back +@cbind m = forward +@cbind S = stop +@cbind r = reload +@cbind R = reload_ign_cache + +# --- Zoom binds --- +@cbind + = zoom_in +@cbind - = zoom_out +@cbind T = toggle_zoom_type +@cbind 1 = set zoom_level 1.0 +@cbind 2 = set zoom_level 2.0 + +# --- Appearance binds --- +@cbind t = toggle_status + +# --- Page searching binds --- +@cbind /* = search %s +@cbind ?* = search_reverse %s +# Jump to next and previous items +@cbind n = search +@cbind N = search_reverse + +# --- Web searching binds --- +@cbind gg_ = uri http://www.google.com/search?q=%s +@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go +@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=%s&go=Go + +# --- Handy binds --- +# Set function shortcut +@cbind s__ = set %1 = %2 +# Exit binding +@cbind ZZ = exit +# Dump config to stdout +@cbind !dump = sh "echo dump_config > $4" +# Reload config +@cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" + +# --- Uri opening prompts --- +@cbind o_ = uri %s +# Or have it load the current uri into the keycmd for editing +@cbind O_ = uri %s + +# --- Mode setting binds --- +# Changing mode via set. +@cbind I = @set_mode insert +# Or toggle between modes by raising the toggle event. +set toggle_cmd_ins = @toggle_modes command insert +@cbind i = @toggle_cmd_ins +# And the global toggle bind. +@bind i = @toggle_cmd_ins + +# --- Hard-bound bookmarks --- +@cbind gh = uri http://www.uzbl.org + +# --- Yanking & pasting binds --- +@cbind yurl = sh 'echo -n $6 | xclip' +@cbind ytitle = sh 'echo -n $7 | xclip' +# Go the page from primary selection +@cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' +# Go to the page in clipboard +@cbind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' +# Start a new uzbl instance from the page in primary selection +@cbind 'p = sh 'exec uzbl-browser --uri $(xclip -o)' + +# --- Bookmark inserting binds --- +@cbind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +# Or use a script to insert a bookmark. +@cbind B = spawn @scripts_dir/insert_bookmark.sh + +# --- Bookmark/history loading --- +@cbind U = spawn @scripts_dir/load_url_from_history.sh +@cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh + +# --- Link following (similar to vimperator and konqueror) --- +@cbind fl* = script @scripts_dir/follow_Numbers.js %s +# Or number with strings instead of numbers: +@cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s + + +@cbind Xs = js alert("hi"); # example showing how to use sh # it sends a command to the fifo, whose path is told via a positional param # if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it @@ -208,73 +294,37 @@ menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js # you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes # in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file # path, fifo & socket dirs, etc.) -@bind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' - -@bind !dump = sh "echo dump_config > $4" -@bind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" +@cbind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -# this script allows you to configure (per domain) values to fill in form fields (eg login information) and to fill in these values automatically +# --- Form filler binds --- +# this script allows you to configure (per domain) values to fill in form +# fields (eg login information) and to fill in these values automatically set formfiller = spawn @scripts_dir/formfiller -@bind za = @{formfiller}.sh -@bind ze = @{formfiller}.sh edit -@bind zn = @{formfiller}.sh new -@bind zl = @{formfiller}.sh load - +@cbind za = @{formfiller}.sh +@cbind ze = @{formfiller}.sh edit +@cbind zn = @{formfiller}.sh new +@cbind zl = @{formfiller}.sh load # Or the more advanced implementation using perl: (could not get this to run - Dieter) -@bind LL = @{formfiller}.pl load -@bind LN = @{formfiller}.pl new -@bind LE = @{formfiller}.pl edit - -# we ship some javascripts to do keyboard based link hinting/following. (webkit does not have C DOM bindings yet) -# this is similar to how it works in vimperator (and konqueror) -# TODO: did we resolve: "no click() event for hyperlinks so no referrer set" ? -#hit F to toggle the Hints (now in form of link numbering) -@bind F = script @scripts_dir/hint.js -# the most stable version: -@bind fl* = script @scripts_dir/follow_Numbers.js %s -# using strings, not polished yet: -@bind fL* = script @scripts_dir/follow_Numbers_Strings.js %s - - -# Examples using multi-stage-bindings with text prompts. -@bind o_ = uri %s -@bind O_ = uri %s - -# multi-stage binding way to write bookmarks to file from inside uzbl. -@bind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' - -# Multi-stage bindings with blank prompts (similar behaviour to emacs M-c M-s bindings?) -@bind a<:>q = exit -@bind a<:>h = uri http://uzbl.org/ - -# Inject handy values into the keycmd. -@bind su = event INJECT_KEYCMD \@uri -@bind st = event INJECT_KEYCMD \@TITLE -# Or append. -@bind du = event APPEND_KEYCMD \@uri -@bind dt = event APPEND_KEYCMD \@TITLE - - -# === command editing configuration ========================================== - -# you'll want this at the very least -@bind = event KEYCMD_EXEC_CURRENT -@bind = @set_mode - -# basic searching -@bind = event SET_CURSOR_POS 0 -@bind = event SET_CURSOR_POS -1 -@bind = event SET_CURSOR_POS - -@bind = event SET_CURSOR_POS + -@bind = event KEYCMD_BACKSPACE -@bind = event KEYCMD_DELETE -@bind = event START_COMPLETION - -# readline-ish bindings -@bind w = event KEYCMD_STRIP_WORD -@bind u = event SET_KEYCMD -@bind a = event SET_CURSOR_POS 0 -@bind e = event SET_CURSOR_POS -1 +@cbind LL = @{formfiller}.pl load +@cbind LN = @{formfiller}.pl new +@cbind LE = @{formfiller}.pl edit + +# --- External edit script configuration & binds --- +# Edit form input fields in an external editor (gvim, emacs, urxvt -e vim, ..) +set external_editor = gvim +#set external_editor = xterm -e vim +@cbind E = script @scripts_dir/extedit.js +# And add menu option. +menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js + +# --- Examples --- +# Example showing how to use uzbl's fifo to execute a command. +#@bind X1 = sh 'echo "set zoom_level = 1.0" > "$4"' +#@bind X2 = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' + +# Working with the javascript helper variable jsh. +#@bind X3 = @jsh alert(get('zoom_level')); +#@bind X4 = @jsh if(get('mode') == "insert") { alert("You are in insert mode") } else { alert(get('mode')+" is a silly mode.") }; # === Context menu items ===================================================== @@ -316,16 +366,6 @@ set stack = @mode_config stack set default_mode = command -# Mode bindings: -# Changing mode method via set. -@bind I = @set_mode insert - -# Or toggle between modes by raising the toggle event. -set toggle_cmd_ins = @toggle_modes command insert - -@bind i = @toggle_cmd_ins -@bind i = @toggle_cmd_ins - # === Post-load misc commands =============================================== -- cgit v1.2.3 From 49941155e43eb520c43b02b55e0bbced2b657cf6 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 23 Dec 2009 01:07:54 +0800 Subject: Unified yank bind. --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index ce75ecd..9dc4a35 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -262,8 +262,8 @@ set toggle_cmd_ins = @toggle_modes command insert @cbind gh = uri http://www.uzbl.org # --- Yanking & pasting binds --- -@cbind yurl = sh 'echo -n $6 | xclip' -@cbind ytitle = sh 'echo -n $7 | xclip' +@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); + # Go the page from primary selection @cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' # Go to the page in clipboard -- cgit v1.2.3 From 09d59497d1c06f07b1915e34c0110401916231b9 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 23 Dec 2009 21:15:18 +0800 Subject: Added the escaped and quoted %r replace for on_event and bind args. --- examples/data/uzbl/plugins/bind.py | 10 ++++++++++ examples/data/uzbl/plugins/on_event.py | 11 +++++++++++ 2 files changed, 21 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 1cba7b2..668b595 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -306,9 +306,19 @@ class Bind(object): def expand(cmd, args): '''Replaces "%s %1 %2 %3..." with " ...".''' + # Direct string replace. if '%s' in cmd: cmd = cmd.replace('%s', ' '.join(map(unicode, args))) + # Escaped and quoted string replace. + if '%r' in cmd: + joined = ('%r' % ' '.join(map(unicode, args)))[1:] + for char in ['\\', '@']: + joined = joined.replace(char, '\\'+char) + + cmd = cmd.replace('%r', joined) + + # Arg index string replace. for (index, arg) in enumerate(args): index += 1 if '%%%d' % index in cmd: diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index afee4e6..9d2525b 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -2,6 +2,7 @@ Formatting options: %s = space separated string of the arguments + %r = escaped and quoted version of %s %1 = argument 1 %2 = argument 2 %n = argument n @@ -47,9 +48,19 @@ def get_on_events(uzbl): def expand(cmd, args): '''Replaces "%s %1 %2 %3..." with " ...".''' + # Direct string replace. if '%s' in cmd: cmd = cmd.replace('%s', ' '.join(map(unicode, args))) + # Escaped and quoted string replace. + if '%r' in cmd: + joined = ('%r' % ' '.join(map(unicode, args)))[1:] + for char in ['\\', '@']: + joined = joined.replace(char, '\\'+char) + + cmd = cmd.replace('%r', joined) + + # Arg index string replace. for (index, arg) in enumerate(args): index += 1 if '%%%d' % index in cmd: -- cgit v1.2.3 From f200c865fb8a5daae30ff9c070eb5c929c720a4b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 24 Dec 2009 00:27:19 +0800 Subject: Moved expand function to external plugin to reduce code duplication. --- examples/data/uzbl/plugins/bind.py | 27 ++------------------ examples/data/uzbl/plugins/cmd_expand.py | 43 ++++++++++++++++++++++++++++++++ examples/data/uzbl/plugins/on_event.py | 27 ++------------------ 3 files changed, 47 insertions(+), 50 deletions(-) create mode 100644 examples/data/uzbl/plugins/cmd_expand.py (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 668b595..9614df6 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -303,30 +303,6 @@ class Bind(object): return self._repr_cache -def expand(cmd, args): - '''Replaces "%s %1 %2 %3..." with " ...".''' - - # Direct string replace. - if '%s' in cmd: - cmd = cmd.replace('%s', ' '.join(map(unicode, args))) - - # Escaped and quoted string replace. - if '%r' in cmd: - joined = ('%r' % ' '.join(map(unicode, args)))[1:] - for char in ['\\', '@']: - joined = joined.replace(char, '\\'+char) - - cmd = cmd.replace('%r', joined) - - # Arg index string replace. - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - def exec_bind(uzbl, bind, *args, **kargs): '''Execute bind objects.''' @@ -342,8 +318,9 @@ def exec_bind(uzbl, bind, *args, **kargs): raise ArgumentError('cannot supply kargs for uzbl commands') commands = [] + cmd_expand = uzbl.cmd_expand for cmd in bind.commands: - cmd = expand(cmd, args) + cmd = cmd_expand(cmd, args) uzbl.send(cmd) diff --git a/examples/data/uzbl/plugins/cmd_expand.py b/examples/data/uzbl/plugins/cmd_expand.py new file mode 100644 index 0000000..a5c279d --- /dev/null +++ b/examples/data/uzbl/plugins/cmd_expand.py @@ -0,0 +1,43 @@ +__export__ = ['cmd_expand',] + + +def escape(str): + for (level, char) in [(3, '\\'), (2, "'"), (2, '"'), (1, '@')]: + str = str.replace(char, (level * '\\') + char) + + return str + + +def cmd_expand(uzbl, cmd, args): + '''Exports a function that provides the following + expansions in any uzbl command string: + + %s = replace('%s', ' '.join(args)) + %r = replace('%r', "'%s'" % escaped(' '.join(args))) + %1 = replace('%1', arg[0]) + %2 = replace('%2', arg[1]) + %n = replace('%n', arg[n-1]) + ''' + + # Ensure (1) all string representable and (2) correct string encoding. + args = map(unicode, args) + + # Direct string replace. + if '%s' in cmd: + cmd = cmd.replace('%s', ' '.join(args)) + + # Escaped and quoted string replace. + if '%r' in cmd: + cmd = cmd.replace('%r', "'%s'" % escape(' '.join(args))) + + # Arg index string replace. + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) + + return cmd + + +def init(*args): + pass diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index 9d2525b..f1ad0c9 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -45,30 +45,6 @@ def get_on_events(uzbl): return UZBLS[uzbl] -def expand(cmd, args): - '''Replaces "%s %1 %2 %3..." with " ...".''' - - # Direct string replace. - if '%s' in cmd: - cmd = cmd.replace('%s', ' '.join(map(unicode, args))) - - # Escaped and quoted string replace. - if '%r' in cmd: - joined = ('%r' % ' '.join(map(unicode, args)))[1:] - for char in ['\\', '@']: - joined = joined.replace(char, '\\'+char) - - cmd = cmd.replace('%r', joined) - - # Arg index string replace. - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - def event_handler(uzbl, *args, **kargs): '''This function handles all the events being watched by various on_event definitions and responds accordingly.''' @@ -79,8 +55,9 @@ def event_handler(uzbl, *args, **kargs): return commands = events[event] + cmd_expand = uzbl.cmd_expand for cmd in commands: - cmd = expand(cmd, args) + cmd = cmd_expand(cmd, args) uzbl.send(cmd) -- cgit v1.2.3 From 92ccf67e010bcff1a153dd67093c23300c2ce47f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 26 Dec 2009 19:27:56 +0800 Subject: URIEncode search string component of web searching binds. --- examples/config/uzbl/config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9dc4a35..a6be6d6 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -230,9 +230,9 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @cbind N = search_reverse # --- Web searching binds --- -@cbind gg_ = uri http://www.google.com/search?q=%s -@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=%s&go=Go +@cbind gg_ = uri http://www.google.com/search?q=\@\@ +@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=\@\@&go=Go +@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=\@\@&go=Go # --- Handy binds --- # Set function shortcut -- cgit v1.2.3 From 3733d86d0d28e072697a17a43eff360dcdac8038 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 26 Dec 2009 20:53:24 +0800 Subject: Keycmd plugin now sets raw_{key,mod}cmd vars and updated title format. --- examples/config/uzbl/config | 2 ++ examples/data/uzbl/plugins/keycmd.py | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index a6be6d6..072c045 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -96,6 +96,8 @@ set selected_section = \@[\@SELECTED_URI]\@ set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section +set title_format_long = \@keycmd_prompt \@raw_modcmd \@raw_keycmd \@TITLE - Uzbl browser <\@NAME> \@SELECTED_URI + # Progress bar config @progress width = 8 # %d = done, %p = pending %c = percent done, %i = int done, %s = spinner, diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index af6beff..8475c1d 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -10,20 +10,18 @@ UZBLS = {} # Keycmd format which includes the markup for the cursor. KEYCMD_FORMAT = "%s%s%s" +MODCMD_FORMAT = " %s " -def uzbl_escape(str): - '''Prevent outgoing keycmd values from expanding inside the - status_format.''' +def escape(str): + for char in ['\\', '@']: + str = str.replace(char, '\\'+char) - if not str: - return '' + return str - for char in ['\\', '@']: - if char in str: - str = str.replace(char, '\\'+char) - return "@[%s]@" % str +def uzbl_escape(str): + return "@[%s]@" % escape(str) if str else '' class Keylet(object): @@ -261,6 +259,7 @@ def clear_keycmd(uzbl): k.cursor = 0 k._repr_cache = False uzbl.set('keycmd') + uzbl.set('raw_keycmd') uzbl.event('KEYCMD_CLEARED') @@ -276,6 +275,7 @@ def clear_modcmd(uzbl, clear_held=False): k.held = set() uzbl.set('modcmd') + uzbl.set('raw_modcmd') uzbl.event('MODCMD_CLEARED') @@ -314,9 +314,11 @@ def update_event(uzbl, k, execute=True): new_modcmd = k.get_modcmd() if not new_modcmd: uzbl.set('modcmd', config=config) + uzbl.set('raw_modcmd', config=config) elif new_modcmd == modcmd: - uzbl.set('modcmd', ' %s ' % uzbl_escape(new_modcmd), + uzbl.set('raw_modcmd', escape(modcmd), config=config) + uzbl.set('modcmd', MODCMD_FORMAT % uzbl_escape(modcmd), config=config) if 'keycmd_events' in config and config['keycmd_events'] != '1': @@ -325,6 +327,7 @@ def update_event(uzbl, k, execute=True): new_keycmd = k.get_keycmd() if not new_keycmd: uzbl.set('keycmd', config=config) + uzbl.set('raw_keycmd', config=config) elif new_keycmd == keycmd: # Generate the pango markup for the cursor in the keycmd. @@ -332,6 +335,7 @@ def update_event(uzbl, k, execute=True): chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] value = KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks)) uzbl.set('keycmd', value, config=config) + uzbl.set('raw_keycmd', escape(keycmd), config=config) def inject_str(str, index, inj): @@ -391,6 +395,7 @@ def key_press(uzbl, key): k.keycmd = '' k.cursor = 0 uzbl.set('keycmd', config=config) + uzbl.set('raw_keycmd', config=config) return k.keycmd = inject_str(k.keycmd, k.cursor, key) -- cgit v1.2.3 From 198afaca6d39a5fa2e9927ad6a297fe166a0b5b1 Mon Sep 17 00:00:00 2001 From: cy Date: Mon, 28 Dec 2009 21:17:10 +0200 Subject: add link following script with configurable keys --- examples/data/uzbl/scripts/follow.js | 256 +++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 examples/data/uzbl/scripts/follow.js (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow.js b/examples/data/uzbl/scripts/follow.js new file mode 100644 index 0000000..6b71372 --- /dev/null +++ b/examples/data/uzbl/scripts/follow.js @@ -0,0 +1,256 @@ +/* This is the basic linkfollowing script. + * + * TODO: check if all characters in follow_hint_keys from config + * are unique. + * TODO: Some pages mess around a lot with the zIndex which + * lets some hints in the background. + * TODO: Some positions are not calculated correctly (mostly + * because of uber-fancy-designed-webpages. Basic HTML and CSS + * works good + * TODO: Still some links can't be followed/unexpected things + * happen. Blame some freaky webdesigners ;) + */ + +//Just some shortcuts and globals +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; + +//This string should be 10 unique characters long. Set it in your config +//with: +// set follow_hint_keys = asdfghjkl; # no quotes! +var defaultHintKeys = '0123456789'; +var hintKeys = Uzbl.run("print @follow_hint_keys") || defaultHintKeys; +if (hintKeys.length != 10) hintKeys = defaultHintKeys; + +//Reset keycmd, modcmd and return to default mode. +function clearKeycmd() { Uzbl.run('set mode ='); } + +//Make onclick-links "clickable" +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +//Catch the ESC keypress to stop linkfollowing +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +//Calculate element position to draw the hint +//Pretty accurate but on fails in some very fancy cases +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +//Calculate if an element is visible +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +//Calculate if an element is on the viewport. +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +//Removes all hints/leftovers that might be generated +//by this script. +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +//Generate a hint for an element with the given label +//Here you can play around with the style of the hints! +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '1000'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +//Here we choose what to do with an element if we +//want to "follow" it. On form elements we "select" +//or pass the focus, on links we try to perform a click, +//but at least set the href of the link. (needs some improvements) +function clickElem(item) { + removeAllHints(); + clearKeycmd(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +//Returns a list of all links (in this version +//just the elements itself, but in other versions, we +//add the label here. +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + } + } + return res; +} +//Same as above, just for the form elements +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + } + } + } + return res; +} +//Draw all hints for all elements passed. "len" is for +//the number of chars we should use to avoid collisions +function reDrawHints(elems, chars) { + removeAllHints(); + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + for (var i = 0; i < elems[0].length; i++) { + if (elems[0][i]) { + var label = elems[1][i].substring(chars); + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + } +} +//Map 0123456789 to hintKeys +function mapNumToHintKeys(label) { + label = label + ''; + for (var j = 0; j < label.length; j++) { + var pos = parseInt(label[j]); + label = label.replace(label[j], hintKeys[pos]); + } + return label; +} +//Map hintKeys to 0123456789 +function mapHintKeysToNum(label) { + label = label + ''; + for (var j = 0; j < label.length; j++) { + var pos = hintKeys.search(label[j]); + if (pos < 0 || pos > 9) return; // bad input, key not in hintKeys + label = label.replace(label[j], pos+''); + } + return parseInt(label); +} +//Put it all together +function followLinks(follow) { + var s = follow.split(''); + var linknr = mapHintKeysToNum(follow); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + var label = j + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + label = mapNumToHintKeys(label); + for (var k = 0; k < s.length; k++) { + b = b && label.charAt(k) == s[k]; + } + if (b) { + leftover[0].push(elems[0][j]); + leftover[1].push(label); + } + } + reDrawHints(leftover, s.length); + } +} +followLinks('%s'); -- cgit v1.2.3 From ed7e5126df07826aac90869200e4f48ed6bb9336 Mon Sep 17 00:00:00 2001 From: tczy Date: Tue, 29 Dec 2009 18:40:42 +0200 Subject: fixed http://www.uzbl.org/bugs/index.php?do=details&task_id=165 using supplied patch --- examples/data/uzbl/scripts/insert_bookmark.sh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh index e04e6d4..c34e7db 100755 --- a/examples/data/uzbl/scripts/insert_bookmark.sh +++ b/examples/data/uzbl/scripts/insert_bookmark.sh @@ -6,6 +6,8 @@ file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks which zenity &>/dev/null || exit 2 entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` +exitstatus=$? +if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi url=`echo $entry | awk '{print $1}'` # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags -- cgit v1.2.3 From 41719db3a893189f68dbb97cc49df1fed1e1163a Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 30 Dec 2009 02:10:35 +0200 Subject: uzbl-tabbed bind '@' fix --- examples/data/uzbl/scripts/uzbl-tabbed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index bb9b9a2..d93a3f4 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -1010,7 +1010,7 @@ class UzblTabbed: instance.''' binds = [] - bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""' + bind_format = r'@bind %s = sh "echo \"%s\" > \"%s\""' bind = lambda key, action: binds.append(bind_format % (key, action,\ self.fifo_socket)) -- cgit v1.2.3 From 3a73a42aae448240211d6d96349f1afb7e4e4996 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 1 Jan 2010 09:29:34 +0800 Subject: Add 'uzbl terminal' binding & remove old example lines. --- examples/config/uzbl/config | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 072c045..9d0f710 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -245,6 +245,9 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @cbind !dump = sh "echo dump_config > $4" # Reload config @cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" +# Uzbl Terminal +@cbind t = sh 'xterm -e "socat unix-connect:$5 -"' +#@cbind t = sh 'urxvt -e socat unix-connect:$5 -' # --- Uri opening prompts --- @cbind o_ = uri %s @@ -287,17 +290,6 @@ set toggle_cmd_ins = @toggle_modes command insert # Or number with strings instead of numbers: @cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s - -@cbind Xs = js alert("hi"); -# example showing how to use sh -# it sends a command to the fifo, whose path is told via a positional param -# if fifo_dir is not set, it'll echo to a file named (null) somewhere >:) remember to delete it -# The body of the shell command should be one parameter, so if it has spaces like here, -# you must enclose it in quotes. Remember to escape (and double-escape) quotes and backslashes -# in the body. Any additional parameters you use will appear AFTER the default parameters (cfg file -# path, fifo & socket dirs, etc.) -@cbind XS = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' - # --- Form filler binds --- # this script allows you to configure (per domain) values to fill in form # fields (eg login information) and to fill in these values automatically -- cgit v1.2.3 From d55f6c7e55a94161924e1380dd70ef72624cecd7 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 1 Jan 2010 13:09:36 +0800 Subject: Moved xdghome function out of config section. --- examples/data/uzbl/scripts/uzbl-event-manager | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 916259a..a3148a2 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -41,13 +41,6 @@ from traceback import print_exc from functools import partial -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -# `make install` will put the correct value here for your system -PREFIX = '/usr/local/' - def xdghome(key, default): '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise use $HOME and the default path.''' @@ -58,11 +51,18 @@ def xdghome(key, default): return os.path.join(os.environ['HOME'], default) + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# `make install` will put the correct value here for your system +PREFIX = '/usr/local/' + # Setup xdg paths. DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') - # Event manager config dictionary. This is not to be confused with the config # dict that tracks variables in the uzbl instance. CONFIG = { @@ -80,7 +80,6 @@ CONFIG = { 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), } - # ============================================================================ # ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: # ============================================================================ -- cgit v1.2.3 From 3d9e04194d816f28621b6f3fdd5c73d58f271545 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 1 Jan 2010 16:55:39 +0800 Subject: Correctness re-write of the export mechanism. Exporting is now done with the following two new functions: 1. `uzbl.export('external_name', function)` 2. `uzbl.export_dict({'name1': func1, 'name2': func2, ...})` This system is preferable to the old `__export__` variable for several reasons. The first being that the exporting system is now very similar to the connect (read: `uzbl.connect(..)` and `uzbl.connect_dict({..})`) system in the event manager. And consider the following: 1. User wishes to write a plugin that doesn't connect to any events but exports a function. 2. It's an arbitrary requirement that a plugin have an `init(uzbl)` function. 3. The user would have done the following (example plugin snippet): __export__ = 'my_function' def my_function(uzbl, ..): # Do something def init(uzbl): # Do nothing pass 4. The user now does the following: def my_function(uzbl, ..): # do something def init(uzbl): uzbl.export('my_function', my_function) Note that the name in `uzbl.export('external_name', function)` doesn't need to match the function name. Example pseudo-python: # In the plugin >>> def hello(uzbl): ... return "Hello, World!" >>> def init(uzbl): ... uzbl.export('say_hello', hello) ... print uzbl.say_hello() # In the event manager >>> plugin.init(uzbl) Hello, World! --- examples/data/uzbl/scripts/uzbl-event-manager | 101 ++++++++++---------------- 1 file changed, 38 insertions(+), 63 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 916259a..afef6fd 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -350,61 +350,23 @@ class UzblInstance(object): def __init__(self, parent, client_socket): # Internal variables. - self._exports = {} - self._handlers = {} - self._parent = parent - self._client_socket = client_socket + self.exports = {} + self.handlers = {} + self.parent = parent + self.client_socket = client_socket self.depth = 0 self.buffer = '' self.pid = None - # Call the init() function in every plugin. Inside the init function - # is where the plugins insert the hooks into the event system. - self._init_plugins() - - - def __getattribute__(self, attr): - '''Expose any exported functions before class functions.''' - - if not attr.startswith('_'): - exports = object.__getattribute__(self, '_exports') - if attr in exports: - return exports[attr] - - return object.__getattribute__(self, attr) - - - def _init_plugins(self): - '''Call the init() function in every plugin and expose all exposable - functions in the plugins root namespace.''' - - plugins = self._parent['plugins'] - - # Map all plugin exports - for (name, plugin) in plugins.items(): - if not hasattr(plugin, '__export__'): - continue - - for export in plugin.__export__: - if export in self._exports: - raise KeyError("conflicting export: %r" % export) - - obj = getattr(plugin, export) - if callable(obj): - obj = partial(obj, self) - - self._exports[export] = obj - - echo("exposed attribute(s): %s" % ', '.join(self._exports.keys())) - - # Now call the init function in all plugins. - for (name, plugin) in plugins.items(): + # Call the init function in every plugin. The init function in each + # plugin is where that plugin connects functions to events and exports + # functions to the uzbl object. + for plugin in self.parent['plugins'].values(): try: plugin.init(self) except: - #print_exc() raise @@ -412,26 +374,43 @@ class UzblInstance(object): '''Send a command to the uzbl instance via the socket file.''' msg = msg.strip() - if self._client_socket: + if self.client_socket: print '%s<-- %s' % (' ' * self.depth, msg) - self._client_socket.send(("%s\n" % msg).encode('utf-8')) + self.client_socket.send(("%s\n" % msg).encode('utf-8')) else: print '%s!-- %s' % (' ' * self.depth, msg) + def export(self, name, function): + '''Export `function(uzbl, *args, ..)` inside a plugin to the uzbl + object like so `uzbl.function(*args, ..)`. This will allow other + plugins to call functions inside the current plugin (which is currently + calling this function) via the uzbl object.''' + + self.__dict__.__setitem__(name, partial(function, self)) + + + def export_dict(self, export_dict): + '''Export multiple (name, function)'s at once inside a dict of the + form `{name1: function1, name2: function2, ...}`.''' + + for (name, function) in export_dict.items(): + self.export(name, function) + + def connect(self, event, handler, *args, **kargs): - '''Connect event with handler and return the newly created handler. - Handlers can either be a function or a uzbl command string.''' + '''Connect a uzbl event with a handler. Handlers can either be a + function or a uzbl command string.''' event = event.upper().strip() assert event and ' ' not in event - if event not in self._handlers.keys(): - self._handlers[event] = [] + if event not in self.handlers.keys(): + self.handlers[event] = [] handlerobj = EventHandler(event, handler, *args, **kargs) - self._handlers[event].append(handlerobj) + self.handlers[event].append(handlerobj) print handlerobj @@ -449,7 +428,7 @@ class UzblInstance(object): def remove_by_id(self, hid): '''Remove connected event handler by unique handler id.''' - for (event, handlers) in self._handlers.items(): + for (event, handlers) in self.handlers.items(): for handler in list(handlers): if hid != handler.hid: continue @@ -464,7 +443,7 @@ class UzblInstance(object): def remove(self, handler): '''Remove connected event handler.''' - for (event, handlers) in self._handlers.items(): + for (event, handlers) in self.handlers.items(): if handler in handlers: echo("removed %r" % handler) handlers.remove(handler) @@ -493,10 +472,10 @@ class UzblInstance(object): if event == "INSTANCE_START" and args: self.pid = int(args[0]) - if event not in self._handlers: + if event not in self.handlers: return - for handler in self._handlers[event]: + for handler in self.handlers[event]: self.depth += 1 try: self.exec_handler(handler, *args, **kargs) @@ -511,19 +490,15 @@ class UzblInstance(object): '''Close the client socket and clean up.''' try: - self._client_socket.close() + self.client_socket.close() except: pass - for (name, plugin) in self._parent['plugins'].items(): + for (name, plugin) in self.parent['plugins'].items(): if hasattr(plugin, 'cleanup'): plugin.cleanup(self) - del self._exports - del self._handlers - del self._client_socket - class UzblEventDaemon(dict): def __init__(self): -- cgit v1.2.3 From b0e7190acd1c266b20d2624051d6932bbf90a3d9 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 1 Jan 2010 17:16:09 +0800 Subject: Use new export mechanism in all plugins. --- examples/data/uzbl/plugins/bind.py | 30 ++++++++------ examples/data/uzbl/plugins/cmd_expand.py | 9 ++-- examples/data/uzbl/plugins/completion.py | 25 ++++++----- examples/data/uzbl/plugins/config.py | 19 ++++++--- examples/data/uzbl/plugins/keycmd.py | 60 ++++++++++++++++----------- examples/data/uzbl/plugins/mode.py | 27 ++++++++---- examples/data/uzbl/plugins/on_event.py | 19 ++++++--- examples/data/uzbl/plugins/plugin_template.py | 25 +++++------ examples/data/uzbl/plugins/progress_bar.py | 15 +++---- 9 files changed, 138 insertions(+), 91 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 9614df6..9e09337 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -13,9 +13,6 @@ import sys import re import pprint -# Export these functions to uzbl. -__export__ = ['bind', 'mode_bind', 'get_bindlet'] - # Hold the bind dicts for each uzbl instance. UZBLS = {} @@ -504,12 +501,21 @@ def modcmd_exec(uzbl, keylet): def init(uzbl): - connects = {'BIND': parse_bind, - 'MODE_BIND': parse_mode_bind, - 'KEYCMD_UPDATE': keycmd_update, - 'MODCMD_UPDATE': modcmd_update, - 'KEYCMD_EXEC': keycmd_exec, - 'MODCMD_EXEC': modcmd_exec, - 'MODE_CHANGED': mode_changed} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'BIND': parse_bind, + 'KEYCMD_EXEC': keycmd_exec, + 'KEYCMD_UPDATE': keycmd_update, + 'MODCMD_EXEC': modcmd_exec, + 'MODCMD_UPDATE': modcmd_update, + 'MODE_BIND': parse_mode_bind, + 'MODE_CHANGED': mode_changed, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'bind': bind, + 'mode_bind': mode_bind, + 'get_bindlet': get_bindlet, + }) diff --git a/examples/data/uzbl/plugins/cmd_expand.py b/examples/data/uzbl/plugins/cmd_expand.py index a5c279d..3f6ae2b 100644 --- a/examples/data/uzbl/plugins/cmd_expand.py +++ b/examples/data/uzbl/plugins/cmd_expand.py @@ -1,6 +1,3 @@ -__export__ = ['cmd_expand',] - - def escape(str): for (level, char) in [(3, '\\'), (2, "'"), (2, '"'), (1, '@')]: str = str.replace(char, (level * '\\') + char) @@ -39,5 +36,7 @@ def cmd_expand(uzbl, cmd, args): return cmd -def init(*args): - pass +def init(uzbl): + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export('cmd_expand', cmd_expand) diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py index 8e055e1..8cea203 100644 --- a/examples/data/uzbl/plugins/completion.py +++ b/examples/data/uzbl/plugins/completion.py @@ -185,17 +185,22 @@ def add_config_key(uzbl, key, value): def init(uzbl): - connects = { - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, + # Event handling hooks. + uzbl.connect_dict({ 'BUILTINS': add_builtins, 'CONFIG_CHANGED': add_config_key, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEYCMD_CLEARED': stop_completion, + 'KEYCMD_EXEC': stop_completion, 'KEYCMD_UPDATE': update_completion_list, 'START_COMPLETION': start_completion, - } - - # And connect the dicts event handlers to the handler stack. - uzbl.connect_dict(connects) - - for event in ['STOP_COMPLETION', 'KEYCMD_EXEC', 'KEYCMD_CLEARED']: - uzbl.connect(event, stop_completion) + 'STOP_COMPLETION': stop_completion, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_completion_dict': get_completion_dict, + 'start_completion': start_completion, + }) diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py index b43161b..4a848a3 100644 --- a/examples/data/uzbl/plugins/config.py +++ b/examples/data/uzbl/plugins/config.py @@ -82,9 +82,16 @@ def variable_set(uzbl, args): def init(uzbl): - - connects = {'VARIABLE_SET': variable_set, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'VARIABLE_SET': variable_set, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_config': get_config, + 'set': set, + }) diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py index 8475c1d..c119077 100644 --- a/examples/data/uzbl/plugins/keycmd.py +++ b/examples/data/uzbl/plugins/keycmd.py @@ -1,10 +1,5 @@ import re -# Map these functions/variables in the plugins namespace to the uzbl object. -__export__ = ['clear_keycmd', 'set_keycmd', 'set_cursor_pos', 'get_keylet', - 'clear_current', 'clear_modcmd', 'add_modmap', 'add_key_ignore', - 'append_keycmd', 'inject_keycmd', 'add_modkey_addition'] - # Hold the keylets. UZBLS = {} @@ -538,22 +533,39 @@ def set_cursor_pos(uzbl, index): def init(uzbl): '''Connect handlers to uzbl events.''' - connects = {'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'KEY_PRESS': key_press, - 'KEY_RELEASE': key_release, - 'SET_KEYCMD': set_keycmd, - 'KEYCMD_STRIP_WORD': keycmd_strip_word, - 'KEYCMD_BACKSPACE': keycmd_backspace, - 'KEYCMD_DELETE': keycmd_delete, - 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, - 'SET_CURSOR_POS': set_cursor_pos, - 'FOCUS_LOST': focus_changed, - 'FOCUS_GAINED': focus_changed, - 'MODMAP': modmap_parse, - 'APPEND_KEYCMD': append_keycmd, - 'INJECT_KEYCMD': inject_keycmd, - 'IGNORE_KEY': add_key_ignore, - 'MODKEY_ADDITION': modkey_addition_parse} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'APPEND_KEYCMD': append_keycmd, + 'FOCUS_GAINED': focus_changed, + 'FOCUS_LOST': focus_changed, + 'IGNORE_KEY': add_key_ignore, + 'INJECT_KEYCMD': inject_keycmd, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEYCMD_BACKSPACE': keycmd_backspace, + 'KEYCMD_DELETE': keycmd_delete, + 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, + 'KEYCMD_STRIP_WORD': keycmd_strip_word, + 'KEY_PRESS': key_press, + 'KEY_RELEASE': key_release, + 'MODKEY_ADDITION': modkey_addition_parse, + 'MODMAP': modmap_parse, + 'SET_CURSOR_POS': set_cursor_pos, + 'SET_KEYCMD': set_keycmd, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'add_key_ignore': add_key_ignore, + 'add_modkey_addition': add_modkey_addition, + 'add_modmap': add_modmap, + 'append_keycmd': append_keycmd, + 'clear_current': clear_current, + 'clear_keycmd': clear_keycmd, + 'clear_modcmd': clear_modcmd, + 'get_keylet': get_keylet, + 'inject_keycmd': inject_keycmd, + 'set_cursor_pos': set_cursor_pos, + 'set_keycmd': set_keycmd, + }) diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py index f85d999..54d865a 100644 --- a/examples/data/uzbl/plugins/mode.py +++ b/examples/data/uzbl/plugins/mode.py @@ -156,12 +156,21 @@ def toggle_modes(uzbl, modes): def init(uzbl): - - connects = {'CONFIG_CHANGED': config_changed, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'MODE_CONFIG': mode_config, - 'TOGGLE_MODES': toggle_modes, - 'MODE_CHANGED': mode_changed} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'CONFIG_CHANGED': config_changed, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'MODE_CHANGED': mode_changed, + 'MODE_CONFIG': mode_config, + 'TOGGLE_MODES': toggle_modes, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_mode': get_mode, + 'get_mode_config': get_mode_config, + 'set_mode': set_mode, + 'set_mode_config': set_mode_config, + }) diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index f1ad0c9..b9c504a 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -92,9 +92,16 @@ def parse_on_event(uzbl, args): def init(uzbl): - - connects = {'ON_EVENT': parse_on_event, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'ON_EVENT': parse_on_event, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_on_events': get_on_events, + 'on_event': on_event, + }) diff --git a/examples/data/uzbl/plugins/plugin_template.py b/examples/data/uzbl/plugins/plugin_template.py index 03cb748..565a999 100644 --- a/examples/data/uzbl/plugins/plugin_template.py +++ b/examples/data/uzbl/plugins/plugin_template.py @@ -1,8 +1,5 @@ '''Plugin template.''' -# A list of functions this plugin exports to be used via uzbl object. -__export__ = ['myplugin_function',] - # Holds the per-instance data dict. UZBLS = {} @@ -60,16 +57,20 @@ def init(uzbl): # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event # handler stack: - connects = { - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'MYPLUGIN_EVENT': myplugin_event_parser, - } - - # And connect the dicts event handlers to the handler stack. - uzbl.connect_dict(connects) + uzbl.connect_dict({ + # event name function + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'MYPLUGIN_EVENT': myplugin_event_parser, + }) # Or connect a handler to an event manually and supply additional optional # arguments: - #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.connect_dict({ + # external name function + 'myplugin_function': myplugin_function, + }) diff --git a/examples/data/uzbl/plugins/progress_bar.py b/examples/data/uzbl/plugins/progress_bar.py index b6fcb1b..89ba175 100644 --- a/examples/data/uzbl/plugins/progress_bar.py +++ b/examples/data/uzbl/plugins/progress_bar.py @@ -149,10 +149,11 @@ def reset_progress(uzbl, args): def init(uzbl): - connects = {'LOAD_PROGRESS': update_progress, - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'PROGRESS_CONFIG': progress_config, - 'LOAD_COMMIT': reset_progress} - - uzbl.connect_dict(connects) + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'LOAD_COMMIT': reset_progress, + 'LOAD_PROGRESS': update_progress, + 'PROGRESS_CONFIG': progress_config, + }) -- cgit v1.2.3 From 759143756ff5ab9076b5d9e1a3839d1e8690ede2 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 1 Jan 2010 21:29:16 +0800 Subject: We don't have support for inline comments. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9d0f710..bf08c9e 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -45,7 +45,7 @@ set scheme_handler = sync_spawn @scripts_dir/scheme.py # New window handler options #set new_window = sh 'echo uri "$8" > $4' # open in same window -set new_window = sh 'uzbl-browser -u $8' # equivalent to the default behaviour +set new_window = sh 'uzbl-browser -u $8' # Load start handlers @on_event LOAD_START @set_status wait -- cgit v1.2.3 From b1b605ef4b4bcdb4ae080cb9a596ce39892e58f4 Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 30 Dec 2009 02:10:35 +0200 Subject: uzbl-tabbed bind '@' fix --- examples/data/uzbl/scripts/uzbl-tabbed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index bb9b9a2..d93a3f4 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -1010,7 +1010,7 @@ class UzblTabbed: instance.''' binds = [] - bind_format = r'bind %s = sh "echo \"%s\" > \"%s\""' + bind_format = r'@bind %s = sh "echo \"%s\" > \"%s\""' bind = lambda key, action: binds.append(bind_format % (key, action,\ self.fifo_socket)) -- cgit v1.2.3 From aaa0654ffaf3c081ce8f0721340e61b2a3ce15e6 Mon Sep 17 00:00:00 2001 From: tczy Date: Tue, 29 Dec 2009 18:40:42 +0200 Subject: fixed http://www.uzbl.org/bugs/index.php?do=details&task_id=165 using supplied patch --- examples/data/uzbl/scripts/insert_bookmark.sh | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh index e04e6d4..c34e7db 100755 --- a/examples/data/uzbl/scripts/insert_bookmark.sh +++ b/examples/data/uzbl/scripts/insert_bookmark.sh @@ -6,6 +6,8 @@ file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks which zenity &>/dev/null || exit 2 entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` +exitstatus=$? +if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi url=`echo $entry | awk '{print $1}'` # TODO: check if already exists, if so, and tags are different: ask if you want to replace tags -- cgit v1.2.3 From 5fab9b5f81ff0d7eeebbd1bf07f4b945e1454165 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 23 Dec 2009 21:15:18 +0800 Subject: Added the escaped and quoted %r replace for on_event and bind args. --- examples/data/uzbl/plugins/bind.py | 10 ++++++++++ examples/data/uzbl/plugins/on_event.py | 11 +++++++++++ 2 files changed, 21 insertions(+) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 1cba7b2..668b595 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -306,9 +306,19 @@ class Bind(object): def expand(cmd, args): '''Replaces "%s %1 %2 %3..." with " ...".''' + # Direct string replace. if '%s' in cmd: cmd = cmd.replace('%s', ' '.join(map(unicode, args))) + # Escaped and quoted string replace. + if '%r' in cmd: + joined = ('%r' % ' '.join(map(unicode, args)))[1:] + for char in ['\\', '@']: + joined = joined.replace(char, '\\'+char) + + cmd = cmd.replace('%r', joined) + + # Arg index string replace. for (index, arg) in enumerate(args): index += 1 if '%%%d' % index in cmd: diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index afee4e6..9d2525b 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -2,6 +2,7 @@ Formatting options: %s = space separated string of the arguments + %r = escaped and quoted version of %s %1 = argument 1 %2 = argument 2 %n = argument n @@ -47,9 +48,19 @@ def get_on_events(uzbl): def expand(cmd, args): '''Replaces "%s %1 %2 %3..." with " ...".''' + # Direct string replace. if '%s' in cmd: cmd = cmd.replace('%s', ' '.join(map(unicode, args))) + # Escaped and quoted string replace. + if '%r' in cmd: + joined = ('%r' % ' '.join(map(unicode, args)))[1:] + for char in ['\\', '@']: + joined = joined.replace(char, '\\'+char) + + cmd = cmd.replace('%r', joined) + + # Arg index string replace. for (index, arg) in enumerate(args): index += 1 if '%%%d' % index in cmd: -- cgit v1.2.3 From d324593e958f89bf15478f60269688b2ca0c1b4a Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Thu, 24 Dec 2009 00:27:19 +0800 Subject: Moved expand function to external plugin to reduce code duplication. --- examples/data/uzbl/plugins/bind.py | 27 ++------------------ examples/data/uzbl/plugins/cmd_expand.py | 43 ++++++++++++++++++++++++++++++++ examples/data/uzbl/plugins/on_event.py | 27 ++------------------ 3 files changed, 47 insertions(+), 50 deletions(-) create mode 100644 examples/data/uzbl/plugins/cmd_expand.py (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 668b595..9614df6 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -303,30 +303,6 @@ class Bind(object): return self._repr_cache -def expand(cmd, args): - '''Replaces "%s %1 %2 %3..." with " ...".''' - - # Direct string replace. - if '%s' in cmd: - cmd = cmd.replace('%s', ' '.join(map(unicode, args))) - - # Escaped and quoted string replace. - if '%r' in cmd: - joined = ('%r' % ' '.join(map(unicode, args)))[1:] - for char in ['\\', '@']: - joined = joined.replace(char, '\\'+char) - - cmd = cmd.replace('%r', joined) - - # Arg index string replace. - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - def exec_bind(uzbl, bind, *args, **kargs): '''Execute bind objects.''' @@ -342,8 +318,9 @@ def exec_bind(uzbl, bind, *args, **kargs): raise ArgumentError('cannot supply kargs for uzbl commands') commands = [] + cmd_expand = uzbl.cmd_expand for cmd in bind.commands: - cmd = expand(cmd, args) + cmd = cmd_expand(cmd, args) uzbl.send(cmd) diff --git a/examples/data/uzbl/plugins/cmd_expand.py b/examples/data/uzbl/plugins/cmd_expand.py new file mode 100644 index 0000000..a5c279d --- /dev/null +++ b/examples/data/uzbl/plugins/cmd_expand.py @@ -0,0 +1,43 @@ +__export__ = ['cmd_expand',] + + +def escape(str): + for (level, char) in [(3, '\\'), (2, "'"), (2, '"'), (1, '@')]: + str = str.replace(char, (level * '\\') + char) + + return str + + +def cmd_expand(uzbl, cmd, args): + '''Exports a function that provides the following + expansions in any uzbl command string: + + %s = replace('%s', ' '.join(args)) + %r = replace('%r', "'%s'" % escaped(' '.join(args))) + %1 = replace('%1', arg[0]) + %2 = replace('%2', arg[1]) + %n = replace('%n', arg[n-1]) + ''' + + # Ensure (1) all string representable and (2) correct string encoding. + args = map(unicode, args) + + # Direct string replace. + if '%s' in cmd: + cmd = cmd.replace('%s', ' '.join(args)) + + # Escaped and quoted string replace. + if '%r' in cmd: + cmd = cmd.replace('%r', "'%s'" % escape(' '.join(args))) + + # Arg index string replace. + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) + + return cmd + + +def init(*args): + pass diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py index 9d2525b..f1ad0c9 100644 --- a/examples/data/uzbl/plugins/on_event.py +++ b/examples/data/uzbl/plugins/on_event.py @@ -45,30 +45,6 @@ def get_on_events(uzbl): return UZBLS[uzbl] -def expand(cmd, args): - '''Replaces "%s %1 %2 %3..." with " ...".''' - - # Direct string replace. - if '%s' in cmd: - cmd = cmd.replace('%s', ' '.join(map(unicode, args))) - - # Escaped and quoted string replace. - if '%r' in cmd: - joined = ('%r' % ' '.join(map(unicode, args)))[1:] - for char in ['\\', '@']: - joined = joined.replace(char, '\\'+char) - - cmd = cmd.replace('%r', joined) - - # Arg index string replace. - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - def event_handler(uzbl, *args, **kargs): '''This function handles all the events being watched by various on_event definitions and responds accordingly.''' @@ -79,8 +55,9 @@ def event_handler(uzbl, *args, **kargs): return commands = events[event] + cmd_expand = uzbl.cmd_expand for cmd in commands: - cmd = expand(cmd, args) + cmd = cmd_expand(cmd, args) uzbl.send(cmd) -- cgit v1.2.3 From cf98a9a7f1713c81ba855f79de2a48aa1f994714 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 26 Dec 2009 19:27:56 +0800 Subject: URIEncode search string component of web searching binds. --- examples/config/uzbl/config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9dc4a35..a6be6d6 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -230,9 +230,9 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @cbind N = search_reverse # --- Web searching binds --- -@cbind gg_ = uri http://www.google.com/search?q=%s -@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=%s&go=Go -@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=%s&go=Go +@cbind gg_ = uri http://www.google.com/search?q=\@\@ +@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=\@\@&go=Go +@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=\@\@&go=Go # --- Handy binds --- # Set function shortcut -- cgit v1.2.3 From 0482aae0aed75e333225c45312c260f63a888517 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 2 Jan 2010 20:53:07 +0800 Subject: Updated comments in handlers section and updated the download handler --- examples/config/uzbl/config | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index bf08c9e..4782a0d 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -39,15 +39,24 @@ set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; func # === Handlers =============================================================== -set download_handler = spawn @scripts_dir/download.sh -set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket -set scheme_handler = sync_spawn @scripts_dir/scheme.py +# --- Hardcoded event handlers ----------------------------------------------- -# New window handler options -#set new_window = sh 'echo uri "$8" > $4' # open in same window -set new_window = sh 'uzbl-browser -u $8' +# These handlers can't be moved to the new event system yet as we don't +# support events that can wait for a response from a script. +set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket +set scheme_handler = sync_spawn @scripts_dir/scheme.py -# Load start handlers +# Open in the same window. +#set new_window = sh 'echo uri "$8" > $4' +# Open a link in a new window. +set new_window = sh 'uzbl-browser -u $8' + +# --- Optional dynamic event handlers ---------------------------------------- + +# Download handler +@on_event DOWNLOAD_REQUEST spawn @scripts_dir/download.sh %s \@proxy_url + +# Load start handler @on_event LOAD_START @set_status wait # Load commit handlers @@ -69,7 +78,7 @@ set new_window = sh 'uzbl-browser -u $8' # Switch to command mode if anything else is clicked @on_event ROOT_ACTIVE @set_mode command -# Misc on_event handlers +# Example CONFIG_CHANGED event handler #@on_event CONFIG_CHANGED print Config changed: %1 = %2 # === Behaviour and appearance =============================================== -- cgit v1.2.3 From 069a2ccef8c9b55b8da5b211134945290a4a05d6 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Mon, 28 Dec 2009 19:45:12 +0100 Subject: uzbl-tabbed: don't use uzbl fifo --- examples/data/uzbl/scripts/uzbl-tabbed | 36 +++++++--------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index d93a3f4..169e773 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -383,25 +383,22 @@ class UzblTabbed: class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' - def __init__(self, parent, tab, fifo_socket, socket_file, pid,\ - uri, title, switch): + def __init__(self, parent, tab, socket_file, pid, uri, title, switch): self.parent = parent self.tab = tab - self.fifo_socket = fifo_socket self.socket_file = socket_file self.pid = pid self.title = title self.uri = uri self.timers = {} self._lastprobe = 0 - self._fifoout = [] self._socketout = [] self._socket = None self._buffer = "" # Switch to tab after loading self._switch = switch - # fifo/socket files exists and socket connected. + # socket files exists and socket connected. self._connected = False # The kill switch self._kill = False @@ -422,7 +419,7 @@ class UzblTabbed: def flush(self, timer_call=False): - '''Flush messages from the socket-out and fifo-out queues.''' + '''Flush messages from the socket-out queue.''' if self._kill: if self._socket: @@ -432,14 +429,6 @@ class UzblTabbed: error("Flush called on dead tab.") return False - if len(self._fifoout): - if os.path.exists(self.fifo_socket): - h = open(self.fifo_socket, 'w') - while len(self._fifoout): - msg = self._fifoout.pop(0) - h.write("%s\n"%msg) - h.close() - if len(self._socketout): if not self._socket and os.path.exists(self.socket_file): sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -452,7 +441,7 @@ class UzblTabbed: self._socket.send("%s\n"%msg) if not self._connected and timer_call: - if not len(self._fifoout + self._socketout): + if not self._socketout: self._connected = True if timer_call in self.timers.keys(): @@ -462,7 +451,7 @@ class UzblTabbed: if self._switch: self.grabfocus() - return len(self._fifoout + self._socketout) + return len(self._socketout) def grabfocus(self): @@ -481,14 +470,6 @@ class UzblTabbed: self._lastprobe = time.time() - def write(self, msg): - '''Child fifo write function.''' - - self._fifoout.append(msg) - # Flush messages from the queue if able. - return self.flush() - - def send(self, msg): '''Child socket send function.''' @@ -965,8 +946,6 @@ class UzblTabbed: sid = tab.get_id() uri = uri.strip() - fifo_filename = 'uzbl_fifo_%s_%0.2d' % (self.wid, pid) - fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) socket_file = os.path.join(config['socket_dir'], socket_filename) @@ -976,7 +955,7 @@ class UzblTabbed: if not title: title = config['new_tab_title'] - uzbl = self.UzblInstance(self, tab, fifo_socket, socket_file, pid,\ + uzbl = self.UzblInstance(self, tab, socket_file, pid,\ uri, title, switch) if len(uri): @@ -986,7 +965,7 @@ class UzblTabbed: cmd = 'uzbl-browser -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? - # Add gobject timer to make sure the config is pushed when fifo socket + # Add gobject timer to make sure the config is pushed when socket # has been created. timerid = timeout_add(100, uzbl.flush, "flush-initial-config") uzbl.timers['flush-initial-config'] = timerid @@ -1138,7 +1117,6 @@ class UzblTabbed: uzbl._socket.close() uzbl._socket = None - uzbl._fifoout = [] uzbl._socketout = [] uzbl._kill = True self._closed.append((uzbl.uri, uzbl.title)) -- cgit v1.2.3 From f2f1600e33e6f9487ea5cc96dcefb576cb5684d3 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Mon, 28 Dec 2009 19:45:44 +0100 Subject: uzbl-tabbed: get UzblInstance out of UzblTabbed --- examples/data/uzbl/scripts/uzbl-tabbed | 153 ++++++++++++++++----------------- 1 file changed, 76 insertions(+), 77 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 169e773..6bab849 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -377,106 +377,105 @@ def gen_endmarker(): return hashlib.md5(str(random.random()*time.time())).hexdigest() -class UzblTabbed: - '''A tabbed version of uzbl using gtk.Notebook''' - - class UzblInstance: - '''Uzbl instance meta-data/meta-action object.''' - - def __init__(self, parent, tab, socket_file, pid, uri, title, switch): - - self.parent = parent - self.tab = tab - self.socket_file = socket_file - self.pid = pid - self.title = title - self.uri = uri - self.timers = {} - self._lastprobe = 0 - self._socketout = [] - self._socket = None - self._buffer = "" - # Switch to tab after loading - self._switch = switch - # socket files exists and socket connected. - self._connected = False - # The kill switch - self._kill = False +class UzblInstance: + '''Uzbl instance meta-data/meta-action object.''' + + def __init__(self, parent, tab, socket_file, pid, uri, title, switch): + + self.parent = parent + self.tab = tab + self.socket_file = socket_file + self.pid = pid + self.title = title + self.uri = uri + self.timers = {} + self._lastprobe = 0 + self._socketout = [] + self._socket = None + self._buffer = "" + # Switch to tab after loading + self._switch = switch + # socket files exists and socket connected. + self._connected = False + # The kill switch + self._kill = False - # Message termination endmarker. - self._marker = gen_endmarker() + # Message termination endmarker. + self._marker = gen_endmarker() - # Gen probe commands string - probes = [] - probe = probes.append - probe('print uri %d @uri %s' % (self.pid, self._marker)) - probe('print title %d @@ %s' % (self.pid,\ - self._marker)) - self._probecmds = '\n'.join(probes) + # Gen probe commands string + probes = [] + probe = probes.append + probe('print uri %d @uri %s' % (self.pid, self._marker)) + probe('print title %d @@ %s' % (self.pid,\ + self._marker)) + self._probecmds = '\n'.join(probes) - # Enqueue keybinding config for child uzbl instance - self.parent.config_uzbl(self) + # Enqueue keybinding config for child uzbl instance + self.parent.config_uzbl(self) - def flush(self, timer_call=False): - '''Flush messages from the socket-out queue.''' + def flush(self, timer_call=False): + '''Flush messages from the socket-out queue.''' - if self._kill: - if self._socket: - self._socket.close() - self._socket = None + if self._kill: + if self._socket: + self._socket.close() + self._socket = None - error("Flush called on dead tab.") - return False + error("Flush called on dead tab.") + return False - if len(self._socketout): - if not self._socket and os.path.exists(self.socket_file): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(self.socket_file) - self._socket = sock + if len(self._socketout): + if not self._socket and os.path.exists(self.socket_file): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(self.socket_file) + self._socket = sock - if self._socket: - while len(self._socketout): - msg = self._socketout.pop(0) - self._socket.send("%s\n"%msg) + if self._socket: + while len(self._socketout): + msg = self._socketout.pop(0) + self._socket.send("%s\n"%msg) - if not self._connected and timer_call: - if not self._socketout: - self._connected = True + if not self._connected and timer_call: + if not self._socketout: + self._connected = True - if timer_call in self.timers.keys(): - source_remove(self.timers[timer_call]) - del self.timers[timer_call] + if timer_call in self.timers.keys(): + source_remove(self.timers[timer_call]) + del self.timers[timer_call] - if self._switch: - self.grabfocus() + if self._switch: + self.grabfocus() - return len(self._socketout) + return len(self._socketout) - def grabfocus(self): - '''Steal parent focus and switch the notebook to my own tab.''' + def grabfocus(self): + '''Steal parent focus and switch the notebook to my own tab.''' - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) - self.parent.goto_tab(tabid) + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) + self.parent.goto_tab(tabid) - def probe(self): - '''Probes the client for information about its self.''' + def probe(self): + '''Probes the client for information about its self.''' - if self._connected: - self.send(self._probecmds) - self._lastprobe = time.time() + if self._connected: + self.send(self._probecmds) + self._lastprobe = time.time() - def send(self, msg): - '''Child socket send function.''' + def send(self, msg): + '''Child socket send function.''' - self._socketout.append(msg) - # Flush messages from queue if able. - return self.flush() + self._socketout.append(msg) + # Flush messages from queue if able. + return self.flush() +class UzblTabbed: + '''A tabbed version of uzbl using gtk.Notebook''' def __init__(self): '''Create tablist, window and notebook.''' -- cgit v1.2.3 From 6a2b62a798bbaca10ded2d95d739b877b735b10e Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Mon, 28 Dec 2009 23:49:35 +0100 Subject: uzbl-tabbed changes : * Remove bind_* options: does not work with current uzbl revisions, and a better implementation will come soon. * Remove reading of uzbl config file (same reason) * Better IPC handling (to sumarize: less periodic polling): * Better separation between network layers (communication is in SocketClient, protocol in UzblInstance, user interface in UzblTabbed) * use io_add_watch instead of select for reading uzbl events * does not use a generated hash to separate events, but the LF character * get rid of all the flush()ing logic * does not probe periodically for the title anymore; use uzbl events * create a /tmp/uzbltabbed_socket instead of polling the /tmp/uzbl_socket_* socket --- examples/data/uzbl/scripts/uzbl-tabbed | 442 ++++++++++++++------------------- 1 file changed, 183 insertions(+), 259 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 6bab849..9d8e1e6 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -96,25 +96,6 @@ # window_size = 800,800 # verbose = 0 # -# And the key bindings: -# bind_new_tab = gn -# bind_tab_from_clip = gY -# bind_tab_from_uri = go _ -# bind_close_tab = gC -# bind_next_tab = gt -# bind_prev_tab = gT -# bind_goto_tab = gi_ -# bind_goto_first = g< -# bind_goto_last = g> -# bind_clean_slate = gQ -# bind_exit = gZ -# -# Session preset key bindings: -# bind_save_preset = gsave _ -# bind_load_preset = gload _ -# bind_del_preset = gdel _ -# bind_list_presets = glist -# # And uzbl_tabbed.py takes care of the actual binding of the commands via each # instances fifo socket. # @@ -209,12 +190,6 @@ for path in [DATA_DIR, CONFIG_DIR]: if not os.path.exists(path): os.makedirs(path) -# Path to uzbl config -UZBL_CONFIG = os.path.join(CONFIG_DIR, 'config') -if not os.path.exists(UZBL_CONFIG): - error("cannot find uzbl config file at %r" % UZBL_CONFIG) - sys.exit(1) - # All of these settings can be inherited from your uzbl config file. config = { # Tab options @@ -249,25 +224,6 @@ config = { 'window_size': "800,800", # width,height in pixels. 'verbose': False, # Print verbose output. - # Key bindings - 'bind_new_tab': 'gn', # Open new tab. - 'bind_tab_from_clip': 'gY', # Open tab from clipboard. - 'bind_tab_from_uri': 'go _', # Open new tab and goto entered uri. - 'bind_close_tab': 'gC', # Close tab. - 'bind_next_tab': 'gt', # Next tab. - 'bind_prev_tab': 'gT', # Prev tab. - 'bind_goto_tab': 'gi_', # Goto tab by tab-number (in title). - 'bind_goto_first': 'g<', # Goto first tab. - 'bind_goto_last': 'g>', # Goto last tab. - 'bind_clean_slate': 'gQ', # Close all tabs and open new tab. - 'bind_exit': 'gZ', # Exit nicely. - - # Session preset key bindings - 'bind_save_preset': 'gsave _', # Save session to file %s. - 'bind_load_preset': 'gload _', # Load preset session from file %s. - 'bind_del_preset': 'gdel _', # Delete preset session %s. - 'bind_list_presets': 'glist', # List all session presets. - # Add custom tab style definitions to be used by the tab colour policy # handler here. Because these are added to the config dictionary like # any other uzbl_tabbed configuration option remember that they can @@ -371,108 +327,132 @@ def escape(s): return s -def gen_endmarker(): - '''Generates a random md5 for socket message-termination endmarkers.''' +class SocketClient: + '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance''' + + # List of UzblInstance objects not already linked with a SocketClient + instances_queue = {} + + def __init__(self, socket): + self._buffer = "" + self._socket = socket + self._watchers = [io_add_watch(socket, IO_IN, self._socket_recv),\ + io_add_watch(socket, IO_HUP, self._socket_closed)] + self.uzbl = None + + + def _socket_recv(self, fd, condition): + '''Data available on socket, process it''' + + self._feed(self._socket.recv(1024)) #TODO: is io_add_watch edge or level-triggered ? + return True + + + def _socket_closed(self, fd, condition): + '''Remote client exited''' + self.uzbl.close() + return False - return hashlib.md5(str(random.random()*time.time())).hexdigest() + + def _feed(self, data): + '''An Uzbl instance sent some data, parse it''' + + self._buffer += data + if self.uzbl: + if "\n" in self._buffer: + cmds = self._buffer.split("\n") + + if cmds[-1]: # Last command has been received incomplete, don't process it + self._buffer, cmds = cmds[-1], cmds[:-1] + else: + self._buffer = "" + + for cmd in cmds: + if cmd: + self.uzbl.parse_command(cmd) + else: + name = re.findall('^EVENT \[(\d+-\d+)\] INSTANCE_START \d+$', self._buffer, re.M) + uzbl = self.instances_queue.get(name[0]) + if uzbl: + del self.instances_queue[name[0]] + self.uzbl = uzbl + self.uzbl.got_socket(self) + self._feed("") + + def send(self, data): + '''Child socket send function.''' + + self._socket.send(data + "\n") + + def close(self): + '''Close the connection''' + + if self._socket: + self._socket.close() + self._socket = None + map(source_remove, self._watchers) + self._watchers = [] class UzblInstance: '''Uzbl instance meta-data/meta-action object.''' - def __init__(self, parent, tab, socket_file, pid, uri, title, switch): + def __init__(self, parent, tab, name, uri, title, switch): self.parent = parent self.tab = tab - self.socket_file = socket_file - self.pid = pid + self.name = name self.title = title self.uri = uri - self.timers = {} - self._lastprobe = 0 - self._socketout = [] - self._socket = None - self._buffer = "" - # Switch to tab after loading - self._switch = switch - # socket files exists and socket connected. - self._connected = False - # The kill switch - self._kill = False - - # Message termination endmarker. - self._marker = gen_endmarker() - - # Gen probe commands string - probes = [] - probe = probes.append - probe('print uri %d @uri %s' % (self.pid, self._marker)) - probe('print title %d @@ %s' % (self.pid,\ - self._marker)) - self._probecmds = '\n'.join(probes) - - # Enqueue keybinding config for child uzbl instance - self.parent.config_uzbl(self) + self._client = None + self._switch = switch # Switch to tab after loading ? - def flush(self, timer_call=False): - '''Flush messages from the socket-out queue.''' + def got_socket(self, client): + '''Uzbl instance is now connected''' + self._client = client - if self._kill: - if self._socket: - self._socket.close() - self._socket = None + self.parent.tabs[self.tab] = self + self.parent.update_tablist() - error("Flush called on dead tab.") - return False - - if len(self._socketout): - if not self._socket and os.path.exists(self.socket_file): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(self.socket_file) - self._socket = sock + self.parent.config_uzbl(self) - if self._socket: - while len(self._socketout): - msg = self._socketout.pop(0) - self._socket.send("%s\n"%msg) + if self._switch: + tabs = list(self.parent.notebook) + tabid = tabs.index(self.tab) + self.parent.goto_tab(tabid) - if not self._connected and timer_call: - if not self._socketout: - self._connected = True - if timer_call in self.timers.keys(): - source_remove(self.timers[timer_call]) - del self.timers[timer_call] + def set(self, key, val): + ''' Send the SET command to Uzbl ''' - if self._switch: - self.grabfocus() + self._client.send('set %s = %s') #TODO: escape chars ? - return len(self._socketout) + def exit(sedf): + ''' Ask the Uzbl instance to close ''' - def grabfocus(self): - '''Steal parent focus and switch the notebook to my own tab.''' + self._client.send('exit') #TODO: escape chars ? - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) - self.parent.goto_tab(tabid) + def parse_command(self, cmd): + ''' Parse event givent by the Uzbl instance ''' - def probe(self): - '''Probes the client for information about its self.''' + type, _, args = cmd.split(" ", 2) + if type == "EVENT": + type, args = args.split(" ", 1) + if type == "TITLE_CHANGED": + self.title = args + self.parent.update_tablist() - if self._connected: - self.send(self._probecmds) - self._lastprobe = time.time() + def close(self): + '''The remote instance exited''' - def send(self, msg): - '''Child socket send function.''' + if self._client: + self._client.close() + self._client = None - self._socketout.append(msg) - # Flush messages from queue if able. - return self.flush() class UzblTabbed: '''A tabbed version of uzbl using gtk.Notebook''' @@ -480,9 +460,6 @@ class UzblTabbed: def __init__(self): '''Create tablist, window and notebook.''' - # Store information about the applications fifo_socket. - self._fifo = None - self._timers = {} self._buffer = "" self._killed = False @@ -493,6 +470,9 @@ class UzblTabbed: # Holds metadata on the uzbl childen open. self.tabs = {} + # Uzbl sockets (socket => SocketClient) + self.clients = {} + # Generates a unique id for uzbl socket filenames. self.next_pid = counter().next @@ -577,12 +557,18 @@ class UzblTabbed: self.window.show() self.wid = self.notebook.window.xid - # Generate the fifo socket filename. - fifo_filename = 'uzbltabbed_%d' % os.getpid() - self.fifo_socket = os.path.join(config['fifo_dir'], fifo_filename) - # Now initialise the fifo socket at self.fifo_socket - self.init_fifo_socket() + # Store information about the applications fifo and socket. + fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid() + socket_filename = 'uzbltabbed_%d.socket' % os.getpid() + self._fifo = None + self._socket = None + self.fifo_path = os.path.join(config['fifo_dir'], fifo_filename) + self.socket_path = os.path.join(config['socket_dir'], socket_filename) + + # Now initialise the fifo and the socket + self.init_fifo() + self.init_socket() # If we are using sessions then load the last one if it exists. if config['save_session']: @@ -592,7 +578,7 @@ class UzblTabbed: def run(self): '''UzblTabbed main function that calls the gtk loop.''' - if not len(self.tabs): + if not self.clients and not SocketClient.instances_queue and not self.tabs: self.new_tab() gtk_refresh = int(config['gtk_refresh']) @@ -603,10 +589,6 @@ class UzblTabbed: timerid = timeout_add(gtk_refresh, self.update_tablist) self._timers["update-tablist"] = timerid - # Probe clients every second for window titles and location - timerid = timeout_add(gtk_refresh, self.probe_clients) - self._timers["probe-clients"] = timerid - # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) @@ -620,7 +602,7 @@ class UzblTabbed: error("encounted error %r" % sys.exc_info()[1]) # Unlink fifo socket - self.unlink_fifo_socket() + self.unlink_fifo() # Attempt to close all uzbl instances nicely. self.quitrequest() @@ -651,40 +633,72 @@ class UzblTabbed: self.quitrequest() - def init_fifo_socket(self): - '''Create interprocess communication fifo socket.''' + def init_socket(self): + '''Create interprocess communication socket.''' + + def accept(sock, condition): + '''A new uzbl instance was created''' + + client, _ = sock.accept() + self.clients[client] = SocketClient(client) + + return True + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(self.socket_path) + sock.listen(1) + + # Add event handler for IO_IN event. + self._socket = (sock, io_add_watch(sock, IO_IN, accept)) + + echo("[socket] listening at %r" % self.socket_path) + + # Add atexit register to destroy the socket on program termination. + atexit.register(self.close_socket) + + + def close_socket(self): + '''Close the socket when closing the application''' + + (fd, watcher) = self._socket + source_remove(watcher) + fd.close() + + + def init_fifo(self): + '''Create interprocess communication fifo.''' - if os.path.exists(self.fifo_socket): - if not os.access(self.fifo_socket, os.F_OK | os.R_OK | os.W_OK): - os.mkfifo(self.fifo_socket) + 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_socket) + basedir = os.path.dirname(self.fifo_path) if not os.path.exists(basedir): os.makedirs(basedir) - os.mkfifo(self.fifo_socket) + os.mkfifo(self.fifo_path) # Add event handlers for IO_IN & IO_HUP events. self.setup_fifo_watchers() - echo("listening at %r" % self.fifo_socket) + echo("[fifo] listening at %r" % self.fifo_path) - # Add atexit register to destroy the socket on program termination. - atexit.register(self.unlink_fifo_socket) + # Add atexit register to destroy the fifo on program termination. + atexit.register(self.unlink_fifo) - def unlink_fifo_socket(self): + def unlink_fifo(self): '''Unlink the fifo socket. Note: This function is called automatically on exit by an atexit register.''' - # Make sure the fifo_socket fd is closed. + # Make sure the fifo fd is closed. self.close_fifo() - # And unlink if the real fifo_socket exists. - if os.path.exists(self.fifo_socket): - os.unlink(self.fifo_socket) - echo("unlinked %r" % self.fifo_socket) + # 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): @@ -707,10 +721,10 @@ class UzblTabbed: '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event handlers.''' - # Close currently open fifo_socket fd and kill all watchers + # Close currently open fifo fd and kill all watchers self.close_fifo() - fd = os.open(self.fifo_socket, os.O_RDONLY | os.O_NONBLOCK) + 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),\ @@ -749,43 +763,6 @@ class UzblTabbed: return True - def probe_clients(self): - '''Probe all uzbl clients for up-to-date window titles and uri's.''' - - save_session = config['save_session'] - - sockd = {} - tabskeys = self.tabs.keys() - notebooklist = list(self.notebook) - - for tab in notebooklist: - if tab not in tabskeys: continue - uzbl = self.tabs[tab] - uzbl.probe() - if uzbl._socket: - sockd[uzbl._socket] = uzbl - - sockets = sockd.keys() - (reading, _, errors) = select.select(sockets, [], sockets, 0) - - for sock in reading: - uzbl = sockd[sock] - uzbl._buffer = sock.recv(1024).replace('\n',' ') - temp = uzbl._buffer.split(uzbl._marker) - 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: - error("parse_command: invalid command %s" % ' '.join(cmd)) - raise - - return True - - def parse_command(self, cmd): '''Parse instructions from uzbl child processes.''' @@ -858,7 +835,7 @@ class UzblTabbed: elif cmd[0] in ["title", "uri"]: if len(cmd) > 2: - uzbl = self.get_tab_by_pid(int(cmd[1])) + uzbl = self.get_tab_by_name(int(cmd[1])) if uzbl: old = getattr(uzbl, cmd[0]) new = ' '.join(cmd[2:]) @@ -867,7 +844,7 @@ class UzblTabbed: self.update_tablist() else: - error("parse_command: no uzbl with pid %r" % int(cmd[1])) + error("parse_command: no uzbl with name %r" % int(cmd[1])) elif cmd[0] == "preset": if len(cmd) < 3: @@ -890,20 +867,20 @@ class UzblTabbed: error("parse_command: preset %r does not exist." % path) elif cmd[1] == "list": - uzbl = self.get_tab_by_pid(int(cmd[2])) + 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.send(js) + 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.send(js) + uzbl._client.send(js) else: - error("parse_command: unknown tab pid.") + error("parse_command: unknown tab name.") else: error("parse_command: unknown parse command %r"\ @@ -922,11 +899,11 @@ class UzblTabbed: error("parse_command: unknown command %r" % ' '.join(cmd)) - def get_tab_by_pid(self, pid): - '''Return uzbl instance by pid.''' + def get_tab_by_name(self, name): + '''Return uzbl instance by name.''' for (tab, uzbl) in self.tabs.items(): - if uzbl.pid == pid: + if uzbl.name == name: return uzbl return False @@ -938,15 +915,12 @@ class UzblTabbed: when you need to load multiple tabs at a time (I.e. like when restoring a session from a file).''' - pid = self.next_pid() tab = gtk.Socket() tab.show() self.notebook.append_page(tab) sid = tab.get_id() uri = uri.strip() - - socket_filename = 'uzbl_socket_%s_%0.2d' % (self.wid, pid) - socket_file = os.path.join(config['socket_dir'], socket_filename) + name = "%d-%d" % (os.getpid(), self.next_pid()) if switch is None: switch = config['switch_to_new_tabs'] @@ -954,22 +928,12 @@ class UzblTabbed: if not title: title = config['new_tab_title'] - uzbl = self.UzblInstance(self, tab, socket_file, pid,\ - uri, title, switch) - - if len(uri): - uri = "--uri %r" % uri - - self.tabs[tab] = uzbl - cmd = 'uzbl-browser -s %s -n %s_%0.2d %s &' % (sid, self.wid, pid, uri) - subprocess.Popen([cmd], shell=True) # TODO: do i need close_fds=True ? - - # Add gobject timer to make sure the config is pushed when socket - # has been created. - timerid = timeout_add(100, uzbl.flush, "flush-initial-config") - uzbl.timers['flush-initial-config'] = timerid + cmd = ['uzbl-browser', '-n', name, '-s', str(sid), + '--connect-socket', self.socket_path, '--uri', uri] + subprocess.Popen(cmd) # TODO: do i need close_fds=True ? - self.update_tablist() + uzbl = UzblInstance(self, tab, name, uri, title, switch) + SocketClient.instances_queue[name] = uzbl def clean_slate(self): @@ -980,48 +944,17 @@ class UzblTabbed: for tab in list(self.notebook)[:-1]: if tab not in tabs: continue uzbl = self.tabs[tab] - uzbl.send("exit") + uzbl.exit() def config_uzbl(self, uzbl): '''Send bind commands for tab new/close/next/prev to a uzbl instance.''' - binds = [] - bind_format = r'@bind %s = sh "echo \"%s\" > \"%s\""' - bind = lambda key, action: binds.append(bind_format % (key, action,\ - self.fifo_socket)) - - sets = [] - set_format = r'set %s = sh \"echo \\"%s\\" > \\"%s\\""' - set = lambda key, action: binds.append(set_format % (key, action,\ - self.fifo_socket)) - - # Bind definitions here - # bind(key, command back to fifo) - bind(config['bind_new_tab'], 'new') - bind(config['bind_tab_from_clip'], 'newfromclip') - bind(config['bind_tab_from_uri'], 'new %s') - bind(config['bind_close_tab'], 'close') - bind(config['bind_next_tab'], 'next') - bind(config['bind_prev_tab'], 'prev') - bind(config['bind_goto_tab'], 'goto %s') - bind(config['bind_goto_first'], 'goto 0') - bind(config['bind_goto_last'], 'goto -1') - bind(config['bind_clean_slate'], 'clean') - bind(config['bind_save_preset'], 'preset save %s') - bind(config['bind_load_preset'], 'preset load %s') - bind(config['bind_del_preset'], 'preset del %s') - bind(config['bind_list_presets'], 'preset list %d' % uzbl.pid) - bind(config['bind_exit'], 'exit') - # Set definitions here # set(key, command back to fifo) if config['capture_new_windows']: - set("new_window", r'new $8') - - # Send config to uzbl instance via its socket file. - uzbl.send("\n".join(binds+sets)) + uzbl.set("new_window", r'new $8') def goto_tab(self, index): @@ -1107,17 +1040,8 @@ class UzblTabbed: if tab in self.tabs.keys(): uzbl = self.tabs[tab] - for (timer, gid) in uzbl.timers.items(): - error("tab_closed: removing timer %r" % timer) - source_remove(gid) - del uzbl.timers[timer] - - if uzbl._socket: - uzbl._socket.close() - uzbl._socket = None + uzbl.close() - uzbl._socketout = [] - uzbl._kill = True self._closed.append((uzbl.uri, uzbl.title)) self._closed = self._closed[-10:] del self.tabs[tab] @@ -1375,7 +1299,7 @@ class UzblTabbed: os.remove(config['session_file']) for (tab, uzbl) in self.tabs.items(): - uzbl.send("exit") + uzbl.exit() # Add a gobject timer to make sure the application force-quits after a # reasonable period. Calling quit when all the tabs haven't had time to @@ -1390,7 +1314,7 @@ class UzblTabbed: # Close the fifo socket, remove any gobject io event handlers and # delete socket. - self.unlink_fifo_socket() + self.unlink_fifo() # Remove all gobject timers that are still ticking. for (timerid, gid) in self._timers.items(): -- cgit v1.2.3 From 0787a00be40badff461e4f931944f199b68a5408 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Tue, 29 Dec 2009 00:59:15 +0100 Subject: uzbl-tabbed: * misc fixes (problems introduced in last commit) * correct implemenation of the configuration (use uzbl events insted of config file; you can now do :set show_tablist=0) --- examples/data/uzbl/scripts/uzbl-tabbed | 166 +++++++++++++++++---------------- 1 file changed, 88 insertions(+), 78 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 9d8e1e6..dc6c773 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -183,12 +183,10 @@ def xdghome(key, default): # Setup xdg paths. DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') -CONFIG_DIR = os.path.join(xdghome('CONFIG', '.config/'), 'uzbl/') # Ensure uzbl xdg paths exist -for path in [DATA_DIR, CONFIG_DIR]: - if not os.path.exists(path): - os.makedirs(path) +if not os.path.exists(DATA_DIR): + os.makedirs(DATA_DIR) # All of these settings can be inherited from your uzbl config file. config = { @@ -240,6 +238,8 @@ config = { } # End of config dict. +UZBL_TABBED_VARS = config.keys() + # This is the tab style policy handler. Every time the tablist is updated # this function is called to determine how to colourise that specific tab # according the simple/complex rules as defined here. You may even wish to @@ -279,37 +279,6 @@ def echo(msg): sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) -def readconfig(uzbl_config, config): - '''Loads relevant config from the users uzbl config file into the global - config dictionary.''' - - if not os.path.exists(uzbl_config): - error("Unable to load config %r" % uzbl_config) - return None - - # Define parsing regular expressions - isint = re.compile("^(\-|)[0-9]+$").match - findsets = re.compile("^set\s+([^\=]+)\s*\=\s*(.+)$",\ - re.MULTILINE).findall - - h = open(os.path.expandvars(uzbl_config), 'r') - rawconfig = h.read() - h.close() - - configkeys, strip = config.keys(), str.strip - for (key, value) in findsets(rawconfig): - key, value = strip(key), strip(value) - if key not in configkeys: continue - if isint(value): value = int(value) - config[key] = value - - # Ensure that config keys that relate to paths are expanded. - pathkeys = ['fifo_dir', 'socket_dir', 'session_file', 'icon_path', - 'saved_sessions_dir'] - for key in pathkeys: - config[key] = os.path.expandvars(config[key]) - - def counter(): '''To infinity and beyond!''' @@ -429,7 +398,7 @@ class UzblInstance: self._client.send('set %s = %s') #TODO: escape chars ? - def exit(sedf): + def exit(self): ''' Ask the Uzbl instance to close ''' self._client.send('exit') #TODO: escape chars ? @@ -444,6 +413,34 @@ class UzblInstance: if type == "TITLE_CHANGED": self.title = args self.parent.update_tablist() + elif type == "VARIABLE_SET": + var, _, val = args.split(" ", 2) + try: + val = int(val) + except: + pass + + if var in UZBL_TABBED_VARS: + if config[var] != val: + config[var] = val + if var == "show_gtk_tabs": + self.parent.notebook.set_show_tabs(bool(val)) + elif var == "show_tablist" or var == "tablist_top": + self.parent.update_tablist_display() + elif var == "gtk_tab_pos": + self.parent.update_gtk_tab_pos() + elif var == "status_background": + col = gtk.gdk.color_parse(config['status_background']) + self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col) + self.parent.update_tablist() + else: + config[var] = val + + if var == "uri": + self.uri = var + self.parent.update_tablist() + else: + print type, args def close(self): @@ -502,35 +499,33 @@ class UzblTabbed: self.window.connect("delete-event", self.quitrequest) # Create tab list - if config['show_tablist']: - vbox = gtk.VBox() - self.window.add(vbox) - ebox = gtk.EventBox() - self.tablist = gtk.Label() - - self.tablist.set_use_markup(True) - self.tablist.set_justify(gtk.JUSTIFY_LEFT) - self.tablist.set_line_wrap(False) - self.tablist.set_selectable(False) - self.tablist.set_padding(2,2) - self.tablist.set_alignment(0,0) - self.tablist.set_ellipsize(pango.ELLIPSIZE_END) - self.tablist.set_text(" ") - self.tablist.show() - ebox.add(self.tablist) - ebox.show() - bgcolor = gtk.gdk.color_parse(config['status_background']) - ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) + vbox = gtk.VBox() + self.vbox = vbox + self.window.add(vbox) + ebox = gtk.EventBox() + self.ebox = ebox + self.tablist = gtk.Label() + + self.tablist.set_use_markup(True) + self.tablist.set_justify(gtk.JUSTIFY_LEFT) + self.tablist.set_line_wrap(False) + self.tablist.set_selectable(False) + self.tablist.set_padding(2,2) + self.tablist.set_alignment(0,0) + self.tablist.set_ellipsize(pango.ELLIPSIZE_END) + self.tablist.set_text(" ") + self.tablist.show() + ebox.add(self.tablist) + ebox.show() + bgcolor = gtk.gdk.color_parse(config['status_background']) + ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) # Create notebook self.notebook = gtk.Notebook() self.notebook.set_show_tabs(config['show_gtk_tabs']) # Set tab position - allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, - 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} - if config['gtk_tab_pos'] in allposes.keys(): - self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + self.update_gtk_tab_pos() self.notebook.set_show_border(False) self.notebook.set_scrollable(True) @@ -541,20 +536,11 @@ class UzblTabbed: self.notebook.connect("page-added", self.tab_opened) self.notebook.show() - if config['show_tablist']: - if config['tablist_top']: - vbox.pack_start(ebox, False, False, 0) - vbox.pack_end(self.notebook, True, True, 0) - - else: - vbox.pack_start(self.notebook, True, True, 0) - vbox.pack_end(ebox, False, False, 0) - - vbox.show() - - else: - self.window.add(self.notebook) + vbox.pack_start(self.notebook, True, True, 0) + vbox.reorder_child(self.notebook, 1) + self.update_tablist_display() + self.vbox.show() self.window.show() self.wid = self.notebook.window.xid @@ -603,6 +589,7 @@ class UzblTabbed: # Unlink fifo socket self.unlink_fifo() + self.close_socket() # Attempt to close all uzbl instances nicely. self.quitrequest() @@ -660,9 +647,12 @@ class UzblTabbed: def close_socket(self): '''Close the socket when closing the application''' - (fd, watcher) = self._socket - source_remove(watcher) - fd.close() + if self._socket: + (fd, watcher) = self._socket + source_remove(watcher) + fd.close() + os.unlink(self.socket_path) + self._socket = None def init_fifo(self): @@ -1067,6 +1057,28 @@ class UzblTabbed: return True + def update_tablist_display(self): + '''Called when show_tablist or tablist_top has changed''' + + if self.ebox in self.vbox.get_children(): + self.vbox.remove(self.ebox) + + if config['show_tablist']: + self.vbox.pack_start(self.ebox, False, False, 0) + if config['tablist_top']: + self.vbox.reorder_child(self.ebox, 0) + else: + self.vbox.reorder_child(self.ebox, 2) + + def update_gtk_tab_pos(self): + ''' Called when gtk_tab_pos has changed ''' + + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} + if config['gtk_tab_pos'] in allposes.keys(): + self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + + def update_tablist(self, curpage=None): '''Upate tablist status bar.''' @@ -1315,6 +1327,7 @@ class UzblTabbed: # Close the fifo socket, remove any gobject io event handlers and # delete socket. self.unlink_fifo() + self.close_socket() # Remove all gobject timers that are still ticking. for (timerid, gid) in self._timers.items(): @@ -1330,9 +1343,6 @@ class UzblTabbed: if __name__ == "__main__": - # Read from the uzbl config into the global config dictionary. - readconfig(UZBL_CONFIG, config) - # Build command line parser usage = "usage: %prog [OPTIONS] {URIS}..." parser = OptionParser(usage=usage) -- cgit v1.2.3 From a5724db578e2595f57698eb5ad01f033a3e4a510 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Tue, 29 Dec 2009 01:28:33 +0100 Subject: implemented new actions for uzbl_tabbed --- examples/data/uzbl/scripts/uzbl-tabbed | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index dc6c773..0752895 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -439,8 +439,32 @@ class UzblInstance: if var == "uri": self.uri = var self.parent.update_tablist() - else: - print type, args + elif type == "NEW_TAB": + self.parent.new_tab(args) + elif type == "NEXT_TAB": + if args: + self.parent.next_tab(int(args)) + else: + self.parent.next_tab() + elif type == "PREV_TAB": + if args: + self.parent.prev_tab(int(args)) + else: + self.parent.prev_tab() + elif type == "GOTO_TAB": + self.parent.goto_tab(int(args)) + elif type == "FIRST_TAB": + self.parent.goto_tab(0) + elif type == "LAST_TAB": + self.parent.goto_tab(-1) + elif type == "PRESET_TABS": + self.parent.parse_command(["preset"] + args.split()) + elif type == "BRING_TO_FRONT": + self.parent.window.present() + elif type == "CLEAN_TABS": + self.parent.clean_slate() + elif type == "EXIT_ALL_TABS": + self.parent.quitrequest() def close(self): -- cgit v1.2.3 From ddddb35a2b5127847a3e354c7e9725e9fcecaeb3 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Tue, 29 Dec 2009 14:00:46 +0100 Subject: uzbl-tabbed: get rid of update-tablist timer --- examples/data/uzbl/scripts/uzbl-tabbed | 163 ++++++++++++++++----------------- 1 file changed, 81 insertions(+), 82 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 0752895..84f1158 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -372,9 +372,11 @@ class UzblInstance: self.tab = tab self.name = name self.title = title + self.tabtitle = "" self.uri = uri self._client = None self._switch = switch # Switch to tab after loading ? + self.title_changed() def got_socket(self, client): @@ -382,16 +384,45 @@ class UzblInstance: self._client = client self.parent.tabs[self.tab] = self - self.parent.update_tablist() - self.parent.config_uzbl(self) if self._switch: - tabs = list(self.parent.notebook) - tabid = tabs.index(self.tab) + tabid = self.parent.notebook.page_num(self.tab) self.parent.goto_tab(tabid) + def title_changed(self, gtk_only = True): # GTK-only is for indexes + '''self.title has changed, update the tabs list''' + + tab_titles = config['tab_titles'] + show_ellipsis = config['show_ellipsis'] + max_title_len = config['max_title_len'] + + # Unicode heavy strings do not like being truncated/sliced so by + # re-encoding the string sliced of limbs are removed. + self.tabtitle = self.title[:max_title_len + int(show_ellipsis)] + if type(self.tabtitle) != types.UnicodeType: + self.tabtitle = unicode(self.tabtitle, 'utf-8', 'ignore') + + self.tabtitle = self.tabtitle.encode('utf-8', 'ignore').strip() + + if show_ellipsis and len(self.tabtitle) != len(self.title): + self.tabtitle += "\xe2\x80\xa6" + + gtk_tab_format = "%d %s" + tab_titles = config['tab_titles'] + index = self.parent.notebook.page_num(self.tab) + if tab_titles: + self.parent.notebook.set_tab_label_text(self.tab, + gtk_tab_format % (index, self.tabtitle)) + else: + self.parent.notebook.set_tab_label_text(self.tab, str(index)) + + # Non-GTK tabs + if not gtk_only: + self.parent.update_tablist() + + def set(self, key, val): ''' Send the SET command to Uzbl ''' @@ -401,7 +432,7 @@ class UzblInstance: def exit(self): ''' Ask the Uzbl instance to close ''' - self._client.send('exit') #TODO: escape chars ? + self._client.send('exit') def parse_command(self, cmd): @@ -412,7 +443,7 @@ class UzblInstance: type, args = args.split(" ", 1) if type == "TITLE_CHANGED": self.title = args - self.parent.update_tablist() + self.title_changed() elif type == "VARIABLE_SET": var, _, val = args.split(" ", 2) try: @@ -595,10 +626,6 @@ class UzblTabbed: if gtk_refresh < 100: gtk_refresh = 100 - # Update tablist timer - timerid = timeout_add(gtk_refresh, self.update_tablist) - self._timers["update-tablist"] = timerid - # Make SIGTERM act orderly. signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) @@ -974,9 +1001,13 @@ class UzblTabbed: def goto_tab(self, index): '''Goto tab n (supports negative indexing).''' + title_format = "%s - Uzbl Browser" + tabs = list(self.notebook) if 0 <= index < len(tabs): self.notebook.set_current_page(index) + uzbl = self.tabs[self.notebook.get_nth_page(index)] + self.window.set_title(title_format % uzbl.title) self.update_tablist() return None @@ -986,6 +1017,8 @@ class UzblTabbed: # negative index. index = tabs.index(tab) self.notebook.set_current_page(index) + uzbl = self.tabs[self.notebook.get_nth_page(index)] + self.window.set_title(title_format % uzbl.title) self.update_tablist() except IndexError: @@ -1001,8 +1034,7 @@ class UzblTabbed: ntabs = self.notebook.get_n_pages() tabn = (self.notebook.get_current_page() + step) % ntabs - self.notebook.set_current_page(tabn) - self.update_tablist() + self.goto_tab(tabn) def prev_tab(self, step=1): @@ -1015,8 +1047,7 @@ class UzblTabbed: ntabs = self.notebook.get_n_pages() tabn = self.notebook.get_current_page() - step while tabn < 0: tabn += ntabs - self.notebook.set_current_page(tabn) - self.update_tablist() + self.goto_tab(tabn) def close_tab(self, tabn=None): @@ -1067,6 +1098,8 @@ class UzblTabbed: self.quit() + for tab in self.notebook: + self.tabs[tab].title_changed(True) self.update_tablist() return True @@ -1106,102 +1139,68 @@ class UzblTabbed: def update_tablist(self, curpage=None): '''Upate tablist status bar.''' - show_tablist = config['show_tablist'] - show_gtk_tabs = config['show_gtk_tabs'] + if not config['show_tablist']: + return True + tab_titles = config['tab_titles'] - show_ellipsis = config['show_ellipsis'] multiline_tabs = config['multiline_tabs'] if multiline_tabs: multiline = [] - if not show_tablist and not show_gtk_tabs: - return True - tabs = self.tabs.keys() if curpage is None: curpage = self.notebook.get_current_page() - title_format = "%s - Uzbl Browser" - max_title_len = config['max_title_len'] - - if show_tablist: - pango = "" - normal = (config['tab_colours'], config['tab_text_colours']) - selected = (config['selected_tab'], config['selected_tab_text']) + pango = "" + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) - if tab_titles: - tab_format = " [ %d %s ] " - - else: - tab_format = " [ %d ] " + if tab_titles: + tab_format = " [ %d %s ] " - if show_gtk_tabs: - gtk_tab_format = "%d %s" + else: + tab_format = " [ %d ] " for index, tab in enumerate(self.notebook): if tab not in tabs: continue uzbl = self.tabs[tab] - if index == curpage: - self.window.set_title(title_format % uzbl.title) - - # Unicode heavy strings do not like being truncated/sliced so by - # re-encoding the string sliced of limbs are removed. - tabtitle = uzbl.title[:max_title_len + int(show_ellipsis)] - if type(tabtitle) != types.UnicodeType: - tabtitle = unicode(tabtitle, 'utf-8', 'ignore') - - tabtitle = tabtitle.encode('utf-8', 'ignore').strip() + style = colour_selector(index, curpage, uzbl) + (tabc, textc) = style - if show_ellipsis and len(tabtitle) != len(uzbl.title): - tabtitle += "\xe2\x80\xa6" + if multiline_tabs: + opango = pango - if show_gtk_tabs: if tab_titles: - self.notebook.set_tab_label_text(tab, - gtk_tab_format % (index, tabtitle)) + pango += tab_format % (tabc, index, textc, + escape(uzbl.tabtitle)) else: - self.notebook.set_tab_label_text(tab, str(index)) - - if show_tablist: - style = colour_selector(index, curpage, uzbl) - (tabc, textc) = style - - if multiline_tabs: - opango = pango - - if tab_titles: - pango += tab_format % (tabc, index, textc, - escape(tabtitle)) - - else: - pango += tab_format % (tabc, textc, index) + pango += tab_format % (tabc, textc, index) - self.tablist.set_markup(pango) - listwidth = self.tablist.get_layout().get_pixel_size()[0] - winwidth = self.window.get_size()[0] + self.tablist.set_markup(pango) + listwidth = self.tablist.get_layout().get_pixel_size()[0] + winwidth = self.window.get_size()[0] - if listwidth > (winwidth - 20): - multiline.append(opango) - pango = tab_format % (tabc, index, textc, - escape(tabtitle)) + if listwidth > (winwidth - 20): + multiline.append(opango) + pango = tab_format % (tabc, index, textc, + escape(uzbl.tabtitle)) - elif tab_titles: - pango += tab_format % (tabc, index, textc, - escape(tabtitle)) + elif tab_titles: + pango += tab_format % (tabc, index, textc, + escape(uzbl.tabtitle)) - else: - pango += tab_format % (tabc, textc, index) + else: + pango += tab_format % (tabc, textc, index) - if show_tablist: - if multiline_tabs: - multiline.append(pango) - self.tablist.set_markup(' '.join(multiline)) + if multiline_tabs: + multiline.append(pango) + self.tablist.set_markup(' '.join(multiline)) - else: - self.tablist.set_markup(pango) + else: + self.tablist.set_markup(pango) return True -- cgit v1.2.3 From 1e6d390fb965f0f5692d8a5c441fb12b01283941 Mon Sep 17 00:00:00 2001 From: Simon Lipp Date: Tue, 29 Dec 2009 15:40:09 +0100 Subject: uzbl-tabbed: add a tab_indexes option --- examples/data/uzbl/scripts/uzbl-tabbed | 56 +++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 84f1158..0252f5c 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -77,6 +77,7 @@ # # Tab title options: # tab_titles = 1 +# tab_indexes = 1 # new_tab_title = Loading # max_title_len = 50 # show_ellipsis = 1 @@ -202,6 +203,7 @@ config = { # Tab title options 'tab_titles': True, # Display tab titles (else only tab-nums) + 'tab_indexes': True, # Display tab nums (else only tab titles) 'new_tab_title': 'Loading', # New tab title 'max_title_len': 50, # Truncate title at n characters 'show_ellipsis': True, # Show ellipsis when truncating titles @@ -381,11 +383,9 @@ class UzblInstance: def got_socket(self, client): '''Uzbl instance is now connected''' - self._client = client - self.parent.tabs[self.tab] = self + self._client = client self.parent.config_uzbl(self) - if self._switch: tabid = self.parent.notebook.page_num(self.tab) self.parent.goto_tab(tabid) @@ -395,6 +395,7 @@ class UzblInstance: '''self.title has changed, update the tabs list''' tab_titles = config['tab_titles'] + tab_indexes = config['tab_indexes'] show_ellipsis = config['show_ellipsis'] max_title_len = config['max_title_len'] @@ -410,14 +411,20 @@ class UzblInstance: self.tabtitle += "\xe2\x80\xa6" gtk_tab_format = "%d %s" - tab_titles = config['tab_titles'] index = self.parent.notebook.page_num(self.tab) - if tab_titles: + if tab_titles and tab_indexes: self.parent.notebook.set_tab_label_text(self.tab, gtk_tab_format % (index, self.tabtitle)) + elif tab_titles: + self.parent.notebook.set_tab_label_text(self.tab, self.tabtitle) else: self.parent.notebook.set_tab_label_text(self.tab, str(index)) + # If instance is current tab, update window title + if index == self.parent.notebook.get_current_page(): + title_format = "%s - Uzbl Browser" + self.parent.window.set_title(title_format % self.title) + # Non-GTK tabs if not gtk_only: self.parent.update_tablist() @@ -426,13 +433,15 @@ class UzblInstance: def set(self, key, val): ''' Send the SET command to Uzbl ''' - self._client.send('set %s = %s') #TODO: escape chars ? + if self._client: + self._client.send('set %s = %s') #TODO: escape chars ? def exit(self): ''' Ask the Uzbl instance to close ''' - self._client.send('exit') + if self._client: + self._client.send('exit') def parse_command(self, cmd): @@ -463,6 +472,10 @@ class UzblInstance: elif var == "status_background": col = gtk.gdk.color_parse(config['status_background']) self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col) + elif var == "tab_titles" or var == "tab_indexes": + for tab in self.parent.notebook: + self.parent.tabs[tab].title_changed(True) + self.parent.update_tablist() else: config[var] = val @@ -975,6 +988,7 @@ class UzblTabbed: uzbl = UzblInstance(self, tab, name, uri, title, switch) SocketClient.instances_queue[name] = uzbl + self.tabs[tab] = uzbl def clean_slate(self): @@ -1143,6 +1157,7 @@ class UzblTabbed: return True tab_titles = config['tab_titles'] + tab_indexes = config['tab_indexes'] multiline_tabs = config['multiline_tabs'] if multiline_tabs: @@ -1156,15 +1171,17 @@ class UzblTabbed: normal = (config['tab_colours'], config['tab_text_colours']) selected = (config['selected_tab'], config['selected_tab_text']) - if tab_titles: - tab_format = " [ %d %s ] " - + if tab_titles and tab_indexes: + tab_format = " [ %(index)d %(title)s ] " + elif tab_titles: + tab_format = " [ %(title)s ] " else: - tab_format = " [ %d ] " + tab_format = " [ %(index)d ] " for index, tab in enumerate(self.notebook): if tab not in tabs: continue uzbl = self.tabs[tab] + title = escape(uzbl.tabtitle) style = colour_selector(index, curpage, uzbl) (tabc, textc) = style @@ -1172,12 +1189,7 @@ class UzblTabbed: if multiline_tabs: opango = pango - if tab_titles: - pango += tab_format % (tabc, index, textc, - escape(uzbl.tabtitle)) - - else: - pango += tab_format % (tabc, textc, index) + pango += tab_format % locals() self.tablist.set_markup(pango) listwidth = self.tablist.get_layout().get_pixel_size()[0] @@ -1185,15 +1197,9 @@ class UzblTabbed: if listwidth > (winwidth - 20): multiline.append(opango) - pango = tab_format % (tabc, index, textc, - escape(uzbl.tabtitle)) - - elif tab_titles: - pango += tab_format % (tabc, index, textc, - escape(uzbl.tabtitle)) - + pango = tab_format % locals() else: - pango += tab_format % (tabc, textc, index) + pango += tab_format % locals() if multiline_tabs: multiline.append(pango) -- cgit v1.2.3 From a5f014de5f76169a38ee67e46a0526e5d80a3433 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 2 Jan 2010 18:08:16 +0100 Subject: add notes into example config --- examples/config/uzbl/config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 4782a0d..3edb36c 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -48,7 +48,7 @@ set scheme_handler = sync_spawn @scripts_dir/scheme.py # Open in the same window. #set new_window = sh 'echo uri "$8" > $4' -# Open a link in a new window. +# Open a link in a new window. equivalent to default behavior set new_window = sh 'uzbl-browser -u $8' # --- Optional dynamic event handlers ---------------------------------------- @@ -254,7 +254,7 @@ set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' @cbind !dump = sh "echo dump_config > $4" # Reload config @cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" -# Uzbl Terminal +# Uzbl Terminal. TODO explain why this is useful @cbind t = sh 'xterm -e "socat unix-connect:$5 -"' #@cbind t = sh 'urxvt -e socat unix-connect:$5 -' -- cgit v1.2.3 From 30b7d1630e487f01f0f2ddc0fffca9d492213619 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 2 Jan 2010 18:21:25 +0100 Subject: authors file updates --- AUTHORS | 2 +- examples/data/uzbl/scripts/uzbl-tabbed | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/AUTHORS b/AUTHORS index b5d538f..6f540d0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,7 +54,7 @@ In alphabetical order: Přemysl Hrubý (anydot) - several C contributions and cleanups Robert Manea (robm) - C code all over the place Sergey Shepelev (temoto) - doc patch - Simon Lipp (sloonz) - various patches + Simon Lipp (sloonz) - various patches, EM contributions Sylvester Johansson (scj) - form filler script & different take on link follower Tassilo Horn (tsdh) - $VISUAL patch Thorsten Wilms - logo design diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed index 0252f5c..5d1a9f8 100755 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ b/examples/data/uzbl/scripts/uzbl-tabbed @@ -44,6 +44,9 @@ # # Devon Jones # Fifo command bring_to_front which brings the gtk window to focus. +# +# Simon Lipp (sloonz) +# Various # Dependencies: -- cgit v1.2.3 From 9dd1370d0b7cd876f004f7a822b0357039252184 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 2 Jan 2010 20:11:15 +0100 Subject: remove the 'uzbl' subdirectory in examples/*/, since the sandbox they are no longer needed + update paths everywhere + remove examples/config/enchant (also not needed since sandbox) + bugfix: set /home/dieter in sandbox --- .gitignore | 1 - Makefile | 18 +- examples/config/config | 376 ++++++ examples/config/cookies | 22 + examples/config/uzbl/config | 376 ------ examples/config/uzbl/cookies | 22 - examples/data/bookmarks | 4 + examples/data/forms/bbs.archlinux.org | 5 + examples/data/plugins/bind.py | 521 +++++++ examples/data/plugins/cmd_expand.py | 42 + examples/data/plugins/completion.py | 206 +++ examples/data/plugins/config.py | 97 ++ examples/data/plugins/keycmd.py | 571 ++++++++ examples/data/plugins/mode.py | 176 +++ examples/data/plugins/on_event.py | 107 ++ examples/data/plugins/plugin_template.py | 76 ++ examples/data/plugins/progress_bar.py | 159 +++ examples/data/scripts/cookies.sh | 154 +++ examples/data/scripts/download.sh | 22 + examples/data/scripts/extedit.js | 102 ++ examples/data/scripts/follow_Numbers.js | 228 ++++ examples/data/scripts/follow_Numbers_Strings.js | 212 +++ examples/data/scripts/formfiller.pl | 99 ++ examples/data/scripts/formfiller.sh | 62 + examples/data/scripts/hint.js | 26 + examples/data/scripts/history.sh | 5 + examples/data/scripts/insert_bookmark.sh | 16 + examples/data/scripts/instance-select-wmii.sh | 54 + examples/data/scripts/linkfollow.js | 269 ++++ examples/data/scripts/load_url_from_bookmarks.sh | 20 + examples/data/scripts/load_url_from_history.sh | 24 + examples/data/scripts/scheme.py | 24 + examples/data/scripts/scroll-percentage.js | 68 + examples/data/scripts/session.sh | 62 + examples/data/scripts/uzbl-cookie-daemon | 664 +++++++++ examples/data/scripts/uzbl-event-manager | 833 ++++++++++++ examples/data/scripts/uzbl-tabbed | 1417 ++++++++++++++++++++ examples/data/scripts/uzblcat | 12 + examples/data/style.css | 25 + examples/data/uzbl.png | Bin 0 -> 2185 bytes examples/data/uzbl/bookmarks | 4 - examples/data/uzbl/forms/bbs.archlinux.org | 5 - examples/data/uzbl/plugins/bind.py | 521 ------- examples/data/uzbl/plugins/cmd_expand.py | 42 - examples/data/uzbl/plugins/completion.py | 206 --- examples/data/uzbl/plugins/config.py | 97 -- examples/data/uzbl/plugins/keycmd.py | 571 -------- examples/data/uzbl/plugins/mode.py | 176 --- examples/data/uzbl/plugins/on_event.py | 107 -- examples/data/uzbl/plugins/plugin_template.py | 76 -- examples/data/uzbl/plugins/progress_bar.py | 159 --- examples/data/uzbl/scripts/cookies.sh | 154 --- examples/data/uzbl/scripts/download.sh | 22 - examples/data/uzbl/scripts/extedit.js | 102 -- examples/data/uzbl/scripts/follow_Numbers.js | 228 ---- .../data/uzbl/scripts/follow_Numbers_Strings.js | 212 --- examples/data/uzbl/scripts/formfiller.pl | 99 -- examples/data/uzbl/scripts/formfiller.sh | 62 - examples/data/uzbl/scripts/hint.js | 26 - examples/data/uzbl/scripts/history.sh | 5 - examples/data/uzbl/scripts/insert_bookmark.sh | 16 - examples/data/uzbl/scripts/instance-select-wmii.sh | 54 - examples/data/uzbl/scripts/linkfollow.js | 269 ---- .../data/uzbl/scripts/load_url_from_bookmarks.sh | 20 - .../data/uzbl/scripts/load_url_from_history.sh | 24 - examples/data/uzbl/scripts/scheme.py | 24 - examples/data/uzbl/scripts/scroll-percentage.js | 68 - examples/data/uzbl/scripts/session.sh | 62 - examples/data/uzbl/scripts/uzbl-cookie-daemon | 664 --------- examples/data/uzbl/scripts/uzbl-event-manager | 833 ------------ examples/data/uzbl/scripts/uzbl-tabbed | 1417 -------------------- examples/data/uzbl/scripts/uzblcat | 12 - examples/data/uzbl/style.css | 25 - examples/data/uzbl/uzbl.png | Bin 2185 -> 0 bytes sandbox/env.sh | 9 +- src/uzbl-browser | 2 +- 76 files changed, 6780 insertions(+), 6770 deletions(-) create mode 100644 examples/config/config create mode 100644 examples/config/cookies delete mode 100644 examples/config/uzbl/config delete mode 100644 examples/config/uzbl/cookies create mode 100644 examples/data/bookmarks create mode 100644 examples/data/forms/bbs.archlinux.org create mode 100644 examples/data/plugins/bind.py create mode 100644 examples/data/plugins/cmd_expand.py create mode 100644 examples/data/plugins/completion.py create mode 100644 examples/data/plugins/config.py create mode 100644 examples/data/plugins/keycmd.py create mode 100644 examples/data/plugins/mode.py create mode 100644 examples/data/plugins/on_event.py create mode 100644 examples/data/plugins/plugin_template.py create mode 100644 examples/data/plugins/progress_bar.py create mode 100755 examples/data/scripts/cookies.sh create mode 100755 examples/data/scripts/download.sh create mode 100644 examples/data/scripts/extedit.js create mode 100644 examples/data/scripts/follow_Numbers.js create mode 100644 examples/data/scripts/follow_Numbers_Strings.js create mode 100755 examples/data/scripts/formfiller.pl create mode 100755 examples/data/scripts/formfiller.sh create mode 100644 examples/data/scripts/hint.js create mode 100755 examples/data/scripts/history.sh create mode 100755 examples/data/scripts/insert_bookmark.sh create mode 100755 examples/data/scripts/instance-select-wmii.sh create mode 100644 examples/data/scripts/linkfollow.js create mode 100755 examples/data/scripts/load_url_from_bookmarks.sh create mode 100755 examples/data/scripts/load_url_from_history.sh create mode 100755 examples/data/scripts/scheme.py create mode 100644 examples/data/scripts/scroll-percentage.js create mode 100755 examples/data/scripts/session.sh create mode 100755 examples/data/scripts/uzbl-cookie-daemon create mode 100755 examples/data/scripts/uzbl-event-manager create mode 100755 examples/data/scripts/uzbl-tabbed create mode 100755 examples/data/scripts/uzblcat create mode 100644 examples/data/style.css create mode 100644 examples/data/uzbl.png delete mode 100644 examples/data/uzbl/bookmarks delete mode 100644 examples/data/uzbl/forms/bbs.archlinux.org delete mode 100644 examples/data/uzbl/plugins/bind.py delete mode 100644 examples/data/uzbl/plugins/cmd_expand.py delete mode 100644 examples/data/uzbl/plugins/completion.py delete mode 100644 examples/data/uzbl/plugins/config.py delete mode 100644 examples/data/uzbl/plugins/keycmd.py delete mode 100644 examples/data/uzbl/plugins/mode.py delete mode 100644 examples/data/uzbl/plugins/on_event.py delete mode 100644 examples/data/uzbl/plugins/plugin_template.py delete mode 100644 examples/data/uzbl/plugins/progress_bar.py delete mode 100755 examples/data/uzbl/scripts/cookies.sh delete mode 100755 examples/data/uzbl/scripts/download.sh delete mode 100644 examples/data/uzbl/scripts/extedit.js delete mode 100644 examples/data/uzbl/scripts/follow_Numbers.js delete mode 100644 examples/data/uzbl/scripts/follow_Numbers_Strings.js delete mode 100755 examples/data/uzbl/scripts/formfiller.pl delete mode 100755 examples/data/uzbl/scripts/formfiller.sh delete mode 100644 examples/data/uzbl/scripts/hint.js delete mode 100755 examples/data/uzbl/scripts/history.sh delete mode 100755 examples/data/uzbl/scripts/insert_bookmark.sh delete mode 100755 examples/data/uzbl/scripts/instance-select-wmii.sh delete mode 100644 examples/data/uzbl/scripts/linkfollow.js delete mode 100755 examples/data/uzbl/scripts/load_url_from_bookmarks.sh delete mode 100755 examples/data/uzbl/scripts/load_url_from_history.sh delete mode 100755 examples/data/uzbl/scripts/scheme.py delete mode 100644 examples/data/uzbl/scripts/scroll-percentage.js delete mode 100755 examples/data/uzbl/scripts/session.sh delete mode 100755 examples/data/uzbl/scripts/uzbl-cookie-daemon delete mode 100755 examples/data/uzbl/scripts/uzbl-event-manager delete mode 100755 examples/data/uzbl/scripts/uzbl-tabbed delete mode 100755 examples/data/uzbl/scripts/uzblcat delete mode 100644 examples/data/uzbl/style.css delete mode 100644 examples/data/uzbl/uzbl.png (limited to 'examples') diff --git a/.gitignore b/.gitignore index 803a154..078164f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ uzbl-core *.pyc *~ tags -examples/config/enchant diff --git a/Makefile b/Makefile index f48d1f0..626d21e 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ test-uzbl-browser: uzbl-browser test-uzbl-core-sandbox: uzbl-core make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-core + make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data source ./sandbox/env.sh && uzbl-core --uri http://www.uzbl.org --verbose make DESTDIR=./sandbox uninstall rm -rf ./sandbox/usr @@ -72,6 +73,7 @@ test-uzbl-core-sandbox: uzbl-core test-uzbl-browser-sandbox: uzbl-browser make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-core make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-uzbl-browser + make DESTDIR=./sandbox RUN_PREFIX=`pwd`/sandbox/usr/local install-example-data source ./sandbox/env.sh && uzbl-cookie-daemon restart -nv & source ./sandbox/env.sh && uzbl-event-manager restart -nav & source ./sandbox/env.sh && uzbl-browser --uri http://www.uzbl.org --verbose @@ -102,19 +104,27 @@ install-uzbl-core: all install -m755 uzbl-core $(INSTALLDIR)/bin/uzbl-core install -m644 AUTHORS $(INSTALLDIR)/share/uzbl/docs install -m644 README $(INSTALLDIR)/share/uzbl/docs - sed -i 's#^set prefix.*=.*#set prefix = $(RUN_PREFIX)#' $(INSTALLDIR)/share/uzbl/examples/config/uzbl/config + sed -i 's#^set prefix.*=.*#set prefix = $(RUN_PREFIX)#' $(INSTALLDIR)/share/uzbl/examples/config/config install-uzbl-browser: install -d $(INSTALLDIR)/bin install -m755 src/uzbl-browser $(INSTALLDIR)/bin/uzbl-browser - install -m755 examples/data/uzbl/scripts/uzbl-cookie-daemon $(INSTALLDIR)/bin/uzbl-cookie-daemon - install -m755 examples/data/uzbl/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager + install -m755 examples/data/scripts/uzbl-cookie-daemon $(INSTALLDIR)/bin/uzbl-cookie-daemon + install -m755 examples/data/scripts/uzbl-event-manager $(INSTALLDIR)/bin/uzbl-event-manager sed -i 's#^PREFIX=.*#PREFIX=$(RUN_PREFIX)#' $(INSTALLDIR)/bin/uzbl-browser sed -i "s#^PREFIX = .*#PREFIX = '$(RUN_PREFIX)'#" $(INSTALLDIR)/bin/uzbl-event-manager install-uzbl-tabbed: install -d $(INSTALLDIR)/bin - install -m755 examples/data/uzbl/scripts/uzbl-tabbed $(INSTALLDIR)/bin/uzbl-tabbed + install -m755 examples/data/scripts/uzbl-tabbed $(INSTALLDIR)/bin/uzbl-tabbed + +# you probably only want to do this manually when testing and/or to the sandbox. not meant for distributors +install-example-data: + install -d $(INSTALLDIR)/home/.config/uzbl + install -d $(INSTALLDIR)/home/.cache/uzbl + install -d $(INSTALLDIR)/home/.local/share/uzbl + cp -rp examples/config/* $(INSTALLDIR)/home/.config/uzbl/ + cp -rp examples/data/* $(INSTALLDIR)/home/.local/share/uzbl/ uninstall: rm -rf $(INSTALLDIR)/bin/uzbl-* diff --git a/examples/config/config b/examples/config/config new file mode 100644 index 0000000..eb17813 --- /dev/null +++ b/examples/config/config @@ -0,0 +1,376 @@ +# example uzbl config. +# all settings are optional. you can use uzbl without any config at all (but it won't do much) + +set prefix = /usr/local + +# === Shortcuts / Aliases =================================================== + +# Config related events (use the request function): +# request BIND = +set bind = request BIND +# request MODE_BIND = +set mode_bind = request MODE_BIND +# request MODE_CONFIG = +set mode_config = request MODE_CONFIG +# request ON_EVENT +set on_event = request ON_EVENT +# request PROGRESS_CONFIG = +set progress = request PROGRESS_CONFIG +# request MODMAP +set modmap = request MODMAP +# request IGNORE_KEY +set ignore_key = request IGNORE_KEY +# request MODKEY_ADDITION +set modkey_addition = request MODKEY_ADDITION + +# Action related events (use the event function): +# event TOGGLE_MODES ... +set toggle_modes = event TOGGLE_MODES + +set set_mode = set mode = +set set_status = set status_message = +set shell_cmd = sh -c + +# Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" +set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data:scripts + +# Javascipt helpers. +set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; + +# === Handlers =============================================================== + +# --- Hardcoded event handlers ----------------------------------------------- + +# These handlers can't be moved to the new event system yet as we don't +# support events that can wait for a response from a script. +set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket +set scheme_handler = sync_spawn @scripts_dir/scheme.py + +# Open in the same window. +#set new_window = sh 'echo uri "$8" > $4' +# Open a link in a new window. equivalent to default behavior +set new_window = sh 'uzbl-browser -u $8' + +# --- Optional dynamic event handlers ---------------------------------------- + +# Download handler +@on_event DOWNLOAD_REQUEST spawn @scripts_dir/download.sh %s \@proxy_url + +# Load start handler +@on_event LOAD_START @set_status wait + +# Load commit handlers +@on_event LOAD_COMMIT @set_status recv +@on_event LOAD_COMMIT script @scripts_dir/scroll-percentage.js +# Reset the keycmd on navigation +@on_event LOAD_COMMIT @set_mode + +# Load finish handlers +@on_event LOAD_FINISH @set_status done +@on_event LOAD_FINISH spawn @scripts_dir/history.sh + +# Generate a FORM_ACTIVE event if an editable +# element on the loaded site has initial focus +@on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} + +# Switch to insert mode if a (editable) html form is clicked +@on_event FORM_ACTIVE @set_mode insert +# Switch to command mode if anything else is clicked +@on_event ROOT_ACTIVE @set_mode command + +# Example CONFIG_CHANGED event handler +#@on_event CONFIG_CHANGED print Config changed: %1 = %2 + +# === Behaviour and appearance =============================================== + +set show_status = 1 +set status_top = 0 +set status_background = #303030 + +set modcmd_style = weight="bold" foreground="red" +set keycmd_style = weight="light" foreground="red" +set prompt_style = foreground="grey" +set cursor_style = underline="single" +set completion_style = foreground="green" +set hint_style = weight="bold" + +set mode_section = [\@[\@mode_indicator]\@] +set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd\@completion_list] +set progress_section = \@[\@progress_format]\@ +set scroll_section = \@[\@scroll_message]\@ +set uri_section = \@[\@uri]\@ +set name_section = \@[\@NAME]\@ +set status_section = \@status_message +set selected_section = \@[\@SELECTED_URI]\@ + +set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section + +set title_format_long = \@keycmd_prompt \@raw_modcmd \@raw_keycmd \@TITLE - Uzbl browser <\@NAME> \@SELECTED_URI + +# Progress bar config +@progress width = 8 +# %d = done, %p = pending %c = percent done, %i = int done, %s = spinner, +# %t = percent pending, %o = int pending, %r = sprite scroll +@progress format = [%d>%p]%c +@progress done = = +@progress pending = + +# Or ride those spinnas' +#@progress format = [%d%s%p] +#@progress spinner = -\\|/ +#@progress done = - +#@progress pending = + + +# === Core settings ========================================================== + +set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(+uname -o)@ @(+uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) +set fifo_dir = /tmp +set socket_dir = /tmp + + +# === Key modmapping and ignoring ============================================ + +#modmap +@modmap +@modmap +@modmap + +#modkey_addition +@modkey_addition +@modkey_addition + +#ignore_key +@ignore_key +@ignore_key + + +# === Mode bind aliases ====================================================== + +# Global binding alias (this is done automatically inside the bind plugin). +#set bind = @mode_bind global + +# Insert mode binding alias +set ibind = @mode_bind insert + +# Command mode binding alias +set cbind = @mode_bind command + +# Non-insert mode bindings alias (ebind for edit-bind). +set ebind = @mode_bind global,-insert + + +# === Global & keycmd editing binds ========================================== + +# Resets keycmd and returns to default mode. +@bind = @set_mode + +# Commands for editing and traversing the keycmd. +@ebind = event KEYCMD_EXEC_CURRENT +@ebind = event SET_CURSOR_POS +@ebind = event SET_CURSOR_POS -1 +@ebind = event SET_CURSOR_POS - +@ebind = event SET_CURSOR_POS + +@ebind = event KEYCMD_BACKSPACE +@ebind = event KEYCMD_DELETE +@ebind = event START_COMPLETION +# Readline-ish bindings. +@ebind w = event KEYCMD_STRIP_WORD +@ebind u = event SET_KEYCMD +@ebind a = event SET_CURSOR_POS 0 +@ebind e = event SET_CURSOR_POS -1 + +# Keycmd injection/append examples. +#@ebind su = event INJECT_KEYCMD \@uri +#@ebind st = event INJECT_KEYCMD \@title +#@ebind du = event APPEND_KEYCMD \@uri +#@ebind dt = event APPEND_KEYCMD \@title + + +# === Mouse bindings ========================================================= + +# Middle click +# if clicked on a link open the link in a new uzbl window +# otherwise open the selection in the current window +set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' +set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' +@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } + + +# === Keyboard bindings ====================================================== + +# With this command you can enter in any command at runtime when prefixed with +# a colon. +@cbind :_ = %s + +# --- Page movement binds --- +@cbind j = scroll vertical 20 +@cbind k = scroll vertical -20 +@cbind h = scroll horizontal -20 +@cbind l = scroll horizontal 20 +@cbind = scroll vertical -100% +@cbind = scroll vertical 100% +@cbind << = scroll vertical begin +@cbind >> = scroll vertical end +@cbind ^ = scroll horizontal begin +@cbind $ = scroll horizontal end +@cbind = scroll vertical end + +# --- Navigation binds --- +@cbind b = back +@cbind m = forward +@cbind S = stop +@cbind r = reload +@cbind R = reload_ign_cache + +# --- Zoom binds --- +@cbind + = zoom_in +@cbind - = zoom_out +@cbind T = toggle_zoom_type +@cbind 1 = set zoom_level 1.0 +@cbind 2 = set zoom_level 2.0 + +# --- Appearance binds --- +@cbind t = toggle_status + +# --- Page searching binds --- +@cbind /* = search %s +@cbind ?* = search_reverse %s +# Jump to next and previous items +@cbind n = search +@cbind N = search_reverse + +# --- Web searching binds --- +@cbind gg_ = uri http://www.google.com/search?q=\@\@ +@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=\@\@&go=Go +@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=\@\@&go=Go + +# --- Handy binds --- +# Set function shortcut +@cbind s__ = set %1 = %2 +# Exit binding +@cbind ZZ = exit +# Dump config to stdout +@cbind !dump = sh "echo dump_config > $4" +# Reload config +@cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" +# Uzbl Terminal. TODO explain why this is useful +@cbind t = sh 'xterm -e "socat unix-connect:$5 -"' +#@cbind t = sh 'urxvt -e socat unix-connect:$5 -' + +# --- Uri opening prompts --- +@cbind o_ = uri %s +# Or have it load the current uri into the keycmd for editing +@cbind O_ = uri %s + +# --- Mode setting binds --- +# Changing mode via set. +@cbind I = @set_mode insert +# Or toggle between modes by raising the toggle event. +set toggle_cmd_ins = @toggle_modes command insert +@cbind i = @toggle_cmd_ins +# And the global toggle bind. +@bind i = @toggle_cmd_ins + +# --- Hard-bound bookmarks --- +@cbind gh = uri http://www.uzbl.org + +# --- Yanking & pasting binds --- +@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); + +# Go the page from primary selection +@cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' +# Go to the page in clipboard +@cbind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' +# Start a new uzbl instance from the page in primary selection +@cbind 'p = sh 'exec uzbl-browser --uri $(xclip -o)' + +# --- Bookmark inserting binds --- +@cbind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' +# Or use a script to insert a bookmark. +@cbind B = spawn @scripts_dir/insert_bookmark.sh + +# --- Bookmark/history loading --- +@cbind U = spawn @scripts_dir/load_url_from_history.sh +@cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh + +# --- Link following (similar to vimperator and konqueror) --- +@cbind fl* = script @scripts_dir/follow_Numbers.js %s +# Or number with strings instead of numbers: +@cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s + +# --- Form filler binds --- +# this script allows you to configure (per domain) values to fill in form +# fields (eg login information) and to fill in these values automatically +set formfiller = spawn @scripts_dir/formfiller +@cbind za = @{formfiller}.sh +@cbind ze = @{formfiller}.sh edit +@cbind zn = @{formfiller}.sh new +@cbind zl = @{formfiller}.sh load +# Or the more advanced implementation using perl: (could not get this to run - Dieter) +@cbind LL = @{formfiller}.pl load +@cbind LN = @{formfiller}.pl new +@cbind LE = @{formfiller}.pl edit + +# --- External edit script configuration & binds --- +# Edit form input fields in an external editor (gvim, emacs, urxvt -e vim, ..) +set external_editor = gvim +#set external_editor = xterm -e vim +@cbind E = script @scripts_dir/extedit.js +# And add menu option. +menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js + +# --- Examples --- +# Example showing how to use uzbl's fifo to execute a command. +#@bind X1 = sh 'echo "set zoom_level = 1.0" > "$4"' +#@bind X2 = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' + +# Working with the javascript helper variable jsh. +#@bind X3 = @jsh alert(get('zoom_level')); +#@bind X4 = @jsh if(get('mode') == "insert") { alert("You are in insert mode") } else { alert(get('mode')+" is a silly mode.") }; + + +# === Context menu items ===================================================== + +# Default context menu +menu_add Google = set uri = http://google.com +menu_add Go Home = set uri = http://uzbl.org +menu_separator separator_1 +menu_add Quit uzbl = exit + +# Link context menu +menu_link_add Print Link = print \@SELECTED_URI + + +# === Mode configuration ===================================================== + +# Define some mode specific uzbl configurations. +set command = @mode_config command +set insert = @mode_config insert +set stack = @mode_config stack + +# Command mode config. +@command keycmd_style = foreground="red" +@command status_background = #202020 +@command mode_indicator = Cmd + +# Insert mode config. +@insert status_background = #303030 +@insert mode_indicator = Ins + +# Multi-stage-binding mode config. +@stack keycmd_events = 1 +@stack modcmd_updates = 1 +@stack forward_keys = 0 +@stack keycmd_style = foreground="red" +@stack prompt_style = foreground="#888" weight="light" +@stack status_background = #202020 +@stack mode_indicator = Bnd + +set default_mode = command + + +# === Post-load misc commands =============================================== + +# Set the "home" page. +set uri = uzbl.org/doesitwork/@COMMIT diff --git a/examples/config/cookies b/examples/config/cookies new file mode 100644 index 0000000..9b7374a --- /dev/null +++ b/examples/config/cookies @@ -0,0 +1,22 @@ +# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script. +# stick to this format. +# trusted -> always store what we get, send what we have (TODO: by default, or when requested?) +# deny -> deny storing + sending + +# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind... + + +TRUSTED +bbs.archlinux.org +archlinux.org +linux.com + + + + +DENY +www.icanhascheezburger.com + + + +# rest -> ask \ No newline at end of file diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config deleted file mode 100644 index 3edb36c..0000000 --- a/examples/config/uzbl/config +++ /dev/null @@ -1,376 +0,0 @@ -# example uzbl config. -# all settings are optional. you can use uzbl without any config at all (but it won't do much) - -set prefix = /usr/local - -# === Shortcuts / Aliases =================================================== - -# Config related events (use the request function): -# request BIND = -set bind = request BIND -# request MODE_BIND = -set mode_bind = request MODE_BIND -# request MODE_CONFIG = -set mode_config = request MODE_CONFIG -# request ON_EVENT -set on_event = request ON_EVENT -# request PROGRESS_CONFIG = -set progress = request PROGRESS_CONFIG -# request MODMAP -set modmap = request MODMAP -# request IGNORE_KEY -set ignore_key = request IGNORE_KEY -# request MODKEY_ADDITION -set modkey_addition = request MODKEY_ADDITION - -# Action related events (use the event function): -# event TOGGLE_MODES ... -set toggle_modes = event TOGGLE_MODES - -set set_mode = set mode = -set set_status = set status_message = -set shell_cmd = sh -c - -# Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" -set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts - -# Javascipt helpers. -set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; - -# === Handlers =============================================================== - -# --- Hardcoded event handlers ----------------------------------------------- - -# These handlers can't be moved to the new event system yet as we don't -# support events that can wait for a response from a script. -set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket -set scheme_handler = sync_spawn @scripts_dir/scheme.py - -# Open in the same window. -#set new_window = sh 'echo uri "$8" > $4' -# Open a link in a new window. equivalent to default behavior -set new_window = sh 'uzbl-browser -u $8' - -# --- Optional dynamic event handlers ---------------------------------------- - -# Download handler -@on_event DOWNLOAD_REQUEST spawn @scripts_dir/download.sh %s \@proxy_url - -# Load start handler -@on_event LOAD_START @set_status wait - -# Load commit handlers -@on_event LOAD_COMMIT @set_status recv -@on_event LOAD_COMMIT script @scripts_dir/scroll-percentage.js -# Reset the keycmd on navigation -@on_event LOAD_COMMIT @set_mode - -# Load finish handlers -@on_event LOAD_FINISH @set_status done -@on_event LOAD_FINISH spawn @scripts_dir/history.sh - -# Generate a FORM_ACTIVE event if an editable -# element on the loaded site has initial focus -@on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} - -# Switch to insert mode if a (editable) html form is clicked -@on_event FORM_ACTIVE @set_mode insert -# Switch to command mode if anything else is clicked -@on_event ROOT_ACTIVE @set_mode command - -# Example CONFIG_CHANGED event handler -#@on_event CONFIG_CHANGED print Config changed: %1 = %2 - -# === Behaviour and appearance =============================================== - -set show_status = 1 -set status_top = 0 -set status_background = #303030 - -set modcmd_style = weight="bold" foreground="red" -set keycmd_style = weight="light" foreground="red" -set prompt_style = foreground="grey" -set cursor_style = underline="single" -set completion_style = foreground="green" -set hint_style = weight="bold" - -set mode_section = [\@[\@mode_indicator]\@] -set keycmd_section = [\@[\@keycmd_prompt]\@\@modcmd\@keycmd\@completion_list] -set progress_section = \@[\@progress_format]\@ -set scroll_section = \@[\@scroll_message]\@ -set uri_section = \@[\@uri]\@ -set name_section = \@[\@NAME]\@ -set status_section = \@status_message -set selected_section = \@[\@SELECTED_URI]\@ - -set status_format = @mode_section @keycmd_section @progress_section @uri_section @name_section @status_section @scroll_section @selected_section - -set title_format_long = \@keycmd_prompt \@raw_modcmd \@raw_keycmd \@TITLE - Uzbl browser <\@NAME> \@SELECTED_URI - -# Progress bar config -@progress width = 8 -# %d = done, %p = pending %c = percent done, %i = int done, %s = spinner, -# %t = percent pending, %o = int pending, %r = sprite scroll -@progress format = [%d>%p]%c -@progress done = = -@progress pending = - -# Or ride those spinnas' -#@progress format = [%d%s%p] -#@progress spinner = -\\|/ -#@progress done = - -#@progress pending = - - -# === Core settings ========================================================== - -set useragent = Uzbl (Webkit @WEBKIT_MAJOR.@WEBKIT_MINOR.@WEBKIT_MICRO) (@(+uname -o)@ @(+uname -m)@ [@ARCH_UZBL]) (Commit @COMMIT) -set fifo_dir = /tmp -set socket_dir = /tmp - - -# === Key modmapping and ignoring ============================================ - -#modmap -@modmap -@modmap -@modmap - -#modkey_addition -@modkey_addition -@modkey_addition - -#ignore_key -@ignore_key -@ignore_key - - -# === Mode bind aliases ====================================================== - -# Global binding alias (this is done automatically inside the bind plugin). -#set bind = @mode_bind global - -# Insert mode binding alias -set ibind = @mode_bind insert - -# Command mode binding alias -set cbind = @mode_bind command - -# Non-insert mode bindings alias (ebind for edit-bind). -set ebind = @mode_bind global,-insert - - -# === Global & keycmd editing binds ========================================== - -# Resets keycmd and returns to default mode. -@bind = @set_mode - -# Commands for editing and traversing the keycmd. -@ebind = event KEYCMD_EXEC_CURRENT -@ebind = event SET_CURSOR_POS -@ebind = event SET_CURSOR_POS -1 -@ebind = event SET_CURSOR_POS - -@ebind = event SET_CURSOR_POS + -@ebind = event KEYCMD_BACKSPACE -@ebind = event KEYCMD_DELETE -@ebind = event START_COMPLETION -# Readline-ish bindings. -@ebind w = event KEYCMD_STRIP_WORD -@ebind u = event SET_KEYCMD -@ebind a = event SET_CURSOR_POS 0 -@ebind e = event SET_CURSOR_POS -1 - -# Keycmd injection/append examples. -#@ebind su = event INJECT_KEYCMD \@uri -#@ebind st = event INJECT_KEYCMD \@title -#@ebind du = event APPEND_KEYCMD \@uri -#@ebind dt = event APPEND_KEYCMD \@title - - -# === Mouse bindings ========================================================= - -# Middle click -# if clicked on a link open the link in a new uzbl window -# otherwise open the selection in the current window -set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' -set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' -@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } - - -# === Keyboard bindings ====================================================== - -# With this command you can enter in any command at runtime when prefixed with -# a colon. -@cbind :_ = %s - -# --- Page movement binds --- -@cbind j = scroll vertical 20 -@cbind k = scroll vertical -20 -@cbind h = scroll horizontal -20 -@cbind l = scroll horizontal 20 -@cbind = scroll vertical -100% -@cbind = scroll vertical 100% -@cbind << = scroll vertical begin -@cbind >> = scroll vertical end -@cbind ^ = scroll horizontal begin -@cbind $ = scroll horizontal end -@cbind = scroll vertical end - -# --- Navigation binds --- -@cbind b = back -@cbind m = forward -@cbind S = stop -@cbind r = reload -@cbind R = reload_ign_cache - -# --- Zoom binds --- -@cbind + = zoom_in -@cbind - = zoom_out -@cbind T = toggle_zoom_type -@cbind 1 = set zoom_level 1.0 -@cbind 2 = set zoom_level 2.0 - -# --- Appearance binds --- -@cbind t = toggle_status - -# --- Page searching binds --- -@cbind /* = search %s -@cbind ?* = search_reverse %s -# Jump to next and previous items -@cbind n = search -@cbind N = search_reverse - -# --- Web searching binds --- -@cbind gg_ = uri http://www.google.com/search?q=\@\@ -@cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=\@\@&go=Go -@cbind \\wiki_ = uri http://en.wikipedia.org/w/index.php?title=Special:Search&search=\@\@&go=Go - -# --- Handy binds --- -# Set function shortcut -@cbind s__ = set %1 = %2 -# Exit binding -@cbind ZZ = exit -# Dump config to stdout -@cbind !dump = sh "echo dump_config > $4" -# Reload config -@cbind !reload = sh "sed '/^# === Post-load misc commands/,$d' $1 > $4" -# Uzbl Terminal. TODO explain why this is useful -@cbind t = sh 'xterm -e "socat unix-connect:$5 -"' -#@cbind t = sh 'urxvt -e socat unix-connect:$5 -' - -# --- Uri opening prompts --- -@cbind o_ = uri %s -# Or have it load the current uri into the keycmd for editing -@cbind O_ = uri %s - -# --- Mode setting binds --- -# Changing mode via set. -@cbind I = @set_mode insert -# Or toggle between modes by raising the toggle event. -set toggle_cmd_ins = @toggle_modes command insert -@cbind i = @toggle_cmd_ins -# And the global toggle bind. -@bind i = @toggle_cmd_ins - -# --- Hard-bound bookmarks --- -@cbind gh = uri http://www.uzbl.org - -# --- Yanking & pasting binds --- -@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); - -# Go the page from primary selection -@cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' -# Go to the page in clipboard -@cbind P = sh 'echo "uri `xclip -selection clipboard -o`" > $4' -# Start a new uzbl instance from the page in primary selection -@cbind 'p = sh 'exec uzbl-browser --uri $(xclip -o)' - -# --- Bookmark inserting binds --- -@cbind b_ = sh 'echo -e "$6 %s" >> $XDG_DATA_HOME/uzbl/bookmarks' -# Or use a script to insert a bookmark. -@cbind B = spawn @scripts_dir/insert_bookmark.sh - -# --- Bookmark/history loading --- -@cbind U = spawn @scripts_dir/load_url_from_history.sh -@cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh - -# --- Link following (similar to vimperator and konqueror) --- -@cbind fl* = script @scripts_dir/follow_Numbers.js %s -# Or number with strings instead of numbers: -@cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s - -# --- Form filler binds --- -# this script allows you to configure (per domain) values to fill in form -# fields (eg login information) and to fill in these values automatically -set formfiller = spawn @scripts_dir/formfiller -@cbind za = @{formfiller}.sh -@cbind ze = @{formfiller}.sh edit -@cbind zn = @{formfiller}.sh new -@cbind zl = @{formfiller}.sh load -# Or the more advanced implementation using perl: (could not get this to run - Dieter) -@cbind LL = @{formfiller}.pl load -@cbind LN = @{formfiller}.pl new -@cbind LE = @{formfiller}.pl edit - -# --- External edit script configuration & binds --- -# Edit form input fields in an external editor (gvim, emacs, urxvt -e vim, ..) -set external_editor = gvim -#set external_editor = xterm -e vim -@cbind E = script @scripts_dir/extedit.js -# And add menu option. -menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js - -# --- Examples --- -# Example showing how to use uzbl's fifo to execute a command. -#@bind X1 = sh 'echo "set zoom_level = 1.0" > "$4"' -#@bind X2 = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' - -# Working with the javascript helper variable jsh. -#@bind X3 = @jsh alert(get('zoom_level')); -#@bind X4 = @jsh if(get('mode') == "insert") { alert("You are in insert mode") } else { alert(get('mode')+" is a silly mode.") }; - - -# === Context menu items ===================================================== - -# Default context menu -menu_add Google = set uri = http://google.com -menu_add Go Home = set uri = http://uzbl.org -menu_separator separator_1 -menu_add Quit uzbl = exit - -# Link context menu -menu_link_add Print Link = print \@SELECTED_URI - - -# === Mode configuration ===================================================== - -# Define some mode specific uzbl configurations. -set command = @mode_config command -set insert = @mode_config insert -set stack = @mode_config stack - -# Command mode config. -@command keycmd_style = foreground="red" -@command status_background = #202020 -@command mode_indicator = Cmd - -# Insert mode config. -@insert status_background = #303030 -@insert mode_indicator = Ins - -# Multi-stage-binding mode config. -@stack keycmd_events = 1 -@stack modcmd_updates = 1 -@stack forward_keys = 0 -@stack keycmd_style = foreground="red" -@stack prompt_style = foreground="#888" weight="light" -@stack status_background = #202020 -@stack mode_indicator = Bnd - -set default_mode = command - - -# === Post-load misc commands =============================================== - -# Set the "home" page. -set uri = uzbl.org/doesitwork/@COMMIT diff --git a/examples/config/uzbl/cookies b/examples/config/uzbl/cookies deleted file mode 100644 index 9b7374a..0000000 --- a/examples/config/uzbl/cookies +++ /dev/null @@ -1,22 +0,0 @@ -# This file demonstrates how one *could* manage his cookies. this file is used by the example cookie handler script. -# stick to this format. -# trusted -> always store what we get, send what we have (TODO: by default, or when requested?) -# deny -> deny storing + sending - -# if you don't like to edit this file manually, you could even write a script that adds/removes entries using sed, and call the script from uzbl with a keybind... - - -TRUSTED -bbs.archlinux.org -archlinux.org -linux.com - - - - -DENY -www.icanhascheezburger.com - - - -# rest -> ask \ No newline at end of file diff --git a/examples/data/bookmarks b/examples/data/bookmarks new file mode 100644 index 0000000..13fcd48 --- /dev/null +++ b/examples/data/bookmarks @@ -0,0 +1,4 @@ +http://www.archlinux.org linux arch +http://www.uzbl.org uzbl browser +http://dieter.plaetinck.be uzbl +http://www.icanhascheezburger.com lolcats fun diff --git a/examples/data/forms/bbs.archlinux.org b/examples/data/forms/bbs.archlinux.org new file mode 100644 index 0000000..73c1539 --- /dev/null +++ b/examples/data/forms/bbs.archlinux.org @@ -0,0 +1,5 @@ +form_sent: +redirect_url: +req_username: +req_password: +login: diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py new file mode 100644 index 0000000..9e09337 --- /dev/null +++ b/examples/data/plugins/bind.py @@ -0,0 +1,521 @@ +'''Plugin provides support for binds in uzbl. + +For example: + event BIND ZZ = exit -> bind('ZZ', 'exit') + event BIND o _ = uri %s -> bind('o _', 'uri %s') + event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") + +And it is also possible to execute a function on activation: + bind('DD', myhandler) +''' + +import sys +import re +import pprint + +# Hold the bind dicts for each uzbl instance. +UZBLS = {} + +# Commonly used regular expressions. +MOD_START = re.compile('^<([A-Z][A-Za-z0-9-_]*)>').match +# Matches , <'x':y>, <:'y'>, , <'x'!y>, ... +PROMPTS = '<(\"[^\"]*\"|\'[^\']*\'|[^:!>]*)(:|!)(\"[^\"]*\"|\'[^\']*\'|[^>]*)>' +FIND_PROMPTS = re.compile(PROMPTS).split +VALID_MODE = re.compile('^(-|)[A-Za-z0-9][A-Za-z0-9_]*$').match + +# For accessing a bind glob stack. +ON_EXEC, HAS_ARGS, MOD_CMD, GLOB, MORE = range(5) + + +# Custom errors. +class ArgumentError(Exception): pass + + +class Bindlet(object): + '''Per-instance bind status/state tracker.''' + + def __init__(self, uzbl): + self.binds = {'global': {}} + self.uzbl = uzbl + self.depth = 0 + self.args = [] + self.last_mode = None + self.after_cmds = None + self.stack_binds = [] + + # A subset of the global mode binds containing non-stack and modkey + # activiated binds for use in the stack mode. + self.globals = [] + + + def __getitem__(self, key): + return self.get_binds(key) + + + def reset(self): + '''Reset the tracker state and return to last mode.''' + + self.depth = 0 + self.args = [] + self.after_cmds = None + self.stack_binds = [] + + if self.last_mode: + mode, self.last_mode = self.last_mode, None + self.uzbl.set_mode(mode) + + self.uzbl.set('keycmd_prompt') + + + def stack(self, bind, args, depth): + '''Enter or add new bind in the next stack level.''' + + if self.depth != depth: + if bind not in self.stack_binds: + self.stack_binds.append(bind) + + return + + current_mode = self.uzbl.get_mode() + if current_mode != 'stack': + self.last_mode = current_mode + self.uzbl.set_mode('stack') + + self.stack_binds = [bind,] + self.args += args + self.depth += 1 + self.after_cmds = bind.prompts[depth] + + + def after(self): + '''If a stack was triggered then set the prompt and default value.''' + + if self.after_cmds is None: + return + + (prompt, is_cmd, set), self.after_cmds = self.after_cmds, None + + self.uzbl.clear_keycmd() + if prompt: + self.uzbl.set('keycmd_prompt', prompt) + + if set and is_cmd: + self.uzbl.send(set) + + elif set and not is_cmd: + self.uzbl.send('event SET_KEYCMD %s' % set) + + + def get_binds(self, mode=None): + '''Return the mode binds + globals. If we are stacked then return + the filtered stack list and modkey & non-stack globals.''' + + if mode is None: + mode = self.uzbl.get_mode() + + if not mode: + mode = 'global' + + if self.depth: + return self.stack_binds + self.globals + + globals = self.binds['global'] + if mode not in self.binds or mode == 'global': + return filter(None, globals.values()) + + binds = dict(globals.items() + self.binds[mode].items()) + return filter(None, binds.values()) + + + def add_bind(self, mode, glob, bind=None): + '''Insert (or override) a bind into the mode bind dict.''' + + if mode not in self.binds: + self.binds[mode] = {glob: bind} + return + + binds = self.binds[mode] + binds[glob] = bind + + if mode == 'global': + # Regen the global-globals list. + self.globals = [] + for bind in binds.values(): + if bind is not None and bind.is_global: + self.globals.append(bind) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = Bindlet(uzbl) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_bindlet(uzbl): + '''Return the bind tracklet for the given uzbl instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def ismodbind(glob): + '''Return True if the glob specifies a modbind.''' + + return bool(MOD_START(glob)) + + +def split_glob(glob): + '''Take a string of the form "cmd _" and return a list of the + modkeys in the glob and the command.''' + + mods = set() + while True: + match = MOD_START(glob) + if not match: + break + + end = match.span()[1] + mods.add(glob[:end]) + glob = glob[end:] + + 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. + counter = [0,] + + def __init__(self, glob, handler, *args, **kargs): + self.is_callable = callable(handler) + self._repr_cache = None + + if not glob: + raise ArgumentError('glob cannot be blank') + + if self.is_callable: + self.function = handler + self.args = args + self.kargs = kargs + + elif kargs: + raise ArgumentError('cannot supply kargs for uzbl commands') + + elif hasattr(handler, '__iter__'): + self.commands = handler + + else: + self.commands = [handler,] + list(args) + + self.glob = glob + + # Assign unique id. + self.counter[0] += 1 + self.bid = self.counter[0] + + self.split = split = FIND_PROMPTS(glob) + self.prompts = [] + for (prompt, cmd, set) in zip(split[1::4], split[2::4], split[3::4]): + prompt, set = map(unquote, [prompt, set]) + cmd = True if cmd == '!' else False + if prompt and prompt[-1] != ":": + prompt = "%s:" % prompt + + self.prompts.append((prompt, cmd, set)) + + # Check that there is nothing like: fl** + for glob in split[:-1:4]: + if glob.endswith('*'): + msg = "token '*' not at the end of a prompt bind: %r" % split + raise SyntaxError(msg) + + # Check that there is nothing like: fl_ + for glob in split[4::4]: + if not glob: + msg = 'found null segment after first prompt: %r' % split + raise SyntaxError(msg) + + stack = [] + for (index, glob) in enumerate(reversed(split[::4])): + # Is the binding a MODCMD or KEYCMD: + mod_cmd = ismodbind(glob) + + # Do we execute on UPDATES or EXEC events? + on_exec = True if glob[-1] in ['!', '_'] else False + + # Does the command take arguments? + has_args = True if glob[-1] in ['*', '_'] else False + + glob = glob[:-1] if has_args or on_exec else glob + mods, glob = split_glob(glob) + stack.append((on_exec, has_args, mods, glob, index)) + + self.stack = list(reversed(stack)) + self.is_global = (len(self.stack) == 1 and self.stack[0][MOD_CMD]) + + + def __getitem__(self, depth): + '''Get bind info at a depth.''' + + if self.is_global: + return self.stack[0] + + return self.stack[depth] + + + def __repr__(self): + if self._repr_cache: + return self._repr_cache + + args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] + + if self.is_callable: + args.append('function=%r' % self.function) + if self.args: + args.append('args=%r' % self.args) + + if self.kargs: + args.append('kargs=%r' % self.kargs) + + else: + cmdlen = len(self.commands) + cmds = self.commands[0] if cmdlen == 1 else self.commands + args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) + + self._repr_cache = '' % ', '.join(args) + return self._repr_cache + + +def exec_bind(uzbl, bind, *args, **kargs): + '''Execute bind objects.''' + + uzbl.event("EXEC_BIND", bind, args, kargs) + + if bind.is_callable: + args += bind.args + kargs = dict(bind.kargs.items()+kargs.items()) + bind.function(uzbl, *args, **kargs) + return + + if kargs: + raise ArgumentError('cannot supply kargs for uzbl commands') + + commands = [] + cmd_expand = uzbl.cmd_expand + for cmd in bind.commands: + cmd = cmd_expand(cmd, args) + uzbl.send(cmd) + + +def mode_bind(uzbl, modes, glob, handler=None, *args, **kargs): + '''Add a mode bind.''' + + bindlet = get_bindlet(uzbl) + + if not hasattr(modes, '__iter__'): + modes = unicode(modes).split(',') + + # Sort and filter binds. + modes = filter(None, map(unicode.strip, modes)) + + if callable(handler) or (handler is not None and handler.strip()): + bind = Bind(glob, handler, *args, **kargs) + + else: + bind = None + + for mode in modes: + if not VALID_MODE(mode): + raise NameError('invalid mode name: %r' % mode) + + for mode in modes: + if mode[0] == '-': + mode, bind = mode[1:], None + + bindlet.add_bind(mode, glob, bind) + uzbl.event('ADDED_MODE_BIND', mode, glob, bind) + + +def bind(uzbl, glob, handler, *args, **kargs): + '''Legacy bind function.''' + + mode_bind(uzbl, 'global', glob, handler, *args, **kargs) + + +def parse_mode_bind(uzbl, args): + '''Parser for the MODE_BIND event. + + Example events: + MODE_BIND = + MODE_BIND command o_ = uri %s + MODE_BIND insert,command = ... + MODE_BIND global ... = ... + MODE_BIND global,-insert ... = ... + ''' + + if not args: + raise ArgumentError('missing bind arguments') + + split = map(unicode.strip, args.split(' ', 1)) + if len(split) != 2: + raise ArgumentError('missing mode or bind section: %r' % args) + + modes, args = split[0].split(','), split[1] + split = map(unicode.strip, args.split('=', 1)) + if len(split) != 2: + raise ArgumentError('missing delimiter in bind section: %r' % args) + + glob, command = split + mode_bind(uzbl, modes, glob, command) + + +def parse_bind(uzbl, args): + '''Legacy parsing of the BIND event and conversion to the new format. + + Example events: + request BIND = + request BIND o_ = uri %s + request BIND = ... + request BIND ... = ... + ''' + + parse_mode_bind(uzbl, "global %s" % args) + + +def mode_changed(uzbl, mode): + '''Clear the stack on all non-stack mode changes.''' + + if mode != 'stack': + get_bindlet(uzbl).reset() + + +def match_and_exec(uzbl, bind, depth, keylet, bindlet): + + (on_exec, has_args, mod_cmd, glob, more) = bind[depth] + cmd = keylet.modcmd if mod_cmd else keylet.keycmd + + if mod_cmd and keylet.held != mod_cmd: + return False + + if has_args: + if not cmd.startswith(glob): + return False + + args = [cmd[len(glob):],] + + elif cmd != glob: + return False + + else: + args = [] + + if bind.is_global or (not more and depth == 0): + exec_bind(uzbl, bind, *args) + if not has_args: + uzbl.clear_current() + + return True + + elif more: + bindlet.stack(bind, args, depth) + return False + + args = bindlet.args + args + exec_bind(uzbl, bind, *args) + uzbl.set_mode() + if not has_args: + bindlet.reset() + uzbl.clear_current() + + return True + + +def keycmd_update(uzbl, keylet): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): + t = bind[depth] + if t[MOD_CMD] or t[ON_EXEC]: + continue + + if match_and_exec(uzbl, bind, depth, keylet, bindlet): + return + + bindlet.after() + + +def keycmd_exec(uzbl, keylet): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): + t = bind[depth] + if t[MOD_CMD] or not t[ON_EXEC]: + continue + + if match_and_exec(uzbl, bind, depth, keylet, bindlet): + return uzbl.clear_keycmd() + + bindlet.after() + + +def modcmd_update(uzbl, keylet): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): + t = bind[depth] + if not t[MOD_CMD] or t[ON_EXEC]: + continue + + if match_and_exec(uzbl, bind, depth, keylet, bindlet): + return + + bindlet.after() + + +def modcmd_exec(uzbl, keylet): + bindlet = get_bindlet(uzbl) + depth = bindlet.depth + for bind in bindlet.get_binds(): + t = bind[depth] + if not t[MOD_CMD] or not t[ON_EXEC]: + continue + + if match_and_exec(uzbl, bind, depth, keylet, bindlet): + return uzbl.clear_modcmd() + + bindlet.after() + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'BIND': parse_bind, + 'KEYCMD_EXEC': keycmd_exec, + 'KEYCMD_UPDATE': keycmd_update, + 'MODCMD_EXEC': modcmd_exec, + 'MODCMD_UPDATE': modcmd_update, + 'MODE_BIND': parse_mode_bind, + 'MODE_CHANGED': mode_changed, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'bind': bind, + 'mode_bind': mode_bind, + 'get_bindlet': get_bindlet, + }) diff --git a/examples/data/plugins/cmd_expand.py b/examples/data/plugins/cmd_expand.py new file mode 100644 index 0000000..3f6ae2b --- /dev/null +++ b/examples/data/plugins/cmd_expand.py @@ -0,0 +1,42 @@ +def escape(str): + for (level, char) in [(3, '\\'), (2, "'"), (2, '"'), (1, '@')]: + str = str.replace(char, (level * '\\') + char) + + return str + + +def cmd_expand(uzbl, cmd, args): + '''Exports a function that provides the following + expansions in any uzbl command string: + + %s = replace('%s', ' '.join(args)) + %r = replace('%r', "'%s'" % escaped(' '.join(args))) + %1 = replace('%1', arg[0]) + %2 = replace('%2', arg[1]) + %n = replace('%n', arg[n-1]) + ''' + + # Ensure (1) all string representable and (2) correct string encoding. + args = map(unicode, args) + + # Direct string replace. + if '%s' in cmd: + cmd = cmd.replace('%s', ' '.join(args)) + + # Escaped and quoted string replace. + if '%r' in cmd: + cmd = cmd.replace('%r', "'%s'" % escape(' '.join(args))) + + # Arg index string replace. + for (index, arg) in enumerate(args): + index += 1 + if '%%%d' % index in cmd: + cmd = cmd.replace('%%%d' % index, unicode(arg)) + + return cmd + + +def init(uzbl): + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export('cmd_expand', cmd_expand) diff --git a/examples/data/plugins/completion.py b/examples/data/plugins/completion.py new file mode 100644 index 0000000..8cea203 --- /dev/null +++ b/examples/data/plugins/completion.py @@ -0,0 +1,206 @@ +'''Keycmd completion.''' + +# A list of functions this plugin exports to be used via uzbl object. +__export__ = ['start_completion', 'get_completion_dict'] + +import re + +# Holds the per-instance completion dicts. +UZBLS = {} + +# Completion level +NONE, ONCE, LIST, COMPLETE = range(4) + +# Default instance dict. +DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} + +# The reverse keyword finding re. +FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall + +# Formats +LIST_FORMAT = " %s " +ITEM_FORMAT = "%s%s" + + +def escape(str): + return str.replace("@", "\@") + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + # Make sure the config keys for all possible completions are known. + uzbl.send('dump_config_as_events') + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_completion_dict(uzbl): + '''Get data stored for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_incomplete_keyword(uzbl): + '''Gets the segment of the keycmd leading up to the cursor position and + uses a regular expression to search backwards finding parially completed + keywords or @variables. Returns a null string if the correct completion + conditions aren't met.''' + + keylet = uzbl.get_keylet() + left_segment = keylet.keycmd[:keylet.cursor] + partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() + if partial.startswith('set '): + return ('@%s' % partial[4:].lstrip(), True) + + return (partial, False) + + +def stop_completion(uzbl, *args): + '''Stop command completion and return the level to NONE.''' + + d = get_completion_dict(uzbl) + d['level'] = NONE + uzbl.set('completion_list') + + +def complete_completion(uzbl, partial, hint, set_completion=False): + '''Inject the remaining porition of the keyword into the keycmd then stop + the completioning.''' + + if set_completion: + remainder = "%s = " % hint[len(partial):] + + else: + remainder = "%s " % hint[len(partial):] + + uzbl.inject_keycmd(remainder) + stop_completion(uzbl) + + +def partial_completion(uzbl, partial, hint): + '''Inject a common portion of the hints into the keycmd.''' + + remainder = hint[len(partial):] + uzbl.inject_keycmd(remainder) + + +def update_completion_list(uzbl, *args): + '''Checks if the user still has a partially completed keyword under his + cursor then update the completion hints list.''' + + partial = get_incomplete_keyword(uzbl)[0] + if not partial: + return stop_completion(uzbl) + + d = get_completion_dict(uzbl) + if d['level'] < LIST: + return + + hints = [h for h in d['completions'] if h.startswith(partial)] + if not hints: + return uzbl.set('completion_list') + + j = len(partial) + l = [ITEM_FORMAT % (escape(h[:j]), h[j:]) for h in sorted(hints)] + uzbl.set('completion_list', LIST_FORMAT % ' '.join(l)) + + +def start_completion(uzbl, *args): + + d = get_completion_dict(uzbl) + if d['lock']: + return + + (partial, set_completion) = get_incomplete_keyword(uzbl) + if not partial: + return stop_completion(uzbl) + + if d['level'] < COMPLETE: + d['level'] += 1 + + hints = [h for h in d['completions'] if h.startswith(partial)] + if not hints: + return + + elif len(hints) == 1: + d['lock'] = True + complete_completion(uzbl, partial, hints[0], set_completion) + d['lock'] = False + return + + elif partial in hints and d['level'] == COMPLETE: + d['lock'] = True + complete_completion(uzbl, partial, partial, set_completion) + d['lock'] = False + return + + smalllen, smallest = sorted([(len(h), h) for h in hints])[0] + common = '' + for i in range(len(partial), smalllen): + char, same = smallest[i], True + for hint in hints: + if hint[i] != char: + same = False + break + + if not same: + break + + common += char + + if common: + d['lock'] = True + partial_completion(uzbl, partial, partial+common) + d['lock'] = False + + update_completion_list(uzbl) + + +def add_builtins(uzbl, args): + '''Pump the space delimited list of builtin commands into the + builtin list.''' + + completions = get_completion_dict(uzbl)['completions'] + builtins = filter(None, map(unicode.strip, args.split(" "))) + for builtin in builtins: + if builtin not in completions: + completions.append(builtin) + + +def add_config_key(uzbl, key, value): + '''Listen on the CONFIG_CHANGED event and add config keys to the variable + list for @var like expansion support.''' + + completions = get_completion_dict(uzbl)['completions'] + key = "@%s" % key + if key not in completions: + completions.append(key) + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'BUILTINS': add_builtins, + 'CONFIG_CHANGED': add_config_key, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEYCMD_CLEARED': stop_completion, + 'KEYCMD_EXEC': stop_completion, + 'KEYCMD_UPDATE': update_completion_list, + 'START_COMPLETION': start_completion, + 'STOP_COMPLETION': stop_completion, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_completion_dict': get_completion_dict, + 'start_completion': start_completion, + }) diff --git a/examples/data/plugins/config.py b/examples/data/plugins/config.py new file mode 100644 index 0000000..4a848a3 --- /dev/null +++ b/examples/data/plugins/config.py @@ -0,0 +1,97 @@ +import re +import types + +__export__ = ['set', 'get_config'] + +VALIDKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match +TYPECONVERT = {'int': int, 'float': float, 'str': unicode} + +UZBLS = {} + + +def escape(value): + '''A real escaping function may be required.''' + + return unicode(value) + + +def set(uzbl, key, value='', config=None, force=False): + '''Sends a: "set key = value" command to the uzbl instance. If force is + False then only send a set command if the values aren't equal.''' + + if type(value) == types.BooleanType: + value = int(value) + + else: + value = unicode(value) + + if not VALIDKEY(key): + raise KeyError("%r" % key) + + value = escape(value) + if '\n' in value: + value = value.replace("\n", "\\n") + + if not force: + if config is None: + config = get_config(uzbl) + + if key in config and config[key] == value: + return + + uzbl.send('set %s = %s' % (key, value)) + + +class ConfigDict(dict): + def __init__(self, uzbl): + self._uzbl = uzbl + + def __setitem__(self, key, value): + '''Makes "config[key] = value" a wrapper for the set function.''' + + set(self._uzbl, key, value, config=self) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = ConfigDict(uzbl) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del uzbl + + +def get_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def variable_set(uzbl, args): + config = get_config(uzbl) + + key, type, value = list(args.split(' ', 2) + ['',])[:3] + old = config[key] if key in config else None + value = TYPECONVERT[type](value) + + dict.__setitem__(config, key, value) + + if old != value: + uzbl.event("CONFIG_CHANGED", key, value) + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'VARIABLE_SET': variable_set, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_config': get_config, + 'set': set, + }) diff --git a/examples/data/plugins/keycmd.py b/examples/data/plugins/keycmd.py new file mode 100644 index 0000000..c119077 --- /dev/null +++ b/examples/data/plugins/keycmd.py @@ -0,0 +1,571 @@ +import re + +# Hold the keylets. +UZBLS = {} + +# Keycmd format which includes the markup for the cursor. +KEYCMD_FORMAT = "%s%s%s" +MODCMD_FORMAT = " %s " + + +def escape(str): + for char in ['\\', '@']: + str = str.replace(char, '\\'+char) + + return str + + +def uzbl_escape(str): + return "@[%s]@" % escape(str) if str else '' + + +class Keylet(object): + '''Small per-instance object that tracks all the keys held and characters + typed.''' + + def __init__(self): + # Modcmd tracking + self.held = set() + self.ignored = set() + self.modcmd = '' + self.is_modcmd = False + + # Keycmd tracking + self.keycmd = '' + self.cursor = 0 + + self.modmaps = {} + self.ignores = {} + self.additions = {} + + # Keylet string repr cache. + self._repr_cache = None + + + def get_keycmd(self): + '''Get the keycmd-part of the keylet.''' + + return self.keycmd + + + def get_modcmd(self): + '''Get the modcmd-part of the keylet.''' + + if not self.is_modcmd: + return '' + + return ''.join(self.held) + self.modcmd + + + def modmap_key(self, key): + '''Make some obscure names for some keys friendlier.''' + + if key in self.modmaps: + return self.modmaps[key] + + elif key.endswith('_L') or key.endswith('_R'): + # Remove left-right discrimination and try again. + return self.modmap_key(key[:-2]) + + else: + return key + + + def find_addition(self, modkey): + '''Key has just been pressed, check if this key + the held list + results in a modkey addition. Return that addition and remove all + modkeys that created it.''' + + # Intersection of (held list + modkey) and additions. + added = (self.held | set([modkey])) & set(self.additions.keys()) + for key in added: + if key == modkey or modkey in self.additions[key]: + self.held -= self.additions[key] + return key + + # Held list + ignored list + modkey. + modkeys = self.held | self.ignored | set([modkey]) + for (key, value) in self.additions.items(): + if modkeys.issuperset(value): + self.held -= value + return key + + return modkey + + + def key_ignored(self, key): + '''Check if the given key is ignored by any ignore rules.''' + + for (glob, match) in self.ignores.items(): + if match(key): + return True + + return False + + + def __repr__(self): + '''Return a string representation of the keylet.''' + + if self._repr_cache: + return self._repr_cache + + l = [] + if self.is_modcmd: + l.append('modcmd=%r' % self.get_modcmd()) + + elif self.held: + l.append('held=%r' % ''.join(sorted(self.held))) + + if self.keycmd: + l.append('keycmd=%r' % self.get_keycmd()) + + self._repr_cache = '' % ', '.join(l) + return self._repr_cache + + +def add_modmap(uzbl, key, map): + '''Add modmaps. + + Examples: + set modmap = request MODMAP + @modmap + @modmap + ... + + Then: + @bind = + @bind x = + ... + + ''' + + assert len(key) + modmaps = get_keylet(uzbl).modmaps + + if key[0] == "<" and key[-1] == ">": + key = key[1:-1] + + modmaps[key] = map + uzbl.event("NEW_MODMAP", key, map) + + +def modmap_parse(uzbl, map): + '''Parse a modmap definiton.''' + + split = [s.strip() for s in map.split(' ') if s.split()] + + if not split or len(split) > 2: + raise Exception('Invalid modmap arugments: %r' % map) + + add_modmap(uzbl, *split) + + +def add_key_ignore(uzbl, glob): + '''Add an ignore definition. + + Examples: + set ignore_key = request IGNORE_KEY + @ignore_key + @ignore_key + ... + ''' + + assert len(glob) > 1 + ignores = get_keylet(uzbl).ignores + + glob = "<%s>" % glob.strip("<> ") + restr = glob.replace('*', '[^\s]*') + match = re.compile(restr).match + + ignores[glob] = match + uzbl.event('NEW_KEY_IGNORE', glob) + + +def add_modkey_addition(uzbl, modkeys, result): + '''Add a modkey addition definition. + + Examples: + set mod_addition = request MODKEY_ADDITION + @mod_addition + @mod_addition + @mod_addition + ... + + Then: + @bind = + @bind o = + ... + ''' + + additions = get_keylet(uzbl).additions + modkeys = set(modkeys) + + assert len(modkeys) and result and result not in modkeys + + for (existing_result, existing_modkeys) in additions.items(): + if existing_result != result: + assert modkeys != existing_modkeys + + additions[result] = modkeys + uzbl.event('NEW_MODKEY_ADDITION', modkeys, result) + + +def modkey_addition_parse(uzbl, modkeys): + '''Parse modkey addition definition.''' + + keys = filter(None, map(unicode.strip, modkeys.split(" "))) + keys = ['<%s>' % key.strip("<>") for key in keys if key.strip("<>")] + + assert len(keys) > 1 + add_modkey_addition(uzbl, keys[:-1], keys[-1]) + + +def add_instance(uzbl, *args): + '''Create the Keylet object for this uzbl instance.''' + + UZBLS[uzbl] = Keylet() + + +def del_instance(uzbl, *args): + '''Delete the Keylet object for this uzbl instance.''' + + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_keylet(uzbl): + '''Return the corresponding keylet for this uzbl instance.''' + + # Startup events are not correctly captured and sent over the uzbl socket + # yet so this line is needed because the INSTANCE_START event is lost. + if uzbl not in UZBLS: + add_instance(uzbl) + + keylet = UZBLS[uzbl] + keylet._repr_cache = False + return keylet + + +def clear_keycmd(uzbl): + '''Clear the keycmd for this uzbl instance.''' + + k = get_keylet(uzbl) + k.keycmd = '' + k.cursor = 0 + k._repr_cache = False + uzbl.set('keycmd') + uzbl.set('raw_keycmd') + uzbl.event('KEYCMD_CLEARED') + + +def clear_modcmd(uzbl, clear_held=False): + '''Clear the modcmd for this uzbl instance.''' + + k = get_keylet(uzbl) + k.modcmd = '' + k.is_modcmd = False + k._repr_cache = False + if clear_held: + k.ignored = set() + k.held = set() + + uzbl.set('modcmd') + uzbl.set('raw_modcmd') + uzbl.event('MODCMD_CLEARED') + + +def clear_current(uzbl): + '''Clear the modcmd if is_modcmd else clear keycmd.''' + + k = get_keylet(uzbl) + if k.is_modcmd: + clear_modcmd(uzbl) + + else: + clear_keycmd(uzbl) + + +def focus_changed(uzbl, *args): + '''Focus to the uzbl instance has now been lost which means all currently + held keys in the held list will not get a KEY_RELEASE event so clear the + entire held list.''' + + clear_modcmd(uzbl, clear_held=True) + + +def update_event(uzbl, k, execute=True): + '''Raise keycmd & modcmd update events.''' + + config = uzbl.get_config() + keycmd, modcmd = k.get_keycmd(), k.get_modcmd() + + if k.is_modcmd: + uzbl.event('MODCMD_UPDATE', k) + + else: + uzbl.event('KEYCMD_UPDATE', k) + + if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': + new_modcmd = k.get_modcmd() + if not new_modcmd: + uzbl.set('modcmd', config=config) + uzbl.set('raw_modcmd', config=config) + + elif new_modcmd == modcmd: + uzbl.set('raw_modcmd', escape(modcmd), config=config) + uzbl.set('modcmd', MODCMD_FORMAT % uzbl_escape(modcmd), + config=config) + + if 'keycmd_events' in config and config['keycmd_events'] != '1': + return + + new_keycmd = k.get_keycmd() + if not new_keycmd: + uzbl.set('keycmd', config=config) + uzbl.set('raw_keycmd', config=config) + + elif new_keycmd == keycmd: + # Generate the pango markup for the cursor in the keycmd. + curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' + chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] + value = KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks)) + uzbl.set('keycmd', value, config=config) + uzbl.set('raw_keycmd', escape(keycmd), config=config) + + +def inject_str(str, index, inj): + '''Inject a string into string at at given index.''' + + return "%s%s%s" % (str[:index], inj, str[index:]) + + +def get_keylet_and_key(uzbl, key, add=True): + '''Return the keylet and apply any transformations to the key as defined + by the modmapping or modkey addition rules. Return None if the key is + ignored.''' + + keylet = get_keylet(uzbl) + key = keylet.modmap_key(key) + if len(key) == 1: + return (keylet, key) + + modkey = "<%s>" % key.strip("<>") + + if keylet.key_ignored(modkey): + if add: + keylet.ignored.add(modkey) + + elif modkey in keylet.ignored: + keylet.ignored.remove(modkey) + + modkey = keylet.find_addition(modkey) + + if keylet.key_ignored(modkey): + return (keylet, None) + + return (keylet, modkey) + + +def key_press(uzbl, key): + '''Handle KEY_PRESS events. Things done by this function include: + + 1. Ignore all shift key presses (shift can be detected by capital chars) + 3. In non-modcmd mode: + a. append char to keycmd + 4. If not in modcmd mode and a modkey was pressed set modcmd mode. + 5. If in modcmd mode the pressed key is added to the held keys list. + 6. Keycmd is updated and events raised if anything is changed.''' + + (k, key) = get_keylet_and_key(uzbl, key.strip()) + if not key: + return + + if key.lower() == '' and not k.held and k.keycmd: + k.keycmd = inject_str(k.keycmd, k.cursor, ' ') + k.cursor += 1 + + elif not k.held and len(key) == 1: + config = uzbl.get_config() + if 'keycmd_events' in config and config['keycmd_events'] != '1': + k.keycmd = '' + k.cursor = 0 + uzbl.set('keycmd', config=config) + uzbl.set('raw_keycmd', config=config) + return + + k.keycmd = inject_str(k.keycmd, k.cursor, key) + k.cursor += 1 + + elif len(key) > 1: + k.is_modcmd = True + if key not in k.held: + k.held.add(key) + + else: + k.is_modcmd = True + k.modcmd += key + + update_event(uzbl, k) + + +def key_release(uzbl, key): + '''Respond to KEY_RELEASE event. Things done by this function include: + + 1. Remove the key from the keylet held list. + 2. If in a mod-command then raise a MODCMD_EXEC. + 3. Check if any modkey is held, if so set modcmd mode. + 4. Update the keycmd uzbl variable if anything changed.''' + + (k, key) = get_keylet_and_key(uzbl, key.strip(), add=False) + + if key in k.held: + if k.is_modcmd: + uzbl.event('MODCMD_EXEC', k) + + k.held.remove(key) + clear_modcmd(uzbl) + + +def set_keycmd(uzbl, keycmd): + '''Allow setting of the keycmd externally.''' + + k = get_keylet(uzbl) + k.keycmd = keycmd + k._repr_cache = None + k.cursor = len(keycmd) + update_event(uzbl, k, False) + + +def inject_keycmd(uzbl, keycmd): + '''Allow injecting of a string into the keycmd at the cursor position.''' + + k = get_keylet(uzbl) + k.keycmd = inject_str(k.keycmd, k.cursor, keycmd) + k._repr_cache = None + k.cursor += len(keycmd) + update_event(uzbl, k, False) + + +def append_keycmd(uzbl, keycmd): + '''Allow appening of a string to the keycmd.''' + + k = get_keylet(uzbl) + k.keycmd += keycmd + k._repr_cache = None + k.cursor = len(k.keycmd) + update_event(uzbl, k, False) + + +def keycmd_strip_word(uzbl, sep): + ''' Removes the last word from the keycmd, similar to readline ^W ''' + + sep = sep or ' ' + k = get_keylet(uzbl) + if not k.keycmd: + return + + head, tail = k.keycmd[:k.cursor].rstrip(sep), k.keycmd[k.cursor:] + rfind = head.rfind(sep) + head = head[:rfind] if rfind + 1 else '' + k.keycmd = head + tail + k.cursor = len(head) + update_event(uzbl, k, False) + + +def keycmd_backspace(uzbl, *args): + '''Removes the character at the cursor position in the keycmd.''' + + k = get_keylet(uzbl) + if not k.keycmd: + return + + k.keycmd = k.keycmd[:k.cursor-1] + k.keycmd[k.cursor:] + k.cursor -= 1 + update_event(uzbl, k, False) + + +def keycmd_delete(uzbl, *args): + '''Removes the character after the cursor position in the keycmd.''' + + k = get_keylet(uzbl) + if not k.keycmd: + return + + k.keycmd = k.keycmd[:k.cursor] + k.keycmd[k.cursor+1:] + update_event(uzbl, k, False) + + +def keycmd_exec_current(uzbl, *args): + '''Raise a KEYCMD_EXEC with the current keylet and then clear the + keycmd.''' + + k = get_keylet(uzbl) + uzbl.event('KEYCMD_EXEC', k) + clear_keycmd(uzbl) + + +def set_cursor_pos(uzbl, index): + '''Allow setting of the cursor position externally. Supports negative + indexing and relative stepping with '+' and '-'.''' + + k = get_keylet(uzbl) + if index == '-': + cursor = k.cursor - 1 + + elif index == '+': + cursor = k.cursor + 1 + + else: + cursor = int(index.strip()) + if cursor < 0: + cursor = len(k.keycmd) + cursor + 1 + + if cursor < 0: + cursor = 0 + + if cursor > len(k.keycmd): + cursor = len(k.keycmd) + + k.cursor = cursor + update_event(uzbl, k, False) + + +def init(uzbl): + '''Connect handlers to uzbl events.''' + + # Event handling hooks. + uzbl.connect_dict({ + 'APPEND_KEYCMD': append_keycmd, + 'FOCUS_GAINED': focus_changed, + 'FOCUS_LOST': focus_changed, + 'IGNORE_KEY': add_key_ignore, + 'INJECT_KEYCMD': inject_keycmd, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'KEYCMD_BACKSPACE': keycmd_backspace, + 'KEYCMD_DELETE': keycmd_delete, + 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, + 'KEYCMD_STRIP_WORD': keycmd_strip_word, + 'KEY_PRESS': key_press, + 'KEY_RELEASE': key_release, + 'MODKEY_ADDITION': modkey_addition_parse, + 'MODMAP': modmap_parse, + 'SET_CURSOR_POS': set_cursor_pos, + 'SET_KEYCMD': set_keycmd, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'add_key_ignore': add_key_ignore, + 'add_modkey_addition': add_modkey_addition, + 'add_modmap': add_modmap, + 'append_keycmd': append_keycmd, + 'clear_current': clear_current, + 'clear_keycmd': clear_keycmd, + 'clear_modcmd': clear_modcmd, + 'get_keylet': get_keylet, + 'inject_keycmd': inject_keycmd, + 'set_cursor_pos': set_cursor_pos, + 'set_keycmd': set_keycmd, + }) diff --git a/examples/data/plugins/mode.py b/examples/data/plugins/mode.py new file mode 100644 index 0000000..54d865a --- /dev/null +++ b/examples/data/plugins/mode.py @@ -0,0 +1,176 @@ +import sys +import re + +__export__ = ['set_mode', 'get_mode', 'set_mode_config', 'get_mode_config'] + +UZBLS = {} + +DEFAULTS = { + 'mode': '', + 'modes': { + 'insert': { + 'forward_keys': True, + 'keycmd_events': False, + 'modcmd_updates': False, + 'mode_indicator': 'I'}, + 'command': { + 'forward_keys': False, + 'keycmd_events': True, + 'modcmd_updates': True, + 'mode_indicator': 'C'}}} + +FINDSPACES = re.compile("\s+") +VALID_KEY = re.compile("^[\w_]+$").match + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_mode_dict(uzbl): + '''Return the mode dict for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def get_mode_config(uzbl, mode): + '''Return the mode config for a given mode.''' + + modes = get_mode_dict(uzbl)['modes'] + if mode not in modes: + modes[mode] = {} + + return modes[mode] + + +def get_mode(uzbl): + return get_mode_dict(uzbl)['mode'] + + +def mode_changed(uzbl, mode): + '''The mode has just been changed, now set the per-mode config.''' + + if get_mode(uzbl) != mode: + return + + config = uzbl.get_config() + mode_config = get_mode_config(uzbl, mode) + for (key, value) in mode_config.items(): + uzbl.set(key, value, config=config) + + if 'mode_indicator' not in mode_config: + config['mode_indicator'] = mode + + uzbl.clear_keycmd() + uzbl.clear_modcmd() + + +def set_mode(uzbl, mode=None): + '''Set the mode and raise the MODE_CHANGED event if the mode has changed. + Fallback on the default mode if no mode argument was given and the default + mode is not null.''' + + config = uzbl.get_config() + mode_dict = get_mode_dict(uzbl) + if mode is None: + mode_dict['mode'] = '' + if 'default_mode' in config: + mode = config['default_mode'] + + else: + mode = 'command' + + if not VALID_KEY(mode): + raise KeyError("invalid mode name: %r" % mode) + + if 'mode' not in config or config['mode'] != mode: + config['mode'] = mode + + elif mode_dict['mode'] != mode: + mode_dict['mode'] = mode + uzbl.event("MODE_CHANGED", mode) + + +def config_changed(uzbl, key, value): + '''Check for mode related config changes.''' + + value = None if not value else value + if key == 'default_mode': + if not get_mode(uzbl): + set_mode(uzbl, value) + + elif key == 'mode': + set_mode(uzbl, value) + + +def set_mode_config(uzbl, mode, key, value): + '''Set mode specific configs. If the mode being modified is the current + mode then apply the changes on the go.''' + + assert VALID_KEY(mode) and VALID_KEY(key) + + mode_config = get_mode_config(uzbl, mode) + mode_config[key] = value + + if get_mode(uzbl) == mode: + uzbl.set(key, value) + + +def mode_config(uzbl, args): + '''Parse mode config events.''' + + split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1)) + if len(split) != 2: + raise SyntaxError('invalid mode config syntax: %r' % args) + + mode, set = split + split = map(unicode.strip, set.split('=', 1)) + if len(split) != 2: + raise SyntaxError('invalid set syntax: %r' % args) + + key, value = split + set_mode_config(uzbl, mode, key, value) + + +def toggle_modes(uzbl, modes): + '''Toggle or cycle between or through a list of modes.''' + + assert len(modes.strip()) + + modelist = filter(None, map(unicode.strip, modes.split(' '))) + mode = get_mode(uzbl) + + index = 0 + if mode in modelist: + index = (modelist.index(mode)+1) % len(modelist) + + set_mode(uzbl, modelist[index]) + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'CONFIG_CHANGED': config_changed, + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'MODE_CHANGED': mode_changed, + 'MODE_CONFIG': mode_config, + 'TOGGLE_MODES': toggle_modes, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_mode': get_mode, + 'get_mode_config': get_mode_config, + 'set_mode': set_mode, + 'set_mode_config': set_mode_config, + }) diff --git a/examples/data/plugins/on_event.py b/examples/data/plugins/on_event.py new file mode 100644 index 0000000..b9c504a --- /dev/null +++ b/examples/data/plugins/on_event.py @@ -0,0 +1,107 @@ +'''Plugin provides arbitrary binding of uzbl events to uzbl commands. + +Formatting options: + %s = space separated string of the arguments + %r = escaped and quoted version of %s + %1 = argument 1 + %2 = argument 2 + %n = argument n + +Usage: + request ON_EVENT LINK_HOVER set selected_uri = $1 + --> LINK_HOVER http://uzbl.org/ + <-- set selected_uri = http://uzbl.org/ + + request ON_EVENT CONFIG_CHANGED print Config changed: %1 = %2 + --> CONFIG_CHANGED selected_uri http://uzbl.org/ + <-- print Config changed: selected_uri = http://uzbl.org/ +''' + +import sys +import re + +__export__ = ['get_on_events', 'on_event'] + +UZBLS = {} + + +def error(msg): + sys.stderr.write('on_event plugin: error: %s\n' % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = {} + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_on_events(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def event_handler(uzbl, *args, **kargs): + '''This function handles all the events being watched by various + on_event definitions and responds accordingly.''' + + events = get_on_events(uzbl) + event = kargs['on_event'] + if event not in events: + return + + commands = events[event] + cmd_expand = uzbl.cmd_expand + for cmd in commands: + cmd = cmd_expand(cmd, args) + uzbl.send(cmd) + + +def on_event(uzbl, event, cmd): + '''Add a new event to watch and respond to.''' + + event = event.upper() + events = get_on_events(uzbl) + if event not in events: + uzbl.connect(event, event_handler, on_event=event) + events[event] = [] + + cmds = events[event] + if cmd not in cmds: + cmds.append(cmd) + + +def parse_on_event(uzbl, args): + '''Parse ON_EVENT events and pass them to the on_event function. + + Syntax: "event ON_EVENT commands".''' + + if not args: + return error("missing on_event arguments") + + split = args.split(' ', 1) + if len(split) != 2: + return error("invalid ON_EVENT syntax: %r" % args) + + event, cmd = split + on_event(uzbl, event, cmd) + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'ON_EVENT': parse_on_event, + }) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.export_dict({ + 'get_on_events': get_on_events, + 'on_event': on_event, + }) diff --git a/examples/data/plugins/plugin_template.py b/examples/data/plugins/plugin_template.py new file mode 100644 index 0000000..565a999 --- /dev/null +++ b/examples/data/plugins/plugin_template.py @@ -0,0 +1,76 @@ +'''Plugin template.''' + +# Holds the per-instance data dict. +UZBLS = {} + +# The default instance dict. +DEFAULTS = {} + + +def add_instance(uzbl, *args): + '''Add a new instance with default config options.''' + + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + '''Delete data stored for an instance.''' + + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_myplugin_dict(uzbl): + '''Get data stored for an instance.''' + + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def myplugin_function(uzbl, *args, **kargs): + '''Custom plugin function which is exported by the __export__ list at the + top of the file for use by other functions/callbacks.''' + + print "My plugin function arguments:", args, kargs + + # Get the per-instance data object. + data = get_myplugin_dict(uzbl) + + # Function logic goes here. + + +def myplugin_event_parser(uzbl, args): + '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' + + print "Got MYPLUGIN_EVENT with arguments: %r" % args + + # Parsing logic goes here. + + +def init(uzbl): + '''The main function of the plugin which is used to attach all the event + hooks that are going to be used throughout the plugins life. This function + is called each time a UzblInstance() object is created in the event + manager.''' + + # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event + # handler stack: + uzbl.connect_dict({ + # event name function + 'INSTANCE_START': add_instance, + 'INSTANCE_EXIT': del_instance, + 'MYPLUGIN_EVENT': myplugin_event_parser, + }) + + # Or connect a handler to an event manually and supply additional optional + # arguments: + #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) + + # Function exports to the uzbl object, `function(uzbl, *args, ..)` + # becomes `uzbl.function(*args, ..)`. + uzbl.connect_dict({ + # external name function + 'myplugin_function': myplugin_function, + }) diff --git a/examples/data/plugins/progress_bar.py b/examples/data/plugins/progress_bar.py new file mode 100644 index 0000000..89ba175 --- /dev/null +++ b/examples/data/plugins/progress_bar.py @@ -0,0 +1,159 @@ +import sys + +UZBLS = {} + +DEFAULTS = {'width': 8, + 'done': '=', + 'pending': '.', + 'format': '[%d%a%p]%c', + 'spinner': '-\\|/', + 'sprites': 'loading', + 'updates': 0, + 'progress': 100} + + +def error(msg): + sys.stderr.write("progress_bar plugin: error: %s\n" % msg) + + +def add_instance(uzbl, *args): + UZBLS[uzbl] = dict(DEFAULTS) + + +def del_instance(uzbl, *args): + if uzbl in UZBLS: + del UZBLS[uzbl] + + +def get_progress_config(uzbl): + if uzbl not in UZBLS: + add_instance(uzbl) + + return UZBLS[uzbl] + + +def update_progress(uzbl, prog=None): + '''Updates the progress_format variable on LOAD_PROGRESS update. + + The current substitution options are: + %d = done char * done + %p = pending char * remaining + %c = percent done + %i = int done + %s = -\|/ spinner + %t = percent pending + %o = int pending + %r = sprites + ''' + + prog_config = get_progress_config(uzbl) + config = uzbl.get_config() + + if prog is None: + prog = prog_config['progress'] + + else: + prog = int(prog) + prog_config['progress'] = prog + + prog_config['updates'] += 1 + format = prog_config['format'] + width = prog_config['width'] + + # Inflate the done and pending bars to stop the progress bar + # jumping around. + if '%c' in format or '%i' in format: + count = format.count('%c') + format.count('%i') + width += (3-len(str(prog))) * count + + if '%t' in format or '%o' in format: + count = format.count('%t') + format.count('%o') + width += (3-len(str(100-prog))) * count + + done = int(((prog/100.0)*width)+0.5) + pending = width - done + + if '%d' in format: + format = format.replace('%d', prog_config['done']*done) + + if '%p' in format: + format = format.replace('%p', prog_config['pending']*pending) + + if '%c' in format: + format = format.replace('%c', '%d%%' % prog) + + if '%i' in format: + format = format.replace('%i', '%d' % prog) + + if '%t' in format: + format = format.replace('%t', '%d%%' % (100-prog)) + + if '%o' in format: + format = format.replace('%o', '%d' % (100-prog)) + + if '%s' in format: + spinner = prog_config['spinner'] + spin = '-' if not spinner else spinner + index = 0 if prog == 100 else prog_config['updates'] % len(spin) + char = '\\\\' if spin[index] == '\\' else spin[index] + format = format.replace('%s', char) + + if '%r' in format: + sprites = prog_config['sprites'] + sprites = '-' if not sprites else sprites + index = int(((prog/100.0)*len(sprites))+0.5)-1 + sprite = '\\\\' if sprites[index] == '\\' else sprites[index] + format = format.replace('%r', sprite) + + if 'progress_format' not in config or config['progress_format'] != format: + config['progress_format'] = format + + +def progress_config(uzbl, args): + '''Parse PROGRESS_CONFIG events from the uzbl instance. + + Syntax: event PROGRESS_CONFIG = + ''' + + split = args.split('=', 1) + if len(split) != 2: + return error("invalid syntax: %r" % args) + + key, value = map(unicode.strip, split) + prog_config = get_progress_config(uzbl) + + if key not in prog_config: + return error("key error: %r" % args) + + if type(prog_config[key]) == type(1): + try: + value = int(value) + + except: + return error("invalid type: %r" % args) + + elif not value: + value = ' ' + + prog_config[key] = value + update_progress(uzbl) + + +def reset_progress(uzbl, args): + '''Reset the spinner counter, reset the progress int and re-draw the + progress bar on LOAD_COMMIT.''' + + prog_dict = get_progress_config(uzbl) + prog_dict['updates'] = prog_dict['progress'] = 0 + update_progress(uzbl) + + +def init(uzbl): + # Event handling hooks. + uzbl.connect_dict({ + 'INSTANCE_EXIT': del_instance, + 'INSTANCE_START': add_instance, + 'LOAD_COMMIT': reset_progress, + 'LOAD_PROGRESS': update_progress, + 'PROGRESS_CONFIG': progress_config, + }) diff --git a/examples/data/scripts/cookies.sh b/examples/data/scripts/cookies.sh new file mode 100755 index 0000000..ee2ce51 --- /dev/null +++ b/examples/data/scripts/cookies.sh @@ -0,0 +1,154 @@ +#!/bin/sh + +set -n; + +# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! + +# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as uzbl-cookie-daemon +# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) +# This is one textfile with entries like this: +# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 +# domain alow-read-other-subdomains path http-required expiration name value +# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) +# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" +# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( +# TODO: different cookie paths per config (eg per group of uzbl instances) + +# TODO: correct implementation. +# see http://curl.haxx.se/rfc/cookie_spec.html +# http://en.wikipedia.org/wiki/HTTP_cookie + +# TODO : check expires= before sending. +# write sample script that cleans up cookies dir based on expires attribute. +# TODO: check uri against domain attribute. and path also. +# implement secure attribute. +# support blocking or not for 3rd parties +# http://kb.mozillazine.org/Cookies.txt +# don't always append cookies, sometimes we need to overwrite + +cookie_config=${XDG_CONFIG_HOME:-${HOME}/.config}/uzbl/cookies +[ "x$cookie_config" = x ] && exit 1 +[ -d "${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/" ] &&\ +cookie_data=${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/cookies.txt || exit 1 + +notifier= +#notifier=notify-send +#notify_wrapper () { +# echo "$@" >> $HOME/cookielog +#} +#notifier=notifier_wrapper + +# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. +# it's primarily used for debugging +notifier= +which zenity &>/dev/null || exit 2 + +# Example cookie: +# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net + +# uri=$6 +# uri=${uri/http:\/\/} # strip 'http://' part +# host=${uri/\/*/} +action=$8 # GET/PUT +shift +host=$9 +shift +path=$9 +shift +cookie=$9 + +field_domain=$host +field_path=$path +field_name= +field_value= +field_exp='end_session' + +notify() { + [ -n "$notifier" ] && $notifier "$@" +} + + +# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET +parse_cookie() { + IFS=$';' + first_pair=1 + for pair in $cookie + do + if [ "x$first_pair" = x1 ] + then + field_name=${pair%%=*} + field_value=${pair#*=} + first_pair=0 + else + echo "$pair" | read -r pair #strip leading/trailing wite space + key=${pair%%=*} + val=${pair#*=} + [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` + # TODO: domain + [ "$key" == path ] && field_path=$val + fi + done + unset IFS +} + +# match cookies in cookies.txt against hostname and path +get_cookie() { + path_esc=${path//\//\\/} + search="^[^\t]*$host\t[^\t]*\t$path_esc" + cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` + if [ -z "$cookie" ] + then + notify "Get_cookie: search: $search in $cookie_data -> no result" + false + else + notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" + echo "$cookie" | \ + read domain alow_read_other_subdomains path http_required expiration name \ + value; + cookie="$name=$value" + true + fi +} + +save_cookie() { + if parse_cookie + then + data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" + notify "save_cookie: adding $data to $cookie_data" + echo -e "$data" >> $cookie_data + else + notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" + fi +} + +[ "x$action" = xPUT ] && save_cookie +[ "x$action" = xGET ] && get_cookie && echo "$cookie" + +exit + + +# TODO: implement this later. +# $1 = section (TRUSTED or DENY) +# $2 =url +match() { + sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" +} + +fetch_cookie() { + cookie=`cat $cookie_data` +} + +store_cookie() { + echo $cookie > $cookie_data +} + +if match TRUSTED $host +then + [ "x$action" = xPUT ] && store_cookie $host + [ "x$action" = xGET ] && fetch_cookie && echo "$cookie" +elif ! match DENY $host +then + [ "x$action" = xPUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host + [ "x$action" = xGET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie +fi +exit 0 diff --git a/examples/data/scripts/download.sh b/examples/data/scripts/download.sh new file mode 100755 index 0000000..1c7d039 --- /dev/null +++ b/examples/data/scripts/download.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# just an example of how you could handle your downloads +# try some pattern matching on the uri to determine what we should do + +# Some sites block the default wget --user-agent.. +GET="wget --user-agent=Firefox" + +dest="$HOME" +url="$8" + +http_proxy="$9" +export http_proxy + +test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } + +# only changes the dir for the $get sub process +if echo "$url" | grep -E '.*\.torrent' >/dev/null; +then + ( cd "$dest"; $GET "$url") +else + ( cd "$dest"; $GET "$url") +fi diff --git a/examples/data/scripts/extedit.js b/examples/data/scripts/extedit.js new file mode 100644 index 0000000..8ed346d --- /dev/null +++ b/examples/data/scripts/extedit.js @@ -0,0 +1,102 @@ +/* + * Edit forms in external editor + * + * (c) 2009, Robert Manea + * utf8 functions are (c) by Webtoolkit.info (http://www.webtoolkit.info/) + * + * + * Installation: + * - Copy this script to $HOME/.local/share/uzbl/scripts + * - Add the following to $HOME/.config/uzbl/config: + * @bind E = script @scripts_dir/extedit.js + * - Set your preferred editor + * set editor = gvim + * - non-GUI editors + * set editor = xterm -e vim + * + * Usage: + * Select (click) an editable form, go to command mode and hit E + * +*/ + + +function utf8_decode ( str_data ) { + var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; + + str_data += ''; + + while ( i < str_data.length ) { + c1 = str_data.charCodeAt(i); + if (c1 < 128) { + tmp_arr[ac++] = String.fromCharCode(c1); + i++; + } else if ((c1 > 191) && (c1 < 224)) { + c2 = str_data.charCodeAt(i+1); + tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + i += 2; + } else { + c2 = str_data.charCodeAt(i+1); + c3 = str_data.charCodeAt(i+2); + tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + } + + return tmp_arr.join(''); +} + + +function utf8_encode ( argString ) { + var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); + + var utftext = ""; + var start, end; + var stringl = 0; + + start = end = 0; + stringl = string.length; + for (var n = 0; n < stringl; n++) { + var c1 = string.charCodeAt(n); + var enc = null; + + if (c1 < 128) { + end++; + } else if (c1 > 127 && c1 < 2048) { + enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128); + } else { + enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128); + } + if (enc !== null) { + if (end > start) { + utftext += string.substring(start, end); + } + utftext += enc; + start = end = n+1; + } + } + + if (end > start) { + utftext += string.substring(start, string.length); + } + + return utftext; +} + + +(function() { + var actelem = document.activeElement; + + if(actelem.type == 'text' || actelem.type == 'textarea') { + var editor = Uzbl.run("print @external_editor") || "gvim"; + var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit.XXXXXX)@"); + + if(actelem.value) + Uzbl.run("sh 'echo " + window.btoa(utf8_encode(actelem.value)) + " | base64 -d > " + filename + "'"); + + Uzbl.run("sync_sh '" + editor + " " + filename + "'"); + actelem.value = utf8_decode(window.atob(Uzbl.run("print @(base64 -w 0 " + filename + ")@"))); + + Uzbl.run("sh 'rm -f " + filename + "'"); + } + + })(); diff --git a/examples/data/scripts/follow_Numbers.js b/examples/data/scripts/follow_Numbers.js new file mode 100644 index 0000000..00b279e --- /dev/null +++ b/examples/data/scripts/follow_Numbers.js @@ -0,0 +1,228 @@ +/* This is the basic linkfollowing script. + * Its pretty stable, only using numbers to navigate. + * + * TODO: Some pages mess around a lot with the zIndex which + * lets some hints in the background. + * TODO: Some positions are not calculated correctly (mostly + * because of uber-fancy-designed-webpages. Basic HTML and CSS + * works good + * TODO: Still some links can't be followed/unexpected things + * happen. Blame some freaky webdesigners ;) + */ + +//Just some shortcuts and globals +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; + +//Reset keycmd, modcmd and return to default mode. +function clearKeycmd() { Uzbl.run('set mode ='); } + +//Make onlick-links "clickable" +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +//Catch the ESC keypress to stop linkfollowing +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +//Calculate element position to draw the hint +//Pretty accurate but on fails in some very fancy cases +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +//Calculate if an element is visible +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +//Calculate if an element is on the viewport. +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +//Removes all hints/leftovers that might be generated +//by this script. +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +//Generate a hint for an element with the given label +//Here you can play around with the style of the hints! +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '1000'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + // Play around with this, pretty funny things to do :) + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} +//Here we choose what to do with an element if we +//want to "follow" it. On form elements we "select" +//or pass the focus, on links we try to perform a click, +//but at least set the href of the link. (needs some improvements) +function clickElem(item) { + removeAllHints(); + clearKeycmd(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} +//Returns a list of all links (in this version +//just the elements itself, but in other versions, we +//add the label here. +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + } + } + return res; +} +//Same as above, just for the form elements +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + } + } + } + return res; +} +//Draw all hints for all elements passed. "len" is for +//the number of chars we should use to avoid collisions +function reDrawHints(elems, chars) { + removeAllHints(); + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + for (var i = 0; i < elems[0].length; i++) { + if (elems[0][i]) { + var label = elems[1][i].substring(chars); + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + } +} +//Put it all together +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + var label = j + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + for (var k = 0; k < s.length; k++) { + b = b && label.charAt(k) == s[k]; + } + if (b) { + leftover[0].push(elems[0][j]); + leftover[1].push(label); + } + } + reDrawHints(leftover, s.length); + } +} +followLinks('%s'); diff --git a/examples/data/scripts/follow_Numbers_Strings.js b/examples/data/scripts/follow_Numbers_Strings.js new file mode 100644 index 0000000..e50da5d --- /dev/null +++ b/examples/data/scripts/follow_Numbers_Strings.js @@ -0,0 +1,212 @@ +var uzblid = 'uzbl_link_hint'; +var uzbldivid = uzblid + '_div_container'; +var doc = document; +var win = window; +var links = document.links; +var forms = document.forms; + +//Reset keycmd, modcmd and return to default mode. +function clearKeycmd() { Uzbl.run('set mode ='); } + +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} +function keyPressHandler(e) { + var kC = window.event ? event.keyCode: e.keyCode; + var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; + if (kC == Esc) { + removeAllHints(); + } +} +function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; + var width = el.offsetWidth; + var height = el.offsetHeight; + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return [up, left, width, height]; +} +function isVisible(el) { + if (el == doc) { + return true; + } + if (!el) { + return false; + } + if (!el.parentNode) { + return false; + } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); +} +function elementInViewport(el) { + offset = elementPosition(el); + var up = offset[0]; + var left = offset[1]; + var width = offset[2]; + var height = offset[3]; + return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; +} +function removeAllHints() { + var elements = doc.getElementById(uzbldivid); + if (elements) { + elements.parentNode.removeChild(elements); + } +} +function generateHint(el, label) { + var pos = elementPosition(el); + var hint = doc.createElement('div'); + hint.setAttribute('name', uzblid); + hint.innerText = label; + hint.style.display = 'inline'; + hint.style.backgroundColor = '#B9FF00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.zIndex = '1000'; + hint.style.fontSize = '9px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '9px'; + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + var img = el.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = pos[1] + img[0].width / 2 + 'px'; + } + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + return hint; +} + +function clickElem(item) { + removeAllHints(); + clearKeycmd(); + if (item) { + var name = item.tagName; + if (name == 'A') { + item.click(); + window.location = item.href; + } else if (name == 'INPUT') { + var type = item.getAttribute('type').toUpperCase(); + if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { + item.focus(); + item.select(); + } else { + item.click(); + } + } else if (name == 'TEXTAREA' || name == 'SELECT') { + item.focus(); + item.select(); + } else { + item.click(); + window.location = item.href; + } + } +} + +function addLinks() { + res = [[], []]; + for (var l = 0; l < links.length; l++) { + var li = links[l]; + if (isVisible(li) && elementInViewport(li)) { + res[0].push(li); + res[1].push(li.innerText.toLowerCase()); + } + } + return res; +} +function addFormElems() { + res = [[], []]; + for (var f = 0; f < forms.length; f++) { + for (var e = 0; e < forms[f].elements.length; e++) { + var el = forms[f].elements[e]; + if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { + res[0].push(el); + if (el.getAttribute('value')) { + res[1].push(el.getAttribute('value').toLowerCase()); + } else { + res[1].push(el.getAttribute('name').toLowerCase()); + } + } + } + } + return res; +} +function reDrawHints(elems, len) { + var hintdiv = doc.createElement('div'); + hintdiv.setAttribute('id', uzbldivid); + hintdiv.style.opacity = '0.0'; + for (var i = 0; i < elems[0].length; i++) { + var label = i + ''; + var n = label.length; + for (n; n < len; n++) { + label = '0' + label; + } + if (elems[0][i]) { + var h = generateHint(elems[0][i], label); + hintdiv.appendChild(h); + } + } + if (document.body) { + document.body.appendChild(hintdiv); + hintdiv.style.opacity = '0.7' + } +} +function followLinks(follow) { + var s = follow.split(''); + var linknr = parseInt(follow, 10); + if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); + var linkelems = addLinks(); + var formelems = addFormElems(); + var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; + var len = (elems[0].length + '').length; + var oldDiv = doc.getElementById(uzbldivid); + var leftover = [[], []]; + if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + clickElem(elems[0][linknr]); + } else { + for (var j = 0; j < elems[0].length; j++) { + var b = true; + for (var k = 0; k < s.length; k++) { + b = b && elems[1][j].charAt(k) == s[k]; + } + if (!b) { + elems[0][j] = null; + elems[1][j] = null; + } else { + leftover[0].push(elems[0][j]); + leftover[1].push(elems[1][j]); + } + } + if (leftover[0].length == 1) { + clickElem(leftover[0][0]); + } else if (!oldDiv) { + if (linknr + 1 || s.length == 0) { + reDrawHints(elems, len); + } else { + reDrawHints(leftover, len); + } + } + } +} +followLinks('%s'); diff --git a/examples/data/scripts/formfiller.pl b/examples/data/scripts/formfiller.pl new file mode 100755 index 0000000..74dcc80 --- /dev/null +++ b/examples/data/scripts/formfiller.pl @@ -0,0 +1,99 @@ +#!/usr/bin/perl + +# a slightly more advanced form filler +# +# uses settings file like: $keydir/ +#TODO: fallback to $HOME/.local/share +# user arg 1: +# edit: force editing of the file (fetches if file is missing) +# load: fill forms from file (fetches if file is missing) +# new: fetch new file + +# usage example: +# bind LL = spawn /usr/share/uzbl/examples/data/scripts/formfiller.pl load +# bind LN = spawn /usr/share/uzbl/examples/data/scripts/formfiller.pl new +# bind LE = spawn /usr/share/uzbl/examples/data/scripts/formfiller.pl edit + +use strict; +use warnings; + +my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; +my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; +if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } + +sub domain { + my ($url) = @_; + $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#; + return $url; +}; + +my $editor = "xterm -e vim"; +#my $editor = "gvim"; + +# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with +# Also, you may need to fake the user-agent on some sites (like facebook) + my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' "; +#my $downloader = "curl -s"; + +my @fields = ("type","name","value"); + +my %command; + +$command{load} = sub { + my ($domain) = @_; + my $filename = "$keydir/$domain"; + if (-e $filename){ + open(my $file, $filename) or die "Failed to open $filename: $!"; + my (@lines) = <$file>; + close($file); + $|++; + open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; + foreach my $line (@lines) { + next if ($line =~ m/^#/); + my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); + if ($type eq "checkbox") + { + printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; + } elsif ($type eq "submit") + { + printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; + } elsif ($type ne "") + { + printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; + } + print $fifo "\n"; + } + $|--; + } else { + $command{new}->($domain); + $command{edit}->($domain); + } +}; +$command{edit} = sub { + my ($domain) = @_; + my $file = "$keydir/$domain"; + if(-e $file){ + system ($editor, $file); + } else { + $command{new}->($domain); + } +}; +$command{new} = sub { + my ($domain) = @_; + my $filename = "$keydir/$domain"; + open (my $file,">>", $filename) or die "Failed to open $filename: $!"; + $|++; + print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; + printf $file "#%-10s | %-10s | %s\n", @fields; + print $file "#------------------------------\n"; + my @data = `$downloader $url`; + foreach my $line (@data){ + if($line =~ m/].*?)>/i){ + $line =~ s/.*(].*?)>).*/$1/; + printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; + }; + }; + $|--; +}; + +$command{$cmd}->(domain($url)); diff --git a/examples/data/scripts/formfiller.sh b/examples/data/scripts/formfiller.sh new file mode 100755 index 0000000..10afaba --- /dev/null +++ b/examples/data/scripts/formfiller.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# simple html form (eg for logins) filler (and manager) for uzbl. +# uses settings files like: $keydir/ +# files contain lines like: : + + +# user arg 1: +# edit: force editing the file (falls back to new if not found) +# new: start with a new file. +# load: try to load from file into form + +# something else (or empty): if file not available: new, otherwise load. + +keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms +[ -d "`dirname $keydir`" ] || exit 1 +[ -d "$keydir" ] || mkdir "$keydir" + +editor=${VISUAL} +if [[ -z ${editor} ]]; then + #editor='gvim' + editor='urxvt -e vim' +fi + +config=$1; shift +pid=$1; shift +xid=$1; shift +fifo=$1; shift +socket=$1; shift +url=$1; shift +title=$1; shift +action=$1 + +[ -d $keydir ] || mkdir $keydir || exit 1 + +if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ] +then + action=new + [[ -e $keydir/$domain ]] && action=load +elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]] +then + action=new +fi +domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') + + +#regex='s|.*.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page + regex='s|.*> $fifo +else + if [ "$action" == 'new' ] + then + curl "$url" | grep ' $keydir/$domain + fi + [[ -e $keydir/$domain ]] || exit 3 #this should never happen, but you never know. + $editor $keydir/$domain #TODO: if user aborts save in editor, the file is already overwritten +fi diff --git a/examples/data/scripts/hint.js b/examples/data/scripts/hint.js new file mode 100644 index 0000000..ec7f1e2 --- /dev/null +++ b/examples/data/scripts/hint.js @@ -0,0 +1,26 @@ +for (var i=0; i < document.links.length; i++) { + var uzblid = 'uzbl_link_hint_'; + var li = document.links[i]; + var pre = document.getElementById(uzblid+i); + + if (pre) { + li.removeChild(pre); + } else { + var hint = document.createElement('div'); + hint.setAttribute('id',uzblid+i); + hint.innerHTML = i; + hint.style.display='inline'; + hint.style.lineHeight='90%'; + hint.style.backgroundColor='red'; + hint.style.color='white'; + hint.style.fontSize='small-xx'; + hint.style.fontWeight='light'; + hint.style.margin='0px'; + hint.style.padding='2px'; + hint.style.position='absolute'; + hint.style.textDecoration='none'; + hint.style.left=li.style.left; + hint.style.top=li.style.top; + li.insertAdjacentElement('afterBegin',hint); + } +} diff --git a/examples/data/scripts/history.sh b/examples/data/scripts/history.sh new file mode 100755 index 0000000..7c83aa6 --- /dev/null +++ b/examples/data/scripts/history.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history +[ -d `dirname $file` ] || exit 1 +echo `date +'%Y-%m-%d %H:%M:%S'`" $6 $7" >> $file diff --git a/examples/data/scripts/insert_bookmark.sh b/examples/data/scripts/insert_bookmark.sh new file mode 100755 index 0000000..c34e7db --- /dev/null +++ b/examples/data/scripts/insert_bookmark.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1 +file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks + +which zenity &>/dev/null || exit 2 + +entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` +exitstatus=$? +if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi +url=`echo $entry | awk '{print $1}'` + +# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags +echo "$entry" >/dev/null #for some reason we need this.. don't ask me why +echo -e "$entry" >> $file +true diff --git a/examples/data/scripts/instance-select-wmii.sh b/examples/data/scripts/instance-select-wmii.sh new file mode 100755 index 0000000..2bf13ba --- /dev/null +++ b/examples/data/scripts/instance-select-wmii.sh @@ -0,0 +1,54 @@ +#!/bin/sh + + +# This script allows you to focus another uzbl window +# It considers all uzbl windows in the current tag +# you can select one from a list, or go to the next/previous one +# It does not change the layout (stacked/tiled/floating) nor does it +# changes the size or viewing mode of a uzbl window +# When your current uzbl window is maximized, the one you change to +# will be maximized as well. +# See http://www.uzbl.org/wiki/wmii for more info +# $1 must be one of 'list', 'next', 'prev' + +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" + +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch +else + DMENU="dmenu -i" +fi + +if [ "$1" == 'list' ] +then + list= + # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky + for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) + do + label=$(wmiir read /client/$i/label) + list="$list$i : $label\n" + done + window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) + wmiir xwrite /tag/sel/ctl "select client $window" +elif [ "$1" == 'next' ] +then + current=$(wmiir read /client/sel/ctl | head -n 1) + # find the next uzbl window and focus it + next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2) + if [ x"$next" != "x" ] + then + wmiir xwrite /tag/sel/ctl "select client $next" + fi +elif [ "$1" == 'prev' ] +then + current=$(wmiir read /client/sel/ctl | head -n 1) + prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2) + if [ x"$prev" != "x" ] + then + wmiir xwrite /tag/sel/ctl "select client $prev" + fi +else + echo "\$1 not valid" >&2 + exit 2 +fi diff --git a/examples/data/scripts/linkfollow.js b/examples/data/scripts/linkfollow.js new file mode 100644 index 0000000..3109cda --- /dev/null +++ b/examples/data/scripts/linkfollow.js @@ -0,0 +1,269 @@ +// link follower for uzbl +// requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 +// +// first, it needs to be loaded before every time it is used. +// One way would be to use the load_commit_handler: +// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/data/scripts/linkfollow.js" > "$4"' +// +// when script is loaded, it can be invoked with +// bind f* = js hints.set("%s", hints.open) +// bind f_ = js hints.follow("%s",hints.open) +// +// At the moment, it may be useful to have way of forcing uzbl to load the script +// bind :lf = script /usr/share/uzbl/examples/data/scripts/linkfollow.js +// +// The default style for the hints are pretty ugly, so it is recommended to add the following +// to config file +// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css +// +// based on follow_Numbers.js +// +// TODO: fix styling for the first element +// TODO: emulate mouseover events when visiting some elements +// TODO: rewrite the element->action handling + + +function Hints(){ + + // Settings + //////////////////////////////////////////////////////////////////////////// + + // if set to true, you must explicitly call hints.follow(), otherwise it will + // follow the link if there is only one matching result + var requireReturn = true; + + // Case sensitivity flag + var matchCase = "i"; + + // For case sensitive matching, uncomment: + // var matchCase = ""; + + + var uzblid = 'uzbl_hint'; + var uzblclass = 'uzbl_highlight'; + var uzblclassfirst = 'uzbl_h_first'; + var doc = document; + var visible = []; + var hintdiv; + + this.set = hint; + this.follow = follow; + this.keyPressHandler = keyPressHandler; + + function elementPosition(el) { + var up = el.offsetTop; + var left = el.offsetLeft; var width = el.offsetWidth; + var height = el.offsetHeight; + + while (el.offsetParent) { + el = el.offsetParent; + up += el.offsetTop; + left += el.offsetLeft; + } + return {up: up, left: left, width: width, height: height}; + } + + function elementInViewport(p) { + return (p.up < window.pageYOffset + window.innerHeight && + p.left < window.pageXOffset + window.innerWidth && + (p.up + p.height) > window.pageYOffset && + (p.left + p.width) > window.pageXOffset); + } + + function isVisible(el) { + if (el == doc) { return true; } + if (!el) { return false; } + if (!el.parentNode) { return false; } + if (el.style) { + if (el.style.display == 'none') { + return false; + } + if (el.style.visibility == 'hidden') { + return false; + } + } + return isVisible(el.parentNode); + } + + // the vimperator defaults minus the xhtml elements, since it gave DOM errors + var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; + + function Matcher(str){ + var numbers = str.replace(/[^\d]/g,""); + var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); + this.test = test; + this.toString = toString; + this.numbers = numbers; + function matchAgainst(element){ + if(element.node.nodeName == "INPUT"){ + return element.node.value; + } else { + return element.node.textContent; + } + } + function test(element) { + // test all the regexp + var item = matchAgainst(element); + return words.every(function (regex) { return item.match(regex)}); + } + } + + function HintElement(node,pos){ + + this.node = node; + this.isHinted = false; + this.position = pos; + this.num = 0; + + this.addHint = function (labelNum) { + // TODO: fix uzblclassfirst + if(!this.isHinted){ + this.node.className += " " + uzblclass; + } + this.isHinted = true; + + // create hint + var hintNode = doc.createElement('div'); + hintNode.name = uzblid; + hintNode.innerText = labelNum; + hintNode.style.left = this.position.left + 'px'; + hintNode.style.top = this.position.up + 'px'; + hintNode.style.position = "absolute"; + doc.body.firstChild.appendChild(hintNode); + + } + this.removeHint = function(){ + if(this.isHinted){ + var s = (this.num)?uzblclassfirst:uzblclass; + this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); + this.isHinted = false; + } + } + } + + function createHintDiv(){ + var hintdiv = doc.getElementById(uzblid); + if(hintdiv){ + hintdiv.parentNode.removeChild(hintdiv); + } + hintdiv = doc.createElement("div"); + hintdiv.setAttribute('id',uzblid); + doc.body.insertBefore(hintdiv,doc.body.firstChild); + return hintdiv; + } + + function init(){ + // WHAT? + doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); + hintdiv = createHintDiv(); + visible = []; + + var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); + for (var i = 0;i&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # show tags as well + goto=`$DMENU $COLORS < $file | awk '{print $1}'` +else + DMENU="dmenu -i" + # because they are all after each other, just show the url, not their tags. + goto=`awk '{print $1}' $file | $DMENU $COLORS` +fi + +#[ -n "$goto" ] && echo "uri $goto" > $4 +[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/examples/data/scripts/load_url_from_history.sh b/examples/data/scripts/load_url_from_history.sh new file mode 100755 index 0000000..62e02ac --- /dev/null +++ b/examples/data/scripts/load_url_from_history.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history +[ -r "$history_file" ] || exit 1 + +# choose from all entries, sorted and uniqued +# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` +COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" +if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'; +then + DMENU="dmenu -i -xs -rs -l 10" # vertical patch + # choose an item in reverse order, showing also the date and page titles + # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. + goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` +else + DMENU="dmenu -i" + # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order + current=`tail -n 1 $history_file | awk '{print $3}'`; + goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \ + | sort -u) | $DMENU $COLORS` +fi + +[ -n "$goto" ] && echo "uri $goto" > $4 +#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/examples/data/scripts/scheme.py b/examples/data/scripts/scheme.py new file mode 100755 index 0000000..0916466 --- /dev/null +++ b/examples/data/scripts/scheme.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import os, subprocess, sys, urlparse + +def detach_open(cmd): + # Thanks to the vast knowledge of Laurence Withers (lwithers) and this message: + # http://mail.python.org/pipermail/python-list/2006-November/587523.html + if not os.fork(): + null = os.open(os.devnull,os.O_WRONLY) + for i in range(3): os.dup2(null,i) + os.close(null) + subprocess.Popen(cmd) + print 'USED' + +if __name__ == '__main__': + uri = sys.argv[8] + u = urlparse.urlparse(uri) + if u.scheme == 'mailto': + detach_open(['xterm', '-e', 'mail', u.path]) + elif u.scheme == 'xmpp': + # Someone check for safe arguments to gajim-remote + detach_open(['gajim-remote', 'open_chat', uri]) + elif u.scheme == 'git': + detach_open(['git', 'clone', '--', uri], cwd=os.path.expanduser('~/src')) diff --git a/examples/data/scripts/scroll-percentage.js b/examples/data/scripts/scroll-percentage.js new file mode 100644 index 0000000..c9a51aa --- /dev/null +++ b/examples/data/scripts/scroll-percentage.js @@ -0,0 +1,68 @@ +// VIM ruler style scroll message +(function() { + var run = Uzbl.run; + var update_message = function() { + var innerHeight = window.innerHeight; + var scrollY = window.scrollY; + var height = document.height; + var message; + + if (UzblZoom.type === "full") { + var zoom_level = UzblZoom.level; + innerHeight = Math.ceil(innerHeight * zoom_level); + scrollY = Math.ceil(scrollY * zoom_level); + height -= 1; + } + + if (! height) { + message = ""; + } + else if (height <= innerHeight) { + message = run("print @scroll_all_indicator") || "All"; + } + else if (scrollY === 0) { + message = run("print @scroll_top_indicator") || "Top"; + } + else if (scrollY + innerHeight >= height) { + message = run("print @scroll_bottom_indicator") || "Bot"; + } + else { + var percentage = Math.round(scrollY / (height - innerHeight) * 100); + message = percentage + "%"; + } + run("set scroll_message=" + message); + }; + + self.UzblZoom = { + get level() { + return Number(run("print @zoom_level")) || 1; + }, + set level(level) { + if (typeof level === "number" && level > 0) { + run("set zoom_level = " + level); + update_message(); + } + }, + get type() { + return run("print @zoom_type") || "text"; + }, + set type(type) { + if ((type === "text" || type === "full") && this.type != type) { + run("toggle_zoom_type"); + run("set zoom_type = " + type); + update_message(); + } + }, + toggle_type: function() { + this.type = (this.type === "text" ? "full" : "text"); + } + }; + + window.addEventListener("DOMContentLoaded", update_message, false); + window.addEventListener("load", update_message, false); + window.addEventListener("resize", update_message, false); + window.addEventListener("scroll", update_message, false); + update_message(); +})(); + +// vim: set noet ff=unix diff --git a/examples/data/scripts/session.sh b/examples/data/scripts/session.sh new file mode 100755 index 0000000..1059b5e --- /dev/null +++ b/examples/data/scripts/session.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +# Very simple session manager for uzbl-browser. When called with "endsession" as the +# argument, it'll backup $sessionfile, look for fifos in $fifodir and +# instruct each of them to store their current url in $sessionfile and +# terminate themselves. Run with "launch" as the argument and an instance of +# uzbl-browser will be launched for each stored url. "endinstance" is used internally +# and doesn't need to be called manually at any point. +# Add a line like 'bind quit = /path/to/session.sh endsession' to your config + +[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1 +scriptfile=$0 # this script +sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/browser-session # the file in which the "session" (i.e. urls) are stored +configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file +UZBL="uzbl-browser -c $configfile" # add custom flags and whatever here. + +fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere +thisfifo="$4" +act="$8" +url="$6" + +if [ "$act." = "." ]; then + act="$1" +fi + + +case $act in + "launch" ) + urls=`cat $sessionfile` + if [ "$urls." = "." ]; then + $UZBL + else + for url in $urls; do + $UZBL --uri "$url" & + done + fi + exit 0 + ;; + + "endinstance" ) + if [ "$url" != "(null)" ]; then + echo "$url" >> $sessionfile; + fi + echo "exit" > "$thisfifo" + ;; + + "endsession" ) + mv "$sessionfile" "$sessionfile~" + for fifo in $fifodir/uzbl_fifo_*; do + if [ "$fifo" != "$thisfifo" ]; then + echo "spawn $scriptfile endinstance" > "$fifo" + fi + done + echo "spawn $scriptfile endinstance" > "$thisfifo" + ;; + + * ) echo "session manager: bad action" + echo "Usage: $scriptfile [COMMAND] where commands are:" + echo " launch - Restore a saved session or start a new one" + echo " endsession - Quit the running session. Must be called from uzbl" + ;; +esac diff --git a/examples/data/scripts/uzbl-cookie-daemon b/examples/data/scripts/uzbl-cookie-daemon new file mode 100755 index 0000000..fde8b8e --- /dev/null +++ b/examples/data/scripts/uzbl-cookie-daemon @@ -0,0 +1,664 @@ +#!/usr/bin/env python + +# The Python Cookie Daemon for Uzbl. +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, Dieter Plaetinck +# Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Michael Fiano +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +''' +The Python Cookie Daemon +======================== + +This daemon is a re-write of the original cookies.py script found in uzbl's +master branch. This script provides more functionality than the original +cookies.py by adding numerous command line options to specify different cookie +jar locations, socket locations, verbose output, etc. This functionality is +very useful as it allows you to run multiple daemons at once serving cookies +to different groups of uzbl instances as required. + +Keeping up to date +================== + +Check the cookie daemon uzbl-wiki page for more information on where to +find the latest version of the cookie_daemon.py + + http://www.uzbl.org/wiki/cookie_daemon.py + +Command line options +==================== + +Use the following command to get a full list of the cookie_daemon.py command +line options: + + ./cookie_daemon.py --help + +Talking with uzbl +================= + +In order to get uzbl to talk to a running cookie daemon you add the following +to your uzbl config: + + set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket + +Or if you prefer using the $HOME variable: + + set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket + +Todo list +========= + + - Use a pid file to make force killing a running daemon possible. + +Reporting bugs / getting help +============================= + +The best way to report bugs and or get help with the cookie daemon is to +contact the maintainers it the #uzbl irc channel found on the Freenode IRC +network (irc.freenode.org). +''' + +import cookielib +import os +import sys +import urllib2 +import select +import socket +import time +import atexit +from traceback import print_exc +from signal import signal, SIGTERM +from optparse import OptionParser +from os.path import join + +try: + import cStringIO as StringIO + +except ImportError: + import StringIO + + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return join(os.environ['HOME'], default) + +# Setup xdg paths. +CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/') +DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/') +CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/') + +# Ensure data paths exist. +for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]: + if not os.path.exists(path): + os.makedirs(path) + +# Default config +config = { + + # Default cookie jar, whitelist, and daemon socket locations. + 'cookie_jar': join(DATA_DIR, 'cookies.txt'), + 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), + 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), + + # Don't use a cookie whitelist policy by default. + 'use_whitelist': False, + + # Time out after x seconds of inactivity (set to 0 for never time out). + # WARNING: Do not use this option if you are manually launching the daemon. + 'daemon_timeout': 0, + + # Daemonise by default. + 'daemon_mode': True, + + # Optionally print helpful debugging messages to the terminal. + 'verbose': False, + +} # End of config dictionary. + + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +_SCRIPTNAME = os.path.basename(sys.argv[0]) +def echo(msg): + '''Prints only if the verbose flag has been set.''' + + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error message and exits.''' + + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + sys.exit(1) + + +def mkbasedir(filepath): + '''Create the base directories of the file in the file-path if the dirs + don't exist.''' + + dirname = os.path.dirname(filepath) + if not os.path.exists(dirname): + echo("creating dirs: %r" % dirname) + os.makedirs(dirname) + + +def daemon_running(cookie_socket): + '''Check if another process (hopefully a cookie_daemon.py) is listening + on the cookie daemon socket. If another process is found to be + listening on the socket exit the daemon immediately and leave the + socket alone. If the connect fails assume the socket has been abandoned + and delete it (to be re-created in the create socket function).''' + + if not os.path.exists(cookie_socket): + return False + + if os.path.isfile(cookie_socket): + raise Exception("regular file at %r is not a socket" % cookie_socket) + + + if os.path.isdir(cookie_socket): + raise Exception("directory at %r is not a socket" % cookie_socket) + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.close() + echo("detected daemon listening on %r" % cookie_socket) + return True + + except socket.error: + # Failed to connect to cookie_socket so assume it has been + # abandoned by another cookie daemon process. + if os.path.exists(cookie_socket): + echo("deleting abandoned socket at %r" % cookie_socket) + os.remove(cookie_socket) + + return False + + +def send_command(cookie_socket, cmd): + '''Send a command to a running cookie daemon.''' + + if not daemon_running(cookie_socket): + return False + + try: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) + sock.connect(cookie_socket) + sock.send(cmd) + sock.close() + echo("sent command %r to %r" % (cmd, cookie_socket)) + return True + + except socket.error: + print_exc() + error("failed to send message %r to %r" % (cmd, cookie_socket)) + return False + + +def kill_daemon(cookie_socket): + '''Send the "EXIT" command to running cookie_daemon.''' + + if send_command(cookie_socket, "EXIT"): + # Now ensure the cookie_socket is cleaned up. + start = time.time() + while os.path.exists(cookie_socket): + time.sleep(0.1) + if (time.time() - start) > 5: + error("force deleting socket %r" % cookie_socket) + os.remove(cookie_socket) + return + + echo("stopped daemon listening on %r"% cookie_socket) + + else: + if os.path.exists(cookie_socket): + os.remove(cookie_socket) + echo("removed abandoned/broken socket %r" % cookie_socket) + + +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + +class CookieMonster: + '''The uzbl cookie daemon class.''' + + def __init__(self): + '''Initialise class variables.''' + + self.server_socket = None + self.jar = None + self.last_request = time.time() + self._running = False + + + def run(self): + '''Start the daemon.''' + + # The check healthy function will exit if another daemon is detected + # listening on the cookie socket and remove the abandoned socket if + # there isnt. + if os.path.exists(config['cookie_socket']): + if daemon_running(config['cookie_socket']): + sys.exit(1) + + # Create cookie daemon socket. + self.create_socket() + + # Daemonize process. + if config['daemon_mode']: + echo("entering daemon mode") + daemonize() + + # Register a function to cleanup on exit. + atexit.register(self.quit) + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + # Create cookie jar object from file. + self.open_cookie_jar() + + # Create a way to exit nested loops by setting a running flag. + self._running = True + + while self._running: + try: + # Enter main listen loop. + self.listen() + + except KeyboardInterrupt: + self._running = False + print + + except socket.error: + print_exc() + + except: + # Clean up + self.del_socket() + + # Raise exception + raise + + # Always delete the socket before calling create again. + self.del_socket() + # Create cookie daemon socket. + self.create_socket() + + + def load_whitelist(self): + '''Load the cookie jar whitelist policy.''' + + cookie_whitelist = config['cookie_whitelist'] + + if cookie_whitelist: + mkbasedir(cookie_whitelist) + + # Create cookie whitelist file if it does not exist. + if not os.path.exists(cookie_whitelist): + open(cookie_whitelist, 'w').close() + + # Read cookie whitelist file into list. + file = open(cookie_whitelist,'r') + domain_list = [line.rstrip('\n') for line in file] + file.close() + + # Define policy of allowed domains + policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) + self.jar.set_policy(policy) + + # Save the last modified time of the whitelist. + self._whitelistmtime = os.stat(cookie_whitelist).st_mtime + + + def open_cookie_jar(self): + '''Open the cookie jar.''' + + cookie_jar = config['cookie_jar'] + cookie_whitelist = config['cookie_whitelist'] + + if cookie_jar: + mkbasedir(cookie_jar) + + # Create cookie jar object from file. + self.jar = cookielib.MozillaCookieJar(cookie_jar) + + # Load cookie whitelist policy. + if config['use_whitelist']: + self.load_whitelist() + + if cookie_jar: + try: + # Attempt to load cookies from the cookie jar. + self.jar.load(ignore_discard=True) + + # Ensure restrictive permissions are set on the cookie jar + # to prevent other users on the system from hi-jacking your + # authenticated sessions simply by copying your cookie jar. + os.chmod(cookie_jar, 0600) + + except: + pass + + + def reload_whitelist(self): + '''Reload the cookie whitelist.''' + + cookie_whitelist = config['cookie_whitelist'] + if os.path.exists(cookie_whitelist): + echo("reloading whitelist %r" % cookie_whitelist) + self.open_cookie_jar() + + + def create_socket(self): + '''Create AF_UNIX socket for communication with uzbl instances.''' + + cookie_socket = config['cookie_socket'] + mkbasedir(cookie_socket) + + self.server_socket = socket.socket(socket.AF_UNIX, + socket.SOCK_SEQPACKET) + + self.server_socket.bind(cookie_socket) + + # Set restrictive permissions on the cookie socket to prevent other + # users on the system from data-mining your cookies. + os.chmod(cookie_socket, 0600) + + + def listen(self): + '''Listen for incoming cookie PUT and GET requests.''' + + daemon_timeout = config['daemon_timeout'] + echo("listening on %r" % config['cookie_socket']) + + while self._running: + # This line tells the socket how many pending incoming connections + # to enqueue at once. Raising this number may or may not increase + # performance. + self.server_socket.listen(1) + + if bool(select.select([self.server_socket], [], [], 1)[0]): + client_socket, _ = self.server_socket.accept() + self.handle_request(client_socket) + self.last_request = time.time() + client_socket.close() + continue + + if daemon_timeout: + # Checks if the daemon has been idling for too long. + idle = time.time() - self.last_request + if idle > daemon_timeout: + self._running = False + + + def handle_request(self, client_socket): + '''Connection made, now to serve a cookie PUT or GET request.''' + + # Receive cookie request from client. + data = client_socket.recv(8192) + if not data: + return + + # Cookie argument list in packet is null separated. + argv = data.split("\0") + action = argv[0].upper().strip() + + # Catch the EXIT command sent to kill running daemons. + if action == "EXIT": + self._running = False + return + + # Catch whitelist RELOAD command. + elif action == "RELOAD": + self.reload_whitelist() + return + + # Return if command unknown. + elif action not in ['GET', 'PUT']: + error("unknown command %r." % argv) + return + + # Determine whether or not to print cookie data to terminal. + print_cookie = (config['verbose'] and not config['daemon_mode']) + if print_cookie: + print ' '.join(argv[:4]) + + uri = urllib2.urlparse.ParseResult( + scheme=argv[1], + netloc=argv[2], + path=argv[3], + params='', + query='', + fragment='').geturl() + + req = urllib2.Request(uri) + + if action == "GET": + self.jar.add_cookie_header(req) + if req.has_header('Cookie'): + cookie = req.get_header('Cookie') + client_socket.send(cookie) + if print_cookie: + print cookie + + else: + client_socket.send("\0") + + elif action == "PUT": + cookie = argv[4] if len(argv) > 3 else None + if print_cookie: + print cookie + + self.put_cookie(req, cookie) + + if print_cookie: + print + + + def put_cookie(self, req, cookie=None): + '''Put a cookie in the cookie jar.''' + + hdr = urllib2.httplib.HTTPMessage(\ + StringIO.StringIO('Set-Cookie: %s' % cookie)) + res = urllib2.addinfourl(StringIO.StringIO(), hdr, + req.get_full_url()) + self.jar.extract_cookies(res, req) + if config['cookie_jar']: + self.jar.save(ignore_discard=True) + + + def del_socket(self): + '''Remove the cookie_socket file on exit. In a way the cookie_socket + is the daemons pid file equivalent.''' + + if self.server_socket: + try: + self.server_socket.close() + + except: + pass + + self.server_socket = None + + cookie_socket = config['cookie_socket'] + if os.path.exists(cookie_socket): + echo("deleting socket %r" % cookie_socket) + os.remove(cookie_socket) + + + def quit(self): + '''Called on exit to make sure all loose ends are tied up.''' + + self.del_socket() + sys.exit(0) + + +def main(): + '''Main function.''' + + # Define command line parameters. + usage = "usage: %prog [options] {start|stop|restart|reload}" + parser = OptionParser(usage=usage) + parser.add_option('-n', '--no-daemon', dest='no_daemon', + action='store_true', help="don't daemonise the process.") + + parser.add_option('-v', '--verbose', dest="verbose", + action='store_true', help="print verbose output.") + + parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout', + action="store", metavar="SECONDS", help="shutdown the daemon after x "\ + "seconds inactivity. WARNING: Do not use this when launching the "\ + "cookie daemon manually.") + + parser.add_option('-s', '--cookie-socket', dest="cookie_socket", + metavar="SOCKET", help="manually specify the socket location.") + + parser.add_option('-j', '--cookie-jar', dest='cookie_jar', + metavar="FILE", help="manually specify the cookie jar location.") + + parser.add_option('-m', '--memory', dest='memory', action='store_true', + help="store cookies in memory only - do not write to disk") + + parser.add_option('-u', '--use-whitelist', dest='usewhitelist', + action='store_true', help="use cookie whitelist policy") + + parser.add_option('-w', '--cookie-whitelist', dest='whitelist', + action='store', help="manually specify whitelist location", + metavar='FILE') + + # Parse the command line arguments. + (options, args) = parser.parse_args() + + expand = lambda p: os.path.realpath(os.path.expandvars(p)) + + initcommands = ['start', 'stop', 'restart', 'reload'] + for arg in args: + if arg not in initcommands: + error("unknown argument %r" % args[0]) + sys.exit(1) + + if len(args) > 1: + error("the daemon only accepts one {%s} action at a time." + % '|'.join(initcommands)) + sys.exit(1) + + if len(args): + action = args[0] + + else: + action = "start" + + if options.no_daemon: + config['daemon_mode'] = False + + if options.cookie_socket: + config['cookie_socket'] = expand(options.cookie_socket) + + if options.cookie_jar: + config['cookie_jar'] = expand(options.cookie_jar) + + if options.memory: + config['cookie_jar'] = None + + if options.whitelist: + config['cookie_whitelist'] = expand(options.whitelist) + + if options.whitelist or options.usewhitelist: + config['use_whitelist'] = True + + if options.daemon_timeout: + try: + config['daemon_timeout'] = int(options.daemon_timeout) + + except ValueError: + error("expected int argument for -t, --daemon-timeout") + + # Expand $VAR's in config keys that relate to paths. + for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']: + if config[key]: + config[key] = os.path.expandvars(config[key]) + + if options.verbose: + config['verbose'] = True + import pprint + sys.stderr.write("%s\n" % pprint.pformat(config)) + + # It would be better if we didn't need to start this python process just + # to send a command to the socket, but unfortunately socat doesn't seem + # to support SEQPACKET. + if action == "reload": + send_command(config['cookie_socket'], "RELOAD") + + if action in ['stop', 'restart']: + kill_daemon(config['cookie_socket']) + + if action in ['start', 'restart']: + CookieMonster().run() + + +if __name__ == "__main__": + main() diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager new file mode 100755 index 0000000..99b215a --- /dev/null +++ b/examples/data/scripts/uzbl-event-manager @@ -0,0 +1,833 @@ +#!/usr/bin/env python + +# Event Manager for Uzbl +# Copyright (c) 2009, Mason Larobina +# Copyright (c) 2009, Dieter Plaetinck +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +''' + +E V E N T _ M A N A G E R . P Y +=============================== + +Event manager for uzbl written in python. + +''' + +import imp +import os +import sys +import re +import socket +import pprint +import time +import atexit +from select import select +from signal import signal, SIGTERM +from optparse import OptionParser +from traceback import print_exc +from functools import partial + + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return os.path.join(os.environ['HOME'], default) + + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +# `make install` will put the correct value here for your system +PREFIX = '/usr/local/' + +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') +CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') + +# Event manager config dictionary. This is not to be confused with the config +# dict that tracks variables in the uzbl instance. +CONFIG = { + 'verbose': False, + 'daemon_mode': True, + 'auto_close': False, + + 'plugins_load': [], + 'plugins_ignore': [], + + 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), + os.path.join(PREFIX, 'share/uzbl/examples/data/plugins/')], + + 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), + 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), +} + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + + +# Define some globals. +SCRIPTNAME = os.path.basename(sys.argv[0]) +FINDSPACES = re.compile("\s+") + + +class ArgumentError(Exception): + pass + + +def echo(msg): + '''Prints only if the verbose flag has been set.''' + + if CONFIG['verbose']: + sys.stdout.write("%s: %s\n" % (SCRIPTNAME, msg)) + + +def error(msg): + '''Prints error messages to stderr.''' + + sys.stderr.write("%s: error: %s\n" % (SCRIPTNAME, msg)) + + +def counter(): + '''Generate unique object id's.''' + + i = 0 + while True: + i += 1 + yield i + + +def find_plugins(plugin_dirs): + '''Find all event manager plugins in the plugin dirs and return a + dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' + + plugins = {} + + for plugin_dir in plugin_dirs: + plugin_dir = os.path.realpath(os.path.expandvars(plugin_dir)) + if not os.path.isdir(plugin_dir): + continue + + for filename in os.listdir(plugin_dir): + if not filename.lower().endswith('.py'): + continue + + path = os.path.join(plugin_dir, filename) + if not os.path.isfile(path): + continue + + if filename not in plugins: + plugins[filename] = plugin_dir + + return plugins + + +def load_plugins(plugin_dirs, load=None, ignore=None): + '''Load event manager plugins found in the plugin_dirs.''' + + load = [] if load is None else load + ignore = [] if ignore is None else ignore + + # Find the plugins in the plugin_dirs. + found = find_plugins(plugin_dirs) + + if load: + # Ignore anything not in the load list. + for plugin in found.keys(): + if plugin not in load: + del found[plugin] + + if ignore: + # Ignore anything in the ignore list. + for plugin in found.keys(): + if plugin in ignore: + del found[plugin] + + # Print plugin list to be loaded. + pprint.pprint(found) + + loaded = {} + # Load all found plugins into the loaded dict. + for (filename, plugin_dir) in found.items(): + name = filename[:-3] + info = imp.find_module(name, [plugin_dir]) + plugin = imp.load_module(name, *info) + loaded[(plugin_dir, filename)] = plugin + + return loaded + + +def daemonize(): + '''Daemonize the process using the Stevens' double-fork magic.''' + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #1 failed") + sys.exit(1) + + os.chdir('/') + os.setsid() + os.umask(0) + + try: + if os.fork(): + os._exit(0) + + except OSError: + print_exc() + sys.stderr.write("fork #2 failed") + sys.exit(1) + + sys.stdout.flush() + sys.stderr.flush() + + devnull = '/dev/null' + stdin = file(devnull, 'r') + stdout = file(devnull, 'a+') + stderr = file(devnull, 'a+', 0) + + os.dup2(stdin.fileno(), sys.stdin.fileno()) + os.dup2(stdout.fileno(), sys.stdout.fileno()) + os.dup2(stderr.fileno(), sys.stderr.fileno()) + + +def make_dirs(path): + '''Make all basedirs recursively as required.''' + + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + +def make_pid_file(pid_file): + '''Make pid file at given pid_file location.''' + + make_dirs(pid_file) + fileobj = open(pid_file, 'w') + fileobj.write('%d' % os.getpid()) + fileobj.close() + + +def del_pid_file(pid_file): + '''Delete pid file at given pid_file location.''' + + if os.path.isfile(pid_file): + os.remove(pid_file) + + +def get_pid(pid_file): + '''Read pid from pid_file.''' + + try: + fileobj = open(pid_file, 'r') + pid = int(fileobj.read()) + fileobj.close() + return pid + + except IOError, ValueError: + print_exc() + return None + + +def pid_running(pid): + '''Returns True if a process with the given pid is running.''' + + try: + os.kill(pid, 0) + + except OSError: + return False + + else: + return True + + +def term_process(pid): + '''Send a SIGTERM signal to the process with the given pid.''' + + if not pid_running(pid): + return False + + os.kill(pid, SIGTERM) + + start = time.time() + while True: + if not pid_running(pid): + return True + + if time.time() - start > 5: + raise OSError('failed to stop process with pid: %d' % pid) + + time.sleep(0.25) + + +def parse_msg(uzbl, msg): + '''Parse an incoming msg from a uzbl instance. All non-event messages + will be printed here and not be passed to the uzbl instance event + handler function.''' + + if not msg: + return + + cmd = FINDSPACES.split(msg, 3) + if not cmd or cmd[0] != 'EVENT': + # Not an event message. + print '---', msg + return + + while len(cmd) < 4: + cmd.append('') + + event, args = cmd[2], cmd[3] + if not event: + return + + try: + uzbl.event(event, args) + + except: + print_exc() + + +class EventHandler(object): + + nexthid = counter().next + + def __init__(self, event, handler, *args, **kargs): + if not callable(handler): + raise ArgumentError("EventHandler object requires a callable " + "object function for the handler argument not: %r" % handler) + + self.function = handler + self.args = args + self.kargs = kargs + self.event = event + self.hid = self.nexthid() + + + def __repr__(self): + args = ["event=%s" % self.event, "hid=%d" % self.hid, + "function=%r" % self.function] + + if self.args: + args.append("args=%r" % self.args) + + if self.kargs: + args.append("kargs=%r" % self.kargs) + + return "" % ', '.join(args) + + +class UzblInstance(object): + + # Give all plugins access to the main config dict. + config = CONFIG + + def __init__(self, parent, client_socket): + + # Internal variables. + self.exports = {} + self.handlers = {} + self.parent = parent + self.client_socket = client_socket + + self.depth = 0 + self.buffer = '' + self.pid = None + + # Call the init function in every plugin. The init function in each + # plugin is where that plugin connects functions to events and exports + # functions to the uzbl object. + for plugin in self.parent['plugins'].values(): + try: + plugin.init(self) + + except: + raise + + + def send(self, msg): + '''Send a command to the uzbl instance via the socket file.''' + + msg = msg.strip() + if self.client_socket: + print '%s<-- %s' % (' ' * self.depth, msg) + self.client_socket.send(("%s\n" % msg).encode('utf-8')) + + else: + print '%s!-- %s' % (' ' * self.depth, msg) + + + def export(self, name, function): + '''Export `function(uzbl, *args, ..)` inside a plugin to the uzbl + object like so `uzbl.function(*args, ..)`. This will allow other + plugins to call functions inside the current plugin (which is currently + calling this function) via the uzbl object.''' + + self.__dict__.__setitem__(name, partial(function, self)) + + + def export_dict(self, export_dict): + '''Export multiple (name, function)'s at once inside a dict of the + form `{name1: function1, name2: function2, ...}`.''' + + for (name, function) in export_dict.items(): + self.export(name, function) + + + def connect(self, event, handler, *args, **kargs): + '''Connect a uzbl event with a handler. Handlers can either be a + function or a uzbl command string.''' + + event = event.upper().strip() + assert event and ' ' not in event + + if event not in self.handlers.keys(): + self.handlers[event] = [] + + handlerobj = EventHandler(event, handler, *args, **kargs) + self.handlers[event].append(handlerobj) + print handlerobj + + + def connect_dict(self, connect_dict): + '''Connect a dictionary comprising of {"EVENT_NAME": handler, ..} to + the event handler stack. + + If you need to supply args or kargs to an event use the normal connect + function.''' + + for (event, handler) in connect_dict.items(): + self.connect(event, handler) + + + def remove_by_id(self, hid): + '''Remove connected event handler by unique handler id.''' + + for (event, handlers) in self.handlers.items(): + for handler in list(handlers): + if hid != handler.hid: + continue + + echo("removed %r" % handler) + handlers.remove(handler) + return + + echo('unable to find & remove handler with id: %d' % hid) + + + def remove(self, handler): + '''Remove connected event handler.''' + + for (event, handlers) in self.handlers.items(): + if handler in handlers: + echo("removed %r" % handler) + handlers.remove(handler) + return + + echo('unable to find & remove handler: %r' % handler) + + + def exec_handler(self, handler, *args, **kargs): + '''Execute event handler function.''' + + args += handler.args + kargs = dict(handler.kargs.items()+kargs.items()) + handler.function(self, *args, **kargs) + + + def event(self, event, *args, **kargs): + '''Raise an event.''' + + event = event.upper() + elems = [event,] + if args: elems.append(unicode(args)) + if kargs: elems.append(unicode(kargs)) + print "%s--> %s" % (' ' * self.depth, ' '.join(elems)) + + if event == "INSTANCE_START" and args: + self.pid = int(args[0]) + + if event not in self.handlers: + return + + for handler in self.handlers[event]: + self.depth += 1 + try: + self.exec_handler(handler, *args, **kargs) + + except: + print_exc() + + self.depth -= 1 + + + def close(self): + '''Close the client socket and clean up.''' + + try: + self.client_socket.close() + + except: + pass + + for (name, plugin) in self.parent['plugins'].items(): + if hasattr(plugin, 'cleanup'): + plugin.cleanup(self) + + +class UzblEventDaemon(dict): + def __init__(self): + + # Init variables and dict keys. + dict.__init__(self, {'uzbls': {}}) + self.running = None + self.server_socket = None + self.socket_location = None + + # Register that the event daemon server has started by creating the + # pid file. + make_pid_file(CONFIG['pid_file']) + + # Register a function to clean up the socket and pid file on exit. + atexit.register(self.quit) + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) + + # Load plugins, first-build of the plugins may be a costly operation. + self['plugins'] = load_plugins(CONFIG['plugin_dirs'], + CONFIG['plugins_load'], CONFIG['plugins_ignore']) + + + def _create_server_socket(self): + '''Create the event manager daemon socket for uzbl instance duplex + communication.''' + + server_socket = CONFIG['server_socket'] + server_socket = os.path.realpath(os.path.expandvars(server_socket)) + self.socket_location = server_socket + + # Delete socket if it exists. + if os.path.exists(server_socket): + os.remove(server_socket) + + self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.server_socket.bind(server_socket) + self.server_socket.listen(5) + + + def _close_server_socket(self): + '''Close and delete the server socket.''' + + try: + self.server_socket.close() + self.server_socket = None + + if os.path.exists(self.socket_location): + os.remove(self.socket_location) + + except: + pass + + + def run(self): + '''Main event daemon loop.''' + + # Create event daemon socket. + self._create_server_socket() + echo('listening on: %s' % self.socket_location) + + if CONFIG['daemon_mode']: + echo('entering daemon mode.') + daemonize() + # The pid has changed so update the pid file. + make_pid_file(CONFIG['pid_file']) + + # Now listen for incoming connections and or data. + self.listen() + + # Clean up. + self.quit() + + + def listen(self): + '''Accept incoming connections and constantly poll instance sockets + for incoming data.''' + + self.running = True + while self.running: + + sockets = [self.server_socket] + self['uzbls'].keys() + + reads, _, errors = select(sockets, [], sockets, 1) + + if self.server_socket in reads: + self.accept_connection() + reads.remove(self.server_socket) + + for client in reads: + self.read_socket(client) + + for client in errors: + error('Unknown error on socket: %r' % client) + self.close_connection(client) + + + def read_socket(self, client): + '''Read data from an instance socket and pass to the uzbl objects + event handler function.''' + + uzbl = self['uzbls'][client] + try: + raw = unicode(client.recv(8192), 'utf-8', 'ignore') + + except: + print_exc() + raw = None + + if not raw: + # Read null byte, close socket. + return self.close_connection(client) + + uzbl.buffer += raw + msgs = uzbl.buffer.split('\n') + uzbl.buffer = msgs.pop() + + for msg in msgs: + try: + parse_msg(uzbl, msg.strip()) + + except: + print_exc() + + + def accept_connection(self): + '''Accept incoming connection to the server socket.''' + + client_socket = self.server_socket.accept()[0] + + uzbl = UzblInstance(self, client_socket) + self['uzbls'][client_socket] = uzbl + + + def close_connection(self, client): + '''Clean up after instance close.''' + + try: + if client in self['uzbls']: + uzbl = self['uzbls'][client] + uzbl.close() + del self['uzbls'][client] + + except: + print_exc() + + if not len(self['uzbls']) and CONFIG['auto_close']: + echo('auto closing event manager.') + self.running = False + + + def quit(self): + '''Close all instance socket objects, server socket and delete the + pid file.''' + + echo('shutting down event manager.') + + for client in self['uzbls'].keys(): + self.close_connection(client) + + echo('unlinking: %r' % self.socket_location) + self._close_server_socket() + + echo('deleting pid file: %r' % CONFIG['pid_file']) + del_pid_file(CONFIG['pid_file']) + + +def stop_action(): + '''Stop the event manager daemon.''' + + pid_file = CONFIG['pid_file'] + if not os.path.isfile(pid_file): + return echo('no running daemon found.') + + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if not pid_running(pid): + echo('no process with pid: %d' % pid) + return os.remove(pid_file) + + echo("terminating process with pid: %d" % pid) + term_process(pid) + if os.path.isfile(pid_file): + os.remove(pid_file) + + echo('stopped event daemon.') + + +def start_action(): + '''Start the event manager daemon.''' + + pid_file = CONFIG['pid_file'] + if os.path.isfile(pid_file): + echo('found pid file: %r' % pid_file) + pid = get_pid(pid_file) + if pid_running(pid): + return echo('event daemon already started with pid: %d' % pid) + + echo('no process with pid: %d' % pid) + os.remove(pid_file) + + echo('starting event manager.') + UzblEventDaemon().run() + + +def restart_action(): + '''Restart the event manager daemon.''' + + echo('restarting event manager daemon.') + stop_action() + start_action() + + +def list_action(): + '''List all the plugins being loaded by the event daemon.''' + + plugins = find_plugins(CONFIG['plugin_dirs']) + dirs = {} + + for (plugin, plugin_dir) in plugins.items(): + if plugin_dir not in dirs: + dirs[plugin_dir] = [] + + dirs[plugin_dir].append(plugin) + + for (index, (plugin_dir, plugin_list)) in enumerate(sorted(dirs.items())): + if index: + print + + print "%s:" % plugin_dir + for plugin in sorted(plugin_list): + print " %s" % plugin + + +if __name__ == "__main__": + USAGE = "usage: %prog [options] {start|stop|restart|list}" + PARSER = OptionParser(usage=USAGE) + PARSER.add_option('-v', '--verbose', dest='verbose', action="store_true", + help="print verbose output.") + + PARSER.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", + metavar="DIRS", help="Specify plugin directories in the form of "\ + "'dir1:dir2:dir3'.") + + PARSER.add_option('-l', '--load-plugins', dest="load", action="store", + metavar="PLUGINS", help="comma separated list of plugins to load") + + PARSER.add_option('-i', '--ignore-plugins', dest="ignore", action="store", + metavar="PLUGINS", help="comma separated list of plugins to ignore") + + PARSER.add_option('-p', '--pid-file', dest='pid', action='store', + metavar='FILE', help="specify pid file location") + + PARSER.add_option('-s', '--server-socket', dest='socket', action='store', + metavar='SOCKET', help="specify the daemon socket location") + + PARSER.add_option('-n', '--no-daemon', dest="daemon", + action="store_true", help="don't enter daemon mode.") + + PARSER.add_option('-a', '--auto-close', dest='autoclose', + action='store_true', help='auto close after all instances disconnect.') + + (OPTIONS, ARGS) = PARSER.parse_args() + + # init like {start|stop|..} daemon actions dict. + DAEMON_ACTIONS = {'start': start_action, 'stop': stop_action, + 'restart': restart_action, 'list': list_action} + + if not ARGS: + ACTION = 'start' + + elif len(ARGS) == 1: + ACTION = ARGS[0] + if ACTION not in DAEMON_ACTIONS: + raise ArgumentError("unknown argument: %r" % ACTION) + + else: + raise ArgumentError("too many arguments: %r" % ARGS) + + # parse other flags & options. + if OPTIONS.verbose: + CONFIG['verbose'] = True + + if OPTIONS.plugin_dirs: + PLUGIN_DIRS = [] + for DIR in OPTIONS.plugin_dirs.split(':'): + if not DIR: + continue + + PLUGIN_DIRS.append(os.path.realpath(DIR)) + + CONFIG['plugin_dirs'] = PLUGIN_DIRS + echo("plugin search dirs: %r" % PLUGIN_DIRS) + + if OPTIONS.load and OPTIONS.ignore: + error("you can't load and ignore at the same time.") + sys.exit(1) + + elif OPTIONS.load: + LOAD = CONFIG['plugins_load'] + for PLUGIN in OPTIONS.load.split(','): + if PLUGIN.strip(): + LOAD.append(PLUGIN.strip()) + + echo('only loading plugin(s): %s' % ', '.join(LOAD)) + + elif OPTIONS.ignore: + IGNORE = CONFIG['plugins_ignore'] + for PLUGIN in OPTIONS.ignore.split(','): + if PLUGIN.strip(): + IGNORE.append(PLUGIN.strip()) + + echo('ignoring plugin(s): %s' % ', '.join(IGNORE)) + + if OPTIONS.autoclose: + CONFIG['auto_close'] = True + echo('will auto close.') + + if OPTIONS.pid: + CONFIG['pid_file'] = os.path.realpath(OPTIONS.pid) + echo("pid file location: %r" % CONFIG['pid_file']) + + if OPTIONS.socket: + CONFIG['server_socket'] = os.path.realpath(OPTIONS.socket) + echo("daemon socket location: %s" % CONFIG['server_socket']) + + if OPTIONS.daemon: + CONFIG['daemon_mode'] = False + + # Now {start|stop|...} + DAEMON_ACTIONS[ACTION]() diff --git a/examples/data/scripts/uzbl-tabbed b/examples/data/scripts/uzbl-tabbed new file mode 100755 index 0000000..7bd90d5 --- /dev/null +++ b/examples/data/scripts/uzbl-tabbed @@ -0,0 +1,1417 @@ +#!/usr/bin/env python + +# Uzbl tabbing wrapper using a fifo socket interface +# Copyright (c) 2009, Tom Adams +# Copyright (c) 2009, Chris van Dijk +# Copyright (c) 2009, Mason Larobina +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# Author(s): +# Tom Adams +# Wrote the original uzbl_tabbed.py as a proof of concept. +# +# Chris van Dijk (quigybo) +# Made signifigant headway on the old uzbl_tabbing.py script on the +# uzbl wiki +# +# Mason Larobina +# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface +# and inherit configuration options from the user's uzbl config. +# +# Contributor(s): +# mxey +# uzbl_config path now honors XDG_CONFIG_HOME if it exists. +# +# Romain Bignon +# Fix for session restoration code. +# +# Jake Probst +# Wrote a patch that overflows tabs in the tablist on to new lines when +# running of room. +# +# Devon Jones +# Fifo command bring_to_front which brings the gtk window to focus. +# +# Simon Lipp (sloonz) +# Various + + +# Dependencies: +# pygtk - python bindings for gtk. +# pango - python bindings needed for text rendering & layout in gtk widgets. +# pygobject - GLib's GObject bindings for python. +# +# Optional dependencies: +# simplejson - save uzbl_tabbed.py sessions & presets in json. +# +# Note: I haven't included version numbers with this dependency list because +# I've only ever tested uzbl_tabbed.py on the latest stable versions of these +# packages in Gentoo's portage. Package names may vary on different systems. + + +# Configuration: +# Because this version of uzbl_tabbed is able to inherit options from your main +# uzbl configuration file you may wish to configure uzbl tabbed from there. +# Here is a list of configuration options that can be customised and some +# example values for each: +# +# General tabbing options: +# show_tablist = 1 +# show_gtk_tabs = 0 +# tablist_top = 1 +# gtk_tab_pos = (top|left|bottom|right) +# gtk_refresh = 1000 +# switch_to_new_tabs = 1 +# capture_new_windows = 1 +# multiline_tabs = 1 +# +# Tab title options: +# tab_titles = 1 +# tab_indexes = 1 +# new_tab_title = Loading +# max_title_len = 50 +# show_ellipsis = 1 +# +# Session options: +# save_session = 1 +# json_session = 0 +# session_file = $HOME/.local/share/uzbl/session +# +# Inherited uzbl options: +# fifo_dir = /tmp +# socket_dir = /tmp +# icon_path = $HOME/.local/share/uzbl/uzbl.png +# status_background = #303030 +# +# Misc options: +# window_size = 800,800 +# verbose = 0 +# +# And uzbl_tabbed.py takes care of the actual binding of the commands via each +# instances fifo socket. +# +# Custom tab styling: +# tab_colours = foreground = "#888" background = "#303030" +# tab_text_colours = foreground = "#bbb" +# selected_tab = foreground = "#fff" +# selected_tab_text = foreground = "green" +# tab_indicate_https = 1 +# https_colours = foreground = "#888" +# https_text_colours = foreground = "#9c8e2d" +# selected_https = foreground = "#fff" +# selected_https_text = foreground = "gold" +# +# How these styling values are used are soley defined by the syling policy +# handler below (the function in the config section). So you can for example +# turn the tab text colour Firetruck-Red in the event "error" appears in the +# tab title or some other arbitrary event. You may wish to make a trusted +# hosts file and turn tab titles of tabs visiting trusted hosts purple. + + +# Issues: +# - new windows are not caught and opened in a new tab. +# - when uzbl_tabbed.py crashes it takes all the children with it. +# - when a new tab is opened when using gtk tabs the tab button itself +# grabs focus from its child for a few seconds. +# - when switch_to_new_tabs is not selected the notebook page is +# maintained but the new window grabs focus (try as I might to stop it). + + +# Todo: +# - add command line options to use a different session file, not use a +# session file and or open a uri on starup. +# - ellipsize individual tab titles when the tab-list becomes over-crowded +# - add "<" & ">" arrows to tablist to indicate that only a subset of the +# currently open tabs are being displayed on the tablist. +# - add the small tab-list display when both gtk tabs and text vim-like +# tablist are hidden (I.e. [ 1 2 3 4 5 ]) +# - check spelling. +# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into +# the collective. Resistance is futile! + + +import pygtk +import gtk +import subprocess +import os +import re +import time +import getopt +import pango +import select +import sys +import gobject +import socket +import random +import hashlib +import atexit +import types + +from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP +from signal import signal, SIGTERM, SIGINT +from optparse import OptionParser, OptionGroup + + +pygtk.require('2.0') + +_SCRIPTNAME = os.path.basename(sys.argv[0]) +def error(msg): + sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) + +# ============================================================================ +# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def xdghome(key, default): + '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise + use $HOME and the default path.''' + + xdgkey = "XDG_%s_HOME" % key + if xdgkey in os.environ.keys() and os.environ[xdgkey]: + return os.environ[xdgkey] + + return os.path.join(os.environ['HOME'], default) + +# Setup xdg paths. +DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') + +# Ensure uzbl xdg paths exist +if not os.path.exists(DATA_DIR): + os.makedirs(DATA_DIR) + +# All of these settings can be inherited from your uzbl config file. +config = { + # Tab options + 'show_tablist': True, # Show text uzbl like statusbar tab-list + 'show_gtk_tabs': False, # Show gtk notebook tabs + 'tablist_top': True, # Display tab-list at top of window + 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) + 'gtk_refresh': 1000, # Tablist refresh millisecond interval + 'switch_to_new_tabs': True, # Upon opening a new tab switch to it + 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows + 'multiline_tabs': True, # Tabs overflow onto new tablist lines. + + # Tab title options + 'tab_titles': True, # Display tab titles (else only tab-nums) + 'tab_indexes': True, # Display tab nums (else only tab titles) + 'new_tab_title': 'Loading', # New tab title + 'max_title_len': 50, # Truncate title at n characters + 'show_ellipsis': True, # Show ellipsis when truncating titles + + # Session options + 'save_session': True, # Save session in file when quit + 'json_session': False, # Use json to save session. + 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'), + 'session_file': os.path.join(DATA_DIR, 'session'), + + # Inherited uzbl options + 'fifo_dir': '/tmp', # Path to look for uzbl fifo. + 'socket_dir': '/tmp', # Path to look for uzbl socket. + 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'), + 'status_background': "#303030", # Default background for all panels. + + # Misc options + 'window_size': "800,800", # width,height in pixels. + 'verbose': False, # Print verbose output. + + # Add custom tab style definitions to be used by the tab colour policy + # handler here. Because these are added to the config dictionary like + # any other uzbl_tabbed configuration option remember that they can + # be superseeded from your main uzbl config file. + 'tab_colours': 'foreground = "#888" background = "#303030"', + 'tab_text_colours': 'foreground = "#bbb"', + 'selected_tab': 'foreground = "#fff"', + 'selected_tab_text': 'foreground = "green"', + 'tab_indicate_https': True, + 'https_colours': 'foreground = "#888"', + 'https_text_colours': 'foreground = "#9c8e2d"', + 'selected_https': 'foreground = "#fff"', + 'selected_https_text': 'foreground = "gold"', + +} # End of config dict. + +UZBL_TABBED_VARS = config.keys() + +# This is the tab style policy handler. Every time the tablist is updated +# this function is called to determine how to colourise that specific tab +# according the simple/complex rules as defined here. You may even wish to +# move this function into another python script and import it using: +# from mycustomtabbingconfig import colour_selector +# Remember to rename, delete or comment out this function if you do that. + +def colour_selector(tabindex, currentpage, uzbl): + '''Tablist styling policy handler. This function must return a tuple of + the form (tab style, text style).''' + + # Just as an example: + # if 'error' in uzbl.title: + # if tabindex == currentpage: + # return ('foreground="#fff"', 'foreground="red"') + # return ('foreground="#888"', 'foreground="red"') + + # Style tabs to indicate connected via https. + if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): + if tabindex == currentpage: + return (config['selected_https'], config['selected_https_text']) + return (config['https_colours'], config['https_text_colours']) + + # Style to indicate selected. + if tabindex == currentpage: + return (config['selected_tab'], config['selected_tab_text']) + + # Default tab style. + return (config['tab_colours'], config['tab_text_colours']) + +# ============================================================================ +# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: +# ============================================================================ + +def echo(msg): + if config['verbose']: + sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) + + +def counter(): + '''To infinity and beyond!''' + + i = 0 + while True: + i += 1 + yield i + + +def escape(s): + '''Replaces html markup in tab titles that screw around with pango.''' + + for (split, glue) in [('&','&'), ('<', '<'), ('>', '>')]: + s = s.replace(split, glue) + return s + + +class SocketClient: + '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance''' + + # List of UzblInstance objects not already linked with a SocketClient + instances_queue = {} + + def __init__(self, socket): + self._buffer = "" + self._socket = socket + self._watchers = [io_add_watch(socket, IO_IN, self._socket_recv),\ + io_add_watch(socket, IO_HUP, self._socket_closed)] + self.uzbl = None + + + def _socket_recv(self, fd, condition): + '''Data available on socket, process it''' + + self._feed(self._socket.recv(1024)) #TODO: is io_add_watch edge or level-triggered ? + return True + + + def _socket_closed(self, fd, condition): + '''Remote client exited''' + self.uzbl.close() + return False + + + def _feed(self, data): + '''An Uzbl instance sent some data, parse it''' + + self._buffer += data + if self.uzbl: + if "\n" in self._buffer: + cmds = self._buffer.split("\n") + + if cmds[-1]: # Last command has been received incomplete, don't process it + self._buffer, cmds = cmds[-1], cmds[:-1] + else: + self._buffer = "" + + for cmd in cmds: + if cmd: + self.uzbl.parse_command(cmd) + else: + name = re.findall('^EVENT \[(\d+-\d+)\] INSTANCE_START \d+$', self._buffer, re.M) + uzbl = self.instances_queue.get(name[0]) + if uzbl: + del self.instances_queue[name[0]] + self.uzbl = uzbl + self.uzbl.got_socket(self) + self._feed("") + + def send(self, data): + '''Child socket send function.''' + + self._socket.send(data + "\n") + + def close(self): + '''Close the connection''' + + if self._socket: + self._socket.close() + self._socket = None + map(source_remove, self._watchers) + self._watchers = [] + + +class UzblInstance: + '''Uzbl instance meta-data/meta-action object.''' + + def __init__(self, parent, tab, name, uri, title, switch): + + self.parent = parent + self.tab = tab + self.name = name + self.title = title + self.tabtitle = "" + self.uri = uri + self._client = None + self._switch = switch # Switch to tab after loading ? + self.title_changed() + + + def got_socket(self, client): + '''Uzbl instance is now connected''' + + self._client = client + self.parent.config_uzbl(self) + if self._switch: + tabid = self.parent.notebook.page_num(self.tab) + self.parent.goto_tab(tabid) + + + def title_changed(self, gtk_only = True): # GTK-only is for indexes + '''self.title has changed, update the tabs list''' + + tab_titles = config['tab_titles'] + tab_indexes = config['tab_indexes'] + show_ellipsis = config['show_ellipsis'] + max_title_len = config['max_title_len'] + + # Unicode heavy strings do not like being truncated/sliced so by + # re-encoding the string sliced of limbs are removed. + self.tabtitle = self.title[:max_title_len + int(show_ellipsis)] + if type(self.tabtitle) != types.UnicodeType: + self.tabtitle = unicode(self.tabtitle, 'utf-8', 'ignore') + + self.tabtitle = self.tabtitle.encode('utf-8', 'ignore').strip() + + if show_ellipsis and len(self.tabtitle) != len(self.title): + self.tabtitle += "\xe2\x80\xa6" + + gtk_tab_format = "%d %s" + index = self.parent.notebook.page_num(self.tab) + if tab_titles and tab_indexes: + self.parent.notebook.set_tab_label_text(self.tab, + gtk_tab_format % (index, self.tabtitle)) + elif tab_titles: + self.parent.notebook.set_tab_label_text(self.tab, self.tabtitle) + else: + self.parent.notebook.set_tab_label_text(self.tab, str(index)) + + # If instance is current tab, update window title + if index == self.parent.notebook.get_current_page(): + title_format = "%s - Uzbl Browser" + self.parent.window.set_title(title_format % self.title) + + # Non-GTK tabs + if not gtk_only: + self.parent.update_tablist() + + + def set(self, key, val): + ''' Send the SET command to Uzbl ''' + + if self._client: + self._client.send('set %s = %s') #TODO: escape chars ? + + + def exit(self): + ''' Ask the Uzbl instance to close ''' + + if self._client: + self._client.send('exit') + + + def parse_command(self, cmd): + ''' Parse event givent by the Uzbl instance ''' + + type, _, args = cmd.split(" ", 2) + if type == "EVENT": + type, args = args.split(" ", 1) + if type == "TITLE_CHANGED": + self.title = args + self.title_changed() + elif type == "VARIABLE_SET": + var, _, val = args.split(" ", 2) + try: + val = int(val) + except: + pass + + if var in UZBL_TABBED_VARS: + if config[var] != val: + config[var] = val + if var == "show_gtk_tabs": + self.parent.notebook.set_show_tabs(bool(val)) + elif var == "show_tablist" or var == "tablist_top": + self.parent.update_tablist_display() + elif var == "gtk_tab_pos": + self.parent.update_gtk_tab_pos() + elif var == "status_background": + col = gtk.gdk.color_parse(config['status_background']) + self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col) + elif var == "tab_titles" or var == "tab_indexes": + for tab in self.parent.notebook: + self.parent.tabs[tab].title_changed(True) + + self.parent.update_tablist() + else: + config[var] = val + + if var == "uri": + self.uri = var + self.parent.update_tablist() + elif type == "NEW_TAB": + self.parent.new_tab(args) + elif type == "NEXT_TAB": + if args: + self.parent.next_tab(int(args)) + else: + self.parent.next_tab() + elif type == "PREV_TAB": + if args: + self.parent.prev_tab(int(args)) + else: + self.parent.prev_tab() + elif type == "GOTO_TAB": + self.parent.goto_tab(int(args)) + elif type == "FIRST_TAB": + self.parent.goto_tab(0) + elif type == "LAST_TAB": + self.parent.goto_tab(-1) + elif type == "PRESET_TABS": + self.parent.parse_command(["preset"] + args.split()) + elif type == "BRING_TO_FRONT": + self.parent.window.present() + elif type == "CLEAN_TABS": + self.parent.clean_slate() + elif type == "EXIT_ALL_TABS": + self.parent.quitrequest() + + + def close(self): + '''The remote instance exited''' + + if self._client: + self._client.close() + self._client = None + + +class UzblTabbed: + '''A tabbed version of uzbl using gtk.Notebook''' + + def __init__(self): + '''Create tablist, window and notebook.''' + + self._timers = {} + self._buffer = "" + self._killed = False + + # A list of the recently closed tabs + self._closed = [] + + # Holds metadata on the uzbl childen open. + self.tabs = {} + + # Uzbl sockets (socket => SocketClient) + self.clients = {} + + # Generates a unique id for uzbl socket filenames. + self.next_pid = counter().next + + # Create main window + self.window = gtk.Window() + try: + window_size = map(int, config['window_size'].split(',')) + self.window.set_default_size(*window_size) + + except: + error("Invalid value for default_size in config file.") + + self.window.set_title("Uzbl Browser") + self.window.set_border_width(0) + + # Set main window icon + icon_path = config['icon_path'] + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + else: + icon_path = '/usr/share/uzbl/examples/data/uzbl.png' + if os.path.exists(icon_path): + self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) + + # Attach main window event handlers + self.window.connect("delete-event", self.quitrequest) + + # Create tab list + vbox = gtk.VBox() + self.vbox = vbox + self.window.add(vbox) + ebox = gtk.EventBox() + self.ebox = ebox + self.tablist = gtk.Label() + + self.tablist.set_use_markup(True) + self.tablist.set_justify(gtk.JUSTIFY_LEFT) + self.tablist.set_line_wrap(False) + self.tablist.set_selectable(False) + self.tablist.set_padding(2,2) + self.tablist.set_alignment(0,0) + self.tablist.set_ellipsize(pango.ELLIPSIZE_END) + self.tablist.set_text(" ") + self.tablist.show() + ebox.add(self.tablist) + ebox.show() + bgcolor = gtk.gdk.color_parse(config['status_background']) + ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) + + # Create notebook + self.notebook = gtk.Notebook() + self.notebook.set_show_tabs(config['show_gtk_tabs']) + + # Set tab position + self.update_gtk_tab_pos() + + self.notebook.set_show_border(False) + self.notebook.set_scrollable(True) + self.notebook.set_border_width(0) + + self.notebook.connect("page-removed", self.tab_closed) + self.notebook.connect("switch-page", self.tab_changed) + self.notebook.connect("page-added", self.tab_opened) + + self.notebook.show() + vbox.pack_start(self.notebook, True, True, 0) + vbox.reorder_child(self.notebook, 1) + self.update_tablist_display() + + self.vbox.show() + self.window.show() + self.wid = self.notebook.window.xid + + # Store information about the applications fifo and socket. + fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid() + socket_filename = 'uzbltabbed_%d.socket' % os.getpid() + self._fifo = None + self._socket = None + self.fifo_path = os.path.join(config['fifo_dir'], fifo_filename) + self.socket_path = os.path.join(config['socket_dir'], socket_filename) + + # Now initialise the fifo and the socket + self.init_fifo() + self.init_socket() + + # If we are using sessions then load the last one if it exists. + if config['save_session']: + self.load_session() + + + def run(self): + '''UzblTabbed main function that calls the gtk loop.''' + + if not self.clients and not SocketClient.instances_queue and not self.tabs: + self.new_tab() + + gtk_refresh = int(config['gtk_refresh']) + if gtk_refresh < 100: + gtk_refresh = 100 + + # Make SIGTERM act orderly. + signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) + + # Catch keyboard interrupts + signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) + + try: + gtk.main() + + except: + error("encounted error %r" % sys.exc_info()[1]) + + # Unlink fifo socket + self.unlink_fifo() + self.close_socket() + + # Attempt to close all uzbl instances nicely. + self.quitrequest() + + # Allow time for all the uzbl instances to quit. + time.sleep(1) + + raise + + + def terminate(self, termsig=None): + '''Handle termination signals and exit safely and cleanly.''' + + # Not required but at least it lets the user know what killed his + # browsing session. + if termsig == SIGTERM: + error("caught SIGTERM signal") + + elif termsig == SIGINT: + error("caught keyboard interrupt") + + else: + error("caught unknown signal") + + error("commencing infanticide!") + + # Sends the exit signal to all uzbl instances. + self.quitrequest() + + + def init_socket(self): + '''Create interprocess communication socket.''' + + def accept(sock, condition): + '''A new uzbl instance was created''' + + client, _ = sock.accept() + self.clients[client] = SocketClient(client) + + return True + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(self.socket_path) + sock.listen(1) + + # Add event handler for IO_IN event. + self._socket = (sock, io_add_watch(sock, IO_IN, accept)) + + echo("[socket] listening at %r" % self.socket_path) + + # Add atexit register to destroy the socket on program termination. + atexit.register(self.close_socket) + + + def close_socket(self): + '''Close the socket when closing the application''' + + if self._socket: + (fd, watcher) = self._socket + source_remove(watcher) + fd.close() + os.unlink(self.socket_path) + self._socket = None + + + def init_fifo(self): + '''Create interprocess communication fifo.''' + + if os.path.exists(self.fifo_path): + if not os.access(self.fifo_path, os.F_OK | os.R_OK | os.W_OK): + os.mkfifo(self.fifo_path) + + else: + basedir = os.path.dirname(self.fifo_path) + if not os.path.exists(basedir): + os.makedirs(basedir) + + os.mkfifo(self.fifo_path) + + # Add event handlers for IO_IN & IO_HUP events. + self.setup_fifo_watchers() + + echo("[fifo] listening at %r" % self.fifo_path) + + # Add atexit register to destroy the fifo on program termination. + atexit.register(self.unlink_fifo) + + + def unlink_fifo(self): + '''Unlink the fifo socket. Note: This function is called automatically + on exit by an atexit register.''' + + # Make sure the fifo fd is closed. + self.close_fifo() + + # And unlink if the real fifo exists. + if os.path.exists(self.fifo_path): + os.unlink(self.fifo_path) + echo("unlinked %r" % self.fifo_path) + + + def close_fifo(self): + '''Remove all event handlers watching the fifo and close the fd.''' + + # Already closed + if self._fifo is None: return + + (fd, watchers) = self._fifo + os.close(fd) + + # Stop all gobject io watchers watching the fifo. + for gid in watchers: + source_remove(gid) + + self._fifo = None + + + def setup_fifo_watchers(self): + '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event + handlers.''' + + # Close currently open fifo fd and kill all watchers + self.close_fifo() + + fd = os.open(self.fifo_path, os.O_RDONLY | os.O_NONBLOCK) + + # Add gobject io event handlers to the fifo socket. + watchers = [io_add_watch(fd, IO_IN, self.main_fifo_read),\ + io_add_watch(fd, IO_HUP, self.main_fifo_hangup)] + + self._fifo = (fd, watchers) + + + def main_fifo_hangup(self, fd, cb_condition): + '''Handle main fifo socket hangups.''' + + # Close old fd, open new fifo socket and add io event handlers. + self.setup_fifo_watchers() + + # Kill the gobject event handler calling this handler function. + return False + + + def main_fifo_read(self, fd, cb_condition): + '''Read from main fifo socket.''' + + self._buffer = os.read(fd, 1024) + temp = self._buffer.split("\n") + self._buffer = temp.pop() + cmds = [s.strip().split() for s in temp if len(s.strip())] + + for cmd in cmds: + try: + #print cmd + self.parse_command(cmd) + + except: + 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. + # 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] == "newfromclip": + uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ + stdout=subprocess.PIPE).communicate()[0] + if uri: + self.new_tab(uri) + + elif cmd[0] == "close": + if len(cmd) == 2: + self.close_tab(int(cmd[1])) + + else: + self.close_tab() + + elif cmd[0] == "next": + if len(cmd) == 2: + self.next_tab(int(cmd[1])) + + else: + self.next_tab() + + elif cmd[0] == "prev": + if len(cmd) == 2: + self.prev_tab(int(cmd[1])) + + else: + self.prev_tab() + + elif cmd[0] == "goto": + self.goto_tab(int(cmd[1])) + + elif cmd[0] == "first": + self.goto_tab(0) + + elif cmd[0] == "last": + self.goto_tab(-1) + + elif cmd[0] in ["title", "uri"]: + if len(cmd) > 2: + uzbl = self.get_tab_by_name(int(cmd[1])) + if uzbl: + old = getattr(uzbl, cmd[0]) + new = ' '.join(cmd[2:]) + setattr(uzbl, cmd[0], new) + if old != new: + self.update_tablist() + + else: + error("parse_command: no uzbl with name %r" % int(cmd[1])) + + elif cmd[0] == "preset": + if len(cmd) < 3: + error("parse_command: invalid preset command") + + elif cmd[1] == "save": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.save_session(path) + + elif cmd[1] == "load": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + self.load_session(path) + + elif cmd[1] == "del": + path = os.path.join(config['saved_sessions_dir'], cmd[2]) + if os.path.isfile(path): + os.remove(path) + + else: + error("parse_command: preset %r does not exist." % path) + + elif cmd[1] == "list": + uzbl = self.get_tab_by_name(int(cmd[2])) + if uzbl: + if not os.path.isdir(config['saved_sessions_dir']): + js = "js alert('No saved presets.');" + uzbl._client.send(js) + + else: + listdir = os.listdir(config['saved_sessions_dir']) + listdir = "\\n".join(listdir) + js = "js alert('Session presets:\\n\\n%s');" % listdir + uzbl._client.send(js) + + else: + error("parse_command: unknown tab name.") + + else: + error("parse_command: unknown parse command %r"\ + % ' '.join(cmd)) + + elif cmd[0] == "bring_to_front": + self.window.present() + + elif cmd[0] == "clean": + self.clean_slate() + + elif cmd[0] == "exit": + self.quitrequest() + + else: + error("parse_command: unknown command %r" % ' '.join(cmd)) + + + def get_tab_by_name(self, name): + '''Return uzbl instance by name.''' + + for (tab, uzbl) in self.tabs.items(): + if uzbl.name == name: + return uzbl + + return False + + + def new_tab(self, uri='', title='', switch=None): + '''Add a new tab to the notebook and start a new instance of uzbl. + Use the switch option to negate config['switch_to_new_tabs'] option + when you need to load multiple tabs at a time (I.e. like when + restoring a session from a file).''' + + tab = gtk.Socket() + tab.show() + self.notebook.append_page(tab) + sid = tab.get_id() + uri = uri.strip() + name = "%d-%d" % (os.getpid(), self.next_pid()) + + if switch is None: + switch = config['switch_to_new_tabs'] + + if not title: + title = config['new_tab_title'] + + cmd = ['uzbl-browser', '-n', name, '-s', str(sid), + '--connect-socket', self.socket_path, '--uri', uri] + subprocess.Popen(cmd) # TODO: do i need close_fds=True ? + + uzbl = UzblInstance(self, tab, name, uri, title, switch) + SocketClient.instances_queue[name] = uzbl + self.tabs[tab] = uzbl + + + def clean_slate(self): + '''Close all open tabs and open a fresh brand new one.''' + + self.new_tab() + tabs = self.tabs.keys() + for tab in list(self.notebook)[:-1]: + if tab not in tabs: continue + uzbl = self.tabs[tab] + uzbl.exit() + + + def config_uzbl(self, uzbl): + '''Send bind commands for tab new/close/next/prev to a uzbl + instance.''' + + # Set definitions here + # set(key, command back to fifo) + if config['capture_new_windows']: + uzbl.set("new_window", r'new $8') + + + def goto_tab(self, index): + '''Goto tab n (supports negative indexing).''' + + title_format = "%s - Uzbl Browser" + + tabs = list(self.notebook) + if 0 <= index < len(tabs): + self.notebook.set_current_page(index) + uzbl = self.tabs[self.notebook.get_nth_page(index)] + self.window.set_title(title_format % uzbl.title) + self.update_tablist() + return None + + try: + tab = tabs[index] + # Update index because index might have previously been a + # negative index. + index = tabs.index(tab) + self.notebook.set_current_page(index) + uzbl = self.tabs[self.notebook.get_nth_page(index)] + self.window.set_title(title_format % uzbl.title) + self.update_tablist() + + except IndexError: + pass + + + def next_tab(self, step=1): + '''Switch to next tab or n tabs right.''' + + if step < 1: + error("next_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = (self.notebook.get_current_page() + step) % ntabs + self.goto_tab(tabn) + + + def prev_tab(self, step=1): + '''Switch to prev tab or n tabs left.''' + + if step < 1: + error("prev_tab: invalid step %r" % step) + return None + + ntabs = self.notebook.get_n_pages() + tabn = self.notebook.get_current_page() - step + while tabn < 0: tabn += ntabs + self.goto_tab(tabn) + + + def close_tab(self, tabn=None): + '''Closes current tab. Supports negative indexing.''' + + if tabn is None: + tabn = self.notebook.get_current_page() + + else: + try: + tab = list(self.notebook)[tabn] + + except IndexError: + error("close_tab: invalid index %r" % tabn) + return None + + self.notebook.remove_page(tabn) + + + def tab_opened(self, notebook, tab, index): + '''Called upon tab creation. Called by page-added signal.''' + + if config['switch_to_new_tabs']: + self.notebook.set_focus_child(tab) + + else: + oldindex = self.notebook.get_current_page() + oldtab = self.notebook.get_nth_page(oldindex) + self.notebook.set_focus_child(oldtab) + + + def tab_closed(self, notebook, tab, index): + '''Close the window if no tabs are left. Called by page-removed + signal.''' + + if tab in self.tabs.keys(): + uzbl = self.tabs[tab] + uzbl.close() + + self._closed.append((uzbl.uri, uzbl.title)) + self._closed = self._closed[-10:] + del self.tabs[tab] + + if self.notebook.get_n_pages() == 0: + if not self._killed and config['save_session']: + if os.path.exists(config['session_file']): + os.remove(config['session_file']) + + self.quit() + + for tab in self.notebook: + self.tabs[tab].title_changed(True) + self.update_tablist() + + return True + + + def tab_changed(self, notebook, page, index): + '''Refresh tab list. Called by switch-page signal.''' + + tab = self.notebook.get_nth_page(index) + self.notebook.set_focus_child(tab) + self.update_tablist(index) + return True + + + def update_tablist_display(self): + '''Called when show_tablist or tablist_top has changed''' + + if self.ebox in self.vbox.get_children(): + self.vbox.remove(self.ebox) + + if config['show_tablist']: + self.vbox.pack_start(self.ebox, False, False, 0) + if config['tablist_top']: + self.vbox.reorder_child(self.ebox, 0) + else: + self.vbox.reorder_child(self.ebox, 2) + + def update_gtk_tab_pos(self): + ''' Called when gtk_tab_pos has changed ''' + + allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, + 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} + if config['gtk_tab_pos'] in allposes.keys(): + self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) + + + def update_tablist(self, curpage=None): + '''Upate tablist status bar.''' + + if not config['show_tablist']: + return True + + tab_titles = config['tab_titles'] + tab_indexes = config['tab_indexes'] + multiline_tabs = config['multiline_tabs'] + + if multiline_tabs: + multiline = [] + + tabs = self.tabs.keys() + if curpage is None: + curpage = self.notebook.get_current_page() + + pango = "" + normal = (config['tab_colours'], config['tab_text_colours']) + selected = (config['selected_tab'], config['selected_tab_text']) + + if tab_titles and tab_indexes: + tab_format = " [ %(index)d %(title)s ] " + elif tab_titles: + tab_format = " [ %(title)s ] " + else: + tab_format = " [ %(index)d ] " + + for index, tab in enumerate(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + title = escape(uzbl.tabtitle) + + style = colour_selector(index, curpage, uzbl) + (tabc, textc) = style + + if multiline_tabs: + opango = pango + + pango += tab_format % locals() + + self.tablist.set_markup(pango) + listwidth = self.tablist.get_layout().get_pixel_size()[0] + winwidth = self.window.get_size()[0] + + if listwidth > (winwidth - 20): + multiline.append(opango) + pango = tab_format % locals() + else: + pango += tab_format % locals() + + if multiline_tabs: + multiline.append(pango) + self.tablist.set_markup(' '.join(multiline)) + + else: + self.tablist.set_markup(pango) + + return True + + + def save_session(self, session_file=None): + '''Save the current session to file for restoration on next load.''' + + strip = str.strip + + if session_file is None: + session_file = config['session_file'] + + tabs = self.tabs.keys() + state = [] + for tab in list(self.notebook): + if tab not in tabs: continue + uzbl = self.tabs[tab] + if not uzbl.uri: continue + state += [(uzbl.uri, uzbl.title),] + + session = {'curtab': self.notebook.get_current_page(), + 'tabs': state} + + if config['json_session']: + raw = json.dumps(session) + + else: + lines = ["curtab = %d" % session['curtab'],] + for (uri, title) in session['tabs']: + lines += ["%s\t%s" % (strip(uri), strip(title)),] + + raw = "\n".join(lines) + + if not os.path.isfile(session_file): + dirname = os.path.dirname(session_file) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + h = open(session_file, 'w') + h.write(raw) + h.close() + + + def load_session(self, session_file=None): + '''Load a saved session from file.''' + + default_path = False + strip = str.strip + json_session = config['json_session'] + delete_loaded = False + + if session_file is None: + default_path = True + delete_loaded = True + session_file = config['session_file'] + + if not os.path.isfile(session_file): + return False + + h = open(session_file, 'r') + raw = h.read() + h.close() + if json_session: + if sum([1 for s in raw.split("\n") if strip(s)]) != 1: + error("Warning: The session file %r does not look json. "\ + "Trying to load it as a non-json session file."\ + % session_file) + json_session = False + + if json_session: + try: + session = json.loads(raw) + curtab, tabs = session['curtab'], session['tabs'] + + except: + error("Failed to load jsonifed session from %r"\ + % session_file) + return None + + else: + tabs = [] + strip = str.strip + curtab, tabs = 0, [] + lines = [s for s in raw.split("\n") if strip(s)] + if len(lines) < 2: + error("Warning: The non-json session file %r looks invalid."\ + % session_file) + return None + + try: + for line in lines: + if line.startswith("curtab"): + curtab = int(line.split()[-1]) + + else: + uri, title = line.split("\t",1) + tabs += [(strip(uri), strip(title)),] + + except: + error("Warning: failed to load session file %r" % session_file) + return None + + session = {'curtab': curtab, 'tabs': tabs} + + # Now populate notebook with the loaded session. + for (index, (uri, title)) in enumerate(tabs): + self.new_tab(uri=uri, title=title, switch=(curtab==index)) + + # A saved session has been loaded now delete it. + if delete_loaded and os.path.exists(session_file): + os.remove(session_file) + + # There may be other state information in the session dict of use to + # other functions. Of course however the non-json session object is + # just a dummy object of no use to no one. + return session + + + def quitrequest(self, *args): + '''Attempt to close all uzbl instances nicely and exit.''' + + self._killed = True + + if config['save_session']: + if len(list(self.notebook)) > 1: + self.save_session() + + else: + # Notebook has one page open so delete the session file. + if os.path.isfile(config['session_file']): + os.remove(config['session_file']) + + for (tab, uzbl) in self.tabs.items(): + uzbl.exit() + + # Add a gobject timer to make sure the application force-quits after a + # reasonable period. Calling quit when all the tabs haven't had time to + # close should be a last resort. + timer = "force-quit" + timerid = timeout_add(5000, self.quit, timer) + self._timers[timer] = timerid + + + def quit(self, *args): + '''Cleanup and quit. Called by delete-event signal.''' + + # Close the fifo socket, remove any gobject io event handlers and + # delete socket. + self.unlink_fifo() + self.close_socket() + + # Remove all gobject timers that are still ticking. + for (timerid, gid) in self._timers.items(): + source_remove(gid) + del self._timers[timerid] + + try: + gtk.main_quit() + + except: + pass + + +if __name__ == "__main__": + + # Build command line parser + usage = "usage: %prog [OPTIONS] {URIS}..." + parser = OptionParser(usage=usage) + parser.add_option('-n', '--no-session', dest='nosession', + action='store_true', help="ignore session saving a loading.") + parser.add_option('-v', '--verbose', dest='verbose', + action='store_true', help='print verbose output.') + + # Parse command line options + (options, uris) = parser.parse_args() + + if options.nosession: + config['save_session'] = False + + if options.verbose: + config['verbose'] = True + + if config['json_session']: + try: + import simplejson as json + + except: + error("Warning: json_session set but cannot import the python "\ + "module simplejson. Fix: \"set json_session = 0\" or "\ + "install the simplejson python module to remove this warning.") + config['json_session'] = False + + if config['verbose']: + import pprint + sys.stderr.write("%s\n" % pprint.pformat(config)) + + uzbl = UzblTabbed() + + # All extra arguments given to uzbl_tabbed.py are interpreted as + # web-locations to opened in new tabs. + lasturi = len(uris)-1 + for (index,uri) in enumerate(uris): + uzbl.new_tab(uri, switch=(index==lasturi)) + + uzbl.run() diff --git a/examples/data/scripts/uzblcat b/examples/data/scripts/uzblcat new file mode 100755 index 0000000..e955608 --- /dev/null +++ b/examples/data/scripts/uzblcat @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# uzblcat - safely push html to uzbl +# See http://www.uzbl.org/wiki/html-mode + +from sys import stdin, stdout + +stdout.write("uri data:text/html,") +for line in stdin: + stdout.write(line[0:-1]) + +# vim: set noet ff=unix + diff --git a/examples/data/style.css b/examples/data/style.css new file mode 100644 index 0000000..f9b111e --- /dev/null +++ b/examples/data/style.css @@ -0,0 +1,25 @@ +.uzbl_highlight { background-color: yellow;} +.uzbl_h_first { background-color: lightgreen;} + +.uzbl_follow { border-style: dotted; + border-width: thin; +} + +#uzbl_hint > div { + display: inline; + border: 2px solid #4a6600; + background-color: #b9ff00; + color: black; + font-size: 9px; + font-weight: bold; + line-height: 9px; + margin: 0px; + padding: 0px; + position: absolute; + z-index: 1000; + -webkit-border-radius: 6px; + text-decoration: none; + -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); +} + +/* vim:set et ts=4: */ diff --git a/examples/data/uzbl.png b/examples/data/uzbl.png new file mode 100644 index 0000000..773ea84 Binary files /dev/null and b/examples/data/uzbl.png differ diff --git a/examples/data/uzbl/bookmarks b/examples/data/uzbl/bookmarks deleted file mode 100644 index 13fcd48..0000000 --- a/examples/data/uzbl/bookmarks +++ /dev/null @@ -1,4 +0,0 @@ -http://www.archlinux.org linux arch -http://www.uzbl.org uzbl browser -http://dieter.plaetinck.be uzbl -http://www.icanhascheezburger.com lolcats fun diff --git a/examples/data/uzbl/forms/bbs.archlinux.org b/examples/data/uzbl/forms/bbs.archlinux.org deleted file mode 100644 index 73c1539..0000000 --- a/examples/data/uzbl/forms/bbs.archlinux.org +++ /dev/null @@ -1,5 +0,0 @@ -form_sent: -redirect_url: -req_username: -req_password: -login: diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py deleted file mode 100644 index 9e09337..0000000 --- a/examples/data/uzbl/plugins/bind.py +++ /dev/null @@ -1,521 +0,0 @@ -'''Plugin provides support for binds in uzbl. - -For example: - event BIND ZZ = exit -> bind('ZZ', 'exit') - event BIND o _ = uri %s -> bind('o _', 'uri %s') - event BIND fl* = sh 'echo %s' -> bind('fl*', "sh 'echo %s'") - -And it is also possible to execute a function on activation: - bind('DD', myhandler) -''' - -import sys -import re -import pprint - -# Hold the bind dicts for each uzbl instance. -UZBLS = {} - -# Commonly used regular expressions. -MOD_START = re.compile('^<([A-Z][A-Za-z0-9-_]*)>').match -# Matches , <'x':y>, <:'y'>, , <'x'!y>, ... -PROMPTS = '<(\"[^\"]*\"|\'[^\']*\'|[^:!>]*)(:|!)(\"[^\"]*\"|\'[^\']*\'|[^>]*)>' -FIND_PROMPTS = re.compile(PROMPTS).split -VALID_MODE = re.compile('^(-|)[A-Za-z0-9][A-Za-z0-9_]*$').match - -# For accessing a bind glob stack. -ON_EXEC, HAS_ARGS, MOD_CMD, GLOB, MORE = range(5) - - -# Custom errors. -class ArgumentError(Exception): pass - - -class Bindlet(object): - '''Per-instance bind status/state tracker.''' - - def __init__(self, uzbl): - self.binds = {'global': {}} - self.uzbl = uzbl - self.depth = 0 - self.args = [] - self.last_mode = None - self.after_cmds = None - self.stack_binds = [] - - # A subset of the global mode binds containing non-stack and modkey - # activiated binds for use in the stack mode. - self.globals = [] - - - def __getitem__(self, key): - return self.get_binds(key) - - - def reset(self): - '''Reset the tracker state and return to last mode.''' - - self.depth = 0 - self.args = [] - self.after_cmds = None - self.stack_binds = [] - - if self.last_mode: - mode, self.last_mode = self.last_mode, None - self.uzbl.set_mode(mode) - - self.uzbl.set('keycmd_prompt') - - - def stack(self, bind, args, depth): - '''Enter or add new bind in the next stack level.''' - - if self.depth != depth: - if bind not in self.stack_binds: - self.stack_binds.append(bind) - - return - - current_mode = self.uzbl.get_mode() - if current_mode != 'stack': - self.last_mode = current_mode - self.uzbl.set_mode('stack') - - self.stack_binds = [bind,] - self.args += args - self.depth += 1 - self.after_cmds = bind.prompts[depth] - - - def after(self): - '''If a stack was triggered then set the prompt and default value.''' - - if self.after_cmds is None: - return - - (prompt, is_cmd, set), self.after_cmds = self.after_cmds, None - - self.uzbl.clear_keycmd() - if prompt: - self.uzbl.set('keycmd_prompt', prompt) - - if set and is_cmd: - self.uzbl.send(set) - - elif set and not is_cmd: - self.uzbl.send('event SET_KEYCMD %s' % set) - - - def get_binds(self, mode=None): - '''Return the mode binds + globals. If we are stacked then return - the filtered stack list and modkey & non-stack globals.''' - - if mode is None: - mode = self.uzbl.get_mode() - - if not mode: - mode = 'global' - - if self.depth: - return self.stack_binds + self.globals - - globals = self.binds['global'] - if mode not in self.binds or mode == 'global': - return filter(None, globals.values()) - - binds = dict(globals.items() + self.binds[mode].items()) - return filter(None, binds.values()) - - - def add_bind(self, mode, glob, bind=None): - '''Insert (or override) a bind into the mode bind dict.''' - - if mode not in self.binds: - self.binds[mode] = {glob: bind} - return - - binds = self.binds[mode] - binds[glob] = bind - - if mode == 'global': - # Regen the global-globals list. - self.globals = [] - for bind in binds.values(): - if bind is not None and bind.is_global: - self.globals.append(bind) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = Bindlet(uzbl) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_bindlet(uzbl): - '''Return the bind tracklet for the given uzbl instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def ismodbind(glob): - '''Return True if the glob specifies a modbind.''' - - return bool(MOD_START(glob)) - - -def split_glob(glob): - '''Take a string of the form "cmd _" and return a list of the - modkeys in the glob and the command.''' - - mods = set() - while True: - match = MOD_START(glob) - if not match: - break - - end = match.span()[1] - mods.add(glob[:end]) - glob = glob[end:] - - 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. - counter = [0,] - - def __init__(self, glob, handler, *args, **kargs): - self.is_callable = callable(handler) - self._repr_cache = None - - if not glob: - raise ArgumentError('glob cannot be blank') - - if self.is_callable: - self.function = handler - self.args = args - self.kargs = kargs - - elif kargs: - raise ArgumentError('cannot supply kargs for uzbl commands') - - elif hasattr(handler, '__iter__'): - self.commands = handler - - else: - self.commands = [handler,] + list(args) - - self.glob = glob - - # Assign unique id. - self.counter[0] += 1 - self.bid = self.counter[0] - - self.split = split = FIND_PROMPTS(glob) - self.prompts = [] - for (prompt, cmd, set) in zip(split[1::4], split[2::4], split[3::4]): - prompt, set = map(unquote, [prompt, set]) - cmd = True if cmd == '!' else False - if prompt and prompt[-1] != ":": - prompt = "%s:" % prompt - - self.prompts.append((prompt, cmd, set)) - - # Check that there is nothing like: fl** - for glob in split[:-1:4]: - if glob.endswith('*'): - msg = "token '*' not at the end of a prompt bind: %r" % split - raise SyntaxError(msg) - - # Check that there is nothing like: fl_ - for glob in split[4::4]: - if not glob: - msg = 'found null segment after first prompt: %r' % split - raise SyntaxError(msg) - - stack = [] - for (index, glob) in enumerate(reversed(split[::4])): - # Is the binding a MODCMD or KEYCMD: - mod_cmd = ismodbind(glob) - - # Do we execute on UPDATES or EXEC events? - on_exec = True if glob[-1] in ['!', '_'] else False - - # Does the command take arguments? - has_args = True if glob[-1] in ['*', '_'] else False - - glob = glob[:-1] if has_args or on_exec else glob - mods, glob = split_glob(glob) - stack.append((on_exec, has_args, mods, glob, index)) - - self.stack = list(reversed(stack)) - self.is_global = (len(self.stack) == 1 and self.stack[0][MOD_CMD]) - - - def __getitem__(self, depth): - '''Get bind info at a depth.''' - - if self.is_global: - return self.stack[0] - - return self.stack[depth] - - - def __repr__(self): - if self._repr_cache: - return self._repr_cache - - args = ['glob=%r' % self.glob, 'bid=%d' % self.bid] - - if self.is_callable: - args.append('function=%r' % self.function) - if self.args: - args.append('args=%r' % self.args) - - if self.kargs: - args.append('kargs=%r' % self.kargs) - - else: - cmdlen = len(self.commands) - cmds = self.commands[0] if cmdlen == 1 else self.commands - args.append('command%s=%r' % ('s' if cmdlen-1 else '', cmds)) - - self._repr_cache = '' % ', '.join(args) - return self._repr_cache - - -def exec_bind(uzbl, bind, *args, **kargs): - '''Execute bind objects.''' - - uzbl.event("EXEC_BIND", bind, args, kargs) - - if bind.is_callable: - args += bind.args - kargs = dict(bind.kargs.items()+kargs.items()) - bind.function(uzbl, *args, **kargs) - return - - if kargs: - raise ArgumentError('cannot supply kargs for uzbl commands') - - commands = [] - cmd_expand = uzbl.cmd_expand - for cmd in bind.commands: - cmd = cmd_expand(cmd, args) - uzbl.send(cmd) - - -def mode_bind(uzbl, modes, glob, handler=None, *args, **kargs): - '''Add a mode bind.''' - - bindlet = get_bindlet(uzbl) - - if not hasattr(modes, '__iter__'): - modes = unicode(modes).split(',') - - # Sort and filter binds. - modes = filter(None, map(unicode.strip, modes)) - - if callable(handler) or (handler is not None and handler.strip()): - bind = Bind(glob, handler, *args, **kargs) - - else: - bind = None - - for mode in modes: - if not VALID_MODE(mode): - raise NameError('invalid mode name: %r' % mode) - - for mode in modes: - if mode[0] == '-': - mode, bind = mode[1:], None - - bindlet.add_bind(mode, glob, bind) - uzbl.event('ADDED_MODE_BIND', mode, glob, bind) - - -def bind(uzbl, glob, handler, *args, **kargs): - '''Legacy bind function.''' - - mode_bind(uzbl, 'global', glob, handler, *args, **kargs) - - -def parse_mode_bind(uzbl, args): - '''Parser for the MODE_BIND event. - - Example events: - MODE_BIND = - MODE_BIND command o_ = uri %s - MODE_BIND insert,command = ... - MODE_BIND global ... = ... - MODE_BIND global,-insert ... = ... - ''' - - if not args: - raise ArgumentError('missing bind arguments') - - split = map(unicode.strip, args.split(' ', 1)) - if len(split) != 2: - raise ArgumentError('missing mode or bind section: %r' % args) - - modes, args = split[0].split(','), split[1] - split = map(unicode.strip, args.split('=', 1)) - if len(split) != 2: - raise ArgumentError('missing delimiter in bind section: %r' % args) - - glob, command = split - mode_bind(uzbl, modes, glob, command) - - -def parse_bind(uzbl, args): - '''Legacy parsing of the BIND event and conversion to the new format. - - Example events: - request BIND = - request BIND o_ = uri %s - request BIND = ... - request BIND ... = ... - ''' - - parse_mode_bind(uzbl, "global %s" % args) - - -def mode_changed(uzbl, mode): - '''Clear the stack on all non-stack mode changes.''' - - if mode != 'stack': - get_bindlet(uzbl).reset() - - -def match_and_exec(uzbl, bind, depth, keylet, bindlet): - - (on_exec, has_args, mod_cmd, glob, more) = bind[depth] - cmd = keylet.modcmd if mod_cmd else keylet.keycmd - - if mod_cmd and keylet.held != mod_cmd: - return False - - if has_args: - if not cmd.startswith(glob): - return False - - args = [cmd[len(glob):],] - - elif cmd != glob: - return False - - else: - args = [] - - if bind.is_global or (not more and depth == 0): - exec_bind(uzbl, bind, *args) - if not has_args: - uzbl.clear_current() - - return True - - elif more: - bindlet.stack(bind, args, depth) - return False - - args = bindlet.args + args - exec_bind(uzbl, bind, *args) - uzbl.set_mode() - if not has_args: - bindlet.reset() - uzbl.clear_current() - - return True - - -def keycmd_update(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if t[MOD_CMD] or t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return - - bindlet.after() - - -def keycmd_exec(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if t[MOD_CMD] or not t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return uzbl.clear_keycmd() - - bindlet.after() - - -def modcmd_update(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if not t[MOD_CMD] or t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return - - bindlet.after() - - -def modcmd_exec(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if not t[MOD_CMD] or not t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return uzbl.clear_modcmd() - - bindlet.after() - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'BIND': parse_bind, - 'KEYCMD_EXEC': keycmd_exec, - 'KEYCMD_UPDATE': keycmd_update, - 'MODCMD_EXEC': modcmd_exec, - 'MODCMD_UPDATE': modcmd_update, - 'MODE_BIND': parse_mode_bind, - 'MODE_CHANGED': mode_changed, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'bind': bind, - 'mode_bind': mode_bind, - 'get_bindlet': get_bindlet, - }) diff --git a/examples/data/uzbl/plugins/cmd_expand.py b/examples/data/uzbl/plugins/cmd_expand.py deleted file mode 100644 index 3f6ae2b..0000000 --- a/examples/data/uzbl/plugins/cmd_expand.py +++ /dev/null @@ -1,42 +0,0 @@ -def escape(str): - for (level, char) in [(3, '\\'), (2, "'"), (2, '"'), (1, '@')]: - str = str.replace(char, (level * '\\') + char) - - return str - - -def cmd_expand(uzbl, cmd, args): - '''Exports a function that provides the following - expansions in any uzbl command string: - - %s = replace('%s', ' '.join(args)) - %r = replace('%r', "'%s'" % escaped(' '.join(args))) - %1 = replace('%1', arg[0]) - %2 = replace('%2', arg[1]) - %n = replace('%n', arg[n-1]) - ''' - - # Ensure (1) all string representable and (2) correct string encoding. - args = map(unicode, args) - - # Direct string replace. - if '%s' in cmd: - cmd = cmd.replace('%s', ' '.join(args)) - - # Escaped and quoted string replace. - if '%r' in cmd: - cmd = cmd.replace('%r', "'%s'" % escape(' '.join(args))) - - # Arg index string replace. - for (index, arg) in enumerate(args): - index += 1 - if '%%%d' % index in cmd: - cmd = cmd.replace('%%%d' % index, unicode(arg)) - - return cmd - - -def init(uzbl): - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export('cmd_expand', cmd_expand) diff --git a/examples/data/uzbl/plugins/completion.py b/examples/data/uzbl/plugins/completion.py deleted file mode 100644 index 8cea203..0000000 --- a/examples/data/uzbl/plugins/completion.py +++ /dev/null @@ -1,206 +0,0 @@ -'''Keycmd completion.''' - -# A list of functions this plugin exports to be used via uzbl object. -__export__ = ['start_completion', 'get_completion_dict'] - -import re - -# Holds the per-instance completion dicts. -UZBLS = {} - -# Completion level -NONE, ONCE, LIST, COMPLETE = range(4) - -# Default instance dict. -DEFAULTS = {'completions': [], 'level': NONE, 'lock': False} - -# The reverse keyword finding re. -FIND_SEGMENT = re.compile("(\@[\w_]+|set[\s]+[\w_]+|[\w_]+)$").findall - -# Formats -LIST_FORMAT = " %s " -ITEM_FORMAT = "%s%s" - - -def escape(str): - return str.replace("@", "\@") - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - # Make sure the config keys for all possible completions are known. - uzbl.send('dump_config_as_events') - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_completion_dict(uzbl): - '''Get data stored for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def get_incomplete_keyword(uzbl): - '''Gets the segment of the keycmd leading up to the cursor position and - uses a regular expression to search backwards finding parially completed - keywords or @variables. Returns a null string if the correct completion - conditions aren't met.''' - - keylet = uzbl.get_keylet() - left_segment = keylet.keycmd[:keylet.cursor] - partial = (FIND_SEGMENT(left_segment) + ['',])[0].lstrip() - if partial.startswith('set '): - return ('@%s' % partial[4:].lstrip(), True) - - return (partial, False) - - -def stop_completion(uzbl, *args): - '''Stop command completion and return the level to NONE.''' - - d = get_completion_dict(uzbl) - d['level'] = NONE - uzbl.set('completion_list') - - -def complete_completion(uzbl, partial, hint, set_completion=False): - '''Inject the remaining porition of the keyword into the keycmd then stop - the completioning.''' - - if set_completion: - remainder = "%s = " % hint[len(partial):] - - else: - remainder = "%s " % hint[len(partial):] - - uzbl.inject_keycmd(remainder) - stop_completion(uzbl) - - -def partial_completion(uzbl, partial, hint): - '''Inject a common portion of the hints into the keycmd.''' - - remainder = hint[len(partial):] - uzbl.inject_keycmd(remainder) - - -def update_completion_list(uzbl, *args): - '''Checks if the user still has a partially completed keyword under his - cursor then update the completion hints list.''' - - partial = get_incomplete_keyword(uzbl)[0] - if not partial: - return stop_completion(uzbl) - - d = get_completion_dict(uzbl) - if d['level'] < LIST: - return - - hints = [h for h in d['completions'] if h.startswith(partial)] - if not hints: - return uzbl.set('completion_list') - - j = len(partial) - l = [ITEM_FORMAT % (escape(h[:j]), h[j:]) for h in sorted(hints)] - uzbl.set('completion_list', LIST_FORMAT % ' '.join(l)) - - -def start_completion(uzbl, *args): - - d = get_completion_dict(uzbl) - if d['lock']: - return - - (partial, set_completion) = get_incomplete_keyword(uzbl) - if not partial: - return stop_completion(uzbl) - - if d['level'] < COMPLETE: - d['level'] += 1 - - hints = [h for h in d['completions'] if h.startswith(partial)] - if not hints: - return - - elif len(hints) == 1: - d['lock'] = True - complete_completion(uzbl, partial, hints[0], set_completion) - d['lock'] = False - return - - elif partial in hints and d['level'] == COMPLETE: - d['lock'] = True - complete_completion(uzbl, partial, partial, set_completion) - d['lock'] = False - return - - smalllen, smallest = sorted([(len(h), h) for h in hints])[0] - common = '' - for i in range(len(partial), smalllen): - char, same = smallest[i], True - for hint in hints: - if hint[i] != char: - same = False - break - - if not same: - break - - common += char - - if common: - d['lock'] = True - partial_completion(uzbl, partial, partial+common) - d['lock'] = False - - update_completion_list(uzbl) - - -def add_builtins(uzbl, args): - '''Pump the space delimited list of builtin commands into the - builtin list.''' - - completions = get_completion_dict(uzbl)['completions'] - builtins = filter(None, map(unicode.strip, args.split(" "))) - for builtin in builtins: - if builtin not in completions: - completions.append(builtin) - - -def add_config_key(uzbl, key, value): - '''Listen on the CONFIG_CHANGED event and add config keys to the variable - list for @var like expansion support.''' - - completions = get_completion_dict(uzbl)['completions'] - key = "@%s" % key - if key not in completions: - completions.append(key) - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'BUILTINS': add_builtins, - 'CONFIG_CHANGED': add_config_key, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'KEYCMD_CLEARED': stop_completion, - 'KEYCMD_EXEC': stop_completion, - 'KEYCMD_UPDATE': update_completion_list, - 'START_COMPLETION': start_completion, - 'STOP_COMPLETION': stop_completion, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_completion_dict': get_completion_dict, - 'start_completion': start_completion, - }) diff --git a/examples/data/uzbl/plugins/config.py b/examples/data/uzbl/plugins/config.py deleted file mode 100644 index 4a848a3..0000000 --- a/examples/data/uzbl/plugins/config.py +++ /dev/null @@ -1,97 +0,0 @@ -import re -import types - -__export__ = ['set', 'get_config'] - -VALIDKEY = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$").match -TYPECONVERT = {'int': int, 'float': float, 'str': unicode} - -UZBLS = {} - - -def escape(value): - '''A real escaping function may be required.''' - - return unicode(value) - - -def set(uzbl, key, value='', config=None, force=False): - '''Sends a: "set key = value" command to the uzbl instance. If force is - False then only send a set command if the values aren't equal.''' - - if type(value) == types.BooleanType: - value = int(value) - - else: - value = unicode(value) - - if not VALIDKEY(key): - raise KeyError("%r" % key) - - value = escape(value) - if '\n' in value: - value = value.replace("\n", "\\n") - - if not force: - if config is None: - config = get_config(uzbl) - - if key in config and config[key] == value: - return - - uzbl.send('set %s = %s' % (key, value)) - - -class ConfigDict(dict): - def __init__(self, uzbl): - self._uzbl = uzbl - - def __setitem__(self, key, value): - '''Makes "config[key] = value" a wrapper for the set function.''' - - set(self._uzbl, key, value, config=self) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = ConfigDict(uzbl) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del uzbl - - -def get_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def variable_set(uzbl, args): - config = get_config(uzbl) - - key, type, value = list(args.split(' ', 2) + ['',])[:3] - old = config[key] if key in config else None - value = TYPECONVERT[type](value) - - dict.__setitem__(config, key, value) - - if old != value: - uzbl.event("CONFIG_CHANGED", key, value) - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'VARIABLE_SET': variable_set, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_config': get_config, - 'set': set, - }) diff --git a/examples/data/uzbl/plugins/keycmd.py b/examples/data/uzbl/plugins/keycmd.py deleted file mode 100644 index c119077..0000000 --- a/examples/data/uzbl/plugins/keycmd.py +++ /dev/null @@ -1,571 +0,0 @@ -import re - -# Hold the keylets. -UZBLS = {} - -# Keycmd format which includes the markup for the cursor. -KEYCMD_FORMAT = "%s%s%s" -MODCMD_FORMAT = " %s " - - -def escape(str): - for char in ['\\', '@']: - str = str.replace(char, '\\'+char) - - return str - - -def uzbl_escape(str): - return "@[%s]@" % escape(str) if str else '' - - -class Keylet(object): - '''Small per-instance object that tracks all the keys held and characters - typed.''' - - def __init__(self): - # Modcmd tracking - self.held = set() - self.ignored = set() - self.modcmd = '' - self.is_modcmd = False - - # Keycmd tracking - self.keycmd = '' - self.cursor = 0 - - self.modmaps = {} - self.ignores = {} - self.additions = {} - - # Keylet string repr cache. - self._repr_cache = None - - - def get_keycmd(self): - '''Get the keycmd-part of the keylet.''' - - return self.keycmd - - - def get_modcmd(self): - '''Get the modcmd-part of the keylet.''' - - if not self.is_modcmd: - return '' - - return ''.join(self.held) + self.modcmd - - - def modmap_key(self, key): - '''Make some obscure names for some keys friendlier.''' - - if key in self.modmaps: - return self.modmaps[key] - - elif key.endswith('_L') or key.endswith('_R'): - # Remove left-right discrimination and try again. - return self.modmap_key(key[:-2]) - - else: - return key - - - def find_addition(self, modkey): - '''Key has just been pressed, check if this key + the held list - results in a modkey addition. Return that addition and remove all - modkeys that created it.''' - - # Intersection of (held list + modkey) and additions. - added = (self.held | set([modkey])) & set(self.additions.keys()) - for key in added: - if key == modkey or modkey in self.additions[key]: - self.held -= self.additions[key] - return key - - # Held list + ignored list + modkey. - modkeys = self.held | self.ignored | set([modkey]) - for (key, value) in self.additions.items(): - if modkeys.issuperset(value): - self.held -= value - return key - - return modkey - - - def key_ignored(self, key): - '''Check if the given key is ignored by any ignore rules.''' - - for (glob, match) in self.ignores.items(): - if match(key): - return True - - return False - - - def __repr__(self): - '''Return a string representation of the keylet.''' - - if self._repr_cache: - return self._repr_cache - - l = [] - if self.is_modcmd: - l.append('modcmd=%r' % self.get_modcmd()) - - elif self.held: - l.append('held=%r' % ''.join(sorted(self.held))) - - if self.keycmd: - l.append('keycmd=%r' % self.get_keycmd()) - - self._repr_cache = '' % ', '.join(l) - return self._repr_cache - - -def add_modmap(uzbl, key, map): - '''Add modmaps. - - Examples: - set modmap = request MODMAP - @modmap - @modmap - ... - - Then: - @bind = - @bind x = - ... - - ''' - - assert len(key) - modmaps = get_keylet(uzbl).modmaps - - if key[0] == "<" and key[-1] == ">": - key = key[1:-1] - - modmaps[key] = map - uzbl.event("NEW_MODMAP", key, map) - - -def modmap_parse(uzbl, map): - '''Parse a modmap definiton.''' - - split = [s.strip() for s in map.split(' ') if s.split()] - - if not split or len(split) > 2: - raise Exception('Invalid modmap arugments: %r' % map) - - add_modmap(uzbl, *split) - - -def add_key_ignore(uzbl, glob): - '''Add an ignore definition. - - Examples: - set ignore_key = request IGNORE_KEY - @ignore_key - @ignore_key - ... - ''' - - assert len(glob) > 1 - ignores = get_keylet(uzbl).ignores - - glob = "<%s>" % glob.strip("<> ") - restr = glob.replace('*', '[^\s]*') - match = re.compile(restr).match - - ignores[glob] = match - uzbl.event('NEW_KEY_IGNORE', glob) - - -def add_modkey_addition(uzbl, modkeys, result): - '''Add a modkey addition definition. - - Examples: - set mod_addition = request MODKEY_ADDITION - @mod_addition - @mod_addition - @mod_addition - ... - - Then: - @bind = - @bind o = - ... - ''' - - additions = get_keylet(uzbl).additions - modkeys = set(modkeys) - - assert len(modkeys) and result and result not in modkeys - - for (existing_result, existing_modkeys) in additions.items(): - if existing_result != result: - assert modkeys != existing_modkeys - - additions[result] = modkeys - uzbl.event('NEW_MODKEY_ADDITION', modkeys, result) - - -def modkey_addition_parse(uzbl, modkeys): - '''Parse modkey addition definition.''' - - keys = filter(None, map(unicode.strip, modkeys.split(" "))) - keys = ['<%s>' % key.strip("<>") for key in keys if key.strip("<>")] - - assert len(keys) > 1 - add_modkey_addition(uzbl, keys[:-1], keys[-1]) - - -def add_instance(uzbl, *args): - '''Create the Keylet object for this uzbl instance.''' - - UZBLS[uzbl] = Keylet() - - -def del_instance(uzbl, *args): - '''Delete the Keylet object for this uzbl instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_keylet(uzbl): - '''Return the corresponding keylet for this uzbl instance.''' - - # Startup events are not correctly captured and sent over the uzbl socket - # yet so this line is needed because the INSTANCE_START event is lost. - if uzbl not in UZBLS: - add_instance(uzbl) - - keylet = UZBLS[uzbl] - keylet._repr_cache = False - return keylet - - -def clear_keycmd(uzbl): - '''Clear the keycmd for this uzbl instance.''' - - k = get_keylet(uzbl) - k.keycmd = '' - k.cursor = 0 - k._repr_cache = False - uzbl.set('keycmd') - uzbl.set('raw_keycmd') - uzbl.event('KEYCMD_CLEARED') - - -def clear_modcmd(uzbl, clear_held=False): - '''Clear the modcmd for this uzbl instance.''' - - k = get_keylet(uzbl) - k.modcmd = '' - k.is_modcmd = False - k._repr_cache = False - if clear_held: - k.ignored = set() - k.held = set() - - uzbl.set('modcmd') - uzbl.set('raw_modcmd') - uzbl.event('MODCMD_CLEARED') - - -def clear_current(uzbl): - '''Clear the modcmd if is_modcmd else clear keycmd.''' - - k = get_keylet(uzbl) - if k.is_modcmd: - clear_modcmd(uzbl) - - else: - clear_keycmd(uzbl) - - -def focus_changed(uzbl, *args): - '''Focus to the uzbl instance has now been lost which means all currently - held keys in the held list will not get a KEY_RELEASE event so clear the - entire held list.''' - - clear_modcmd(uzbl, clear_held=True) - - -def update_event(uzbl, k, execute=True): - '''Raise keycmd & modcmd update events.''' - - config = uzbl.get_config() - keycmd, modcmd = k.get_keycmd(), k.get_modcmd() - - if k.is_modcmd: - uzbl.event('MODCMD_UPDATE', k) - - else: - uzbl.event('KEYCMD_UPDATE', k) - - if 'modcmd_updates' not in config or config['modcmd_updates'] == '1': - new_modcmd = k.get_modcmd() - if not new_modcmd: - uzbl.set('modcmd', config=config) - uzbl.set('raw_modcmd', config=config) - - elif new_modcmd == modcmd: - uzbl.set('raw_modcmd', escape(modcmd), config=config) - uzbl.set('modcmd', MODCMD_FORMAT % uzbl_escape(modcmd), - config=config) - - if 'keycmd_events' in config and config['keycmd_events'] != '1': - return - - new_keycmd = k.get_keycmd() - if not new_keycmd: - uzbl.set('keycmd', config=config) - uzbl.set('raw_keycmd', config=config) - - elif new_keycmd == keycmd: - # Generate the pango markup for the cursor in the keycmd. - curchar = keycmd[k.cursor] if k.cursor < len(keycmd) else ' ' - chunks = [keycmd[:k.cursor], curchar, keycmd[k.cursor+1:]] - value = KEYCMD_FORMAT % tuple(map(uzbl_escape, chunks)) - uzbl.set('keycmd', value, config=config) - uzbl.set('raw_keycmd', escape(keycmd), config=config) - - -def inject_str(str, index, inj): - '''Inject a string into string at at given index.''' - - return "%s%s%s" % (str[:index], inj, str[index:]) - - -def get_keylet_and_key(uzbl, key, add=True): - '''Return the keylet and apply any transformations to the key as defined - by the modmapping or modkey addition rules. Return None if the key is - ignored.''' - - keylet = get_keylet(uzbl) - key = keylet.modmap_key(key) - if len(key) == 1: - return (keylet, key) - - modkey = "<%s>" % key.strip("<>") - - if keylet.key_ignored(modkey): - if add: - keylet.ignored.add(modkey) - - elif modkey in keylet.ignored: - keylet.ignored.remove(modkey) - - modkey = keylet.find_addition(modkey) - - if keylet.key_ignored(modkey): - return (keylet, None) - - return (keylet, modkey) - - -def key_press(uzbl, key): - '''Handle KEY_PRESS events. Things done by this function include: - - 1. Ignore all shift key presses (shift can be detected by capital chars) - 3. In non-modcmd mode: - a. append char to keycmd - 4. If not in modcmd mode and a modkey was pressed set modcmd mode. - 5. If in modcmd mode the pressed key is added to the held keys list. - 6. Keycmd is updated and events raised if anything is changed.''' - - (k, key) = get_keylet_and_key(uzbl, key.strip()) - if not key: - return - - if key.lower() == '' and not k.held and k.keycmd: - k.keycmd = inject_str(k.keycmd, k.cursor, ' ') - k.cursor += 1 - - elif not k.held and len(key) == 1: - config = uzbl.get_config() - if 'keycmd_events' in config and config['keycmd_events'] != '1': - k.keycmd = '' - k.cursor = 0 - uzbl.set('keycmd', config=config) - uzbl.set('raw_keycmd', config=config) - return - - k.keycmd = inject_str(k.keycmd, k.cursor, key) - k.cursor += 1 - - elif len(key) > 1: - k.is_modcmd = True - if key not in k.held: - k.held.add(key) - - else: - k.is_modcmd = True - k.modcmd += key - - update_event(uzbl, k) - - -def key_release(uzbl, key): - '''Respond to KEY_RELEASE event. Things done by this function include: - - 1. Remove the key from the keylet held list. - 2. If in a mod-command then raise a MODCMD_EXEC. - 3. Check if any modkey is held, if so set modcmd mode. - 4. Update the keycmd uzbl variable if anything changed.''' - - (k, key) = get_keylet_and_key(uzbl, key.strip(), add=False) - - if key in k.held: - if k.is_modcmd: - uzbl.event('MODCMD_EXEC', k) - - k.held.remove(key) - clear_modcmd(uzbl) - - -def set_keycmd(uzbl, keycmd): - '''Allow setting of the keycmd externally.''' - - k = get_keylet(uzbl) - k.keycmd = keycmd - k._repr_cache = None - k.cursor = len(keycmd) - update_event(uzbl, k, False) - - -def inject_keycmd(uzbl, keycmd): - '''Allow injecting of a string into the keycmd at the cursor position.''' - - k = get_keylet(uzbl) - k.keycmd = inject_str(k.keycmd, k.cursor, keycmd) - k._repr_cache = None - k.cursor += len(keycmd) - update_event(uzbl, k, False) - - -def append_keycmd(uzbl, keycmd): - '''Allow appening of a string to the keycmd.''' - - k = get_keylet(uzbl) - k.keycmd += keycmd - k._repr_cache = None - k.cursor = len(k.keycmd) - update_event(uzbl, k, False) - - -def keycmd_strip_word(uzbl, sep): - ''' Removes the last word from the keycmd, similar to readline ^W ''' - - sep = sep or ' ' - k = get_keylet(uzbl) - if not k.keycmd: - return - - head, tail = k.keycmd[:k.cursor].rstrip(sep), k.keycmd[k.cursor:] - rfind = head.rfind(sep) - head = head[:rfind] if rfind + 1 else '' - k.keycmd = head + tail - k.cursor = len(head) - update_event(uzbl, k, False) - - -def keycmd_backspace(uzbl, *args): - '''Removes the character at the cursor position in the keycmd.''' - - k = get_keylet(uzbl) - if not k.keycmd: - return - - k.keycmd = k.keycmd[:k.cursor-1] + k.keycmd[k.cursor:] - k.cursor -= 1 - update_event(uzbl, k, False) - - -def keycmd_delete(uzbl, *args): - '''Removes the character after the cursor position in the keycmd.''' - - k = get_keylet(uzbl) - if not k.keycmd: - return - - k.keycmd = k.keycmd[:k.cursor] + k.keycmd[k.cursor+1:] - update_event(uzbl, k, False) - - -def keycmd_exec_current(uzbl, *args): - '''Raise a KEYCMD_EXEC with the current keylet and then clear the - keycmd.''' - - k = get_keylet(uzbl) - uzbl.event('KEYCMD_EXEC', k) - clear_keycmd(uzbl) - - -def set_cursor_pos(uzbl, index): - '''Allow setting of the cursor position externally. Supports negative - indexing and relative stepping with '+' and '-'.''' - - k = get_keylet(uzbl) - if index == '-': - cursor = k.cursor - 1 - - elif index == '+': - cursor = k.cursor + 1 - - else: - cursor = int(index.strip()) - if cursor < 0: - cursor = len(k.keycmd) + cursor + 1 - - if cursor < 0: - cursor = 0 - - if cursor > len(k.keycmd): - cursor = len(k.keycmd) - - k.cursor = cursor - update_event(uzbl, k, False) - - -def init(uzbl): - '''Connect handlers to uzbl events.''' - - # Event handling hooks. - uzbl.connect_dict({ - 'APPEND_KEYCMD': append_keycmd, - 'FOCUS_GAINED': focus_changed, - 'FOCUS_LOST': focus_changed, - 'IGNORE_KEY': add_key_ignore, - 'INJECT_KEYCMD': inject_keycmd, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'KEYCMD_BACKSPACE': keycmd_backspace, - 'KEYCMD_DELETE': keycmd_delete, - 'KEYCMD_EXEC_CURRENT': keycmd_exec_current, - 'KEYCMD_STRIP_WORD': keycmd_strip_word, - 'KEY_PRESS': key_press, - 'KEY_RELEASE': key_release, - 'MODKEY_ADDITION': modkey_addition_parse, - 'MODMAP': modmap_parse, - 'SET_CURSOR_POS': set_cursor_pos, - 'SET_KEYCMD': set_keycmd, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'add_key_ignore': add_key_ignore, - 'add_modkey_addition': add_modkey_addition, - 'add_modmap': add_modmap, - 'append_keycmd': append_keycmd, - 'clear_current': clear_current, - 'clear_keycmd': clear_keycmd, - 'clear_modcmd': clear_modcmd, - 'get_keylet': get_keylet, - 'inject_keycmd': inject_keycmd, - 'set_cursor_pos': set_cursor_pos, - 'set_keycmd': set_keycmd, - }) diff --git a/examples/data/uzbl/plugins/mode.py b/examples/data/uzbl/plugins/mode.py deleted file mode 100644 index 54d865a..0000000 --- a/examples/data/uzbl/plugins/mode.py +++ /dev/null @@ -1,176 +0,0 @@ -import sys -import re - -__export__ = ['set_mode', 'get_mode', 'set_mode_config', 'get_mode_config'] - -UZBLS = {} - -DEFAULTS = { - 'mode': '', - 'modes': { - 'insert': { - 'forward_keys': True, - 'keycmd_events': False, - 'modcmd_updates': False, - 'mode_indicator': 'I'}, - 'command': { - 'forward_keys': False, - 'keycmd_events': True, - 'modcmd_updates': True, - 'mode_indicator': 'C'}}} - -FINDSPACES = re.compile("\s+") -VALID_KEY = re.compile("^[\w_]+$").match - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_mode_dict(uzbl): - '''Return the mode dict for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def get_mode_config(uzbl, mode): - '''Return the mode config for a given mode.''' - - modes = get_mode_dict(uzbl)['modes'] - if mode not in modes: - modes[mode] = {} - - return modes[mode] - - -def get_mode(uzbl): - return get_mode_dict(uzbl)['mode'] - - -def mode_changed(uzbl, mode): - '''The mode has just been changed, now set the per-mode config.''' - - if get_mode(uzbl) != mode: - return - - config = uzbl.get_config() - mode_config = get_mode_config(uzbl, mode) - for (key, value) in mode_config.items(): - uzbl.set(key, value, config=config) - - if 'mode_indicator' not in mode_config: - config['mode_indicator'] = mode - - uzbl.clear_keycmd() - uzbl.clear_modcmd() - - -def set_mode(uzbl, mode=None): - '''Set the mode and raise the MODE_CHANGED event if the mode has changed. - Fallback on the default mode if no mode argument was given and the default - mode is not null.''' - - config = uzbl.get_config() - mode_dict = get_mode_dict(uzbl) - if mode is None: - mode_dict['mode'] = '' - if 'default_mode' in config: - mode = config['default_mode'] - - else: - mode = 'command' - - if not VALID_KEY(mode): - raise KeyError("invalid mode name: %r" % mode) - - if 'mode' not in config or config['mode'] != mode: - config['mode'] = mode - - elif mode_dict['mode'] != mode: - mode_dict['mode'] = mode - uzbl.event("MODE_CHANGED", mode) - - -def config_changed(uzbl, key, value): - '''Check for mode related config changes.''' - - value = None if not value else value - if key == 'default_mode': - if not get_mode(uzbl): - set_mode(uzbl, value) - - elif key == 'mode': - set_mode(uzbl, value) - - -def set_mode_config(uzbl, mode, key, value): - '''Set mode specific configs. If the mode being modified is the current - mode then apply the changes on the go.''' - - assert VALID_KEY(mode) and VALID_KEY(key) - - mode_config = get_mode_config(uzbl, mode) - mode_config[key] = value - - if get_mode(uzbl) == mode: - uzbl.set(key, value) - - -def mode_config(uzbl, args): - '''Parse mode config events.''' - - split = map(unicode.strip, FINDSPACES.split(args.lstrip(), 1)) - if len(split) != 2: - raise SyntaxError('invalid mode config syntax: %r' % args) - - mode, set = split - split = map(unicode.strip, set.split('=', 1)) - if len(split) != 2: - raise SyntaxError('invalid set syntax: %r' % args) - - key, value = split - set_mode_config(uzbl, mode, key, value) - - -def toggle_modes(uzbl, modes): - '''Toggle or cycle between or through a list of modes.''' - - assert len(modes.strip()) - - modelist = filter(None, map(unicode.strip, modes.split(' '))) - mode = get_mode(uzbl) - - index = 0 - if mode in modelist: - index = (modelist.index(mode)+1) % len(modelist) - - set_mode(uzbl, modelist[index]) - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'CONFIG_CHANGED': config_changed, - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'MODE_CHANGED': mode_changed, - 'MODE_CONFIG': mode_config, - 'TOGGLE_MODES': toggle_modes, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_mode': get_mode, - 'get_mode_config': get_mode_config, - 'set_mode': set_mode, - 'set_mode_config': set_mode_config, - }) diff --git a/examples/data/uzbl/plugins/on_event.py b/examples/data/uzbl/plugins/on_event.py deleted file mode 100644 index b9c504a..0000000 --- a/examples/data/uzbl/plugins/on_event.py +++ /dev/null @@ -1,107 +0,0 @@ -'''Plugin provides arbitrary binding of uzbl events to uzbl commands. - -Formatting options: - %s = space separated string of the arguments - %r = escaped and quoted version of %s - %1 = argument 1 - %2 = argument 2 - %n = argument n - -Usage: - request ON_EVENT LINK_HOVER set selected_uri = $1 - --> LINK_HOVER http://uzbl.org/ - <-- set selected_uri = http://uzbl.org/ - - request ON_EVENT CONFIG_CHANGED print Config changed: %1 = %2 - --> CONFIG_CHANGED selected_uri http://uzbl.org/ - <-- print Config changed: selected_uri = http://uzbl.org/ -''' - -import sys -import re - -__export__ = ['get_on_events', 'on_event'] - -UZBLS = {} - - -def error(msg): - sys.stderr.write('on_event plugin: error: %s\n' % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = {} - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_on_events(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def event_handler(uzbl, *args, **kargs): - '''This function handles all the events being watched by various - on_event definitions and responds accordingly.''' - - events = get_on_events(uzbl) - event = kargs['on_event'] - if event not in events: - return - - commands = events[event] - cmd_expand = uzbl.cmd_expand - for cmd in commands: - cmd = cmd_expand(cmd, args) - uzbl.send(cmd) - - -def on_event(uzbl, event, cmd): - '''Add a new event to watch and respond to.''' - - event = event.upper() - events = get_on_events(uzbl) - if event not in events: - uzbl.connect(event, event_handler, on_event=event) - events[event] = [] - - cmds = events[event] - if cmd not in cmds: - cmds.append(cmd) - - -def parse_on_event(uzbl, args): - '''Parse ON_EVENT events and pass them to the on_event function. - - Syntax: "event ON_EVENT commands".''' - - if not args: - return error("missing on_event arguments") - - split = args.split(' ', 1) - if len(split) != 2: - return error("invalid ON_EVENT syntax: %r" % args) - - event, cmd = split - on_event(uzbl, event, cmd) - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'ON_EVENT': parse_on_event, - }) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.export_dict({ - 'get_on_events': get_on_events, - 'on_event': on_event, - }) diff --git a/examples/data/uzbl/plugins/plugin_template.py b/examples/data/uzbl/plugins/plugin_template.py deleted file mode 100644 index 565a999..0000000 --- a/examples/data/uzbl/plugins/plugin_template.py +++ /dev/null @@ -1,76 +0,0 @@ -'''Plugin template.''' - -# Holds the per-instance data dict. -UZBLS = {} - -# The default instance dict. -DEFAULTS = {} - - -def add_instance(uzbl, *args): - '''Add a new instance with default config options.''' - - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - '''Delete data stored for an instance.''' - - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_myplugin_dict(uzbl): - '''Get data stored for an instance.''' - - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def myplugin_function(uzbl, *args, **kargs): - '''Custom plugin function which is exported by the __export__ list at the - top of the file for use by other functions/callbacks.''' - - print "My plugin function arguments:", args, kargs - - # Get the per-instance data object. - data = get_myplugin_dict(uzbl) - - # Function logic goes here. - - -def myplugin_event_parser(uzbl, args): - '''Parses MYPLUGIN_EVENT raised by uzbl or another plugin.''' - - print "Got MYPLUGIN_EVENT with arguments: %r" % args - - # Parsing logic goes here. - - -def init(uzbl): - '''The main function of the plugin which is used to attach all the event - hooks that are going to be used throughout the plugins life. This function - is called each time a UzblInstance() object is created in the event - manager.''' - - # Make a dictionary comprising of {"EVENT_NAME": handler, ..} to the event - # handler stack: - uzbl.connect_dict({ - # event name function - 'INSTANCE_START': add_instance, - 'INSTANCE_EXIT': del_instance, - 'MYPLUGIN_EVENT': myplugin_event_parser, - }) - - # Or connect a handler to an event manually and supply additional optional - # arguments: - #uzbl.connect("MYOTHER_EVENT", myother_event_parser, True, limit=20) - - # Function exports to the uzbl object, `function(uzbl, *args, ..)` - # becomes `uzbl.function(*args, ..)`. - uzbl.connect_dict({ - # external name function - 'myplugin_function': myplugin_function, - }) diff --git a/examples/data/uzbl/plugins/progress_bar.py b/examples/data/uzbl/plugins/progress_bar.py deleted file mode 100644 index 89ba175..0000000 --- a/examples/data/uzbl/plugins/progress_bar.py +++ /dev/null @@ -1,159 +0,0 @@ -import sys - -UZBLS = {} - -DEFAULTS = {'width': 8, - 'done': '=', - 'pending': '.', - 'format': '[%d%a%p]%c', - 'spinner': '-\\|/', - 'sprites': 'loading', - 'updates': 0, - 'progress': 100} - - -def error(msg): - sys.stderr.write("progress_bar plugin: error: %s\n" % msg) - - -def add_instance(uzbl, *args): - UZBLS[uzbl] = dict(DEFAULTS) - - -def del_instance(uzbl, *args): - if uzbl in UZBLS: - del UZBLS[uzbl] - - -def get_progress_config(uzbl): - if uzbl not in UZBLS: - add_instance(uzbl) - - return UZBLS[uzbl] - - -def update_progress(uzbl, prog=None): - '''Updates the progress_format variable on LOAD_PROGRESS update. - - The current substitution options are: - %d = done char * done - %p = pending char * remaining - %c = percent done - %i = int done - %s = -\|/ spinner - %t = percent pending - %o = int pending - %r = sprites - ''' - - prog_config = get_progress_config(uzbl) - config = uzbl.get_config() - - if prog is None: - prog = prog_config['progress'] - - else: - prog = int(prog) - prog_config['progress'] = prog - - prog_config['updates'] += 1 - format = prog_config['format'] - width = prog_config['width'] - - # Inflate the done and pending bars to stop the progress bar - # jumping around. - if '%c' in format or '%i' in format: - count = format.count('%c') + format.count('%i') - width += (3-len(str(prog))) * count - - if '%t' in format or '%o' in format: - count = format.count('%t') + format.count('%o') - width += (3-len(str(100-prog))) * count - - done = int(((prog/100.0)*width)+0.5) - pending = width - done - - if '%d' in format: - format = format.replace('%d', prog_config['done']*done) - - if '%p' in format: - format = format.replace('%p', prog_config['pending']*pending) - - if '%c' in format: - format = format.replace('%c', '%d%%' % prog) - - if '%i' in format: - format = format.replace('%i', '%d' % prog) - - if '%t' in format: - format = format.replace('%t', '%d%%' % (100-prog)) - - if '%o' in format: - format = format.replace('%o', '%d' % (100-prog)) - - if '%s' in format: - spinner = prog_config['spinner'] - spin = '-' if not spinner else spinner - index = 0 if prog == 100 else prog_config['updates'] % len(spin) - char = '\\\\' if spin[index] == '\\' else spin[index] - format = format.replace('%s', char) - - if '%r' in format: - sprites = prog_config['sprites'] - sprites = '-' if not sprites else sprites - index = int(((prog/100.0)*len(sprites))+0.5)-1 - sprite = '\\\\' if sprites[index] == '\\' else sprites[index] - format = format.replace('%r', sprite) - - if 'progress_format' not in config or config['progress_format'] != format: - config['progress_format'] = format - - -def progress_config(uzbl, args): - '''Parse PROGRESS_CONFIG events from the uzbl instance. - - Syntax: event PROGRESS_CONFIG = - ''' - - split = args.split('=', 1) - if len(split) != 2: - return error("invalid syntax: %r" % args) - - key, value = map(unicode.strip, split) - prog_config = get_progress_config(uzbl) - - if key not in prog_config: - return error("key error: %r" % args) - - if type(prog_config[key]) == type(1): - try: - value = int(value) - - except: - return error("invalid type: %r" % args) - - elif not value: - value = ' ' - - prog_config[key] = value - update_progress(uzbl) - - -def reset_progress(uzbl, args): - '''Reset the spinner counter, reset the progress int and re-draw the - progress bar on LOAD_COMMIT.''' - - prog_dict = get_progress_config(uzbl) - prog_dict['updates'] = prog_dict['progress'] = 0 - update_progress(uzbl) - - -def init(uzbl): - # Event handling hooks. - uzbl.connect_dict({ - 'INSTANCE_EXIT': del_instance, - 'INSTANCE_START': add_instance, - 'LOAD_COMMIT': reset_progress, - 'LOAD_PROGRESS': update_progress, - 'PROGRESS_CONFIG': progress_config, - }) diff --git a/examples/data/uzbl/scripts/cookies.sh b/examples/data/uzbl/scripts/cookies.sh deleted file mode 100755 index ee2ce51..0000000 --- a/examples/data/uzbl/scripts/cookies.sh +++ /dev/null @@ -1,154 +0,0 @@ -#!/bin/sh - -set -n; - -# THIS IS EXPERIMENTAL AND COULD BE INSECURE !!!!!! - -# this is an example bash script of how you could manage your cookies. it is very raw and basic and not as good as uzbl-cookie-daemon -# we use the cookies.txt format (See http://kb.mozillazine.org/Cookies.txt) -# This is one textfile with entries like this: -# kb.mozillazine.org FALSE / FALSE 1146030396 wikiUserID 16993 -# domain alow-read-other-subdomains path http-required expiration name value -# you probably want your cookies config file in your $XDG_CONFIG_HOME ( eg $HOME/.config/uzbl/cookies) -# Note. in uzbl there is no strict definition on what a session is. it's YOUR job to clear cookies marked as end_session if you want to keep cookies only valid during a "session" -# MAYBE TODO: allow user to edit cookie before saving. this cannot be done with zenity :( -# TODO: different cookie paths per config (eg per group of uzbl instances) - -# TODO: correct implementation. -# see http://curl.haxx.se/rfc/cookie_spec.html -# http://en.wikipedia.org/wiki/HTTP_cookie - -# TODO : check expires= before sending. -# write sample script that cleans up cookies dir based on expires attribute. -# TODO: check uri against domain attribute. and path also. -# implement secure attribute. -# support blocking or not for 3rd parties -# http://kb.mozillazine.org/Cookies.txt -# don't always append cookies, sometimes we need to overwrite - -cookie_config=${XDG_CONFIG_HOME:-${HOME}/.config}/uzbl/cookies -[ "x$cookie_config" = x ] && exit 1 -[ -d "${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/" ] &&\ -cookie_data=${XDG_DATA_HOME:-${HOME}/.local/share}/uzbl/cookies.txt || exit 1 - -notifier= -#notifier=notify-send -#notify_wrapper () { -# echo "$@" >> $HOME/cookielog -#} -#notifier=notifier_wrapper - -# if this variable is set, we will use it to inform you when and which cookies we store, and when/which we send. -# it's primarily used for debugging -notifier= -which zenity &>/dev/null || exit 2 - -# Example cookie: -# test_cookie=CheckForPermission; expires=Thu, 07-May-2009 19:17:55 GMT; path=/; domain=.doubleclick.net - -# uri=$6 -# uri=${uri/http:\/\/} # strip 'http://' part -# host=${uri/\/*/} -action=$8 # GET/PUT -shift -host=$9 -shift -path=$9 -shift -cookie=$9 - -field_domain=$host -field_path=$path -field_name= -field_value= -field_exp='end_session' - -notify() { - [ -n "$notifier" ] && $notifier "$@" -} - - -# FOR NOW LETS KEEP IT SIMPLE AND JUST ALWAYS PUT AND ALWAYS GET -parse_cookie() { - IFS=$';' - first_pair=1 - for pair in $cookie - do - if [ "x$first_pair" = x1 ] - then - field_name=${pair%%=*} - field_value=${pair#*=} - first_pair=0 - else - echo "$pair" | read -r pair #strip leading/trailing wite space - key=${pair%%=*} - val=${pair#*=} - [ "$key" == expires ] && field_exp=`date -u -d "$val" +'%s'` - # TODO: domain - [ "$key" == path ] && field_path=$val - fi - done - unset IFS -} - -# match cookies in cookies.txt against hostname and path -get_cookie() { - path_esc=${path//\//\\/} - search="^[^\t]*$host\t[^\t]*\t$path_esc" - cookie=`awk "/$search/" $cookie_data 2>/dev/null | tail -n 1` - if [ -z "$cookie" ] - then - notify "Get_cookie: search: $search in $cookie_data -> no result" - false - else - notify "Get_cookie: search: $search in $cookie_data -> result: $cookie" - echo "$cookie" | \ - read domain alow_read_other_subdomains path http_required expiration name \ - value; - cookie="$name=$value" - true - fi -} - -save_cookie() { - if parse_cookie - then - data="$field_domain\tFALSE\t$field_path\tFALSE\t$field_exp\t$field_name\t$field_value" - notify "save_cookie: adding $data to $cookie_data" - echo -e "$data" >> $cookie_data - else - notify "not saving a cookie. since we don't have policies yet, parse_cookie must have returned false. this is a bug" - fi -} - -[ "x$action" = xPUT ] && save_cookie -[ "x$action" = xGET ] && get_cookie && echo "$cookie" - -exit - - -# TODO: implement this later. -# $1 = section (TRUSTED or DENY) -# $2 =url -match() { - sed -n "/$1/,/^\$/p" $cookie_config 2>/dev/null | grep -q "^$host" -} - -fetch_cookie() { - cookie=`cat $cookie_data` -} - -store_cookie() { - echo $cookie > $cookie_data -} - -if match TRUSTED $host -then - [ "x$action" = xPUT ] && store_cookie $host - [ "x$action" = xGET ] && fetch_cookie && echo "$cookie" -elif ! match DENY $host -then - [ "x$action" = xPUT ] && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Accept this cookie from $host ?" --entry-text="$cookie"` && store_cookie $host - [ "x$action" = xGET ] && fetch_cookie && cookie=`zenity --entry --title 'Uzbl Cookie handler' --text "Submit this cookie to $host ?" --entry-text="$cookie"` && echo $cookie -fi -exit 0 diff --git a/examples/data/uzbl/scripts/download.sh b/examples/data/uzbl/scripts/download.sh deleted file mode 100755 index 1c7d039..0000000 --- a/examples/data/uzbl/scripts/download.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# just an example of how you could handle your downloads -# try some pattern matching on the uri to determine what we should do - -# Some sites block the default wget --user-agent.. -GET="wget --user-agent=Firefox" - -dest="$HOME" -url="$8" - -http_proxy="$9" -export http_proxy - -test "x$url" = "x" && { echo "you must supply a url! ($url)"; exit 1; } - -# only changes the dir for the $get sub process -if echo "$url" | grep -E '.*\.torrent' >/dev/null; -then - ( cd "$dest"; $GET "$url") -else - ( cd "$dest"; $GET "$url") -fi diff --git a/examples/data/uzbl/scripts/extedit.js b/examples/data/uzbl/scripts/extedit.js deleted file mode 100644 index 8ed346d..0000000 --- a/examples/data/uzbl/scripts/extedit.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Edit forms in external editor - * - * (c) 2009, Robert Manea - * utf8 functions are (c) by Webtoolkit.info (http://www.webtoolkit.info/) - * - * - * Installation: - * - Copy this script to $HOME/.local/share/uzbl/scripts - * - Add the following to $HOME/.config/uzbl/config: - * @bind E = script @scripts_dir/extedit.js - * - Set your preferred editor - * set editor = gvim - * - non-GUI editors - * set editor = xterm -e vim - * - * Usage: - * Select (click) an editable form, go to command mode and hit E - * -*/ - - -function utf8_decode ( str_data ) { - var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0; - - str_data += ''; - - while ( i < str_data.length ) { - c1 = str_data.charCodeAt(i); - if (c1 < 128) { - tmp_arr[ac++] = String.fromCharCode(c1); - i++; - } else if ((c1 > 191) && (c1 < 224)) { - c2 = str_data.charCodeAt(i+1); - tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); - i += 2; - } else { - c2 = str_data.charCodeAt(i+1); - c3 = str_data.charCodeAt(i+2); - tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); - i += 3; - } - } - - return tmp_arr.join(''); -} - - -function utf8_encode ( argString ) { - var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n"); - - var utftext = ""; - var start, end; - var stringl = 0; - - start = end = 0; - stringl = string.length; - for (var n = 0; n < stringl; n++) { - var c1 = string.charCodeAt(n); - var enc = null; - - if (c1 < 128) { - end++; - } else if (c1 > 127 && c1 < 2048) { - enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128); - } else { - enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128); - } - if (enc !== null) { - if (end > start) { - utftext += string.substring(start, end); - } - utftext += enc; - start = end = n+1; - } - } - - if (end > start) { - utftext += string.substring(start, string.length); - } - - return utftext; -} - - -(function() { - var actelem = document.activeElement; - - if(actelem.type == 'text' || actelem.type == 'textarea') { - var editor = Uzbl.run("print @external_editor") || "gvim"; - var filename = Uzbl.run("print @(mktemp /tmp/uzbl_edit.XXXXXX)@"); - - if(actelem.value) - Uzbl.run("sh 'echo " + window.btoa(utf8_encode(actelem.value)) + " | base64 -d > " + filename + "'"); - - Uzbl.run("sync_sh '" + editor + " " + filename + "'"); - actelem.value = utf8_decode(window.atob(Uzbl.run("print @(base64 -w 0 " + filename + ")@"))); - - Uzbl.run("sh 'rm -f " + filename + "'"); - } - - })(); diff --git a/examples/data/uzbl/scripts/follow_Numbers.js b/examples/data/uzbl/scripts/follow_Numbers.js deleted file mode 100644 index 00b279e..0000000 --- a/examples/data/uzbl/scripts/follow_Numbers.js +++ /dev/null @@ -1,228 +0,0 @@ -/* This is the basic linkfollowing script. - * Its pretty stable, only using numbers to navigate. - * - * TODO: Some pages mess around a lot with the zIndex which - * lets some hints in the background. - * TODO: Some positions are not calculated correctly (mostly - * because of uber-fancy-designed-webpages. Basic HTML and CSS - * works good - * TODO: Still some links can't be followed/unexpected things - * happen. Blame some freaky webdesigners ;) - */ - -//Just some shortcuts and globals -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; - -//Reset keycmd, modcmd and return to default mode. -function clearKeycmd() { Uzbl.run('set mode ='); } - -//Make onlick-links "clickable" -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -//Catch the ESC keypress to stop linkfollowing -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -//Calculate element position to draw the hint -//Pretty accurate but on fails in some very fancy cases -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -//Calculate if an element is visible -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -//Calculate if an element is on the viewport. -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -//Removes all hints/leftovers that might be generated -//by this script. -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -//Generate a hint for an element with the given label -//Here you can play around with the style of the hints! -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '1000'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} -//Here we choose what to do with an element if we -//want to "follow" it. On form elements we "select" -//or pass the focus, on links we try to perform a click, -//but at least set the href of the link. (needs some improvements) -function clickElem(item) { - removeAllHints(); - clearKeycmd(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} -//Returns a list of all links (in this version -//just the elements itself, but in other versions, we -//add the label here. -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - } - } - return res; -} -//Same as above, just for the form elements -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - } - } - } - return res; -} -//Draw all hints for all elements passed. "len" is for -//the number of chars we should use to avoid collisions -function reDrawHints(elems, chars) { - removeAllHints(); - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - for (var i = 0; i < elems[0].length; i++) { - if (elems[0][i]) { - var label = elems[1][i].substring(chars); - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - } -} -//Put it all together -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - var label = j + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - for (var k = 0; k < s.length; k++) { - b = b && label.charAt(k) == s[k]; - } - if (b) { - leftover[0].push(elems[0][j]); - leftover[1].push(label); - } - } - reDrawHints(leftover, s.length); - } -} -followLinks('%s'); diff --git a/examples/data/uzbl/scripts/follow_Numbers_Strings.js b/examples/data/uzbl/scripts/follow_Numbers_Strings.js deleted file mode 100644 index e50da5d..0000000 --- a/examples/data/uzbl/scripts/follow_Numbers_Strings.js +++ /dev/null @@ -1,212 +0,0 @@ -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; - -//Reset keycmd, modcmd and return to default mode. -function clearKeycmd() { Uzbl.run('set mode ='); } - -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.zIndex = '1000'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} - -function clickElem(item) { - removeAllHints(); - clearKeycmd(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} - -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - res[1].push(li.innerText.toLowerCase()); - } - } - return res; -} -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - if (el.getAttribute('value')) { - res[1].push(el.getAttribute('value').toLowerCase()); - } else { - res[1].push(el.getAttribute('name').toLowerCase()); - } - } - } - } - return res; -} -function reDrawHints(elems, len) { - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - hintdiv.style.opacity = '0.0'; - for (var i = 0; i < elems[0].length; i++) { - var label = i + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - if (elems[0][i]) { - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - hintdiv.style.opacity = '0.7' - } -} -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - for (var k = 0; k < s.length; k++) { - b = b && elems[1][j].charAt(k) == s[k]; - } - if (!b) { - elems[0][j] = null; - elems[1][j] = null; - } else { - leftover[0].push(elems[0][j]); - leftover[1].push(elems[1][j]); - } - } - if (leftover[0].length == 1) { - clickElem(leftover[0][0]); - } else if (!oldDiv) { - if (linknr + 1 || s.length == 0) { - reDrawHints(elems, len); - } else { - reDrawHints(leftover, len); - } - } - } -} -followLinks('%s'); diff --git a/examples/data/uzbl/scripts/formfiller.pl b/examples/data/uzbl/scripts/formfiller.pl deleted file mode 100755 index 23da347..0000000 --- a/examples/data/uzbl/scripts/formfiller.pl +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/perl - -# a slightly more advanced form filler -# -# uses settings file like: $keydir/ -#TODO: fallback to $HOME/.local/share -# user arg 1: -# edit: force editing of the file (fetches if file is missing) -# load: fill forms from file (fetches if file is missing) -# new: fetch new file - -# usage example: -# bind LL = spawn /usr/share/uzbl/examples/scripts/formfiller.pl load -# bind LN = spawn /usr/share/uzbl/examples/scripts/formfiller.pl new -# bind LE = spawn /usr/share/uzbl/examples/scripts/formfiller.pl edit - -use strict; -use warnings; - -my $keydir = $ENV{XDG_CONFIG_HOME} . "/uzbl/forms"; -my ($config,$pid,$xid,$fifoname,$socket,$url,$title,$cmd) = @ARGV; -if (!defined $fifoname || $fifoname eq "") { die "No fifo"; } - -sub domain { - my ($url) = @_; - $url =~ s#http(s)?://([A-Za-z0-9\.-]+)(/.*)?#$2#; - return $url; -}; - -my $editor = "xterm -e vim"; -#my $editor = "gvim"; - -# ideally, there would be some way to ask uzbl for the html content instead of having to redownload it with -# Also, you may need to fake the user-agent on some sites (like facebook) - my $downloader = "curl -A 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10) Gecko/2009042810 GranParadiso/3.0.10' "; -#my $downloader = "curl -s"; - -my @fields = ("type","name","value"); - -my %command; - -$command{load} = sub { - my ($domain) = @_; - my $filename = "$keydir/$domain"; - if (-e $filename){ - open(my $file, $filename) or die "Failed to open $filename: $!"; - my (@lines) = <$file>; - close($file); - $|++; - open(my $fifo, ">>", $fifoname) or die "Failed to open $fifoname: $!"; - foreach my $line (@lines) { - next if ($line =~ m/^#/); - my ($type,$name,$value) = ($line =~ /^\s*(\w+)\s*\|\s*(.*?)\s*\|\s*(.*?)\s*$/); - if ($type eq "checkbox") - { - printf $fifo 'js document.getElementsByName("%s")[0].checked = %s;', $name, $value; - } elsif ($type eq "submit") - { - printf $fifo 'js function fs (n) {try{n.submit()} catch (e){fs(n.parentNode)}}; fs(document.getElementsByName("%s")[0]);', $name; - } elsif ($type ne "") - { - printf $fifo 'js document.getElementsByName("%s")[0].value = "%s";', $name, $value; - } - print $fifo "\n"; - } - $|--; - } else { - $command{new}->($domain); - $command{edit}->($domain); - } -}; -$command{edit} = sub { - my ($domain) = @_; - my $file = "$keydir/$domain"; - if(-e $file){ - system ($editor, $file); - } else { - $command{new}->($domain); - } -}; -$command{new} = sub { - my ($domain) = @_; - my $filename = "$keydir/$domain"; - open (my $file,">>", $filename) or die "Failed to open $filename: $!"; - $|++; - print $file "# Make sure that there are no extra submits, since it may trigger the wrong one.\n"; - printf $file "#%-10s | %-10s | %s\n", @fields; - print $file "#------------------------------\n"; - my @data = `$downloader $url`; - foreach my $line (@data){ - if($line =~ m/].*?)>/i){ - $line =~ s/.*(].*?)>).*/$1/; - printf $file " %-10s | %-10s | %s\n", map { my ($r) = $line =~ /.*$_=["'](.*?)["']/;$r } @fields; - }; - }; - $|--; -}; - -$command{$cmd}->(domain($url)); diff --git a/examples/data/uzbl/scripts/formfiller.sh b/examples/data/uzbl/scripts/formfiller.sh deleted file mode 100755 index 10afaba..0000000 --- a/examples/data/uzbl/scripts/formfiller.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# simple html form (eg for logins) filler (and manager) for uzbl. -# uses settings files like: $keydir/ -# files contain lines like: : - - -# user arg 1: -# edit: force editing the file (falls back to new if not found) -# new: start with a new file. -# load: try to load from file into form - -# something else (or empty): if file not available: new, otherwise load. - -keydir=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/forms -[ -d "`dirname $keydir`" ] || exit 1 -[ -d "$keydir" ] || mkdir "$keydir" - -editor=${VISUAL} -if [[ -z ${editor} ]]; then - #editor='gvim' - editor='urxvt -e vim' -fi - -config=$1; shift -pid=$1; shift -xid=$1; shift -fifo=$1; shift -socket=$1; shift -url=$1; shift -title=$1; shift -action=$1 - -[ -d $keydir ] || mkdir $keydir || exit 1 - -if [ "$action" != 'edit' -a "$action" != 'new' -a "$action" != 'load' ] -then - action=new - [[ -e $keydir/$domain ]] && action=load -elif [ "$action" == 'edit' ] && [[ ! -e $keydir/$domain ]] -then - action=new -fi -domain=$(echo $url | sed -re 's|(http\|https)+://([A-Za-z0-9\.]+)/.*|\2|') - - -#regex='s|.*.*|\1: |p' # sscj's first version, does not work on http://wiki.archlinux.org/index.php?title=Special:UserLogin&returnto=Main_Page - regex='s|.*> $fifo -else - if [ "$action" == 'new' ] - then - curl "$url" | grep ' $keydir/$domain - fi - [[ -e $keydir/$domain ]] || exit 3 #this should never happen, but you never know. - $editor $keydir/$domain #TODO: if user aborts save in editor, the file is already overwritten -fi diff --git a/examples/data/uzbl/scripts/hint.js b/examples/data/uzbl/scripts/hint.js deleted file mode 100644 index ec7f1e2..0000000 --- a/examples/data/uzbl/scripts/hint.js +++ /dev/null @@ -1,26 +0,0 @@ -for (var i=0; i < document.links.length; i++) { - var uzblid = 'uzbl_link_hint_'; - var li = document.links[i]; - var pre = document.getElementById(uzblid+i); - - if (pre) { - li.removeChild(pre); - } else { - var hint = document.createElement('div'); - hint.setAttribute('id',uzblid+i); - hint.innerHTML = i; - hint.style.display='inline'; - hint.style.lineHeight='90%'; - hint.style.backgroundColor='red'; - hint.style.color='white'; - hint.style.fontSize='small-xx'; - hint.style.fontWeight='light'; - hint.style.margin='0px'; - hint.style.padding='2px'; - hint.style.position='absolute'; - hint.style.textDecoration='none'; - hint.style.left=li.style.left; - hint.style.top=li.style.top; - li.insertAdjacentElement('afterBegin',hint); - } -} diff --git a/examples/data/uzbl/scripts/history.sh b/examples/data/uzbl/scripts/history.sh deleted file mode 100755 index 7c83aa6..0000000 --- a/examples/data/uzbl/scripts/history.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history -[ -d `dirname $file` ] || exit 1 -echo `date +'%Y-%m-%d %H:%M:%S'`" $6 $7" >> $file diff --git a/examples/data/uzbl/scripts/insert_bookmark.sh b/examples/data/uzbl/scripts/insert_bookmark.sh deleted file mode 100755 index c34e7db..0000000 --- a/examples/data/uzbl/scripts/insert_bookmark.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -[ -d "${XDG_DATA_HOME:-$HOME/.local/share}/uzbl" ] || exit 1 -file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/bookmarks - -which zenity &>/dev/null || exit 2 - -entry=`zenity --entry --text="Add bookmark. add tags after the '\t', separated by spaces" --entry-text="$6 $7\t"` -exitstatus=$? -if [ $exitstatus -ne 0 ]; then exit $exitstatus; fi -url=`echo $entry | awk '{print $1}'` - -# TODO: check if already exists, if so, and tags are different: ask if you want to replace tags -echo "$entry" >/dev/null #for some reason we need this.. don't ask me why -echo -e "$entry" >> $file -true diff --git a/examples/data/uzbl/scripts/instance-select-wmii.sh b/examples/data/uzbl/scripts/instance-select-wmii.sh deleted file mode 100755 index 2bf13ba..0000000 --- a/examples/data/uzbl/scripts/instance-select-wmii.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh - - -# This script allows you to focus another uzbl window -# It considers all uzbl windows in the current tag -# you can select one from a list, or go to the next/previous one -# It does not change the layout (stacked/tiled/floating) nor does it -# changes the size or viewing mode of a uzbl window -# When your current uzbl window is maximized, the one you change to -# will be maximized as well. -# See http://www.uzbl.org/wiki/wmii for more info -# $1 must be one of 'list', 'next', 'prev' - -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" - -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch -else - DMENU="dmenu -i" -fi - -if [ "$1" == 'list' ] -then - list= - # get window id's of uzbl clients. we could also get the label in one shot but it's pretty tricky - for i in $(wmiir read /tag/sel/index | grep uzbl |cut -d ' ' -f2) - do - label=$(wmiir read /client/$i/label) - list="$list$i : $label\n" - done - window=$(echo -e "$list" | $DMENU $COLORS | cut -d ' ' -f1) - wmiir xwrite /tag/sel/ctl "select client $window" -elif [ "$1" == 'next' ] -then - current=$(wmiir read /client/sel/ctl | head -n 1) - # find the next uzbl window and focus it - next=$(wmiir read /tag/sel/index | grep -A 10000 " $current " | grep -m 1 uzbl | cut -d ' ' -f2) - if [ x"$next" != "x" ] - then - wmiir xwrite /tag/sel/ctl "select client $next" - fi -elif [ "$1" == 'prev' ] -then - current=$(wmiir read /client/sel/ctl | head -n 1) - prev=$(wmiir read /tag/sel/index | grep -B 10000 " $current " | tac | grep -m 1 uzbl | cut -d ' ' -f2) - if [ x"$prev" != "x" ] - then - wmiir xwrite /tag/sel/ctl "select client $prev" - fi -else - echo "\$1 not valid" >&2 - exit 2 -fi diff --git a/examples/data/uzbl/scripts/linkfollow.js b/examples/data/uzbl/scripts/linkfollow.js deleted file mode 100644 index 0eb629b..0000000 --- a/examples/data/uzbl/scripts/linkfollow.js +++ /dev/null @@ -1,269 +0,0 @@ -// link follower for uzbl -// requires http://github.com/DuClare/uzbl/commit/6c11777067bdb8aac09bba78d54caea04f85e059 -// -// first, it needs to be loaded before every time it is used. -// One way would be to use the load_commit_handler: -// set load_commit_handler = sh 'echo "script /usr/share/uzbl/examples/scripts/linkfollow.js" > "$4"' -// -// when script is loaded, it can be invoked with -// bind f* = js hints.set("%s", hints.open) -// bind f_ = js hints.follow("%s",hints.open) -// -// At the moment, it may be useful to have way of forcing uzbl to load the script -// bind :lf = script /usr/share/uzbl/examples/scripts/linkfollow.js -// -// The default style for the hints are pretty ugly, so it is recommended to add the following -// to config file -// set stylesheet_uri = /usr/share/uzbl/examples/data/style.css -// -// based on follow_Numbers.js -// -// TODO: fix styling for the first element -// TODO: emulate mouseover events when visiting some elements -// TODO: rewrite the element->action handling - - -function Hints(){ - - // Settings - //////////////////////////////////////////////////////////////////////////// - - // if set to true, you must explicitly call hints.follow(), otherwise it will - // follow the link if there is only one matching result - var requireReturn = true; - - // Case sensitivity flag - var matchCase = "i"; - - // For case sensitive matching, uncomment: - // var matchCase = ""; - - - var uzblid = 'uzbl_hint'; - var uzblclass = 'uzbl_highlight'; - var uzblclassfirst = 'uzbl_h_first'; - var doc = document; - var visible = []; - var hintdiv; - - this.set = hint; - this.follow = follow; - this.keyPressHandler = keyPressHandler; - - function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; var width = el.offsetWidth; - var height = el.offsetHeight; - - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return {up: up, left: left, width: width, height: height}; - } - - function elementInViewport(p) { - return (p.up < window.pageYOffset + window.innerHeight && - p.left < window.pageXOffset + window.innerWidth && - (p.up + p.height) > window.pageYOffset && - (p.left + p.width) > window.pageXOffset); - } - - function isVisible(el) { - if (el == doc) { return true; } - if (!el) { return false; } - if (!el.parentNode) { return false; } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); - } - - // the vimperator defaults minus the xhtml elements, since it gave DOM errors - var hintable = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; - - function Matcher(str){ - var numbers = str.replace(/[^\d]/g,""); - var words = str.replace(/\d/g,"").split(/\s+/).map(function (n) { return new RegExp(n,matchCase)}); - this.test = test; - this.toString = toString; - this.numbers = numbers; - function matchAgainst(element){ - if(element.node.nodeName == "INPUT"){ - return element.node.value; - } else { - return element.node.textContent; - } - } - function test(element) { - // test all the regexp - var item = matchAgainst(element); - return words.every(function (regex) { return item.match(regex)}); - } - } - - function HintElement(node,pos){ - - this.node = node; - this.isHinted = false; - this.position = pos; - this.num = 0; - - this.addHint = function (labelNum) { - // TODO: fix uzblclassfirst - if(!this.isHinted){ - this.node.className += " " + uzblclass; - } - this.isHinted = true; - - // create hint - var hintNode = doc.createElement('div'); - hintNode.name = uzblid; - hintNode.innerText = labelNum; - hintNode.style.left = this.position.left + 'px'; - hintNode.style.top = this.position.up + 'px'; - hintNode.style.position = "absolute"; - doc.body.firstChild.appendChild(hintNode); - - } - this.removeHint = function(){ - if(this.isHinted){ - var s = (this.num)?uzblclassfirst:uzblclass; - this.node.className = this.node.className.replace(new RegExp(" "+s,"g"),""); - this.isHinted = false; - } - } - } - - function createHintDiv(){ - var hintdiv = doc.getElementById(uzblid); - if(hintdiv){ - hintdiv.parentNode.removeChild(hintdiv); - } - hintdiv = doc.createElement("div"); - hintdiv.setAttribute('id',uzblid); - doc.body.insertBefore(hintdiv,doc.body.firstChild); - return hintdiv; - } - - function init(){ - // WHAT? - doc.body.setAttribute("onkeyup","hints.keyPressHandler(event)"); - hintdiv = createHintDiv(); - visible = []; - - var items = doc.evaluate(hintable,doc,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); - for (var i = 0;i&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]' -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # show tags as well - goto=`$DMENU $COLORS < $file | awk '{print $1}'` -else - DMENU="dmenu -i" - # because they are all after each other, just show the url, not their tags. - goto=`awk '{print $1}' $file | $DMENU $COLORS` -fi - -#[ -n "$goto" ] && echo "uri $goto" > $4 -[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/examples/data/uzbl/scripts/load_url_from_history.sh b/examples/data/uzbl/scripts/load_url_from_history.sh deleted file mode 100755 index 62e02ac..0000000 --- a/examples/data/uzbl/scripts/load_url_from_history.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -history_file=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/history -[ -r "$history_file" ] || exit 1 - -# choose from all entries, sorted and uniqued -# goto=`awk '{print $3}' $history_file | sort -u | dmenu -i` -COLORS=" -nb #303030 -nf khaki -sb #CCFFAA -sf #303030" -if dmenu --help 2>&1 | grep -q '\[-rs\] \[-ni\] \[-nl\] \[-xs\]'; -then - DMENU="dmenu -i -xs -rs -l 10" # vertical patch - # choose an item in reverse order, showing also the date and page titles - # pick the last field from the first 3 fields. this way you can pick a url (prefixed with date & time) or type just a new url. - goto=`tac $history_file | $DMENU $COLORS | cut -d ' ' -f -3 | awk '{print $NF}'` -else - DMENU="dmenu -i" - # choose from all entries (no date or title), the first one being current url, and after that all others, sorted and uniqued, in ascending order - current=`tail -n 1 $history_file | awk '{print $3}'`; - goto=`(echo $current; awk '{print $3}' $history_file | grep -v "^$current\$" \ - | sort -u) | $DMENU $COLORS` -fi - -[ -n "$goto" ] && echo "uri $goto" > $4 -#[ -n "$goto" ] && echo "uri $goto" | socat - unix-connect:$5 diff --git a/examples/data/uzbl/scripts/scheme.py b/examples/data/uzbl/scripts/scheme.py deleted file mode 100755 index 0916466..0000000 --- a/examples/data/uzbl/scripts/scheme.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import os, subprocess, sys, urlparse - -def detach_open(cmd): - # Thanks to the vast knowledge of Laurence Withers (lwithers) and this message: - # http://mail.python.org/pipermail/python-list/2006-November/587523.html - if not os.fork(): - null = os.open(os.devnull,os.O_WRONLY) - for i in range(3): os.dup2(null,i) - os.close(null) - subprocess.Popen(cmd) - print 'USED' - -if __name__ == '__main__': - uri = sys.argv[8] - u = urlparse.urlparse(uri) - if u.scheme == 'mailto': - detach_open(['xterm', '-e', 'mail', u.path]) - elif u.scheme == 'xmpp': - # Someone check for safe arguments to gajim-remote - detach_open(['gajim-remote', 'open_chat', uri]) - elif u.scheme == 'git': - detach_open(['git', 'clone', '--', uri], cwd=os.path.expanduser('~/src')) diff --git a/examples/data/uzbl/scripts/scroll-percentage.js b/examples/data/uzbl/scripts/scroll-percentage.js deleted file mode 100644 index c9a51aa..0000000 --- a/examples/data/uzbl/scripts/scroll-percentage.js +++ /dev/null @@ -1,68 +0,0 @@ -// VIM ruler style scroll message -(function() { - var run = Uzbl.run; - var update_message = function() { - var innerHeight = window.innerHeight; - var scrollY = window.scrollY; - var height = document.height; - var message; - - if (UzblZoom.type === "full") { - var zoom_level = UzblZoom.level; - innerHeight = Math.ceil(innerHeight * zoom_level); - scrollY = Math.ceil(scrollY * zoom_level); - height -= 1; - } - - if (! height) { - message = ""; - } - else if (height <= innerHeight) { - message = run("print @scroll_all_indicator") || "All"; - } - else if (scrollY === 0) { - message = run("print @scroll_top_indicator") || "Top"; - } - else if (scrollY + innerHeight >= height) { - message = run("print @scroll_bottom_indicator") || "Bot"; - } - else { - var percentage = Math.round(scrollY / (height - innerHeight) * 100); - message = percentage + "%"; - } - run("set scroll_message=" + message); - }; - - self.UzblZoom = { - get level() { - return Number(run("print @zoom_level")) || 1; - }, - set level(level) { - if (typeof level === "number" && level > 0) { - run("set zoom_level = " + level); - update_message(); - } - }, - get type() { - return run("print @zoom_type") || "text"; - }, - set type(type) { - if ((type === "text" || type === "full") && this.type != type) { - run("toggle_zoom_type"); - run("set zoom_type = " + type); - update_message(); - } - }, - toggle_type: function() { - this.type = (this.type === "text" ? "full" : "text"); - } - }; - - window.addEventListener("DOMContentLoaded", update_message, false); - window.addEventListener("load", update_message, false); - window.addEventListener("resize", update_message, false); - window.addEventListener("scroll", update_message, false); - update_message(); -})(); - -// vim: set noet ff=unix diff --git a/examples/data/uzbl/scripts/session.sh b/examples/data/uzbl/scripts/session.sh deleted file mode 100755 index 1059b5e..0000000 --- a/examples/data/uzbl/scripts/session.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -# Very simple session manager for uzbl-browser. When called with "endsession" as the -# argument, it'll backup $sessionfile, look for fifos in $fifodir and -# instruct each of them to store their current url in $sessionfile and -# terminate themselves. Run with "launch" as the argument and an instance of -# uzbl-browser will be launched for each stored url. "endinstance" is used internally -# and doesn't need to be called manually at any point. -# Add a line like 'bind quit = /path/to/session.sh endsession' to your config - -[ -d ${XDG_DATA_HOME:-$HOME/.local/share}/uzbl ] || exit 1 -scriptfile=$0 # this script -sessionfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/browser-session # the file in which the "session" (i.e. urls) are stored -configfile=${XDG_DATA_HOME:-$HOME/.local/share}/uzbl/config # uzbl configuration file -UZBL="uzbl-browser -c $configfile" # add custom flags and whatever here. - -fifodir=/tmp # remember to change this if you instructed uzbl to put its fifos elsewhere -thisfifo="$4" -act="$8" -url="$6" - -if [ "$act." = "." ]; then - act="$1" -fi - - -case $act in - "launch" ) - urls=`cat $sessionfile` - if [ "$urls." = "." ]; then - $UZBL - else - for url in $urls; do - $UZBL --uri "$url" & - done - fi - exit 0 - ;; - - "endinstance" ) - if [ "$url" != "(null)" ]; then - echo "$url" >> $sessionfile; - fi - echo "exit" > "$thisfifo" - ;; - - "endsession" ) - mv "$sessionfile" "$sessionfile~" - for fifo in $fifodir/uzbl_fifo_*; do - if [ "$fifo" != "$thisfifo" ]; then - echo "spawn $scriptfile endinstance" > "$fifo" - fi - done - echo "spawn $scriptfile endinstance" > "$thisfifo" - ;; - - * ) echo "session manager: bad action" - echo "Usage: $scriptfile [COMMAND] where commands are:" - echo " launch - Restore a saved session or start a new one" - echo " endsession - Quit the running session. Must be called from uzbl" - ;; -esac diff --git a/examples/data/uzbl/scripts/uzbl-cookie-daemon b/examples/data/uzbl/scripts/uzbl-cookie-daemon deleted file mode 100755 index fde8b8e..0000000 --- a/examples/data/uzbl/scripts/uzbl-cookie-daemon +++ /dev/null @@ -1,664 +0,0 @@ -#!/usr/bin/env python - -# The Python Cookie Daemon for Uzbl. -# Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, Dieter Plaetinck -# Copyright (c) 2009, Mason Larobina -# Copyright (c) 2009, Michael Fiano -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -''' -The Python Cookie Daemon -======================== - -This daemon is a re-write of the original cookies.py script found in uzbl's -master branch. This script provides more functionality than the original -cookies.py by adding numerous command line options to specify different cookie -jar locations, socket locations, verbose output, etc. This functionality is -very useful as it allows you to run multiple daemons at once serving cookies -to different groups of uzbl instances as required. - -Keeping up to date -================== - -Check the cookie daemon uzbl-wiki page for more information on where to -find the latest version of the cookie_daemon.py - - http://www.uzbl.org/wiki/cookie_daemon.py - -Command line options -==================== - -Use the following command to get a full list of the cookie_daemon.py command -line options: - - ./cookie_daemon.py --help - -Talking with uzbl -================= - -In order to get uzbl to talk to a running cookie daemon you add the following -to your uzbl config: - - set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket - -Or if you prefer using the $HOME variable: - - set cookie_handler = talk_to_socket $HOME/.cache/uzbl/cookie_daemon_socket - -Todo list -========= - - - Use a pid file to make force killing a running daemon possible. - -Reporting bugs / getting help -============================= - -The best way to report bugs and or get help with the cookie daemon is to -contact the maintainers it the #uzbl irc channel found on the Freenode IRC -network (irc.freenode.org). -''' - -import cookielib -import os -import sys -import urllib2 -import select -import socket -import time -import atexit -from traceback import print_exc -from signal import signal, SIGTERM -from optparse import OptionParser -from os.path import join - -try: - import cStringIO as StringIO - -except ImportError: - import StringIO - - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return join(os.environ['HOME'], default) - -# Setup xdg paths. -CACHE_DIR = join(xdghome('CACHE', '.cache/'), 'uzbl/') -DATA_DIR = join(xdghome('DATA', '.local/share/'), 'uzbl/') -CONFIG_DIR = join(xdghome('CONFIG', '.config/'), 'uzbl/') - -# Ensure data paths exist. -for path in [CACHE_DIR, DATA_DIR, CONFIG_DIR]: - if not os.path.exists(path): - os.makedirs(path) - -# Default config -config = { - - # Default cookie jar, whitelist, and daemon socket locations. - 'cookie_jar': join(DATA_DIR, 'cookies.txt'), - 'cookie_whitelist': join(CONFIG_DIR, 'cookie_whitelist'), - 'cookie_socket': join(CACHE_DIR, 'cookie_daemon_socket'), - - # Don't use a cookie whitelist policy by default. - 'use_whitelist': False, - - # Time out after x seconds of inactivity (set to 0 for never time out). - # WARNING: Do not use this option if you are manually launching the daemon. - 'daemon_timeout': 0, - - # Daemonise by default. - 'daemon_mode': True, - - # Optionally print helpful debugging messages to the terminal. - 'verbose': False, - -} # End of config dictionary. - - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - - -_SCRIPTNAME = os.path.basename(sys.argv[0]) -def echo(msg): - '''Prints only if the verbose flag has been set.''' - - if config['verbose']: - sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) - - -def error(msg): - '''Prints error message and exits.''' - - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - sys.exit(1) - - -def mkbasedir(filepath): - '''Create the base directories of the file in the file-path if the dirs - don't exist.''' - - dirname = os.path.dirname(filepath) - if not os.path.exists(dirname): - echo("creating dirs: %r" % dirname) - os.makedirs(dirname) - - -def daemon_running(cookie_socket): - '''Check if another process (hopefully a cookie_daemon.py) is listening - on the cookie daemon socket. If another process is found to be - listening on the socket exit the daemon immediately and leave the - socket alone. If the connect fails assume the socket has been abandoned - and delete it (to be re-created in the create socket function).''' - - if not os.path.exists(cookie_socket): - return False - - if os.path.isfile(cookie_socket): - raise Exception("regular file at %r is not a socket" % cookie_socket) - - - if os.path.isdir(cookie_socket): - raise Exception("directory at %r is not a socket" % cookie_socket) - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(cookie_socket) - sock.close() - echo("detected daemon listening on %r" % cookie_socket) - return True - - except socket.error: - # Failed to connect to cookie_socket so assume it has been - # abandoned by another cookie daemon process. - if os.path.exists(cookie_socket): - echo("deleting abandoned socket at %r" % cookie_socket) - os.remove(cookie_socket) - - return False - - -def send_command(cookie_socket, cmd): - '''Send a command to a running cookie daemon.''' - - if not daemon_running(cookie_socket): - return False - - try: - sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - sock.connect(cookie_socket) - sock.send(cmd) - sock.close() - echo("sent command %r to %r" % (cmd, cookie_socket)) - return True - - except socket.error: - print_exc() - error("failed to send message %r to %r" % (cmd, cookie_socket)) - return False - - -def kill_daemon(cookie_socket): - '''Send the "EXIT" command to running cookie_daemon.''' - - if send_command(cookie_socket, "EXIT"): - # Now ensure the cookie_socket is cleaned up. - start = time.time() - while os.path.exists(cookie_socket): - time.sleep(0.1) - if (time.time() - start) > 5: - error("force deleting socket %r" % cookie_socket) - os.remove(cookie_socket) - return - - echo("stopped daemon listening on %r"% cookie_socket) - - else: - if os.path.exists(cookie_socket): - os.remove(cookie_socket) - echo("removed abandoned/broken socket %r" % cookie_socket) - - -def daemonize(): - '''Daemonize the process using the Stevens' double-fork magic.''' - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #1 failed") - sys.exit(1) - - os.chdir('/') - os.setsid() - os.umask(0) - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #2 failed") - sys.exit(1) - - sys.stdout.flush() - sys.stderr.flush() - - devnull = '/dev/null' - stdin = file(devnull, 'r') - stdout = file(devnull, 'a+') - stderr = file(devnull, 'a+', 0) - - os.dup2(stdin.fileno(), sys.stdin.fileno()) - os.dup2(stdout.fileno(), sys.stdout.fileno()) - os.dup2(stderr.fileno(), sys.stderr.fileno()) - - -class CookieMonster: - '''The uzbl cookie daemon class.''' - - def __init__(self): - '''Initialise class variables.''' - - self.server_socket = None - self.jar = None - self.last_request = time.time() - self._running = False - - - def run(self): - '''Start the daemon.''' - - # The check healthy function will exit if another daemon is detected - # listening on the cookie socket and remove the abandoned socket if - # there isnt. - if os.path.exists(config['cookie_socket']): - if daemon_running(config['cookie_socket']): - sys.exit(1) - - # Create cookie daemon socket. - self.create_socket() - - # Daemonize process. - if config['daemon_mode']: - echo("entering daemon mode") - daemonize() - - # Register a function to cleanup on exit. - atexit.register(self.quit) - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - - # Create cookie jar object from file. - self.open_cookie_jar() - - # Create a way to exit nested loops by setting a running flag. - self._running = True - - while self._running: - try: - # Enter main listen loop. - self.listen() - - except KeyboardInterrupt: - self._running = False - print - - except socket.error: - print_exc() - - except: - # Clean up - self.del_socket() - - # Raise exception - raise - - # Always delete the socket before calling create again. - self.del_socket() - # Create cookie daemon socket. - self.create_socket() - - - def load_whitelist(self): - '''Load the cookie jar whitelist policy.''' - - cookie_whitelist = config['cookie_whitelist'] - - if cookie_whitelist: - mkbasedir(cookie_whitelist) - - # Create cookie whitelist file if it does not exist. - if not os.path.exists(cookie_whitelist): - open(cookie_whitelist, 'w').close() - - # Read cookie whitelist file into list. - file = open(cookie_whitelist,'r') - domain_list = [line.rstrip('\n') for line in file] - file.close() - - # Define policy of allowed domains - policy = cookielib.DefaultCookiePolicy(allowed_domains=domain_list) - self.jar.set_policy(policy) - - # Save the last modified time of the whitelist. - self._whitelistmtime = os.stat(cookie_whitelist).st_mtime - - - def open_cookie_jar(self): - '''Open the cookie jar.''' - - cookie_jar = config['cookie_jar'] - cookie_whitelist = config['cookie_whitelist'] - - if cookie_jar: - mkbasedir(cookie_jar) - - # Create cookie jar object from file. - self.jar = cookielib.MozillaCookieJar(cookie_jar) - - # Load cookie whitelist policy. - if config['use_whitelist']: - self.load_whitelist() - - if cookie_jar: - try: - # Attempt to load cookies from the cookie jar. - self.jar.load(ignore_discard=True) - - # Ensure restrictive permissions are set on the cookie jar - # to prevent other users on the system from hi-jacking your - # authenticated sessions simply by copying your cookie jar. - os.chmod(cookie_jar, 0600) - - except: - pass - - - def reload_whitelist(self): - '''Reload the cookie whitelist.''' - - cookie_whitelist = config['cookie_whitelist'] - if os.path.exists(cookie_whitelist): - echo("reloading whitelist %r" % cookie_whitelist) - self.open_cookie_jar() - - - def create_socket(self): - '''Create AF_UNIX socket for communication with uzbl instances.''' - - cookie_socket = config['cookie_socket'] - mkbasedir(cookie_socket) - - self.server_socket = socket.socket(socket.AF_UNIX, - socket.SOCK_SEQPACKET) - - self.server_socket.bind(cookie_socket) - - # Set restrictive permissions on the cookie socket to prevent other - # users on the system from data-mining your cookies. - os.chmod(cookie_socket, 0600) - - - def listen(self): - '''Listen for incoming cookie PUT and GET requests.''' - - daemon_timeout = config['daemon_timeout'] - echo("listening on %r" % config['cookie_socket']) - - while self._running: - # This line tells the socket how many pending incoming connections - # to enqueue at once. Raising this number may or may not increase - # performance. - self.server_socket.listen(1) - - if bool(select.select([self.server_socket], [], [], 1)[0]): - client_socket, _ = self.server_socket.accept() - self.handle_request(client_socket) - self.last_request = time.time() - client_socket.close() - continue - - if daemon_timeout: - # Checks if the daemon has been idling for too long. - idle = time.time() - self.last_request - if idle > daemon_timeout: - self._running = False - - - def handle_request(self, client_socket): - '''Connection made, now to serve a cookie PUT or GET request.''' - - # Receive cookie request from client. - data = client_socket.recv(8192) - if not data: - return - - # Cookie argument list in packet is null separated. - argv = data.split("\0") - action = argv[0].upper().strip() - - # Catch the EXIT command sent to kill running daemons. - if action == "EXIT": - self._running = False - return - - # Catch whitelist RELOAD command. - elif action == "RELOAD": - self.reload_whitelist() - return - - # Return if command unknown. - elif action not in ['GET', 'PUT']: - error("unknown command %r." % argv) - return - - # Determine whether or not to print cookie data to terminal. - print_cookie = (config['verbose'] and not config['daemon_mode']) - if print_cookie: - print ' '.join(argv[:4]) - - uri = urllib2.urlparse.ParseResult( - scheme=argv[1], - netloc=argv[2], - path=argv[3], - params='', - query='', - fragment='').geturl() - - req = urllib2.Request(uri) - - if action == "GET": - self.jar.add_cookie_header(req) - if req.has_header('Cookie'): - cookie = req.get_header('Cookie') - client_socket.send(cookie) - if print_cookie: - print cookie - - else: - client_socket.send("\0") - - elif action == "PUT": - cookie = argv[4] if len(argv) > 3 else None - if print_cookie: - print cookie - - self.put_cookie(req, cookie) - - if print_cookie: - print - - - def put_cookie(self, req, cookie=None): - '''Put a cookie in the cookie jar.''' - - hdr = urllib2.httplib.HTTPMessage(\ - StringIO.StringIO('Set-Cookie: %s' % cookie)) - res = urllib2.addinfourl(StringIO.StringIO(), hdr, - req.get_full_url()) - self.jar.extract_cookies(res, req) - if config['cookie_jar']: - self.jar.save(ignore_discard=True) - - - def del_socket(self): - '''Remove the cookie_socket file on exit. In a way the cookie_socket - is the daemons pid file equivalent.''' - - if self.server_socket: - try: - self.server_socket.close() - - except: - pass - - self.server_socket = None - - cookie_socket = config['cookie_socket'] - if os.path.exists(cookie_socket): - echo("deleting socket %r" % cookie_socket) - os.remove(cookie_socket) - - - def quit(self): - '''Called on exit to make sure all loose ends are tied up.''' - - self.del_socket() - sys.exit(0) - - -def main(): - '''Main function.''' - - # Define command line parameters. - usage = "usage: %prog [options] {start|stop|restart|reload}" - parser = OptionParser(usage=usage) - parser.add_option('-n', '--no-daemon', dest='no_daemon', - action='store_true', help="don't daemonise the process.") - - parser.add_option('-v', '--verbose', dest="verbose", - action='store_true', help="print verbose output.") - - parser.add_option('-t', '--daemon-timeout', dest='daemon_timeout', - action="store", metavar="SECONDS", help="shutdown the daemon after x "\ - "seconds inactivity. WARNING: Do not use this when launching the "\ - "cookie daemon manually.") - - parser.add_option('-s', '--cookie-socket', dest="cookie_socket", - metavar="SOCKET", help="manually specify the socket location.") - - parser.add_option('-j', '--cookie-jar', dest='cookie_jar', - metavar="FILE", help="manually specify the cookie jar location.") - - parser.add_option('-m', '--memory', dest='memory', action='store_true', - help="store cookies in memory only - do not write to disk") - - parser.add_option('-u', '--use-whitelist', dest='usewhitelist', - action='store_true', help="use cookie whitelist policy") - - parser.add_option('-w', '--cookie-whitelist', dest='whitelist', - action='store', help="manually specify whitelist location", - metavar='FILE') - - # Parse the command line arguments. - (options, args) = parser.parse_args() - - expand = lambda p: os.path.realpath(os.path.expandvars(p)) - - initcommands = ['start', 'stop', 'restart', 'reload'] - for arg in args: - if arg not in initcommands: - error("unknown argument %r" % args[0]) - sys.exit(1) - - if len(args) > 1: - error("the daemon only accepts one {%s} action at a time." - % '|'.join(initcommands)) - sys.exit(1) - - if len(args): - action = args[0] - - else: - action = "start" - - if options.no_daemon: - config['daemon_mode'] = False - - if options.cookie_socket: - config['cookie_socket'] = expand(options.cookie_socket) - - if options.cookie_jar: - config['cookie_jar'] = expand(options.cookie_jar) - - if options.memory: - config['cookie_jar'] = None - - if options.whitelist: - config['cookie_whitelist'] = expand(options.whitelist) - - if options.whitelist or options.usewhitelist: - config['use_whitelist'] = True - - if options.daemon_timeout: - try: - config['daemon_timeout'] = int(options.daemon_timeout) - - except ValueError: - error("expected int argument for -t, --daemon-timeout") - - # Expand $VAR's in config keys that relate to paths. - for key in ['cookie_socket', 'cookie_jar', 'cookie_whitelist']: - if config[key]: - config[key] = os.path.expandvars(config[key]) - - if options.verbose: - config['verbose'] = True - import pprint - sys.stderr.write("%s\n" % pprint.pformat(config)) - - # It would be better if we didn't need to start this python process just - # to send a command to the socket, but unfortunately socat doesn't seem - # to support SEQPACKET. - if action == "reload": - send_command(config['cookie_socket'], "RELOAD") - - if action in ['stop', 'restart']: - kill_daemon(config['cookie_socket']) - - if action in ['start', 'restart']: - CookieMonster().run() - - -if __name__ == "__main__": - main() diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager deleted file mode 100755 index b3fdb3c..0000000 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ /dev/null @@ -1,833 +0,0 @@ -#!/usr/bin/env python - -# Event Manager for Uzbl -# Copyright (c) 2009, Mason Larobina -# Copyright (c) 2009, Dieter Plaetinck -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -''' - -E V E N T _ M A N A G E R . P Y -=============================== - -Event manager for uzbl written in python. - -''' - -import imp -import os -import sys -import re -import socket -import pprint -import time -import atexit -from select import select -from signal import signal, SIGTERM -from optparse import OptionParser -from traceback import print_exc -from functools import partial - - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return os.path.join(os.environ['HOME'], default) - - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -# `make install` will put the correct value here for your system -PREFIX = '/usr/local/' - -# Setup xdg paths. -DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') -CACHE_DIR = os.path.join(xdghome('CACHE', '.cache/'), 'uzbl/') - -# Event manager config dictionary. This is not to be confused with the config -# dict that tracks variables in the uzbl instance. -CONFIG = { - 'verbose': False, - 'daemon_mode': True, - 'auto_close': False, - - 'plugins_load': [], - 'plugins_ignore': [], - - 'plugin_dirs': [os.path.join(DATA_DIR, 'plugins/'), - os.path.join(PREFIX, 'share/uzbl/examples/data/uzbl/plugins/')], - - 'server_socket': os.path.join(CACHE_DIR, 'event_daemon'), - 'pid_file': os.path.join(CACHE_DIR, 'event_daemon.pid'), -} - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - - -# Define some globals. -SCRIPTNAME = os.path.basename(sys.argv[0]) -FINDSPACES = re.compile("\s+") - - -class ArgumentError(Exception): - pass - - -def echo(msg): - '''Prints only if the verbose flag has been set.''' - - if CONFIG['verbose']: - sys.stdout.write("%s: %s\n" % (SCRIPTNAME, msg)) - - -def error(msg): - '''Prints error messages to stderr.''' - - sys.stderr.write("%s: error: %s\n" % (SCRIPTNAME, msg)) - - -def counter(): - '''Generate unique object id's.''' - - i = 0 - while True: - i += 1 - yield i - - -def find_plugins(plugin_dirs): - '''Find all event manager plugins in the plugin dirs and return a - dictionary of {'plugin-name.py': '/full/path/to/plugin-name.py', ...}''' - - plugins = {} - - for plugin_dir in plugin_dirs: - plugin_dir = os.path.realpath(os.path.expandvars(plugin_dir)) - if not os.path.isdir(plugin_dir): - continue - - for filename in os.listdir(plugin_dir): - if not filename.lower().endswith('.py'): - continue - - path = os.path.join(plugin_dir, filename) - if not os.path.isfile(path): - continue - - if filename not in plugins: - plugins[filename] = plugin_dir - - return plugins - - -def load_plugins(plugin_dirs, load=None, ignore=None): - '''Load event manager plugins found in the plugin_dirs.''' - - load = [] if load is None else load - ignore = [] if ignore is None else ignore - - # Find the plugins in the plugin_dirs. - found = find_plugins(plugin_dirs) - - if load: - # Ignore anything not in the load list. - for plugin in found.keys(): - if plugin not in load: - del found[plugin] - - if ignore: - # Ignore anything in the ignore list. - for plugin in found.keys(): - if plugin in ignore: - del found[plugin] - - # Print plugin list to be loaded. - pprint.pprint(found) - - loaded = {} - # Load all found plugins into the loaded dict. - for (filename, plugin_dir) in found.items(): - name = filename[:-3] - info = imp.find_module(name, [plugin_dir]) - plugin = imp.load_module(name, *info) - loaded[(plugin_dir, filename)] = plugin - - return loaded - - -def daemonize(): - '''Daemonize the process using the Stevens' double-fork magic.''' - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #1 failed") - sys.exit(1) - - os.chdir('/') - os.setsid() - os.umask(0) - - try: - if os.fork(): - os._exit(0) - - except OSError: - print_exc() - sys.stderr.write("fork #2 failed") - sys.exit(1) - - sys.stdout.flush() - sys.stderr.flush() - - devnull = '/dev/null' - stdin = file(devnull, 'r') - stdout = file(devnull, 'a+') - stderr = file(devnull, 'a+', 0) - - os.dup2(stdin.fileno(), sys.stdin.fileno()) - os.dup2(stdout.fileno(), sys.stdout.fileno()) - os.dup2(stderr.fileno(), sys.stderr.fileno()) - - -def make_dirs(path): - '''Make all basedirs recursively as required.''' - - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - - -def make_pid_file(pid_file): - '''Make pid file at given pid_file location.''' - - make_dirs(pid_file) - fileobj = open(pid_file, 'w') - fileobj.write('%d' % os.getpid()) - fileobj.close() - - -def del_pid_file(pid_file): - '''Delete pid file at given pid_file location.''' - - if os.path.isfile(pid_file): - os.remove(pid_file) - - -def get_pid(pid_file): - '''Read pid from pid_file.''' - - try: - fileobj = open(pid_file, 'r') - pid = int(fileobj.read()) - fileobj.close() - return pid - - except IOError, ValueError: - print_exc() - return None - - -def pid_running(pid): - '''Returns True if a process with the given pid is running.''' - - try: - os.kill(pid, 0) - - except OSError: - return False - - else: - return True - - -def term_process(pid): - '''Send a SIGTERM signal to the process with the given pid.''' - - if not pid_running(pid): - return False - - os.kill(pid, SIGTERM) - - start = time.time() - while True: - if not pid_running(pid): - return True - - if time.time() - start > 5: - raise OSError('failed to stop process with pid: %d' % pid) - - time.sleep(0.25) - - -def parse_msg(uzbl, msg): - '''Parse an incoming msg from a uzbl instance. All non-event messages - will be printed here and not be passed to the uzbl instance event - handler function.''' - - if not msg: - return - - cmd = FINDSPACES.split(msg, 3) - if not cmd or cmd[0] != 'EVENT': - # Not an event message. - print '---', msg - return - - while len(cmd) < 4: - cmd.append('') - - event, args = cmd[2], cmd[3] - if not event: - return - - try: - uzbl.event(event, args) - - except: - print_exc() - - -class EventHandler(object): - - nexthid = counter().next - - def __init__(self, event, handler, *args, **kargs): - if not callable(handler): - raise ArgumentError("EventHandler object requires a callable " - "object function for the handler argument not: %r" % handler) - - self.function = handler - self.args = args - self.kargs = kargs - self.event = event - self.hid = self.nexthid() - - - def __repr__(self): - args = ["event=%s" % self.event, "hid=%d" % self.hid, - "function=%r" % self.function] - - if self.args: - args.append("args=%r" % self.args) - - if self.kargs: - args.append("kargs=%r" % self.kargs) - - return "" % ', '.join(args) - - -class UzblInstance(object): - - # Give all plugins access to the main config dict. - config = CONFIG - - def __init__(self, parent, client_socket): - - # Internal variables. - self.exports = {} - self.handlers = {} - self.parent = parent - self.client_socket = client_socket - - self.depth = 0 - self.buffer = '' - self.pid = None - - # Call the init function in every plugin. The init function in each - # plugin is where that plugin connects functions to events and exports - # functions to the uzbl object. - for plugin in self.parent['plugins'].values(): - try: - plugin.init(self) - - except: - raise - - - def send(self, msg): - '''Send a command to the uzbl instance via the socket file.''' - - msg = msg.strip() - if self.client_socket: - print '%s<-- %s' % (' ' * self.depth, msg) - self.client_socket.send(("%s\n" % msg).encode('utf-8')) - - else: - print '%s!-- %s' % (' ' * self.depth, msg) - - - def export(self, name, function): - '''Export `function(uzbl, *args, ..)` inside a plugin to the uzbl - object like so `uzbl.function(*args, ..)`. This will allow other - plugins to call functions inside the current plugin (which is currently - calling this function) via the uzbl object.''' - - self.__dict__.__setitem__(name, partial(function, self)) - - - def export_dict(self, export_dict): - '''Export multiple (name, function)'s at once inside a dict of the - form `{name1: function1, name2: function2, ...}`.''' - - for (name, function) in export_dict.items(): - self.export(name, function) - - - def connect(self, event, handler, *args, **kargs): - '''Connect a uzbl event with a handler. Handlers can either be a - function or a uzbl command string.''' - - event = event.upper().strip() - assert event and ' ' not in event - - if event not in self.handlers.keys(): - self.handlers[event] = [] - - handlerobj = EventHandler(event, handler, *args, **kargs) - self.handlers[event].append(handlerobj) - print handlerobj - - - def connect_dict(self, connect_dict): - '''Connect a dictionary comprising of {"EVENT_NAME": handler, ..} to - the event handler stack. - - If you need to supply args or kargs to an event use the normal connect - function.''' - - for (event, handler) in connect_dict.items(): - self.connect(event, handler) - - - def remove_by_id(self, hid): - '''Remove connected event handler by unique handler id.''' - - for (event, handlers) in self.handlers.items(): - for handler in list(handlers): - if hid != handler.hid: - continue - - echo("removed %r" % handler) - handlers.remove(handler) - return - - echo('unable to find & remove handler with id: %d' % hid) - - - def remove(self, handler): - '''Remove connected event handler.''' - - for (event, handlers) in self.handlers.items(): - if handler in handlers: - echo("removed %r" % handler) - handlers.remove(handler) - return - - echo('unable to find & remove handler: %r' % handler) - - - def exec_handler(self, handler, *args, **kargs): - '''Execute event handler function.''' - - args += handler.args - kargs = dict(handler.kargs.items()+kargs.items()) - handler.function(self, *args, **kargs) - - - def event(self, event, *args, **kargs): - '''Raise an event.''' - - event = event.upper() - elems = [event,] - if args: elems.append(unicode(args)) - if kargs: elems.append(unicode(kargs)) - print "%s--> %s" % (' ' * self.depth, ' '.join(elems)) - - if event == "INSTANCE_START" and args: - self.pid = int(args[0]) - - if event not in self.handlers: - return - - for handler in self.handlers[event]: - self.depth += 1 - try: - self.exec_handler(handler, *args, **kargs) - - except: - print_exc() - - self.depth -= 1 - - - def close(self): - '''Close the client socket and clean up.''' - - try: - self.client_socket.close() - - except: - pass - - for (name, plugin) in self.parent['plugins'].items(): - if hasattr(plugin, 'cleanup'): - plugin.cleanup(self) - - -class UzblEventDaemon(dict): - def __init__(self): - - # Init variables and dict keys. - dict.__init__(self, {'uzbls': {}}) - self.running = None - self.server_socket = None - self.socket_location = None - - # Register that the event daemon server has started by creating the - # pid file. - make_pid_file(CONFIG['pid_file']) - - # Register a function to clean up the socket and pid file on exit. - atexit.register(self.quit) - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: sys.exit(1)) - - # Load plugins, first-build of the plugins may be a costly operation. - self['plugins'] = load_plugins(CONFIG['plugin_dirs'], - CONFIG['plugins_load'], CONFIG['plugins_ignore']) - - - def _create_server_socket(self): - '''Create the event manager daemon socket for uzbl instance duplex - communication.''' - - server_socket = CONFIG['server_socket'] - server_socket = os.path.realpath(os.path.expandvars(server_socket)) - self.socket_location = server_socket - - # Delete socket if it exists. - if os.path.exists(server_socket): - os.remove(server_socket) - - self.server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.server_socket.bind(server_socket) - self.server_socket.listen(5) - - - def _close_server_socket(self): - '''Close and delete the server socket.''' - - try: - self.server_socket.close() - self.server_socket = None - - if os.path.exists(self.socket_location): - os.remove(self.socket_location) - - except: - pass - - - def run(self): - '''Main event daemon loop.''' - - # Create event daemon socket. - self._create_server_socket() - echo('listening on: %s' % self.socket_location) - - if CONFIG['daemon_mode']: - echo('entering daemon mode.') - daemonize() - # The pid has changed so update the pid file. - make_pid_file(CONFIG['pid_file']) - - # Now listen for incoming connections and or data. - self.listen() - - # Clean up. - self.quit() - - - def listen(self): - '''Accept incoming connections and constantly poll instance sockets - for incoming data.''' - - self.running = True - while self.running: - - sockets = [self.server_socket] + self['uzbls'].keys() - - reads, _, errors = select(sockets, [], sockets, 1) - - if self.server_socket in reads: - self.accept_connection() - reads.remove(self.server_socket) - - for client in reads: - self.read_socket(client) - - for client in errors: - error('Unknown error on socket: %r' % client) - self.close_connection(client) - - - def read_socket(self, client): - '''Read data from an instance socket and pass to the uzbl objects - event handler function.''' - - uzbl = self['uzbls'][client] - try: - raw = unicode(client.recv(8192), 'utf-8', 'ignore') - - except: - print_exc() - raw = None - - if not raw: - # Read null byte, close socket. - return self.close_connection(client) - - uzbl.buffer += raw - msgs = uzbl.buffer.split('\n') - uzbl.buffer = msgs.pop() - - for msg in msgs: - try: - parse_msg(uzbl, msg.strip()) - - except: - print_exc() - - - def accept_connection(self): - '''Accept incoming connection to the server socket.''' - - client_socket = self.server_socket.accept()[0] - - uzbl = UzblInstance(self, client_socket) - self['uzbls'][client_socket] = uzbl - - - def close_connection(self, client): - '''Clean up after instance close.''' - - try: - if client in self['uzbls']: - uzbl = self['uzbls'][client] - uzbl.close() - del self['uzbls'][client] - - except: - print_exc() - - if not len(self['uzbls']) and CONFIG['auto_close']: - echo('auto closing event manager.') - self.running = False - - - def quit(self): - '''Close all instance socket objects, server socket and delete the - pid file.''' - - echo('shutting down event manager.') - - for client in self['uzbls'].keys(): - self.close_connection(client) - - echo('unlinking: %r' % self.socket_location) - self._close_server_socket() - - echo('deleting pid file: %r' % CONFIG['pid_file']) - del_pid_file(CONFIG['pid_file']) - - -def stop_action(): - '''Stop the event manager daemon.''' - - pid_file = CONFIG['pid_file'] - if not os.path.isfile(pid_file): - return echo('no running daemon found.') - - echo('found pid file: %r' % pid_file) - pid = get_pid(pid_file) - if not pid_running(pid): - echo('no process with pid: %d' % pid) - return os.remove(pid_file) - - echo("terminating process with pid: %d" % pid) - term_process(pid) - if os.path.isfile(pid_file): - os.remove(pid_file) - - echo('stopped event daemon.') - - -def start_action(): - '''Start the event manager daemon.''' - - pid_file = CONFIG['pid_file'] - if os.path.isfile(pid_file): - echo('found pid file: %r' % pid_file) - pid = get_pid(pid_file) - if pid_running(pid): - return echo('event daemon already started with pid: %d' % pid) - - echo('no process with pid: %d' % pid) - os.remove(pid_file) - - echo('starting event manager.') - UzblEventDaemon().run() - - -def restart_action(): - '''Restart the event manager daemon.''' - - echo('restarting event manager daemon.') - stop_action() - start_action() - - -def list_action(): - '''List all the plugins being loaded by the event daemon.''' - - plugins = find_plugins(CONFIG['plugin_dirs']) - dirs = {} - - for (plugin, plugin_dir) in plugins.items(): - if plugin_dir not in dirs: - dirs[plugin_dir] = [] - - dirs[plugin_dir].append(plugin) - - for (index, (plugin_dir, plugin_list)) in enumerate(sorted(dirs.items())): - if index: - print - - print "%s:" % plugin_dir - for plugin in sorted(plugin_list): - print " %s" % plugin - - -if __name__ == "__main__": - USAGE = "usage: %prog [options] {start|stop|restart|list}" - PARSER = OptionParser(usage=USAGE) - PARSER.add_option('-v', '--verbose', dest='verbose', action="store_true", - help="print verbose output.") - - PARSER.add_option('-d', '--plugin-dirs', dest='plugin_dirs', action="store", - metavar="DIRS", help="Specify plugin directories in the form of "\ - "'dir1:dir2:dir3'.") - - PARSER.add_option('-l', '--load-plugins', dest="load", action="store", - metavar="PLUGINS", help="comma separated list of plugins to load") - - PARSER.add_option('-i', '--ignore-plugins', dest="ignore", action="store", - metavar="PLUGINS", help="comma separated list of plugins to ignore") - - PARSER.add_option('-p', '--pid-file', dest='pid', action='store', - metavar='FILE', help="specify pid file location") - - PARSER.add_option('-s', '--server-socket', dest='socket', action='store', - metavar='SOCKET', help="specify the daemon socket location") - - PARSER.add_option('-n', '--no-daemon', dest="daemon", - action="store_true", help="don't enter daemon mode.") - - PARSER.add_option('-a', '--auto-close', dest='autoclose', - action='store_true', help='auto close after all instances disconnect.') - - (OPTIONS, ARGS) = PARSER.parse_args() - - # init like {start|stop|..} daemon actions dict. - DAEMON_ACTIONS = {'start': start_action, 'stop': stop_action, - 'restart': restart_action, 'list': list_action} - - if not ARGS: - ACTION = 'start' - - elif len(ARGS) == 1: - ACTION = ARGS[0] - if ACTION not in DAEMON_ACTIONS: - raise ArgumentError("unknown argument: %r" % ACTION) - - else: - raise ArgumentError("too many arguments: %r" % ARGS) - - # parse other flags & options. - if OPTIONS.verbose: - CONFIG['verbose'] = True - - if OPTIONS.plugin_dirs: - PLUGIN_DIRS = [] - for DIR in OPTIONS.plugin_dirs.split(':'): - if not DIR: - continue - - PLUGIN_DIRS.append(os.path.realpath(DIR)) - - CONFIG['plugin_dirs'] = PLUGIN_DIRS - echo("plugin search dirs: %r" % PLUGIN_DIRS) - - if OPTIONS.load and OPTIONS.ignore: - error("you can't load and ignore at the same time.") - sys.exit(1) - - elif OPTIONS.load: - LOAD = CONFIG['plugins_load'] - for PLUGIN in OPTIONS.load.split(','): - if PLUGIN.strip(): - LOAD.append(PLUGIN.strip()) - - echo('only loading plugin(s): %s' % ', '.join(LOAD)) - - elif OPTIONS.ignore: - IGNORE = CONFIG['plugins_ignore'] - for PLUGIN in OPTIONS.ignore.split(','): - if PLUGIN.strip(): - IGNORE.append(PLUGIN.strip()) - - echo('ignoring plugin(s): %s' % ', '.join(IGNORE)) - - if OPTIONS.autoclose: - CONFIG['auto_close'] = True - echo('will auto close.') - - if OPTIONS.pid: - CONFIG['pid_file'] = os.path.realpath(OPTIONS.pid) - echo("pid file location: %r" % CONFIG['pid_file']) - - if OPTIONS.socket: - CONFIG['server_socket'] = os.path.realpath(OPTIONS.socket) - echo("daemon socket location: %s" % CONFIG['server_socket']) - - if OPTIONS.daemon: - CONFIG['daemon_mode'] = False - - # Now {start|stop|...} - DAEMON_ACTIONS[ACTION]() diff --git a/examples/data/uzbl/scripts/uzbl-tabbed b/examples/data/uzbl/scripts/uzbl-tabbed deleted file mode 100755 index 5d1a9f8..0000000 --- a/examples/data/uzbl/scripts/uzbl-tabbed +++ /dev/null @@ -1,1417 +0,0 @@ -#!/usr/bin/env python - -# Uzbl tabbing wrapper using a fifo socket interface -# Copyright (c) 2009, Tom Adams -# Copyright (c) 2009, Chris van Dijk -# Copyright (c) 2009, Mason Larobina -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -# Author(s): -# Tom Adams -# Wrote the original uzbl_tabbed.py as a proof of concept. -# -# Chris van Dijk (quigybo) -# Made signifigant headway on the old uzbl_tabbing.py script on the -# uzbl wiki -# -# Mason Larobina -# Rewrite of the uzbl_tabbing.py script to use a fifo socket interface -# and inherit configuration options from the user's uzbl config. -# -# Contributor(s): -# mxey -# uzbl_config path now honors XDG_CONFIG_HOME if it exists. -# -# Romain Bignon -# Fix for session restoration code. -# -# Jake Probst -# Wrote a patch that overflows tabs in the tablist on to new lines when -# running of room. -# -# Devon Jones -# Fifo command bring_to_front which brings the gtk window to focus. -# -# Simon Lipp (sloonz) -# Various - - -# Dependencies: -# pygtk - python bindings for gtk. -# pango - python bindings needed for text rendering & layout in gtk widgets. -# pygobject - GLib's GObject bindings for python. -# -# Optional dependencies: -# simplejson - save uzbl_tabbed.py sessions & presets in json. -# -# Note: I haven't included version numbers with this dependency list because -# I've only ever tested uzbl_tabbed.py on the latest stable versions of these -# packages in Gentoo's portage. Package names may vary on different systems. - - -# Configuration: -# Because this version of uzbl_tabbed is able to inherit options from your main -# uzbl configuration file you may wish to configure uzbl tabbed from there. -# Here is a list of configuration options that can be customised and some -# example values for each: -# -# General tabbing options: -# show_tablist = 1 -# show_gtk_tabs = 0 -# tablist_top = 1 -# gtk_tab_pos = (top|left|bottom|right) -# gtk_refresh = 1000 -# switch_to_new_tabs = 1 -# capture_new_windows = 1 -# multiline_tabs = 1 -# -# Tab title options: -# tab_titles = 1 -# tab_indexes = 1 -# new_tab_title = Loading -# max_title_len = 50 -# show_ellipsis = 1 -# -# Session options: -# save_session = 1 -# json_session = 0 -# session_file = $HOME/.local/share/uzbl/session -# -# Inherited uzbl options: -# fifo_dir = /tmp -# socket_dir = /tmp -# icon_path = $HOME/.local/share/uzbl/uzbl.png -# status_background = #303030 -# -# Misc options: -# window_size = 800,800 -# verbose = 0 -# -# And uzbl_tabbed.py takes care of the actual binding of the commands via each -# instances fifo socket. -# -# Custom tab styling: -# tab_colours = foreground = "#888" background = "#303030" -# tab_text_colours = foreground = "#bbb" -# selected_tab = foreground = "#fff" -# selected_tab_text = foreground = "green" -# tab_indicate_https = 1 -# https_colours = foreground = "#888" -# https_text_colours = foreground = "#9c8e2d" -# selected_https = foreground = "#fff" -# selected_https_text = foreground = "gold" -# -# How these styling values are used are soley defined by the syling policy -# handler below (the function in the config section). So you can for example -# turn the tab text colour Firetruck-Red in the event "error" appears in the -# tab title or some other arbitrary event. You may wish to make a trusted -# hosts file and turn tab titles of tabs visiting trusted hosts purple. - - -# Issues: -# - new windows are not caught and opened in a new tab. -# - when uzbl_tabbed.py crashes it takes all the children with it. -# - when a new tab is opened when using gtk tabs the tab button itself -# grabs focus from its child for a few seconds. -# - when switch_to_new_tabs is not selected the notebook page is -# maintained but the new window grabs focus (try as I might to stop it). - - -# Todo: -# - add command line options to use a different session file, not use a -# session file and or open a uri on starup. -# - ellipsize individual tab titles when the tab-list becomes over-crowded -# - add "<" & ">" arrows to tablist to indicate that only a subset of the -# currently open tabs are being displayed on the tablist. -# - add the small tab-list display when both gtk tabs and text vim-like -# tablist are hidden (I.e. [ 1 2 3 4 5 ]) -# - check spelling. -# - pass a uzbl socketid to uzbl_tabbed.py and have it assimilated into -# the collective. Resistance is futile! - - -import pygtk -import gtk -import subprocess -import os -import re -import time -import getopt -import pango -import select -import sys -import gobject -import socket -import random -import hashlib -import atexit -import types - -from gobject import io_add_watch, source_remove, timeout_add, IO_IN, IO_HUP -from signal import signal, SIGTERM, SIGINT -from optparse import OptionParser, OptionGroup - - -pygtk.require('2.0') - -_SCRIPTNAME = os.path.basename(sys.argv[0]) -def error(msg): - sys.stderr.write("%s: error: %s\n" % (_SCRIPTNAME, msg)) - -# ============================================================================ -# ::: Default configuration section :::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def xdghome(key, default): - '''Attempts to use the environ XDG_*_HOME paths if they exist otherwise - use $HOME and the default path.''' - - xdgkey = "XDG_%s_HOME" % key - if xdgkey in os.environ.keys() and os.environ[xdgkey]: - return os.environ[xdgkey] - - return os.path.join(os.environ['HOME'], default) - -# Setup xdg paths. -DATA_DIR = os.path.join(xdghome('DATA', '.local/share/'), 'uzbl/') - -# Ensure uzbl xdg paths exist -if not os.path.exists(DATA_DIR): - os.makedirs(DATA_DIR) - -# All of these settings can be inherited from your uzbl config file. -config = { - # Tab options - 'show_tablist': True, # Show text uzbl like statusbar tab-list - 'show_gtk_tabs': False, # Show gtk notebook tabs - 'tablist_top': True, # Display tab-list at top of window - 'gtk_tab_pos': 'top', # Gtk tab position (top|left|bottom|right) - 'gtk_refresh': 1000, # Tablist refresh millisecond interval - 'switch_to_new_tabs': True, # Upon opening a new tab switch to it - 'capture_new_windows': True, # Use uzbl_tabbed to catch new windows - 'multiline_tabs': True, # Tabs overflow onto new tablist lines. - - # Tab title options - 'tab_titles': True, # Display tab titles (else only tab-nums) - 'tab_indexes': True, # Display tab nums (else only tab titles) - 'new_tab_title': 'Loading', # New tab title - 'max_title_len': 50, # Truncate title at n characters - 'show_ellipsis': True, # Show ellipsis when truncating titles - - # Session options - 'save_session': True, # Save session in file when quit - 'json_session': False, # Use json to save session. - 'saved_sessions_dir': os.path.join(DATA_DIR, 'sessions/'), - 'session_file': os.path.join(DATA_DIR, 'session'), - - # Inherited uzbl options - 'fifo_dir': '/tmp', # Path to look for uzbl fifo. - 'socket_dir': '/tmp', # Path to look for uzbl socket. - 'icon_path': os.path.join(DATA_DIR, 'uzbl.png'), - 'status_background': "#303030", # Default background for all panels. - - # Misc options - 'window_size': "800,800", # width,height in pixels. - 'verbose': False, # Print verbose output. - - # Add custom tab style definitions to be used by the tab colour policy - # handler here. Because these are added to the config dictionary like - # any other uzbl_tabbed configuration option remember that they can - # be superseeded from your main uzbl config file. - 'tab_colours': 'foreground = "#888" background = "#303030"', - 'tab_text_colours': 'foreground = "#bbb"', - 'selected_tab': 'foreground = "#fff"', - 'selected_tab_text': 'foreground = "green"', - 'tab_indicate_https': True, - 'https_colours': 'foreground = "#888"', - 'https_text_colours': 'foreground = "#9c8e2d"', - 'selected_https': 'foreground = "#fff"', - 'selected_https_text': 'foreground = "gold"', - -} # End of config dict. - -UZBL_TABBED_VARS = config.keys() - -# This is the tab style policy handler. Every time the tablist is updated -# this function is called to determine how to colourise that specific tab -# according the simple/complex rules as defined here. You may even wish to -# move this function into another python script and import it using: -# from mycustomtabbingconfig import colour_selector -# Remember to rename, delete or comment out this function if you do that. - -def colour_selector(tabindex, currentpage, uzbl): - '''Tablist styling policy handler. This function must return a tuple of - the form (tab style, text style).''' - - # Just as an example: - # if 'error' in uzbl.title: - # if tabindex == currentpage: - # return ('foreground="#fff"', 'foreground="red"') - # return ('foreground="#888"', 'foreground="red"') - - # Style tabs to indicate connected via https. - if config['tab_indicate_https'] and uzbl.uri.startswith("https://"): - if tabindex == currentpage: - return (config['selected_https'], config['selected_https_text']) - return (config['https_colours'], config['https_text_colours']) - - # Style to indicate selected. - if tabindex == currentpage: - return (config['selected_tab'], config['selected_tab_text']) - - # Default tab style. - return (config['tab_colours'], config['tab_text_colours']) - -# ============================================================================ -# ::: End of configuration section ::::::::::::::::::::::::::::::::::::::::::: -# ============================================================================ - -def echo(msg): - if config['verbose']: - sys.stderr.write("%s: %s\n" % (_SCRIPTNAME, msg)) - - -def counter(): - '''To infinity and beyond!''' - - i = 0 - while True: - i += 1 - yield i - - -def escape(s): - '''Replaces html markup in tab titles that screw around with pango.''' - - for (split, glue) in [('&','&'), ('<', '<'), ('>', '>')]: - s = s.replace(split, glue) - return s - - -class SocketClient: - '''Represents a Uzbl instance, which is not necessarly linked with a UzblInstance''' - - # List of UzblInstance objects not already linked with a SocketClient - instances_queue = {} - - def __init__(self, socket): - self._buffer = "" - self._socket = socket - self._watchers = [io_add_watch(socket, IO_IN, self._socket_recv),\ - io_add_watch(socket, IO_HUP, self._socket_closed)] - self.uzbl = None - - - def _socket_recv(self, fd, condition): - '''Data available on socket, process it''' - - self._feed(self._socket.recv(1024)) #TODO: is io_add_watch edge or level-triggered ? - return True - - - def _socket_closed(self, fd, condition): - '''Remote client exited''' - self.uzbl.close() - return False - - - def _feed(self, data): - '''An Uzbl instance sent some data, parse it''' - - self._buffer += data - if self.uzbl: - if "\n" in self._buffer: - cmds = self._buffer.split("\n") - - if cmds[-1]: # Last command has been received incomplete, don't process it - self._buffer, cmds = cmds[-1], cmds[:-1] - else: - self._buffer = "" - - for cmd in cmds: - if cmd: - self.uzbl.parse_command(cmd) - else: - name = re.findall('^EVENT \[(\d+-\d+)\] INSTANCE_START \d+$', self._buffer, re.M) - uzbl = self.instances_queue.get(name[0]) - if uzbl: - del self.instances_queue[name[0]] - self.uzbl = uzbl - self.uzbl.got_socket(self) - self._feed("") - - def send(self, data): - '''Child socket send function.''' - - self._socket.send(data + "\n") - - def close(self): - '''Close the connection''' - - if self._socket: - self._socket.close() - self._socket = None - map(source_remove, self._watchers) - self._watchers = [] - - -class UzblInstance: - '''Uzbl instance meta-data/meta-action object.''' - - def __init__(self, parent, tab, name, uri, title, switch): - - self.parent = parent - self.tab = tab - self.name = name - self.title = title - self.tabtitle = "" - self.uri = uri - self._client = None - self._switch = switch # Switch to tab after loading ? - self.title_changed() - - - def got_socket(self, client): - '''Uzbl instance is now connected''' - - self._client = client - self.parent.config_uzbl(self) - if self._switch: - tabid = self.parent.notebook.page_num(self.tab) - self.parent.goto_tab(tabid) - - - def title_changed(self, gtk_only = True): # GTK-only is for indexes - '''self.title has changed, update the tabs list''' - - tab_titles = config['tab_titles'] - tab_indexes = config['tab_indexes'] - show_ellipsis = config['show_ellipsis'] - max_title_len = config['max_title_len'] - - # Unicode heavy strings do not like being truncated/sliced so by - # re-encoding the string sliced of limbs are removed. - self.tabtitle = self.title[:max_title_len + int(show_ellipsis)] - if type(self.tabtitle) != types.UnicodeType: - self.tabtitle = unicode(self.tabtitle, 'utf-8', 'ignore') - - self.tabtitle = self.tabtitle.encode('utf-8', 'ignore').strip() - - if show_ellipsis and len(self.tabtitle) != len(self.title): - self.tabtitle += "\xe2\x80\xa6" - - gtk_tab_format = "%d %s" - index = self.parent.notebook.page_num(self.tab) - if tab_titles and tab_indexes: - self.parent.notebook.set_tab_label_text(self.tab, - gtk_tab_format % (index, self.tabtitle)) - elif tab_titles: - self.parent.notebook.set_tab_label_text(self.tab, self.tabtitle) - else: - self.parent.notebook.set_tab_label_text(self.tab, str(index)) - - # If instance is current tab, update window title - if index == self.parent.notebook.get_current_page(): - title_format = "%s - Uzbl Browser" - self.parent.window.set_title(title_format % self.title) - - # Non-GTK tabs - if not gtk_only: - self.parent.update_tablist() - - - def set(self, key, val): - ''' Send the SET command to Uzbl ''' - - if self._client: - self._client.send('set %s = %s') #TODO: escape chars ? - - - def exit(self): - ''' Ask the Uzbl instance to close ''' - - if self._client: - self._client.send('exit') - - - def parse_command(self, cmd): - ''' Parse event givent by the Uzbl instance ''' - - type, _, args = cmd.split(" ", 2) - if type == "EVENT": - type, args = args.split(" ", 1) - if type == "TITLE_CHANGED": - self.title = args - self.title_changed() - elif type == "VARIABLE_SET": - var, _, val = args.split(" ", 2) - try: - val = int(val) - except: - pass - - if var in UZBL_TABBED_VARS: - if config[var] != val: - config[var] = val - if var == "show_gtk_tabs": - self.parent.notebook.set_show_tabs(bool(val)) - elif var == "show_tablist" or var == "tablist_top": - self.parent.update_tablist_display() - elif var == "gtk_tab_pos": - self.parent.update_gtk_tab_pos() - elif var == "status_background": - col = gtk.gdk.color_parse(config['status_background']) - self.parent.ebox.modify_bg(gtk.STATE_NORMAL, col) - elif var == "tab_titles" or var == "tab_indexes": - for tab in self.parent.notebook: - self.parent.tabs[tab].title_changed(True) - - self.parent.update_tablist() - else: - config[var] = val - - if var == "uri": - self.uri = var - self.parent.update_tablist() - elif type == "NEW_TAB": - self.parent.new_tab(args) - elif type == "NEXT_TAB": - if args: - self.parent.next_tab(int(args)) - else: - self.parent.next_tab() - elif type == "PREV_TAB": - if args: - self.parent.prev_tab(int(args)) - else: - self.parent.prev_tab() - elif type == "GOTO_TAB": - self.parent.goto_tab(int(args)) - elif type == "FIRST_TAB": - self.parent.goto_tab(0) - elif type == "LAST_TAB": - self.parent.goto_tab(-1) - elif type == "PRESET_TABS": - self.parent.parse_command(["preset"] + args.split()) - elif type == "BRING_TO_FRONT": - self.parent.window.present() - elif type == "CLEAN_TABS": - self.parent.clean_slate() - elif type == "EXIT_ALL_TABS": - self.parent.quitrequest() - - - def close(self): - '''The remote instance exited''' - - if self._client: - self._client.close() - self._client = None - - -class UzblTabbed: - '''A tabbed version of uzbl using gtk.Notebook''' - - def __init__(self): - '''Create tablist, window and notebook.''' - - self._timers = {} - self._buffer = "" - self._killed = False - - # A list of the recently closed tabs - self._closed = [] - - # Holds metadata on the uzbl childen open. - self.tabs = {} - - # Uzbl sockets (socket => SocketClient) - self.clients = {} - - # Generates a unique id for uzbl socket filenames. - self.next_pid = counter().next - - # Create main window - self.window = gtk.Window() - try: - window_size = map(int, config['window_size'].split(',')) - self.window.set_default_size(*window_size) - - except: - error("Invalid value for default_size in config file.") - - self.window.set_title("Uzbl Browser") - self.window.set_border_width(0) - - # Set main window icon - icon_path = config['icon_path'] - if os.path.exists(icon_path): - self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) - - else: - icon_path = '/usr/share/uzbl/examples/data/uzbl/uzbl.png' - if os.path.exists(icon_path): - self.window.set_icon(gtk.gdk.pixbuf_new_from_file(icon_path)) - - # Attach main window event handlers - self.window.connect("delete-event", self.quitrequest) - - # Create tab list - vbox = gtk.VBox() - self.vbox = vbox - self.window.add(vbox) - ebox = gtk.EventBox() - self.ebox = ebox - self.tablist = gtk.Label() - - self.tablist.set_use_markup(True) - self.tablist.set_justify(gtk.JUSTIFY_LEFT) - self.tablist.set_line_wrap(False) - self.tablist.set_selectable(False) - self.tablist.set_padding(2,2) - self.tablist.set_alignment(0,0) - self.tablist.set_ellipsize(pango.ELLIPSIZE_END) - self.tablist.set_text(" ") - self.tablist.show() - ebox.add(self.tablist) - ebox.show() - bgcolor = gtk.gdk.color_parse(config['status_background']) - ebox.modify_bg(gtk.STATE_NORMAL, bgcolor) - - # Create notebook - self.notebook = gtk.Notebook() - self.notebook.set_show_tabs(config['show_gtk_tabs']) - - # Set tab position - self.update_gtk_tab_pos() - - self.notebook.set_show_border(False) - self.notebook.set_scrollable(True) - self.notebook.set_border_width(0) - - self.notebook.connect("page-removed", self.tab_closed) - self.notebook.connect("switch-page", self.tab_changed) - self.notebook.connect("page-added", self.tab_opened) - - self.notebook.show() - vbox.pack_start(self.notebook, True, True, 0) - vbox.reorder_child(self.notebook, 1) - self.update_tablist_display() - - self.vbox.show() - self.window.show() - self.wid = self.notebook.window.xid - - # Store information about the applications fifo and socket. - fifo_filename = 'uzbltabbed_%d.fifo' % os.getpid() - socket_filename = 'uzbltabbed_%d.socket' % os.getpid() - self._fifo = None - self._socket = None - self.fifo_path = os.path.join(config['fifo_dir'], fifo_filename) - self.socket_path = os.path.join(config['socket_dir'], socket_filename) - - # Now initialise the fifo and the socket - self.init_fifo() - self.init_socket() - - # If we are using sessions then load the last one if it exists. - if config['save_session']: - self.load_session() - - - def run(self): - '''UzblTabbed main function that calls the gtk loop.''' - - if not self.clients and not SocketClient.instances_queue and not self.tabs: - self.new_tab() - - gtk_refresh = int(config['gtk_refresh']) - if gtk_refresh < 100: - gtk_refresh = 100 - - # Make SIGTERM act orderly. - signal(SIGTERM, lambda signum, stack_frame: self.terminate(SIGTERM)) - - # Catch keyboard interrupts - signal(SIGINT, lambda signum, stack_frame: self.terminate(SIGINT)) - - try: - gtk.main() - - except: - error("encounted error %r" % sys.exc_info()[1]) - - # Unlink fifo socket - self.unlink_fifo() - self.close_socket() - - # Attempt to close all uzbl instances nicely. - self.quitrequest() - - # Allow time for all the uzbl instances to quit. - time.sleep(1) - - raise - - - def terminate(self, termsig=None): - '''Handle termination signals and exit safely and cleanly.''' - - # Not required but at least it lets the user know what killed his - # browsing session. - if termsig == SIGTERM: - error("caught SIGTERM signal") - - elif termsig == SIGINT: - error("caught keyboard interrupt") - - else: - error("caught unknown signal") - - error("commencing infanticide!") - - # Sends the exit signal to all uzbl instances. - self.quitrequest() - - - def init_socket(self): - '''Create interprocess communication socket.''' - - def accept(sock, condition): - '''A new uzbl instance was created''' - - client, _ = sock.accept() - self.clients[client] = SocketClient(client) - - return True - - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind(self.socket_path) - sock.listen(1) - - # Add event handler for IO_IN event. - self._socket = (sock, io_add_watch(sock, IO_IN, accept)) - - echo("[socket] listening at %r" % self.socket_path) - - # Add atexit register to destroy the socket on program termination. - atexit.register(self.close_socket) - - - def close_socket(self): - '''Close the socket when closing the application''' - - if self._socket: - (fd, watcher) = self._socket - source_remove(watcher) - fd.close() - os.unlink(self.socket_path) - self._socket = None - - - def init_fifo(self): - '''Create interprocess communication fifo.''' - - if os.path.exists(self.fifo_path): - if not os.access(self.fifo_path, os.F_OK | os.R_OK | os.W_OK): - os.mkfifo(self.fifo_path) - - else: - basedir = os.path.dirname(self.fifo_path) - if not os.path.exists(basedir): - os.makedirs(basedir) - - os.mkfifo(self.fifo_path) - - # Add event handlers for IO_IN & IO_HUP events. - self.setup_fifo_watchers() - - echo("[fifo] listening at %r" % self.fifo_path) - - # Add atexit register to destroy the fifo on program termination. - atexit.register(self.unlink_fifo) - - - def unlink_fifo(self): - '''Unlink the fifo socket. Note: This function is called automatically - on exit by an atexit register.''' - - # Make sure the fifo fd is closed. - self.close_fifo() - - # And unlink if the real fifo exists. - if os.path.exists(self.fifo_path): - os.unlink(self.fifo_path) - echo("unlinked %r" % self.fifo_path) - - - def close_fifo(self): - '''Remove all event handlers watching the fifo and close the fd.''' - - # Already closed - if self._fifo is None: return - - (fd, watchers) = self._fifo - os.close(fd) - - # Stop all gobject io watchers watching the fifo. - for gid in watchers: - source_remove(gid) - - self._fifo = None - - - def setup_fifo_watchers(self): - '''Open fifo socket fd and setup gobject IO_IN & IO_HUP event - handlers.''' - - # Close currently open fifo fd and kill all watchers - self.close_fifo() - - fd = os.open(self.fifo_path, os.O_RDONLY | os.O_NONBLOCK) - - # Add gobject io event handlers to the fifo socket. - watchers = [io_add_watch(fd, IO_IN, self.main_fifo_read),\ - io_add_watch(fd, IO_HUP, self.main_fifo_hangup)] - - self._fifo = (fd, watchers) - - - def main_fifo_hangup(self, fd, cb_condition): - '''Handle main fifo socket hangups.''' - - # Close old fd, open new fifo socket and add io event handlers. - self.setup_fifo_watchers() - - # Kill the gobject event handler calling this handler function. - return False - - - def main_fifo_read(self, fd, cb_condition): - '''Read from main fifo socket.''' - - self._buffer = os.read(fd, 1024) - temp = self._buffer.split("\n") - self._buffer = temp.pop() - cmds = [s.strip().split() for s in temp if len(s.strip())] - - for cmd in cmds: - try: - #print cmd - self.parse_command(cmd) - - except: - 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. - # 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] == "newfromclip": - uri = subprocess.Popen(['xclip','-selection','clipboard','-o'],\ - stdout=subprocess.PIPE).communicate()[0] - if uri: - self.new_tab(uri) - - elif cmd[0] == "close": - if len(cmd) == 2: - self.close_tab(int(cmd[1])) - - else: - self.close_tab() - - elif cmd[0] == "next": - if len(cmd) == 2: - self.next_tab(int(cmd[1])) - - else: - self.next_tab() - - elif cmd[0] == "prev": - if len(cmd) == 2: - self.prev_tab(int(cmd[1])) - - else: - self.prev_tab() - - elif cmd[0] == "goto": - self.goto_tab(int(cmd[1])) - - elif cmd[0] == "first": - self.goto_tab(0) - - elif cmd[0] == "last": - self.goto_tab(-1) - - elif cmd[0] in ["title", "uri"]: - if len(cmd) > 2: - uzbl = self.get_tab_by_name(int(cmd[1])) - if uzbl: - old = getattr(uzbl, cmd[0]) - new = ' '.join(cmd[2:]) - setattr(uzbl, cmd[0], new) - if old != new: - self.update_tablist() - - else: - error("parse_command: no uzbl with name %r" % int(cmd[1])) - - elif cmd[0] == "preset": - if len(cmd) < 3: - error("parse_command: invalid preset command") - - elif cmd[1] == "save": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - self.save_session(path) - - elif cmd[1] == "load": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - self.load_session(path) - - elif cmd[1] == "del": - path = os.path.join(config['saved_sessions_dir'], cmd[2]) - if os.path.isfile(path): - os.remove(path) - - else: - error("parse_command: preset %r does not exist." % path) - - elif cmd[1] == "list": - uzbl = self.get_tab_by_name(int(cmd[2])) - if uzbl: - if not os.path.isdir(config['saved_sessions_dir']): - js = "js alert('No saved presets.');" - uzbl._client.send(js) - - else: - listdir = os.listdir(config['saved_sessions_dir']) - listdir = "\\n".join(listdir) - js = "js alert('Session presets:\\n\\n%s');" % listdir - uzbl._client.send(js) - - else: - error("parse_command: unknown tab name.") - - else: - error("parse_command: unknown parse command %r"\ - % ' '.join(cmd)) - - elif cmd[0] == "bring_to_front": - self.window.present() - - elif cmd[0] == "clean": - self.clean_slate() - - elif cmd[0] == "exit": - self.quitrequest() - - else: - error("parse_command: unknown command %r" % ' '.join(cmd)) - - - def get_tab_by_name(self, name): - '''Return uzbl instance by name.''' - - for (tab, uzbl) in self.tabs.items(): - if uzbl.name == name: - return uzbl - - return False - - - def new_tab(self, uri='', title='', switch=None): - '''Add a new tab to the notebook and start a new instance of uzbl. - Use the switch option to negate config['switch_to_new_tabs'] option - when you need to load multiple tabs at a time (I.e. like when - restoring a session from a file).''' - - tab = gtk.Socket() - tab.show() - self.notebook.append_page(tab) - sid = tab.get_id() - uri = uri.strip() - name = "%d-%d" % (os.getpid(), self.next_pid()) - - if switch is None: - switch = config['switch_to_new_tabs'] - - if not title: - title = config['new_tab_title'] - - cmd = ['uzbl-browser', '-n', name, '-s', str(sid), - '--connect-socket', self.socket_path, '--uri', uri] - subprocess.Popen(cmd) # TODO: do i need close_fds=True ? - - uzbl = UzblInstance(self, tab, name, uri, title, switch) - SocketClient.instances_queue[name] = uzbl - self.tabs[tab] = uzbl - - - def clean_slate(self): - '''Close all open tabs and open a fresh brand new one.''' - - self.new_tab() - tabs = self.tabs.keys() - for tab in list(self.notebook)[:-1]: - if tab not in tabs: continue - uzbl = self.tabs[tab] - uzbl.exit() - - - def config_uzbl(self, uzbl): - '''Send bind commands for tab new/close/next/prev to a uzbl - instance.''' - - # Set definitions here - # set(key, command back to fifo) - if config['capture_new_windows']: - uzbl.set("new_window", r'new $8') - - - def goto_tab(self, index): - '''Goto tab n (supports negative indexing).''' - - title_format = "%s - Uzbl Browser" - - tabs = list(self.notebook) - if 0 <= index < len(tabs): - self.notebook.set_current_page(index) - uzbl = self.tabs[self.notebook.get_nth_page(index)] - self.window.set_title(title_format % uzbl.title) - self.update_tablist() - return None - - try: - tab = tabs[index] - # Update index because index might have previously been a - # negative index. - index = tabs.index(tab) - self.notebook.set_current_page(index) - uzbl = self.tabs[self.notebook.get_nth_page(index)] - self.window.set_title(title_format % uzbl.title) - self.update_tablist() - - except IndexError: - pass - - - def next_tab(self, step=1): - '''Switch to next tab or n tabs right.''' - - if step < 1: - error("next_tab: invalid step %r" % step) - return None - - ntabs = self.notebook.get_n_pages() - tabn = (self.notebook.get_current_page() + step) % ntabs - self.goto_tab(tabn) - - - def prev_tab(self, step=1): - '''Switch to prev tab or n tabs left.''' - - if step < 1: - error("prev_tab: invalid step %r" % step) - return None - - ntabs = self.notebook.get_n_pages() - tabn = self.notebook.get_current_page() - step - while tabn < 0: tabn += ntabs - self.goto_tab(tabn) - - - def close_tab(self, tabn=None): - '''Closes current tab. Supports negative indexing.''' - - if tabn is None: - tabn = self.notebook.get_current_page() - - else: - try: - tab = list(self.notebook)[tabn] - - except IndexError: - error("close_tab: invalid index %r" % tabn) - return None - - self.notebook.remove_page(tabn) - - - def tab_opened(self, notebook, tab, index): - '''Called upon tab creation. Called by page-added signal.''' - - if config['switch_to_new_tabs']: - self.notebook.set_focus_child(tab) - - else: - oldindex = self.notebook.get_current_page() - oldtab = self.notebook.get_nth_page(oldindex) - self.notebook.set_focus_child(oldtab) - - - def tab_closed(self, notebook, tab, index): - '''Close the window if no tabs are left. Called by page-removed - signal.''' - - if tab in self.tabs.keys(): - uzbl = self.tabs[tab] - uzbl.close() - - self._closed.append((uzbl.uri, uzbl.title)) - self._closed = self._closed[-10:] - del self.tabs[tab] - - if self.notebook.get_n_pages() == 0: - if not self._killed and config['save_session']: - if os.path.exists(config['session_file']): - os.remove(config['session_file']) - - self.quit() - - for tab in self.notebook: - self.tabs[tab].title_changed(True) - self.update_tablist() - - return True - - - def tab_changed(self, notebook, page, index): - '''Refresh tab list. Called by switch-page signal.''' - - tab = self.notebook.get_nth_page(index) - self.notebook.set_focus_child(tab) - self.update_tablist(index) - return True - - - def update_tablist_display(self): - '''Called when show_tablist or tablist_top has changed''' - - if self.ebox in self.vbox.get_children(): - self.vbox.remove(self.ebox) - - if config['show_tablist']: - self.vbox.pack_start(self.ebox, False, False, 0) - if config['tablist_top']: - self.vbox.reorder_child(self.ebox, 0) - else: - self.vbox.reorder_child(self.ebox, 2) - - def update_gtk_tab_pos(self): - ''' Called when gtk_tab_pos has changed ''' - - allposes = {'left': gtk.POS_LEFT, 'right':gtk.POS_RIGHT, - 'top':gtk.POS_TOP, 'bottom':gtk.POS_BOTTOM} - if config['gtk_tab_pos'] in allposes.keys(): - self.notebook.set_tab_pos(allposes[config['gtk_tab_pos']]) - - - def update_tablist(self, curpage=None): - '''Upate tablist status bar.''' - - if not config['show_tablist']: - return True - - tab_titles = config['tab_titles'] - tab_indexes = config['tab_indexes'] - multiline_tabs = config['multiline_tabs'] - - if multiline_tabs: - multiline = [] - - tabs = self.tabs.keys() - if curpage is None: - curpage = self.notebook.get_current_page() - - pango = "" - normal = (config['tab_colours'], config['tab_text_colours']) - selected = (config['selected_tab'], config['selected_tab_text']) - - if tab_titles and tab_indexes: - tab_format = " [ %(index)d %(title)s ] " - elif tab_titles: - tab_format = " [ %(title)s ] " - else: - tab_format = " [ %(index)d ] " - - for index, tab in enumerate(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - title = escape(uzbl.tabtitle) - - style = colour_selector(index, curpage, uzbl) - (tabc, textc) = style - - if multiline_tabs: - opango = pango - - pango += tab_format % locals() - - self.tablist.set_markup(pango) - listwidth = self.tablist.get_layout().get_pixel_size()[0] - winwidth = self.window.get_size()[0] - - if listwidth > (winwidth - 20): - multiline.append(opango) - pango = tab_format % locals() - else: - pango += tab_format % locals() - - if multiline_tabs: - multiline.append(pango) - self.tablist.set_markup(' '.join(multiline)) - - else: - self.tablist.set_markup(pango) - - return True - - - def save_session(self, session_file=None): - '''Save the current session to file for restoration on next load.''' - - strip = str.strip - - if session_file is None: - session_file = config['session_file'] - - tabs = self.tabs.keys() - state = [] - for tab in list(self.notebook): - if tab not in tabs: continue - uzbl = self.tabs[tab] - if not uzbl.uri: continue - state += [(uzbl.uri, uzbl.title),] - - session = {'curtab': self.notebook.get_current_page(), - 'tabs': state} - - if config['json_session']: - raw = json.dumps(session) - - else: - lines = ["curtab = %d" % session['curtab'],] - for (uri, title) in session['tabs']: - lines += ["%s\t%s" % (strip(uri), strip(title)),] - - raw = "\n".join(lines) - - if not os.path.isfile(session_file): - dirname = os.path.dirname(session_file) - if not os.path.isdir(dirname): - os.makedirs(dirname) - - h = open(session_file, 'w') - h.write(raw) - h.close() - - - def load_session(self, session_file=None): - '''Load a saved session from file.''' - - default_path = False - strip = str.strip - json_session = config['json_session'] - delete_loaded = False - - if session_file is None: - default_path = True - delete_loaded = True - session_file = config['session_file'] - - if not os.path.isfile(session_file): - return False - - h = open(session_file, 'r') - raw = h.read() - h.close() - if json_session: - if sum([1 for s in raw.split("\n") if strip(s)]) != 1: - error("Warning: The session file %r does not look json. "\ - "Trying to load it as a non-json session file."\ - % session_file) - json_session = False - - if json_session: - try: - session = json.loads(raw) - curtab, tabs = session['curtab'], session['tabs'] - - except: - error("Failed to load jsonifed session from %r"\ - % session_file) - return None - - else: - tabs = [] - strip = str.strip - curtab, tabs = 0, [] - lines = [s for s in raw.split("\n") if strip(s)] - if len(lines) < 2: - error("Warning: The non-json session file %r looks invalid."\ - % session_file) - return None - - try: - for line in lines: - if line.startswith("curtab"): - curtab = int(line.split()[-1]) - - else: - uri, title = line.split("\t",1) - tabs += [(strip(uri), strip(title)),] - - except: - error("Warning: failed to load session file %r" % session_file) - return None - - session = {'curtab': curtab, 'tabs': tabs} - - # Now populate notebook with the loaded session. - for (index, (uri, title)) in enumerate(tabs): - self.new_tab(uri=uri, title=title, switch=(curtab==index)) - - # A saved session has been loaded now delete it. - if delete_loaded and os.path.exists(session_file): - os.remove(session_file) - - # There may be other state information in the session dict of use to - # other functions. Of course however the non-json session object is - # just a dummy object of no use to no one. - return session - - - def quitrequest(self, *args): - '''Attempt to close all uzbl instances nicely and exit.''' - - self._killed = True - - if config['save_session']: - if len(list(self.notebook)) > 1: - self.save_session() - - else: - # Notebook has one page open so delete the session file. - if os.path.isfile(config['session_file']): - os.remove(config['session_file']) - - for (tab, uzbl) in self.tabs.items(): - uzbl.exit() - - # Add a gobject timer to make sure the application force-quits after a - # reasonable period. Calling quit when all the tabs haven't had time to - # close should be a last resort. - timer = "force-quit" - timerid = timeout_add(5000, self.quit, timer) - self._timers[timer] = timerid - - - def quit(self, *args): - '''Cleanup and quit. Called by delete-event signal.''' - - # Close the fifo socket, remove any gobject io event handlers and - # delete socket. - self.unlink_fifo() - self.close_socket() - - # Remove all gobject timers that are still ticking. - for (timerid, gid) in self._timers.items(): - source_remove(gid) - del self._timers[timerid] - - try: - gtk.main_quit() - - except: - pass - - -if __name__ == "__main__": - - # Build command line parser - usage = "usage: %prog [OPTIONS] {URIS}..." - parser = OptionParser(usage=usage) - parser.add_option('-n', '--no-session', dest='nosession', - action='store_true', help="ignore session saving a loading.") - parser.add_option('-v', '--verbose', dest='verbose', - action='store_true', help='print verbose output.') - - # Parse command line options - (options, uris) = parser.parse_args() - - if options.nosession: - config['save_session'] = False - - if options.verbose: - config['verbose'] = True - - if config['json_session']: - try: - import simplejson as json - - except: - error("Warning: json_session set but cannot import the python "\ - "module simplejson. Fix: \"set json_session = 0\" or "\ - "install the simplejson python module to remove this warning.") - config['json_session'] = False - - if config['verbose']: - import pprint - sys.stderr.write("%s\n" % pprint.pformat(config)) - - uzbl = UzblTabbed() - - # All extra arguments given to uzbl_tabbed.py are interpreted as - # web-locations to opened in new tabs. - lasturi = len(uris)-1 - for (index,uri) in enumerate(uris): - uzbl.new_tab(uri, switch=(index==lasturi)) - - uzbl.run() diff --git a/examples/data/uzbl/scripts/uzblcat b/examples/data/uzbl/scripts/uzblcat deleted file mode 100755 index e955608..0000000 --- a/examples/data/uzbl/scripts/uzblcat +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# uzblcat - safely push html to uzbl -# See http://www.uzbl.org/wiki/html-mode - -from sys import stdin, stdout - -stdout.write("uri data:text/html,") -for line in stdin: - stdout.write(line[0:-1]) - -# vim: set noet ff=unix - diff --git a/examples/data/uzbl/style.css b/examples/data/uzbl/style.css deleted file mode 100644 index f9b111e..0000000 --- a/examples/data/uzbl/style.css +++ /dev/null @@ -1,25 +0,0 @@ -.uzbl_highlight { background-color: yellow;} -.uzbl_h_first { background-color: lightgreen;} - -.uzbl_follow { border-style: dotted; - border-width: thin; -} - -#uzbl_hint > div { - display: inline; - border: 2px solid #4a6600; - background-color: #b9ff00; - color: black; - font-size: 9px; - font-weight: bold; - line-height: 9px; - margin: 0px; - padding: 0px; - position: absolute; - z-index: 1000; - -webkit-border-radius: 6px; - text-decoration: none; - -wekit-transform: scale(1) rotate(0deg) translate(-6px,-5px); -} - -/* vim:set et ts=4: */ diff --git a/examples/data/uzbl/uzbl.png b/examples/data/uzbl/uzbl.png deleted file mode 100644 index 773ea84..0000000 Binary files a/examples/data/uzbl/uzbl.png and /dev/null differ diff --git a/sandbox/env.sh b/sandbox/env.sh index 0bf812a..122a7f2 100755 --- a/sandbox/env.sh +++ b/sandbox/env.sh @@ -5,8 +5,9 @@ # - executing limits scope of variables too much (even with exporting) # maybe we should spawn processes from here with an 'exec' at the end? -export XDG_DATA_HOME=./sandbox/examples/data -export XDG_CACHE_HOME=./sandbox/examples/cache -export XDG_CONFIG_HOME=./sandbox/examples/config -#export PATH="./sandbox/usr/local/share/uzbl/examples/data/uzbl/scripts/:$PATH" # needed when running uzbl-browser from here? don't think so.. +export HOME=./sandbox/home +export XDG_DATA_HOME=$HOME/.local/share +export XDG_CACHE_HOME=$HOME/.cache +export XDG_CONFIG_HOME=$HOME/.config +#export PATH="./sandbox/usr/local/share/uzbl/examples/data/scripts/:$PATH" # needed when running uzbl-browser from here? don't think so.. export PATH="./sandbox/usr/local/bin:$PATH" # needed to run uzbl-browser etc from here diff --git a/src/uzbl-browser b/src/uzbl-browser index d9b9752..8a7ab36 100755 --- a/src/uzbl-browser +++ b/src/uzbl-browser @@ -40,7 +40,7 @@ done # if no config exists yet in the recommended location, put the default (recommended) config there if [ ! -f $XDG_CONFIG_HOME/uzbl/config ] then - if ! cp $PREFIX/share/uzbl/examples/config/uzbl/config $XDG_CONFIG_HOME/uzbl/config + if ! cp $PREFIX/share/uzbl/examples/config/config $XDG_CONFIG_HOME/uzbl/config then echo "Could not copy default config to $XDG_CONFIG_HOME/uzbl/config" >&2 exit 3 -- cgit v1.2.3 From 7a0a558cf745fa57a9db92216f98be2a80de6adc Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 5 Jan 2010 22:15:18 +0800 Subject: Make verbose print format string unicode. --- examples/data/uzbl/scripts/uzbl-event-manager | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index afef6fd..2b0ac33 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -375,11 +375,11 @@ class UzblInstance(object): msg = msg.strip() if self.client_socket: - print '%s<-- %s' % (' ' * self.depth, msg) + print u'%s<-- %s' % (' ' * self.depth, msg) self.client_socket.send(("%s\n" % msg).encode('utf-8')) else: - print '%s!-- %s' % (' ' * self.depth, msg) + print u'%s!-- %s' % (' ' * self.depth, msg) def export(self, name, function): @@ -467,7 +467,7 @@ class UzblInstance(object): elems = [event,] if args: elems.append(unicode(args)) if kargs: elems.append(unicode(kargs)) - print "%s--> %s" % (' ' * self.depth, ' '.join(elems)) + print u'%s--> %s' % (' ' * self.depth, ' '.join(elems)) if event == "INSTANCE_START" and args: self.pid = int(args[0]) -- cgit v1.2.3 From 585226c1cb80488f1fbd4ad2635550a728bf2747 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 5 Jan 2010 23:06:21 +0800 Subject: Encode utf-8 strings being sent to stdout. --- examples/data/uzbl/scripts/uzbl-event-manager | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 2b0ac33..2df3357 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -296,7 +296,7 @@ def parse_msg(uzbl, msg): cmd = FINDSPACES.split(msg, 3) if not cmd or cmd[0] != 'EVENT': # Not an event message. - print '---', msg + print '---', msg.encode('utf-8') return while len(cmd) < 4: @@ -375,11 +375,11 @@ class UzblInstance(object): msg = msg.strip() if self.client_socket: - print u'%s<-- %s' % (' ' * self.depth, msg) + print (u'%s<-- %s' % (' ' * self.depth, msg)).encode('utf-8') self.client_socket.send(("%s\n" % msg).encode('utf-8')) else: - print u'%s!-- %s' % (' ' * self.depth, msg) + print (u'%s!-- %s' % (' ' * self.depth, msg)).encode('utf-8') def export(self, name, function): @@ -467,7 +467,7 @@ class UzblInstance(object): elems = [event,] if args: elems.append(unicode(args)) if kargs: elems.append(unicode(kargs)) - print u'%s--> %s' % (' ' * self.depth, ' '.join(elems)) + print (u'%s--> %s' % (' ' * self.depth, ' '.join(elems))).encode('utf-8') if event == "INSTANCE_START" and args: self.pid = int(args[0]) -- cgit v1.2.3 From 27ed5bd4959e5546bf1d44f17854d85b50dfe1e3 Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 6 Jan 2010 06:05:10 +0200 Subject: appropriate changes to the config example --- examples/config/uzbl/config | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 9dc4a35..d696c19 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -281,9 +281,11 @@ set toggle_cmd_ins = @toggle_modes command insert @cbind u = spawn @scripts_dir/load_url_from_bookmarks.sh # --- Link following (similar to vimperator and konqueror) --- -@cbind fl* = script @scripts_dir/follow_Numbers.js %s -# Or number with strings instead of numbers: -@cbind fL* = script @scripts_dir/follow_Numbers_Strings.js %s +# Set custom keys you wish to use for navigation. Some common examples: +#set follow_hint_keys = qwerty +#set follow_hint_keys = asdfghjkl; +#set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 +@cbind f* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' @cbind Xs = js alert("hi"); -- cgit v1.2.3 From 90f440600dd6a080baf38e3a2b1519eb6bc14195 Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 6 Jan 2010 06:11:34 +0200 Subject: Jason's linkfollower with modifications: navigation keys are optionally set in Uzbl's config; code for one-hand navigation is commented out. --- examples/data/uzbl/scripts/follow.js | 107 ++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 47 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow.js b/examples/data/uzbl/scripts/follow.js index 6b71372..19a0a28 100644 --- a/examples/data/uzbl/scripts/follow.js +++ b/examples/data/uzbl/scripts/follow.js @@ -1,7 +1,6 @@ /* This is the basic linkfollowing script. + * Its pretty stable, only using numbers to navigate. * - * TODO: check if all characters in follow_hint_keys from config - * are unique. * TODO: Some pages mess around a lot with the zIndex which * lets some hints in the background. * TODO: Some positions are not calculated correctly (mostly @@ -18,18 +17,7 @@ var doc = document; var win = window; var links = document.links; var forms = document.forms; - -//This string should be 10 unique characters long. Set it in your config -//with: -// set follow_hint_keys = asdfghjkl; # no quotes! -var defaultHintKeys = '0123456789'; -var hintKeys = Uzbl.run("print @follow_hint_keys") || defaultHintKeys; -if (hintKeys.length != 10) hintKeys = defaultHintKeys; - -//Reset keycmd, modcmd and return to default mode. -function clearKeycmd() { Uzbl.run('set mode ='); } - -//Make onclick-links "clickable" +//Make onlick-links "clickable" try { HTMLElement.prototype.click = function() { if (typeof this.onclick == 'function') { @@ -114,19 +102,19 @@ function generateHint(el, label) { hint.style.fontWeight = 'bold'; hint.style.lineHeight = '9px'; hint.style.margin = '0px'; + hint.style.width = 'auto'; // fix broken rendering on w3schools.com hint.style.padding = '1px'; hint.style.position = 'absolute'; hint.style.zIndex = '1000'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; +// hint.style.textTransform = 'uppercase'; + hint.style.left = Math.max(-1, (pos[1] - (7 + label.length * 9))) + 'px'; + hint.style.top = (pos[0] + 1) + 'px'; var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } + //if (img.length > 0) { + //hint.style.top = pos[1] + img[0].height / 2 - 6 + 'px'; + //} hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; + // hint.style.webkitBorderRadius = '6px'; // slow return hint; } //Here we choose what to do with an element if we @@ -135,7 +123,6 @@ function generateHint(el, label) { //but at least set the href of the link. (needs some improvements) function clickElem(item) { removeAllHints(); - clearKeycmd(); if (item) { var name = item.tagName; if (name == 'A') { @@ -201,47 +188,67 @@ function reDrawHints(elems, chars) { document.body.appendChild(hintdiv); } } -//Map 0123456789 to hintKeys -function mapNumToHintKeys(label) { - label = label + ''; - for (var j = 0; j < label.length; j++) { - var pos = parseInt(label[j]); - label = label.replace(label[j], hintKeys[pos]); - } - return label; +// pass: number of keys +// returns: key length +function labelLength(n) { + var oldn = n; + var keylen = 0; + if(n < 2) { + return 1; + } + n -= 1; // our highest key will be n-1 + while(n) { + keylen += 1; + n = Math.floor(n / charset.length); + } + return keylen; } -//Map hintKeys to 0123456789 -function mapHintKeysToNum(label) { - label = label + ''; - for (var j = 0; j < label.length; j++) { - var pos = hintKeys.search(label[j]); - if (pos < 0 || pos > 9) return; // bad input, key not in hintKeys - label = label.replace(label[j], pos+''); - } - return parseInt(label); +// pass: number +// returns: label +function intToLabel(n) { + var label = ''; + do { + label = charset.charAt(n % charset.length) + label; + n = Math.floor(n / charset.length); + } while(n); + return label; +} +// pass: label +// returns: number +function labelToInt(label) { + var n = 0; + var i; + for(i = 0; i < label.length; ++i) { + n *= charset.length; + n += charset.indexOf(label[i]); + } + return n; } //Put it all together function followLinks(follow) { + // if(follow.charAt(0) == 'l') { + // follow = follow.substr(1); + // charset = 'thsnlrcgfdbmwvz-/'; + // } var s = follow.split(''); - var linknr = mapHintKeysToNum(follow); + var linknr = labelToInt(follow); if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); var linkelems = addLinks(); var formelems = addFormElems(); var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; + var len = labelLength(elems[0].length); var oldDiv = doc.getElementById(uzbldivid); var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { + if (s.length == len && linknr < elems[0].length && linknr >= 0) { clickElem(elems[0][linknr]); } else { for (var j = 0; j < elems[0].length; j++) { var b = true; - var label = j + ''; + var label = intToLabel(j); var n = label.length; for (n; n < len; n++) { - label = '0' + label; + label = charset.charAt(0) + label; } - label = mapNumToHintKeys(label); for (var k = 0; k < s.length; k++) { b = b && label.charAt(k) == s[k]; } @@ -253,4 +260,10 @@ function followLinks(follow) { reDrawHints(leftover, s.length); } } -followLinks('%s'); + +//Parse input: first argument is user input, second is allowed hint keys. +var args = '%s'.split(' '); +var following = args[0]; +var charset = args[1]; + +followLinks(following); -- cgit v1.2.3 From da244b530d8e99eae6766b3ff01bbd484929e4f7 Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 6 Jan 2010 06:12:18 +0200 Subject: remove follow scripts that are replaced by follow.js --- examples/data/uzbl/scripts/follow_Numbers.js | 228 --------------------- .../data/uzbl/scripts/follow_Numbers_Strings.js | 212 ------------------- 2 files changed, 440 deletions(-) delete mode 100644 examples/data/uzbl/scripts/follow_Numbers.js delete mode 100644 examples/data/uzbl/scripts/follow_Numbers_Strings.js (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow_Numbers.js b/examples/data/uzbl/scripts/follow_Numbers.js deleted file mode 100644 index 00b279e..0000000 --- a/examples/data/uzbl/scripts/follow_Numbers.js +++ /dev/null @@ -1,228 +0,0 @@ -/* This is the basic linkfollowing script. - * Its pretty stable, only using numbers to navigate. - * - * TODO: Some pages mess around a lot with the zIndex which - * lets some hints in the background. - * TODO: Some positions are not calculated correctly (mostly - * because of uber-fancy-designed-webpages. Basic HTML and CSS - * works good - * TODO: Still some links can't be followed/unexpected things - * happen. Blame some freaky webdesigners ;) - */ - -//Just some shortcuts and globals -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; - -//Reset keycmd, modcmd and return to default mode. -function clearKeycmd() { Uzbl.run('set mode ='); } - -//Make onlick-links "clickable" -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -//Catch the ESC keypress to stop linkfollowing -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -//Calculate element position to draw the hint -//Pretty accurate but on fails in some very fancy cases -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -//Calculate if an element is visible -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -//Calculate if an element is on the viewport. -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -//Removes all hints/leftovers that might be generated -//by this script. -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -//Generate a hint for an element with the given label -//Here you can play around with the style of the hints! -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.zIndex = '1000'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - // Play around with this, pretty funny things to do :) - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} -//Here we choose what to do with an element if we -//want to "follow" it. On form elements we "select" -//or pass the focus, on links we try to perform a click, -//but at least set the href of the link. (needs some improvements) -function clickElem(item) { - removeAllHints(); - clearKeycmd(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} -//Returns a list of all links (in this version -//just the elements itself, but in other versions, we -//add the label here. -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - } - } - return res; -} -//Same as above, just for the form elements -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - } - } - } - return res; -} -//Draw all hints for all elements passed. "len" is for -//the number of chars we should use to avoid collisions -function reDrawHints(elems, chars) { - removeAllHints(); - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - for (var i = 0; i < elems[0].length; i++) { - if (elems[0][i]) { - var label = elems[1][i].substring(chars); - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - } -} -//Put it all together -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - var label = j + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - for (var k = 0; k < s.length; k++) { - b = b && label.charAt(k) == s[k]; - } - if (b) { - leftover[0].push(elems[0][j]); - leftover[1].push(label); - } - } - reDrawHints(leftover, s.length); - } -} -followLinks('%s'); diff --git a/examples/data/uzbl/scripts/follow_Numbers_Strings.js b/examples/data/uzbl/scripts/follow_Numbers_Strings.js deleted file mode 100644 index e50da5d..0000000 --- a/examples/data/uzbl/scripts/follow_Numbers_Strings.js +++ /dev/null @@ -1,212 +0,0 @@ -var uzblid = 'uzbl_link_hint'; -var uzbldivid = uzblid + '_div_container'; -var doc = document; -var win = window; -var links = document.links; -var forms = document.forms; - -//Reset keycmd, modcmd and return to default mode. -function clearKeycmd() { Uzbl.run('set mode ='); } - -try { - HTMLElement.prototype.click = function() { - if (typeof this.onclick == 'function') { - this.onclick({ - type: 'click' - }); - } - }; -} catch(e) {} -function keyPressHandler(e) { - var kC = window.event ? event.keyCode: e.keyCode; - var Esc = window.event ? 27 : e.DOM_VK_ESCAPE; - if (kC == Esc) { - removeAllHints(); - } -} -function elementPosition(el) { - var up = el.offsetTop; - var left = el.offsetLeft; - var width = el.offsetWidth; - var height = el.offsetHeight; - while (el.offsetParent) { - el = el.offsetParent; - up += el.offsetTop; - left += el.offsetLeft; - } - return [up, left, width, height]; -} -function isVisible(el) { - if (el == doc) { - return true; - } - if (!el) { - return false; - } - if (!el.parentNode) { - return false; - } - if (el.style) { - if (el.style.display == 'none') { - return false; - } - if (el.style.visibility == 'hidden') { - return false; - } - } - return isVisible(el.parentNode); -} -function elementInViewport(el) { - offset = elementPosition(el); - var up = offset[0]; - var left = offset[1]; - var width = offset[2]; - var height = offset[3]; - return up < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && (up + height) > window.pageYOffset && (left + width) > window.pageXOffset; -} -function removeAllHints() { - var elements = doc.getElementById(uzbldivid); - if (elements) { - elements.parentNode.removeChild(elements); - } -} -function generateHint(el, label) { - var pos = elementPosition(el); - var hint = doc.createElement('div'); - hint.setAttribute('name', uzblid); - hint.innerText = label; - hint.style.display = 'inline'; - hint.style.backgroundColor = '#B9FF00'; - hint.style.border = '2px solid #4A6600'; - hint.style.color = 'black'; - hint.style.zIndex = '1000'; - hint.style.fontSize = '9px'; - hint.style.fontWeight = 'bold'; - hint.style.lineHeight = '9px'; - hint.style.margin = '0px'; - hint.style.padding = '1px'; - hint.style.position = 'absolute'; - hint.style.left = pos[1] + 'px'; - hint.style.top = pos[0] + 'px'; - var img = el.getElementsByTagName('img'); - if (img.length > 0) { - hint.style.left = pos[1] + img[0].width / 2 + 'px'; - } - hint.style.textDecoration = 'none'; - hint.style.webkitBorderRadius = '6px'; - hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; - return hint; -} - -function clickElem(item) { - removeAllHints(); - clearKeycmd(); - if (item) { - var name = item.tagName; - if (name == 'A') { - item.click(); - window.location = item.href; - } else if (name == 'INPUT') { - var type = item.getAttribute('type').toUpperCase(); - if (type == 'TEXT' || type == 'FILE' || type == 'PASSWORD') { - item.focus(); - item.select(); - } else { - item.click(); - } - } else if (name == 'TEXTAREA' || name == 'SELECT') { - item.focus(); - item.select(); - } else { - item.click(); - window.location = item.href; - } - } -} - -function addLinks() { - res = [[], []]; - for (var l = 0; l < links.length; l++) { - var li = links[l]; - if (isVisible(li) && elementInViewport(li)) { - res[0].push(li); - res[1].push(li.innerText.toLowerCase()); - } - } - return res; -} -function addFormElems() { - res = [[], []]; - for (var f = 0; f < forms.length; f++) { - for (var e = 0; e < forms[f].elements.length; e++) { - var el = forms[f].elements[e]; - if (el && ['INPUT', 'TEXTAREA', 'SELECT'].indexOf(el.tagName) + 1 && isVisible(el) && elementInViewport(el)) { - res[0].push(el); - if (el.getAttribute('value')) { - res[1].push(el.getAttribute('value').toLowerCase()); - } else { - res[1].push(el.getAttribute('name').toLowerCase()); - } - } - } - } - return res; -} -function reDrawHints(elems, len) { - var hintdiv = doc.createElement('div'); - hintdiv.setAttribute('id', uzbldivid); - hintdiv.style.opacity = '0.0'; - for (var i = 0; i < elems[0].length; i++) { - var label = i + ''; - var n = label.length; - for (n; n < len; n++) { - label = '0' + label; - } - if (elems[0][i]) { - var h = generateHint(elems[0][i], label); - hintdiv.appendChild(h); - } - } - if (document.body) { - document.body.appendChild(hintdiv); - hintdiv.style.opacity = '0.7' - } -} -function followLinks(follow) { - var s = follow.split(''); - var linknr = parseInt(follow, 10); - if (document.body) document.body.setAttribute('onkeyup', 'keyPressHandler(event)'); - var linkelems = addLinks(); - var formelems = addFormElems(); - var elems = [linkelems[0].concat(formelems[0]), linkelems[1].concat(formelems[1])]; - var len = (elems[0].length + '').length; - var oldDiv = doc.getElementById(uzbldivid); - var leftover = [[], []]; - if (linknr + 1 && s.length == len && linknr < elems[0].length && linknr >= 0) { - clickElem(elems[0][linknr]); - } else { - for (var j = 0; j < elems[0].length; j++) { - var b = true; - for (var k = 0; k < s.length; k++) { - b = b && elems[1][j].charAt(k) == s[k]; - } - if (!b) { - elems[0][j] = null; - elems[1][j] = null; - } else { - leftover[0].push(elems[0][j]); - leftover[1].push(elems[1][j]); - } - } - if (leftover[0].length == 1) { - clickElem(leftover[0][0]); - } else if (!oldDiv) { - if (linknr + 1 || s.length == 0) { - reDrawHints(elems, len); - } else { - reDrawHints(leftover, len); - } - } - } -} -followLinks('%s'); -- cgit v1.2.3 From b073f78bbcb1bbf7699707aa1381df78737b06fc Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 6 Jan 2010 06:43:24 +0200 Subject: get back to default styles, github had a mess --- examples/data/uzbl/scripts/follow.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow.js b/examples/data/uzbl/scripts/follow.js index 19a0a28..d697368 100644 --- a/examples/data/uzbl/scripts/follow.js +++ b/examples/data/uzbl/scripts/follow.js @@ -106,15 +106,17 @@ function generateHint(el, label) { hint.style.padding = '1px'; hint.style.position = 'absolute'; hint.style.zIndex = '1000'; -// hint.style.textTransform = 'uppercase'; - hint.style.left = Math.max(-1, (pos[1] - (7 + label.length * 9))) + 'px'; - hint.style.top = (pos[0] + 1) + 'px'; - var img = el.getElementsByTagName('img'); - //if (img.length > 0) { - //hint.style.top = pos[1] + img[0].height / 2 - 6 + 'px'; - //} + // hint.style.textTransform = 'uppercase'; + hint.style.left = pos[1] + 'px'; + hint.style.top = pos[0] + 'px'; + // var img = el.getElementsByTagName('img'); + // if (img.length > 0) { + // hint.style.top = pos[1] + img[0].height / 2 - 6 + 'px'; + // } hint.style.textDecoration = 'none'; // hint.style.webkitBorderRadius = '6px'; // slow + // Play around with this, pretty funny things to do :) + // hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px,-5px)'; return hint; } //Here we choose what to do with an element if we -- cgit v1.2.3 From 9d53b1fcc0828b0359bdae606d79f3106b7cca49 Mon Sep 17 00:00:00 2001 From: tczy Date: Wed, 6 Jan 2010 06:58:28 +0200 Subject: remove unneeded var --- examples/data/uzbl/scripts/follow.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/follow.js b/examples/data/uzbl/scripts/follow.js index d697368..12b3765 100644 --- a/examples/data/uzbl/scripts/follow.js +++ b/examples/data/uzbl/scripts/follow.js @@ -263,9 +263,8 @@ function followLinks(follow) { } } -//Parse input: first argument is user input, second is allowed hint keys. +//Parse input: first argument is user input, second is defined hint keys. var args = '%s'.split(' '); -var following = args[0]; var charset = args[1]; -followLinks(following); +followLinks(args[0]); -- cgit v1.2.3 From 36029e1faf0761607e3192fb4968f3228d84af9f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sat, 9 Jan 2010 13:47:54 +0800 Subject: Comment out anything in the config that used @jsh or the Uzbl object. --- examples/config/uzbl/config | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 3edb36c..e53dd1a 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -35,7 +35,7 @@ set shell_cmd = sh -c set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts # Javascipt helpers. -set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; +#set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; # === Handlers =============================================================== @@ -71,7 +71,7 @@ set new_window = sh 'uzbl-browser -u $8' # Generate a FORM_ACTIVE event if an editable # element on the loaded site has initial focus -@on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} +#@on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} # Switch to insert mode if a (editable) html form is clicked @on_event FORM_ACTIVE @set_mode insert @@ -192,9 +192,9 @@ set ebind = @mode_bind global,-insert # Middle click # if clicked on a link open the link in a new uzbl window # otherwise open the selection in the current window -set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' -set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' -@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } +#set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' +#set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' +#@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } # === Keyboard bindings ====================================================== @@ -276,7 +276,7 @@ set toggle_cmd_ins = @toggle_modes command insert @cbind gh = uri http://www.uzbl.org # --- Yanking & pasting binds --- -@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); +#@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); # Go the page from primary selection @cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' -- cgit v1.2.3 From e1806cf413fbafa7dfef273ca4ced37e1918d080 Mon Sep 17 00:00:00 2001 From: Paweł Zuzelski Date: Sun, 10 Jan 2010 02:39:50 +0100 Subject: authentication_handler implementaion Authentication handler allows to delegate http authentication to external program. It introduces one new configuration variable: authentication_handler. Note that this commit does not affect uzbl behaviour unless this variable is set. Also updated README documentation, default config and added example authentication script. --- README | 32 +++++++++++++++++++++++++ examples/config/config | 1 + examples/data/scripts/auth.py | 53 ++++++++++++++++++++++++++++++++++++++++ src/callbacks.c | 11 +++++++++ src/callbacks.h | 3 +++ src/uzbl-core.c | 56 +++++++++++++++++++++++++++++++++++++++++++ src/uzbl-core.h | 8 +++++++ 7 files changed, 164 insertions(+) create mode 100644 examples/data/scripts/auth.py (limited to 'examples') diff --git a/README b/README index 217e6bf..99daef1 100644 --- a/README +++ b/README @@ -204,6 +204,7 @@ Besides the builtin variables you can also define your own ones and use them in - `cookie_handler` - `new_window`: handler to execute to invoke new uzbl window (TODO better name) - `scheme_handler`: handler to execute for each URI navigated to - the navigation request will be ignored if handler prints "USED\n" + - `authentication_handler`: command that handles http authentication - `fifo_dir`: location to store fifo's - `socket_dir`: location to store sockets - `print_events`: show events on stdout @@ -395,6 +396,12 @@ The script specific arguments are this: $8 URI of the page to be navigated to +* authentication handler: + + $8 authentication zone unique identifier + $9 domain part of URL that requests authentication + $10 authentication realm + $11 FALSE if this is the first attempt to authenticate, TRUE otherwise Custom, userdefined scripts (`spawn foo bar`) get first the arguments as specified in the config and then the above 7 are added at the end. @@ -411,6 +418,31 @@ Currently, the `Uzbl` object provides only one function: * `Uzbl.run("spawn insert_bookmark.sh")` * `uri = Uzbl.run("print @uri")` (see variable expansion below) +### AUTHENTICATION ### + +If authentication_handler variable is not set, http authentication is handled internally by WebKit. If you want to use custom script for http authentication, set authentication_handler. For example: + + set authentication_handler = sync_spawn /patch/to/your/script + +Script will be executed on each authentication request. It will receive four auth-related parameters: + + $8 authentication zone unique identifier (may be used as hash key in passwords database) + $9 domain part of URL that requests authentication + $10 authentication realm + $11 FALSE if this is the first attempt to authenticate, TRUE otherwise + +Script is expected to print exactly two lines of text on stdout (that means its output must contain exactly two '\n' bytes). The first line contains username, the second one - password. +If authentication fail, script will be executed again (with $11 = TRUE). Non-interactive scripts should handle this case and do not try to authenticate again to avoid loops. +If number of '\n' characters in scripts output does not equal 2, authentication will fail. That means 401 error will be displayed and uzbl won't try to authenticate anymore. + +The simplest example of authentication handler script is: + +#!/bin/sh +[ "$11" == "TRUE ] && exit +echo alice +echo wonderland + +This script tries to authenticate as user alice with password wonderland once and never retries authentication. See examples for more sofisticated, interactive authentication handler. ### EVENTS ### diff --git a/examples/config/config b/examples/config/config index eb17813..91ef872 100644 --- a/examples/config/config +++ b/examples/config/config @@ -45,6 +45,7 @@ set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; func # support events that can wait for a response from a script. set cookie_handler = talk_to_socket $XDG_CACHE_HOME/uzbl/cookie_daemon_socket set scheme_handler = sync_spawn @scripts_dir/scheme.py +set authentication_handler = sync_spawn @scripts_dir/auth.py # Open in the same window. #set new_window = sh 'echo uri "$8" > $4' diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py new file mode 100644 index 0000000..4feb90b --- /dev/null +++ b/examples/data/scripts/auth.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import gtk +import sys + +def responseToDialog(entry, dialog, response): + dialog.response(response) + +def getText(authInfo, authHost, authRealm): + dialog = gtk.MessageDialog( + None, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_QUESTION, + gtk.BUTTONS_OK_CANCEL, + None) + dialog.set_markup('%s at %s' % (authRealm, authHost)) + + login = gtk.Entry() + password = gtk.Entry() + password.set_visibility(False) + + login.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) + password.connect("activate", responseToDialog, dialog, gtk.RESPONSE_OK) + + hbox = gtk.HBox(); + + vbox_entries = gtk.VBox(); + vbox_labels = gtk.VBox(); + + vbox_labels.pack_start(gtk.Label("Login:"), False, 5, 5) + vbox_labels.pack_end(gtk.Label("Password:"), False, 5, 5) + + vbox_entries.pack_start(login) + vbox_entries.pack_end(password) + + dialog.format_secondary_markup("Please enter username and password:") + hbox.pack_start(vbox_labels, True, True, 0) + hbox.pack_end(vbox_entries, True, True, 0) + + dialog.vbox.pack_start(hbox) + dialog.show_all() + rv = dialog.run() + + output = login.get_text() + "\n" + password.get_text() + dialog.destroy() + return rv, output + +if __name__ == '__main__': + rv, output = getText(sys.argv[8], sys.argv[9], sys.argv[10]) + if (rv == gtk.RESPONSE_OK): + print output; + else: + exit(1) diff --git a/src/callbacks.c b/src/callbacks.c index dab92c1..b2f05cf 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -26,6 +26,17 @@ set_proxy_url() { return; } +void +set_authentication_handler() { + if (uzbl.behave.authentication_handler) + soup_session_remove_feature_by_type + (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG); + else + soup_session_add_feature_by_type + (uzbl.net.soup_session, (GType) WEBKIT_TYPE_SOUP_AUTH_DIALOG); + return; +} + void set_icon() { if(file_exists(uzbl.gui.icon)) { diff --git a/src/callbacks.h b/src/callbacks.h index 3f318f2..7fe5c19 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -12,6 +12,9 @@ cmd_set_status(); void set_proxy_url(); +void +set_authentication_handler(); + void set_icon(); diff --git a/src/uzbl-core.c b/src/uzbl-core.c index 8a053f6..cd907f4 100644 --- a/src/uzbl-core.c +++ b/src/uzbl-core.c @@ -101,6 +101,7 @@ const struct var_name_to_ptr_t { { "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)}, { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, NULL)}, + { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)}, { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)}, { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)}, { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)}, @@ -2316,6 +2317,61 @@ settings_init () { init_connect_socket(); g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL); + g_signal_connect(n->soup_session, "authenticate", G_CALLBACK(handle_authentication), NULL); +} + +void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data) { + + (void) user_data; + + if(uzbl.behave.authentication_handler) { + char *username, *password; + gchar *info, *host, *realm; + int number_of_endls=0; + gchar *p; + + soup_session_pause_message(session, msg); + + /* Sanitize strings */ + info = g_strdup(soup_auth_get_info(auth)); + host = g_strdup(soup_auth_get_host(auth)); + realm = g_strdup(soup_auth_get_realm(auth)); + for (p = info; *p; p++) if (*p == '\'') *p = '\"'; + for (p = host; *p; p++) if (*p == '\'') *p = '\"'; + for (p = realm; *p; p++) if (*p == '\'') *p = '\"'; + + GString *s = g_string_new (""); + g_string_printf(s, "'%s' '%s' '%s' '%s'", + info, host, realm, retrying?"TRUE":"FALSE"); + + run_handler(uzbl.behave.authentication_handler, s->str); + + username = uzbl.comm.sync_stdout; + + for (p = uzbl.comm.sync_stdout; *p; p++) { + if (*p == '\n') { + *p = '\0'; + if (++number_of_endls == 1) + password = p + 1; + } + } + + /* If stdout was correct (contains exactly two lines of text) do + * authenticate. Otherwise fail. */ + if (number_of_endls == 2) { + soup_auth_authenticate(auth, username, password); + } else { + g_free(username); + g_free(password); + } + + soup_session_unpause_message(session, msg); + + g_string_free(s, TRUE); + g_free(info); + g_free(host); + g_free(realm); + } } void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ diff --git a/src/uzbl-core.h b/src/uzbl-core.h index df9eb1a..998ea1d 100644 --- a/src/uzbl-core.h +++ b/src/uzbl-core.h @@ -122,6 +122,7 @@ typedef struct { gchar* socket_dir; gchar* download_handler; gchar* cookie_handler; + gchar* authentication_handler; gchar* new_window; gchar* default_font_family; gchar* monospace_font_family; @@ -389,6 +390,13 @@ run_external_js (WebKitWebView * web_view, GArray *argv, GString *result); void eval_js(WebKitWebView * web_view, gchar *script, GString *result); +void +handle_authentication (SoupSession *session, + SoupMessage *msg, + SoupAuth *auth, + gboolean retrying, + gpointer user_data); + void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data); -- cgit v1.2.3 From c6756f9373b837aa3ff499f1e6bd7477d0eec361 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Mon, 11 Jan 2010 20:05:32 +0800 Subject: Fix yank bind now that the Uzbl object is gone. --- examples/config/uzbl/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index e53dd1a..2832505 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -276,7 +276,8 @@ set toggle_cmd_ins = @toggle_modes command insert @cbind gh = uri http://www.uzbl.org # --- Yanking & pasting binds --- -#@cbind y* = @jsh if('%s' == 'u') { run("sh 'echo -n $6 | xclip'"); } else if('%s' == 't') { run("sh 'echo -n $7 | xclip'"); }; run('event SET_KEYCMD'); +@cbind yu = sh 'echo -n $6 | xclip' +@cbind yy = sh 'echo -n $7 | xclip' # Go the page from primary selection @cbind p = sh 'echo "uri `xclip -selection primary -o`" > $4' -- cgit v1.2.3 From 579c60242c8054659482443f95c6e13a79807843 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 13 Jan 2010 16:14:20 +0800 Subject: Fix middle click binding (to open selected uri in new window). --- examples/config/uzbl/config | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 2832505..6843804 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -189,12 +189,8 @@ set ebind = @mode_bind global,-insert # === Mouse bindings ========================================================= -# Middle click -# if clicked on a link open the link in a new uzbl window -# otherwise open the selection in the current window -#set load_from_xclip = sh 'echo "uri $(xclip -o)" > $4' -#set open_new_window = sh 'uzbl-browser -u \@SELECTED_URI' -#@bind = @jsh if(get("SELECTED_URI")) { run("\@open_new_window"); } else { run("\\\@load_from_xclip"); } +# Middle click open in new window +@bind = sh 'uzbl-browser -u \@SELECTED_URI' # === Keyboard bindings ====================================================== -- cgit v1.2.3 From 0cd867b2329ed9bb67796e01036ba27ad7530445 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 19 Jan 2010 19:39:22 +0800 Subject: Unicode connect arguments were crashing the handler __repr__ method --- examples/data/uzbl/scripts/uzbl-event-manager | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/scripts/uzbl-event-manager b/examples/data/uzbl/scripts/uzbl-event-manager index 2df3357..2da899e 100755 --- a/examples/data/uzbl/scripts/uzbl-event-manager +++ b/examples/data/uzbl/scripts/uzbl-event-manager @@ -334,12 +334,12 @@ class EventHandler(object): "function=%r" % self.function] if self.args: - args.append("args=%r" % self.args) + args.append(u"args=%r" % unicode(self.args)) if self.kargs: - args.append("kargs=%r" % self.kargs) + args.append(u"kargs=%r" % unicode(self.kargs)) - return "" % ', '.join(args) + return u"" % ', '.join(args) class UzblInstance(object): -- cgit v1.2.3 From c31bec6355e70a3867505a7ab3eb4c4e974e1631 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 19 Jan 2010 19:41:37 +0800 Subject: Reduced the {key,mod}cmd_{update,exec} functions into a single function. --- examples/data/uzbl/plugins/bind.py | 59 +++++++------------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 9e09337..427c8d3 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -444,12 +444,12 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): return True -def keycmd_update(uzbl, keylet): +def key_event(uzbl, keylet, modcmd=False, onexec=False): bindlet = get_bindlet(uzbl) depth = bindlet.depth for bind in bindlet.get_binds(): t = bind[depth] - if t[MOD_CMD] or t[ON_EXEC]: + if (bool(t[MOD_CMD]) != modcmd) or (t[ON_EXEC] != onexec): continue if match_and_exec(uzbl, bind, depth, keylet, bindlet): @@ -458,60 +458,23 @@ def keycmd_update(uzbl, keylet): bindlet.after() -def keycmd_exec(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if t[MOD_CMD] or not t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return uzbl.clear_keycmd() - - bindlet.after() - - -def modcmd_update(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if not t[MOD_CMD] or t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return - - bindlet.after() - - -def modcmd_exec(uzbl, keylet): - bindlet = get_bindlet(uzbl) - depth = bindlet.depth - for bind in bindlet.get_binds(): - t = bind[depth] - if not t[MOD_CMD] or not t[ON_EXEC]: - continue - - if match_and_exec(uzbl, bind, depth, keylet, bindlet): - return uzbl.clear_modcmd() - - bindlet.after() - - def init(uzbl): # Event handling hooks. uzbl.connect_dict({ 'BIND': parse_bind, - 'KEYCMD_EXEC': keycmd_exec, - 'KEYCMD_UPDATE': keycmd_update, - 'MODCMD_EXEC': modcmd_exec, - 'MODCMD_UPDATE': modcmd_update, 'MODE_BIND': parse_mode_bind, 'MODE_CHANGED': mode_changed, }) + # Connect key related events to the key_event function. + events = [['KEYCMD_UPDATE', 'KEYCMD_EXEC'], + ['MODCMD_UPDATE', 'MODCMD_EXEC']] + + for modcmd in range(2): + for onexec in range(2): + event = events[modcmd][onexec] + uzbl.connect(event, key_event, bool(modcmd), bool(onexec)) + # Function exports to the uzbl object, `function(uzbl, *args, ..)` # becomes `uzbl.function(*args, ..)`. uzbl.export_dict({ -- cgit v1.2.3 From 8b40bdc060f29d9c7d2092fce2bd33f1c3115b7f Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 19 Jan 2010 21:00:44 +0800 Subject: Fixed problem with * binds in stack mode. --- examples/data/uzbl/plugins/bind.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/data/uzbl/plugins/bind.py b/examples/data/uzbl/plugins/bind.py index 427c8d3..1dd2ee8 100644 --- a/examples/data/uzbl/plugins/bind.py +++ b/examples/data/uzbl/plugins/bind.py @@ -404,7 +404,6 @@ def mode_changed(uzbl, mode): def match_and_exec(uzbl, bind, depth, keylet, bindlet): - (on_exec, has_args, mod_cmd, glob, more) = bind[depth] cmd = keylet.modcmd if mod_cmd else keylet.keycmd @@ -436,20 +435,20 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): args = bindlet.args + args exec_bind(uzbl, bind, *args) - uzbl.set_mode() - if not has_args: + if not has_args or on_exec: + uzbl.set_mode() bindlet.reset() uzbl.clear_current() return True -def key_event(uzbl, keylet, modcmd=False, onexec=False): +def key_event(uzbl, keylet, mod_cmd=False, on_exec=False): bindlet = get_bindlet(uzbl) depth = bindlet.depth for bind in bindlet.get_binds(): t = bind[depth] - if (bool(t[MOD_CMD]) != modcmd) or (t[ON_EXEC] != onexec): + if (bool(t[MOD_CMD]) != mod_cmd) or (t[ON_EXEC] != on_exec): continue if match_and_exec(uzbl, bind, depth, keylet, bindlet): @@ -457,6 +456,11 @@ def key_event(uzbl, keylet, modcmd=False, onexec=False): bindlet.after() + # Return to the previous mode if the KEYCMD_EXEC keycmd doesn't match any + # binds in the stack mode. + if on_exec and not mod_cmd and depth and depth == bindlet.depth: + uzbl.set_mode() + def init(uzbl): # Event handling hooks. @@ -470,10 +474,10 @@ def init(uzbl): events = [['KEYCMD_UPDATE', 'KEYCMD_EXEC'], ['MODCMD_UPDATE', 'MODCMD_EXEC']] - for modcmd in range(2): - for onexec in range(2): - event = events[modcmd][onexec] - uzbl.connect(event, key_event, bool(modcmd), bool(onexec)) + for mod_cmd in range(2): + for on_exec in range(2): + event = events[mod_cmd][on_exec] + uzbl.connect(event, key_event, bool(mod_cmd), bool(on_exec)) # Function exports to the uzbl object, `function(uzbl, *args, ..)` # becomes `uzbl.function(*args, ..)`. -- cgit v1.2.3 From c92b449db2dc60403b5c2c465d878f8691021306 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 19 Jan 2010 21:27:36 +0800 Subject: Reverting back to better non-js middle click binding. --- examples/config/uzbl/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index 6843804..f65566c 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -190,7 +190,7 @@ set ebind = @mode_bind global,-insert # === Mouse bindings ========================================================= # Middle click open in new window -@bind = sh 'uzbl-browser -u \@SELECTED_URI' +@bind = sh 'if [ "\@SELECTED_URI" ]; then uzbl-browser -u "\@SELECTED_URI"; else echo "uri $(xclip -o)" > $4; fi' # === Keyboard bindings ====================================================== -- cgit v1.2.3 From a7e844dae0d77918673d1d0a41b3bd6f1e763893 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Tue, 19 Jan 2010 21:37:07 +0800 Subject: Remove all mentions of the Uzbl object and @jsh helper variable. --- examples/config/uzbl/config | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index f65566c..081ea8a 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -34,8 +34,6 @@ set shell_cmd = sh -c # Spawn path shortcuts. In spawn the first dir+path match is used in "dir1:dir2:dir3:executable" set scripts_dir = $XDG_DATA_HOME/uzbl:@prefix/share/uzbl/examples/data/uzbl:scripts -# Javascipt helpers. -#set jsh = js var run=Uzbl.run; function get(k){return run("print \\\@"+k)}; function set(k, v) {run("set "+k+" = "+v)}; # === Handlers =============================================================== @@ -69,10 +67,6 @@ set new_window = sh 'uzbl-browser -u $8' @on_event LOAD_FINISH @set_status done @on_event LOAD_FINISH spawn @scripts_dir/history.sh -# Generate a FORM_ACTIVE event if an editable -# element on the loaded site has initial focus -#@on_event LOAD_FINISH js if(document.activeElement.type == 'text') {Uzbl.run("event FORM_ACTIVE");} - # Switch to insert mode if a (editable) html form is clicked @on_event FORM_ACTIVE @set_mode insert # Switch to command mode if anything else is clicked @@ -81,6 +75,7 @@ set new_window = sh 'uzbl-browser -u $8' # Example CONFIG_CHANGED event handler #@on_event CONFIG_CHANGED print Config changed: %1 = %2 + # === Behaviour and appearance =============================================== set show_status = 1 @@ -322,10 +317,6 @@ menu_editable_add Open in @external_editor = script @scripts_dir/extedit.js #@bind X1 = sh 'echo "set zoom_level = 1.0" > "$4"' #@bind X2 = sh 'echo "js alert (\\"This is sent by the shell via a fifo\\")" > "$4"' -# Working with the javascript helper variable jsh. -#@bind X3 = @jsh alert(get('zoom_level')); -#@bind X4 = @jsh if(get('mode') == "insert") { alert("You are in insert mode") } else { alert(get('mode')+" is a silly mode.") }; - # === Context menu items ===================================================== -- cgit v1.2.3 From 5aa5cbdb8d12c6b2675e416f69ec36aaed7696c0 Mon Sep 17 00:00:00 2001 From: tczy Date: Tue, 19 Jan 2010 17:26:28 +0200 Subject: No script fluff should be in config.h, thanks mason. --- config.h | 1 - examples/config/uzbl/config | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/config.h b/config.h index 80ca29c..e9b9a8e 100644 --- a/config.h +++ b/config.h @@ -6,6 +6,5 @@ const struct { { "set title_format_short = \\@TITLE - Uzbl browser <\\@NAME>"}, { "set max_conns = 100"}, /* WebkitGTK default: 10 */ { "set max_conns_host = 6"}, /* WebkitGTK default: 2 */ -{ "set follow_hint_keys = 0123456789"}, { NULL } }; diff --git a/examples/config/uzbl/config b/examples/config/uzbl/config index f8a2058..e000015 100644 --- a/examples/config/uzbl/config +++ b/examples/config/uzbl/config @@ -296,7 +296,7 @@ set toggle_cmd_ins = @toggle_modes command insert # --- Link following (similar to vimperator and konqueror) --- # Set custom keys you wish to use for navigation. Some common examples: -#set follow_hint_keys = qwerty +set follow_hint_keys = qwerty #set follow_hint_keys = asdfghjkl; #set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 @cbind f* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' -- cgit v1.2.3 From 5c4a5d2bd8adbe8ceca6afda1a721991a6f73c82 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 24 Jan 2010 20:23:36 +0800 Subject: Added example uzbl-tabbed binds for updated uzbl-tabbed. --- examples/config/config | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'examples') diff --git a/examples/config/config b/examples/config/config index 2a18a57..28fa5fd 100644 --- a/examples/config/config +++ b/examples/config/config @@ -240,6 +240,27 @@ set ebind = @mode_bind global,-insert @cbind n = search @cbind N = search_reverse +# --- Uzbl tabbed binds --- +# Tab opening +@cbind gn = event NEW_TAB +@cbind go_ = event NEW_TAB %s +@cbind gY = sh 'echo "event NEW_TAB `xclip -selection primary -o`" > $4' +# Closing / resting +@cbind gC = exit +@cbind gQ = event CLEAN_TABS +# Tab navigating +@cbind g< = event FIRST_TAB +@cbind g> = event LAST_TAB +@cbind gt = event NEXT_TAB +@cbind gT = event PREV_TAB +@cbind gi_ = event GOTO_TAB %s +# Preset loading +set preset = event PRESET_TABS +@cbind gs_ = @preset save %s +@cbind glo_ = @preset load %s +@cbind gd_ = @preset del %s +@cbind gli = @preset list + # --- Web searching binds --- @cbind gg_ = uri http://www.google.com/search?q=\@\@ @cbind \\awiki_ = uri http://wiki.archlinux.org/index.php/Special:Search?search=\@\@&go=Go -- cgit v1.2.3 From 1e34a994e7ce556c45a7fd294c35a085c12b504c Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 24 Jan 2010 22:14:13 +0800 Subject: Ignore os.makedirs race-condition exceptions. --- examples/data/scripts/uzbl-event-manager | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/data/scripts/uzbl-event-manager b/examples/data/scripts/uzbl-event-manager index a234985..9624b14 100755 --- a/examples/data/scripts/uzbl-event-manager +++ b/examples/data/scripts/uzbl-event-manager @@ -217,9 +217,13 @@ def daemonize(): def make_dirs(path): '''Make all basedirs recursively as required.''' - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) + try: + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + + except OSError: + print_exc() def make_pid_file(pid_file): -- cgit v1.2.3 From ddf6cfbb7f85ae994681e2578d230563baa419f4 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 24 Jan 2010 22:16:21 +0800 Subject: Consistency fix in the bind plugin with regard to '*' binds. The problem (as highlighted by the link following scripts) was that when the user enters a stack bind (like a "fl*" bind) that binds command isn't executed with a null argument. When you do the equivalent without stack binds (like a "fl*" bind) that binds command is executed with a null argument as soon as you type "fl". This behaviour is useful and exploited heavily by the link following scripts which use the null argument as a trigger to "numberize" all the links in the visible area. --- examples/data/plugins/bind.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/data/plugins/bind.py b/examples/data/plugins/bind.py index 1dd2ee8..a1a5d89 100644 --- a/examples/data/plugins/bind.py +++ b/examples/data/plugins/bind.py @@ -431,6 +431,10 @@ def match_and_exec(uzbl, bind, depth, keylet, bindlet): elif more: bindlet.stack(bind, args, depth) + (on_exec, has_args, mod_cmd, glob, more) = bind[depth+1] + if not on_exec and has_args and not glob and not more: + exec_bind(uzbl, bind, *(args+['',])) + return False args = bindlet.args + args -- cgit v1.2.3 From c3c4d481079f2a24ea16cd49b785b6f358a28fc9 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 24 Jan 2010 15:35:50 +0100 Subject: add P.C. Shyamshankar's follower --- examples/data/scripts/follower.js | 420 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 examples/data/scripts/follower.js (limited to 'examples') diff --git a/examples/data/scripts/follower.js b/examples/data/scripts/follower.js new file mode 100644 index 0000000..604b779 --- /dev/null +++ b/examples/data/scripts/follower.js @@ -0,0 +1,420 @@ +// A Link Follower for Uzbl. +// P.C. Shyamshankar +// +// WARNING: this script depends on the Uzbl object which is now disabled for +// WARNING security reasons. So the script currently doesn't work but it's +// WARNING interesting nonetheless +// +// Based extensively (like copy-paste) on the follow_numbers.js and +// linkfollow.js included with uzbl, but modified to be more customizable and +// extensible. +// +// Usage +// ----- +// +// First, you'll need to make sure the script is loaded on each page. This can +// be done with: +// +// @on_event LOAD_COMMIT script /path/to/follower.js +// +// Then you can bind it to a key: +// +// @bind f* = js follower.follow('%s', matchSpec, handler, hintStyler) +// +// where matchSpec, handler and hintStyler are parameters which control the +// operation of follower. If you don't want to customize any further, you can +// set these to follower.genericMatchSpec, follower.genericHandler and +// follower.genericHintStyler respectively. +// +// For example, +// +// @bind f* = js follower.follow('%s', follower.genericMatchSpec, follower.genericHandler, follower.genericHintStyler) +// @bind F* = js follower.follow('%s', follower.onlyLinksMatchSpec, follower.newPageHandler, follower.newPageHintStyler) +// +// In order to make hints disappear when pressing a key (the Escape key, for +// example), you can do this: +// +// @bind = js follower.clearHints() +// +// If your Escape is already bound to something like command mode, chain it. +// +// Alternatively, you can tell your key to emit an event, and handle +// that instead. +// +// @bind = event ESCAPE +// @on_event ESCAPE js follower.clearHints() +// +// Customization +// ------------- +// +// If however you do want to customize, 3 Aspects of the link follower can be +// customized with minimal pain or alteration to the existing code base: +// +// * What elements are hinted. +// * The style of the hints displayed. +// * How the hints are handled. +// +// In order to customize behavior, write an alternative, and pass that in to +// follower.follow invocation. You _will_ have to modify this script, but only +// locally, it beats having to copy the entire script under a new name and +// modify. +// +// TODO: +// * Whatever all the other TODOs in the file say. +// * Find out how to do default arguments in Javascript. +// * Abstract out the hints into a Hint object, make hintables a list of hint +// objects instead of two lists. + +// Helpers +String.prototype.lpad = function(padding, length) { + var padded = this; + while (padded.length < length) { + padded = padding + padded; + } + + return padded; +} + +function Follower() { + + // Globals + var uzblID = 'uzbl-follow'; // ID to apply to each hint. + var uzblContainerID = 'uzbl-follow-container'; // ID to apply to the div containing hints. + + // Translation table, used to display something other than numbers as hint + // labels. Typically set to the ten keys of the home row. + // + // Must have exactly 10 elements. + // + // I haven't parameterized this, to make it customizable. Should I? Do + // people really use more than one set of keys at a time? + var translation = ["a", "r", "s", "t", "d", "h", "n", "e", "i", "o"]; + + // MatchSpecs + // These are XPath expressions which indicate which elements will be hinted. + // Use multiple expressions for different situations, like hinting only form + // elements, or only links, etc. + // + // TODO: Check that these XPath expressions are correct, and optimize/make + // them more elegant. Preferably by someone who actually knows XPath, unlike + // me. + + // Vimperator default (copy-pasted, I never used vimperator). + this.genericMatchSpec = " //*[@onclick or @onmouseover or @onmousedown or @onmouseup or @oncommand or @class='lk' or @role='link' or @href] | //input[not(@type='hidden')] | //a | //area | //iframe | //textarea | //button | //select"; + + // Matches only links, suitable for opening in a new instance (I think). + this.onlyLinksMatchSpec = " //*[@href] | //a | //area"; + + // Follow Handlers + // These decide how an element should be 'followed'. The handler is passed + // the element in question. + + // Generic Handler, opens links in the same instance, emits the FORM_ACTIVE + // event if a form element was chosen. Also clears the keycmd. + this.genericHandler = function(node) { + if (node) { + if (window.itemClicker != undefined) { + window.itemClicker(node); + } else { + var tag = node.tagName.toLowerCase(); + if (tag == 'a') { + node.click(); + window.location = node.href; + } else if (tag == 'input') { + var inputType = node.getAttribute('type'); + if (inputType == undefined) + inputType = 'text'; + + inputType = inputType.toLowerCase(); + + if (inputType == 'text' || inputType == 'file' || inputType == 'password') { + node.focus(); + node.select(); + } else { + node.click(); + } + Uzbl.run("event FORM_ACTIVE"); + } else if (tag == 'textarea'|| tag == 'select') { + node.focus(); + node.select(); + Uzbl.run("event FORM_ACTIVE"); + } else { + node.click(); + if ((node.href != undefined) && node.href) + window.location = node.href; + } + } + } + Uzbl.run("event SET_KEYCMD"); + } + + // Handler to open links in a new page. The rest is the same as before. + this.newPageHandler = function(node) { + if (node) { + if (window.itemClicker != undefined) { + window.itemClicker(node); + } else { + var tag = node.tagName.toLowerCase(); + if (tag == 'a') { + node.click(); + Uzbl.run("@new_window " + node.href); + } else if (tag == 'input') { + var inputType = node.getAttribute('type'); + if (inputType == undefined) + inputType = 'text'; + + inputType = inputType.toLowerCase(); + + if (inputType == 'text' || inputType == 'file' || inputType == 'password') { + node.focus(); + node.select(); + } else { + node.click(); + } + Uzbl.run("event FORM_ACTIVE"); + } else if (tag == 'textarea'|| tag == 'select') { + node.focus(); + node.select(); + Uzbl.run("event FORM_ACTIVE"); + } else { + node.click(); + if ((node.href != undefined) && node.href) + window.location = node.href; + } + } + } + Uzbl.run("event SET_KEYCMD"); + }; + + // Hint styling. + // Pretty much any attribute of the hint object can be modified here, but it + // was meant to change the styling. Useful to differentiate between hints + // with different handlers. + // + // Hint stylers are applied at the end of hint creation, so that they + // override the defaults. + + this.genericHintStyler = function(hint) { + hint.style.backgroundColor = '#AAAAAA'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '10px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '12px'; + return hint; + }; + + this.newPageHintStyler = function(hint) { + hint.style.backgroundColor = '#FFCC00'; + hint.style.border = '2px solid #4A6600'; + hint.style.color = 'black'; + hint.style.fontSize = '10px'; + hint.style.fontWeight = 'bold'; + hint.style.lineHeight = '12px'; + return hint; + }; + + // Beyond lies a jungle of pasta and verbosity. + + // Translate a numeric label using the translation table. + function translate(digitLabel, translationTable) { + translatedLabel = ''; + for (var i = 0; i < digitLabel.length; i++) { + translatedLabel += translationTable[digitLabel.charAt(i)]; + } + + return translatedLabel; + } + + function computeElementPosition(element) { + var up = element.offsetTop; + var left = element.offsetLeft; + var width = element.offsetWidth; + var height = element.offsetHeight; + + while (element.offsetParent) { + element = element.offsetParent; + up += element.offsetTop; + left += element.offsetLeft; + } + + return {up: up, left: left, width: width, height: height}; + } + + // Pretty much copy-pasted from every other link following script. + function isInViewport(element) { + offset = computeElementPosition(element); + + var up = offset.up; + var left = offset.left; + var width = offset.width; + var height = offset.height; + + return up < window.pageYOffset + window.innerHeight && + left < window.pageXOffset + window.innerWidth && + (up + height) > window.pageYOffset && + (left + width) > window.pageXOffset; + } + + function isVisible(element) { + if (element == document) { + return true; + } + + if (!element){ + return false; + } + + if (element.style) { + if (element.style.display == 'none' || element.style.visibiilty == 'hidden') { + return false; + } + } + + return isVisible(element.parentNode); + } + + function generateHintContainer() { + var container = document.getElementById(uzblContainerID); + if (container) { + container.parentNode.removeChild(container); + } + + container = document.createElement('div'); + container.id = uzblContainerID; + + if (document.body) { + document.body.appendChild(container); + } + return container; + } + + // Generate everything that is to be hinted, as per the given matchSpec. + // hintables[0] refers to the items, hintables[1] to their labels. + function generateHintables(matchSpec) { + var hintables = [[], []]; + + var itemsFromXPath = document.evaluate(matchSpec, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + + for (var i = 0; i < itemsFromXPath.snapshotLength; ++i) { + var element = itemsFromXPath.snapshotItem(i); + if (element && isVisible(element) && isInViewport(element)) { + hintables[0].push(element); + } + } + + // Assign labels to each hintable. Can't be combined with the previous + // step, because we didn't know how many there were at that time. + var hintLength = hintables.length; + for (var i = 0; i < hintables[0].length; ++i) { + var code = translate(i.toString(), translation); + hintables[1].push(code.lpad(translation[0], hintLength)); + } + + return hintables; + } + + // Filter the hintables based on input from the user. Makes the screen less + // cluttered after the user has typed some prefix of hint labels. + function filterHintables(hintables, target) { + var filtered = [[], []]; + + var targetPattern = new RegExp("^" + target); + + for (var i = 0; i < hintables[0].length; i++) { + if (hintables[1][i].match(targetPattern)) { + filtered[0].push(hintables[0][i]); + filtered[1].push(hintables[1][i].substring(target.length)); + } + } + + return filtered; + } + + // TODO make this use the container variable from main, instead of searching + // for it? + function clearHints() { + var container = document.getElementById(uzblContainerID); + if (container) { + container.parentNode.removeChild(container); + } + } + + // So that we can offer this as a separate function. + this.clearHints = clearHints; + + function makeHint(node, code, styler) { + var position = computeElementPosition(node); + var hint = document.createElement('div'); + + hint.name = uzblID; + hint.innerText = code; + hint.style.display = 'inline'; + + hint.style.margin = '0px'; + hint.style.padding = '1px'; + hint.style.position = 'absolute'; + hint.style.zIndex = '10000'; + + hint.style.left = position.left + 'px'; + hint.style.top = position.up + 'px'; + + var img = node.getElementsByTagName('img'); + if (img.length > 0) { + hint.style.left = position.left + img[0].width / 2 + 'px'; + } + + hint.style.textDecoration = 'none'; + hint.style.webkitBorderRadius = '6px'; + hint.style.webkitTransform = 'scale(1) rotate(0deg) translate(-6px, -5px)'; + + hint = styler(hint); // So that custom hint stylers can override the above. + return hint; + } + + + function drawHints(container, hintables, styler) { + for (var i = 0; i < hintables[0].length; i++) { + hint = makeHint(hintables[0][i], hintables[1][i], styler); + container.appendChild(hint); + } + + if (document.body) { + document.body.appendChild(container); + } + } + + // The main hinting function. I don't know how to do default values to + // functions, so all arguments must be specified. Use generics if you must. + this.follow = function(target, matchSpec, handler, hintStyler) { + var container = generateHintContainer(); // Get a container to hold all hints. + var allHintables = generateHintables(matchSpec); // Get all items that can be hinted. + hintables = filterHintables(allHintables, target); // Filter them based on current input. + + clearHints(); // Clear existing hints, if any. + + if (hintables[0].length == 0) { + // Nothing was hinted, user pressed an unknown key, maybe? + // Do nothing. + } else if (hintables[0].length == 1) { + handler(hintables[0][0]); // Only one hint remains, handle it. + } else { + drawHints(container, hintables, hintStyler); // Draw whatever hints remain. + } + + return; + }; +} + +// Make on-click links clickable. +try { + HTMLElement.prototype.click = function() { + if (typeof this.onclick == 'function') { + this.onclick({ + type: 'click' + }); + } + }; +} catch(e) {} + +follower = new Follower(); -- cgit v1.2.3 From 5ade8b362a571ce1c1411bbaf1a779d58a2a616b Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Sun, 24 Jan 2010 23:14:53 +0800 Subject: Default follow keys to numbers and fix follower script argument order. --- examples/config/config | 5 +++-- examples/data/scripts/follow.js | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/config/config b/examples/config/config index a2cbdcb..b376d0b 100644 --- a/examples/config/config +++ b/examples/config/config @@ -309,10 +309,11 @@ set toggle_cmd_ins = @toggle_modes command insert # --- Link following (similar to vimperator and konqueror) --- # Set custom keys you wish to use for navigation. Some common examples: -set follow_hint_keys = qwerty +set follow_hint_keys = 0123456789 +#set follow_hint_keys = qwerty #set follow_hint_keys = asdfghjkl; #set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 -@cbind f* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' +@cbind f* = script @scripts_dir/follow.js '@{follow_hint_keys} %s' # --- Form filler binds --- # this script allows you to configure (per domain) values to fill in form diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js index 12b3765..afb327f 100644 --- a/examples/data/scripts/follow.js +++ b/examples/data/scripts/follow.js @@ -263,8 +263,7 @@ function followLinks(follow) { } } -//Parse input: first argument is user input, second is defined hint keys. +//Parse input: first argument is follow keys, second is user input. var args = '%s'.split(' '); -var charset = args[1]; - -followLinks(args[0]); +var charset = args[0]; +followLinks(args[1]); -- cgit v1.2.3 From c5621d312b1ce79a6242a4aa4a9cb4b3181c6d33 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sun, 24 Jan 2010 16:22:04 +0100 Subject: permissions fix --- examples/data/scripts/auth.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/data/scripts/auth.py (limited to 'examples') diff --git a/examples/data/scripts/auth.py b/examples/data/scripts/auth.py old mode 100644 new mode 100755 -- cgit v1.2.3 From a1f343c7c57fcee1aaf22ad446198cc082c45768 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Wed, 27 Jan 2010 10:27:17 +0800 Subject: Honour old link following bind with new follow.js script. --- examples/config/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/config b/examples/config/config index a2cbdcb..dfa0f7e 100644 --- a/examples/config/config +++ b/examples/config/config @@ -312,7 +312,7 @@ set toggle_cmd_ins = @toggle_modes command insert set follow_hint_keys = qwerty #set follow_hint_keys = asdfghjkl; #set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 -@cbind f* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' +@cbind fl* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' # --- Form filler binds --- # this script allows you to configure (per domain) values to fill in form -- cgit v1.2.3 From 31b71b5d608b55b2a1460786d5ce8c0e574c0fd1 Mon Sep 17 00:00:00 2001 From: Mason Larobina Date: Fri, 29 Jan 2010 22:07:53 +0800 Subject: Re-fix order of follow.js arguments. --- examples/config/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/config/config b/examples/config/config index b30ff45..4c63fe7 100644 --- a/examples/config/config +++ b/examples/config/config @@ -314,7 +314,7 @@ set follow_hint_keys = 0123456789 #set follow_hint_keys = qwerty #set follow_hint_keys = asdfghjkl; #set follow_hint_keys = thsnd-rcgmvwb/;789aefijkopquxyz234 -@cbind fl* = script @scripts_dir/follow.js '%s @{follow_hint_keys}' +@cbind fl* = script @scripts_dir/follow.js '@follow_hint_keys %s' # --- Form filler binds --- # this script allows you to configure (per domain) values to fill in form -- cgit v1.2.3 From f15512e073ccad89e2b352147d9b69a87cad7319 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Tue, 2 Feb 2010 20:59:04 +0100 Subject: update comments about usability --- examples/data/scripts/follow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/data/scripts/follow.js b/examples/data/scripts/follow.js index afb327f..a42447c 100644 --- a/examples/data/scripts/follow.js +++ b/examples/data/scripts/follow.js @@ -1,5 +1,5 @@ /* This is the basic linkfollowing script. - * Its pretty stable, only using numbers to navigate. + * Its pretty stable, and you configure which keys to use for hinting * * TODO: Some pages mess around a lot with the zIndex which * lets some hints in the background. -- cgit v1.2.3