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 { "history_handler", PTR_V_STR(uzbl.behave.history_handler, 1, NULL)},
141 { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
142 { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)},
143 { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, NULL)},
144 { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, cmd_scheme_handler)},
145 { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
146 { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
147 { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
148 { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
149 { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
150 { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
151 { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
152 { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
154 /* exported WebKitWebSettings properties */
155 { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
156 { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
157 { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
158 { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
159 { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
160 { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
161 { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
162 { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
163 { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
164 { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
165 { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
166 { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
167 { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
168 { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
169 { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
170 { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
171 { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
172 { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
173 { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
174 { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
175 { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
176 { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
178 /* constants (not dumpable or writeable) */
179 { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
180 { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
181 { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
182 { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
183 { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
184 { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)},
185 { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)},
186 { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
187 { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
188 { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)},
189 { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
191 { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
196 /*@null@*/ char *key;
199 { "SHIFT", GDK_SHIFT_MASK }, // shift
200 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
201 { "CONTROL", GDK_CONTROL_MASK }, // control
202 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
203 { "MOD2", GDK_MOD2_MASK }, // 5th mod
204 { "MOD3", GDK_MOD3_MASK }, // 6th mod
205 { "MOD4", GDK_MOD4_MASK }, // 7th mod
206 { "MOD5", GDK_MOD5_MASK }, // 8th mod
207 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
208 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
209 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
210 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
211 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
212 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
213 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
214 { "META", GDK_META_MASK }, // meta (since 2.10)
219 /* construct a hash from the var_name_to_ptr array for quick access */
221 make_var_to_name_hash() {
222 const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
223 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
225 g_hash_table_insert(uzbl.comm.proto_var,
226 (gpointer) n2v_p->name,
227 (gpointer) &n2v_p->cp);
232 /* --- UTILITY FUNCTIONS --- */
233 enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
235 get_exp_type(const gchar *s) {
239 else if(*(s+1) == '{')
240 return EXP_BRACED_VAR;
241 else if(*(s+1) == '<')
243 else if(*(s+1) == '[')
246 return EXP_SIMPLE_VAR;
253 * recurse == 1: don't expand '@(command)@'
254 * recurse == 2: don't expand '@<java script>@'
257 expand(const char *s, guint recurse) {
260 char *end_simple_var = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
264 gchar *cmd_stdout = NULL;
266 GString *buf = g_string_new("");
267 GString *js_ret = g_string_new("");
272 g_string_append_c(buf, *++s);
277 etype = get_exp_type(s);
282 vend = strpbrk(s, end_simple_var);
283 if(!vend) vend = strchr(s, '\0');
287 vend = strchr(s, '}');
288 if(!vend) vend = strchr(s, '\0');
292 vend = strstr(s, ")@");
293 if(!vend) vend = strchr(s, '\0');
297 vend = strstr(s, ">@");
298 if(!vend) vend = strchr(s, '\0');
302 vend = strstr(s, "]@");
303 if(!vend) vend = strchr(s, '\0');
311 ret = g_strndup(s, vend-s);
313 if(etype == EXP_SIMPLE_VAR ||
314 etype == EXP_BRACED_VAR) {
315 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
316 if(c->type == TYPE_STR && *c->ptr.s != NULL) {
317 g_string_append(buf, (gchar *)*c->ptr.s);
319 else if(c->type == TYPE_INT) {
320 g_string_append_printf(buf, "%d", *c->ptr.i);
322 else if(c->type == TYPE_FLOAT) {
323 g_string_append_printf(buf, "%f", *c->ptr.f);
327 if(etype == EXP_SIMPLE_VAR)
332 else if(recurse != 1 &&
334 mycmd = expand(ret, 1);
335 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
339 g_printerr("error on running command: %s\n", err->message);
342 else if (*cmd_stdout) {
343 size_t len = strlen(cmd_stdout);
345 if(len > 0 && cmd_stdout[len-1] == '\n')
346 cmd_stdout[--len] = '\0'; /* strip trailing newline */
348 g_string_append(buf, cmd_stdout);
353 else if(recurse != 2 &&
355 mycmd = expand(ret, 2);
356 eval_js(uzbl.gui.web_view, mycmd, js_ret);
360 g_string_append(buf, js_ret->str);
361 g_string_free(js_ret, TRUE);
362 js_ret = g_string_new("");
366 else if(etype == EXP_ESCAPE) {
367 mycmd = expand(ret, 0);
368 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
370 g_string_append(buf, escaped);
382 g_string_append_c(buf, *s);
387 g_string_free(js_ret, TRUE);
388 return g_string_free(buf, FALSE);
395 snprintf(tmp, sizeof(tmp), "%i", val);
396 return g_strdup(tmp);
400 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
403 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
406 str_replace (const char* search, const char* replace, const char* string) {
410 buf = g_strsplit (string, search, -1);
411 ret = g_strjoinv (replace, buf);
412 g_strfreev(buf); // somebody said this segfaults
418 read_file_by_line (const gchar *path) {
419 GIOChannel *chan = NULL;
420 gchar *readbuf = NULL;
422 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
425 chan = g_io_channel_new_file(path, "r", NULL);
428 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
429 const gchar* val = g_strdup (readbuf);
430 g_array_append_val (lines, val);
435 g_io_channel_unref (chan);
437 fprintf(stderr, "File '%s' not be read.\n", path);
444 parseenv (char* string) {
445 extern char** environ;
446 gchar* tmpstr = NULL;
450 while (environ[i] != NULL) {
451 gchar** env = g_strsplit (environ[i], "=", 2);
452 gchar* envname = g_strconcat ("$", env[0], NULL);
454 if (g_strrstr (string, envname) != NULL) {
455 tmpstr = g_strdup(string);
457 string = str_replace(envname, env[1], tmpstr);
462 g_strfreev (env); // somebody said this breaks uzbl
470 setup_signal(int signr, sigfunc *shandler) {
471 struct sigaction nh, oh;
473 nh.sa_handler = shandler;
474 sigemptyset(&nh.sa_mask);
477 if(sigaction(signr, &nh, &oh) < 0)
485 if (uzbl.behave.fifo_dir)
486 unlink (uzbl.comm.fifo_path);
487 if (uzbl.behave.socket_dir)
488 unlink (uzbl.comm.socket_path);
490 g_free(uzbl.state.executable_path);
491 g_free(uzbl.state.keycmd);
492 g_hash_table_destroy(uzbl.bindings);
493 g_hash_table_destroy(uzbl.behave.commands);
496 /* --- SIGNAL HANDLER --- */
499 catch_sigterm(int s) {
505 catch_sigint(int s) {
511 /* --- CALLBACKS --- */
514 navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
517 (void) navigation_action;
520 const gchar* uri = webkit_network_request_get_uri (request);
521 gboolean decision_made = FALSE;
523 if (uzbl.state.verbose)
524 printf("Navigation requested -> %s\n", uri);
526 if (uzbl.behave.scheme_handler) {
527 GString *s = g_string_new ("");
528 g_string_printf(s, "'%s'", uri);
530 run_handler(uzbl.behave.scheme_handler, s->str);
532 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
533 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
534 if ( p != NULL ) *p = '\0';
535 if (!strcmp(uzbl.comm.sync_stdout, "USED")) {
536 webkit_web_policy_decision_ignore(policy_decision);
537 decision_made = TRUE;
540 if (uzbl.comm.sync_stdout)
541 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
543 g_string_free(s, TRUE);
546 webkit_web_policy_decision_use(policy_decision);
552 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
555 (void) navigation_action;
556 (void) policy_decision;
558 const gchar* uri = webkit_network_request_get_uri (request);
559 if (uzbl.state.verbose)
560 printf("New window requested -> %s \n", uri);
561 webkit_web_policy_decision_use(policy_decision);
566 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
571 /* If we can display it, let's display it... */
572 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
573 webkit_web_policy_decision_use (policy_decision);
577 /* ...everything we can't displayed is downloaded */
578 webkit_web_policy_decision_download (policy_decision);
582 /*@null@*/ WebKitWebView*
583 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
587 if (uzbl.state.selected_url != NULL) {
588 if (uzbl.state.verbose)
589 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
590 new_window_load_uri(uzbl.state.selected_url);
592 if (uzbl.state.verbose)
593 printf("New web view -> %s\n","Nothing to open, exiting");
599 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
602 if (uzbl.behave.download_handler) {
603 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
604 if (uzbl.state.verbose)
605 printf("Download -> %s\n",uri);
606 /* if urls not escaped, we may have to escape and quote uri before this call */
607 run_handler(uzbl.behave.download_handler, uri);
612 /* scroll a bar in a given direction */
614 scroll (GtkAdjustment* bar, GArray *argv) {
618 gdouble page_size = gtk_adjustment_get_page_size(bar);
619 gdouble value = gtk_adjustment_get_value(bar);
620 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
623 value += page_size * amount * 0.01;
627 max_value = gtk_adjustment_get_upper(bar) - page_size;
629 if (value > max_value)
630 value = max_value; /* don't scroll past the end of the page */
632 gtk_adjustment_set_value (bar, value);
636 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
637 (void) page; (void) argv; (void) result;
638 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
642 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
643 (void) page; (void) argv; (void) result;
644 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
645 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
649 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
650 (void) page; (void) result;
651 scroll(uzbl.gui.bar_v, argv);
655 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
656 (void) page; (void) result;
657 scroll(uzbl.gui.bar_h, argv);
662 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
663 if(uzbl.state.verbose)
664 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
666 /* update geometry var with the actual geometry
667 this is necessary as some WMs don't seem to honour
668 the above setting and we don't want to end up with
669 wrong geometry information
676 if (!uzbl.behave.show_status) {
677 gtk_widget_hide(uzbl.gui.mainbar);
679 gtk_widget_show(uzbl.gui.mainbar);
685 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
690 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
694 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
699 if (uzbl.behave.show_status) {
700 gtk_widget_hide(uzbl.gui.mainbar);
702 gtk_widget_show(uzbl.gui.mainbar);
704 uzbl.behave.show_status = !uzbl.behave.show_status;
709 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
713 //Set selected_url state variable
714 g_free(uzbl.state.selected_url);
715 uzbl.state.selected_url = NULL;
717 uzbl.state.selected_url = g_strdup(link);
723 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
726 const gchar *title = webkit_web_view_get_title(web_view);
727 if (uzbl.gui.main_title)
728 g_free (uzbl.gui.main_title);
729 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
734 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
737 uzbl.gui.sbar.load_progress = progress;
739 g_free(uzbl.gui.sbar.progress_bar);
740 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
746 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
750 if (uzbl.behave.load_finish_handler)
751 run_handler(uzbl.behave.load_finish_handler, "");
754 void clear_keycmd() {
755 g_free(uzbl.state.keycmd);
756 uzbl.state.keycmd = g_strdup("");
760 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
764 uzbl.gui.sbar.load_progress = 0;
765 clear_keycmd(); // don't need old commands to remain on new page?
766 if (uzbl.behave.load_start_handler)
767 run_handler(uzbl.behave.load_start_handler, "");
771 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
774 g_free (uzbl.state.uri);
775 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
776 uzbl.state.uri = g_string_free (newuri, FALSE);
777 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
778 set_insert_mode(uzbl.behave.always_insert_mode);
781 if (uzbl.behave.load_commit_handler)
782 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
786 destroy_cb (GtkWidget* widget, gpointer data) {
794 if (uzbl.behave.history_handler) {
796 struct tm * timeinfo;
799 timeinfo = localtime ( &rawtime );
800 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
801 run_handler(uzbl.behave.history_handler, date);
806 /* VIEW funcs (little webkit wrappers) */
807 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
809 VIEWFUNC(reload_bypass_cache)
810 VIEWFUNC(stop_loading)
817 /* -- command to callback/function map for things we cannot attach to any signals */
818 struct {const char *key; CommandInfo value;} cmdlist[] =
819 { /* key function no_split */
820 { "back", {view_go_back, 0} },
821 { "forward", {view_go_forward, 0} },
822 { "scroll_vert", {scroll_vert, 0} },
823 { "scroll_horz", {scroll_horz, 0} },
824 { "scroll_begin", {scroll_begin, 0} },
825 { "scroll_end", {scroll_end, 0} },
826 { "reload", {view_reload, 0}, },
827 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
828 { "stop", {view_stop_loading, 0}, },
829 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
830 { "zoom_out", {view_zoom_out, 0}, },
831 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
832 { "uri", {load_uri, TRUE} },
833 { "js", {run_js, TRUE} },
834 { "script", {run_external_js, 0} },
835 { "toggle_status", {toggle_status_cb, 0} },
836 { "spawn", {spawn, 0} },
837 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
838 { "sh", {spawn_sh, 0} },
839 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
840 { "talk_to_socket", {talk_to_socket, 0} },
841 { "exit", {close_uzbl, 0} },
842 { "search", {search_forward_text, TRUE} },
843 { "search_reverse", {search_reverse_text, TRUE} },
844 { "dehilight", {dehilight, 0} },
845 { "toggle_insert_mode", {toggle_insert_mode, 0} },
846 { "set", {set_var, TRUE} },
847 //{ "get", {get_var, TRUE} },
848 { "bind", {act_bind, TRUE} },
849 { "dump_config", {act_dump_config, 0} },
850 { "keycmd", {keycmd, TRUE} },
851 { "keycmd_nl", {keycmd_nl, TRUE} },
852 { "keycmd_bs", {keycmd_bs, 0} },
853 { "chain", {chain, 0} },
854 { "print", {print, TRUE} },
855 { "update_gui", {update_gui, TRUE} }
862 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
864 for (i = 0; i < LENGTH(cmdlist); i++)
865 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
868 /* -- CORE FUNCTIONS -- */
871 free_action(gpointer act) {
872 Action *action = (Action*)act;
873 g_free(action->name);
875 g_free(action->param);
880 new_action(const gchar *name, const gchar *param) {
881 Action *action = g_new(Action, 1);
883 action->name = g_strdup(name);
885 action->param = g_strdup(param);
887 action->param = NULL;
893 file_exists (const char * filename) {
894 return (access(filename, F_OK) == 0);
898 set_var(WebKitWebView *page, GArray *argv, GString *result) {
899 (void) page; (void) result;
900 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
901 if (split[0] != NULL) {
902 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
903 set_var_value(g_strstrip(split[0]), value);
910 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
911 (void) page; (void) argv; (void) result;
917 print(WebKitWebView *page, GArray *argv, GString *result) {
918 (void) page; (void) result;
921 buf = expand(argv_idx(argv, 0), 0);
922 g_string_assign(result, buf);
927 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
928 (void) page; (void) result;
929 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
930 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
931 add_binding(g_strstrip(split[0]), value);
949 set_mode_indicator() {
950 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
951 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
956 set_mode_indicator();
961 set_insert_mode(gboolean mode) {
962 uzbl.behave.insert_mode = mode;
963 set_mode_indicator();
967 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
968 (void) page; (void) result;
970 if (argv_idx(argv, 0)) {
971 if (strcmp (argv_idx(argv, 0), "0") == 0) {
972 set_insert_mode(FALSE);
974 set_insert_mode(TRUE);
977 set_insert_mode( !uzbl.behave.insert_mode );
984 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
987 if (argv_idx(argv, 0)) {
988 GString* newuri = g_string_new (argv_idx(argv, 0));
989 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
990 run_js(web_view, argv, NULL);
993 if (!soup_uri_new(argv_idx(argv, 0)))
994 g_string_prepend (newuri, "http://");
995 /* if we do handle cookies, ask our handler for them */
996 webkit_web_view_load_uri (web_view, newuri->str);
997 g_string_free (newuri, TRUE);
1004 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
1005 size_t argumentCount, const JSValueRef arguments[],
1006 JSValueRef* exception) {
1011 JSStringRef js_result_string;
1012 GString *result = g_string_new("");
1014 if (argumentCount >= 1) {
1015 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1016 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1017 char ctl_line[arg_size];
1018 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1020 parse_cmd_line(ctl_line, result);
1022 JSStringRelease(arg);
1024 js_result_string = JSStringCreateWithUTF8CString(result->str);
1026 g_string_free(result, TRUE);
1028 return JSValueMakeString(ctx, js_result_string);
1031 JSStaticFunction js_static_functions[] = {
1032 {"run", js_run_command, kJSPropertyAttributeNone},
1037 /* This function creates the class and its definition, only once */
1038 if (!uzbl.js.initialized) {
1039 /* it would be pretty cool to make this dynamic */
1040 uzbl.js.classdef = kJSClassDefinitionEmpty;
1041 uzbl.js.classdef.staticFunctions = js_static_functions;
1043 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1049 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1050 WebKitWebFrame *frame;
1051 JSGlobalContextRef context;
1052 JSObjectRef globalobject;
1053 JSStringRef var_name;
1055 JSStringRef js_script;
1056 JSValueRef js_result;
1057 JSStringRef js_result_string;
1058 size_t js_result_size;
1062 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1063 context = webkit_web_frame_get_global_context(frame);
1064 globalobject = JSContextGetGlobalObject(context);
1066 /* uzbl javascript namespace */
1067 var_name = JSStringCreateWithUTF8CString("Uzbl");
1068 JSObjectSetProperty(context, globalobject, var_name,
1069 JSObjectMake(context, uzbl.js.classref, NULL),
1070 kJSClassAttributeNone, NULL);
1072 /* evaluate the script and get return value*/
1073 js_script = JSStringCreateWithUTF8CString(script);
1074 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1075 if (js_result && !JSValueIsUndefined(context, js_result)) {
1076 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1077 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1079 if (js_result_size) {
1080 char js_result_utf8[js_result_size];
1081 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1082 g_string_assign(result, js_result_utf8);
1085 JSStringRelease(js_result_string);
1089 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1091 JSStringRelease(var_name);
1092 JSStringRelease(js_script);
1096 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1097 if (argv_idx(argv, 0))
1098 eval_js(web_view, argv_idx(argv, 0), result);
1102 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1104 if (argv_idx(argv, 0)) {
1105 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1110 while ((line = g_array_index(lines, gchar*, i))) {
1112 js = g_strdup (line);
1114 gchar* newjs = g_strconcat (js, line, NULL);
1121 if (uzbl.state.verbose)
1122 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1124 if (argv_idx (argv, 1)) {
1125 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1129 eval_js (web_view, js, result);
1131 g_array_free (lines, TRUE);
1136 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1137 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1138 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1139 webkit_web_view_unmark_text_matches (page);
1140 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1141 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1145 if (uzbl.state.searchtx) {
1146 if (uzbl.state.verbose)
1147 printf ("Searching: %s\n", uzbl.state.searchtx);
1148 webkit_web_view_set_highlight_text_matches (page, TRUE);
1149 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1154 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1156 search_text(page, argv, TRUE);
1160 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1162 search_text(page, argv, FALSE);
1166 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1167 (void) argv; (void) result;
1168 webkit_web_view_set_highlight_text_matches (page, FALSE);
1173 new_window_load_uri (const gchar * uri) {
1174 if (uzbl.behave.new_window) {
1175 GString *s = g_string_new ("");
1176 g_string_printf(s, "'%s'", uri);
1177 run_handler(uzbl.behave.new_window, s->str);
1180 GString* to_execute = g_string_new ("");
1181 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1183 for (i = 0; entries[i].long_name != NULL; i++) {
1184 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1185 gchar** str = (gchar**)entries[i].arg_data;
1187 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1191 if (uzbl.state.verbose)
1192 printf("\n%s\n", to_execute->str);
1193 g_spawn_command_line_async (to_execute->str, NULL);
1194 g_string_free (to_execute, TRUE);
1198 chain (WebKitWebView *page, GArray *argv, GString *result) {
1199 (void) page; (void) result;
1201 gchar **parts = NULL;
1203 while ((a = argv_idx(argv, i++))) {
1204 parts = g_strsplit (a, " ", 2);
1206 parse_command(parts[0], parts[1], result);
1212 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1216 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1222 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1226 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1232 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1237 int len = strlen(uzbl.state.keycmd);
1238 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1240 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1245 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1252 /* --Statusbar functions-- */
1254 build_progressbar_ascii(int percent) {
1255 int width=uzbl.gui.sbar.progress_w;
1258 GString *bar = g_string_new("");
1260 l = (double)percent*((double)width/100.);
1261 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1263 for(i=0; i<(int)l; i++)
1264 g_string_append(bar, uzbl.gui.sbar.progress_s);
1267 g_string_append(bar, uzbl.gui.sbar.progress_u);
1269 return g_string_free(bar, FALSE);
1271 /* --End Statusbar functions-- */
1274 sharg_append(GArray *a, const gchar *str) {
1275 const gchar *s = (str ? str : "");
1276 g_array_append_val(a, s);
1279 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1281 run_command (const gchar *command, const guint npre, const gchar **args,
1282 const gboolean sync, char **output_stdout) {
1283 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1286 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1287 gchar *pid = itos(getpid());
1288 gchar *xwin = itos(uzbl.xwin);
1290 sharg_append(a, command);
1291 for (i = 0; i < npre; i++) /* add n args before the default vars */
1292 sharg_append(a, args[i]);
1293 sharg_append(a, uzbl.state.config_file);
1294 sharg_append(a, pid);
1295 sharg_append(a, xwin);
1296 sharg_append(a, uzbl.comm.fifo_path);
1297 sharg_append(a, uzbl.comm.socket_path);
1298 sharg_append(a, uzbl.state.uri);
1299 sharg_append(a, uzbl.gui.main_title);
1301 for (i = npre; i < g_strv_length((gchar**)args); i++)
1302 sharg_append(a, args[i]);
1306 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1308 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1309 NULL, NULL, output_stdout, NULL, NULL, &err);
1310 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1311 NULL, NULL, NULL, &err);
1313 if (uzbl.state.verbose) {
1314 GString *s = g_string_new("spawned:");
1315 for (i = 0; i < (a->len); i++) {
1316 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1317 g_string_append_printf(s, " %s", qarg);
1320 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1321 printf("%s\n", s->str);
1322 g_string_free(s, TRUE);
1324 printf("Stdout: %s\n", *output_stdout);
1328 g_printerr("error on run_command: %s\n", err->message);
1333 g_array_free (a, TRUE);
1338 split_quoted(const gchar* src, const gboolean unquote) {
1339 /* split on unquoted space, return array of strings;
1340 remove a layer of quotes and backslashes if unquote */
1341 if (!src) return NULL;
1343 gboolean dq = FALSE;
1344 gboolean sq = FALSE;
1345 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1346 GString *s = g_string_new ("");
1350 for (p = src; *p != '\0'; p++) {
1351 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1352 else if (*p == '\\') { g_string_append_c(s, *p++);
1353 g_string_append_c(s, *p); }
1354 else if ((*p == '"') && unquote && !sq) dq = !dq;
1355 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1357 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1358 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1360 else if ((*p == ' ') && !dq && !sq) {
1361 dup = g_strdup(s->str);
1362 g_array_append_val(a, dup);
1363 g_string_truncate(s, 0);
1364 } else g_string_append_c(s, *p);
1366 dup = g_strdup(s->str);
1367 g_array_append_val(a, dup);
1368 ret = (gchar**)a->data;
1369 g_array_free (a, FALSE);
1370 g_string_free (s, TRUE);
1375 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1376 (void)web_view; (void)result;
1377 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1378 if (argv_idx(argv, 0))
1379 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1383 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1384 (void)web_view; (void)result;
1386 if (argv_idx(argv, 0))
1387 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1388 TRUE, &uzbl.comm.sync_stdout);
1392 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1393 (void)web_view; (void)result;
1394 if (!uzbl.behave.shell_cmd) {
1395 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1400 gchar *spacer = g_strdup("");
1401 g_array_insert_val(argv, 1, spacer);
1402 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1404 for (i = 1; i < g_strv_length(cmd); i++)
1405 g_array_prepend_val(argv, cmd[i]);
1407 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1413 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1414 (void)web_view; (void)result;
1415 if (!uzbl.behave.shell_cmd) {
1416 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1421 gchar *spacer = g_strdup("");
1422 g_array_insert_val(argv, 1, spacer);
1423 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1425 for (i = 1; i < g_strv_length(cmd); i++)
1426 g_array_prepend_val(argv, cmd[i]);
1428 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1429 TRUE, &uzbl.comm.sync_stdout);
1435 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1436 (void)web_view; (void)result;
1439 struct sockaddr_un sa;
1446 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1448 /* This function could be optimised by storing a hash table of socket paths
1449 and associated connected file descriptors rather than closing and
1450 re-opening for every call. Also we could launch a script if socket connect
1453 /* First element argv[0] is path to socket. Following elements are tokens to
1454 write to the socket. We write them as a single packet with each token
1455 separated by an ASCII nul (\0). */
1457 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1462 /* copy socket path, null terminate result */
1463 sockpath = g_array_index(argv, char*, 0);
1464 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1465 sa.sun_family = AF_UNIX;
1467 /* create socket file descriptor and connect it to path */
1468 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1470 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1473 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1474 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1479 /* build request vector */
1480 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1482 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1486 for(i = 1; i < argv->len; ++i) {
1487 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1488 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1492 ret = writev(fd, iov, argv->len - 1);
1495 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1500 /* wait for a response, with a 500ms timeout */
1502 pfd.events = POLLIN;
1504 ret = poll(&pfd, 1, 500);
1506 if(ret == 0) errno = ETIMEDOUT;
1507 if(errno == EINTR) continue;
1508 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1514 /* get length of response */
1515 if(ioctl(fd, FIONREAD, &len) == -1) {
1516 g_printerr("talk_to_socket: cannot find daemon response length, "
1517 "ioctl failed (%s)\n", strerror(errno));
1522 /* if there is a response, read it */
1524 uzbl.comm.sync_stdout = g_malloc(len + 1);
1525 if(!uzbl.comm.sync_stdout) {
1526 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1530 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1532 ret = read(fd, uzbl.comm.sync_stdout, len);
1534 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1547 parse_command(const char *cmd, const char *param, GString *result) {
1550 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1552 gchar **par = split_quoted(param, TRUE);
1553 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1555 if (c->no_split) { /* don't split */
1556 sharg_append(a, param);
1558 for (i = 0; i < g_strv_length(par); i++)
1559 sharg_append(a, par[i]);
1562 if (result == NULL) {
1563 GString *result_print = g_string_new("");
1565 c->function(uzbl.gui.web_view, a, result_print);
1566 if (result_print->len)
1567 printf("%*s\n", (int)result_print->len, result_print->str);
1569 g_string_free(result_print, TRUE);
1571 c->function(uzbl.gui.web_view, a, result);
1574 g_array_free (a, TRUE);
1577 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1584 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1585 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1586 (GType) SOUP_SESSION_PROXY_URI);
1589 suri = soup_uri_new(uzbl.net.proxy_url);
1590 g_object_set(G_OBJECT(uzbl.net.soup_session),
1591 SOUP_SESSION_PROXY_URI,
1593 soup_uri_free(suri);
1600 if(file_exists(uzbl.gui.icon)) {
1601 if (uzbl.gui.main_window)
1602 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1604 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1610 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1611 g_array_append_val (a, uzbl.state.uri);
1612 load_uri(uzbl.gui.web_view, a, NULL);
1613 g_array_free (a, TRUE);
1617 cmd_always_insert_mode() {
1618 set_insert_mode(uzbl.behave.always_insert_mode);
1624 g_object_set(G_OBJECT(uzbl.net.soup_session),
1625 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1629 cmd_max_conns_host() {
1630 g_object_set(G_OBJECT(uzbl.net.soup_session),
1631 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1636 soup_session_remove_feature
1637 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1638 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1639 /*g_free(uzbl.net.soup_logger);*/
1641 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1642 soup_session_add_feature(uzbl.net.soup_session,
1643 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1648 return webkit_web_view_get_settings(uzbl.gui.web_view);
1653 WebKitWebSettings *ws = view_settings();
1654 if (uzbl.behave.font_size > 0) {
1655 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1658 if (uzbl.behave.monospace_size > 0) {
1659 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1660 uzbl.behave.monospace_size, NULL);
1662 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1663 uzbl.behave.font_size, NULL);
1668 cmd_default_font_family() {
1669 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1670 uzbl.behave.default_font_family, NULL);
1674 cmd_monospace_font_family() {
1675 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1676 uzbl.behave.monospace_font_family, NULL);
1680 cmd_sans_serif_font_family() {
1681 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1682 uzbl.behave.sans_serif_font_family, NULL);
1686 cmd_serif_font_family() {
1687 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1688 uzbl.behave.serif_font_family, NULL);
1692 cmd_cursive_font_family() {
1693 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1694 uzbl.behave.cursive_font_family, NULL);
1698 cmd_fantasy_font_family() {
1699 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1700 uzbl.behave.fantasy_font_family, NULL);
1705 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1709 cmd_disable_plugins() {
1710 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1711 !uzbl.behave.disable_plugins, NULL);
1715 cmd_disable_scripts() {
1716 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1717 !uzbl.behave.disable_scripts, NULL);
1721 cmd_minimum_font_size() {
1722 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1723 uzbl.behave.minimum_font_size, NULL);
1726 cmd_autoload_img() {
1727 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1728 uzbl.behave.autoload_img, NULL);
1733 cmd_autoshrink_img() {
1734 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1735 uzbl.behave.autoshrink_img, NULL);
1740 cmd_enable_spellcheck() {
1741 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1742 uzbl.behave.enable_spellcheck, NULL);
1746 cmd_enable_private() {
1747 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1748 uzbl.behave.enable_private, NULL);
1753 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1754 uzbl.behave.print_bg, NULL);
1759 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1760 uzbl.behave.style_uri, NULL);
1764 cmd_resizable_txt() {
1765 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1766 uzbl.behave.resizable_txt, NULL);
1770 cmd_default_encoding() {
1771 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1772 uzbl.behave.default_encoding, NULL);
1776 cmd_enforce_96dpi() {
1777 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1778 uzbl.behave.enforce_96dpi, NULL);
1782 cmd_caret_browsing() {
1783 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1784 uzbl.behave.caret_browsing, NULL);
1788 cmd_cookie_handler() {
1789 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1790 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1791 if ((g_strcmp0(split[0], "sh") == 0) ||
1792 (g_strcmp0(split[0], "spawn") == 0)) {
1793 g_free (uzbl.behave.cookie_handler);
1794 uzbl.behave.cookie_handler =
1795 g_strdup_printf("sync_%s %s", split[0], split[1]);
1801 cmd_scheme_handler() {
1802 gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2);
1803 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1804 if ((g_strcmp0(split[0], "sh") == 0) ||
1805 (g_strcmp0(split[0], "spawn") == 0)) {
1806 g_free (uzbl.behave.scheme_handler);
1807 uzbl.behave.scheme_handler =
1808 g_strdup_printf("sync_%s %s", split[0], split[1]);
1815 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1820 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1825 if(uzbl.behave.inject_html) {
1826 webkit_web_view_load_html_string (uzbl.gui.web_view,
1827 uzbl.behave.inject_html, NULL);
1836 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1837 uzbl.behave.modmask = 0;
1839 if(uzbl.behave.modkey)
1840 g_free(uzbl.behave.modkey);
1841 uzbl.behave.modkey = buf;
1843 for (i = 0; modkeys[i].key != NULL; i++) {
1844 if (g_strrstr(buf, modkeys[i].key))
1845 uzbl.behave.modmask |= modkeys[i].mask;
1851 if (*uzbl.net.useragent == ' ') {
1852 g_free (uzbl.net.useragent);
1853 uzbl.net.useragent = NULL;
1855 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1856 uzbl.net.useragent, NULL);
1862 if (!uzbl.gui.scrolled_win &&
1866 gtk_widget_ref(uzbl.gui.scrolled_win);
1867 gtk_widget_ref(uzbl.gui.mainbar);
1868 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1869 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1871 if(uzbl.behave.status_top) {
1872 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1873 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1876 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1877 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1879 gtk_widget_unref(uzbl.gui.scrolled_win);
1880 gtk_widget_unref(uzbl.gui.mainbar);
1881 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1886 set_var_value(const gchar *name, gchar *val) {
1887 uzbl_cmdprop *c = NULL;
1890 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1892 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1893 if(!c->writeable) return FALSE;
1895 /* check for the variable type */
1896 if (c->type == TYPE_STR) {
1897 buf = expand(val, 0);
1900 } else if(c->type == TYPE_INT) {
1901 buf = expand(val, 0);
1902 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1904 } else if (c->type == TYPE_FLOAT) {
1905 buf = expand(val, 0);
1906 *c->ptr.f = strtod(buf, &endp);
1910 /* invoke a command specific function */
1911 if(c->func) c->func();
1913 /* check wether name violates our naming scheme */
1914 if(strpbrk(name, invalid_chars)) {
1915 if (uzbl.state.verbose)
1916 printf("Invalid variable name\n");
1921 c = malloc(sizeof(uzbl_cmdprop));
1926 buf = expand(val, 0);
1927 c->ptr.s = malloc(sizeof(char *));
1929 g_hash_table_insert(uzbl.comm.proto_var,
1930 g_strdup(name), (gpointer) c);
1935 enum {M_CMD, M_HTML};
1937 parse_cmd_line(const char *ctl_line, GString *result) {
1940 if((ctl_line[0] == '#') /* Comments */
1941 || (ctl_line[0] == ' ')
1942 || (ctl_line[0] == '\n'))
1943 ; /* ignore these lines */
1944 else { /* parse a command */
1946 gchar **tokens = NULL;
1947 len = strlen(ctl_line);
1949 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1950 ctlstrip = g_strndup(ctl_line, len - 1);
1951 else ctlstrip = g_strdup(ctl_line);
1953 tokens = g_strsplit(ctlstrip, " ", 2);
1954 parse_command(tokens[0], tokens[1], result);
1961 build_stream_name(int type, const gchar* dir) {
1962 State *s = &uzbl.state;
1966 str = g_strdup_printf
1967 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1968 } else if (type == SOCKET) {
1969 str = g_strdup_printf
1970 ("%s/uzbl_socket_%s", dir, s->instance_name);
1976 control_fifo(GIOChannel *gio, GIOCondition condition) {
1977 if (uzbl.state.verbose)
1978 printf("triggered\n");
1983 if (condition & G_IO_HUP)
1984 g_error ("Fifo: Read end of pipe died!\n");
1987 g_error ("Fifo: GIOChannel broke\n");
1989 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1990 if (ret == G_IO_STATUS_ERROR) {
1991 g_error ("Fifo: Error reading: %s\n", err->message);
1995 parse_cmd_line(ctl_line, NULL);
2002 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2003 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2004 if (unlink(uzbl.comm.fifo_path) == -1)
2005 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2006 g_free(uzbl.comm.fifo_path);
2007 uzbl.comm.fifo_path = NULL;
2010 GIOChannel *chan = NULL;
2011 GError *error = NULL;
2012 gchar *path = build_stream_name(FIFO, dir);
2014 if (!file_exists(path)) {
2015 if (mkfifo (path, 0666) == 0) {
2016 // 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.
2017 chan = g_io_channel_new_file(path, "r+", &error);
2019 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2020 if (uzbl.state.verbose)
2021 printf ("init_fifo: created successfully as %s\n", path);
2022 uzbl.comm.fifo_path = path;
2024 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2025 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2026 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2027 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2029 /* if we got this far, there was an error; cleanup */
2030 if (error) g_error_free (error);
2037 control_stdin(GIOChannel *gio, GIOCondition condition) {
2039 gchar *ctl_line = NULL;
2042 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2043 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2046 parse_cmd_line(ctl_line, NULL);
2054 GIOChannel *chan = NULL;
2055 GError *error = NULL;
2057 chan = g_io_channel_unix_new(fileno(stdin));
2059 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2060 g_error ("Stdin: could not add watch\n");
2062 if (uzbl.state.verbose)
2063 printf ("Stdin: watch added successfully\n");
2066 g_error ("Stdin: Error while opening: %s\n", error->message);
2068 if (error) g_error_free (error);
2072 control_socket(GIOChannel *chan) {
2073 struct sockaddr_un remote;
2074 unsigned int t = sizeof(remote);
2076 GIOChannel *clientchan;
2078 clientsock = accept (g_io_channel_unix_get_fd(chan),
2079 (struct sockaddr *) &remote, &t);
2081 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2082 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2083 (GIOFunc) control_client_socket, clientchan);
2090 control_client_socket(GIOChannel *clientchan) {
2092 GString *result = g_string_new("");
2093 GError *error = NULL;
2097 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2098 if (ret == G_IO_STATUS_ERROR) {
2099 g_warning ("Error reading: %s\n", error->message);
2100 g_io_channel_shutdown(clientchan, TRUE, &error);
2102 } else if (ret == G_IO_STATUS_EOF) {
2103 /* shutdown and remove channel watch from main loop */
2104 g_io_channel_shutdown(clientchan, TRUE, &error);
2109 parse_cmd_line (ctl_line, result);
2110 g_string_append_c(result, '\n');
2111 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2113 if (ret == G_IO_STATUS_ERROR) {
2114 g_warning ("Error writing: %s", error->message);
2116 g_io_channel_flush(clientchan, &error);
2119 if (error) g_error_free (error);
2120 g_string_free(result, TRUE);
2126 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2127 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2128 if (unlink(uzbl.comm.socket_path) == -1)
2129 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2130 g_free(uzbl.comm.socket_path);
2131 uzbl.comm.socket_path = NULL;
2139 GIOChannel *chan = NULL;
2141 struct sockaddr_un local;
2142 gchar *path = build_stream_name(SOCKET, dir);
2144 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2146 local.sun_family = AF_UNIX;
2147 strcpy (local.sun_path, path);
2148 unlink (local.sun_path);
2150 len = strlen (local.sun_path) + sizeof (local.sun_family);
2151 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2152 if (uzbl.state.verbose)
2153 printf ("init_socket: opened in %s\n", path);
2156 if( (chan = g_io_channel_unix_new(sock)) ) {
2157 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2158 uzbl.comm.socket_path = path;
2161 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2163 /* if we got this far, there was an error; cleanup */
2170 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2171 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2173 // this function may be called very early when the templates are not set (yet), hence the checks
2175 update_title (void) {
2176 Behaviour *b = &uzbl.behave;
2179 if (b->show_status) {
2180 if (b->title_format_short) {
2181 parsed = expand(b->title_format_short, 0);
2182 if (uzbl.gui.main_window)
2183 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2186 if (b->status_format) {
2187 parsed = expand(b->status_format, 0);
2188 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2191 if (b->status_background) {
2193 gdk_color_parse (b->status_background, &color);
2194 //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)
2195 if (uzbl.gui.main_window)
2196 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2197 else if (uzbl.gui.plug)
2198 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2201 if (b->title_format_long) {
2202 parsed = expand(b->title_format_long, 0);
2203 if (uzbl.gui.main_window)
2204 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2211 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2215 retrieve_geometry();
2220 key_press_cb (GtkWidget* window, GdkEventKey* event)
2222 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2226 if (event->type != GDK_KEY_PRESS ||
2227 event->keyval == GDK_Page_Up ||
2228 event->keyval == GDK_Page_Down ||
2229 event->keyval == GDK_Up ||
2230 event->keyval == GDK_Down ||
2231 event->keyval == GDK_Left ||
2232 event->keyval == GDK_Right ||
2233 event->keyval == GDK_Shift_L ||
2234 event->keyval == GDK_Shift_R)
2237 /* turn off insert mode (if always_insert_mode is not used) */
2238 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2239 set_insert_mode(uzbl.behave.always_insert_mode);
2244 if (uzbl.behave.insert_mode &&
2245 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2246 (!uzbl.behave.modmask)
2251 if (event->keyval == GDK_Escape) {
2254 dehilight(uzbl.gui.web_view, NULL, NULL);
2258 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2259 if (event->keyval == GDK_Insert) {
2261 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2262 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2264 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2267 GString* keycmd = g_string_new(uzbl.state.keycmd);
2268 g_string_append (keycmd, str);
2269 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2276 if (event->keyval == GDK_BackSpace)
2277 keycmd_bs(NULL, NULL, NULL);
2279 gboolean key_ret = FALSE;
2280 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2283 GString* keycmd = g_string_new(uzbl.state.keycmd);
2284 g_string_append(keycmd, event->string);
2285 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2288 run_keycmd(key_ret);
2290 if (key_ret) return (!uzbl.behave.insert_mode);
2295 run_keycmd(const gboolean key_ret) {
2296 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2298 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2300 parse_command(act->name, act->param, NULL);
2304 /* try if it's an incremental keycmd or one that takes args, and run it */
2305 GString* short_keys = g_string_new ("");
2306 GString* short_keys_inc = g_string_new ("");
2308 guint len = strlen(uzbl.state.keycmd);
2309 for (i=0; i<len; i++) {
2310 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2311 g_string_assign(short_keys_inc, short_keys->str);
2312 g_string_append_c(short_keys, '_');
2313 g_string_append_c(short_keys_inc, '*');
2315 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2316 /* run normal cmds only if return was pressed */
2317 exec_paramcmd(act, i);
2320 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2321 if (key_ret) /* just quit the incremental command on return */
2323 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2327 g_string_truncate(short_keys, short_keys->len - 1);
2329 g_string_free (short_keys, TRUE);
2330 g_string_free (short_keys_inc, TRUE);
2334 exec_paramcmd(const Action *act, const guint i) {
2335 GString *parampart = g_string_new (uzbl.state.keycmd);
2336 GString *actionname = g_string_new ("");
2337 GString *actionparam = g_string_new ("");
2338 g_string_erase (parampart, 0, i+1);
2340 g_string_printf (actionname, act->name, parampart->str);
2342 g_string_printf (actionparam, act->param, parampart->str);
2343 parse_command(actionname->str, actionparam->str, NULL);
2344 g_string_free(actionname, TRUE);
2345 g_string_free(actionparam, TRUE);
2346 g_string_free(parampart, TRUE);
2354 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2356 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2357 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2358 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2359 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2360 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2361 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2362 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2363 g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view);
2364 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2365 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2366 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2367 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2374 g->mainbar = gtk_hbox_new (FALSE, 0);
2376 /* keep a reference to the bar so we can re-pack it at runtime*/
2377 //sbar_ref = g_object_ref(g->mainbar);
2379 g->mainbar_label = gtk_label_new ("");
2380 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2381 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2382 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2383 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2384 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2385 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2391 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2392 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2393 gtk_widget_set_name (window, "Uzbl browser");
2394 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2395 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2396 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2403 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2404 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2405 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2412 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2414 If actname is one that calls an external command, this function will inject
2415 newargs in front of the user-provided args in that command line. They will
2416 come become after the body of the script (in sh) or after the name of
2417 the command to execute (in spawn).
2418 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2419 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2421 The return value consist of two strings: the action (sh, ...) and its args.
2423 If act is not one that calls an external command, then the given action merely
2426 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2427 /* Arrr! Here be memory leaks */
2428 gchar *actdup = g_strdup(actname);
2429 g_array_append_val(rets, actdup);
2431 if ((g_strcmp0(actname, "spawn") == 0) ||
2432 (g_strcmp0(actname, "sh") == 0) ||
2433 (g_strcmp0(actname, "sync_spawn") == 0) ||
2434 (g_strcmp0(actname, "sync_sh") == 0) ||
2435 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2437 GString *a = g_string_new("");
2438 gchar **spawnparts = split_quoted(origargs, FALSE);
2439 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2440 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2442 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2443 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2445 g_array_append_val(rets, a->str);
2446 g_string_free(a, FALSE);
2447 g_strfreev(spawnparts);
2449 gchar *origdup = g_strdup(origargs);
2450 g_array_append_val(rets, origdup);
2452 return (gchar**)g_array_free(rets, FALSE);
2456 run_handler (const gchar *act, const gchar *args) {
2457 /* Consider this code a temporary hack to make the handlers usable.
2458 In practice, all this splicing, injection, and reconstruction is
2459 inefficient, annoying and hard to manage. Potential pitfalls arise
2460 when the handler specific args 1) are not quoted (the handler
2461 callbacks should take care of this) 2) are quoted but interfere
2462 with the users' own quotation. A more ideal solution is
2463 to refactor parse_command so that it doesn't just take a string
2464 and execute it; rather than that, we should have a function which
2465 returns the argument vector parsed from the string. This vector
2466 could be modified (e.g. insert additional args into it) before
2467 passing it to the next function that actually executes it. Though
2468 it still isn't perfect for chain actions.. will reconsider & re-
2469 factor when I have the time. -duc */
2471 char **parts = g_strsplit(act, " ", 2);
2473 if (g_strcmp0(parts[0], "chain") == 0) {
2474 GString *newargs = g_string_new("");
2475 gchar **chainparts = split_quoted(parts[1], FALSE);
2477 /* for every argument in the chain, inject the handler args
2478 and make sure the new parts are wrapped in quotes */
2479 gchar **cp = chainparts;
2481 gchar *quotless = NULL;
2482 gchar **spliced_quotless = NULL; // sigh -_-;
2483 gchar **inpart = NULL;
2486 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2488 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2489 } else quotless = g_strdup(*cp);
2491 spliced_quotless = g_strsplit(quotless, " ", 2);
2492 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2493 g_strfreev(spliced_quotless);
2495 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2501 parse_command(parts[0], &(newargs->str[1]), NULL);
2502 g_string_free(newargs, TRUE);
2503 g_strfreev(chainparts);
2506 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2507 parse_command(inparts[0], inparts[1], NULL);
2515 add_binding (const gchar *key, const gchar *act) {
2516 char **parts = g_strsplit(act, " ", 2);
2523 if (uzbl.state.verbose)
2524 printf ("Binding %-10s : %s\n", key, act);
2525 action = new_action(parts[0], parts[1]);
2527 if (g_hash_table_remove (uzbl.bindings, key))
2528 g_warning ("Overwriting existing binding for \"%s\"", key);
2529 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2534 get_xdg_var (XDG_Var xdg) {
2535 const gchar* actual_value = getenv (xdg.environmental);
2536 const gchar* home = getenv ("HOME");
2537 gchar* return_value;
2539 if (! actual_value || strcmp (actual_value, "") == 0) {
2540 if (xdg.default_value) {
2541 return_value = str_replace ("~", home, xdg.default_value);
2543 return_value = NULL;
2546 return_value = str_replace("~", home, actual_value);
2549 return return_value;
2553 find_xdg_file (int xdg_type, const char* filename) {
2554 /* xdg_type = 0 => config
2555 xdg_type = 1 => data
2556 xdg_type = 2 => cache*/
2558 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2559 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2562 gchar* temporary_string;
2566 if (! file_exists (temporary_file) && xdg_type != 2) {
2567 buf = get_xdg_var (XDG[3 + xdg_type]);
2568 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2571 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2572 g_free (temporary_file);
2573 temporary_file = g_strconcat (temporary_string, filename, NULL);
2577 //g_free (temporary_string); - segfaults.
2579 if (file_exists (temporary_file)) {
2580 return temporary_file;
2582 g_free(temporary_file);
2588 State *s = &uzbl.state;
2589 Network *n = &uzbl.net;
2591 for (i = 0; default_config[i].command != NULL; i++) {
2592 parse_cmd_line(default_config[i].command, NULL);
2595 if (g_strcmp0(s->config_file, "-") == 0) {
2596 s->config_file = NULL;
2600 else if (!s->config_file) {
2601 s->config_file = find_xdg_file (0, "/uzbl/config");
2604 if (s->config_file) {
2605 GArray* lines = read_file_by_line (s->config_file);
2609 while ((line = g_array_index(lines, gchar*, i))) {
2610 parse_cmd_line (line, NULL);
2614 g_array_free (lines, TRUE);
2616 if (uzbl.state.verbose)
2617 printf ("No configuration file loaded.\n");
2620 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2623 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2626 if (!uzbl.behave.cookie_handler)
2629 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2630 GString *s = g_string_new ("");
2631 SoupURI * soup_uri = soup_message_get_uri(msg);
2632 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2633 run_handler(uzbl.behave.cookie_handler, s->str);
2635 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2636 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2637 if ( p != NULL ) *p = '\0';
2638 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2640 if (uzbl.comm.sync_stdout)
2641 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2643 g_string_free(s, TRUE);
2647 save_cookies (SoupMessage *msg, gpointer user_data){
2651 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2652 cookie = soup_cookie_to_set_cookie_header(ck->data);
2653 SoupURI * soup_uri = soup_message_get_uri(msg);
2654 GString *s = g_string_new ("");
2655 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2656 run_handler(uzbl.behave.cookie_handler, s->str);
2658 g_string_free(s, TRUE);
2663 /* --- WEBINSPECTOR --- */
2665 hide_window_cb(GtkWidget *widget, gpointer data) {
2668 gtk_widget_hide(widget);
2672 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2675 (void) web_inspector;
2676 GtkWidget* scrolled_window;
2677 GtkWidget* new_web_view;
2680 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2681 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2682 G_CALLBACK(hide_window_cb), NULL);
2684 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2685 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2686 gtk_widget_show(g->inspector_window);
2688 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2689 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2690 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2691 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2692 gtk_widget_show(scrolled_window);
2694 new_web_view = webkit_web_view_new();
2695 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2697 return WEBKIT_WEB_VIEW(new_web_view);
2701 inspector_show_window_cb (WebKitWebInspector* inspector){
2703 gtk_widget_show(uzbl.gui.inspector_window);
2707 /* TODO: Add variables and code to make use of these functions */
2709 inspector_close_window_cb (WebKitWebInspector* inspector){
2715 inspector_attach_window_cb (WebKitWebInspector* inspector){
2721 inspector_detach_window_cb (WebKitWebInspector* inspector){
2727 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2733 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2739 set_up_inspector() {
2741 WebKitWebSettings *settings = view_settings();
2742 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2744 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2745 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2746 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2747 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2748 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2749 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2750 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2752 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2756 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2758 uzbl_cmdprop *c = v;
2763 if(c->type == TYPE_STR)
2764 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2765 else if(c->type == TYPE_INT)
2766 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2767 else if(c->type == TYPE_FLOAT)
2768 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2772 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2776 printf("bind %s = %s %s\n", (char *)k ,
2777 (char *)a->name, a->param?(char *)a->param:"");
2782 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2783 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2787 retrieve_geometry() {
2789 GString *buf = g_string_new("");
2791 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2792 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2794 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2796 if(uzbl.gui.geometry)
2797 g_free(uzbl.gui.geometry);
2798 uzbl.gui.geometry = g_string_free(buf, FALSE);
2801 /* set up gtk, gobject, variable defaults and other things that tests and other
2802 * external applications need to do anyhow */
2804 initialize(int argc, char *argv[]) {
2805 if (!g_thread_supported ())
2806 g_thread_init (NULL);
2807 uzbl.state.executable_path = g_strdup(argv[0]);
2808 uzbl.state.selected_url = NULL;
2809 uzbl.state.searchtx = NULL;
2811 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2812 g_option_context_add_main_entries (context, entries, NULL);
2813 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2814 g_option_context_parse (context, &argc, &argv, NULL);
2815 g_option_context_free(context);
2817 if (uzbl.behave.print_version) {
2818 printf("Commit: %s\n", COMMIT);
2822 /* initialize hash table */
2823 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2825 uzbl.net.soup_session = webkit_get_default_session();
2826 uzbl.state.keycmd = g_strdup("");
2828 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2829 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2830 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2831 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2833 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2834 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2835 uzbl.gui.sbar.progress_w = 10;
2837 /* default mode indicators */
2838 uzbl.behave.insert_indicator = g_strdup("I");
2839 uzbl.behave.cmd_indicator = g_strdup("C");
2841 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2842 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2843 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2844 uzbl.info.arch = ARCH;
2845 uzbl.info.commit = COMMIT;
2848 make_var_to_name_hash();
2853 #ifndef UZBL_LIBRARY
2856 main (int argc, char* argv[]) {
2857 initialize(argc, argv);
2859 gtk_init (&argc, &argv);
2861 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2862 //main_window_ref = g_object_ref(scrolled_window);
2863 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2864 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2866 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2867 GTK_WIDGET (uzbl.gui.web_view));
2869 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2873 /* initial packing */
2874 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2875 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2877 if (uzbl.state.socket_id) {
2878 uzbl.gui.plug = create_plug ();
2879 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2880 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2882 uzbl.gui.main_window = create_window ();
2883 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2884 gtk_widget_show_all (uzbl.gui.main_window);
2885 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2888 if(!uzbl.state.instance_name)
2889 uzbl.state.instance_name = itos((int)uzbl.xwin);
2891 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2893 if (uzbl.state.verbose) {
2894 printf("Uzbl start location: %s\n", argv[0]);
2895 if (uzbl.state.socket_id)
2896 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2898 printf("window_id %i\n",(int) uzbl.xwin);
2899 printf("pid %i\n", getpid ());
2900 printf("name: %s\n", uzbl.state.instance_name);
2901 printf("commit: %s\n", uzbl.info.commit);
2904 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2905 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2906 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2907 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2908 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2910 /* Check uzbl is in window mode before getting/setting geometry */
2911 if (uzbl.gui.main_window) {
2912 if(uzbl.gui.geometry)
2915 retrieve_geometry();
2918 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2919 if (argc > 1 && !uzbl.state.uri)
2920 uri_override = g_strdup(argv[1]);
2921 gboolean verbose_override = uzbl.state.verbose;
2924 set_insert_mode(FALSE);
2926 if (!uzbl.behave.show_status)
2927 gtk_widget_hide(uzbl.gui.mainbar);
2934 if (verbose_override > uzbl.state.verbose)
2935 uzbl.state.verbose = verbose_override;
2938 set_var_value("uri", uri_override);
2939 g_free(uri_override);
2940 } else if (uzbl.state.uri)
2946 return EXIT_SUCCESS;
2950 /* vi: set et ts=4: */