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])
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
45 #include <webkit/webkit.h>
46 #include <libsoup/soup.h>
47 #include <JavaScriptCore/JavaScript.h>
59 #include <sys/ioctl.h>
66 /* commandline arguments (set initial values for the state variables) */
68 GOptionEntry entries[] =
70 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
71 "Uri to load at startup (equivalent to 'uzbl <uri>' or 'set uri = URI' after uzbl has launched)", "URI" },
72 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
73 "Whether to print all messages or just errors.", NULL },
74 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
75 "Name of the current instance (defaults to Xorg window id)", "NAME" },
76 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
77 "Path to config file or '-' for stdin", "FILE" },
78 { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
79 "Socket ID", "SOCKET" },
80 { "geometry", 'g', 0, G_OPTION_ARG_STRING, &uzbl.gui.geometry,
81 "Set window geometry (format: WIDTHxHEIGHT+-X+-Y)", "GEOMETRY" },
82 { "version", 'V', 0, G_OPTION_ARG_NONE, &uzbl.behave.print_version,
83 "Print the version and exit", NULL },
84 { NULL, 0, 0, 0, NULL, NULL, NULL }
87 enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT};
89 /* associate command names to their properties */
99 /*@null@*/ void (*func)(void);
102 /* abbreviations to help keep the table's width humane */
103 #define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
104 #define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
105 #define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun }
106 #define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun }
107 #define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun }
108 #define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun }
110 const struct var_name_to_ptr_t {
113 } var_name_to_ptr[] = {
114 /* variable name pointer to variable in code dump callback function */
115 /* ---------------------------------------------------------------------------------------------- */
116 { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)},
117 { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)},
118 { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)},
119 { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)},
120 { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)},
121 { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)},
122 { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)},
123 { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, update_title)},
124 { "status_pbar_done", PTR_V_STR(uzbl.gui.sbar.progress_s, 1, update_title)},
125 { "status_pbar_pending", PTR_V_STR(uzbl.gui.sbar.progress_u, 1, update_title)},
126 { "status_pbar_width", PTR_V_INT(uzbl.gui.sbar.progress_w, 1, update_title)},
127 { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, update_title)},
128 { "insert_indicator", PTR_V_STR(uzbl.behave.insert_indicator, 1, update_indicator)},
129 { "command_indicator", PTR_V_STR(uzbl.behave.cmd_indicator, 1, update_indicator)},
130 { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, update_title)},
131 { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, update_title)},
132 { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
133 { "insert_mode", PTR_V_INT(uzbl.behave.insert_mode, 1, set_mode_indicator)},
134 { "always_insert_mode", PTR_V_INT(uzbl.behave.always_insert_mode, 1, cmd_always_insert_mode)},
135 { "reset_command_mode", PTR_V_INT(uzbl.behave.reset_command_mode, 1, NULL)},
136 { "modkey", PTR_V_STR(uzbl.behave.modkey, 1, cmd_modkey)},
137 { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)},
138 { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)},
139 { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)},
140 { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
141 { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)},
142 { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)},
143 { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, cmd_scheme_handler)},
144 { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
145 { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
146 { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
147 { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
148 { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
149 { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
150 { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
151 { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
153 /* exported WebKitWebSettings properties */
154 { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
155 { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
156 { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
157 { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
158 { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
159 { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
160 { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
161 { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
162 { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
163 { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
164 { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
165 { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
166 { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
167 { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
168 { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
169 { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
170 { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
171 { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
172 { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
173 { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
174 { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
175 { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
177 /* constants (not dumpable or writeable) */
178 { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
179 { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
180 { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
181 { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
182 { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
183 { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)},
184 { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)},
185 { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
186 { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
187 { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)},
188 { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
190 { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
195 /*@null@*/ char *key;
198 { "SHIFT", GDK_SHIFT_MASK }, // shift
199 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
200 { "CONTROL", GDK_CONTROL_MASK }, // control
201 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
202 { "MOD2", GDK_MOD2_MASK }, // 5th mod
203 { "MOD3", GDK_MOD3_MASK }, // 6th mod
204 { "MOD4", GDK_MOD4_MASK }, // 7th mod
205 { "MOD5", GDK_MOD5_MASK }, // 8th mod
206 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
207 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
208 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
209 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
210 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
211 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
212 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
213 { "META", GDK_META_MASK }, // meta (since 2.10)
218 /* construct a hash from the var_name_to_ptr array for quick access */
220 make_var_to_name_hash() {
221 const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
222 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
224 g_hash_table_insert(uzbl.comm.proto_var,
225 (gpointer) n2v_p->name,
226 (gpointer) &n2v_p->cp);
231 /* --- UTILITY FUNCTIONS --- */
232 enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
234 get_exp_type(const gchar *s) {
238 else if(*(s+1) == '{')
239 return EXP_BRACED_VAR;
240 else if(*(s+1) == '<')
242 else if(*(s+1) == '[')
245 return EXP_SIMPLE_VAR;
252 * recurse == 1: don't expand '@(command)@'
253 * recurse == 2: don't expand '@<java script>@'
256 expand(const char *s, guint recurse) {
259 char *end_simple_var = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
263 gchar *cmd_stdout = NULL;
265 GString *buf = g_string_new("");
266 GString *js_ret = g_string_new("");
271 g_string_append_c(buf, *++s);
276 etype = get_exp_type(s);
281 vend = strpbrk(s, end_simple_var);
282 if(!vend) vend = strchr(s, '\0');
286 vend = strchr(s, '}');
287 if(!vend) vend = strchr(s, '\0');
291 vend = strstr(s, ")@");
292 if(!vend) vend = strchr(s, '\0');
296 vend = strstr(s, ">@");
297 if(!vend) vend = strchr(s, '\0');
301 vend = strstr(s, "]@");
302 if(!vend) vend = strchr(s, '\0');
310 ret = g_strndup(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.s != NULL) {
316 g_string_append(buf, (gchar *)*c->ptr.s);
318 else if(c->type == TYPE_INT) {
319 g_string_append_printf(buf, "%d", *c->ptr.i);
321 else if(c->type == TYPE_FLOAT) {
322 g_string_append_printf(buf, "%f", *c->ptr.f);
326 if(etype == EXP_SIMPLE_VAR)
331 else if(recurse != 1 &&
333 mycmd = expand(ret, 1);
334 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
338 g_printerr("error on running command: %s\n", err->message);
341 else if (*cmd_stdout) {
342 size_t len = strlen(cmd_stdout);
344 if(len > 0 && cmd_stdout[len-1] == '\n')
345 cmd_stdout[--len] = '\0'; /* strip trailing newline */
347 g_string_append(buf, cmd_stdout);
352 else if(recurse != 2 &&
354 mycmd = expand(ret, 2);
355 eval_js(uzbl.gui.web_view, mycmd, js_ret);
359 g_string_append(buf, js_ret->str);
360 g_string_free(js_ret, TRUE);
361 js_ret = g_string_new("");
365 else if(etype == EXP_ESCAPE) {
366 mycmd = expand(ret, 0);
367 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
369 g_string_append(buf, escaped);
381 g_string_append_c(buf, *s);
386 g_string_free(js_ret, TRUE);
387 return g_string_free(buf, FALSE);
394 snprintf(tmp, sizeof(tmp), "%i", val);
395 return g_strdup(tmp);
399 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
402 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
405 str_replace (const char* search, const char* replace, const char* string) {
409 buf = g_strsplit (string, search, -1);
410 ret = g_strjoinv (replace, buf);
411 g_strfreev(buf); // somebody said this segfaults
417 read_file_by_line (const gchar *path) {
418 GIOChannel *chan = NULL;
419 gchar *readbuf = NULL;
421 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
424 chan = g_io_channel_new_file(path, "r", NULL);
427 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
428 const gchar* val = g_strdup (readbuf);
429 g_array_append_val (lines, val);
434 g_io_channel_unref (chan);
436 fprintf(stderr, "File '%s' not be read.\n", path);
443 parseenv (char* string) {
444 extern char** environ;
445 gchar* tmpstr = NULL;
449 while (environ[i] != NULL) {
450 gchar** env = g_strsplit (environ[i], "=", 2);
451 gchar* envname = g_strconcat ("$", env[0], NULL);
453 if (g_strrstr (string, envname) != NULL) {
454 tmpstr = g_strdup(string);
456 string = str_replace(envname, env[1], tmpstr);
461 g_strfreev (env); // somebody said this breaks uzbl
469 setup_signal(int signr, sigfunc *shandler) {
470 struct sigaction nh, oh;
472 nh.sa_handler = shandler;
473 sigemptyset(&nh.sa_mask);
476 if(sigaction(signr, &nh, &oh) < 0)
484 if (uzbl.behave.fifo_dir)
485 unlink (uzbl.comm.fifo_path);
486 if (uzbl.behave.socket_dir)
487 unlink (uzbl.comm.socket_path);
489 g_free(uzbl.state.executable_path);
490 g_free(uzbl.state.keycmd);
491 g_hash_table_destroy(uzbl.bindings);
492 g_hash_table_destroy(uzbl.behave.commands);
495 /* --- SIGNAL HANDLER --- */
498 catch_sigterm(int s) {
504 catch_sigint(int s) {
510 /* --- CALLBACKS --- */
513 navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
516 (void) navigation_action;
519 const gchar* uri = webkit_network_request_get_uri (request);
520 gboolean decision_made = FALSE;
522 if (uzbl.state.verbose)
523 printf("Navigation requested -> %s\n", uri);
525 if (uzbl.behave.scheme_handler) {
526 GString *s = g_string_new ("");
527 g_string_printf(s, "'%s'", uri);
529 run_handler(uzbl.behave.scheme_handler, s->str);
531 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
532 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
533 if ( p != NULL ) *p = '\0';
534 if (!strcmp(uzbl.comm.sync_stdout, "USED")) {
535 webkit_web_policy_decision_ignore(policy_decision);
536 decision_made = TRUE;
539 if (uzbl.comm.sync_stdout)
540 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
542 g_string_free(s, TRUE);
545 webkit_web_policy_decision_use(policy_decision);
551 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
554 (void) navigation_action;
555 (void) policy_decision;
557 const gchar* uri = webkit_network_request_get_uri (request);
558 if (uzbl.state.verbose)
559 printf("New window requested -> %s \n", uri);
560 webkit_web_policy_decision_use(policy_decision);
565 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
570 /* If we can display it, let's display it... */
571 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
572 webkit_web_policy_decision_use (policy_decision);
576 /* ...everything we can't displayed is downloaded */
577 webkit_web_policy_decision_download (policy_decision);
581 /*@null@*/ WebKitWebView*
582 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
586 if (uzbl.state.selected_url != NULL) {
587 if (uzbl.state.verbose)
588 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
589 new_window_load_uri(uzbl.state.selected_url);
591 if (uzbl.state.verbose)
592 printf("New web view -> %s\n","Nothing to open, exiting");
598 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
601 if (uzbl.behave.download_handler) {
602 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
603 if (uzbl.state.verbose)
604 printf("Download -> %s\n",uri);
605 /* if urls not escaped, we may have to escape and quote uri before this call */
607 GString *args = g_string_new(uri);
609 if (uzbl.net.proxy_url) {
610 g_string_append_c(args, ' ');
611 g_string_append(args, uzbl.net.proxy_url);
614 run_handler(uzbl.behave.download_handler, args->str);
616 g_string_free(args, TRUE);
621 /* scroll a bar in a given direction */
623 scroll (GtkAdjustment* bar, GArray *argv) {
627 gdouble page_size = gtk_adjustment_get_page_size(bar);
628 gdouble value = gtk_adjustment_get_value(bar);
629 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
632 value += page_size * amount * 0.01;
636 max_value = gtk_adjustment_get_upper(bar) - page_size;
638 if (value > max_value)
639 value = max_value; /* don't scroll past the end of the page */
641 gtk_adjustment_set_value (bar, value);
645 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
646 (void) page; (void) argv; (void) result;
647 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
651 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
652 (void) page; (void) argv; (void) result;
653 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
654 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
658 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
659 (void) page; (void) result;
660 scroll(uzbl.gui.bar_v, argv);
664 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
665 (void) page; (void) result;
666 scroll(uzbl.gui.bar_h, argv);
671 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
672 if(uzbl.state.verbose)
673 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
675 /* update geometry var with the actual geometry
676 this is necessary as some WMs don't seem to honour
677 the above setting and we don't want to end up with
678 wrong geometry information
685 if (!uzbl.behave.show_status) {
686 gtk_widget_hide(uzbl.gui.mainbar);
688 gtk_widget_show(uzbl.gui.mainbar);
694 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
699 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
703 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
708 if (uzbl.behave.show_status) {
709 gtk_widget_hide(uzbl.gui.mainbar);
711 gtk_widget_show(uzbl.gui.mainbar);
713 uzbl.behave.show_status = !uzbl.behave.show_status;
718 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
722 //Set selected_url state variable
723 g_free(uzbl.state.selected_url);
724 uzbl.state.selected_url = NULL;
726 uzbl.state.selected_url = g_strdup(link);
732 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
735 const gchar *title = webkit_web_view_get_title(web_view);
736 if (uzbl.gui.main_title)
737 g_free (uzbl.gui.main_title);
738 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
743 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
746 uzbl.gui.sbar.load_progress = progress;
748 g_free(uzbl.gui.sbar.progress_bar);
749 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
755 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
759 if (uzbl.behave.load_finish_handler)
760 run_handler(uzbl.behave.load_finish_handler, "");
763 void clear_keycmd() {
764 g_free(uzbl.state.keycmd);
765 uzbl.state.keycmd = g_strdup("");
769 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
773 uzbl.gui.sbar.load_progress = 0;
774 if (uzbl.behave.load_start_handler)
775 run_handler(uzbl.behave.load_start_handler, "");
779 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
782 g_free (uzbl.state.uri);
783 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
784 uzbl.state.uri = g_string_free (newuri, FALSE);
785 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
786 set_insert_mode(uzbl.behave.always_insert_mode);
789 if (uzbl.behave.load_commit_handler)
790 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
794 destroy_cb (GtkWidget* widget, gpointer data) {
801 /* VIEW funcs (little webkit wrappers) */
802 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
804 VIEWFUNC(reload_bypass_cache)
805 VIEWFUNC(stop_loading)
812 /* -- command to callback/function map for things we cannot attach to any signals */
813 struct {const char *key; CommandInfo value;} cmdlist[] =
814 { /* key function no_split */
815 { "back", {view_go_back, 0} },
816 { "forward", {view_go_forward, 0} },
817 { "scroll_vert", {scroll_vert, 0} },
818 { "scroll_horz", {scroll_horz, 0} },
819 { "scroll_begin", {scroll_begin, 0} },
820 { "scroll_end", {scroll_end, 0} },
821 { "reload", {view_reload, 0}, },
822 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
823 { "stop", {view_stop_loading, 0}, },
824 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
825 { "zoom_out", {view_zoom_out, 0}, },
826 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
827 { "uri", {load_uri, TRUE} },
828 { "js", {run_js, TRUE} },
829 { "script", {run_external_js, 0} },
830 { "toggle_status", {toggle_status_cb, 0} },
831 { "spawn", {spawn, 0} },
832 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
833 { "sh", {spawn_sh, 0} },
834 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
835 { "talk_to_socket", {talk_to_socket, 0} },
836 { "exit", {close_uzbl, 0} },
837 { "search", {search_forward_text, TRUE} },
838 { "search_reverse", {search_reverse_text, TRUE} },
839 { "dehilight", {dehilight, 0} },
840 { "toggle_insert_mode", {toggle_insert_mode, 0} },
841 { "set", {set_var, TRUE} },
842 //{ "get", {get_var, TRUE} },
843 { "bind", {act_bind, TRUE} },
844 { "dump_config", {act_dump_config, 0} },
845 { "keycmd", {keycmd, TRUE} },
846 { "keycmd_nl", {keycmd_nl, TRUE} },
847 { "keycmd_bs", {keycmd_bs, 0} },
848 { "chain", {chain, 0} },
849 { "print", {print, TRUE} },
850 { "update_gui", {update_gui, TRUE} }
857 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
859 for (i = 0; i < LENGTH(cmdlist); i++)
860 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
863 /* -- CORE FUNCTIONS -- */
866 free_action(gpointer act) {
867 Action *action = (Action*)act;
868 g_free(action->name);
870 g_free(action->param);
875 new_action(const gchar *name, const gchar *param) {
876 Action *action = g_new(Action, 1);
878 action->name = g_strdup(name);
880 action->param = g_strdup(param);
882 action->param = NULL;
888 file_exists (const char * filename) {
889 return (access(filename, F_OK) == 0);
893 set_var(WebKitWebView *page, GArray *argv, GString *result) {
894 (void) page; (void) result;
895 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
896 if (split[0] != NULL) {
897 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
898 set_var_value(g_strstrip(split[0]), value);
905 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
906 (void) page; (void) argv; (void) result;
912 print(WebKitWebView *page, GArray *argv, GString *result) {
913 (void) page; (void) result;
916 buf = expand(argv_idx(argv, 0), 0);
917 g_string_assign(result, buf);
922 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
923 (void) page; (void) result;
924 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
925 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
926 add_binding(g_strstrip(split[0]), value);
944 set_mode_indicator() {
945 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
946 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
951 set_mode_indicator();
956 set_insert_mode(gboolean mode) {
957 uzbl.behave.insert_mode = mode;
958 set_mode_indicator();
962 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
963 (void) page; (void) result;
965 if (argv_idx(argv, 0)) {
966 if (strcmp (argv_idx(argv, 0), "0") == 0) {
967 set_insert_mode(FALSE);
969 set_insert_mode(TRUE);
972 set_insert_mode( !uzbl.behave.insert_mode );
979 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
982 if (argv_idx(argv, 0)) {
983 GString* newuri = g_string_new (argv_idx(argv, 0));
984 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
985 run_js(web_view, argv, NULL);
988 if (!soup_uri_new(argv_idx(argv, 0)))
989 g_string_prepend (newuri, "http://");
990 /* if we do handle cookies, ask our handler for them */
991 webkit_web_view_load_uri (web_view, newuri->str);
992 g_string_free (newuri, TRUE);
999 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
1000 size_t argumentCount, const JSValueRef arguments[],
1001 JSValueRef* exception) {
1006 JSStringRef js_result_string;
1007 GString *result = g_string_new("");
1009 if (argumentCount >= 1) {
1010 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1011 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1012 char ctl_line[arg_size];
1013 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1015 parse_cmd_line(ctl_line, result);
1017 JSStringRelease(arg);
1019 js_result_string = JSStringCreateWithUTF8CString(result->str);
1021 g_string_free(result, TRUE);
1023 return JSValueMakeString(ctx, js_result_string);
1026 JSStaticFunction js_static_functions[] = {
1027 {"run", js_run_command, kJSPropertyAttributeNone},
1032 /* This function creates the class and its definition, only once */
1033 if (!uzbl.js.initialized) {
1034 /* it would be pretty cool to make this dynamic */
1035 uzbl.js.classdef = kJSClassDefinitionEmpty;
1036 uzbl.js.classdef.staticFunctions = js_static_functions;
1038 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1044 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1045 WebKitWebFrame *frame;
1046 JSGlobalContextRef context;
1047 JSObjectRef globalobject;
1048 JSStringRef var_name;
1050 JSStringRef js_script;
1051 JSValueRef js_result;
1052 JSStringRef js_result_string;
1053 size_t js_result_size;
1057 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1058 context = webkit_web_frame_get_global_context(frame);
1059 globalobject = JSContextGetGlobalObject(context);
1061 /* uzbl javascript namespace */
1062 var_name = JSStringCreateWithUTF8CString("Uzbl");
1063 JSObjectSetProperty(context, globalobject, var_name,
1064 JSObjectMake(context, uzbl.js.classref, NULL),
1065 kJSClassAttributeNone, NULL);
1067 /* evaluate the script and get return value*/
1068 js_script = JSStringCreateWithUTF8CString(script);
1069 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1070 if (js_result && !JSValueIsUndefined(context, js_result)) {
1071 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1072 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1074 if (js_result_size) {
1075 char js_result_utf8[js_result_size];
1076 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1077 g_string_assign(result, js_result_utf8);
1080 JSStringRelease(js_result_string);
1084 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1086 JSStringRelease(var_name);
1087 JSStringRelease(js_script);
1091 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1092 if (argv_idx(argv, 0))
1093 eval_js(web_view, argv_idx(argv, 0), result);
1097 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1099 if (argv_idx(argv, 0)) {
1100 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1105 while ((line = g_array_index(lines, gchar*, i))) {
1107 js = g_strdup (line);
1109 gchar* newjs = g_strconcat (js, line, NULL);
1116 if (uzbl.state.verbose)
1117 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1119 if (argv_idx (argv, 1)) {
1120 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1124 eval_js (web_view, js, result);
1126 g_array_free (lines, TRUE);
1131 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1132 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1133 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1134 webkit_web_view_unmark_text_matches (page);
1135 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1136 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1140 if (uzbl.state.searchtx) {
1141 if (uzbl.state.verbose)
1142 printf ("Searching: %s\n", uzbl.state.searchtx);
1143 webkit_web_view_set_highlight_text_matches (page, TRUE);
1144 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1149 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1151 search_text(page, argv, TRUE);
1155 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1157 search_text(page, argv, FALSE);
1161 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1162 (void) argv; (void) result;
1163 webkit_web_view_set_highlight_text_matches (page, FALSE);
1168 new_window_load_uri (const gchar * uri) {
1169 if (uzbl.behave.new_window) {
1170 GString *s = g_string_new ("");
1171 g_string_printf(s, "'%s'", uri);
1172 run_handler(uzbl.behave.new_window, s->str);
1175 GString* to_execute = g_string_new ("");
1176 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1178 for (i = 0; entries[i].long_name != NULL; i++) {
1179 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1180 gchar** str = (gchar**)entries[i].arg_data;
1182 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1186 if (uzbl.state.verbose)
1187 printf("\n%s\n", to_execute->str);
1188 g_spawn_command_line_async (to_execute->str, NULL);
1189 g_string_free (to_execute, TRUE);
1193 chain (WebKitWebView *page, GArray *argv, GString *result) {
1194 (void) page; (void) result;
1196 gchar **parts = NULL;
1198 while ((a = argv_idx(argv, i++))) {
1199 parts = g_strsplit (a, " ", 2);
1201 parse_command(parts[0], parts[1], result);
1207 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1211 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1217 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1221 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1227 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1232 int len = strlen(uzbl.state.keycmd);
1233 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1235 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1240 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1247 /* --Statusbar functions-- */
1249 build_progressbar_ascii(int percent) {
1250 int width=uzbl.gui.sbar.progress_w;
1253 GString *bar = g_string_new("");
1255 l = (double)percent*((double)width/100.);
1256 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1258 for(i=0; i<(int)l; i++)
1259 g_string_append(bar, uzbl.gui.sbar.progress_s);
1262 g_string_append(bar, uzbl.gui.sbar.progress_u);
1264 return g_string_free(bar, FALSE);
1266 /* --End Statusbar functions-- */
1269 sharg_append(GArray *a, const gchar *str) {
1270 const gchar *s = (str ? str : "");
1271 g_array_append_val(a, s);
1274 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1276 run_command (const gchar *command, const guint npre, const gchar **args,
1277 const gboolean sync, char **output_stdout) {
1278 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1281 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1282 gchar *pid = itos(getpid());
1283 gchar *xwin = itos(uzbl.xwin);
1285 sharg_append(a, command);
1286 for (i = 0; i < npre; i++) /* add n args before the default vars */
1287 sharg_append(a, args[i]);
1288 sharg_append(a, uzbl.state.config_file);
1289 sharg_append(a, pid);
1290 sharg_append(a, xwin);
1291 sharg_append(a, uzbl.comm.fifo_path);
1292 sharg_append(a, uzbl.comm.socket_path);
1293 sharg_append(a, uzbl.state.uri);
1294 sharg_append(a, uzbl.gui.main_title);
1296 for (i = npre; i < g_strv_length((gchar**)args); i++)
1297 sharg_append(a, args[i]);
1301 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1303 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1304 NULL, NULL, output_stdout, NULL, NULL, &err);
1305 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1306 NULL, NULL, NULL, &err);
1308 if (uzbl.state.verbose) {
1309 GString *s = g_string_new("spawned:");
1310 for (i = 0; i < (a->len); i++) {
1311 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1312 g_string_append_printf(s, " %s", qarg);
1315 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1316 printf("%s\n", s->str);
1317 g_string_free(s, TRUE);
1319 printf("Stdout: %s\n", *output_stdout);
1323 g_printerr("error on run_command: %s\n", err->message);
1328 g_array_free (a, TRUE);
1333 split_quoted(const gchar* src, const gboolean unquote) {
1334 /* split on unquoted space, return array of strings;
1335 remove a layer of quotes and backslashes if unquote */
1336 if (!src) return NULL;
1338 gboolean dq = FALSE;
1339 gboolean sq = FALSE;
1340 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1341 GString *s = g_string_new ("");
1345 for (p = src; *p != '\0'; p++) {
1346 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1347 else if (*p == '\\') { g_string_append_c(s, *p++);
1348 g_string_append_c(s, *p); }
1349 else if ((*p == '"') && unquote && !sq) dq = !dq;
1350 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1352 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1353 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1355 else if ((*p == ' ') && !dq && !sq) {
1356 dup = g_strdup(s->str);
1357 g_array_append_val(a, dup);
1358 g_string_truncate(s, 0);
1359 } else g_string_append_c(s, *p);
1361 dup = g_strdup(s->str);
1362 g_array_append_val(a, dup);
1363 ret = (gchar**)a->data;
1364 g_array_free (a, FALSE);
1365 g_string_free (s, TRUE);
1370 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1371 (void)web_view; (void)result;
1372 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1373 if (argv_idx(argv, 0))
1374 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1378 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1379 (void)web_view; (void)result;
1381 if (argv_idx(argv, 0))
1382 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1383 TRUE, &uzbl.comm.sync_stdout);
1387 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1388 (void)web_view; (void)result;
1389 if (!uzbl.behave.shell_cmd) {
1390 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1395 gchar *spacer = g_strdup("");
1396 g_array_insert_val(argv, 1, spacer);
1397 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1399 for (i = 1; i < g_strv_length(cmd); i++)
1400 g_array_prepend_val(argv, cmd[i]);
1402 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1408 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1409 (void)web_view; (void)result;
1410 if (!uzbl.behave.shell_cmd) {
1411 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1416 gchar *spacer = g_strdup("");
1417 g_array_insert_val(argv, 1, spacer);
1418 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1420 for (i = 1; i < g_strv_length(cmd); i++)
1421 g_array_prepend_val(argv, cmd[i]);
1423 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1424 TRUE, &uzbl.comm.sync_stdout);
1430 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1431 (void)web_view; (void)result;
1434 struct sockaddr_un sa;
1441 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1443 /* This function could be optimised by storing a hash table of socket paths
1444 and associated connected file descriptors rather than closing and
1445 re-opening for every call. Also we could launch a script if socket connect
1448 /* First element argv[0] is path to socket. Following elements are tokens to
1449 write to the socket. We write them as a single packet with each token
1450 separated by an ASCII nul (\0). */
1452 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1457 /* copy socket path, null terminate result */
1458 sockpath = g_array_index(argv, char*, 0);
1459 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1460 sa.sun_family = AF_UNIX;
1462 /* create socket file descriptor and connect it to path */
1463 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1465 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1468 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1469 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1474 /* build request vector */
1475 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1477 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1481 for(i = 1; i < argv->len; ++i) {
1482 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1483 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1487 ret = writev(fd, iov, argv->len - 1);
1490 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1495 /* wait for a response, with a 500ms timeout */
1497 pfd.events = POLLIN;
1499 ret = poll(&pfd, 1, 500);
1501 if(ret == 0) errno = ETIMEDOUT;
1502 if(errno == EINTR) continue;
1503 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1509 /* get length of response */
1510 if(ioctl(fd, FIONREAD, &len) == -1) {
1511 g_printerr("talk_to_socket: cannot find daemon response length, "
1512 "ioctl failed (%s)\n", strerror(errno));
1517 /* if there is a response, read it */
1519 uzbl.comm.sync_stdout = g_malloc(len + 1);
1520 if(!uzbl.comm.sync_stdout) {
1521 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1525 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1527 ret = read(fd, uzbl.comm.sync_stdout, len);
1529 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1542 parse_command(const char *cmd, const char *param, GString *result) {
1545 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1547 gchar **par = split_quoted(param, TRUE);
1548 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1550 if (c->no_split) { /* don't split */
1551 sharg_append(a, param);
1553 for (i = 0; i < g_strv_length(par); i++)
1554 sharg_append(a, par[i]);
1557 if (result == NULL) {
1558 GString *result_print = g_string_new("");
1560 c->function(uzbl.gui.web_view, a, result_print);
1561 if (result_print->len)
1562 printf("%*s\n", (int)result_print->len, result_print->str);
1564 g_string_free(result_print, TRUE);
1566 c->function(uzbl.gui.web_view, a, result);
1569 g_array_free (a, TRUE);
1572 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1579 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1580 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1581 (GType) SOUP_SESSION_PROXY_URI);
1584 suri = soup_uri_new(uzbl.net.proxy_url);
1585 g_object_set(G_OBJECT(uzbl.net.soup_session),
1586 SOUP_SESSION_PROXY_URI,
1588 soup_uri_free(suri);
1595 if(file_exists(uzbl.gui.icon)) {
1596 if (uzbl.gui.main_window)
1597 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1599 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1605 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1606 g_array_append_val (a, uzbl.state.uri);
1607 load_uri(uzbl.gui.web_view, a, NULL);
1608 g_array_free (a, TRUE);
1612 cmd_always_insert_mode() {
1613 set_insert_mode(uzbl.behave.always_insert_mode);
1619 g_object_set(G_OBJECT(uzbl.net.soup_session),
1620 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1624 cmd_max_conns_host() {
1625 g_object_set(G_OBJECT(uzbl.net.soup_session),
1626 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1631 soup_session_remove_feature
1632 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1633 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1634 /*g_free(uzbl.net.soup_logger);*/
1636 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1637 soup_session_add_feature(uzbl.net.soup_session,
1638 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1643 return webkit_web_view_get_settings(uzbl.gui.web_view);
1648 WebKitWebSettings *ws = view_settings();
1649 if (uzbl.behave.font_size > 0) {
1650 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1653 if (uzbl.behave.monospace_size > 0) {
1654 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1655 uzbl.behave.monospace_size, NULL);
1657 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1658 uzbl.behave.font_size, NULL);
1663 cmd_default_font_family() {
1664 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1665 uzbl.behave.default_font_family, NULL);
1669 cmd_monospace_font_family() {
1670 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1671 uzbl.behave.monospace_font_family, NULL);
1675 cmd_sans_serif_font_family() {
1676 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1677 uzbl.behave.sans_serif_font_family, NULL);
1681 cmd_serif_font_family() {
1682 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1683 uzbl.behave.serif_font_family, NULL);
1687 cmd_cursive_font_family() {
1688 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1689 uzbl.behave.cursive_font_family, NULL);
1693 cmd_fantasy_font_family() {
1694 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1695 uzbl.behave.fantasy_font_family, NULL);
1700 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1704 cmd_disable_plugins() {
1705 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1706 !uzbl.behave.disable_plugins, NULL);
1710 cmd_disable_scripts() {
1711 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1712 !uzbl.behave.disable_scripts, NULL);
1716 cmd_minimum_font_size() {
1717 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1718 uzbl.behave.minimum_font_size, NULL);
1721 cmd_autoload_img() {
1722 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1723 uzbl.behave.autoload_img, NULL);
1728 cmd_autoshrink_img() {
1729 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1730 uzbl.behave.autoshrink_img, NULL);
1735 cmd_enable_spellcheck() {
1736 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1737 uzbl.behave.enable_spellcheck, NULL);
1741 cmd_enable_private() {
1742 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1743 uzbl.behave.enable_private, NULL);
1748 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1749 uzbl.behave.print_bg, NULL);
1754 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1755 uzbl.behave.style_uri, NULL);
1759 cmd_resizable_txt() {
1760 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1761 uzbl.behave.resizable_txt, NULL);
1765 cmd_default_encoding() {
1766 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1767 uzbl.behave.default_encoding, NULL);
1771 cmd_enforce_96dpi() {
1772 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1773 uzbl.behave.enforce_96dpi, NULL);
1777 cmd_caret_browsing() {
1778 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1779 uzbl.behave.caret_browsing, NULL);
1783 cmd_cookie_handler() {
1784 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1785 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1786 if ((g_strcmp0(split[0], "sh") == 0) ||
1787 (g_strcmp0(split[0], "spawn") == 0)) {
1788 g_free (uzbl.behave.cookie_handler);
1789 uzbl.behave.cookie_handler =
1790 g_strdup_printf("sync_%s %s", split[0], split[1]);
1796 cmd_scheme_handler() {
1797 gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2);
1798 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1799 if ((g_strcmp0(split[0], "sh") == 0) ||
1800 (g_strcmp0(split[0], "spawn") == 0)) {
1801 g_free (uzbl.behave.scheme_handler);
1802 uzbl.behave.scheme_handler =
1803 g_strdup_printf("sync_%s %s", split[0], split[1]);
1810 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1815 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1820 if(uzbl.behave.inject_html) {
1821 webkit_web_view_load_html_string (uzbl.gui.web_view,
1822 uzbl.behave.inject_html, NULL);
1831 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1832 uzbl.behave.modmask = 0;
1834 if(uzbl.behave.modkey)
1835 g_free(uzbl.behave.modkey);
1836 uzbl.behave.modkey = buf;
1838 for (i = 0; modkeys[i].key != NULL; i++) {
1839 if (g_strrstr(buf, modkeys[i].key))
1840 uzbl.behave.modmask |= modkeys[i].mask;
1846 if (*uzbl.net.useragent == ' ') {
1847 g_free (uzbl.net.useragent);
1848 uzbl.net.useragent = NULL;
1850 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1851 uzbl.net.useragent, NULL);
1857 if (!uzbl.gui.scrolled_win &&
1861 gtk_widget_ref(uzbl.gui.scrolled_win);
1862 gtk_widget_ref(uzbl.gui.mainbar);
1863 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1864 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1866 if(uzbl.behave.status_top) {
1867 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1868 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1871 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1872 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1874 gtk_widget_unref(uzbl.gui.scrolled_win);
1875 gtk_widget_unref(uzbl.gui.mainbar);
1876 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1881 set_var_value(const gchar *name, gchar *val) {
1882 uzbl_cmdprop *c = NULL;
1885 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1887 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1888 if(!c->writeable) return FALSE;
1890 /* check for the variable type */
1891 if (c->type == TYPE_STR) {
1892 buf = expand(val, 0);
1895 } else if(c->type == TYPE_INT) {
1896 buf = expand(val, 0);
1897 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1899 } else if (c->type == TYPE_FLOAT) {
1900 buf = expand(val, 0);
1901 *c->ptr.f = strtod(buf, &endp);
1905 /* invoke a command specific function */
1906 if(c->func) c->func();
1908 /* check wether name violates our naming scheme */
1909 if(strpbrk(name, invalid_chars)) {
1910 if (uzbl.state.verbose)
1911 printf("Invalid variable name\n");
1916 c = malloc(sizeof(uzbl_cmdprop));
1921 buf = expand(val, 0);
1922 c->ptr.s = malloc(sizeof(char *));
1924 g_hash_table_insert(uzbl.comm.proto_var,
1925 g_strdup(name), (gpointer) c);
1930 enum {M_CMD, M_HTML};
1932 parse_cmd_line(const char *ctl_line, GString *result) {
1935 if((ctl_line[0] == '#') /* Comments */
1936 || (ctl_line[0] == ' ')
1937 || (ctl_line[0] == '\n'))
1938 ; /* ignore these lines */
1939 else { /* parse a command */
1941 gchar **tokens = NULL;
1942 len = strlen(ctl_line);
1944 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1945 ctlstrip = g_strndup(ctl_line, len - 1);
1946 else ctlstrip = g_strdup(ctl_line);
1948 tokens = g_strsplit(ctlstrip, " ", 2);
1949 parse_command(tokens[0], tokens[1], result);
1956 build_stream_name(int type, const gchar* dir) {
1957 State *s = &uzbl.state;
1961 str = g_strdup_printf
1962 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1963 } else if (type == SOCKET) {
1964 str = g_strdup_printf
1965 ("%s/uzbl_socket_%s", dir, s->instance_name);
1971 control_fifo(GIOChannel *gio, GIOCondition condition) {
1972 if (uzbl.state.verbose)
1973 printf("triggered\n");
1978 if (condition & G_IO_HUP)
1979 g_error ("Fifo: Read end of pipe died!\n");
1982 g_error ("Fifo: GIOChannel broke\n");
1984 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1985 if (ret == G_IO_STATUS_ERROR) {
1986 g_error ("Fifo: Error reading: %s\n", err->message);
1990 parse_cmd_line(ctl_line, NULL);
1997 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1998 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1999 if (unlink(uzbl.comm.fifo_path) == -1)
2000 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2001 g_free(uzbl.comm.fifo_path);
2002 uzbl.comm.fifo_path = NULL;
2005 GIOChannel *chan = NULL;
2006 GError *error = NULL;
2007 gchar *path = build_stream_name(FIFO, dir);
2009 if (!file_exists(path)) {
2010 if (mkfifo (path, 0666) == 0) {
2011 // 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.
2012 chan = g_io_channel_new_file(path, "r+", &error);
2014 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2015 if (uzbl.state.verbose)
2016 printf ("init_fifo: created successfully as %s\n", path);
2017 uzbl.comm.fifo_path = path;
2019 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2020 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2021 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2022 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2024 /* if we got this far, there was an error; cleanup */
2025 if (error) g_error_free (error);
2032 control_stdin(GIOChannel *gio, GIOCondition condition) {
2034 gchar *ctl_line = NULL;
2037 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2038 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2041 parse_cmd_line(ctl_line, NULL);
2049 GIOChannel *chan = NULL;
2050 GError *error = NULL;
2052 chan = g_io_channel_unix_new(fileno(stdin));
2054 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2055 g_error ("Stdin: could not add watch\n");
2057 if (uzbl.state.verbose)
2058 printf ("Stdin: watch added successfully\n");
2061 g_error ("Stdin: Error while opening: %s\n", error->message);
2063 if (error) g_error_free (error);
2067 control_socket(GIOChannel *chan) {
2068 struct sockaddr_un remote;
2069 unsigned int t = sizeof(remote);
2071 GIOChannel *clientchan;
2073 clientsock = accept (g_io_channel_unix_get_fd(chan),
2074 (struct sockaddr *) &remote, &t);
2076 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2077 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2078 (GIOFunc) control_client_socket, clientchan);
2085 control_client_socket(GIOChannel *clientchan) {
2087 GString *result = g_string_new("");
2088 GError *error = NULL;
2092 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2093 if (ret == G_IO_STATUS_ERROR) {
2094 g_warning ("Error reading: %s\n", error->message);
2095 g_io_channel_shutdown(clientchan, TRUE, &error);
2097 } else if (ret == G_IO_STATUS_EOF) {
2098 /* shutdown and remove channel watch from main loop */
2099 g_io_channel_shutdown(clientchan, TRUE, &error);
2104 parse_cmd_line (ctl_line, result);
2105 g_string_append_c(result, '\n');
2106 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2108 if (ret == G_IO_STATUS_ERROR) {
2109 g_warning ("Error writing: %s", error->message);
2111 g_io_channel_flush(clientchan, &error);
2114 if (error) g_error_free (error);
2115 g_string_free(result, TRUE);
2121 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2122 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2123 if (unlink(uzbl.comm.socket_path) == -1)
2124 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2125 g_free(uzbl.comm.socket_path);
2126 uzbl.comm.socket_path = NULL;
2134 GIOChannel *chan = NULL;
2136 struct sockaddr_un local;
2137 gchar *path = build_stream_name(SOCKET, dir);
2139 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2141 local.sun_family = AF_UNIX;
2142 strcpy (local.sun_path, path);
2143 unlink (local.sun_path);
2145 len = strlen (local.sun_path) + sizeof (local.sun_family);
2146 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2147 if (uzbl.state.verbose)
2148 printf ("init_socket: opened in %s\n", path);
2151 if( (chan = g_io_channel_unix_new(sock)) ) {
2152 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2153 uzbl.comm.socket_path = path;
2156 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2158 /* if we got this far, there was an error; cleanup */
2165 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2166 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2168 // this function may be called very early when the templates are not set (yet), hence the checks
2170 update_title (void) {
2171 Behaviour *b = &uzbl.behave;
2174 if (b->show_status) {
2175 if (b->title_format_short) {
2176 parsed = expand(b->title_format_short, 0);
2177 if (uzbl.gui.main_window)
2178 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2181 if (b->status_format) {
2182 parsed = expand(b->status_format, 0);
2183 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2186 if (b->status_background) {
2188 gdk_color_parse (b->status_background, &color);
2189 //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)
2190 if (uzbl.gui.main_window)
2191 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2192 else if (uzbl.gui.plug)
2193 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2196 if (b->title_format_long) {
2197 parsed = expand(b->title_format_long, 0);
2198 if (uzbl.gui.main_window)
2199 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2206 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2210 retrieve_geometry();
2215 key_press_cb (GtkWidget* window, GdkEventKey* event)
2217 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2221 if (event->type != GDK_KEY_PRESS ||
2222 event->keyval == GDK_Page_Up ||
2223 event->keyval == GDK_Page_Down ||
2224 event->keyval == GDK_Home ||
2225 event->keyval == GDK_End ||
2226 event->keyval == GDK_Up ||
2227 event->keyval == GDK_Down ||
2228 event->keyval == GDK_Left ||
2229 event->keyval == GDK_Right ||
2230 event->keyval == GDK_Shift_L ||
2231 event->keyval == GDK_Shift_R)
2234 /* turn off insert mode (if always_insert_mode is not used) */
2235 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2236 set_insert_mode(uzbl.behave.always_insert_mode);
2241 if (uzbl.behave.insert_mode &&
2242 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2243 (!uzbl.behave.modmask)
2248 if (event->keyval == GDK_Escape) {
2251 dehilight(uzbl.gui.web_view, NULL, NULL);
2255 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2256 if (event->keyval == GDK_Insert) {
2258 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2259 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2261 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2264 GString* keycmd = g_string_new(uzbl.state.keycmd);
2265 g_string_append (keycmd, str);
2266 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2273 if (event->keyval == GDK_BackSpace)
2274 keycmd_bs(NULL, NULL, NULL);
2276 gboolean key_ret = FALSE;
2277 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2280 GString* keycmd = g_string_new(uzbl.state.keycmd);
2281 g_string_append(keycmd, event->string);
2282 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2285 run_keycmd(key_ret);
2287 if (key_ret) return (!uzbl.behave.insert_mode);
2292 run_keycmd(const gboolean key_ret) {
2293 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2295 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2297 parse_command(act->name, act->param, NULL);
2301 /* try if it's an incremental keycmd or one that takes args, and run it */
2302 GString* short_keys = g_string_new ("");
2303 GString* short_keys_inc = g_string_new ("");
2305 guint len = strlen(uzbl.state.keycmd);
2306 for (i=0; i<len; i++) {
2307 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2308 g_string_assign(short_keys_inc, short_keys->str);
2309 g_string_append_c(short_keys, '_');
2310 g_string_append_c(short_keys_inc, '*');
2312 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2313 /* run normal cmds only if return was pressed */
2314 exec_paramcmd(act, i);
2317 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2318 if (key_ret) /* just quit the incremental command on return */
2320 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2324 g_string_truncate(short_keys, short_keys->len - 1);
2326 g_string_free (short_keys, TRUE);
2327 g_string_free (short_keys_inc, TRUE);
2331 exec_paramcmd(const Action *act, const guint i) {
2332 GString *parampart = g_string_new (uzbl.state.keycmd);
2333 GString *actionname = g_string_new ("");
2334 GString *actionparam = g_string_new ("");
2335 g_string_erase (parampart, 0, i+1);
2337 g_string_printf (actionname, act->name, parampart->str);
2339 g_string_printf (actionparam, act->param, parampart->str);
2340 parse_command(actionname->str, actionparam->str, NULL);
2341 g_string_free(actionname, TRUE);
2342 g_string_free(actionparam, TRUE);
2343 g_string_free(parampart, TRUE);
2351 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2353 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2354 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2355 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2356 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2357 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2358 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2359 g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view);
2360 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2361 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2362 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2363 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2370 g->mainbar = gtk_hbox_new (FALSE, 0);
2372 /* keep a reference to the bar so we can re-pack it at runtime*/
2373 //sbar_ref = g_object_ref(g->mainbar);
2375 g->mainbar_label = gtk_label_new ("");
2376 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2377 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2378 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2379 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2380 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2381 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2387 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2388 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2389 gtk_widget_set_name (window, "Uzbl browser");
2390 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2391 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2392 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2399 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2400 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2401 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2408 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2410 If actname is one that calls an external command, this function will inject
2411 newargs in front of the user-provided args in that command line. They will
2412 come become after the body of the script (in sh) or after the name of
2413 the command to execute (in spawn).
2414 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2415 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2417 The return value consist of two strings: the action (sh, ...) and its args.
2419 If act is not one that calls an external command, then the given action merely
2422 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2423 /* Arrr! Here be memory leaks */
2424 gchar *actdup = g_strdup(actname);
2425 g_array_append_val(rets, actdup);
2427 if ((g_strcmp0(actname, "spawn") == 0) ||
2428 (g_strcmp0(actname, "sh") == 0) ||
2429 (g_strcmp0(actname, "sync_spawn") == 0) ||
2430 (g_strcmp0(actname, "sync_sh") == 0) ||
2431 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2433 GString *a = g_string_new("");
2434 gchar **spawnparts = split_quoted(origargs, FALSE);
2435 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2436 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2438 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2439 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2441 g_array_append_val(rets, a->str);
2442 g_string_free(a, FALSE);
2443 g_strfreev(spawnparts);
2445 gchar *origdup = g_strdup(origargs);
2446 g_array_append_val(rets, origdup);
2448 return (gchar**)g_array_free(rets, FALSE);
2452 run_handler (const gchar *act, const gchar *args) {
2453 /* Consider this code a temporary hack to make the handlers usable.
2454 In practice, all this splicing, injection, and reconstruction is
2455 inefficient, annoying and hard to manage. Potential pitfalls arise
2456 when the handler specific args 1) are not quoted (the handler
2457 callbacks should take care of this) 2) are quoted but interfere
2458 with the users' own quotation. A more ideal solution is
2459 to refactor parse_command so that it doesn't just take a string
2460 and execute it; rather than that, we should have a function which
2461 returns the argument vector parsed from the string. This vector
2462 could be modified (e.g. insert additional args into it) before
2463 passing it to the next function that actually executes it. Though
2464 it still isn't perfect for chain actions.. will reconsider & re-
2465 factor when I have the time. -duc */
2467 char **parts = g_strsplit(act, " ", 2);
2469 if (g_strcmp0(parts[0], "chain") == 0) {
2470 GString *newargs = g_string_new("");
2471 gchar **chainparts = split_quoted(parts[1], FALSE);
2473 /* for every argument in the chain, inject the handler args
2474 and make sure the new parts are wrapped in quotes */
2475 gchar **cp = chainparts;
2477 gchar *quotless = NULL;
2478 gchar **spliced_quotless = NULL; // sigh -_-;
2479 gchar **inpart = NULL;
2482 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2484 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2485 } else quotless = g_strdup(*cp);
2487 spliced_quotless = g_strsplit(quotless, " ", 2);
2488 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2489 g_strfreev(spliced_quotless);
2491 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2497 parse_command(parts[0], &(newargs->str[1]), NULL);
2498 g_string_free(newargs, TRUE);
2499 g_strfreev(chainparts);
2502 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2503 parse_command(inparts[0], inparts[1], NULL);
2511 add_binding (const gchar *key, const gchar *act) {
2512 char **parts = g_strsplit(act, " ", 2);
2519 if (uzbl.state.verbose)
2520 printf ("Binding %-10s : %s\n", key, act);
2521 action = new_action(parts[0], parts[1]);
2523 if (g_hash_table_remove (uzbl.bindings, key))
2524 g_warning ("Overwriting existing binding for \"%s\"", key);
2525 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2530 get_xdg_var (XDG_Var xdg) {
2531 const gchar* actual_value = getenv (xdg.environmental);
2532 const gchar* home = getenv ("HOME");
2533 gchar* return_value;
2535 if (! actual_value || strcmp (actual_value, "") == 0) {
2536 if (xdg.default_value) {
2537 return_value = str_replace ("~", home, xdg.default_value);
2539 return_value = NULL;
2542 return_value = str_replace("~", home, actual_value);
2545 return return_value;
2549 find_xdg_file (int xdg_type, const char* filename) {
2550 /* xdg_type = 0 => config
2551 xdg_type = 1 => data
2552 xdg_type = 2 => cache*/
2554 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2555 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2558 gchar* temporary_string;
2562 if (! file_exists (temporary_file) && xdg_type != 2) {
2563 buf = get_xdg_var (XDG[3 + xdg_type]);
2564 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2567 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2568 g_free (temporary_file);
2569 temporary_file = g_strconcat (temporary_string, filename, NULL);
2573 //g_free (temporary_string); - segfaults.
2575 if (file_exists (temporary_file)) {
2576 return temporary_file;
2578 g_free(temporary_file);
2584 State *s = &uzbl.state;
2585 Network *n = &uzbl.net;
2587 for (i = 0; default_config[i].command != NULL; i++) {
2588 parse_cmd_line(default_config[i].command, NULL);
2591 if (g_strcmp0(s->config_file, "-") == 0) {
2592 s->config_file = NULL;
2596 else if (!s->config_file) {
2597 s->config_file = find_xdg_file (0, "/uzbl/config");
2600 if (s->config_file) {
2601 GArray* lines = read_file_by_line (s->config_file);
2605 while ((line = g_array_index(lines, gchar*, i))) {
2606 parse_cmd_line (line, NULL);
2610 g_array_free (lines, TRUE);
2612 if (uzbl.state.verbose)
2613 printf ("No configuration file loaded.\n");
2616 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2619 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2622 if (!uzbl.behave.cookie_handler)
2625 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2626 GString *s = g_string_new ("");
2627 SoupURI * soup_uri = soup_message_get_uri(msg);
2628 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2629 run_handler(uzbl.behave.cookie_handler, s->str);
2631 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2632 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2633 if ( p != NULL ) *p = '\0';
2634 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2636 if (uzbl.comm.sync_stdout)
2637 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2639 g_string_free(s, TRUE);
2643 save_cookies (SoupMessage *msg, gpointer user_data){
2647 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2648 cookie = soup_cookie_to_set_cookie_header(ck->data);
2649 SoupURI * soup_uri = soup_message_get_uri(msg);
2650 GString *s = g_string_new ("");
2651 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2652 run_handler(uzbl.behave.cookie_handler, s->str);
2654 g_string_free(s, TRUE);
2659 /* --- WEBINSPECTOR --- */
2661 hide_window_cb(GtkWidget *widget, gpointer data) {
2664 gtk_widget_hide(widget);
2668 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2671 (void) web_inspector;
2672 GtkWidget* scrolled_window;
2673 GtkWidget* new_web_view;
2676 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2677 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2678 G_CALLBACK(hide_window_cb), NULL);
2680 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2681 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2682 gtk_widget_show(g->inspector_window);
2684 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2685 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2686 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2687 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2688 gtk_widget_show(scrolled_window);
2690 new_web_view = webkit_web_view_new();
2691 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2693 return WEBKIT_WEB_VIEW(new_web_view);
2697 inspector_show_window_cb (WebKitWebInspector* inspector){
2699 gtk_widget_show(uzbl.gui.inspector_window);
2703 /* TODO: Add variables and code to make use of these functions */
2705 inspector_close_window_cb (WebKitWebInspector* inspector){
2711 inspector_attach_window_cb (WebKitWebInspector* inspector){
2717 inspector_detach_window_cb (WebKitWebInspector* inspector){
2723 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2729 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2735 set_up_inspector() {
2737 WebKitWebSettings *settings = view_settings();
2738 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2740 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2741 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2742 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2743 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2744 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2745 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2746 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2748 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2752 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2754 uzbl_cmdprop *c = v;
2759 if(c->type == TYPE_STR)
2760 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2761 else if(c->type == TYPE_INT)
2762 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2763 else if(c->type == TYPE_FLOAT)
2764 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2768 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2772 printf("bind %s = %s %s\n", (char *)k ,
2773 (char *)a->name, a->param?(char *)a->param:"");
2778 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2779 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2783 retrieve_geometry() {
2785 GString *buf = g_string_new("");
2787 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2788 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2790 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2792 if(uzbl.gui.geometry)
2793 g_free(uzbl.gui.geometry);
2794 uzbl.gui.geometry = g_string_free(buf, FALSE);
2797 /* set up gtk, gobject, variable defaults and other things that tests and other
2798 * external applications need to do anyhow */
2800 initialize(int argc, char *argv[]) {
2801 if (!g_thread_supported ())
2802 g_thread_init (NULL);
2803 uzbl.state.executable_path = g_strdup(argv[0]);
2804 uzbl.state.selected_url = NULL;
2805 uzbl.state.searchtx = NULL;
2807 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2808 g_option_context_add_main_entries (context, entries, NULL);
2809 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2810 g_option_context_parse (context, &argc, &argv, NULL);
2811 g_option_context_free(context);
2813 if (uzbl.behave.print_version) {
2814 printf("Commit: %s\n", COMMIT);
2818 /* initialize hash table */
2819 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2821 uzbl.net.soup_session = webkit_get_default_session();
2822 uzbl.state.keycmd = g_strdup("");
2824 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2825 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2826 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2827 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2829 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2830 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2831 uzbl.gui.sbar.progress_w = 10;
2833 /* default mode indicators */
2834 uzbl.behave.insert_indicator = g_strdup("I");
2835 uzbl.behave.cmd_indicator = g_strdup("C");
2837 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2838 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2839 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2840 uzbl.info.arch = ARCH;
2841 uzbl.info.commit = COMMIT;
2844 make_var_to_name_hash();
2849 #ifndef UZBL_LIBRARY
2852 main (int argc, char* argv[]) {
2853 initialize(argc, argv);
2855 gtk_init (&argc, &argv);
2857 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2858 //main_window_ref = g_object_ref(scrolled_window);
2859 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2860 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2862 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2863 GTK_WIDGET (uzbl.gui.web_view));
2865 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2869 /* initial packing */
2870 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2871 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2873 if (uzbl.state.socket_id) {
2874 uzbl.gui.plug = create_plug ();
2875 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2876 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2878 uzbl.gui.main_window = create_window ();
2879 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2880 gtk_widget_show_all (uzbl.gui.main_window);
2881 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2884 if(!uzbl.state.instance_name)
2885 uzbl.state.instance_name = itos((int)uzbl.xwin);
2887 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2889 if (uzbl.state.verbose) {
2890 printf("Uzbl start location: %s\n", argv[0]);
2891 if (uzbl.state.socket_id)
2892 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2894 printf("window_id %i\n",(int) uzbl.xwin);
2895 printf("pid %i\n", getpid ());
2896 printf("name: %s\n", uzbl.state.instance_name);
2897 printf("commit: %s\n", uzbl.info.commit);
2900 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2901 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2902 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2903 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2904 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2906 /* Check uzbl is in window mode before getting/setting geometry */
2907 if (uzbl.gui.main_window) {
2908 if(uzbl.gui.geometry)
2911 retrieve_geometry();
2914 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2915 if (argc > 1 && !uzbl.state.uri)
2916 uri_override = g_strdup(argv[1]);
2917 gboolean verbose_override = uzbl.state.verbose;
2921 if (!uzbl.behave.always_insert_mode)
2922 set_insert_mode(FALSE);
2924 if (!uzbl.behave.show_status)
2925 gtk_widget_hide(uzbl.gui.mainbar);
2932 if (verbose_override > uzbl.state.verbose)
2933 uzbl.state.verbose = verbose_override;
2936 set_var_value("uri", uri_override);
2937 g_free(uri_override);
2938 } else if (uzbl.state.uri)
2944 return EXIT_SUCCESS;
2948 /* vi: set et ts=4: */