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 { "mode", PTR_V_INT(uzbl.behave.mode, 0, NULL)},
119 { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)},
120 { "base_url", PTR_V_STR(uzbl.behave.base_url, 1, NULL)},
121 { "html_endmarker", PTR_V_STR(uzbl.behave.html_endmarker, 1, NULL)},
122 { "html_mode_timeout", PTR_V_INT(uzbl.behave.html_timeout, 1, NULL)},
123 { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)},
124 { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)},
125 { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)},
126 { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)},
127 { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, update_title)},
128 { "status_pbar_done", PTR_V_STR(uzbl.gui.sbar.progress_s, 1, update_title)},
129 { "status_pbar_pending", PTR_V_STR(uzbl.gui.sbar.progress_u, 1, update_title)},
130 { "status_pbar_width", PTR_V_INT(uzbl.gui.sbar.progress_w, 1, update_title)},
131 { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, update_title)},
132 { "insert_indicator", PTR_V_STR(uzbl.behave.insert_indicator, 1, update_indicator)},
133 { "command_indicator", PTR_V_STR(uzbl.behave.cmd_indicator, 1, update_indicator)},
134 { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, update_title)},
135 { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, update_title)},
136 { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
137 { "insert_mode", PTR_V_INT(uzbl.behave.insert_mode, 1, set_mode_indicator)},
138 { "always_insert_mode", PTR_V_INT(uzbl.behave.always_insert_mode, 1, cmd_always_insert_mode)},
139 { "reset_command_mode", PTR_V_INT(uzbl.behave.reset_command_mode, 1, NULL)},
140 { "modkey", PTR_V_STR(uzbl.behave.modkey, 1, cmd_modkey)},
141 { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)},
142 { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)},
143 { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)},
144 { "history_handler", PTR_V_STR(uzbl.behave.history_handler, 1, NULL)},
145 { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
146 { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)},
147 { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, cmd_new_window)},
148 { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
149 { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
150 { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
151 { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
152 { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
153 { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
154 { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
155 { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
157 /* exported WebKitWebSettings properties */
158 { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
159 { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
160 { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
161 { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
162 { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
163 { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
164 { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
165 { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
166 { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
167 { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
168 { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
169 { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
170 { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
171 { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
172 { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
173 { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
174 { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
175 { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
176 { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
177 { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
178 { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
179 { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
181 /* constants (not dumpable or writeable) */
182 { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
183 { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
184 { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
185 { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
186 { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
187 { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)},
188 { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)},
189 { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
190 { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
191 { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)},
192 { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
194 { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
199 /*@null@*/ char *key;
202 { "SHIFT", GDK_SHIFT_MASK }, // shift
203 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
204 { "CONTROL", GDK_CONTROL_MASK }, // control
205 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
206 { "MOD2", GDK_MOD2_MASK }, // 5th mod
207 { "MOD3", GDK_MOD3_MASK }, // 6th mod
208 { "MOD4", GDK_MOD4_MASK }, // 7th mod
209 { "MOD5", GDK_MOD5_MASK }, // 8th mod
210 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
211 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
212 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
213 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
214 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
215 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
216 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
217 { "META", GDK_META_MASK }, // meta (since 2.10)
222 /* construct a hash from the var_name_to_ptr array for quick access */
224 make_var_to_name_hash() {
225 const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
226 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
228 g_hash_table_insert(uzbl.comm.proto_var,
229 (gpointer) n2v_p->name,
230 (gpointer) &n2v_p->cp);
235 /* --- UTILITY FUNCTIONS --- */
236 enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
238 get_exp_type(const gchar *s) {
242 else if(*(s+1) == '{')
243 return EXP_BRACED_VAR;
244 else if(*(s+1) == '<')
246 else if(*(s+1) == '[')
249 return EXP_SIMPLE_VAR;
256 * recurse == 1: don't expand '@(command)@'
257 * recurse == 2: don't expand '@<java script>@'
260 expand(const char *s, guint recurse) {
263 char *end_simple_var = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
267 gchar *cmd_stdout = NULL;
269 GString *buf = g_string_new("");
270 GString *js_ret = g_string_new("");
275 g_string_append_c(buf, *++s);
280 etype = get_exp_type(s);
285 vend = strpbrk(s, end_simple_var);
286 if(!vend) vend = strchr(s, '\0');
290 vend = strchr(s, '}');
291 if(!vend) vend = strchr(s, '\0');
295 vend = strstr(s, ")@");
296 if(!vend) vend = strchr(s, '\0');
300 vend = strstr(s, ">@");
301 if(!vend) vend = strchr(s, '\0');
305 vend = strstr(s, "]@");
306 if(!vend) vend = strchr(s, '\0');
314 ret = g_strndup(s, vend-s);
316 if(etype == EXP_SIMPLE_VAR ||
317 etype == EXP_BRACED_VAR) {
318 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
319 if(c->type == TYPE_STR && *c->ptr.s != NULL) {
320 g_string_append(buf, (gchar *)*c->ptr.s);
322 else if(c->type == TYPE_INT) {
323 g_string_append_printf(buf, "%d", *c->ptr.i);
325 else if(c->type == TYPE_FLOAT) {
326 g_string_append_printf(buf, "%f", *c->ptr.f);
330 if(etype == EXP_SIMPLE_VAR)
335 else if(recurse != 1 &&
337 mycmd = expand(ret, 1);
338 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
342 g_printerr("error on running command: %s\n", err->message);
345 else if (*cmd_stdout) {
346 size_t len = strlen(cmd_stdout);
348 if(len > 0 && cmd_stdout[len-1] == '\n')
349 cmd_stdout[--len] = '\0'; /* strip trailing newline */
351 g_string_append(buf, cmd_stdout);
356 else if(recurse != 2 &&
358 mycmd = expand(ret, 2);
359 eval_js(uzbl.gui.web_view, mycmd, js_ret);
363 g_string_append(buf, js_ret->str);
364 g_string_free(js_ret, TRUE);
365 js_ret = g_string_new("");
369 else if(etype == EXP_ESCAPE) {
370 mycmd = expand(ret, 0);
371 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
373 g_string_append(buf, escaped);
385 g_string_append_c(buf, *s);
390 g_string_free(js_ret, TRUE);
391 return g_string_free(buf, FALSE);
398 snprintf(tmp, sizeof(tmp), "%i", val);
399 return g_strdup(tmp);
403 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
406 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
409 str_replace (const char* search, const char* replace, const char* string) {
413 buf = g_strsplit (string, search, -1);
414 ret = g_strjoinv (replace, buf);
415 g_strfreev(buf); // somebody said this segfaults
421 read_file_by_line (const gchar *path) {
422 GIOChannel *chan = NULL;
423 gchar *readbuf = NULL;
425 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
428 chan = g_io_channel_new_file(path, "r", NULL);
431 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
432 const gchar* val = g_strdup (readbuf);
433 g_array_append_val (lines, val);
438 g_io_channel_unref (chan);
440 fprintf(stderr, "File '%s' not be read.\n", path);
447 parseenv (char* string) {
448 extern char** environ;
449 gchar* tmpstr = NULL;
453 while (environ[i] != NULL) {
454 gchar** env = g_strsplit (environ[i], "=", 2);
455 gchar* envname = g_strconcat ("$", env[0], NULL);
457 if (g_strrstr (string, envname) != NULL) {
458 tmpstr = g_strdup(string);
460 string = str_replace(envname, env[1], tmpstr);
465 g_strfreev (env); // somebody said this breaks uzbl
473 setup_signal(int signr, sigfunc *shandler) {
474 struct sigaction nh, oh;
476 nh.sa_handler = shandler;
477 sigemptyset(&nh.sa_mask);
480 if(sigaction(signr, &nh, &oh) < 0)
488 if (uzbl.behave.fifo_dir)
489 unlink (uzbl.comm.fifo_path);
490 if (uzbl.behave.socket_dir)
491 unlink (uzbl.comm.socket_path);
493 g_free(uzbl.state.executable_path);
494 g_free(uzbl.state.keycmd);
495 g_hash_table_destroy(uzbl.bindings);
496 g_hash_table_destroy(uzbl.behave.commands);
499 /* used for html_mode_timeout
500 * be sure to extend this function to use
501 * more timers if needed in other places
504 set_timeout(int seconds) {
506 memset(&t, 0, sizeof t);
508 t.it_value.tv_sec = seconds;
509 t.it_value.tv_usec = 0;
510 setitimer(ITIMER_REAL, &t, NULL);
513 /* --- SIGNAL HANDLER --- */
516 catch_sigterm(int s) {
522 catch_sigint(int s) {
532 set_var_value("mode", "0");
537 /* --- CALLBACKS --- */
540 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
543 (void) navigation_action;
544 (void) policy_decision;
546 const gchar* uri = webkit_network_request_get_uri (request);
547 if (uzbl.state.verbose)
548 printf("New window requested -> %s \n", uri);
549 webkit_web_policy_decision_use(policy_decision);
554 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
559 /* If we can display it, let's display it... */
560 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
561 webkit_web_policy_decision_use (policy_decision);
565 /* ...everything we can't displayed is downloaded */
566 webkit_web_policy_decision_download (policy_decision);
570 /*@null@*/ WebKitWebView*
571 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
575 if (uzbl.state.selected_url != NULL) {
576 if (uzbl.state.verbose)
577 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
578 new_window_load_uri(uzbl.state.selected_url);
580 if (uzbl.state.verbose)
581 printf("New web view -> %s\n","Nothing to open, exiting");
587 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
590 if (uzbl.behave.download_handler) {
591 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
592 if (uzbl.state.verbose)
593 printf("Download -> %s\n",uri);
594 /* if urls not escaped, we may have to escape and quote uri before this call */
595 run_handler(uzbl.behave.download_handler, uri);
600 /* scroll a bar in a given direction */
602 scroll (GtkAdjustment* bar, GArray *argv) {
606 gdouble page_size = gtk_adjustment_get_page_size(bar);
607 gdouble value = gtk_adjustment_get_value(bar);
608 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
611 value += page_size * amount * 0.01;
615 max_value = gtk_adjustment_get_upper(bar) - page_size;
617 if (value > max_value)
618 value = max_value; /* don't scroll past the end of the page */
620 gtk_adjustment_set_value (bar, value);
624 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
625 (void) page; (void) argv; (void) result;
626 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
630 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
631 (void) page; (void) argv; (void) result;
632 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
633 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
637 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
638 (void) page; (void) result;
639 scroll(uzbl.gui.bar_v, argv);
643 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
644 (void) page; (void) result;
645 scroll(uzbl.gui.bar_h, argv);
650 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
651 if(uzbl.state.verbose)
652 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
654 /* update geometry var with the actual geometry
655 this is necessary as some WMs don't seem to honour
656 the above setting and we don't want to end up with
657 wrong geometry information
664 if (!uzbl.behave.show_status) {
665 gtk_widget_hide(uzbl.gui.mainbar);
667 gtk_widget_show(uzbl.gui.mainbar);
673 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
678 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
682 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
687 if (uzbl.behave.show_status) {
688 gtk_widget_hide(uzbl.gui.mainbar);
690 gtk_widget_show(uzbl.gui.mainbar);
692 uzbl.behave.show_status = !uzbl.behave.show_status;
697 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
701 //Set selected_url state variable
702 g_free(uzbl.state.selected_url);
703 uzbl.state.selected_url = NULL;
705 uzbl.state.selected_url = g_strdup(link);
711 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
714 const gchar *title = webkit_web_view_get_title(web_view);
715 if (uzbl.gui.main_title)
716 g_free (uzbl.gui.main_title);
717 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
722 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
725 uzbl.gui.sbar.load_progress = progress;
727 g_free(uzbl.gui.sbar.progress_bar);
728 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
734 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
738 if (uzbl.behave.load_finish_handler)
739 run_handler(uzbl.behave.load_finish_handler, "");
742 void clear_keycmd() {
743 g_free(uzbl.state.keycmd);
744 uzbl.state.keycmd = g_strdup("");
748 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
752 uzbl.gui.sbar.load_progress = 0;
753 clear_keycmd(); // don't need old commands to remain on new page?
754 if (uzbl.behave.load_start_handler)
755 run_handler(uzbl.behave.load_start_handler, "");
759 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
762 g_free (uzbl.state.uri);
763 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
764 uzbl.state.uri = g_string_free (newuri, FALSE);
765 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
766 set_insert_mode(uzbl.behave.always_insert_mode);
769 if (uzbl.behave.load_commit_handler)
770 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
774 destroy_cb (GtkWidget* widget, gpointer data) {
782 if (uzbl.behave.history_handler) {
784 struct tm * timeinfo;
787 timeinfo = localtime ( &rawtime );
788 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
789 run_handler(uzbl.behave.history_handler, date);
794 /* VIEW funcs (little webkit wrappers) */
795 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
797 VIEWFUNC(reload_bypass_cache)
798 VIEWFUNC(stop_loading)
805 /* -- command to callback/function map for things we cannot attach to any signals */
806 struct {const char *key; CommandInfo value;} cmdlist[] =
807 { /* key function no_split */
808 { "back", {view_go_back, 0} },
809 { "forward", {view_go_forward, 0} },
810 { "scroll_vert", {scroll_vert, 0} },
811 { "scroll_horz", {scroll_horz, 0} },
812 { "scroll_begin", {scroll_begin, 0} },
813 { "scroll_end", {scroll_end, 0} },
814 { "reload", {view_reload, 0}, },
815 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
816 { "stop", {view_stop_loading, 0}, },
817 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
818 { "zoom_out", {view_zoom_out, 0}, },
819 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
820 { "uri", {load_uri, TRUE} },
821 { "js", {run_js, TRUE} },
822 { "script", {run_external_js, 0} },
823 { "toggle_status", {toggle_status_cb, 0} },
824 { "spawn", {spawn, 0} },
825 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
826 { "sh", {spawn_sh, 0} },
827 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
828 { "talk_to_socket", {talk_to_socket, 0} },
829 { "exit", {close_uzbl, 0} },
830 { "search", {search_forward_text, TRUE} },
831 { "search_reverse", {search_reverse_text, TRUE} },
832 { "dehilight", {dehilight, 0} },
833 { "toggle_insert_mode", {toggle_insert_mode, 0} },
834 { "set", {set_var, TRUE} },
835 //{ "get", {get_var, TRUE} },
836 { "bind", {act_bind, TRUE} },
837 { "dump_config", {act_dump_config, 0} },
838 { "keycmd", {keycmd, TRUE} },
839 { "keycmd_nl", {keycmd_nl, TRUE} },
840 { "keycmd_bs", {keycmd_bs, 0} },
841 { "chain", {chain, 0} },
842 { "print", {print, TRUE} },
843 { "update_gui", {update_gui, TRUE} }
850 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
852 for (i = 0; i < LENGTH(cmdlist); i++)
853 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
856 /* -- CORE FUNCTIONS -- */
859 free_action(gpointer act) {
860 Action *action = (Action*)act;
861 g_free(action->name);
863 g_free(action->param);
868 new_action(const gchar *name, const gchar *param) {
869 Action *action = g_new(Action, 1);
871 action->name = g_strdup(name);
873 action->param = g_strdup(param);
875 action->param = NULL;
881 file_exists (const char * filename) {
882 return (access(filename, F_OK) == 0);
886 set_var(WebKitWebView *page, GArray *argv, GString *result) {
887 (void) page; (void) result;
888 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
889 if (split[0] != NULL) {
890 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
891 set_var_value(g_strstrip(split[0]), value);
898 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
899 (void) page; (void) argv; (void) result;
905 print(WebKitWebView *page, GArray *argv, GString *result) {
906 (void) page; (void) result;
909 buf = expand(argv_idx(argv, 0), 0);
910 g_string_assign(result, buf);
915 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
916 (void) page; (void) result;
917 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
918 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
919 add_binding(g_strstrip(split[0]), value);
937 set_mode_indicator() {
938 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
939 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
944 set_mode_indicator();
949 set_insert_mode(gboolean mode) {
950 uzbl.behave.insert_mode = mode;
951 set_mode_indicator();
955 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
956 (void) page; (void) result;
958 if (argv_idx(argv, 0)) {
959 if (strcmp (argv_idx(argv, 0), "0") == 0) {
960 set_insert_mode(FALSE);
962 set_insert_mode(TRUE);
965 set_insert_mode( !uzbl.behave.insert_mode );
972 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
975 if (argv_idx(argv, 0)) {
976 GString* newuri = g_string_new (argv_idx(argv, 0));
977 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
978 run_js(web_view, argv, NULL);
981 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
982 g_string_prepend (newuri, "http://");
983 /* if we do handle cookies, ask our handler for them */
984 webkit_web_view_load_uri (web_view, newuri->str);
985 g_string_free (newuri, TRUE);
992 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
993 size_t argumentCount, const JSValueRef arguments[],
994 JSValueRef* exception) {
999 JSStringRef js_result_string;
1000 GString *result = g_string_new("");
1002 if (argumentCount >= 1) {
1003 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1004 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1005 char ctl_line[arg_size];
1006 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1008 parse_cmd_line(ctl_line, result);
1010 JSStringRelease(arg);
1012 js_result_string = JSStringCreateWithUTF8CString(result->str);
1014 g_string_free(result, TRUE);
1016 return JSValueMakeString(ctx, js_result_string);
1019 JSStaticFunction js_static_functions[] = {
1020 {"run", js_run_command, kJSPropertyAttributeNone},
1025 /* This function creates the class and its definition, only once */
1026 if (!uzbl.js.initialized) {
1027 /* it would be pretty cool to make this dynamic */
1028 uzbl.js.classdef = kJSClassDefinitionEmpty;
1029 uzbl.js.classdef.staticFunctions = js_static_functions;
1031 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1037 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1038 WebKitWebFrame *frame;
1039 JSGlobalContextRef context;
1040 JSObjectRef globalobject;
1041 JSStringRef var_name;
1043 JSStringRef js_script;
1044 JSValueRef js_result;
1045 JSStringRef js_result_string;
1046 size_t js_result_size;
1050 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1051 context = webkit_web_frame_get_global_context(frame);
1052 globalobject = JSContextGetGlobalObject(context);
1054 /* uzbl javascript namespace */
1055 var_name = JSStringCreateWithUTF8CString("Uzbl");
1056 JSObjectSetProperty(context, globalobject, var_name,
1057 JSObjectMake(context, uzbl.js.classref, NULL),
1058 kJSClassAttributeNone, NULL);
1060 /* evaluate the script and get return value*/
1061 js_script = JSStringCreateWithUTF8CString(script);
1062 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1063 if (js_result && !JSValueIsUndefined(context, js_result)) {
1064 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1065 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1067 if (js_result_size) {
1068 char js_result_utf8[js_result_size];
1069 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1070 g_string_assign(result, js_result_utf8);
1073 JSStringRelease(js_result_string);
1077 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1079 JSStringRelease(var_name);
1080 JSStringRelease(js_script);
1084 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1085 if (argv_idx(argv, 0))
1086 eval_js(web_view, argv_idx(argv, 0), result);
1090 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1092 if (argv_idx(argv, 0)) {
1093 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1098 while ((line = g_array_index(lines, gchar*, i))) {
1100 js = g_strdup (line);
1102 gchar* newjs = g_strconcat (js, line, NULL);
1109 if (uzbl.state.verbose)
1110 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1112 if (argv_idx (argv, 1)) {
1113 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1117 eval_js (web_view, js, result);
1119 g_array_free (lines, TRUE);
1124 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1125 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1126 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1127 webkit_web_view_unmark_text_matches (page);
1128 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1129 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1133 if (uzbl.state.searchtx) {
1134 if (uzbl.state.verbose)
1135 printf ("Searching: %s\n", uzbl.state.searchtx);
1136 webkit_web_view_set_highlight_text_matches (page, TRUE);
1137 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1142 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1144 search_text(page, argv, TRUE);
1148 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1150 search_text(page, argv, FALSE);
1154 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1155 (void) argv; (void) result;
1156 webkit_web_view_set_highlight_text_matches (page, FALSE);
1161 new_window_load_uri (const gchar * uri) {
1162 if (uzbl.behave.new_window) {
1163 GString *s = g_string_new ("");
1164 g_string_printf(s, "'%s'", uri);
1165 run_handler(uzbl.behave.new_window, s->str);
1168 GString* to_execute = g_string_new ("");
1169 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1171 for (i = 0; entries[i].long_name != NULL; i++) {
1172 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1173 gchar** str = (gchar**)entries[i].arg_data;
1175 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1179 if (uzbl.state.verbose)
1180 printf("\n%s\n", to_execute->str);
1181 g_spawn_command_line_async (to_execute->str, NULL);
1182 g_string_free (to_execute, TRUE);
1186 chain (WebKitWebView *page, GArray *argv, GString *result) {
1187 (void) page; (void) result;
1189 gchar **parts = NULL;
1191 while ((a = argv_idx(argv, i++))) {
1192 parts = g_strsplit (a, " ", 2);
1194 parse_command(parts[0], parts[1], result);
1200 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1204 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1210 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1214 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1220 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1225 int len = strlen(uzbl.state.keycmd);
1226 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1228 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1233 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1240 /* --Statusbar functions-- */
1242 build_progressbar_ascii(int percent) {
1243 int width=uzbl.gui.sbar.progress_w;
1246 GString *bar = g_string_new("");
1248 l = (double)percent*((double)width/100.);
1249 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1251 for(i=0; i<(int)l; i++)
1252 g_string_append(bar, uzbl.gui.sbar.progress_s);
1255 g_string_append(bar, uzbl.gui.sbar.progress_u);
1257 return g_string_free(bar, FALSE);
1259 /* --End Statusbar functions-- */
1262 sharg_append(GArray *a, const gchar *str) {
1263 const gchar *s = (str ? str : "");
1264 g_array_append_val(a, s);
1267 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1269 run_command (const gchar *command, const guint npre, const gchar **args,
1270 const gboolean sync, char **output_stdout) {
1271 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1274 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1275 gchar *pid = itos(getpid());
1276 gchar *xwin = itos(uzbl.xwin);
1278 sharg_append(a, command);
1279 for (i = 0; i < npre; i++) /* add n args before the default vars */
1280 sharg_append(a, args[i]);
1281 sharg_append(a, uzbl.state.config_file);
1282 sharg_append(a, pid);
1283 sharg_append(a, xwin);
1284 sharg_append(a, uzbl.comm.fifo_path);
1285 sharg_append(a, uzbl.comm.socket_path);
1286 sharg_append(a, uzbl.state.uri);
1287 sharg_append(a, uzbl.gui.main_title);
1289 for (i = npre; i < g_strv_length((gchar**)args); i++)
1290 sharg_append(a, args[i]);
1294 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1296 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1297 NULL, NULL, output_stdout, NULL, NULL, &err);
1298 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1299 NULL, NULL, NULL, &err);
1301 if (uzbl.state.verbose) {
1302 GString *s = g_string_new("spawned:");
1303 for (i = 0; i < (a->len); i++) {
1304 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1305 g_string_append_printf(s, " %s", qarg);
1308 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1309 printf("%s\n", s->str);
1310 g_string_free(s, TRUE);
1312 printf("Stdout: %s\n", *output_stdout);
1316 g_printerr("error on run_command: %s\n", err->message);
1321 g_array_free (a, TRUE);
1326 split_quoted(const gchar* src, const gboolean unquote) {
1327 /* split on unquoted space, return array of strings;
1328 remove a layer of quotes and backslashes if unquote */
1329 if (!src) return NULL;
1331 gboolean dq = FALSE;
1332 gboolean sq = FALSE;
1333 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1334 GString *s = g_string_new ("");
1338 for (p = src; *p != '\0'; p++) {
1339 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1340 else if (*p == '\\') { g_string_append_c(s, *p++);
1341 g_string_append_c(s, *p); }
1342 else if ((*p == '"') && unquote && !sq) dq = !dq;
1343 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1345 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1346 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1348 else if ((*p == ' ') && !dq && !sq) {
1349 dup = g_strdup(s->str);
1350 g_array_append_val(a, dup);
1351 g_string_truncate(s, 0);
1352 } else g_string_append_c(s, *p);
1354 dup = g_strdup(s->str);
1355 g_array_append_val(a, dup);
1356 ret = (gchar**)a->data;
1357 g_array_free (a, FALSE);
1358 g_string_free (s, TRUE);
1363 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1364 (void)web_view; (void)result;
1365 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1366 if (argv_idx(argv, 0))
1367 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1371 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1372 (void)web_view; (void)result;
1374 if (argv_idx(argv, 0))
1375 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1376 TRUE, &uzbl.comm.sync_stdout);
1380 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1381 (void)web_view; (void)result;
1382 if (!uzbl.behave.shell_cmd) {
1383 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1388 gchar *spacer = g_strdup("");
1389 g_array_insert_val(argv, 1, spacer);
1390 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1392 for (i = 1; i < g_strv_length(cmd); i++)
1393 g_array_prepend_val(argv, cmd[i]);
1395 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1401 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1402 (void)web_view; (void)result;
1403 if (!uzbl.behave.shell_cmd) {
1404 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1409 gchar *spacer = g_strdup("");
1410 g_array_insert_val(argv, 1, spacer);
1411 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1413 for (i = 1; i < g_strv_length(cmd); i++)
1414 g_array_prepend_val(argv, cmd[i]);
1416 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1417 TRUE, &uzbl.comm.sync_stdout);
1423 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1424 (void)web_view; (void)result;
1427 struct sockaddr_un sa;
1434 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1436 /* This function could be optimised by storing a hash table of socket paths
1437 and associated connected file descriptors rather than closing and
1438 re-opening for every call. Also we could launch a script if socket connect
1441 /* First element argv[0] is path to socket. Following elements are tokens to
1442 write to the socket. We write them as a single packet with each token
1443 separated by an ASCII nul (\0). */
1445 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1450 /* copy socket path, null terminate result */
1451 sockpath = g_array_index(argv, char*, 0);
1452 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1453 sa.sun_family = AF_UNIX;
1455 /* create socket file descriptor and connect it to path */
1456 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1458 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1461 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1462 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1467 /* build request vector */
1468 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1470 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1474 for(i = 1; i < argv->len; ++i) {
1475 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1476 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1480 ret = writev(fd, iov, argv->len - 1);
1483 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1488 /* wait for a response, with a 500ms timeout */
1490 pfd.events = POLLIN;
1492 ret = poll(&pfd, 1, 500);
1494 if(ret == 0) errno = ETIMEDOUT;
1495 if(errno == EINTR) continue;
1496 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1502 /* get length of response */
1503 if(ioctl(fd, FIONREAD, &len) == -1) {
1504 g_printerr("talk_to_socket: cannot find daemon response length, "
1505 "ioctl failed (%s)\n", strerror(errno));
1510 /* if there is a response, read it */
1512 uzbl.comm.sync_stdout = g_malloc(len + 1);
1513 if(!uzbl.comm.sync_stdout) {
1514 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1518 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1520 ret = read(fd, uzbl.comm.sync_stdout, len);
1522 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1535 parse_command(const char *cmd, const char *param, GString *result) {
1538 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1540 gchar **par = split_quoted(param, TRUE);
1541 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1543 if (c->no_split) { /* don't split */
1544 sharg_append(a, param);
1546 for (i = 0; i < g_strv_length(par); i++)
1547 sharg_append(a, par[i]);
1550 if (result == NULL) {
1551 GString *result_print = g_string_new("");
1553 c->function(uzbl.gui.web_view, a, result_print);
1554 if (result_print->len)
1555 printf("%*s\n", (int)result_print->len, result_print->str);
1557 g_string_free(result_print, TRUE);
1559 c->function(uzbl.gui.web_view, a, result);
1562 g_array_free (a, TRUE);
1565 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1572 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1573 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1574 (GType) SOUP_SESSION_PROXY_URI);
1577 suri = soup_uri_new(uzbl.net.proxy_url);
1578 g_object_set(G_OBJECT(uzbl.net.soup_session),
1579 SOUP_SESSION_PROXY_URI,
1581 soup_uri_free(suri);
1588 if(file_exists(uzbl.gui.icon)) {
1589 if (uzbl.gui.main_window)
1590 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1592 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1598 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1599 g_array_append_val (a, uzbl.state.uri);
1600 load_uri(uzbl.gui.web_view, a, NULL);
1601 g_array_free (a, TRUE);
1605 cmd_always_insert_mode() {
1606 set_insert_mode(uzbl.behave.always_insert_mode);
1612 g_object_set(G_OBJECT(uzbl.net.soup_session),
1613 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1617 cmd_max_conns_host() {
1618 g_object_set(G_OBJECT(uzbl.net.soup_session),
1619 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1624 soup_session_remove_feature
1625 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1626 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1627 /*g_free(uzbl.net.soup_logger);*/
1629 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1630 soup_session_add_feature(uzbl.net.soup_session,
1631 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1636 return webkit_web_view_get_settings(uzbl.gui.web_view);
1641 WebKitWebSettings *ws = view_settings();
1642 if (uzbl.behave.font_size > 0) {
1643 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1646 if (uzbl.behave.monospace_size > 0) {
1647 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1648 uzbl.behave.monospace_size, NULL);
1650 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1651 uzbl.behave.font_size, NULL);
1656 cmd_default_font_family() {
1657 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1658 uzbl.behave.default_font_family, NULL);
1662 cmd_monospace_font_family() {
1663 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1664 uzbl.behave.monospace_font_family, NULL);
1668 cmd_sans_serif_font_family() {
1669 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1670 uzbl.behave.sans_serif_font_family, NULL);
1674 cmd_serif_font_family() {
1675 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1676 uzbl.behave.serif_font_family, NULL);
1680 cmd_cursive_font_family() {
1681 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1682 uzbl.behave.cursive_font_family, NULL);
1686 cmd_fantasy_font_family() {
1687 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1688 uzbl.behave.fantasy_font_family, NULL);
1693 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1697 cmd_disable_plugins() {
1698 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1699 !uzbl.behave.disable_plugins, NULL);
1703 cmd_disable_scripts() {
1704 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1705 !uzbl.behave.disable_scripts, NULL);
1709 cmd_minimum_font_size() {
1710 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1711 uzbl.behave.minimum_font_size, NULL);
1714 cmd_autoload_img() {
1715 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1716 uzbl.behave.autoload_img, NULL);
1721 cmd_autoshrink_img() {
1722 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1723 uzbl.behave.autoshrink_img, NULL);
1728 cmd_enable_spellcheck() {
1729 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1730 uzbl.behave.enable_spellcheck, NULL);
1734 cmd_enable_private() {
1735 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1736 uzbl.behave.enable_private, NULL);
1741 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1742 uzbl.behave.print_bg, NULL);
1747 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1748 uzbl.behave.style_uri, NULL);
1752 cmd_resizable_txt() {
1753 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1754 uzbl.behave.resizable_txt, NULL);
1758 cmd_default_encoding() {
1759 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1760 uzbl.behave.default_encoding, NULL);
1764 cmd_enforce_96dpi() {
1765 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1766 uzbl.behave.enforce_96dpi, NULL);
1770 cmd_caret_browsing() {
1771 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1772 uzbl.behave.caret_browsing, NULL);
1776 cmd_cookie_handler() {
1777 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1778 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1779 if ((g_strcmp0(split[0], "sh") == 0) ||
1780 (g_strcmp0(split[0], "spawn") == 0)) {
1781 g_free (uzbl.behave.cookie_handler);
1782 uzbl.behave.cookie_handler =
1783 g_strdup_printf("sync_%s %s", split[0], split[1]);
1790 gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
1791 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1792 if ((g_strcmp0(split[0], "sh") == 0) ||
1793 (g_strcmp0(split[0], "spawn") == 0)) {
1794 g_free (uzbl.behave.new_window);
1795 uzbl.behave.new_window =
1796 g_strdup_printf("%s %s", split[0], split[1]);
1803 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1808 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1813 if(uzbl.behave.inject_html) {
1814 webkit_web_view_load_html_string (uzbl.gui.web_view,
1815 uzbl.behave.inject_html, NULL);
1824 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1825 uzbl.behave.modmask = 0;
1827 if(uzbl.behave.modkey)
1828 g_free(uzbl.behave.modkey);
1829 uzbl.behave.modkey = buf;
1831 for (i = 0; modkeys[i].key != NULL; i++) {
1832 if (g_strrstr(buf, modkeys[i].key))
1833 uzbl.behave.modmask |= modkeys[i].mask;
1839 if (*uzbl.net.useragent == ' ') {
1840 g_free (uzbl.net.useragent);
1841 uzbl.net.useragent = NULL;
1843 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1844 uzbl.net.useragent, NULL);
1850 if (!uzbl.gui.scrolled_win &&
1854 gtk_widget_ref(uzbl.gui.scrolled_win);
1855 gtk_widget_ref(uzbl.gui.mainbar);
1856 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1857 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1859 if(uzbl.behave.status_top) {
1860 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1861 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1864 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1865 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1867 gtk_widget_unref(uzbl.gui.scrolled_win);
1868 gtk_widget_unref(uzbl.gui.mainbar);
1869 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1874 set_var_value(const gchar *name, gchar *val) {
1875 uzbl_cmdprop *c = NULL;
1878 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1880 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1881 if(!c->writeable) return FALSE;
1883 /* check for the variable type */
1884 if (c->type == TYPE_STR) {
1885 buf = expand(val, 0);
1888 } else if(c->type == TYPE_INT) {
1889 buf = expand(val, 0);
1890 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1892 } else if (c->type == TYPE_FLOAT) {
1893 buf = expand(val, 0);
1894 *c->ptr.f = strtod(buf, &endp);
1898 /* invoke a command specific function */
1899 if(c->func) c->func();
1901 /* check wether name violates our naming scheme */
1902 if(strpbrk(name, invalid_chars)) {
1903 if (uzbl.state.verbose)
1904 printf("Invalid variable name\n");
1909 c = malloc(sizeof(uzbl_cmdprop));
1914 buf = expand(val, 0);
1915 c->ptr.s = malloc(sizeof(char *));
1917 g_hash_table_insert(uzbl.comm.proto_var,
1918 g_strdup(name), (gpointer) c);
1925 Behaviour *b = &uzbl.behave;
1927 if(b->html_buffer->str) {
1928 webkit_web_view_load_html_string (uzbl.gui.web_view,
1929 b->html_buffer->str, b->base_url);
1930 g_string_free(b->html_buffer, TRUE);
1931 b->html_buffer = g_string_new("");
1935 enum {M_CMD, M_HTML};
1937 parse_cmd_line(const char *ctl_line, GString *result) {
1938 Behaviour *b = &uzbl.behave;
1941 if(b->mode == M_HTML) {
1942 len = strlen(b->html_endmarker);
1943 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1944 if(len == strlen(ctl_line)-1 &&
1945 !strncmp(b->html_endmarker, ctl_line, len)) {
1947 set_var_value("mode", "0");
1952 set_timeout(b->html_timeout);
1953 g_string_append(b->html_buffer, ctl_line);
1956 else if((ctl_line[0] == '#') /* Comments */
1957 || (ctl_line[0] == ' ')
1958 || (ctl_line[0] == '\n'))
1959 ; /* ignore these lines */
1960 else { /* parse a command */
1962 gchar **tokens = NULL;
1963 len = strlen(ctl_line);
1965 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1966 ctlstrip = g_strndup(ctl_line, len - 1);
1967 else ctlstrip = g_strdup(ctl_line);
1969 tokens = g_strsplit(ctlstrip, " ", 2);
1970 parse_command(tokens[0], tokens[1], result);
1977 build_stream_name(int type, const gchar* dir) {
1978 State *s = &uzbl.state;
1982 str = g_strdup_printf
1983 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1984 } else if (type == SOCKET) {
1985 str = g_strdup_printf
1986 ("%s/uzbl_socket_%s", dir, s->instance_name);
1992 control_fifo(GIOChannel *gio, GIOCondition condition) {
1993 if (uzbl.state.verbose)
1994 printf("triggered\n");
1999 if (condition & G_IO_HUP)
2000 g_error ("Fifo: Read end of pipe died!\n");
2003 g_error ("Fifo: GIOChannel broke\n");
2005 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2006 if (ret == G_IO_STATUS_ERROR) {
2007 g_error ("Fifo: Error reading: %s\n", err->message);
2011 parse_cmd_line(ctl_line, NULL);
2018 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2019 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2020 if (unlink(uzbl.comm.fifo_path) == -1)
2021 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2022 g_free(uzbl.comm.fifo_path);
2023 uzbl.comm.fifo_path = NULL;
2026 GIOChannel *chan = NULL;
2027 GError *error = NULL;
2028 gchar *path = build_stream_name(FIFO, dir);
2030 if (!file_exists(path)) {
2031 if (mkfifo (path, 0666) == 0) {
2032 // 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.
2033 chan = g_io_channel_new_file(path, "r+", &error);
2035 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2036 if (uzbl.state.verbose)
2037 printf ("init_fifo: created successfully as %s\n", path);
2038 uzbl.comm.fifo_path = path;
2040 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2041 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2042 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2043 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2045 /* if we got this far, there was an error; cleanup */
2046 if (error) g_error_free (error);
2053 control_stdin(GIOChannel *gio, GIOCondition condition) {
2055 gchar *ctl_line = NULL;
2058 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2059 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2062 parse_cmd_line(ctl_line, NULL);
2070 GIOChannel *chan = NULL;
2071 GError *error = NULL;
2073 chan = g_io_channel_unix_new(fileno(stdin));
2075 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2076 g_error ("Stdin: could not add watch\n");
2078 if (uzbl.state.verbose)
2079 printf ("Stdin: watch added successfully\n");
2082 g_error ("Stdin: Error while opening: %s\n", error->message);
2084 if (error) g_error_free (error);
2088 control_socket(GIOChannel *chan) {
2089 struct sockaddr_un remote;
2090 unsigned int t = sizeof(remote);
2092 GIOChannel *clientchan;
2094 clientsock = accept (g_io_channel_unix_get_fd(chan),
2095 (struct sockaddr *) &remote, &t);
2097 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2098 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2099 (GIOFunc) control_client_socket, clientchan);
2106 control_client_socket(GIOChannel *clientchan) {
2108 GString *result = g_string_new("");
2109 GError *error = NULL;
2113 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2114 if (ret == G_IO_STATUS_ERROR) {
2115 g_warning ("Error reading: %s\n", error->message);
2116 g_io_channel_shutdown(clientchan, TRUE, &error);
2118 } else if (ret == G_IO_STATUS_EOF) {
2119 /* shutdown and remove channel watch from main loop */
2120 g_io_channel_shutdown(clientchan, TRUE, &error);
2125 parse_cmd_line (ctl_line, result);
2126 g_string_append_c(result, '\n');
2127 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2129 if (ret == G_IO_STATUS_ERROR) {
2130 g_warning ("Error writing: %s", error->message);
2132 g_io_channel_flush(clientchan, &error);
2135 if (error) g_error_free (error);
2136 g_string_free(result, TRUE);
2142 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2143 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2144 if (unlink(uzbl.comm.socket_path) == -1)
2145 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2146 g_free(uzbl.comm.socket_path);
2147 uzbl.comm.socket_path = NULL;
2155 GIOChannel *chan = NULL;
2157 struct sockaddr_un local;
2158 gchar *path = build_stream_name(SOCKET, dir);
2160 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2162 local.sun_family = AF_UNIX;
2163 strcpy (local.sun_path, path);
2164 unlink (local.sun_path);
2166 len = strlen (local.sun_path) + sizeof (local.sun_family);
2167 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2168 if (uzbl.state.verbose)
2169 printf ("init_socket: opened in %s\n", path);
2172 if( (chan = g_io_channel_unix_new(sock)) ) {
2173 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2174 uzbl.comm.socket_path = path;
2177 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2179 /* if we got this far, there was an error; cleanup */
2186 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2187 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2189 // this function may be called very early when the templates are not set (yet), hence the checks
2191 update_title (void) {
2192 Behaviour *b = &uzbl.behave;
2195 if (b->show_status) {
2196 if (b->title_format_short) {
2197 parsed = expand(b->title_format_short, 0);
2198 if (uzbl.gui.main_window)
2199 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2202 if (b->status_format) {
2203 parsed = expand(b->status_format, 0);
2204 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2207 if (b->status_background) {
2209 gdk_color_parse (b->status_background, &color);
2210 //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)
2211 if (uzbl.gui.main_window)
2212 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2213 else if (uzbl.gui.plug)
2214 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2217 if (b->title_format_long) {
2218 parsed = expand(b->title_format_long, 0);
2219 if (uzbl.gui.main_window)
2220 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2227 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2231 retrieve_geometry();
2236 key_press_cb (GtkWidget* window, GdkEventKey* event)
2238 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2242 if (event->type != GDK_KEY_PRESS ||
2243 event->keyval == GDK_Page_Up ||
2244 event->keyval == GDK_Page_Down ||
2245 event->keyval == GDK_Up ||
2246 event->keyval == GDK_Down ||
2247 event->keyval == GDK_Left ||
2248 event->keyval == GDK_Right ||
2249 event->keyval == GDK_Shift_L ||
2250 event->keyval == GDK_Shift_R)
2253 /* turn off insert mode (if always_insert_mode is not used) */
2254 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2255 set_insert_mode(uzbl.behave.always_insert_mode);
2260 if (uzbl.behave.insert_mode &&
2261 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2262 (!uzbl.behave.modmask)
2267 if (event->keyval == GDK_Escape) {
2270 dehilight(uzbl.gui.web_view, NULL, NULL);
2274 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2275 if (event->keyval == GDK_Insert) {
2277 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2278 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2280 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2283 GString* keycmd = g_string_new(uzbl.state.keycmd);
2284 g_string_append (keycmd, str);
2285 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2292 if (event->keyval == GDK_BackSpace)
2293 keycmd_bs(NULL, NULL, NULL);
2295 gboolean key_ret = FALSE;
2296 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2299 GString* keycmd = g_string_new(uzbl.state.keycmd);
2300 g_string_append(keycmd, event->string);
2301 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2304 run_keycmd(key_ret);
2306 if (key_ret) return (!uzbl.behave.insert_mode);
2311 run_keycmd(const gboolean key_ret) {
2312 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2314 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2316 parse_command(act->name, act->param, NULL);
2320 /* try if it's an incremental keycmd or one that takes args, and run it */
2321 GString* short_keys = g_string_new ("");
2322 GString* short_keys_inc = g_string_new ("");
2324 guint len = strlen(uzbl.state.keycmd);
2325 for (i=0; i<len; i++) {
2326 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2327 g_string_assign(short_keys_inc, short_keys->str);
2328 g_string_append_c(short_keys, '_');
2329 g_string_append_c(short_keys_inc, '*');
2331 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2332 /* run normal cmds only if return was pressed */
2333 exec_paramcmd(act, i);
2336 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2337 if (key_ret) /* just quit the incremental command on return */
2339 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2343 g_string_truncate(short_keys, short_keys->len - 1);
2345 g_string_free (short_keys, TRUE);
2346 g_string_free (short_keys_inc, TRUE);
2350 exec_paramcmd(const Action *act, const guint i) {
2351 GString *parampart = g_string_new (uzbl.state.keycmd);
2352 GString *actionname = g_string_new ("");
2353 GString *actionparam = g_string_new ("");
2354 g_string_erase (parampart, 0, i+1);
2356 g_string_printf (actionname, act->name, parampart->str);
2358 g_string_printf (actionparam, act->param, parampart->str);
2359 parse_command(actionname->str, actionparam->str, NULL);
2360 g_string_free(actionname, TRUE);
2361 g_string_free(actionparam, TRUE);
2362 g_string_free(parampart, TRUE);
2370 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2372 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2373 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2378 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2379 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2380 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2381 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2382 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2389 g->mainbar = gtk_hbox_new (FALSE, 0);
2391 /* keep a reference to the bar so we can re-pack it at runtime*/
2392 //sbar_ref = g_object_ref(g->mainbar);
2394 g->mainbar_label = gtk_label_new ("");
2395 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2396 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2397 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2398 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2399 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2400 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2406 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2407 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2408 gtk_widget_set_name (window, "Uzbl browser");
2409 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2410 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2411 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2418 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2419 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2420 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2427 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2429 If actname is one that calls an external command, this function will inject
2430 newargs in front of the user-provided args in that command line. They will
2431 come become after the body of the script (in sh) or after the name of
2432 the command to execute (in spawn).
2433 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2434 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2436 The return value consist of two strings: the action (sh, ...) and its args.
2438 If act is not one that calls an external command, then the given action merely
2441 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2442 /* Arrr! Here be memory leaks */
2443 gchar *actdup = g_strdup(actname);
2444 g_array_append_val(rets, actdup);
2446 if ((g_strcmp0(actname, "spawn") == 0) ||
2447 (g_strcmp0(actname, "sh") == 0) ||
2448 (g_strcmp0(actname, "sync_spawn") == 0) ||
2449 (g_strcmp0(actname, "sync_sh") == 0) ||
2450 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2452 GString *a = g_string_new("");
2453 gchar **spawnparts = split_quoted(origargs, FALSE);
2454 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2455 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2457 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2458 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2460 g_array_append_val(rets, a->str);
2461 g_string_free(a, FALSE);
2462 g_strfreev(spawnparts);
2464 gchar *origdup = g_strdup(origargs);
2465 g_array_append_val(rets, origdup);
2467 return (gchar**)g_array_free(rets, FALSE);
2471 run_handler (const gchar *act, const gchar *args) {
2472 /* Consider this code a temporary hack to make the handlers usable.
2473 In practice, all this splicing, injection, and reconstruction is
2474 inefficient, annoying and hard to manage. Potential pitfalls arise
2475 when the handler specific args 1) are not quoted (the handler
2476 callbacks should take care of this) 2) are quoted but interfere
2477 with the users' own quotation. A more ideal solution is
2478 to refactor parse_command so that it doesn't just take a string
2479 and execute it; rather than that, we should have a function which
2480 returns the argument vector parsed from the string. This vector
2481 could be modified (e.g. insert additional args into it) before
2482 passing it to the next function that actually executes it. Though
2483 it still isn't perfect for chain actions.. will reconsider & re-
2484 factor when I have the time. -duc */
2486 char **parts = g_strsplit(act, " ", 2);
2488 if (g_strcmp0(parts[0], "chain") == 0) {
2489 GString *newargs = g_string_new("");
2490 gchar **chainparts = split_quoted(parts[1], FALSE);
2492 /* for every argument in the chain, inject the handler args
2493 and make sure the new parts are wrapped in quotes */
2494 gchar **cp = chainparts;
2496 gchar *quotless = NULL;
2497 gchar **spliced_quotless = NULL; // sigh -_-;
2498 gchar **inpart = NULL;
2501 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2503 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2504 } else quotless = g_strdup(*cp);
2506 spliced_quotless = g_strsplit(quotless, " ", 2);
2507 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2508 g_strfreev(spliced_quotless);
2510 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2516 parse_command(parts[0], &(newargs->str[1]), NULL);
2517 g_string_free(newargs, TRUE);
2518 g_strfreev(chainparts);
2521 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2522 parse_command(inparts[0], inparts[1], NULL);
2530 add_binding (const gchar *key, const gchar *act) {
2531 char **parts = g_strsplit(act, " ", 2);
2538 if (uzbl.state.verbose)
2539 printf ("Binding %-10s : %s\n", key, act);
2540 action = new_action(parts[0], parts[1]);
2542 if (g_hash_table_remove (uzbl.bindings, key))
2543 g_warning ("Overwriting existing binding for \"%s\"", key);
2544 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2549 get_xdg_var (XDG_Var xdg) {
2550 const gchar* actual_value = getenv (xdg.environmental);
2551 const gchar* home = getenv ("HOME");
2552 gchar* return_value;
2554 if (! actual_value || strcmp (actual_value, "") == 0) {
2555 if (xdg.default_value) {
2556 return_value = str_replace ("~", home, xdg.default_value);
2558 return_value = NULL;
2561 return_value = str_replace("~", home, actual_value);
2564 return return_value;
2568 find_xdg_file (int xdg_type, const char* filename) {
2569 /* xdg_type = 0 => config
2570 xdg_type = 1 => data
2571 xdg_type = 2 => cache*/
2573 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2574 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2577 gchar* temporary_string;
2581 if (! file_exists (temporary_file) && xdg_type != 2) {
2582 buf = get_xdg_var (XDG[3 + xdg_type]);
2583 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2586 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2587 g_free (temporary_file);
2588 temporary_file = g_strconcat (temporary_string, filename, NULL);
2592 //g_free (temporary_string); - segfaults.
2594 if (file_exists (temporary_file)) {
2595 return temporary_file;
2597 g_free(temporary_file);
2603 State *s = &uzbl.state;
2604 Network *n = &uzbl.net;
2606 for (i = 0; default_config[i].command != NULL; i++) {
2607 parse_cmd_line(default_config[i].command, NULL);
2610 if (g_strcmp0(s->config_file, "-") == 0) {
2611 s->config_file = NULL;
2615 else if (!s->config_file) {
2616 s->config_file = find_xdg_file (0, "/uzbl/config");
2619 if (s->config_file) {
2620 GArray* lines = read_file_by_line (s->config_file);
2624 while ((line = g_array_index(lines, gchar*, i))) {
2625 parse_cmd_line (line, NULL);
2629 g_array_free (lines, TRUE);
2631 if (uzbl.state.verbose)
2632 printf ("No configuration file loaded.\n");
2635 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2638 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2641 if (!uzbl.behave.cookie_handler)
2644 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2645 GString *s = g_string_new ("");
2646 SoupURI * soup_uri = soup_message_get_uri(msg);
2647 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2648 run_handler(uzbl.behave.cookie_handler, s->str);
2650 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2651 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2652 if ( p != NULL ) *p = '\0';
2653 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2655 if (uzbl.comm.sync_stdout)
2656 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2658 g_string_free(s, TRUE);
2662 save_cookies (SoupMessage *msg, gpointer user_data){
2666 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2667 cookie = soup_cookie_to_set_cookie_header(ck->data);
2668 SoupURI * soup_uri = soup_message_get_uri(msg);
2669 GString *s = g_string_new ("");
2670 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2671 run_handler(uzbl.behave.cookie_handler, s->str);
2673 g_string_free(s, TRUE);
2678 /* --- WEBINSPECTOR --- */
2680 hide_window_cb(GtkWidget *widget, gpointer data) {
2683 gtk_widget_hide(widget);
2687 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2690 (void) web_inspector;
2691 GtkWidget* scrolled_window;
2692 GtkWidget* new_web_view;
2695 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2696 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2697 G_CALLBACK(hide_window_cb), NULL);
2699 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2700 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2701 gtk_widget_show(g->inspector_window);
2703 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2704 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2705 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2706 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2707 gtk_widget_show(scrolled_window);
2709 new_web_view = webkit_web_view_new();
2710 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2712 return WEBKIT_WEB_VIEW(new_web_view);
2716 inspector_show_window_cb (WebKitWebInspector* inspector){
2718 gtk_widget_show(uzbl.gui.inspector_window);
2722 /* TODO: Add variables and code to make use of these functions */
2724 inspector_close_window_cb (WebKitWebInspector* inspector){
2730 inspector_attach_window_cb (WebKitWebInspector* inspector){
2736 inspector_detach_window_cb (WebKitWebInspector* inspector){
2742 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2748 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2754 set_up_inspector() {
2756 WebKitWebSettings *settings = view_settings();
2757 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2759 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2760 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2761 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2762 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2763 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2764 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2765 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2767 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2771 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2773 uzbl_cmdprop *c = v;
2778 if(c->type == TYPE_STR)
2779 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2780 else if(c->type == TYPE_INT)
2781 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2782 else if(c->type == TYPE_FLOAT)
2783 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2787 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2791 printf("bind %s = %s %s\n", (char *)k ,
2792 (char *)a->name, a->param?(char *)a->param:"");
2797 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2798 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2802 retrieve_geometry() {
2804 GString *buf = g_string_new("");
2806 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2807 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2809 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2811 if(uzbl.gui.geometry)
2812 g_free(uzbl.gui.geometry);
2813 uzbl.gui.geometry = g_string_free(buf, FALSE);
2816 /* set up gtk, gobject, variable defaults and other things that tests and other
2817 * external applications need to do anyhow */
2819 initialize(int argc, char *argv[]) {
2820 if (!g_thread_supported ())
2821 g_thread_init (NULL);
2822 uzbl.state.executable_path = g_strdup(argv[0]);
2823 uzbl.state.selected_url = NULL;
2824 uzbl.state.searchtx = NULL;
2826 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2827 g_option_context_add_main_entries (context, entries, NULL);
2828 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2829 g_option_context_parse (context, &argc, &argv, NULL);
2830 g_option_context_free(context);
2832 if (uzbl.behave.print_version) {
2833 printf("Commit: %s\n", COMMIT);
2837 /* initialize hash table */
2838 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2840 uzbl.net.soup_session = webkit_get_default_session();
2841 uzbl.state.keycmd = g_strdup("");
2843 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2844 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2845 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2846 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2847 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2848 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2850 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2851 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2852 uzbl.gui.sbar.progress_w = 10;
2854 /* HTML mode defaults*/
2855 uzbl.behave.html_buffer = g_string_new("");
2856 uzbl.behave.html_endmarker = g_strdup(".");
2857 uzbl.behave.html_timeout = 60;
2858 uzbl.behave.base_url = g_strdup("http://invalid");
2860 /* default mode indicators */
2861 uzbl.behave.insert_indicator = g_strdup("I");
2862 uzbl.behave.cmd_indicator = g_strdup("C");
2864 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2865 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2866 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2867 uzbl.info.arch = ARCH;
2868 uzbl.info.commit = COMMIT;
2871 make_var_to_name_hash();
2876 #ifndef UZBL_LIBRARY
2879 main (int argc, char* argv[]) {
2880 initialize(argc, argv);
2882 gtk_init (&argc, &argv);
2884 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2885 //main_window_ref = g_object_ref(scrolled_window);
2886 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2887 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2889 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2890 GTK_WIDGET (uzbl.gui.web_view));
2892 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2896 /* initial packing */
2897 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2898 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2900 if (uzbl.state.socket_id) {
2901 uzbl.gui.plug = create_plug ();
2902 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2903 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2905 uzbl.gui.main_window = create_window ();
2906 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2907 gtk_widget_show_all (uzbl.gui.main_window);
2908 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2911 if(!uzbl.state.instance_name)
2912 uzbl.state.instance_name = itos((int)uzbl.xwin);
2914 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2916 if (uzbl.state.verbose) {
2917 printf("Uzbl start location: %s\n", argv[0]);
2918 if (uzbl.state.socket_id)
2919 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2921 printf("window_id %i\n",(int) uzbl.xwin);
2922 printf("pid %i\n", getpid ());
2923 printf("name: %s\n", uzbl.state.instance_name);
2926 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2927 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2928 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2929 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2930 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2932 /* Check uzbl is in window mode before getting/setting geometry */
2933 if (uzbl.gui.main_window) {
2934 if(uzbl.gui.geometry)
2937 retrieve_geometry();
2940 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2941 if (argc > 1 && !uzbl.state.uri)
2942 uri_override = g_strdup(argv[1]);
2943 gboolean verbose_override = uzbl.state.verbose;
2946 set_insert_mode(FALSE);
2948 if (!uzbl.behave.show_status)
2949 gtk_widget_hide(uzbl.gui.mainbar);
2956 if (verbose_override > uzbl.state.verbose)
2957 uzbl.state.verbose = verbose_override;
2960 set_var_value("uri", uri_override);
2961 g_free(uri_override);
2962 } else if (uzbl.state.uri)
2968 return EXIT_SUCCESS;
2972 /* vi: set et ts=4: */