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 */
608 GString *args = g_string_new(uri);
610 if (uzbl.net.proxy_url) {
611 g_string_append_c(args, ' ');
612 g_string_append(args, uzbl.net.proxy_url);
615 run_handler(uzbl.behave.download_handler, args->str);
617 g_string_free(args, TRUE);
622 /* scroll a bar in a given direction */
624 scroll (GtkAdjustment* bar, GArray *argv) {
628 gdouble page_size = gtk_adjustment_get_page_size(bar);
629 gdouble value = gtk_adjustment_get_value(bar);
630 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
633 value += page_size * amount * 0.01;
637 max_value = gtk_adjustment_get_upper(bar) - page_size;
639 if (value > max_value)
640 value = max_value; /* don't scroll past the end of the page */
642 gtk_adjustment_set_value (bar, value);
646 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
647 (void) page; (void) argv; (void) result;
648 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
652 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
653 (void) page; (void) argv; (void) result;
654 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
655 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
659 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
660 (void) page; (void) result;
661 scroll(uzbl.gui.bar_v, argv);
665 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
666 (void) page; (void) result;
667 scroll(uzbl.gui.bar_h, argv);
672 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
673 if(uzbl.state.verbose)
674 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
676 /* update geometry var with the actual geometry
677 this is necessary as some WMs don't seem to honour
678 the above setting and we don't want to end up with
679 wrong geometry information
686 if (!uzbl.behave.show_status) {
687 gtk_widget_hide(uzbl.gui.mainbar);
689 gtk_widget_show(uzbl.gui.mainbar);
695 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
700 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
704 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
709 if (uzbl.behave.show_status) {
710 gtk_widget_hide(uzbl.gui.mainbar);
712 gtk_widget_show(uzbl.gui.mainbar);
714 uzbl.behave.show_status = !uzbl.behave.show_status;
719 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
723 //Set selected_url state variable
724 g_free(uzbl.state.selected_url);
725 uzbl.state.selected_url = NULL;
727 uzbl.state.selected_url = g_strdup(link);
733 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
736 const gchar *title = webkit_web_view_get_title(web_view);
737 if (uzbl.gui.main_title)
738 g_free (uzbl.gui.main_title);
739 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
744 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
747 uzbl.gui.sbar.load_progress = progress;
749 g_free(uzbl.gui.sbar.progress_bar);
750 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
756 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
760 if (uzbl.behave.load_finish_handler)
761 run_handler(uzbl.behave.load_finish_handler, "");
764 void clear_keycmd() {
765 g_free(uzbl.state.keycmd);
766 uzbl.state.keycmd = g_strdup("");
770 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
774 uzbl.gui.sbar.load_progress = 0;
775 clear_keycmd(); // don't need old commands to remain on new page?
776 if (uzbl.behave.load_start_handler)
777 run_handler(uzbl.behave.load_start_handler, "");
781 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
784 g_free (uzbl.state.uri);
785 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
786 uzbl.state.uri = g_string_free (newuri, FALSE);
787 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
788 set_insert_mode(uzbl.behave.always_insert_mode);
791 if (uzbl.behave.load_commit_handler)
792 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
796 destroy_cb (GtkWidget* widget, gpointer data) {
804 if (uzbl.behave.history_handler) {
806 struct tm * timeinfo;
809 timeinfo = localtime ( &rawtime );
810 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
811 run_handler(uzbl.behave.history_handler, date);
816 /* VIEW funcs (little webkit wrappers) */
817 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
819 VIEWFUNC(reload_bypass_cache)
820 VIEWFUNC(stop_loading)
827 /* -- command to callback/function map for things we cannot attach to any signals */
828 struct {const char *key; CommandInfo value;} cmdlist[] =
829 { /* key function no_split */
830 { "back", {view_go_back, 0} },
831 { "forward", {view_go_forward, 0} },
832 { "scroll_vert", {scroll_vert, 0} },
833 { "scroll_horz", {scroll_horz, 0} },
834 { "scroll_begin", {scroll_begin, 0} },
835 { "scroll_end", {scroll_end, 0} },
836 { "reload", {view_reload, 0}, },
837 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
838 { "stop", {view_stop_loading, 0}, },
839 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
840 { "zoom_out", {view_zoom_out, 0}, },
841 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
842 { "uri", {load_uri, TRUE} },
843 { "js", {run_js, TRUE} },
844 { "script", {run_external_js, 0} },
845 { "toggle_status", {toggle_status_cb, 0} },
846 { "spawn", {spawn, 0} },
847 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
848 { "sh", {spawn_sh, 0} },
849 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
850 { "talk_to_socket", {talk_to_socket, 0} },
851 { "exit", {close_uzbl, 0} },
852 { "search", {search_forward_text, TRUE} },
853 { "search_reverse", {search_reverse_text, TRUE} },
854 { "dehilight", {dehilight, 0} },
855 { "toggle_insert_mode", {toggle_insert_mode, 0} },
856 { "set", {set_var, TRUE} },
857 //{ "get", {get_var, TRUE} },
858 { "bind", {act_bind, TRUE} },
859 { "dump_config", {act_dump_config, 0} },
860 { "keycmd", {keycmd, TRUE} },
861 { "keycmd_nl", {keycmd_nl, TRUE} },
862 { "keycmd_bs", {keycmd_bs, 0} },
863 { "chain", {chain, 0} },
864 { "print", {print, TRUE} },
865 { "update_gui", {update_gui, TRUE} }
872 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
874 for (i = 0; i < LENGTH(cmdlist); i++)
875 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
878 /* -- CORE FUNCTIONS -- */
881 free_action(gpointer act) {
882 Action *action = (Action*)act;
883 g_free(action->name);
885 g_free(action->param);
890 new_action(const gchar *name, const gchar *param) {
891 Action *action = g_new(Action, 1);
893 action->name = g_strdup(name);
895 action->param = g_strdup(param);
897 action->param = NULL;
903 file_exists (const char * filename) {
904 return (access(filename, F_OK) == 0);
908 set_var(WebKitWebView *page, GArray *argv, GString *result) {
909 (void) page; (void) result;
910 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
911 if (split[0] != NULL) {
912 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
913 set_var_value(g_strstrip(split[0]), value);
920 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
921 (void) page; (void) argv; (void) result;
927 print(WebKitWebView *page, GArray *argv, GString *result) {
928 (void) page; (void) result;
931 buf = expand(argv_idx(argv, 0), 0);
932 g_string_assign(result, buf);
937 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
938 (void) page; (void) result;
939 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
940 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
941 add_binding(g_strstrip(split[0]), value);
959 set_mode_indicator() {
960 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
961 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
966 set_mode_indicator();
971 set_insert_mode(gboolean mode) {
972 uzbl.behave.insert_mode = mode;
973 set_mode_indicator();
977 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
978 (void) page; (void) result;
980 if (argv_idx(argv, 0)) {
981 if (strcmp (argv_idx(argv, 0), "0") == 0) {
982 set_insert_mode(FALSE);
984 set_insert_mode(TRUE);
987 set_insert_mode( !uzbl.behave.insert_mode );
994 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
997 if (argv_idx(argv, 0)) {
998 GString* newuri = g_string_new (argv_idx(argv, 0));
999 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
1000 run_js(web_view, argv, NULL);
1003 if (!soup_uri_new(argv_idx(argv, 0)))
1004 g_string_prepend (newuri, "http://");
1005 /* if we do handle cookies, ask our handler for them */
1006 webkit_web_view_load_uri (web_view, newuri->str);
1007 g_string_free (newuri, TRUE);
1014 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
1015 size_t argumentCount, const JSValueRef arguments[],
1016 JSValueRef* exception) {
1021 JSStringRef js_result_string;
1022 GString *result = g_string_new("");
1024 if (argumentCount >= 1) {
1025 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1026 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1027 char ctl_line[arg_size];
1028 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1030 parse_cmd_line(ctl_line, result);
1032 JSStringRelease(arg);
1034 js_result_string = JSStringCreateWithUTF8CString(result->str);
1036 g_string_free(result, TRUE);
1038 return JSValueMakeString(ctx, js_result_string);
1041 JSStaticFunction js_static_functions[] = {
1042 {"run", js_run_command, kJSPropertyAttributeNone},
1047 /* This function creates the class and its definition, only once */
1048 if (!uzbl.js.initialized) {
1049 /* it would be pretty cool to make this dynamic */
1050 uzbl.js.classdef = kJSClassDefinitionEmpty;
1051 uzbl.js.classdef.staticFunctions = js_static_functions;
1053 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1059 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1060 WebKitWebFrame *frame;
1061 JSGlobalContextRef context;
1062 JSObjectRef globalobject;
1063 JSStringRef var_name;
1065 JSStringRef js_script;
1066 JSValueRef js_result;
1067 JSStringRef js_result_string;
1068 size_t js_result_size;
1072 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1073 context = webkit_web_frame_get_global_context(frame);
1074 globalobject = JSContextGetGlobalObject(context);
1076 /* uzbl javascript namespace */
1077 var_name = JSStringCreateWithUTF8CString("Uzbl");
1078 JSObjectSetProperty(context, globalobject, var_name,
1079 JSObjectMake(context, uzbl.js.classref, NULL),
1080 kJSClassAttributeNone, NULL);
1082 /* evaluate the script and get return value*/
1083 js_script = JSStringCreateWithUTF8CString(script);
1084 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1085 if (js_result && !JSValueIsUndefined(context, js_result)) {
1086 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1087 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1089 if (js_result_size) {
1090 char js_result_utf8[js_result_size];
1091 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1092 g_string_assign(result, js_result_utf8);
1095 JSStringRelease(js_result_string);
1099 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1101 JSStringRelease(var_name);
1102 JSStringRelease(js_script);
1106 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1107 if (argv_idx(argv, 0))
1108 eval_js(web_view, argv_idx(argv, 0), result);
1112 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1114 if (argv_idx(argv, 0)) {
1115 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1120 while ((line = g_array_index(lines, gchar*, i))) {
1122 js = g_strdup (line);
1124 gchar* newjs = g_strconcat (js, line, NULL);
1131 if (uzbl.state.verbose)
1132 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1134 if (argv_idx (argv, 1)) {
1135 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1139 eval_js (web_view, js, result);
1141 g_array_free (lines, TRUE);
1146 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1147 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1148 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1149 webkit_web_view_unmark_text_matches (page);
1150 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1151 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1155 if (uzbl.state.searchtx) {
1156 if (uzbl.state.verbose)
1157 printf ("Searching: %s\n", uzbl.state.searchtx);
1158 webkit_web_view_set_highlight_text_matches (page, TRUE);
1159 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1164 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1166 search_text(page, argv, TRUE);
1170 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1172 search_text(page, argv, FALSE);
1176 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1177 (void) argv; (void) result;
1178 webkit_web_view_set_highlight_text_matches (page, FALSE);
1183 new_window_load_uri (const gchar * uri) {
1184 if (uzbl.behave.new_window) {
1185 GString *s = g_string_new ("");
1186 g_string_printf(s, "'%s'", uri);
1187 run_handler(uzbl.behave.new_window, s->str);
1190 GString* to_execute = g_string_new ("");
1191 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1193 for (i = 0; entries[i].long_name != NULL; i++) {
1194 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1195 gchar** str = (gchar**)entries[i].arg_data;
1197 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1201 if (uzbl.state.verbose)
1202 printf("\n%s\n", to_execute->str);
1203 g_spawn_command_line_async (to_execute->str, NULL);
1204 g_string_free (to_execute, TRUE);
1208 chain (WebKitWebView *page, GArray *argv, GString *result) {
1209 (void) page; (void) result;
1211 gchar **parts = NULL;
1213 while ((a = argv_idx(argv, i++))) {
1214 parts = g_strsplit (a, " ", 2);
1216 parse_command(parts[0], parts[1], result);
1222 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1226 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1232 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1236 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1242 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1247 int len = strlen(uzbl.state.keycmd);
1248 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1250 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1255 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1262 /* --Statusbar functions-- */
1264 build_progressbar_ascii(int percent) {
1265 int width=uzbl.gui.sbar.progress_w;
1268 GString *bar = g_string_new("");
1270 l = (double)percent*((double)width/100.);
1271 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1273 for(i=0; i<(int)l; i++)
1274 g_string_append(bar, uzbl.gui.sbar.progress_s);
1277 g_string_append(bar, uzbl.gui.sbar.progress_u);
1279 return g_string_free(bar, FALSE);
1281 /* --End Statusbar functions-- */
1284 sharg_append(GArray *a, const gchar *str) {
1285 const gchar *s = (str ? str : "");
1286 g_array_append_val(a, s);
1289 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1291 run_command (const gchar *command, const guint npre, const gchar **args,
1292 const gboolean sync, char **output_stdout) {
1293 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1296 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1297 gchar *pid = itos(getpid());
1298 gchar *xwin = itos(uzbl.xwin);
1300 sharg_append(a, command);
1301 for (i = 0; i < npre; i++) /* add n args before the default vars */
1302 sharg_append(a, args[i]);
1303 sharg_append(a, uzbl.state.config_file);
1304 sharg_append(a, pid);
1305 sharg_append(a, xwin);
1306 sharg_append(a, uzbl.comm.fifo_path);
1307 sharg_append(a, uzbl.comm.socket_path);
1308 sharg_append(a, uzbl.state.uri);
1309 sharg_append(a, uzbl.gui.main_title);
1311 for (i = npre; i < g_strv_length((gchar**)args); i++)
1312 sharg_append(a, args[i]);
1316 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1318 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1319 NULL, NULL, output_stdout, NULL, NULL, &err);
1320 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1321 NULL, NULL, NULL, &err);
1323 if (uzbl.state.verbose) {
1324 GString *s = g_string_new("spawned:");
1325 for (i = 0; i < (a->len); i++) {
1326 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1327 g_string_append_printf(s, " %s", qarg);
1330 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1331 printf("%s\n", s->str);
1332 g_string_free(s, TRUE);
1334 printf("Stdout: %s\n", *output_stdout);
1338 g_printerr("error on run_command: %s\n", err->message);
1343 g_array_free (a, TRUE);
1348 split_quoted(const gchar* src, const gboolean unquote) {
1349 /* split on unquoted space, return array of strings;
1350 remove a layer of quotes and backslashes if unquote */
1351 if (!src) return NULL;
1353 gboolean dq = FALSE;
1354 gboolean sq = FALSE;
1355 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1356 GString *s = g_string_new ("");
1360 for (p = src; *p != '\0'; p++) {
1361 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1362 else if (*p == '\\') { g_string_append_c(s, *p++);
1363 g_string_append_c(s, *p); }
1364 else if ((*p == '"') && unquote && !sq) dq = !dq;
1365 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1367 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1368 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1370 else if ((*p == ' ') && !dq && !sq) {
1371 dup = g_strdup(s->str);
1372 g_array_append_val(a, dup);
1373 g_string_truncate(s, 0);
1374 } else g_string_append_c(s, *p);
1376 dup = g_strdup(s->str);
1377 g_array_append_val(a, dup);
1378 ret = (gchar**)a->data;
1379 g_array_free (a, FALSE);
1380 g_string_free (s, TRUE);
1385 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1386 (void)web_view; (void)result;
1387 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1388 if (argv_idx(argv, 0))
1389 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1393 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1394 (void)web_view; (void)result;
1396 if (argv_idx(argv, 0))
1397 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1398 TRUE, &uzbl.comm.sync_stdout);
1402 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1403 (void)web_view; (void)result;
1404 if (!uzbl.behave.shell_cmd) {
1405 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1410 gchar *spacer = g_strdup("");
1411 g_array_insert_val(argv, 1, spacer);
1412 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1414 for (i = 1; i < g_strv_length(cmd); i++)
1415 g_array_prepend_val(argv, cmd[i]);
1417 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1423 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1424 (void)web_view; (void)result;
1425 if (!uzbl.behave.shell_cmd) {
1426 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1431 gchar *spacer = g_strdup("");
1432 g_array_insert_val(argv, 1, spacer);
1433 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1435 for (i = 1; i < g_strv_length(cmd); i++)
1436 g_array_prepend_val(argv, cmd[i]);
1438 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1439 TRUE, &uzbl.comm.sync_stdout);
1445 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1446 (void)web_view; (void)result;
1449 struct sockaddr_un sa;
1456 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1458 /* This function could be optimised by storing a hash table of socket paths
1459 and associated connected file descriptors rather than closing and
1460 re-opening for every call. Also we could launch a script if socket connect
1463 /* First element argv[0] is path to socket. Following elements are tokens to
1464 write to the socket. We write them as a single packet with each token
1465 separated by an ASCII nul (\0). */
1467 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1472 /* copy socket path, null terminate result */
1473 sockpath = g_array_index(argv, char*, 0);
1474 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1475 sa.sun_family = AF_UNIX;
1477 /* create socket file descriptor and connect it to path */
1478 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1480 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1483 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1484 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1489 /* build request vector */
1490 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1492 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1496 for(i = 1; i < argv->len; ++i) {
1497 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1498 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1502 ret = writev(fd, iov, argv->len - 1);
1505 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1510 /* wait for a response, with a 500ms timeout */
1512 pfd.events = POLLIN;
1514 ret = poll(&pfd, 1, 500);
1516 if(ret == 0) errno = ETIMEDOUT;
1517 if(errno == EINTR) continue;
1518 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1524 /* get length of response */
1525 if(ioctl(fd, FIONREAD, &len) == -1) {
1526 g_printerr("talk_to_socket: cannot find daemon response length, "
1527 "ioctl failed (%s)\n", strerror(errno));
1532 /* if there is a response, read it */
1534 uzbl.comm.sync_stdout = g_malloc(len + 1);
1535 if(!uzbl.comm.sync_stdout) {
1536 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1540 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1542 ret = read(fd, uzbl.comm.sync_stdout, len);
1544 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1557 parse_command(const char *cmd, const char *param, GString *result) {
1560 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1562 gchar **par = split_quoted(param, TRUE);
1563 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1565 if (c->no_split) { /* don't split */
1566 sharg_append(a, param);
1568 for (i = 0; i < g_strv_length(par); i++)
1569 sharg_append(a, par[i]);
1572 if (result == NULL) {
1573 GString *result_print = g_string_new("");
1575 c->function(uzbl.gui.web_view, a, result_print);
1576 if (result_print->len)
1577 printf("%*s\n", (int)result_print->len, result_print->str);
1579 g_string_free(result_print, TRUE);
1581 c->function(uzbl.gui.web_view, a, result);
1584 g_array_free (a, TRUE);
1587 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1594 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1595 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1596 (GType) SOUP_SESSION_PROXY_URI);
1599 suri = soup_uri_new(uzbl.net.proxy_url);
1600 g_object_set(G_OBJECT(uzbl.net.soup_session),
1601 SOUP_SESSION_PROXY_URI,
1603 soup_uri_free(suri);
1610 if(file_exists(uzbl.gui.icon)) {
1611 if (uzbl.gui.main_window)
1612 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1614 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1620 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1621 g_array_append_val (a, uzbl.state.uri);
1622 load_uri(uzbl.gui.web_view, a, NULL);
1623 g_array_free (a, TRUE);
1627 cmd_always_insert_mode() {
1628 set_insert_mode(uzbl.behave.always_insert_mode);
1634 g_object_set(G_OBJECT(uzbl.net.soup_session),
1635 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1639 cmd_max_conns_host() {
1640 g_object_set(G_OBJECT(uzbl.net.soup_session),
1641 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1646 soup_session_remove_feature
1647 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1648 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1649 /*g_free(uzbl.net.soup_logger);*/
1651 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1652 soup_session_add_feature(uzbl.net.soup_session,
1653 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1658 return webkit_web_view_get_settings(uzbl.gui.web_view);
1663 WebKitWebSettings *ws = view_settings();
1664 if (uzbl.behave.font_size > 0) {
1665 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1668 if (uzbl.behave.monospace_size > 0) {
1669 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1670 uzbl.behave.monospace_size, NULL);
1672 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1673 uzbl.behave.font_size, NULL);
1678 cmd_default_font_family() {
1679 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1680 uzbl.behave.default_font_family, NULL);
1684 cmd_monospace_font_family() {
1685 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1686 uzbl.behave.monospace_font_family, NULL);
1690 cmd_sans_serif_font_family() {
1691 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1692 uzbl.behave.sans_serif_font_family, NULL);
1696 cmd_serif_font_family() {
1697 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1698 uzbl.behave.serif_font_family, NULL);
1702 cmd_cursive_font_family() {
1703 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1704 uzbl.behave.cursive_font_family, NULL);
1708 cmd_fantasy_font_family() {
1709 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1710 uzbl.behave.fantasy_font_family, NULL);
1715 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1719 cmd_disable_plugins() {
1720 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1721 !uzbl.behave.disable_plugins, NULL);
1725 cmd_disable_scripts() {
1726 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1727 !uzbl.behave.disable_scripts, NULL);
1731 cmd_minimum_font_size() {
1732 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1733 uzbl.behave.minimum_font_size, NULL);
1736 cmd_autoload_img() {
1737 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1738 uzbl.behave.autoload_img, NULL);
1743 cmd_autoshrink_img() {
1744 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1745 uzbl.behave.autoshrink_img, NULL);
1750 cmd_enable_spellcheck() {
1751 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1752 uzbl.behave.enable_spellcheck, NULL);
1756 cmd_enable_private() {
1757 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1758 uzbl.behave.enable_private, NULL);
1763 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1764 uzbl.behave.print_bg, NULL);
1769 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1770 uzbl.behave.style_uri, NULL);
1774 cmd_resizable_txt() {
1775 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1776 uzbl.behave.resizable_txt, NULL);
1780 cmd_default_encoding() {
1781 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1782 uzbl.behave.default_encoding, NULL);
1786 cmd_enforce_96dpi() {
1787 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1788 uzbl.behave.enforce_96dpi, NULL);
1792 cmd_caret_browsing() {
1793 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1794 uzbl.behave.caret_browsing, NULL);
1798 cmd_cookie_handler() {
1799 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1800 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1801 if ((g_strcmp0(split[0], "sh") == 0) ||
1802 (g_strcmp0(split[0], "spawn") == 0)) {
1803 g_free (uzbl.behave.cookie_handler);
1804 uzbl.behave.cookie_handler =
1805 g_strdup_printf("sync_%s %s", split[0], split[1]);
1811 cmd_scheme_handler() {
1812 gchar **split = g_strsplit(uzbl.behave.scheme_handler, " ", 2);
1813 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1814 if ((g_strcmp0(split[0], "sh") == 0) ||
1815 (g_strcmp0(split[0], "spawn") == 0)) {
1816 g_free (uzbl.behave.scheme_handler);
1817 uzbl.behave.scheme_handler =
1818 g_strdup_printf("sync_%s %s", split[0], split[1]);
1825 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1830 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1835 if(uzbl.behave.inject_html) {
1836 webkit_web_view_load_html_string (uzbl.gui.web_view,
1837 uzbl.behave.inject_html, NULL);
1846 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1847 uzbl.behave.modmask = 0;
1849 if(uzbl.behave.modkey)
1850 g_free(uzbl.behave.modkey);
1851 uzbl.behave.modkey = buf;
1853 for (i = 0; modkeys[i].key != NULL; i++) {
1854 if (g_strrstr(buf, modkeys[i].key))
1855 uzbl.behave.modmask |= modkeys[i].mask;
1861 if (*uzbl.net.useragent == ' ') {
1862 g_free (uzbl.net.useragent);
1863 uzbl.net.useragent = NULL;
1865 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1866 uzbl.net.useragent, NULL);
1872 if (!uzbl.gui.scrolled_win &&
1876 gtk_widget_ref(uzbl.gui.scrolled_win);
1877 gtk_widget_ref(uzbl.gui.mainbar);
1878 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1879 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1881 if(uzbl.behave.status_top) {
1882 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1883 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1886 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1887 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1889 gtk_widget_unref(uzbl.gui.scrolled_win);
1890 gtk_widget_unref(uzbl.gui.mainbar);
1891 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1896 set_var_value(const gchar *name, gchar *val) {
1897 uzbl_cmdprop *c = NULL;
1900 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1902 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1903 if(!c->writeable) return FALSE;
1905 /* check for the variable type */
1906 if (c->type == TYPE_STR) {
1907 buf = expand(val, 0);
1910 } else if(c->type == TYPE_INT) {
1911 buf = expand(val, 0);
1912 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1914 } else if (c->type == TYPE_FLOAT) {
1915 buf = expand(val, 0);
1916 *c->ptr.f = strtod(buf, &endp);
1920 /* invoke a command specific function */
1921 if(c->func) c->func();
1923 /* check wether name violates our naming scheme */
1924 if(strpbrk(name, invalid_chars)) {
1925 if (uzbl.state.verbose)
1926 printf("Invalid variable name\n");
1931 c = malloc(sizeof(uzbl_cmdprop));
1936 buf = expand(val, 0);
1937 c->ptr.s = malloc(sizeof(char *));
1939 g_hash_table_insert(uzbl.comm.proto_var,
1940 g_strdup(name), (gpointer) c);
1945 enum {M_CMD, M_HTML};
1947 parse_cmd_line(const char *ctl_line, GString *result) {
1950 if((ctl_line[0] == '#') /* Comments */
1951 || (ctl_line[0] == ' ')
1952 || (ctl_line[0] == '\n'))
1953 ; /* ignore these lines */
1954 else { /* parse a command */
1956 gchar **tokens = NULL;
1957 len = strlen(ctl_line);
1959 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1960 ctlstrip = g_strndup(ctl_line, len - 1);
1961 else ctlstrip = g_strdup(ctl_line);
1963 tokens = g_strsplit(ctlstrip, " ", 2);
1964 parse_command(tokens[0], tokens[1], result);
1971 build_stream_name(int type, const gchar* dir) {
1972 State *s = &uzbl.state;
1976 str = g_strdup_printf
1977 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1978 } else if (type == SOCKET) {
1979 str = g_strdup_printf
1980 ("%s/uzbl_socket_%s", dir, s->instance_name);
1986 control_fifo(GIOChannel *gio, GIOCondition condition) {
1987 if (uzbl.state.verbose)
1988 printf("triggered\n");
1993 if (condition & G_IO_HUP)
1994 g_error ("Fifo: Read end of pipe died!\n");
1997 g_error ("Fifo: GIOChannel broke\n");
1999 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2000 if (ret == G_IO_STATUS_ERROR) {
2001 g_error ("Fifo: Error reading: %s\n", err->message);
2005 parse_cmd_line(ctl_line, NULL);
2012 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2013 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2014 if (unlink(uzbl.comm.fifo_path) == -1)
2015 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2016 g_free(uzbl.comm.fifo_path);
2017 uzbl.comm.fifo_path = NULL;
2020 GIOChannel *chan = NULL;
2021 GError *error = NULL;
2022 gchar *path = build_stream_name(FIFO, dir);
2024 if (!file_exists(path)) {
2025 if (mkfifo (path, 0666) == 0) {
2026 // 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.
2027 chan = g_io_channel_new_file(path, "r+", &error);
2029 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2030 if (uzbl.state.verbose)
2031 printf ("init_fifo: created successfully as %s\n", path);
2032 uzbl.comm.fifo_path = path;
2034 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2035 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2036 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2037 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2039 /* if we got this far, there was an error; cleanup */
2040 if (error) g_error_free (error);
2047 control_stdin(GIOChannel *gio, GIOCondition condition) {
2049 gchar *ctl_line = NULL;
2052 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2053 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2056 parse_cmd_line(ctl_line, NULL);
2064 GIOChannel *chan = NULL;
2065 GError *error = NULL;
2067 chan = g_io_channel_unix_new(fileno(stdin));
2069 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2070 g_error ("Stdin: could not add watch\n");
2072 if (uzbl.state.verbose)
2073 printf ("Stdin: watch added successfully\n");
2076 g_error ("Stdin: Error while opening: %s\n", error->message);
2078 if (error) g_error_free (error);
2082 control_socket(GIOChannel *chan) {
2083 struct sockaddr_un remote;
2084 unsigned int t = sizeof(remote);
2086 GIOChannel *clientchan;
2088 clientsock = accept (g_io_channel_unix_get_fd(chan),
2089 (struct sockaddr *) &remote, &t);
2091 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2092 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2093 (GIOFunc) control_client_socket, clientchan);
2100 control_client_socket(GIOChannel *clientchan) {
2102 GString *result = g_string_new("");
2103 GError *error = NULL;
2107 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2108 if (ret == G_IO_STATUS_ERROR) {
2109 g_warning ("Error reading: %s\n", error->message);
2110 g_io_channel_shutdown(clientchan, TRUE, &error);
2112 } else if (ret == G_IO_STATUS_EOF) {
2113 /* shutdown and remove channel watch from main loop */
2114 g_io_channel_shutdown(clientchan, TRUE, &error);
2119 parse_cmd_line (ctl_line, result);
2120 g_string_append_c(result, '\n');
2121 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2123 if (ret == G_IO_STATUS_ERROR) {
2124 g_warning ("Error writing: %s", error->message);
2126 g_io_channel_flush(clientchan, &error);
2129 if (error) g_error_free (error);
2130 g_string_free(result, TRUE);
2136 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2137 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2138 if (unlink(uzbl.comm.socket_path) == -1)
2139 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2140 g_free(uzbl.comm.socket_path);
2141 uzbl.comm.socket_path = NULL;
2149 GIOChannel *chan = NULL;
2151 struct sockaddr_un local;
2152 gchar *path = build_stream_name(SOCKET, dir);
2154 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2156 local.sun_family = AF_UNIX;
2157 strcpy (local.sun_path, path);
2158 unlink (local.sun_path);
2160 len = strlen (local.sun_path) + sizeof (local.sun_family);
2161 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2162 if (uzbl.state.verbose)
2163 printf ("init_socket: opened in %s\n", path);
2166 if( (chan = g_io_channel_unix_new(sock)) ) {
2167 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2168 uzbl.comm.socket_path = path;
2171 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2173 /* if we got this far, there was an error; cleanup */
2180 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2181 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2183 // this function may be called very early when the templates are not set (yet), hence the checks
2185 update_title (void) {
2186 Behaviour *b = &uzbl.behave;
2189 if (b->show_status) {
2190 if (b->title_format_short) {
2191 parsed = expand(b->title_format_short, 0);
2192 if (uzbl.gui.main_window)
2193 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2196 if (b->status_format) {
2197 parsed = expand(b->status_format, 0);
2198 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2201 if (b->status_background) {
2203 gdk_color_parse (b->status_background, &color);
2204 //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)
2205 if (uzbl.gui.main_window)
2206 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2207 else if (uzbl.gui.plug)
2208 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2211 if (b->title_format_long) {
2212 parsed = expand(b->title_format_long, 0);
2213 if (uzbl.gui.main_window)
2214 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2221 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2225 retrieve_geometry();
2230 key_press_cb (GtkWidget* window, GdkEventKey* event)
2232 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2236 if (event->type != GDK_KEY_PRESS ||
2237 event->keyval == GDK_Page_Up ||
2238 event->keyval == GDK_Page_Down ||
2239 event->keyval == GDK_Up ||
2240 event->keyval == GDK_Down ||
2241 event->keyval == GDK_Left ||
2242 event->keyval == GDK_Right ||
2243 event->keyval == GDK_Shift_L ||
2244 event->keyval == GDK_Shift_R)
2247 /* turn off insert mode (if always_insert_mode is not used) */
2248 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2249 set_insert_mode(uzbl.behave.always_insert_mode);
2254 if (uzbl.behave.insert_mode &&
2255 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2256 (!uzbl.behave.modmask)
2261 if (event->keyval == GDK_Escape) {
2264 dehilight(uzbl.gui.web_view, NULL, NULL);
2268 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2269 if (event->keyval == GDK_Insert) {
2271 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2272 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2274 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2277 GString* keycmd = g_string_new(uzbl.state.keycmd);
2278 g_string_append (keycmd, str);
2279 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2286 if (event->keyval == GDK_BackSpace)
2287 keycmd_bs(NULL, NULL, NULL);
2289 gboolean key_ret = FALSE;
2290 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2293 GString* keycmd = g_string_new(uzbl.state.keycmd);
2294 g_string_append(keycmd, event->string);
2295 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2298 run_keycmd(key_ret);
2300 if (key_ret) return (!uzbl.behave.insert_mode);
2305 run_keycmd(const gboolean key_ret) {
2306 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2308 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2310 parse_command(act->name, act->param, NULL);
2314 /* try if it's an incremental keycmd or one that takes args, and run it */
2315 GString* short_keys = g_string_new ("");
2316 GString* short_keys_inc = g_string_new ("");
2318 guint len = strlen(uzbl.state.keycmd);
2319 for (i=0; i<len; i++) {
2320 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2321 g_string_assign(short_keys_inc, short_keys->str);
2322 g_string_append_c(short_keys, '_');
2323 g_string_append_c(short_keys_inc, '*');
2325 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2326 /* run normal cmds only if return was pressed */
2327 exec_paramcmd(act, i);
2330 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2331 if (key_ret) /* just quit the incremental command on return */
2333 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2337 g_string_truncate(short_keys, short_keys->len - 1);
2339 g_string_free (short_keys, TRUE);
2340 g_string_free (short_keys_inc, TRUE);
2344 exec_paramcmd(const Action *act, const guint i) {
2345 GString *parampart = g_string_new (uzbl.state.keycmd);
2346 GString *actionname = g_string_new ("");
2347 GString *actionparam = g_string_new ("");
2348 g_string_erase (parampart, 0, i+1);
2350 g_string_printf (actionname, act->name, parampart->str);
2352 g_string_printf (actionparam, act->param, parampart->str);
2353 parse_command(actionname->str, actionparam->str, NULL);
2354 g_string_free(actionname, TRUE);
2355 g_string_free(actionparam, TRUE);
2356 g_string_free(parampart, TRUE);
2364 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2366 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2367 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2368 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2369 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2370 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2371 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2372 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2373 g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2384 g->mainbar = gtk_hbox_new (FALSE, 0);
2386 /* keep a reference to the bar so we can re-pack it at runtime*/
2387 //sbar_ref = g_object_ref(g->mainbar);
2389 g->mainbar_label = gtk_label_new ("");
2390 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2391 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2392 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2393 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2394 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2395 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2401 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2402 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2403 gtk_widget_set_name (window, "Uzbl browser");
2404 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2405 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2406 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2413 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2414 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2415 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2422 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2424 If actname is one that calls an external command, this function will inject
2425 newargs in front of the user-provided args in that command line. They will
2426 come become after the body of the script (in sh) or after the name of
2427 the command to execute (in spawn).
2428 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2429 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2431 The return value consist of two strings: the action (sh, ...) and its args.
2433 If act is not one that calls an external command, then the given action merely
2436 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2437 /* Arrr! Here be memory leaks */
2438 gchar *actdup = g_strdup(actname);
2439 g_array_append_val(rets, actdup);
2441 if ((g_strcmp0(actname, "spawn") == 0) ||
2442 (g_strcmp0(actname, "sh") == 0) ||
2443 (g_strcmp0(actname, "sync_spawn") == 0) ||
2444 (g_strcmp0(actname, "sync_sh") == 0) ||
2445 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2447 GString *a = g_string_new("");
2448 gchar **spawnparts = split_quoted(origargs, FALSE);
2449 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2450 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2452 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2453 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2455 g_array_append_val(rets, a->str);
2456 g_string_free(a, FALSE);
2457 g_strfreev(spawnparts);
2459 gchar *origdup = g_strdup(origargs);
2460 g_array_append_val(rets, origdup);
2462 return (gchar**)g_array_free(rets, FALSE);
2466 run_handler (const gchar *act, const gchar *args) {
2467 /* Consider this code a temporary hack to make the handlers usable.
2468 In practice, all this splicing, injection, and reconstruction is
2469 inefficient, annoying and hard to manage. Potential pitfalls arise
2470 when the handler specific args 1) are not quoted (the handler
2471 callbacks should take care of this) 2) are quoted but interfere
2472 with the users' own quotation. A more ideal solution is
2473 to refactor parse_command so that it doesn't just take a string
2474 and execute it; rather than that, we should have a function which
2475 returns the argument vector parsed from the string. This vector
2476 could be modified (e.g. insert additional args into it) before
2477 passing it to the next function that actually executes it. Though
2478 it still isn't perfect for chain actions.. will reconsider & re-
2479 factor when I have the time. -duc */
2481 char **parts = g_strsplit(act, " ", 2);
2483 if (g_strcmp0(parts[0], "chain") == 0) {
2484 GString *newargs = g_string_new("");
2485 gchar **chainparts = split_quoted(parts[1], FALSE);
2487 /* for every argument in the chain, inject the handler args
2488 and make sure the new parts are wrapped in quotes */
2489 gchar **cp = chainparts;
2491 gchar *quotless = NULL;
2492 gchar **spliced_quotless = NULL; // sigh -_-;
2493 gchar **inpart = NULL;
2496 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2498 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2499 } else quotless = g_strdup(*cp);
2501 spliced_quotless = g_strsplit(quotless, " ", 2);
2502 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2503 g_strfreev(spliced_quotless);
2505 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2511 parse_command(parts[0], &(newargs->str[1]), NULL);
2512 g_string_free(newargs, TRUE);
2513 g_strfreev(chainparts);
2516 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2517 parse_command(inparts[0], inparts[1], NULL);
2525 add_binding (const gchar *key, const gchar *act) {
2526 char **parts = g_strsplit(act, " ", 2);
2533 if (uzbl.state.verbose)
2534 printf ("Binding %-10s : %s\n", key, act);
2535 action = new_action(parts[0], parts[1]);
2537 if (g_hash_table_remove (uzbl.bindings, key))
2538 g_warning ("Overwriting existing binding for \"%s\"", key);
2539 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2544 get_xdg_var (XDG_Var xdg) {
2545 const gchar* actual_value = getenv (xdg.environmental);
2546 const gchar* home = getenv ("HOME");
2547 gchar* return_value;
2549 if (! actual_value || strcmp (actual_value, "") == 0) {
2550 if (xdg.default_value) {
2551 return_value = str_replace ("~", home, xdg.default_value);
2553 return_value = NULL;
2556 return_value = str_replace("~", home, actual_value);
2559 return return_value;
2563 find_xdg_file (int xdg_type, const char* filename) {
2564 /* xdg_type = 0 => config
2565 xdg_type = 1 => data
2566 xdg_type = 2 => cache*/
2568 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2569 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2572 gchar* temporary_string;
2576 if (! file_exists (temporary_file) && xdg_type != 2) {
2577 buf = get_xdg_var (XDG[3 + xdg_type]);
2578 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2581 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2582 g_free (temporary_file);
2583 temporary_file = g_strconcat (temporary_string, filename, NULL);
2587 //g_free (temporary_string); - segfaults.
2589 if (file_exists (temporary_file)) {
2590 return temporary_file;
2592 g_free(temporary_file);
2598 State *s = &uzbl.state;
2599 Network *n = &uzbl.net;
2601 for (i = 0; default_config[i].command != NULL; i++) {
2602 parse_cmd_line(default_config[i].command, NULL);
2605 if (g_strcmp0(s->config_file, "-") == 0) {
2606 s->config_file = NULL;
2610 else if (!s->config_file) {
2611 s->config_file = find_xdg_file (0, "/uzbl/config");
2614 if (s->config_file) {
2615 GArray* lines = read_file_by_line (s->config_file);
2619 while ((line = g_array_index(lines, gchar*, i))) {
2620 parse_cmd_line (line, NULL);
2624 g_array_free (lines, TRUE);
2626 if (uzbl.state.verbose)
2627 printf ("No configuration file loaded.\n");
2630 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2633 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2636 if (!uzbl.behave.cookie_handler)
2639 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2640 GString *s = g_string_new ("");
2641 SoupURI * soup_uri = soup_message_get_uri(msg);
2642 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2643 run_handler(uzbl.behave.cookie_handler, s->str);
2645 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2646 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2647 if ( p != NULL ) *p = '\0';
2648 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2650 if (uzbl.comm.sync_stdout)
2651 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2653 g_string_free(s, TRUE);
2657 save_cookies (SoupMessage *msg, gpointer user_data){
2661 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2662 cookie = soup_cookie_to_set_cookie_header(ck->data);
2663 SoupURI * soup_uri = soup_message_get_uri(msg);
2664 GString *s = g_string_new ("");
2665 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2666 run_handler(uzbl.behave.cookie_handler, s->str);
2668 g_string_free(s, TRUE);
2673 /* --- WEBINSPECTOR --- */
2675 hide_window_cb(GtkWidget *widget, gpointer data) {
2678 gtk_widget_hide(widget);
2682 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2685 (void) web_inspector;
2686 GtkWidget* scrolled_window;
2687 GtkWidget* new_web_view;
2690 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2691 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2692 G_CALLBACK(hide_window_cb), NULL);
2694 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2695 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2696 gtk_widget_show(g->inspector_window);
2698 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2699 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2700 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2701 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2702 gtk_widget_show(scrolled_window);
2704 new_web_view = webkit_web_view_new();
2705 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2707 return WEBKIT_WEB_VIEW(new_web_view);
2711 inspector_show_window_cb (WebKitWebInspector* inspector){
2713 gtk_widget_show(uzbl.gui.inspector_window);
2717 /* TODO: Add variables and code to make use of these functions */
2719 inspector_close_window_cb (WebKitWebInspector* inspector){
2725 inspector_attach_window_cb (WebKitWebInspector* inspector){
2731 inspector_detach_window_cb (WebKitWebInspector* inspector){
2737 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2743 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2749 set_up_inspector() {
2751 WebKitWebSettings *settings = view_settings();
2752 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2754 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2755 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2756 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2757 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2758 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2759 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2760 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2762 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2766 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2768 uzbl_cmdprop *c = v;
2773 if(c->type == TYPE_STR)
2774 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2775 else if(c->type == TYPE_INT)
2776 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2777 else if(c->type == TYPE_FLOAT)
2778 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2782 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2786 printf("bind %s = %s %s\n", (char *)k ,
2787 (char *)a->name, a->param?(char *)a->param:"");
2792 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2793 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2797 retrieve_geometry() {
2799 GString *buf = g_string_new("");
2801 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2802 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2804 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2806 if(uzbl.gui.geometry)
2807 g_free(uzbl.gui.geometry);
2808 uzbl.gui.geometry = g_string_free(buf, FALSE);
2811 /* set up gtk, gobject, variable defaults and other things that tests and other
2812 * external applications need to do anyhow */
2814 initialize(int argc, char *argv[]) {
2815 if (!g_thread_supported ())
2816 g_thread_init (NULL);
2817 uzbl.state.executable_path = g_strdup(argv[0]);
2818 uzbl.state.selected_url = NULL;
2819 uzbl.state.searchtx = NULL;
2821 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2822 g_option_context_add_main_entries (context, entries, NULL);
2823 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2824 g_option_context_parse (context, &argc, &argv, NULL);
2825 g_option_context_free(context);
2827 if (uzbl.behave.print_version) {
2828 printf("Commit: %s\n", COMMIT);
2832 /* initialize hash table */
2833 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2835 uzbl.net.soup_session = webkit_get_default_session();
2836 uzbl.state.keycmd = g_strdup("");
2838 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2839 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2840 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2841 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2843 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2844 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2845 uzbl.gui.sbar.progress_w = 10;
2847 /* default mode indicators */
2848 uzbl.behave.insert_indicator = g_strdup("I");
2849 uzbl.behave.cmd_indicator = g_strdup("C");
2851 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2852 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2853 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2854 uzbl.info.arch = ARCH;
2855 uzbl.info.commit = COMMIT;
2858 make_var_to_name_hash();
2863 #ifndef UZBL_LIBRARY
2866 main (int argc, char* argv[]) {
2867 initialize(argc, argv);
2869 gtk_init (&argc, &argv);
2871 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2872 //main_window_ref = g_object_ref(scrolled_window);
2873 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2874 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2876 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2877 GTK_WIDGET (uzbl.gui.web_view));
2879 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2883 /* initial packing */
2884 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2885 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2887 if (uzbl.state.socket_id) {
2888 uzbl.gui.plug = create_plug ();
2889 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2890 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2892 uzbl.gui.main_window = create_window ();
2893 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2894 gtk_widget_show_all (uzbl.gui.main_window);
2895 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2898 if(!uzbl.state.instance_name)
2899 uzbl.state.instance_name = itos((int)uzbl.xwin);
2901 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2903 if (uzbl.state.verbose) {
2904 printf("Uzbl start location: %s\n", argv[0]);
2905 if (uzbl.state.socket_id)
2906 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2908 printf("window_id %i\n",(int) uzbl.xwin);
2909 printf("pid %i\n", getpid ());
2910 printf("name: %s\n", uzbl.state.instance_name);
2911 printf("commit: %s\n", uzbl.info.commit);
2914 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2915 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2916 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2917 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2918 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2920 /* Check uzbl is in window mode before getting/setting geometry */
2921 if (uzbl.gui.main_window) {
2922 if(uzbl.gui.geometry)
2925 retrieve_geometry();
2928 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2929 if (argc > 1 && !uzbl.state.uri)
2930 uri_override = g_strdup(argv[1]);
2931 gboolean verbose_override = uzbl.state.verbose;
2934 set_insert_mode(FALSE);
2936 if (!uzbl.behave.show_status)
2937 gtk_widget_hide(uzbl.gui.mainbar);
2944 if (verbose_override > uzbl.state.verbose)
2945 uzbl.state.verbose = verbose_override;
2948 set_var_value("uri", uri_override);
2949 g_free(uri_override);
2950 } else if (uzbl.state.uri)
2956 return EXIT_SUCCESS;
2960 /* vi: set et ts=4: */