1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
39 #include <gdk/gdkkeysyms.h>
40 #include <sys/socket.h>
42 #include <sys/types.h>
44 #include <sys/utsname.h>
46 #include <webkit/webkit.h>
47 #include <libsoup/soup.h>
48 #include <JavaScriptCore/JavaScript.h>
59 #include <sys/ioctl.h>
65 /* commandline arguments (set initial values for the state variables) */
67 GOptionEntry entries[] =
69 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
70 "Uri to load at startup (equivalent to 'uzbl <uri>' or 'set uri = URI' after uzbl has launched)", "URI" },
71 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
72 "Whether to print all messages or just errors.", NULL },
73 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
74 "Name of the current instance (defaults to Xorg window id)", "NAME" },
75 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
76 "Path to config file or '-' for stdin", "FILE" },
77 { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
78 "Socket ID", "SOCKET" },
79 { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry,
80 "Set window geometry (format: WIDTHxHEIGHT+-X+-Y)", "GEOMETRY" },
81 { "version", 'V', 0, G_OPTION_ARG_NONE, &uzbl.behave.print_version,
82 "Print the version and exit", NULL },
83 { NULL, 0, 0, 0, NULL, NULL, NULL }
86 /* associate command names to their properties */
88 /* TODO: Make this ambiguous void **ptr into a union { char *char_p; int *int_p; float *float_p; } val;
89 the PTR() macro is kind of preventing this change at the moment. */
97 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
99 /* abbreviations to help keep the table's width humane */
100 #define PTR_V(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .writeable = 1, .func = fun }
101 #define PTR_C(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = 0, .writeable = 0, .func = fun }
106 } var_name_to_ptr[] = {
107 /* variable name pointer to variable in code type dump callback function */
108 /* ---------------------------------------------------------------------------------------------- */
109 { "uri", PTR_V(uzbl.state.uri, STR, 1, cmd_load_uri)},
110 { "verbose", PTR_V(uzbl.state.verbose, INT, 1, NULL)},
111 { "mode", PTR_V(uzbl.behave.mode, INT, 0, NULL)},
112 { "inject_html", PTR_V(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
113 { "base_url", PTR_V(uzbl.behave.base_url, STR, 1, NULL)},
114 { "html_endmarker", PTR_V(uzbl.behave.html_endmarker, STR, 1, NULL)},
115 { "html_mode_timeout", PTR_V(uzbl.behave.html_timeout, INT, 1, NULL)},
116 { "keycmd", PTR_V(uzbl.state.keycmd, STR, 1, set_keycmd)},
117 { "status_message", PTR_V(uzbl.gui.sbar.msg, STR, 1, update_title)},
118 { "show_status", PTR_V(uzbl.behave.show_status, INT, 1, cmd_set_status)},
119 { "status_top", PTR_V(uzbl.behave.status_top, INT, 1, move_statusbar)},
120 { "status_format", PTR_V(uzbl.behave.status_format, STR, 1, update_title)},
121 { "status_pbar_done", PTR_V(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
122 { "status_pbar_pending", PTR_V(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
123 { "status_pbar_width", PTR_V(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
124 { "status_background", PTR_V(uzbl.behave.status_background, STR, 1, update_title)},
125 { "insert_indicator", PTR_V(uzbl.behave.insert_indicator, STR, 1, update_indicator)},
126 { "command_indicator", PTR_V(uzbl.behave.cmd_indicator, STR, 1, update_indicator)},
127 { "title_format_long", PTR_V(uzbl.behave.title_format_long, STR, 1, update_title)},
128 { "title_format_short", PTR_V(uzbl.behave.title_format_short, STR, 1, update_title)},
129 { "icon", PTR_V(uzbl.gui.icon, STR, 1, set_icon)},
130 { "insert_mode", PTR_V(uzbl.behave.insert_mode, INT, 1, set_mode_indicator)},
131 { "always_insert_mode", PTR_V(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
132 { "reset_command_mode", PTR_V(uzbl.behave.reset_command_mode, INT, 1, NULL)},
133 { "modkey", PTR_V(uzbl.behave.modkey, STR, 1, cmd_modkey)},
134 { "load_finish_handler", PTR_V(uzbl.behave.load_finish_handler, STR, 1, NULL)},
135 { "load_start_handler", PTR_V(uzbl.behave.load_start_handler, STR, 1, NULL)},
136 { "load_commit_handler", PTR_V(uzbl.behave.load_commit_handler, STR, 1, NULL)},
137 { "history_handler", PTR_V(uzbl.behave.history_handler, STR, 1, NULL)},
138 { "download_handler", PTR_V(uzbl.behave.download_handler, STR, 1, NULL)},
139 { "cookie_handler", PTR_V(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
140 { "new_window", PTR_V(uzbl.behave.new_window, STR, 1, cmd_new_window)},
141 { "fifo_dir", PTR_V(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
142 { "socket_dir", PTR_V(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
143 { "http_debug", PTR_V(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
144 { "shell_cmd", PTR_V(uzbl.behave.shell_cmd, STR, 1, NULL)},
145 { "proxy_url", PTR_V(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
146 { "max_conns", PTR_V(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
147 { "max_conns_host", PTR_V(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
148 { "useragent", PTR_V(uzbl.net.useragent, STR, 1, cmd_useragent)},
150 /* exported WebKitWebSettings properties */
151 { "zoom_level", PTR_V(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
152 { "font_size", PTR_V(uzbl.behave.font_size, INT, 1, cmd_font_size)},
153 { "default_font_family", PTR_V(uzbl.behave.default_font_family, STR, 1, cmd_default_font_family)},
154 { "monospace_font_family", PTR_V(uzbl.behave.monospace_font_family, STR, 1, cmd_monospace_font_family)},
155 { "cursive_font_family", PTR_V(uzbl.behave.cursive_font_family, STR, 1, cmd_cursive_font_family)},
156 { "sans_serif_font_family", PTR_V(uzbl.behave.sans_serif_font_family, STR, 1, cmd_sans_serif_font_family)},
157 { "serif_font_family", PTR_V(uzbl.behave.serif_font_family, STR, 1, cmd_serif_font_family)},
158 { "fantasy_font_family", PTR_V(uzbl.behave.fantasy_font_family, STR, 1, cmd_fantasy_font_family)},
159 { "monospace_size", PTR_V(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
160 { "minimum_font_size", PTR_V(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
161 { "disable_plugins", PTR_V(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
162 { "disable_scripts", PTR_V(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
163 { "autoload_images", PTR_V(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
164 { "autoshrink_images", PTR_V(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
165 { "enable_spellcheck", PTR_V(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
166 { "enable_private", PTR_V(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
167 { "print_backgrounds", PTR_V(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
168 { "stylesheet_uri", PTR_V(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
169 { "resizable_text_areas", PTR_V(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
170 { "default_encoding", PTR_V(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
171 { "enforce_96_dpi", PTR_V(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
172 { "caret_browsing", PTR_V(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
174 /* constants (not dumpable or writeable) */
175 { "WEBKIT_MAJOR", PTR_C(uzbl.info.webkit_major, INT, NULL)},
176 { "WEBKIT_MINOR", PTR_C(uzbl.info.webkit_minor, INT, NULL)},
177 { "WEBKIT_MICRO", PTR_C(uzbl.info.webkit_micro, INT, NULL)},
178 { "ARCH_UZBL", PTR_C(uzbl.info.arch, STR, NULL)},
179 { "COMMIT", PTR_C(uzbl.info.commit, STR, NULL)},
180 { "LOAD_PROGRESS", PTR_C(uzbl.gui.sbar.load_progress, INT, NULL)},
181 { "LOAD_PROGRESSBAR", PTR_C(uzbl.gui.sbar.progress_bar, STR, NULL)},
182 { "TITLE", PTR_C(uzbl.gui.main_title, STR, NULL)},
183 { "SELECTED_URI", PTR_C(uzbl.state.selected_url, STR, NULL)},
184 { "MODE", PTR_C(uzbl.gui.sbar.mode_indicator, STR, NULL)},
185 { "NAME", PTR_C(uzbl.state.instance_name, STR, NULL)},
187 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
188 }, *n2v_p = var_name_to_ptr;
195 { "SHIFT", GDK_SHIFT_MASK }, // shift
196 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
197 { "CONTROL", GDK_CONTROL_MASK }, // control
198 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
199 { "MOD2", GDK_MOD2_MASK }, // 5th mod
200 { "MOD3", GDK_MOD3_MASK }, // 6th mod
201 { "MOD4", GDK_MOD4_MASK }, // 7th mod
202 { "MOD5", GDK_MOD5_MASK }, // 8th mod
203 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
204 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
205 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
206 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
207 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
208 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
209 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
210 { "META", GDK_META_MASK }, // meta (since 2.10)
215 /* construct a hash from the var_name_to_ptr array for quick access */
217 make_var_to_name_hash() {
218 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
220 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
225 /* --- UTILITY FUNCTIONS --- */
226 enum {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
228 get_exp_type(gchar *s) {
232 else if(*(s+1) == '{')
233 return EXP_BRACED_VAR;
234 else if(*(s+1) == '<')
236 else if(*(s+1) == '[')
239 return EXP_SIMPLE_VAR;
245 * recurse == 1: don't expand '@(command)@'
246 * recurse == 2: don't expand '@<java script>@'
249 expand(char *s, guint recurse) {
253 char *end_simple_var = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
258 gchar *cmd_stdout = NULL;
260 GString *buf = g_string_new("");
261 GString *js_ret = g_string_new("");
266 g_string_append_c(buf, *++s);
271 etype = get_exp_type(s);
276 vend = strpbrk(s, end_simple_var);
277 if(!vend) vend = strchr(s, '\0');
281 vend = strchr(s, upto);
282 if(!vend) vend = strchr(s, '\0');
286 strcpy(str_end, ")@");
288 vend = strstr(s, str_end);
289 if(!vend) vend = strchr(s, '\0');
293 strcpy(str_end, ">@");
295 vend = strstr(s, str_end);
296 if(!vend) vend = strchr(s, '\0');
300 strcpy(str_end, "]@");
302 vend = strstr(s, str_end);
303 if(!vend) vend = strchr(s, '\0');
308 strncpy(ret, s, vend-s);
312 if(etype == EXP_SIMPLE_VAR ||
313 etype == EXP_BRACED_VAR) {
314 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
315 if(c->type == TYPE_STR && *c->ptr != NULL) {
316 g_string_append(buf, (gchar *)*c->ptr);
317 } else if(c->type == TYPE_INT) {
318 g_string_append_printf(buf, "%d", (int)*c->ptr);
320 else if(c->type == TYPE_FLOAT) {
321 g_string_append_printf(buf, "%f", *(float *)c->ptr);
325 if(etype == EXP_SIMPLE_VAR)
330 else if(recurse != 1 &&
332 mycmd = expand(ret, 1);
333 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
337 g_printerr("error on running command: %s\n", err->message);
340 else if (*cmd_stdout) {
341 int len = strlen(cmd_stdout);
343 if(cmd_stdout[len-1] == '\n')
344 cmd_stdout[--len] = 0; /* strip trailing newline */
346 g_string_append(buf, cmd_stdout);
351 else if(recurse != 2 &&
353 mycmd = expand(ret, 2);
354 eval_js(uzbl.gui.web_view, mycmd, js_ret);
358 g_string_append(buf, js_ret->str);
359 g_string_free(js_ret, TRUE);
360 js_ret = g_string_new("");
364 else if(etype == EXP_ESCAPE) {
365 mycmd = expand(ret, 0);
366 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
368 g_string_append(buf, escaped);
377 g_string_append_c(buf, *s);
382 g_string_free(js_ret, TRUE);
383 return g_string_free(buf, FALSE);
390 snprintf(tmp, sizeof(tmp), "%i", val);
391 return g_strdup(tmp);
395 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
398 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
401 str_replace (const char* search, const char* replace, const char* string) {
405 buf = g_strsplit (string, search, -1);
406 ret = g_strjoinv (replace, buf);
407 g_strfreev(buf); // somebody said this segfaults
413 read_file_by_line (gchar *path) {
414 GIOChannel *chan = NULL;
415 gchar *readbuf = NULL;
417 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
420 chan = g_io_channel_new_file(path, "r", NULL);
423 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
424 const gchar* val = g_strdup (readbuf);
425 g_array_append_val (lines, val);
430 g_io_channel_unref (chan);
432 fprintf(stderr, "File '%s' not be read.\n", path);
439 parseenv (char* string) {
440 extern char** environ;
441 gchar* tmpstr = NULL;
445 while (environ[i] != NULL) {
446 gchar** env = g_strsplit (environ[i], "=", 2);
447 gchar* envname = g_strconcat ("$", env[0], NULL);
449 if (g_strrstr (string, envname) != NULL) {
450 tmpstr = g_strdup(string);
452 string = str_replace(envname, env[1], tmpstr);
457 g_strfreev (env); // somebody said this breaks uzbl
465 setup_signal(int signr, sigfunc *shandler) {
466 struct sigaction nh, oh;
468 nh.sa_handler = shandler;
469 sigemptyset(&nh.sa_mask);
472 if(sigaction(signr, &nh, &oh) < 0)
480 if (uzbl.behave.fifo_dir)
481 unlink (uzbl.comm.fifo_path);
482 if (uzbl.behave.socket_dir)
483 unlink (uzbl.comm.socket_path);
485 g_free(uzbl.state.executable_path);
486 g_free(uzbl.state.keycmd);
487 g_hash_table_destroy(uzbl.bindings);
488 g_hash_table_destroy(uzbl.behave.commands);
491 /* used for html_mode_timeout
492 * be sure to extend this function to use
493 * more timers if needed in other places
496 set_timeout(int seconds) {
498 memset(&t, 0, sizeof t);
500 t.it_value.tv_sec = seconds;
501 t.it_value.tv_usec = 0;
502 setitimer(ITIMER_REAL, &t, NULL);
505 /* --- SIGNAL HANDLER --- */
508 catch_sigterm(int s) {
514 catch_sigint(int s) {
524 set_var_value("mode", "0");
529 /* --- CALLBACKS --- */
532 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
535 (void) navigation_action;
536 (void) policy_decision;
538 const gchar* uri = webkit_network_request_get_uri (request);
539 if (uzbl.state.verbose)
540 printf("New window requested -> %s \n", uri);
541 webkit_web_policy_decision_use(policy_decision);
546 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
551 /* If we can display it, let's display it... */
552 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
553 webkit_web_policy_decision_use (policy_decision);
557 /* ...everything we can't displayed is downloaded */
558 webkit_web_policy_decision_download (policy_decision);
563 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
567 if (uzbl.state.selected_url != NULL) {
568 if (uzbl.state.verbose)
569 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
570 new_window_load_uri(uzbl.state.selected_url);
572 if (uzbl.state.verbose)
573 printf("New web view -> %s\n","Nothing to open, exiting");
579 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
582 if (uzbl.behave.download_handler) {
583 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
584 if (uzbl.state.verbose)
585 printf("Download -> %s\n",uri);
586 /* if urls not escaped, we may have to escape and quote uri before this call */
587 run_handler(uzbl.behave.download_handler, uri);
592 /* scroll a bar in a given direction */
594 scroll (GtkAdjustment* bar, GArray *argv) {
598 gdouble page_size = gtk_adjustment_get_page_size(bar);
599 gdouble value = gtk_adjustment_get_value(bar);
600 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
603 value += page_size * amount * 0.01;
607 max_value = gtk_adjustment_get_upper(bar) - page_size;
609 if (value > max_value)
610 value = max_value; /* don't scroll past the end of the page */
612 gtk_adjustment_set_value (bar, value);
616 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
617 (void) page; (void) argv; (void) result;
618 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
622 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
623 (void) page; (void) argv; (void) result;
624 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
625 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
629 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
630 (void) page; (void) result;
631 scroll(uzbl.gui.bar_v, argv);
635 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
636 (void) page; (void) result;
637 scroll(uzbl.gui.bar_h, argv);
642 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
643 if(uzbl.state.verbose)
644 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
646 /* update geometry var with the actual geometry
647 this is necessary as some WMs don't seem to honour
648 the above setting and we don't want to end up with
649 wrong geometry information
656 if (!uzbl.behave.show_status) {
657 gtk_widget_hide(uzbl.gui.mainbar);
659 gtk_widget_show(uzbl.gui.mainbar);
665 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
670 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
674 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
679 if (uzbl.behave.show_status) {
680 gtk_widget_hide(uzbl.gui.mainbar);
682 gtk_widget_show(uzbl.gui.mainbar);
684 uzbl.behave.show_status = !uzbl.behave.show_status;
689 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
693 //Set selected_url state variable
694 g_free(uzbl.state.selected_url);
695 uzbl.state.selected_url = NULL;
697 uzbl.state.selected_url = g_strdup(link);
703 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
706 const gchar *title = webkit_web_view_get_title(web_view);
707 if (uzbl.gui.main_title)
708 g_free (uzbl.gui.main_title);
709 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
714 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
717 uzbl.gui.sbar.load_progress = progress;
719 g_free(uzbl.gui.sbar.progress_bar);
720 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
726 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
730 if (uzbl.behave.load_finish_handler)
731 run_handler(uzbl.behave.load_finish_handler, "");
734 void clear_keycmd() {
735 g_free(uzbl.state.keycmd);
736 uzbl.state.keycmd = g_strdup("");
740 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
744 uzbl.gui.sbar.load_progress = 0;
745 clear_keycmd(); // don't need old commands to remain on new page?
746 if (uzbl.behave.load_start_handler)
747 run_handler(uzbl.behave.load_start_handler, "");
751 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
754 g_free (uzbl.state.uri);
755 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
756 uzbl.state.uri = g_string_free (newuri, FALSE);
757 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
758 set_insert_mode(uzbl.behave.always_insert_mode);
761 if (uzbl.behave.load_commit_handler)
762 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
766 destroy_cb (GtkWidget* widget, gpointer data) {
774 if (uzbl.behave.history_handler) {
776 struct tm * timeinfo;
779 timeinfo = localtime ( &rawtime );
780 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
781 run_handler(uzbl.behave.history_handler, date);
786 /* VIEW funcs (little webkit wrappers) */
787 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
789 VIEWFUNC(reload_bypass_cache)
790 VIEWFUNC(stop_loading)
797 /* -- command to callback/function map for things we cannot attach to any signals */
798 struct {char *key; CommandInfo value;} cmdlist[] =
799 { /* key function no_split */
800 { "back", {view_go_back, 0} },
801 { "forward", {view_go_forward, 0} },
802 { "scroll_vert", {scroll_vert, 0} },
803 { "scroll_horz", {scroll_horz, 0} },
804 { "scroll_begin", {scroll_begin, 0} },
805 { "scroll_end", {scroll_end, 0} },
806 { "reload", {view_reload, 0}, },
807 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
808 { "stop", {view_stop_loading, 0}, },
809 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
810 { "zoom_out", {view_zoom_out, 0}, },
811 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
812 { "uri", {load_uri, TRUE} },
813 { "js", {run_js, TRUE} },
814 { "script", {run_external_js, 0} },
815 { "toggle_status", {toggle_status_cb, 0} },
816 { "spawn", {spawn, 0} },
817 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
818 { "sh", {spawn_sh, 0} },
819 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
820 { "talk_to_socket", {talk_to_socket, 0} },
821 { "exit", {close_uzbl, 0} },
822 { "search", {search_forward_text, TRUE} },
823 { "search_reverse", {search_reverse_text, TRUE} },
824 { "dehilight", {dehilight, 0} },
825 { "toggle_insert_mode", {toggle_insert_mode, 0} },
826 { "set", {set_var, TRUE} },
827 //{ "get", {get_var, TRUE} },
828 { "bind", {act_bind, TRUE} },
829 { "dump_config", {act_dump_config, 0} },
830 { "keycmd", {keycmd, TRUE} },
831 { "keycmd_nl", {keycmd_nl, TRUE} },
832 { "keycmd_bs", {keycmd_bs, 0} },
833 { "chain", {chain, 0} },
834 { "print", {print, TRUE} },
835 { "update_gui", {update_gui, TRUE} }
842 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
844 for (i = 0; i < LENGTH(cmdlist); i++)
845 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].key, &cmdlist[i].value);
848 /* -- CORE FUNCTIONS -- */
851 free_action(gpointer act) {
852 Action *action = (Action*)act;
853 g_free(action->name);
855 g_free(action->param);
860 new_action(const gchar *name, const gchar *param) {
861 Action *action = g_new(Action, 1);
863 action->name = g_strdup(name);
865 action->param = g_strdup(param);
867 action->param = NULL;
873 file_exists (const char * filename) {
874 return (access(filename, F_OK) == 0);
878 set_var(WebKitWebView *page, GArray *argv, GString *result) {
879 (void) page; (void) result;
880 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
881 if (split[0] != NULL) {
882 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
883 set_var_value(g_strstrip(split[0]), value);
890 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
891 (void) page; (void) argv; (void) result;
897 print(WebKitWebView *page, GArray *argv, GString *result) {
898 (void) page; (void) result;
901 buf = expand(argv_idx(argv, 0), 0);
902 g_string_assign(result, buf);
907 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
908 (void) page; (void) result;
909 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
910 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
911 add_binding(g_strstrip(split[0]), value);
929 set_mode_indicator() {
930 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
931 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
936 set_mode_indicator();
941 set_insert_mode(gboolean mode) {
942 uzbl.behave.insert_mode = mode;
943 set_mode_indicator();
947 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
948 (void) page; (void) result;
950 if (argv_idx(argv, 0)) {
951 if (strcmp (argv_idx(argv, 0), "0") == 0) {
952 set_insert_mode(FALSE);
954 set_insert_mode(TRUE);
957 set_insert_mode( !uzbl.behave.insert_mode );
964 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
967 if (argv_idx(argv, 0)) {
968 GString* newuri = g_string_new (argv_idx(argv, 0));
969 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
970 run_js(web_view, argv, NULL);
973 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
974 g_string_prepend (newuri, "http://");
975 /* if we do handle cookies, ask our handler for them */
976 webkit_web_view_load_uri (web_view, newuri->str);
977 g_string_free (newuri, TRUE);
984 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
985 size_t argumentCount, const JSValueRef arguments[],
986 JSValueRef* exception) {
991 JSStringRef js_result_string;
992 GString *result = g_string_new("");
994 if (argumentCount >= 1) {
995 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
996 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
997 char ctl_line[arg_size];
998 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1000 parse_cmd_line(ctl_line, result);
1002 JSStringRelease(arg);
1004 js_result_string = JSStringCreateWithUTF8CString(result->str);
1006 g_string_free(result, TRUE);
1008 return JSValueMakeString(ctx, js_result_string);
1011 JSStaticFunction js_static_functions[] = {
1012 {"run", js_run_command, kJSPropertyAttributeNone},
1017 /* This function creates the class and its definition, only once */
1018 if (!uzbl.js.initialized) {
1019 /* it would be pretty cool to make this dynamic */
1020 uzbl.js.classdef = kJSClassDefinitionEmpty;
1021 uzbl.js.classdef.staticFunctions = js_static_functions;
1023 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1029 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1030 WebKitWebFrame *frame;
1031 JSGlobalContextRef context;
1032 JSObjectRef globalobject;
1033 JSStringRef var_name;
1035 JSStringRef js_script;
1036 JSValueRef js_result;
1037 JSStringRef js_result_string;
1038 size_t js_result_size;
1042 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1043 context = webkit_web_frame_get_global_context(frame);
1044 globalobject = JSContextGetGlobalObject(context);
1046 /* uzbl javascript namespace */
1047 var_name = JSStringCreateWithUTF8CString("Uzbl");
1048 JSObjectSetProperty(context, globalobject, var_name,
1049 JSObjectMake(context, uzbl.js.classref, NULL),
1050 kJSClassAttributeNone, NULL);
1052 /* evaluate the script and get return value*/
1053 js_script = JSStringCreateWithUTF8CString(script);
1054 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1055 if (js_result && !JSValueIsUndefined(context, js_result)) {
1056 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1057 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1059 if (js_result_size) {
1060 char js_result_utf8[js_result_size];
1061 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1062 g_string_assign(result, js_result_utf8);
1065 JSStringRelease(js_result_string);
1069 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1071 JSStringRelease(var_name);
1072 JSStringRelease(js_script);
1076 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1077 if (argv_idx(argv, 0))
1078 eval_js(web_view, argv_idx(argv, 0), result);
1082 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1084 if (argv_idx(argv, 0)) {
1085 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1090 while ((line = g_array_index(lines, gchar*, i))) {
1092 js = g_strdup (line);
1094 gchar* newjs = g_strconcat (js, line, NULL);
1101 if (uzbl.state.verbose)
1102 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1104 if (argv_idx (argv, 1)) {
1105 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1109 eval_js (web_view, js, result);
1111 g_array_free (lines, TRUE);
1116 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1117 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1118 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1119 webkit_web_view_unmark_text_matches (page);
1120 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1121 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1125 if (uzbl.state.searchtx) {
1126 if (uzbl.state.verbose)
1127 printf ("Searching: %s\n", uzbl.state.searchtx);
1128 webkit_web_view_set_highlight_text_matches (page, TRUE);
1129 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1134 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1136 search_text(page, argv, TRUE);
1140 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1142 search_text(page, argv, FALSE);
1146 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1147 (void) argv; (void) result;
1148 webkit_web_view_set_highlight_text_matches (page, FALSE);
1153 new_window_load_uri (const gchar * uri) {
1154 if (uzbl.behave.new_window) {
1155 GString *s = g_string_new ("");
1156 g_string_printf(s, "'%s'", uri);
1157 run_handler(uzbl.behave.new_window, s->str);
1160 GString* to_execute = g_string_new ("");
1161 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1163 for (i = 0; entries[i].long_name != NULL; i++) {
1164 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1165 gchar** str = (gchar**)entries[i].arg_data;
1167 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1171 if (uzbl.state.verbose)
1172 printf("\n%s\n", to_execute->str);
1173 g_spawn_command_line_async (to_execute->str, NULL);
1174 g_string_free (to_execute, TRUE);
1178 chain (WebKitWebView *page, GArray *argv, GString *result) {
1179 (void) page; (void) result;
1181 gchar **parts = NULL;
1183 while ((a = argv_idx(argv, i++))) {
1184 parts = g_strsplit (a, " ", 2);
1186 parse_command(parts[0], parts[1], result);
1192 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1196 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1202 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1206 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1212 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1217 int len = strlen(uzbl.state.keycmd);
1218 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1220 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1225 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1232 /* --Statusbar functions-- */
1234 build_progressbar_ascii(int percent) {
1235 int width=uzbl.gui.sbar.progress_w;
1238 GString *bar = g_string_new("");
1240 l = (double)percent*((double)width/100.);
1241 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1243 for(i=0; i<(int)l; i++)
1244 g_string_append(bar, uzbl.gui.sbar.progress_s);
1247 g_string_append(bar, uzbl.gui.sbar.progress_u);
1249 return g_string_free(bar, FALSE);
1251 /* --End Statusbar functions-- */
1254 sharg_append(GArray *a, const gchar *str) {
1255 const gchar *s = (str ? str : "");
1256 g_array_append_val(a, s);
1259 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1261 run_command (const gchar *command, const guint npre, const gchar **args,
1262 const gboolean sync, char **output_stdout) {
1263 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1266 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1267 gchar *pid = itos(getpid());
1268 gchar *xwin = itos(uzbl.xwin);
1270 sharg_append(a, command);
1271 for (i = 0; i < npre; i++) /* add n args before the default vars */
1272 sharg_append(a, args[i]);
1273 sharg_append(a, uzbl.state.config_file);
1274 sharg_append(a, pid);
1275 sharg_append(a, xwin);
1276 sharg_append(a, uzbl.comm.fifo_path);
1277 sharg_append(a, uzbl.comm.socket_path);
1278 sharg_append(a, uzbl.state.uri);
1279 sharg_append(a, uzbl.gui.main_title);
1281 for (i = npre; i < g_strv_length((gchar**)args); i++)
1282 sharg_append(a, args[i]);
1286 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1288 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1289 NULL, NULL, output_stdout, NULL, NULL, &err);
1290 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1291 NULL, NULL, NULL, &err);
1293 if (uzbl.state.verbose) {
1294 GString *s = g_string_new("spawned:");
1295 for (i = 0; i < (a->len); i++) {
1296 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1297 g_string_append_printf(s, " %s", qarg);
1300 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1301 printf("%s\n", s->str);
1302 g_string_free(s, TRUE);
1304 printf("Stdout: %s\n", *output_stdout);
1308 g_printerr("error on run_command: %s\n", err->message);
1313 g_array_free (a, TRUE);
1318 split_quoted(const gchar* src, const gboolean unquote) {
1319 /* split on unquoted space, return array of strings;
1320 remove a layer of quotes and backslashes if unquote */
1321 if (!src) return NULL;
1323 gboolean dq = FALSE;
1324 gboolean sq = FALSE;
1325 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1326 GString *s = g_string_new ("");
1330 for (p = src; *p != '\0'; p++) {
1331 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1332 else if (*p == '\\') { g_string_append_c(s, *p++);
1333 g_string_append_c(s, *p); }
1334 else if ((*p == '"') && unquote && !sq) dq = !dq;
1335 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1337 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1338 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1340 else if ((*p == ' ') && !dq && !sq) {
1341 dup = g_strdup(s->str);
1342 g_array_append_val(a, dup);
1343 g_string_truncate(s, 0);
1344 } else g_string_append_c(s, *p);
1346 dup = g_strdup(s->str);
1347 g_array_append_val(a, dup);
1348 ret = (gchar**)a->data;
1349 g_array_free (a, FALSE);
1350 g_string_free (s, TRUE);
1355 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1356 (void)web_view; (void)result;
1357 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1358 if (argv_idx(argv, 0))
1359 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1363 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1364 (void)web_view; (void)result;
1366 if (argv_idx(argv, 0))
1367 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1368 TRUE, &uzbl.comm.sync_stdout);
1372 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1373 (void)web_view; (void)result;
1374 if (!uzbl.behave.shell_cmd) {
1375 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1380 gchar *spacer = g_strdup("");
1381 g_array_insert_val(argv, 1, spacer);
1382 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1384 for (i = 1; i < g_strv_length(cmd); i++)
1385 g_array_prepend_val(argv, cmd[i]);
1387 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1393 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1394 (void)web_view; (void)result;
1395 if (!uzbl.behave.shell_cmd) {
1396 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1401 gchar *spacer = g_strdup("");
1402 g_array_insert_val(argv, 1, spacer);
1403 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1405 for (i = 1; i < g_strv_length(cmd); i++)
1406 g_array_prepend_val(argv, cmd[i]);
1408 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1409 TRUE, &uzbl.comm.sync_stdout);
1415 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1416 (void)web_view; (void)result;
1419 struct sockaddr_un sa;
1426 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1428 /* This function could be optimised by storing a hash table of socket paths
1429 and associated connected file descriptors rather than closing and
1430 re-opening for every call. Also we could launch a script if socket connect
1433 /* First element argv[0] is path to socket. Following elements are tokens to
1434 write to the socket. We write them as a single packet with each token
1435 separated by an ASCII nul (\0). */
1437 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1442 /* copy socket path, null terminate result */
1443 sockpath = g_array_index(argv, char*, 0);
1444 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1445 sa.sun_family = AF_UNIX;
1447 /* create socket file descriptor and connect it to path */
1448 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1450 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1453 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1454 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1459 /* build request vector */
1460 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1462 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1466 for(i = 1; i < argv->len; ++i) {
1467 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1468 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1472 ret = writev(fd, iov, argv->len - 1);
1475 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1480 /* wait for a response, with a 500ms timeout */
1482 pfd.events = POLLIN;
1484 ret = poll(&pfd, 1, 500);
1486 if(ret == 0) errno = ETIMEDOUT;
1487 if(errno == EINTR) continue;
1488 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1494 /* get length of response */
1495 if(ioctl(fd, FIONREAD, &len) == -1) {
1496 g_printerr("talk_to_socket: cannot find daemon response length, "
1497 "ioctl failed (%s)\n", strerror(errno));
1502 /* if there is a response, read it */
1504 uzbl.comm.sync_stdout = g_malloc(len + 1);
1505 if(!uzbl.comm.sync_stdout) {
1506 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1510 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1512 ret = read(fd, uzbl.comm.sync_stdout, len);
1514 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1527 parse_command(const char *cmd, const char *param, GString *result) {
1530 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1532 gchar **par = split_quoted(param, TRUE);
1533 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1535 if (c->no_split) { /* don't split */
1536 sharg_append(a, param);
1538 for (i = 0; i < g_strv_length(par); i++)
1539 sharg_append(a, par[i]);
1542 if (result == NULL) {
1543 GString *result_print = g_string_new("");
1545 c->function(uzbl.gui.web_view, a, result_print);
1546 if (result_print->len)
1547 printf("%*s\n", result_print->len, result_print->str);
1549 g_string_free(result_print, TRUE);
1551 c->function(uzbl.gui.web_view, a, result);
1554 g_array_free (a, TRUE);
1557 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1564 if(*uzbl.net.proxy_url == ' '
1565 || uzbl.net.proxy_url == NULL) {
1566 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1567 (GType) SOUP_SESSION_PROXY_URI);
1570 suri = soup_uri_new(uzbl.net.proxy_url);
1571 g_object_set(G_OBJECT(uzbl.net.soup_session),
1572 SOUP_SESSION_PROXY_URI,
1574 soup_uri_free(suri);
1581 if(file_exists(uzbl.gui.icon)) {
1582 if (uzbl.gui.main_window)
1583 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1585 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1591 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1592 g_array_append_val (a, uzbl.state.uri);
1593 load_uri(uzbl.gui.web_view, a, NULL);
1594 g_array_free (a, TRUE);
1598 cmd_always_insert_mode() {
1599 set_insert_mode(uzbl.behave.always_insert_mode);
1605 g_object_set(G_OBJECT(uzbl.net.soup_session),
1606 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1610 cmd_max_conns_host() {
1611 g_object_set(G_OBJECT(uzbl.net.soup_session),
1612 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1617 soup_session_remove_feature
1618 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1619 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1620 /*g_free(uzbl.net.soup_logger);*/
1622 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1623 soup_session_add_feature(uzbl.net.soup_session,
1624 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1629 return webkit_web_view_get_settings(uzbl.gui.web_view);
1634 WebKitWebSettings *ws = view_settings();
1635 if (uzbl.behave.font_size > 0) {
1636 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1639 if (uzbl.behave.monospace_size > 0) {
1640 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1641 uzbl.behave.monospace_size, NULL);
1643 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1644 uzbl.behave.font_size, NULL);
1649 cmd_default_font_family() {
1650 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1651 uzbl.behave.default_font_family, NULL);
1655 cmd_monospace_font_family() {
1656 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1657 uzbl.behave.monospace_font_family, NULL);
1661 cmd_sans_serif_font_family() {
1662 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1663 uzbl.behave.sans_serif_font_family, NULL);
1667 cmd_serif_font_family() {
1668 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1669 uzbl.behave.serif_font_family, NULL);
1673 cmd_cursive_font_family() {
1674 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1675 uzbl.behave.cursive_font_family, NULL);
1679 cmd_fantasy_font_family() {
1680 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1681 uzbl.behave.fantasy_font_family, NULL);
1686 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1690 cmd_disable_plugins() {
1691 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1692 !uzbl.behave.disable_plugins, NULL);
1696 cmd_disable_scripts() {
1697 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1698 !uzbl.behave.disable_scripts, NULL);
1702 cmd_minimum_font_size() {
1703 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1704 uzbl.behave.minimum_font_size, NULL);
1707 cmd_autoload_img() {
1708 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1709 uzbl.behave.autoload_img, NULL);
1714 cmd_autoshrink_img() {
1715 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1716 uzbl.behave.autoshrink_img, NULL);
1721 cmd_enable_spellcheck() {
1722 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1723 uzbl.behave.enable_spellcheck, NULL);
1727 cmd_enable_private() {
1728 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1729 uzbl.behave.enable_private, NULL);
1734 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1735 uzbl.behave.print_bg, NULL);
1740 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1741 uzbl.behave.style_uri, NULL);
1745 cmd_resizable_txt() {
1746 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1747 uzbl.behave.resizable_txt, NULL);
1751 cmd_default_encoding() {
1752 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1753 uzbl.behave.default_encoding, NULL);
1757 cmd_enforce_96dpi() {
1758 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1759 uzbl.behave.enforce_96dpi, NULL);
1763 cmd_caret_browsing() {
1764 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1765 uzbl.behave.caret_browsing, NULL);
1769 cmd_cookie_handler() {
1770 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1771 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1772 if ((g_strcmp0(split[0], "sh") == 0) ||
1773 (g_strcmp0(split[0], "spawn") == 0)) {
1774 g_free (uzbl.behave.cookie_handler);
1775 uzbl.behave.cookie_handler =
1776 g_strdup_printf("sync_%s %s", split[0], split[1]);
1783 gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
1784 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1785 if ((g_strcmp0(split[0], "sh") == 0) ||
1786 (g_strcmp0(split[0], "spawn") == 0)) {
1787 g_free (uzbl.behave.new_window);
1788 uzbl.behave.new_window =
1789 g_strdup_printf("%s %s", split[0], split[1]);
1796 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1801 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1806 if(uzbl.behave.inject_html) {
1807 webkit_web_view_load_html_string (uzbl.gui.web_view,
1808 uzbl.behave.inject_html, NULL);
1817 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1818 uzbl.behave.modmask = 0;
1820 if(uzbl.behave.modkey)
1821 g_free(uzbl.behave.modkey);
1822 uzbl.behave.modkey = buf;
1824 for (i = 0; modkeys[i].key != NULL; i++) {
1825 if (g_strrstr(buf, modkeys[i].key))
1826 uzbl.behave.modmask |= modkeys[i].mask;
1832 if (*uzbl.net.useragent == ' ') {
1833 g_free (uzbl.net.useragent);
1834 uzbl.net.useragent = NULL;
1836 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1837 uzbl.net.useragent, NULL);
1843 if (!uzbl.gui.scrolled_win &&
1847 gtk_widget_ref(uzbl.gui.scrolled_win);
1848 gtk_widget_ref(uzbl.gui.mainbar);
1849 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1850 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1852 if(uzbl.behave.status_top) {
1853 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1854 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1857 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1858 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1860 gtk_widget_unref(uzbl.gui.scrolled_win);
1861 gtk_widget_unref(uzbl.gui.mainbar);
1862 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1867 set_var_value(gchar *name, gchar *val) {
1868 uzbl_cmdprop *c = NULL;
1871 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1873 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1874 if(!c->writeable) return FALSE;
1876 /* check for the variable type */
1877 if (c->type == TYPE_STR) {
1878 buf = expand(val, 0);
1881 } else if(c->type == TYPE_INT) {
1882 int *ip = (int *)c->ptr;
1883 buf = expand(val, 0);
1884 *ip = (int)strtoul(buf, &endp, 10);
1886 } else if (c->type == TYPE_FLOAT) {
1887 float *fp = (float *)c->ptr;
1888 buf = expand(val, 0);
1889 *fp = strtod(buf, &endp);
1893 /* invoke a command specific function */
1894 if(c->func) c->func();
1896 /* check wether name violates our naming scheme */
1897 if(strpbrk(name, invalid_chars)) {
1898 if (uzbl.state.verbose)
1899 printf("Invalid variable name\n");
1904 c = malloc(sizeof(uzbl_cmdprop));
1909 buf = expand(val, 0);
1910 c->ptr = malloc(sizeof(char *));
1912 g_hash_table_insert(uzbl.comm.proto_var,
1913 g_strdup(name), (gpointer) c);
1920 Behaviour *b = &uzbl.behave;
1922 if(b->html_buffer->str) {
1923 webkit_web_view_load_html_string (uzbl.gui.web_view,
1924 b->html_buffer->str, b->base_url);
1925 g_string_free(b->html_buffer, TRUE);
1926 b->html_buffer = g_string_new("");
1930 enum {M_CMD, M_HTML};
1932 parse_cmd_line(const char *ctl_line, GString *result) {
1933 Behaviour *b = &uzbl.behave;
1936 if(b->mode == M_HTML) {
1937 len = strlen(b->html_endmarker);
1938 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1939 if(len == strlen(ctl_line)-1 &&
1940 !strncmp(b->html_endmarker, ctl_line, len)) {
1942 set_var_value("mode", "0");
1947 set_timeout(b->html_timeout);
1948 g_string_append(b->html_buffer, ctl_line);
1951 else if((ctl_line[0] == '#') /* Comments */
1952 || (ctl_line[0] == ' ')
1953 || (ctl_line[0] == '\n'))
1954 ; /* ignore these lines */
1955 else { /* parse a command */
1957 gchar **tokens = NULL;
1958 len = strlen(ctl_line);
1960 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1961 ctlstrip = g_strndup(ctl_line, len - 1);
1962 else ctlstrip = g_strdup(ctl_line);
1964 tokens = g_strsplit(ctlstrip, " ", 2);
1965 parse_command(tokens[0], tokens[1], result);
1972 build_stream_name(int type, const gchar* dir) {
1973 State *s = &uzbl.state;
1977 str = g_strdup_printf
1978 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1979 } else if (type == SOCKET) {
1980 str = g_strdup_printf
1981 ("%s/uzbl_socket_%s", dir, s->instance_name);
1987 control_fifo(GIOChannel *gio, GIOCondition condition) {
1988 if (uzbl.state.verbose)
1989 printf("triggered\n");
1994 if (condition & G_IO_HUP)
1995 g_error ("Fifo: Read end of pipe died!\n");
1998 g_error ("Fifo: GIOChannel broke\n");
2000 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2001 if (ret == G_IO_STATUS_ERROR) {
2002 g_error ("Fifo: Error reading: %s\n", err->message);
2006 parse_cmd_line(ctl_line, NULL);
2013 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2014 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2015 if (unlink(uzbl.comm.fifo_path) == -1)
2016 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2017 g_free(uzbl.comm.fifo_path);
2018 uzbl.comm.fifo_path = NULL;
2021 GIOChannel *chan = NULL;
2022 GError *error = NULL;
2023 gchar *path = build_stream_name(FIFO, dir);
2025 if (!file_exists(path)) {
2026 if (mkfifo (path, 0666) == 0) {
2027 // 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.
2028 chan = g_io_channel_new_file(path, "r+", &error);
2030 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2031 if (uzbl.state.verbose)
2032 printf ("init_fifo: created successfully as %s\n", path);
2033 uzbl.comm.fifo_path = path;
2035 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2036 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2037 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2038 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2040 /* if we got this far, there was an error; cleanup */
2041 if (error) g_error_free (error);
2048 control_stdin(GIOChannel *gio, GIOCondition condition) {
2050 gchar *ctl_line = NULL;
2053 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2054 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2057 parse_cmd_line(ctl_line, NULL);
2065 GIOChannel *chan = NULL;
2066 GError *error = NULL;
2068 chan = g_io_channel_unix_new(fileno(stdin));
2070 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2071 g_error ("Stdin: could not add watch\n");
2073 if (uzbl.state.verbose)
2074 printf ("Stdin: watch added successfully\n");
2077 g_error ("Stdin: Error while opening: %s\n", error->message);
2079 if (error) g_error_free (error);
2083 control_socket(GIOChannel *chan) {
2084 struct sockaddr_un remote;
2085 unsigned int t = sizeof(remote);
2087 GIOChannel *clientchan;
2089 clientsock = accept (g_io_channel_unix_get_fd(chan),
2090 (struct sockaddr *) &remote, &t);
2092 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2093 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2094 (GIOFunc) control_client_socket, clientchan);
2101 control_client_socket(GIOChannel *clientchan) {
2103 GString *result = g_string_new("");
2104 GError *error = NULL;
2108 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2109 if (ret == G_IO_STATUS_ERROR) {
2110 g_warning ("Error reading: %s\n", error->message);
2111 g_io_channel_shutdown(clientchan, TRUE, &error);
2113 } else if (ret == G_IO_STATUS_EOF) {
2114 /* shutdown and remove channel watch from main loop */
2115 g_io_channel_shutdown(clientchan, TRUE, &error);
2120 parse_cmd_line (ctl_line, result);
2121 g_string_append_c(result, '\n');
2122 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2124 if (ret == G_IO_STATUS_ERROR) {
2125 g_warning ("Error writing: %s", error->message);
2127 g_io_channel_flush(clientchan, &error);
2130 if (error) g_error_free (error);
2131 g_string_free(result, TRUE);
2137 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2138 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2139 if (unlink(uzbl.comm.socket_path) == -1)
2140 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2141 g_free(uzbl.comm.socket_path);
2142 uzbl.comm.socket_path = NULL;
2150 GIOChannel *chan = NULL;
2152 struct sockaddr_un local;
2153 gchar *path = build_stream_name(SOCKET, dir);
2155 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2157 local.sun_family = AF_UNIX;
2158 strcpy (local.sun_path, path);
2159 unlink (local.sun_path);
2161 len = strlen (local.sun_path) + sizeof (local.sun_family);
2162 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2163 if (uzbl.state.verbose)
2164 printf ("init_socket: opened in %s\n", path);
2167 if( (chan = g_io_channel_unix_new(sock)) ) {
2168 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2169 uzbl.comm.socket_path = path;
2172 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2174 /* if we got this far, there was an error; cleanup */
2181 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2182 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2184 // this function may be called very early when the templates are not set (yet), hence the checks
2186 update_title (void) {
2187 Behaviour *b = &uzbl.behave;
2190 if (b->show_status) {
2191 if (b->title_format_short) {
2192 parsed = expand(b->title_format_short, 0);
2193 if (uzbl.gui.main_window)
2194 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2197 if (b->status_format) {
2198 parsed = expand(b->status_format, 0);
2199 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2202 if (b->status_background) {
2204 gdk_color_parse (b->status_background, &color);
2205 //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)
2206 if (uzbl.gui.main_window)
2207 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2208 else if (uzbl.gui.plug)
2209 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2212 if (b->title_format_long) {
2213 parsed = expand(b->title_format_long, 0);
2214 if (uzbl.gui.main_window)
2215 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2222 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2226 retrieve_geometry();
2231 key_press_cb (GtkWidget* window, GdkEventKey* event)
2233 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2237 if (event->type != GDK_KEY_PRESS ||
2238 event->keyval == GDK_Page_Up ||
2239 event->keyval == GDK_Page_Down ||
2240 event->keyval == GDK_Up ||
2241 event->keyval == GDK_Down ||
2242 event->keyval == GDK_Left ||
2243 event->keyval == GDK_Right ||
2244 event->keyval == GDK_Shift_L ||
2245 event->keyval == GDK_Shift_R)
2248 /* turn off insert mode (if always_insert_mode is not used) */
2249 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2250 set_insert_mode(uzbl.behave.always_insert_mode);
2255 if (uzbl.behave.insert_mode &&
2256 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2257 (!uzbl.behave.modmask)
2262 if (event->keyval == GDK_Escape) {
2265 dehilight(uzbl.gui.web_view, NULL, NULL);
2269 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2270 if (event->keyval == GDK_Insert) {
2272 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2273 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2275 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2278 GString* keycmd = g_string_new(uzbl.state.keycmd);
2279 g_string_append (keycmd, str);
2280 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2287 if (event->keyval == GDK_BackSpace)
2288 keycmd_bs(NULL, NULL, NULL);
2290 gboolean key_ret = FALSE;
2291 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2294 GString* keycmd = g_string_new(uzbl.state.keycmd);
2295 g_string_append(keycmd, event->string);
2296 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2299 run_keycmd(key_ret);
2301 if (key_ret) return (!uzbl.behave.insert_mode);
2306 run_keycmd(const gboolean key_ret) {
2307 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2309 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2311 parse_command(act->name, act->param, NULL);
2315 /* try if it's an incremental keycmd or one that takes args, and run it */
2316 GString* short_keys = g_string_new ("");
2317 GString* short_keys_inc = g_string_new ("");
2319 guint len = strlen(uzbl.state.keycmd);
2320 for (i=0; i<len; i++) {
2321 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2322 g_string_assign(short_keys_inc, short_keys->str);
2323 g_string_append_c(short_keys, '_');
2324 g_string_append_c(short_keys_inc, '*');
2326 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2327 /* run normal cmds only if return was pressed */
2328 exec_paramcmd(act, i);
2331 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2332 if (key_ret) /* just quit the incremental command on return */
2334 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2338 g_string_truncate(short_keys, short_keys->len - 1);
2340 g_string_free (short_keys, TRUE);
2341 g_string_free (short_keys_inc, TRUE);
2345 exec_paramcmd(const Action *act, const guint i) {
2346 GString *parampart = g_string_new (uzbl.state.keycmd);
2347 GString *actionname = g_string_new ("");
2348 GString *actionparam = g_string_new ("");
2349 g_string_erase (parampart, 0, i+1);
2351 g_string_printf (actionname, act->name, parampart->str);
2353 g_string_printf (actionparam, act->param, parampart->str);
2354 parse_command(actionname->str, actionparam->str, NULL);
2355 g_string_free(actionname, TRUE);
2356 g_string_free(actionparam, TRUE);
2357 g_string_free(parampart, TRUE);
2365 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2367 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2368 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2369 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2370 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2371 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2372 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2373 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2384 g->mainbar = gtk_hbox_new (FALSE, 0);
2386 /* keep a reference to the bar so we can re-pack it at runtime*/
2387 //sbar_ref = g_object_ref(g->mainbar);
2389 g->mainbar_label = gtk_label_new ("");
2390 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2391 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2392 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2393 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2394 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2395 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2401 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2402 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2403 gtk_widget_set_name (window, "Uzbl browser");
2404 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2405 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2406 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2413 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2414 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2415 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2422 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2424 If actname is one that calls an external command, this function will inject
2425 newargs in front of the user-provided args in that command line. They will
2426 come become after the body of the script (in sh) or after the name of
2427 the command to execute (in spawn).
2428 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2429 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2431 The return value consist of two strings: the action (sh, ...) and its args.
2433 If act is not one that calls an external command, then the given action merely
2436 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2437 /* Arrr! Here be memory leaks */
2438 gchar *actdup = g_strdup(actname);
2439 g_array_append_val(rets, actdup);
2441 if ((g_strcmp0(actname, "spawn") == 0) ||
2442 (g_strcmp0(actname, "sh") == 0) ||
2443 (g_strcmp0(actname, "sync_spawn") == 0) ||
2444 (g_strcmp0(actname, "sync_sh") == 0) ||
2445 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2447 GString *a = g_string_new("");
2448 gchar **spawnparts = split_quoted(origargs, FALSE);
2449 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2450 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2452 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2453 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2455 g_array_append_val(rets, a->str);
2456 g_string_free(a, FALSE);
2457 g_strfreev(spawnparts);
2459 gchar *origdup = g_strdup(origargs);
2460 g_array_append_val(rets, origdup);
2462 return (gchar**)g_array_free(rets, FALSE);
2466 run_handler (const gchar *act, const gchar *args) {
2467 /* Consider this code a temporary hack to make the handlers usable.
2468 In practice, all this splicing, injection, and reconstruction is
2469 inefficient, annoying and hard to manage. Potential pitfalls arise
2470 when the handler specific args 1) are not quoted (the handler
2471 callbacks should take care of this) 2) are quoted but interfere
2472 with the users' own quotation. A more ideal solution is
2473 to refactor parse_command so that it doesn't just take a string
2474 and execute it; rather than that, we should have a function which
2475 returns the argument vector parsed from the string. This vector
2476 could be modified (e.g. insert additional args into it) before
2477 passing it to the next function that actually executes it. Though
2478 it still isn't perfect for chain actions.. will reconsider & re-
2479 factor when I have the time. -duc */
2481 char **parts = g_strsplit(act, " ", 2);
2483 if (g_strcmp0(parts[0], "chain") == 0) {
2484 GString *newargs = g_string_new("");
2485 gchar **chainparts = split_quoted(parts[1], FALSE);
2487 /* for every argument in the chain, inject the handler args
2488 and make sure the new parts are wrapped in quotes */
2489 gchar **cp = chainparts;
2491 gchar *quotless = NULL;
2492 gchar **spliced_quotless = NULL; // sigh -_-;
2493 gchar **inpart = NULL;
2496 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2498 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2499 } else quotless = g_strdup(*cp);
2501 spliced_quotless = g_strsplit(quotless, " ", 2);
2502 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2503 g_strfreev(spliced_quotless);
2505 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2511 parse_command(parts[0], &(newargs->str[1]), NULL);
2512 g_string_free(newargs, TRUE);
2513 g_strfreev(chainparts);
2516 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2517 parse_command(inparts[0], inparts[1], NULL);
2525 add_binding (const gchar *key, const gchar *act) {
2526 char **parts = g_strsplit(act, " ", 2);
2533 if (uzbl.state.verbose)
2534 printf ("Binding %-10s : %s\n", key, act);
2535 action = new_action(parts[0], parts[1]);
2537 if (g_hash_table_remove (uzbl.bindings, key))
2538 g_warning ("Overwriting existing binding for \"%s\"", key);
2539 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2544 get_xdg_var (XDG_Var xdg) {
2545 const gchar* actual_value = getenv (xdg.environmental);
2546 const gchar* home = getenv ("HOME");
2547 gchar* return_value;
2549 if (! actual_value || strcmp (actual_value, "") == 0) {
2550 if (xdg.default_value) {
2551 return_value = str_replace ("~", home, xdg.default_value);
2553 return_value = NULL;
2556 return_value = str_replace("~", home, actual_value);
2559 return return_value;
2563 find_xdg_file (int xdg_type, char* filename) {
2564 /* xdg_type = 0 => config
2565 xdg_type = 1 => data
2566 xdg_type = 2 => cache*/
2568 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2569 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2572 gchar* temporary_string;
2576 if (! file_exists (temporary_file) && xdg_type != 2) {
2577 buf = get_xdg_var (XDG[3 + xdg_type]);
2578 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2581 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2582 g_free (temporary_file);
2583 temporary_file = g_strconcat (temporary_string, filename, NULL);
2587 //g_free (temporary_string); - segfaults.
2589 if (file_exists (temporary_file)) {
2590 return temporary_file;
2597 State *s = &uzbl.state;
2598 Network *n = &uzbl.net;
2600 for (i = 0; default_config[i].command != NULL; i++) {
2601 parse_cmd_line(default_config[i].command, NULL);
2604 if (g_strcmp0(s->config_file, "-") == 0) {
2605 s->config_file = NULL;
2609 else if (!s->config_file) {
2610 s->config_file = find_xdg_file (0, "/uzbl/config");
2613 if (s->config_file) {
2614 GArray* lines = read_file_by_line (s->config_file);
2618 while ((line = g_array_index(lines, gchar*, i))) {
2619 parse_cmd_line (line, NULL);
2623 g_array_free (lines, TRUE);
2625 if (uzbl.state.verbose)
2626 printf ("No configuration file loaded.\n");
2629 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2632 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2635 if (!uzbl.behave.cookie_handler)
2638 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2639 GString *s = g_string_new ("");
2640 SoupURI * soup_uri = soup_message_get_uri(msg);
2641 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2642 run_handler(uzbl.behave.cookie_handler, s->str);
2644 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2645 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2646 if ( p != NULL ) *p = '\0';
2647 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2649 if (uzbl.comm.sync_stdout)
2650 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2652 g_string_free(s, TRUE);
2656 save_cookies (SoupMessage *msg, gpointer user_data){
2660 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2661 cookie = soup_cookie_to_set_cookie_header(ck->data);
2662 SoupURI * soup_uri = soup_message_get_uri(msg);
2663 GString *s = g_string_new ("");
2664 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2665 run_handler(uzbl.behave.cookie_handler, s->str);
2667 g_string_free(s, TRUE);
2672 /* --- WEBINSPECTOR --- */
2674 hide_window_cb(GtkWidget *widget, gpointer data) {
2677 gtk_widget_hide(widget);
2681 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2684 (void) web_inspector;
2685 GtkWidget* scrolled_window;
2686 GtkWidget* new_web_view;
2689 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2690 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2691 G_CALLBACK(hide_window_cb), NULL);
2693 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2694 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2695 gtk_widget_show(g->inspector_window);
2697 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2698 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2699 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2700 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2701 gtk_widget_show(scrolled_window);
2703 new_web_view = webkit_web_view_new();
2704 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2706 return WEBKIT_WEB_VIEW(new_web_view);
2710 inspector_show_window_cb (WebKitWebInspector* inspector){
2712 gtk_widget_show(uzbl.gui.inspector_window);
2716 /* TODO: Add variables and code to make use of these functions */
2718 inspector_close_window_cb (WebKitWebInspector* inspector){
2724 inspector_attach_window_cb (WebKitWebInspector* inspector){
2730 inspector_detach_window_cb (WebKitWebInspector* inspector){
2736 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2742 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2748 set_up_inspector() {
2750 WebKitWebSettings *settings = view_settings();
2751 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2753 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2754 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2755 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2756 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2757 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2758 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2759 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2761 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2765 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2767 uzbl_cmdprop *c = v;
2772 if(c->type == TYPE_STR)
2773 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2774 else if(c->type == TYPE_INT)
2775 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2776 else if(c->type == TYPE_FLOAT)
2777 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2781 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2785 printf("bind %s = %s %s\n", (char *)k ,
2786 (char *)a->name, a->param?(char *)a->param:"");
2791 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2792 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2796 retrieve_geometry() {
2798 GString *buf = g_string_new("");
2800 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2801 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2803 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2805 if(uzbl.gui.geometry)
2806 g_free(uzbl.gui.geometry);
2807 uzbl.gui.geometry = g_string_free(buf, FALSE);
2810 /* set up gtk, gobject, variable defaults and other things that tests and other
2811 * external applications need to do anyhow */
2813 initialize(int argc, char *argv[]) {
2814 if (!g_thread_supported ())
2815 g_thread_init (NULL);
2816 uzbl.state.executable_path = g_strdup(argv[0]);
2817 uzbl.state.selected_url = NULL;
2818 uzbl.state.searchtx = NULL;
2820 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2821 g_option_context_add_main_entries (context, entries, NULL);
2822 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2823 g_option_context_parse (context, &argc, &argv, NULL);
2824 g_option_context_free(context);
2826 if (uzbl.behave.print_version) {
2827 printf("Commit: %s\n", COMMIT);
2831 /* initialize hash table */
2832 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2834 uzbl.net.soup_session = webkit_get_default_session();
2835 uzbl.state.keycmd = g_strdup("");
2837 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2838 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2839 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2840 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2841 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2842 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2844 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2845 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2846 uzbl.gui.sbar.progress_w = 10;
2848 /* HTML mode defaults*/
2849 uzbl.behave.html_buffer = g_string_new("");
2850 uzbl.behave.html_endmarker = g_strdup(".");
2851 uzbl.behave.html_timeout = 60;
2852 uzbl.behave.base_url = g_strdup("http://invalid");
2854 /* default mode indicators */
2855 uzbl.behave.insert_indicator = g_strdup("I");
2856 uzbl.behave.cmd_indicator = g_strdup("C");
2858 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2859 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2860 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2861 uzbl.info.arch = ARCH;
2862 uzbl.info.commit = COMMIT;
2865 make_var_to_name_hash();
2870 #ifndef UZBL_LIBRARY
2873 main (int argc, char* argv[]) {
2874 initialize(argc, argv);
2876 gtk_init (&argc, &argv);
2878 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2879 //main_window_ref = g_object_ref(scrolled_window);
2880 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2881 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2883 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2884 GTK_WIDGET (uzbl.gui.web_view));
2886 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2890 /* initial packing */
2891 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2892 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2894 if (uzbl.state.socket_id) {
2895 uzbl.gui.plug = create_plug ();
2896 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2897 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2899 uzbl.gui.main_window = create_window ();
2900 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2901 gtk_widget_show_all (uzbl.gui.main_window);
2902 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2905 if(!uzbl.state.instance_name)
2906 uzbl.state.instance_name = itos((int)uzbl.xwin);
2908 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2910 if (uzbl.state.verbose) {
2911 printf("Uzbl start location: %s\n", argv[0]);
2912 if (uzbl.state.socket_id)
2913 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2915 printf("window_id %i\n",(int) uzbl.xwin);
2916 printf("pid %i\n", getpid ());
2917 printf("name: %s\n", uzbl.state.instance_name);
2920 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2921 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2922 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2923 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2924 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2926 if(uzbl.gui.geometry)
2929 retrieve_geometry();
2931 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2932 if (argc > 1 && !uzbl.state.uri)
2933 uri_override = g_strdup(argv[1]);
2934 gboolean verbose_override = uzbl.state.verbose;
2937 set_insert_mode(FALSE);
2939 if (!uzbl.behave.show_status)
2940 gtk_widget_hide(uzbl.gui.mainbar);
2947 if (verbose_override > uzbl.state.verbose)
2948 uzbl.state.verbose = verbose_override;
2951 set_var_value("uri", uri_override);
2952 g_free(uri_override);
2953 } else if (uzbl.state.uri)
2959 return EXIT_SUCCESS;
2963 /* vi: set et ts=4: */