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_Home ||
2240 event->keyval == GDK_End ||
2241 event->keyval == GDK_Up ||
2242 event->keyval == GDK_Down ||
2243 event->keyval == GDK_Left ||
2244 event->keyval == GDK_Right ||
2245 event->keyval == GDK_Shift_L ||
2246 event->keyval == GDK_Shift_R)
2249 /* turn off insert mode (if always_insert_mode is not used) */
2250 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2251 set_insert_mode(uzbl.behave.always_insert_mode);
2256 if (uzbl.behave.insert_mode &&
2257 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2258 (!uzbl.behave.modmask)
2263 if (event->keyval == GDK_Escape) {
2266 dehilight(uzbl.gui.web_view, NULL, NULL);
2270 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2271 if (event->keyval == GDK_Insert) {
2273 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2274 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2276 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2279 GString* keycmd = g_string_new(uzbl.state.keycmd);
2280 g_string_append (keycmd, str);
2281 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2288 if (event->keyval == GDK_BackSpace)
2289 keycmd_bs(NULL, NULL, NULL);
2291 gboolean key_ret = FALSE;
2292 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2295 GString* keycmd = g_string_new(uzbl.state.keycmd);
2296 g_string_append(keycmd, event->string);
2297 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2300 run_keycmd(key_ret);
2302 if (key_ret) return (!uzbl.behave.insert_mode);
2307 run_keycmd(const gboolean key_ret) {
2308 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2310 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2312 parse_command(act->name, act->param, NULL);
2316 /* try if it's an incremental keycmd or one that takes args, and run it */
2317 GString* short_keys = g_string_new ("");
2318 GString* short_keys_inc = g_string_new ("");
2320 guint len = strlen(uzbl.state.keycmd);
2321 for (i=0; i<len; i++) {
2322 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2323 g_string_assign(short_keys_inc, short_keys->str);
2324 g_string_append_c(short_keys, '_');
2325 g_string_append_c(short_keys_inc, '*');
2327 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2328 /* run normal cmds only if return was pressed */
2329 exec_paramcmd(act, i);
2332 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2333 if (key_ret) /* just quit the incremental command on return */
2335 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2339 g_string_truncate(short_keys, short_keys->len - 1);
2341 g_string_free (short_keys, TRUE);
2342 g_string_free (short_keys_inc, TRUE);
2346 exec_paramcmd(const Action *act, const guint i) {
2347 GString *parampart = g_string_new (uzbl.state.keycmd);
2348 GString *actionname = g_string_new ("");
2349 GString *actionparam = g_string_new ("");
2350 g_string_erase (parampart, 0, i+1);
2352 g_string_printf (actionname, act->name, parampart->str);
2354 g_string_printf (actionparam, act->param, parampart->str);
2355 parse_command(actionname->str, actionparam->str, NULL);
2356 g_string_free(actionname, TRUE);
2357 g_string_free(actionparam, TRUE);
2358 g_string_free(parampart, TRUE);
2366 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2368 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2369 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2370 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2371 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2372 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2373 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "navigation-policy-decision-requested", G_CALLBACK (navigation_decision_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2378 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2379 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2386 g->mainbar = gtk_hbox_new (FALSE, 0);
2388 /* keep a reference to the bar so we can re-pack it at runtime*/
2389 //sbar_ref = g_object_ref(g->mainbar);
2391 g->mainbar_label = gtk_label_new ("");
2392 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2393 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2394 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2395 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2396 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2397 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2403 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2404 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2405 gtk_widget_set_name (window, "Uzbl browser");
2406 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2407 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2408 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2415 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2416 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2417 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2424 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2426 If actname is one that calls an external command, this function will inject
2427 newargs in front of the user-provided args in that command line. They will
2428 come become after the body of the script (in sh) or after the name of
2429 the command to execute (in spawn).
2430 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2431 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2433 The return value consist of two strings: the action (sh, ...) and its args.
2435 If act is not one that calls an external command, then the given action merely
2438 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2439 /* Arrr! Here be memory leaks */
2440 gchar *actdup = g_strdup(actname);
2441 g_array_append_val(rets, actdup);
2443 if ((g_strcmp0(actname, "spawn") == 0) ||
2444 (g_strcmp0(actname, "sh") == 0) ||
2445 (g_strcmp0(actname, "sync_spawn") == 0) ||
2446 (g_strcmp0(actname, "sync_sh") == 0) ||
2447 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2449 GString *a = g_string_new("");
2450 gchar **spawnparts = split_quoted(origargs, FALSE);
2451 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2452 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2454 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2455 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2457 g_array_append_val(rets, a->str);
2458 g_string_free(a, FALSE);
2459 g_strfreev(spawnparts);
2461 gchar *origdup = g_strdup(origargs);
2462 g_array_append_val(rets, origdup);
2464 return (gchar**)g_array_free(rets, FALSE);
2468 run_handler (const gchar *act, const gchar *args) {
2469 /* Consider this code a temporary hack to make the handlers usable.
2470 In practice, all this splicing, injection, and reconstruction is
2471 inefficient, annoying and hard to manage. Potential pitfalls arise
2472 when the handler specific args 1) are not quoted (the handler
2473 callbacks should take care of this) 2) are quoted but interfere
2474 with the users' own quotation. A more ideal solution is
2475 to refactor parse_command so that it doesn't just take a string
2476 and execute it; rather than that, we should have a function which
2477 returns the argument vector parsed from the string. This vector
2478 could be modified (e.g. insert additional args into it) before
2479 passing it to the next function that actually executes it. Though
2480 it still isn't perfect for chain actions.. will reconsider & re-
2481 factor when I have the time. -duc */
2483 char **parts = g_strsplit(act, " ", 2);
2485 if (g_strcmp0(parts[0], "chain") == 0) {
2486 GString *newargs = g_string_new("");
2487 gchar **chainparts = split_quoted(parts[1], FALSE);
2489 /* for every argument in the chain, inject the handler args
2490 and make sure the new parts are wrapped in quotes */
2491 gchar **cp = chainparts;
2493 gchar *quotless = NULL;
2494 gchar **spliced_quotless = NULL; // sigh -_-;
2495 gchar **inpart = NULL;
2498 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2500 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2501 } else quotless = g_strdup(*cp);
2503 spliced_quotless = g_strsplit(quotless, " ", 2);
2504 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2505 g_strfreev(spliced_quotless);
2507 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2513 parse_command(parts[0], &(newargs->str[1]), NULL);
2514 g_string_free(newargs, TRUE);
2515 g_strfreev(chainparts);
2518 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2519 parse_command(inparts[0], inparts[1], NULL);
2527 add_binding (const gchar *key, const gchar *act) {
2528 char **parts = g_strsplit(act, " ", 2);
2535 if (uzbl.state.verbose)
2536 printf ("Binding %-10s : %s\n", key, act);
2537 action = new_action(parts[0], parts[1]);
2539 if (g_hash_table_remove (uzbl.bindings, key))
2540 g_warning ("Overwriting existing binding for \"%s\"", key);
2541 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2546 get_xdg_var (XDG_Var xdg) {
2547 const gchar* actual_value = getenv (xdg.environmental);
2548 const gchar* home = getenv ("HOME");
2549 gchar* return_value;
2551 if (! actual_value || strcmp (actual_value, "") == 0) {
2552 if (xdg.default_value) {
2553 return_value = str_replace ("~", home, xdg.default_value);
2555 return_value = NULL;
2558 return_value = str_replace("~", home, actual_value);
2561 return return_value;
2565 find_xdg_file (int xdg_type, const char* filename) {
2566 /* xdg_type = 0 => config
2567 xdg_type = 1 => data
2568 xdg_type = 2 => cache*/
2570 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2571 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2574 gchar* temporary_string;
2578 if (! file_exists (temporary_file) && xdg_type != 2) {
2579 buf = get_xdg_var (XDG[3 + xdg_type]);
2580 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2583 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2584 g_free (temporary_file);
2585 temporary_file = g_strconcat (temporary_string, filename, NULL);
2589 //g_free (temporary_string); - segfaults.
2591 if (file_exists (temporary_file)) {
2592 return temporary_file;
2594 g_free(temporary_file);
2600 State *s = &uzbl.state;
2601 Network *n = &uzbl.net;
2603 for (i = 0; default_config[i].command != NULL; i++) {
2604 parse_cmd_line(default_config[i].command, NULL);
2607 if (g_strcmp0(s->config_file, "-") == 0) {
2608 s->config_file = NULL;
2612 else if (!s->config_file) {
2613 s->config_file = find_xdg_file (0, "/uzbl/config");
2616 if (s->config_file) {
2617 GArray* lines = read_file_by_line (s->config_file);
2621 while ((line = g_array_index(lines, gchar*, i))) {
2622 parse_cmd_line (line, NULL);
2626 g_array_free (lines, TRUE);
2628 if (uzbl.state.verbose)
2629 printf ("No configuration file loaded.\n");
2632 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2635 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2638 if (!uzbl.behave.cookie_handler)
2641 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2642 GString *s = g_string_new ("");
2643 SoupURI * soup_uri = soup_message_get_uri(msg);
2644 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2645 run_handler(uzbl.behave.cookie_handler, s->str);
2647 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2648 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2649 if ( p != NULL ) *p = '\0';
2650 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2652 if (uzbl.comm.sync_stdout)
2653 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2655 g_string_free(s, TRUE);
2659 save_cookies (SoupMessage *msg, gpointer user_data){
2663 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2664 cookie = soup_cookie_to_set_cookie_header(ck->data);
2665 SoupURI * soup_uri = soup_message_get_uri(msg);
2666 GString *s = g_string_new ("");
2667 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2668 run_handler(uzbl.behave.cookie_handler, s->str);
2670 g_string_free(s, TRUE);
2675 /* --- WEBINSPECTOR --- */
2677 hide_window_cb(GtkWidget *widget, gpointer data) {
2680 gtk_widget_hide(widget);
2684 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2687 (void) web_inspector;
2688 GtkWidget* scrolled_window;
2689 GtkWidget* new_web_view;
2692 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2693 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2694 G_CALLBACK(hide_window_cb), NULL);
2696 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2697 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2698 gtk_widget_show(g->inspector_window);
2700 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2701 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2702 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2703 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2704 gtk_widget_show(scrolled_window);
2706 new_web_view = webkit_web_view_new();
2707 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2709 return WEBKIT_WEB_VIEW(new_web_view);
2713 inspector_show_window_cb (WebKitWebInspector* inspector){
2715 gtk_widget_show(uzbl.gui.inspector_window);
2719 /* TODO: Add variables and code to make use of these functions */
2721 inspector_close_window_cb (WebKitWebInspector* inspector){
2727 inspector_attach_window_cb (WebKitWebInspector* inspector){
2733 inspector_detach_window_cb (WebKitWebInspector* inspector){
2739 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2745 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2751 set_up_inspector() {
2753 WebKitWebSettings *settings = view_settings();
2754 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2756 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2757 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2758 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2759 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2760 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2761 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2762 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2764 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2768 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2770 uzbl_cmdprop *c = v;
2775 if(c->type == TYPE_STR)
2776 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2777 else if(c->type == TYPE_INT)
2778 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2779 else if(c->type == TYPE_FLOAT)
2780 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2784 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2788 printf("bind %s = %s %s\n", (char *)k ,
2789 (char *)a->name, a->param?(char *)a->param:"");
2794 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2795 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2799 retrieve_geometry() {
2801 GString *buf = g_string_new("");
2803 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2804 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2806 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2808 if(uzbl.gui.geometry)
2809 g_free(uzbl.gui.geometry);
2810 uzbl.gui.geometry = g_string_free(buf, FALSE);
2813 /* set up gtk, gobject, variable defaults and other things that tests and other
2814 * external applications need to do anyhow */
2816 initialize(int argc, char *argv[]) {
2817 if (!g_thread_supported ())
2818 g_thread_init (NULL);
2819 uzbl.state.executable_path = g_strdup(argv[0]);
2820 uzbl.state.selected_url = NULL;
2821 uzbl.state.searchtx = NULL;
2823 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2824 g_option_context_add_main_entries (context, entries, NULL);
2825 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2826 g_option_context_parse (context, &argc, &argv, NULL);
2827 g_option_context_free(context);
2829 if (uzbl.behave.print_version) {
2830 printf("Commit: %s\n", COMMIT);
2834 /* initialize hash table */
2835 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2837 uzbl.net.soup_session = webkit_get_default_session();
2838 uzbl.state.keycmd = g_strdup("");
2840 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2841 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2842 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2843 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2845 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2846 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2847 uzbl.gui.sbar.progress_w = 10;
2849 /* default mode indicators */
2850 uzbl.behave.insert_indicator = g_strdup("I");
2851 uzbl.behave.cmd_indicator = g_strdup("C");
2853 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2854 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2855 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2856 uzbl.info.arch = ARCH;
2857 uzbl.info.commit = COMMIT;
2860 make_var_to_name_hash();
2865 #ifndef UZBL_LIBRARY
2868 main (int argc, char* argv[]) {
2869 initialize(argc, argv);
2871 gtk_init (&argc, &argv);
2873 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2874 //main_window_ref = g_object_ref(scrolled_window);
2875 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2876 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2878 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2879 GTK_WIDGET (uzbl.gui.web_view));
2881 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2885 /* initial packing */
2886 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2887 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2889 if (uzbl.state.socket_id) {
2890 uzbl.gui.plug = create_plug ();
2891 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2892 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2894 uzbl.gui.main_window = create_window ();
2895 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2896 gtk_widget_show_all (uzbl.gui.main_window);
2897 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2900 if(!uzbl.state.instance_name)
2901 uzbl.state.instance_name = itos((int)uzbl.xwin);
2903 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2905 if (uzbl.state.verbose) {
2906 printf("Uzbl start location: %s\n", argv[0]);
2907 if (uzbl.state.socket_id)
2908 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2910 printf("window_id %i\n",(int) uzbl.xwin);
2911 printf("pid %i\n", getpid ());
2912 printf("name: %s\n", uzbl.state.instance_name);
2913 printf("commit: %s\n", uzbl.info.commit);
2916 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2917 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2918 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2919 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2920 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2922 /* Check uzbl is in window mode before getting/setting geometry */
2923 if (uzbl.gui.main_window) {
2924 if(uzbl.gui.geometry)
2927 retrieve_geometry();
2930 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2931 if (argc > 1 && !uzbl.state.uri)
2932 uri_override = g_strdup(argv[1]);
2933 gboolean verbose_override = uzbl.state.verbose;
2936 set_insert_mode(FALSE);
2938 if (!uzbl.behave.show_status)
2939 gtk_widget_hide(uzbl.gui.mainbar);
2946 if (verbose_override > uzbl.state.verbose)
2947 uzbl.state.verbose = verbose_override;
2950 set_var_value("uri", uri_override);
2951 g_free(uri_override);
2952 } else if (uzbl.state.uri)
2958 return EXIT_SUCCESS;
2962 /* vi: set et ts=4: */