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);
321 } else if(c->type == TYPE_INT) {
322 g_string_append_printf(buf, "%d", *c->ptr.i);
324 else if(c->type == TYPE_FLOAT) {
325 g_string_append_printf(buf, "%f", *c->ptr.f);
329 if(etype == EXP_SIMPLE_VAR)
334 else if(recurse != 1 &&
336 mycmd = expand(ret, 1);
337 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
341 g_printerr("error on running command: %s\n", err->message);
344 else if (*cmd_stdout) {
345 size_t len = strlen(cmd_stdout);
347 if(len > 0 && cmd_stdout[len-1] == '\n')
348 cmd_stdout[--len] = '\0'; /* strip trailing newline */
350 g_string_append(buf, cmd_stdout);
355 else if(recurse != 2 &&
357 mycmd = expand(ret, 2);
358 eval_js(uzbl.gui.web_view, mycmd, js_ret);
362 g_string_append(buf, js_ret->str);
363 g_string_free(js_ret, TRUE);
364 js_ret = g_string_new("");
368 else if(etype == EXP_ESCAPE) {
369 mycmd = expand(ret, 0);
370 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
372 g_string_append(buf, escaped);
384 g_string_append_c(buf, *s);
389 g_string_free(js_ret, TRUE);
390 return g_string_free(buf, FALSE);
397 snprintf(tmp, sizeof(tmp), "%i", val);
398 return g_strdup(tmp);
402 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
405 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
408 str_replace (const char* search, const char* replace, const char* string) {
412 buf = g_strsplit (string, search, -1);
413 ret = g_strjoinv (replace, buf);
414 g_strfreev(buf); // somebody said this segfaults
420 read_file_by_line (const gchar *path) {
421 GIOChannel *chan = NULL;
422 gchar *readbuf = NULL;
424 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
427 chan = g_io_channel_new_file(path, "r", NULL);
430 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
431 const gchar* val = g_strdup (readbuf);
432 g_array_append_val (lines, val);
437 g_io_channel_unref (chan);
439 fprintf(stderr, "File '%s' not be read.\n", path);
446 parseenv (char* string) {
447 extern char** environ;
448 gchar* tmpstr = NULL;
452 while (environ[i] != NULL) {
453 gchar** env = g_strsplit (environ[i], "=", 2);
454 gchar* envname = g_strconcat ("$", env[0], NULL);
456 if (g_strrstr (string, envname) != NULL) {
457 tmpstr = g_strdup(string);
459 string = str_replace(envname, env[1], tmpstr);
464 g_strfreev (env); // somebody said this breaks uzbl
472 setup_signal(int signr, sigfunc *shandler) {
473 struct sigaction nh, oh;
475 nh.sa_handler = shandler;
476 sigemptyset(&nh.sa_mask);
479 if(sigaction(signr, &nh, &oh) < 0)
487 if (uzbl.behave.fifo_dir)
488 unlink (uzbl.comm.fifo_path);
489 if (uzbl.behave.socket_dir)
490 unlink (uzbl.comm.socket_path);
492 g_free(uzbl.state.executable_path);
493 g_free(uzbl.state.keycmd);
494 g_hash_table_destroy(uzbl.bindings);
495 g_hash_table_destroy(uzbl.behave.commands);
498 /* used for html_mode_timeout
499 * be sure to extend this function to use
500 * more timers if needed in other places
503 set_timeout(int seconds) {
505 memset(&t, 0, sizeof t);
507 t.it_value.tv_sec = seconds;
508 t.it_value.tv_usec = 0;
509 setitimer(ITIMER_REAL, &t, NULL);
512 /* --- SIGNAL HANDLER --- */
515 catch_sigterm(int s) {
521 catch_sigint(int s) {
531 set_var_value("mode", "0");
536 /* --- CALLBACKS --- */
539 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
542 (void) navigation_action;
543 (void) policy_decision;
545 const gchar* uri = webkit_network_request_get_uri (request);
546 if (uzbl.state.verbose)
547 printf("New window requested -> %s \n", uri);
548 webkit_web_policy_decision_use(policy_decision);
553 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
558 /* If we can display it, let's display it... */
559 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
560 webkit_web_policy_decision_use (policy_decision);
564 /* ...everything we can't displayed is downloaded */
565 webkit_web_policy_decision_download (policy_decision);
569 /*@null@*/ WebKitWebView*
570 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
574 if (uzbl.state.selected_url != NULL) {
575 if (uzbl.state.verbose)
576 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
577 new_window_load_uri(uzbl.state.selected_url);
579 if (uzbl.state.verbose)
580 printf("New web view -> %s\n","Nothing to open, exiting");
586 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
589 if (uzbl.behave.download_handler) {
590 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
591 if (uzbl.state.verbose)
592 printf("Download -> %s\n",uri);
593 /* if urls not escaped, we may have to escape and quote uri before this call */
594 run_handler(uzbl.behave.download_handler, uri);
599 /* scroll a bar in a given direction */
601 scroll (GtkAdjustment* bar, GArray *argv) {
605 gdouble page_size = gtk_adjustment_get_page_size(bar);
606 gdouble value = gtk_adjustment_get_value(bar);
607 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
610 value += page_size * amount * 0.01;
614 max_value = gtk_adjustment_get_upper(bar) - page_size;
616 if (value > max_value)
617 value = max_value; /* don't scroll past the end of the page */
619 gtk_adjustment_set_value (bar, value);
623 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
624 (void) page; (void) argv; (void) result;
625 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
629 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
630 (void) page; (void) argv; (void) result;
631 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
632 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
636 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
637 (void) page; (void) result;
638 scroll(uzbl.gui.bar_v, argv);
642 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
643 (void) page; (void) result;
644 scroll(uzbl.gui.bar_h, argv);
649 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
650 if(uzbl.state.verbose)
651 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
653 /* update geometry var with the actual geometry
654 this is necessary as some WMs don't seem to honour
655 the above setting and we don't want to end up with
656 wrong geometry information
663 if (!uzbl.behave.show_status) {
664 gtk_widget_hide(uzbl.gui.mainbar);
666 gtk_widget_show(uzbl.gui.mainbar);
672 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
677 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
681 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
686 if (uzbl.behave.show_status) {
687 gtk_widget_hide(uzbl.gui.mainbar);
689 gtk_widget_show(uzbl.gui.mainbar);
691 uzbl.behave.show_status = !uzbl.behave.show_status;
696 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
700 //Set selected_url state variable
701 g_free(uzbl.state.selected_url);
702 uzbl.state.selected_url = NULL;
704 uzbl.state.selected_url = g_strdup(link);
710 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
713 const gchar *title = webkit_web_view_get_title(web_view);
714 if (uzbl.gui.main_title)
715 g_free (uzbl.gui.main_title);
716 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
721 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
724 uzbl.gui.sbar.load_progress = progress;
726 g_free(uzbl.gui.sbar.progress_bar);
727 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
733 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
737 if (uzbl.behave.load_finish_handler)
738 run_handler(uzbl.behave.load_finish_handler, "");
741 void clear_keycmd() {
742 g_free(uzbl.state.keycmd);
743 uzbl.state.keycmd = g_strdup("");
747 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
751 uzbl.gui.sbar.load_progress = 0;
752 clear_keycmd(); // don't need old commands to remain on new page?
753 if (uzbl.behave.load_start_handler)
754 run_handler(uzbl.behave.load_start_handler, "");
758 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
761 g_free (uzbl.state.uri);
762 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
763 uzbl.state.uri = g_string_free (newuri, FALSE);
764 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
765 set_insert_mode(uzbl.behave.always_insert_mode);
768 if (uzbl.behave.load_commit_handler)
769 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
773 destroy_cb (GtkWidget* widget, gpointer data) {
781 if (uzbl.behave.history_handler) {
783 struct tm * timeinfo;
786 timeinfo = localtime ( &rawtime );
787 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
788 run_handler(uzbl.behave.history_handler, date);
793 /* VIEW funcs (little webkit wrappers) */
794 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
796 VIEWFUNC(reload_bypass_cache)
797 VIEWFUNC(stop_loading)
804 /* -- command to callback/function map for things we cannot attach to any signals */
805 struct {const char *key; CommandInfo value;} cmdlist[] =
806 { /* key function no_split */
807 { "back", {view_go_back, 0} },
808 { "forward", {view_go_forward, 0} },
809 { "scroll_vert", {scroll_vert, 0} },
810 { "scroll_horz", {scroll_horz, 0} },
811 { "scroll_begin", {scroll_begin, 0} },
812 { "scroll_end", {scroll_end, 0} },
813 { "reload", {view_reload, 0}, },
814 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
815 { "stop", {view_stop_loading, 0}, },
816 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
817 { "zoom_out", {view_zoom_out, 0}, },
818 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
819 { "uri", {load_uri, TRUE} },
820 { "js", {run_js, TRUE} },
821 { "script", {run_external_js, 0} },
822 { "toggle_status", {toggle_status_cb, 0} },
823 { "spawn", {spawn, 0} },
824 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
825 { "sh", {spawn_sh, 0} },
826 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
827 { "talk_to_socket", {talk_to_socket, 0} },
828 { "exit", {close_uzbl, 0} },
829 { "search", {search_forward_text, TRUE} },
830 { "search_reverse", {search_reverse_text, TRUE} },
831 { "dehilight", {dehilight, 0} },
832 { "toggle_insert_mode", {toggle_insert_mode, 0} },
833 { "set", {set_var, TRUE} },
834 //{ "get", {get_var, TRUE} },
835 { "bind", {act_bind, TRUE} },
836 { "dump_config", {act_dump_config, 0} },
837 { "keycmd", {keycmd, TRUE} },
838 { "keycmd_nl", {keycmd_nl, TRUE} },
839 { "keycmd_bs", {keycmd_bs, 0} },
840 { "chain", {chain, 0} },
841 { "print", {print, TRUE} },
842 { "update_gui", {update_gui, TRUE} }
849 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
851 for (i = 0; i < LENGTH(cmdlist); i++)
852 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
855 /* -- CORE FUNCTIONS -- */
858 free_action(gpointer act) {
859 Action *action = (Action*)act;
860 g_free(action->name);
862 g_free(action->param);
867 new_action(const gchar *name, const gchar *param) {
868 Action *action = g_new(Action, 1);
870 action->name = g_strdup(name);
872 action->param = g_strdup(param);
874 action->param = NULL;
880 file_exists (const char * filename) {
881 return (access(filename, F_OK) == 0);
885 set_var(WebKitWebView *page, GArray *argv, GString *result) {
886 (void) page; (void) result;
887 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
888 if (split[0] != NULL) {
889 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
890 set_var_value(g_strstrip(split[0]), value);
897 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
898 (void) page; (void) argv; (void) result;
904 print(WebKitWebView *page, GArray *argv, GString *result) {
905 (void) page; (void) result;
908 buf = expand(argv_idx(argv, 0), 0);
909 g_string_assign(result, buf);
914 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
915 (void) page; (void) result;
916 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
917 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
918 add_binding(g_strstrip(split[0]), value);
936 set_mode_indicator() {
937 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
938 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
943 set_mode_indicator();
948 set_insert_mode(gboolean mode) {
949 uzbl.behave.insert_mode = mode;
950 set_mode_indicator();
954 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
955 (void) page; (void) result;
957 if (argv_idx(argv, 0)) {
958 if (strcmp (argv_idx(argv, 0), "0") == 0) {
959 set_insert_mode(FALSE);
961 set_insert_mode(TRUE);
964 set_insert_mode( !uzbl.behave.insert_mode );
971 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
974 if (argv_idx(argv, 0)) {
975 GString* newuri = g_string_new (argv_idx(argv, 0));
976 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
977 run_js(web_view, argv, NULL);
980 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
981 g_string_prepend (newuri, "http://");
982 /* if we do handle cookies, ask our handler for them */
983 webkit_web_view_load_uri (web_view, newuri->str);
984 g_string_free (newuri, TRUE);
991 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
992 size_t argumentCount, const JSValueRef arguments[],
993 JSValueRef* exception) {
998 JSStringRef js_result_string;
999 GString *result = g_string_new("");
1001 if (argumentCount >= 1) {
1002 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1003 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1004 char ctl_line[arg_size];
1005 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1007 parse_cmd_line(ctl_line, result);
1009 JSStringRelease(arg);
1011 js_result_string = JSStringCreateWithUTF8CString(result->str);
1013 g_string_free(result, TRUE);
1015 return JSValueMakeString(ctx, js_result_string);
1018 JSStaticFunction js_static_functions[] = {
1019 {"run", js_run_command, kJSPropertyAttributeNone},
1024 /* This function creates the class and its definition, only once */
1025 if (!uzbl.js.initialized) {
1026 /* it would be pretty cool to make this dynamic */
1027 uzbl.js.classdef = kJSClassDefinitionEmpty;
1028 uzbl.js.classdef.staticFunctions = js_static_functions;
1030 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1036 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1037 WebKitWebFrame *frame;
1038 JSGlobalContextRef context;
1039 JSObjectRef globalobject;
1040 JSStringRef var_name;
1042 JSStringRef js_script;
1043 JSValueRef js_result;
1044 JSStringRef js_result_string;
1045 size_t js_result_size;
1049 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1050 context = webkit_web_frame_get_global_context(frame);
1051 globalobject = JSContextGetGlobalObject(context);
1053 /* uzbl javascript namespace */
1054 var_name = JSStringCreateWithUTF8CString("Uzbl");
1055 JSObjectSetProperty(context, globalobject, var_name,
1056 JSObjectMake(context, uzbl.js.classref, NULL),
1057 kJSClassAttributeNone, NULL);
1059 /* evaluate the script and get return value*/
1060 js_script = JSStringCreateWithUTF8CString(script);
1061 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1062 if (js_result && !JSValueIsUndefined(context, js_result)) {
1063 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1064 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1066 if (js_result_size) {
1067 char js_result_utf8[js_result_size];
1068 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1069 g_string_assign(result, js_result_utf8);
1072 JSStringRelease(js_result_string);
1076 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1078 JSStringRelease(var_name);
1079 JSStringRelease(js_script);
1083 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1084 if (argv_idx(argv, 0))
1085 eval_js(web_view, argv_idx(argv, 0), result);
1089 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1091 if (argv_idx(argv, 0)) {
1092 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1097 while ((line = g_array_index(lines, gchar*, i))) {
1099 js = g_strdup (line);
1101 gchar* newjs = g_strconcat (js, line, NULL);
1108 if (uzbl.state.verbose)
1109 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1111 if (argv_idx (argv, 1)) {
1112 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1116 eval_js (web_view, js, result);
1118 g_array_free (lines, TRUE);
1123 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1124 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1125 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1126 webkit_web_view_unmark_text_matches (page);
1127 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1128 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1132 if (uzbl.state.searchtx) {
1133 if (uzbl.state.verbose)
1134 printf ("Searching: %s\n", uzbl.state.searchtx);
1135 webkit_web_view_set_highlight_text_matches (page, TRUE);
1136 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1141 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1143 search_text(page, argv, TRUE);
1147 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1149 search_text(page, argv, FALSE);
1153 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1154 (void) argv; (void) result;
1155 webkit_web_view_set_highlight_text_matches (page, FALSE);
1160 new_window_load_uri (const gchar * uri) {
1161 if (uzbl.behave.new_window) {
1162 GString *s = g_string_new ("");
1163 g_string_printf(s, "'%s'", uri);
1164 run_handler(uzbl.behave.new_window, s->str);
1167 GString* to_execute = g_string_new ("");
1168 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1170 for (i = 0; entries[i].long_name != NULL; i++) {
1171 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1172 gchar** str = (gchar**)entries[i].arg_data;
1174 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1178 if (uzbl.state.verbose)
1179 printf("\n%s\n", to_execute->str);
1180 g_spawn_command_line_async (to_execute->str, NULL);
1181 g_string_free (to_execute, TRUE);
1185 chain (WebKitWebView *page, GArray *argv, GString *result) {
1186 (void) page; (void) result;
1188 gchar **parts = NULL;
1190 while ((a = argv_idx(argv, i++))) {
1191 parts = g_strsplit (a, " ", 2);
1193 parse_command(parts[0], parts[1], result);
1199 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1203 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1209 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1213 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1219 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1224 int len = strlen(uzbl.state.keycmd);
1225 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1227 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1232 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1239 /* --Statusbar functions-- */
1241 build_progressbar_ascii(int percent) {
1242 int width=uzbl.gui.sbar.progress_w;
1245 GString *bar = g_string_new("");
1247 l = (double)percent*((double)width/100.);
1248 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1250 for(i=0; i<(int)l; i++)
1251 g_string_append(bar, uzbl.gui.sbar.progress_s);
1254 g_string_append(bar, uzbl.gui.sbar.progress_u);
1256 return g_string_free(bar, FALSE);
1258 /* --End Statusbar functions-- */
1261 sharg_append(GArray *a, const gchar *str) {
1262 const gchar *s = (str ? str : "");
1263 g_array_append_val(a, s);
1266 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1268 run_command (const gchar *command, const guint npre, const gchar **args,
1269 const gboolean sync, char **output_stdout) {
1270 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1273 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1274 gchar *pid = itos(getpid());
1275 gchar *xwin = itos(uzbl.xwin);
1277 sharg_append(a, command);
1278 for (i = 0; i < npre; i++) /* add n args before the default vars */
1279 sharg_append(a, args[i]);
1280 sharg_append(a, uzbl.state.config_file);
1281 sharg_append(a, pid);
1282 sharg_append(a, xwin);
1283 sharg_append(a, uzbl.comm.fifo_path);
1284 sharg_append(a, uzbl.comm.socket_path);
1285 sharg_append(a, uzbl.state.uri);
1286 sharg_append(a, uzbl.gui.main_title);
1288 for (i = npre; i < g_strv_length((gchar**)args); i++)
1289 sharg_append(a, args[i]);
1293 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1295 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1296 NULL, NULL, output_stdout, NULL, NULL, &err);
1297 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1298 NULL, NULL, NULL, &err);
1300 if (uzbl.state.verbose) {
1301 GString *s = g_string_new("spawned:");
1302 for (i = 0; i < (a->len); i++) {
1303 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1304 g_string_append_printf(s, " %s", qarg);
1307 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1308 printf("%s\n", s->str);
1309 g_string_free(s, TRUE);
1311 printf("Stdout: %s\n", *output_stdout);
1315 g_printerr("error on run_command: %s\n", err->message);
1320 g_array_free (a, TRUE);
1325 split_quoted(const gchar* src, const gboolean unquote) {
1326 /* split on unquoted space, return array of strings;
1327 remove a layer of quotes and backslashes if unquote */
1328 if (!src) return NULL;
1330 gboolean dq = FALSE;
1331 gboolean sq = FALSE;
1332 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1333 GString *s = g_string_new ("");
1337 for (p = src; *p != '\0'; p++) {
1338 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1339 else if (*p == '\\') { g_string_append_c(s, *p++);
1340 g_string_append_c(s, *p); }
1341 else if ((*p == '"') && unquote && !sq) dq = !dq;
1342 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1344 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1345 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1347 else if ((*p == ' ') && !dq && !sq) {
1348 dup = g_strdup(s->str);
1349 g_array_append_val(a, dup);
1350 g_string_truncate(s, 0);
1351 } else g_string_append_c(s, *p);
1353 dup = g_strdup(s->str);
1354 g_array_append_val(a, dup);
1355 ret = (gchar**)a->data;
1356 g_array_free (a, FALSE);
1357 g_string_free (s, TRUE);
1362 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1363 (void)web_view; (void)result;
1364 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1365 if (argv_idx(argv, 0))
1366 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1370 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1371 (void)web_view; (void)result;
1373 if (argv_idx(argv, 0))
1374 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1375 TRUE, &uzbl.comm.sync_stdout);
1379 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1380 (void)web_view; (void)result;
1381 if (!uzbl.behave.shell_cmd) {
1382 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1387 gchar *spacer = g_strdup("");
1388 g_array_insert_val(argv, 1, spacer);
1389 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1391 for (i = 1; i < g_strv_length(cmd); i++)
1392 g_array_prepend_val(argv, cmd[i]);
1394 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1400 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1401 (void)web_view; (void)result;
1402 if (!uzbl.behave.shell_cmd) {
1403 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1408 gchar *spacer = g_strdup("");
1409 g_array_insert_val(argv, 1, spacer);
1410 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1412 for (i = 1; i < g_strv_length(cmd); i++)
1413 g_array_prepend_val(argv, cmd[i]);
1415 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1416 TRUE, &uzbl.comm.sync_stdout);
1422 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1423 (void)web_view; (void)result;
1426 struct sockaddr_un sa;
1433 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1435 /* This function could be optimised by storing a hash table of socket paths
1436 and associated connected file descriptors rather than closing and
1437 re-opening for every call. Also we could launch a script if socket connect
1440 /* First element argv[0] is path to socket. Following elements are tokens to
1441 write to the socket. We write them as a single packet with each token
1442 separated by an ASCII nul (\0). */
1444 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1449 /* copy socket path, null terminate result */
1450 sockpath = g_array_index(argv, char*, 0);
1451 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1452 sa.sun_family = AF_UNIX;
1454 /* create socket file descriptor and connect it to path */
1455 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1457 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1460 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1461 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1466 /* build request vector */
1467 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1469 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1473 for(i = 1; i < argv->len; ++i) {
1474 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1475 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1479 ret = writev(fd, iov, argv->len - 1);
1482 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1487 /* wait for a response, with a 500ms timeout */
1489 pfd.events = POLLIN;
1491 ret = poll(&pfd, 1, 500);
1493 if(ret == 0) errno = ETIMEDOUT;
1494 if(errno == EINTR) continue;
1495 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1501 /* get length of response */
1502 if(ioctl(fd, FIONREAD, &len) == -1) {
1503 g_printerr("talk_to_socket: cannot find daemon response length, "
1504 "ioctl failed (%s)\n", strerror(errno));
1509 /* if there is a response, read it */
1511 uzbl.comm.sync_stdout = g_malloc(len + 1);
1512 if(!uzbl.comm.sync_stdout) {
1513 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1517 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1519 ret = read(fd, uzbl.comm.sync_stdout, len);
1521 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1534 parse_command(const char *cmd, const char *param, GString *result) {
1537 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1539 gchar **par = split_quoted(param, TRUE);
1540 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1542 if (c->no_split) { /* don't split */
1543 sharg_append(a, param);
1545 for (i = 0; i < g_strv_length(par); i++)
1546 sharg_append(a, par[i]);
1549 if (result == NULL) {
1550 GString *result_print = g_string_new("");
1552 c->function(uzbl.gui.web_view, a, result_print);
1553 if (result_print->len)
1554 printf("%*s\n", (int)result_print->len, result_print->str);
1556 g_string_free(result_print, TRUE);
1558 c->function(uzbl.gui.web_view, a, result);
1561 g_array_free (a, TRUE);
1564 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1571 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1572 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1573 (GType) SOUP_SESSION_PROXY_URI);
1576 suri = soup_uri_new(uzbl.net.proxy_url);
1577 g_object_set(G_OBJECT(uzbl.net.soup_session),
1578 SOUP_SESSION_PROXY_URI,
1580 soup_uri_free(suri);
1587 if(file_exists(uzbl.gui.icon)) {
1588 if (uzbl.gui.main_window)
1589 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1591 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1597 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1598 g_array_append_val (a, uzbl.state.uri);
1599 load_uri(uzbl.gui.web_view, a, NULL);
1600 g_array_free (a, TRUE);
1604 cmd_always_insert_mode() {
1605 set_insert_mode(uzbl.behave.always_insert_mode);
1611 g_object_set(G_OBJECT(uzbl.net.soup_session),
1612 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1616 cmd_max_conns_host() {
1617 g_object_set(G_OBJECT(uzbl.net.soup_session),
1618 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1623 soup_session_remove_feature
1624 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1625 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1626 /*g_free(uzbl.net.soup_logger);*/
1628 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1629 soup_session_add_feature(uzbl.net.soup_session,
1630 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1635 return webkit_web_view_get_settings(uzbl.gui.web_view);
1640 WebKitWebSettings *ws = view_settings();
1641 if (uzbl.behave.font_size > 0) {
1642 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1645 if (uzbl.behave.monospace_size > 0) {
1646 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1647 uzbl.behave.monospace_size, NULL);
1649 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1650 uzbl.behave.font_size, NULL);
1655 cmd_default_font_family() {
1656 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1657 uzbl.behave.default_font_family, NULL);
1661 cmd_monospace_font_family() {
1662 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1663 uzbl.behave.monospace_font_family, NULL);
1667 cmd_sans_serif_font_family() {
1668 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1669 uzbl.behave.sans_serif_font_family, NULL);
1673 cmd_serif_font_family() {
1674 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1675 uzbl.behave.serif_font_family, NULL);
1679 cmd_cursive_font_family() {
1680 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1681 uzbl.behave.cursive_font_family, NULL);
1685 cmd_fantasy_font_family() {
1686 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1687 uzbl.behave.fantasy_font_family, NULL);
1692 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1696 cmd_disable_plugins() {
1697 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1698 !uzbl.behave.disable_plugins, NULL);
1702 cmd_disable_scripts() {
1703 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1704 !uzbl.behave.disable_scripts, NULL);
1708 cmd_minimum_font_size() {
1709 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1710 uzbl.behave.minimum_font_size, NULL);
1713 cmd_autoload_img() {
1714 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1715 uzbl.behave.autoload_img, NULL);
1720 cmd_autoshrink_img() {
1721 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1722 uzbl.behave.autoshrink_img, NULL);
1727 cmd_enable_spellcheck() {
1728 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1729 uzbl.behave.enable_spellcheck, NULL);
1733 cmd_enable_private() {
1734 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1735 uzbl.behave.enable_private, NULL);
1740 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1741 uzbl.behave.print_bg, NULL);
1746 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1747 uzbl.behave.style_uri, NULL);
1751 cmd_resizable_txt() {
1752 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1753 uzbl.behave.resizable_txt, NULL);
1757 cmd_default_encoding() {
1758 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1759 uzbl.behave.default_encoding, NULL);
1763 cmd_enforce_96dpi() {
1764 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1765 uzbl.behave.enforce_96dpi, NULL);
1769 cmd_caret_browsing() {
1770 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1771 uzbl.behave.caret_browsing, NULL);
1775 cmd_cookie_handler() {
1776 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1777 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1778 if ((g_strcmp0(split[0], "sh") == 0) ||
1779 (g_strcmp0(split[0], "spawn") == 0)) {
1780 g_free (uzbl.behave.cookie_handler);
1781 uzbl.behave.cookie_handler =
1782 g_strdup_printf("sync_%s %s", split[0], split[1]);
1789 gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
1790 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1791 if ((g_strcmp0(split[0], "sh") == 0) ||
1792 (g_strcmp0(split[0], "spawn") == 0)) {
1793 g_free (uzbl.behave.new_window);
1794 uzbl.behave.new_window =
1795 g_strdup_printf("%s %s", split[0], split[1]);
1802 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1807 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1812 if(uzbl.behave.inject_html) {
1813 webkit_web_view_load_html_string (uzbl.gui.web_view,
1814 uzbl.behave.inject_html, NULL);
1823 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1824 uzbl.behave.modmask = 0;
1826 if(uzbl.behave.modkey)
1827 g_free(uzbl.behave.modkey);
1828 uzbl.behave.modkey = buf;
1830 for (i = 0; modkeys[i].key != NULL; i++) {
1831 if (g_strrstr(buf, modkeys[i].key))
1832 uzbl.behave.modmask |= modkeys[i].mask;
1838 if (*uzbl.net.useragent == ' ') {
1839 g_free (uzbl.net.useragent);
1840 uzbl.net.useragent = NULL;
1842 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1843 uzbl.net.useragent, NULL);
1849 if (!uzbl.gui.scrolled_win &&
1853 gtk_widget_ref(uzbl.gui.scrolled_win);
1854 gtk_widget_ref(uzbl.gui.mainbar);
1855 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1856 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1858 if(uzbl.behave.status_top) {
1859 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1860 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1863 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.mainbar, FALSE, TRUE, 0);
1866 gtk_widget_unref(uzbl.gui.scrolled_win);
1867 gtk_widget_unref(uzbl.gui.mainbar);
1868 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1873 set_var_value(const gchar *name, gchar *val) {
1874 uzbl_cmdprop *c = NULL;
1877 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1879 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1880 if(!c->writeable) return FALSE;
1882 /* check for the variable type */
1883 if (c->type == TYPE_STR) {
1884 buf = expand(val, 0);
1887 } else if(c->type == TYPE_INT) {
1888 buf = expand(val, 0);
1889 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1891 } else if (c->type == TYPE_FLOAT) {
1892 buf = expand(val, 0);
1893 *c->ptr.f = strtod(buf, &endp);
1897 /* invoke a command specific function */
1898 if(c->func) c->func();
1900 /* check wether name violates our naming scheme */
1901 if(strpbrk(name, invalid_chars)) {
1902 if (uzbl.state.verbose)
1903 printf("Invalid variable name\n");
1908 c = malloc(sizeof(uzbl_cmdprop));
1913 buf = expand(val, 0);
1914 c->ptr.s = malloc(sizeof(char *));
1916 g_hash_table_insert(uzbl.comm.proto_var,
1917 g_strdup(name), (gpointer) c);
1924 Behaviour *b = &uzbl.behave;
1926 if(b->html_buffer->str) {
1927 webkit_web_view_load_html_string (uzbl.gui.web_view,
1928 b->html_buffer->str, b->base_url);
1929 g_string_free(b->html_buffer, TRUE);
1930 b->html_buffer = g_string_new("");
1934 enum {M_CMD, M_HTML};
1936 parse_cmd_line(const char *ctl_line, GString *result) {
1937 Behaviour *b = &uzbl.behave;
1940 if(b->mode == M_HTML) {
1941 len = strlen(b->html_endmarker);
1942 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1943 if(len == strlen(ctl_line)-1 &&
1944 !strncmp(b->html_endmarker, ctl_line, len)) {
1946 set_var_value("mode", "0");
1951 set_timeout(b->html_timeout);
1952 g_string_append(b->html_buffer, ctl_line);
1955 else if((ctl_line[0] == '#') /* Comments */
1956 || (ctl_line[0] == ' ')
1957 || (ctl_line[0] == '\n'))
1958 ; /* ignore these lines */
1959 else { /* parse a command */
1961 gchar **tokens = NULL;
1962 len = strlen(ctl_line);
1964 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1965 ctlstrip = g_strndup(ctl_line, len - 1);
1966 else ctlstrip = g_strdup(ctl_line);
1968 tokens = g_strsplit(ctlstrip, " ", 2);
1969 parse_command(tokens[0], tokens[1], result);
1976 build_stream_name(int type, const gchar* dir) {
1977 State *s = &uzbl.state;
1981 str = g_strdup_printf
1982 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1983 } else if (type == SOCKET) {
1984 str = g_strdup_printf
1985 ("%s/uzbl_socket_%s", dir, s->instance_name);
1991 control_fifo(GIOChannel *gio, GIOCondition condition) {
1992 if (uzbl.state.verbose)
1993 printf("triggered\n");
1998 if (condition & G_IO_HUP)
1999 g_error ("Fifo: Read end of pipe died!\n");
2002 g_error ("Fifo: GIOChannel broke\n");
2004 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2005 if (ret == G_IO_STATUS_ERROR) {
2006 g_error ("Fifo: Error reading: %s\n", err->message);
2010 parse_cmd_line(ctl_line, NULL);
2017 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2018 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2019 if (unlink(uzbl.comm.fifo_path) == -1)
2020 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2021 g_free(uzbl.comm.fifo_path);
2022 uzbl.comm.fifo_path = NULL;
2025 GIOChannel *chan = NULL;
2026 GError *error = NULL;
2027 gchar *path = build_stream_name(FIFO, dir);
2029 if (!file_exists(path)) {
2030 if (mkfifo (path, 0666) == 0) {
2031 // 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.
2032 chan = g_io_channel_new_file(path, "r+", &error);
2034 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2035 if (uzbl.state.verbose)
2036 printf ("init_fifo: created successfully as %s\n", path);
2037 uzbl.comm.fifo_path = path;
2039 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2040 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2041 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2042 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2044 /* if we got this far, there was an error; cleanup */
2045 if (error) g_error_free (error);
2052 control_stdin(GIOChannel *gio, GIOCondition condition) {
2054 gchar *ctl_line = NULL;
2057 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2058 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2061 parse_cmd_line(ctl_line, NULL);
2069 GIOChannel *chan = NULL;
2070 GError *error = NULL;
2072 chan = g_io_channel_unix_new(fileno(stdin));
2074 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2075 g_error ("Stdin: could not add watch\n");
2077 if (uzbl.state.verbose)
2078 printf ("Stdin: watch added successfully\n");
2081 g_error ("Stdin: Error while opening: %s\n", error->message);
2083 if (error) g_error_free (error);
2087 control_socket(GIOChannel *chan) {
2088 struct sockaddr_un remote;
2089 unsigned int t = sizeof(remote);
2091 GIOChannel *clientchan;
2093 clientsock = accept (g_io_channel_unix_get_fd(chan),
2094 (struct sockaddr *) &remote, &t);
2096 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2097 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2098 (GIOFunc) control_client_socket, clientchan);
2105 control_client_socket(GIOChannel *clientchan) {
2107 GString *result = g_string_new("");
2108 GError *error = NULL;
2112 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2113 if (ret == G_IO_STATUS_ERROR) {
2114 g_warning ("Error reading: %s\n", error->message);
2115 g_io_channel_shutdown(clientchan, TRUE, &error);
2117 } else if (ret == G_IO_STATUS_EOF) {
2118 /* shutdown and remove channel watch from main loop */
2119 g_io_channel_shutdown(clientchan, TRUE, &error);
2124 parse_cmd_line (ctl_line, result);
2125 g_string_append_c(result, '\n');
2126 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2128 if (ret == G_IO_STATUS_ERROR) {
2129 g_warning ("Error writing: %s", error->message);
2131 g_io_channel_flush(clientchan, &error);
2134 if (error) g_error_free (error);
2135 g_string_free(result, TRUE);
2141 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2142 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2143 if (unlink(uzbl.comm.socket_path) == -1)
2144 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2145 g_free(uzbl.comm.socket_path);
2146 uzbl.comm.socket_path = NULL;
2154 GIOChannel *chan = NULL;
2156 struct sockaddr_un local;
2157 gchar *path = build_stream_name(SOCKET, dir);
2159 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2161 local.sun_family = AF_UNIX;
2162 strcpy (local.sun_path, path);
2163 unlink (local.sun_path);
2165 len = strlen (local.sun_path) + sizeof (local.sun_family);
2166 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2167 if (uzbl.state.verbose)
2168 printf ("init_socket: opened in %s\n", path);
2171 if( (chan = g_io_channel_unix_new(sock)) ) {
2172 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2173 uzbl.comm.socket_path = path;
2176 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2178 /* if we got this far, there was an error; cleanup */
2185 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2186 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2188 // this function may be called very early when the templates are not set (yet), hence the checks
2190 update_title (void) {
2191 Behaviour *b = &uzbl.behave;
2194 if (b->show_status) {
2195 if (b->title_format_short) {
2196 parsed = expand(b->title_format_short, 0);
2197 if (uzbl.gui.main_window)
2198 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2201 if (b->status_format) {
2202 parsed = expand(b->status_format, 0);
2203 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2206 if (b->status_background) {
2208 gdk_color_parse (b->status_background, &color);
2209 //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)
2210 if (uzbl.gui.main_window)
2211 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2212 else if (uzbl.gui.plug)
2213 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2216 if (b->title_format_long) {
2217 parsed = expand(b->title_format_long, 0);
2218 if (uzbl.gui.main_window)
2219 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2226 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2230 retrieve_geometry();
2235 key_press_cb (GtkWidget* window, GdkEventKey* event)
2237 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2241 if (event->type != GDK_KEY_PRESS ||
2242 event->keyval == GDK_Page_Up ||
2243 event->keyval == GDK_Page_Down ||
2244 event->keyval == GDK_Up ||
2245 event->keyval == GDK_Down ||
2246 event->keyval == GDK_Left ||
2247 event->keyval == GDK_Right ||
2248 event->keyval == GDK_Shift_L ||
2249 event->keyval == GDK_Shift_R)
2252 /* turn off insert mode (if always_insert_mode is not used) */
2253 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2254 set_insert_mode(uzbl.behave.always_insert_mode);
2259 if (uzbl.behave.insert_mode &&
2260 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2261 (!uzbl.behave.modmask)
2266 if (event->keyval == GDK_Escape) {
2269 dehilight(uzbl.gui.web_view, NULL, NULL);
2273 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2274 if (event->keyval == GDK_Insert) {
2276 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2277 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2279 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2282 GString* keycmd = g_string_new(uzbl.state.keycmd);
2283 g_string_append (keycmd, str);
2284 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2291 if (event->keyval == GDK_BackSpace)
2292 keycmd_bs(NULL, NULL, NULL);
2294 gboolean key_ret = FALSE;
2295 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2298 GString* keycmd = g_string_new(uzbl.state.keycmd);
2299 g_string_append(keycmd, event->string);
2300 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2303 run_keycmd(key_ret);
2305 if (key_ret) return (!uzbl.behave.insert_mode);
2310 run_keycmd(const gboolean key_ret) {
2311 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2313 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2315 parse_command(act->name, act->param, NULL);
2319 /* try if it's an incremental keycmd or one that takes args, and run it */
2320 GString* short_keys = g_string_new ("");
2321 GString* short_keys_inc = g_string_new ("");
2323 guint len = strlen(uzbl.state.keycmd);
2324 for (i=0; i<len; i++) {
2325 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2326 g_string_assign(short_keys_inc, short_keys->str);
2327 g_string_append_c(short_keys, '_');
2328 g_string_append_c(short_keys_inc, '*');
2330 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2331 /* run normal cmds only if return was pressed */
2332 exec_paramcmd(act, i);
2335 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2336 if (key_ret) /* just quit the incremental command on return */
2338 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2342 g_string_truncate(short_keys, short_keys->len - 1);
2344 g_string_free (short_keys, TRUE);
2345 g_string_free (short_keys_inc, TRUE);
2349 exec_paramcmd(const Action *act, const guint i) {
2350 GString *parampart = g_string_new (uzbl.state.keycmd);
2351 GString *actionname = g_string_new ("");
2352 GString *actionparam = g_string_new ("");
2353 g_string_erase (parampart, 0, i+1);
2355 g_string_printf (actionname, act->name, parampart->str);
2357 g_string_printf (actionparam, act->param, parampart->str);
2358 parse_command(actionname->str, actionparam->str, NULL);
2359 g_string_free(actionname, TRUE);
2360 g_string_free(actionparam, TRUE);
2361 g_string_free(parampart, TRUE);
2369 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2371 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2372 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2373 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2378 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2379 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2380 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2381 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2388 g->mainbar = gtk_hbox_new (FALSE, 0);
2390 /* keep a reference to the bar so we can re-pack it at runtime*/
2391 //sbar_ref = g_object_ref(g->mainbar);
2393 g->mainbar_label = gtk_label_new ("");
2394 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2395 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2396 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2397 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2398 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2399 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2405 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2406 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2407 gtk_widget_set_name (window, "Uzbl browser");
2408 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2409 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2410 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2417 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2418 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2419 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2426 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2428 If actname is one that calls an external command, this function will inject
2429 newargs in front of the user-provided args in that command line. They will
2430 come become after the body of the script (in sh) or after the name of
2431 the command to execute (in spawn).
2432 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2433 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2435 The return value consist of two strings: the action (sh, ...) and its args.
2437 If act is not one that calls an external command, then the given action merely
2440 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2441 /* Arrr! Here be memory leaks */
2442 gchar *actdup = g_strdup(actname);
2443 g_array_append_val(rets, actdup);
2445 if ((g_strcmp0(actname, "spawn") == 0) ||
2446 (g_strcmp0(actname, "sh") == 0) ||
2447 (g_strcmp0(actname, "sync_spawn") == 0) ||
2448 (g_strcmp0(actname, "sync_sh") == 0) ||
2449 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2451 GString *a = g_string_new("");
2452 gchar **spawnparts = split_quoted(origargs, FALSE);
2453 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2454 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2456 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2457 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2459 g_array_append_val(rets, a->str);
2460 g_string_free(a, FALSE);
2461 g_strfreev(spawnparts);
2463 gchar *origdup = g_strdup(origargs);
2464 g_array_append_val(rets, origdup);
2466 return (gchar**)g_array_free(rets, FALSE);
2470 run_handler (const gchar *act, const gchar *args) {
2471 /* Consider this code a temporary hack to make the handlers usable.
2472 In practice, all this splicing, injection, and reconstruction is
2473 inefficient, annoying and hard to manage. Potential pitfalls arise
2474 when the handler specific args 1) are not quoted (the handler
2475 callbacks should take care of this) 2) are quoted but interfere
2476 with the users' own quotation. A more ideal solution is
2477 to refactor parse_command so that it doesn't just take a string
2478 and execute it; rather than that, we should have a function which
2479 returns the argument vector parsed from the string. This vector
2480 could be modified (e.g. insert additional args into it) before
2481 passing it to the next function that actually executes it. Though
2482 it still isn't perfect for chain actions.. will reconsider & re-
2483 factor when I have the time. -duc */
2485 char **parts = g_strsplit(act, " ", 2);
2487 if (g_strcmp0(parts[0], "chain") == 0) {
2488 GString *newargs = g_string_new("");
2489 gchar **chainparts = split_quoted(parts[1], FALSE);
2491 /* for every argument in the chain, inject the handler args
2492 and make sure the new parts are wrapped in quotes */
2493 gchar **cp = chainparts;
2495 gchar *quotless = NULL;
2496 gchar **spliced_quotless = NULL; // sigh -_-;
2497 gchar **inpart = NULL;
2500 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2502 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2503 } else quotless = g_strdup(*cp);
2505 spliced_quotless = g_strsplit(quotless, " ", 2);
2506 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2507 g_strfreev(spliced_quotless);
2509 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2515 parse_command(parts[0], &(newargs->str[1]), NULL);
2516 g_string_free(newargs, TRUE);
2517 g_strfreev(chainparts);
2520 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2521 parse_command(inparts[0], inparts[1], NULL);
2529 add_binding (const gchar *key, const gchar *act) {
2530 char **parts = g_strsplit(act, " ", 2);
2537 if (uzbl.state.verbose)
2538 printf ("Binding %-10s : %s\n", key, act);
2539 action = new_action(parts[0], parts[1]);
2541 if (g_hash_table_remove (uzbl.bindings, key))
2542 g_warning ("Overwriting existing binding for \"%s\"", key);
2543 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2548 get_xdg_var (XDG_Var xdg) {
2549 const gchar* actual_value = getenv (xdg.environmental);
2550 const gchar* home = getenv ("HOME");
2551 gchar* return_value;
2553 if (! actual_value || strcmp (actual_value, "") == 0) {
2554 if (xdg.default_value) {
2555 return_value = str_replace ("~", home, xdg.default_value);
2557 return_value = NULL;
2560 return_value = str_replace("~", home, actual_value);
2563 return return_value;
2567 find_xdg_file (int xdg_type, const char* filename) {
2568 /* xdg_type = 0 => config
2569 xdg_type = 1 => data
2570 xdg_type = 2 => cache*/
2572 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2573 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2576 gchar* temporary_string;
2580 if (! file_exists (temporary_file) && xdg_type != 2) {
2581 buf = get_xdg_var (XDG[3 + xdg_type]);
2582 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2585 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2586 g_free (temporary_file);
2587 temporary_file = g_strconcat (temporary_string, filename, NULL);
2591 //g_free (temporary_string); - segfaults.
2593 if (file_exists (temporary_file)) {
2594 return temporary_file;
2596 g_free(temporary_file);
2602 State *s = &uzbl.state;
2603 Network *n = &uzbl.net;
2605 for (i = 0; default_config[i].command != NULL; i++) {
2606 parse_cmd_line(default_config[i].command, NULL);
2609 if (g_strcmp0(s->config_file, "-") == 0) {
2610 s->config_file = NULL;
2614 else if (!s->config_file) {
2615 s->config_file = find_xdg_file (0, "/uzbl/config");
2618 if (s->config_file) {
2619 GArray* lines = read_file_by_line (s->config_file);
2623 while ((line = g_array_index(lines, gchar*, i))) {
2624 parse_cmd_line (line, NULL);
2628 g_array_free (lines, TRUE);
2630 if (uzbl.state.verbose)
2631 printf ("No configuration file loaded.\n");
2634 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2637 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2640 if (!uzbl.behave.cookie_handler)
2643 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2644 GString *s = g_string_new ("");
2645 SoupURI * soup_uri = soup_message_get_uri(msg);
2646 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2647 run_handler(uzbl.behave.cookie_handler, s->str);
2649 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2650 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2651 if ( p != NULL ) *p = '\0';
2652 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2654 if (uzbl.comm.sync_stdout)
2655 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2657 g_string_free(s, TRUE);
2661 save_cookies (SoupMessage *msg, gpointer user_data){
2665 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2666 cookie = soup_cookie_to_set_cookie_header(ck->data);
2667 SoupURI * soup_uri = soup_message_get_uri(msg);
2668 GString *s = g_string_new ("");
2669 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2670 run_handler(uzbl.behave.cookie_handler, s->str);
2672 g_string_free(s, TRUE);
2677 /* --- WEBINSPECTOR --- */
2679 hide_window_cb(GtkWidget *widget, gpointer data) {
2682 gtk_widget_hide(widget);
2686 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2689 (void) web_inspector;
2690 GtkWidget* scrolled_window;
2691 GtkWidget* new_web_view;
2694 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2695 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2696 G_CALLBACK(hide_window_cb), NULL);
2698 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2699 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2700 gtk_widget_show(g->inspector_window);
2702 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2703 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2704 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2705 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2706 gtk_widget_show(scrolled_window);
2708 new_web_view = webkit_web_view_new();
2709 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2711 return WEBKIT_WEB_VIEW(new_web_view);
2715 inspector_show_window_cb (WebKitWebInspector* inspector){
2717 gtk_widget_show(uzbl.gui.inspector_window);
2721 /* TODO: Add variables and code to make use of these functions */
2723 inspector_close_window_cb (WebKitWebInspector* inspector){
2729 inspector_attach_window_cb (WebKitWebInspector* inspector){
2735 inspector_detach_window_cb (WebKitWebInspector* inspector){
2741 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2747 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2753 set_up_inspector() {
2755 WebKitWebSettings *settings = view_settings();
2756 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2758 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2759 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2760 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2761 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2762 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2763 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2764 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2766 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2770 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2772 uzbl_cmdprop *c = v;
2777 if(c->type == TYPE_STR)
2778 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2779 else if(c->type == TYPE_INT)
2780 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2781 else if(c->type == TYPE_FLOAT)
2782 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2786 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2790 printf("bind %s = %s %s\n", (char *)k ,
2791 (char *)a->name, a->param?(char *)a->param:"");
2796 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2797 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2801 retrieve_geometry() {
2803 GString *buf = g_string_new("");
2805 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2806 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2808 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2810 if(uzbl.gui.geometry)
2811 g_free(uzbl.gui.geometry);
2812 uzbl.gui.geometry = g_string_free(buf, FALSE);
2815 /* set up gtk, gobject, variable defaults and other things that tests and other
2816 * external applications need to do anyhow */
2818 initialize(int argc, char *argv[]) {
2819 if (!g_thread_supported ())
2820 g_thread_init (NULL);
2821 uzbl.state.executable_path = g_strdup(argv[0]);
2822 uzbl.state.selected_url = NULL;
2823 uzbl.state.searchtx = NULL;
2825 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2826 g_option_context_add_main_entries (context, entries, NULL);
2827 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2828 g_option_context_parse (context, &argc, &argv, NULL);
2829 g_option_context_free(context);
2831 if (uzbl.behave.print_version) {
2832 printf("Commit: %s\n", COMMIT);
2836 /* initialize hash table */
2837 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2839 uzbl.net.soup_session = webkit_get_default_session();
2840 uzbl.state.keycmd = g_strdup("");
2842 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2843 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2844 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2845 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2846 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2847 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2849 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2850 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2851 uzbl.gui.sbar.progress_w = 10;
2853 /* HTML mode defaults*/
2854 uzbl.behave.html_buffer = g_string_new("");
2855 uzbl.behave.html_endmarker = g_strdup(".");
2856 uzbl.behave.html_timeout = 60;
2857 uzbl.behave.base_url = g_strdup("http://invalid");
2859 /* default mode indicators */
2860 uzbl.behave.insert_indicator = g_strdup("I");
2861 uzbl.behave.cmd_indicator = g_strdup("C");
2863 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2864 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2865 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2866 uzbl.info.arch = ARCH;
2867 uzbl.info.commit = COMMIT;
2870 make_var_to_name_hash();
2875 #ifndef UZBL_LIBRARY
2878 main (int argc, char* argv[]) {
2879 initialize(argc, argv);
2881 gtk_init (&argc, &argv);
2883 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2884 //main_window_ref = g_object_ref(scrolled_window);
2885 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2886 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2888 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2889 GTK_WIDGET (uzbl.gui.web_view));
2891 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2895 /* initial packing */
2896 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2897 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2899 if (uzbl.state.socket_id) {
2900 uzbl.gui.plug = create_plug ();
2901 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2902 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2904 uzbl.gui.main_window = create_window ();
2905 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2906 gtk_widget_show_all (uzbl.gui.main_window);
2907 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2910 if(!uzbl.state.instance_name)
2911 uzbl.state.instance_name = itos((int)uzbl.xwin);
2913 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2915 if (uzbl.state.verbose) {
2916 printf("Uzbl start location: %s\n", argv[0]);
2917 if (uzbl.state.socket_id)
2918 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2920 printf("window_id %i\n",(int) uzbl.xwin);
2921 printf("pid %i\n", getpid ());
2922 printf("name: %s\n", uzbl.state.instance_name);
2925 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2926 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2927 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2928 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2929 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2931 if(uzbl.gui.geometry)
2934 retrieve_geometry();
2936 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2937 if (argc > 1 && !uzbl.state.uri)
2938 uri_override = g_strdup(argv[1]);
2939 gboolean verbose_override = uzbl.state.verbose;
2942 set_insert_mode(FALSE);
2944 if (!uzbl.behave.show_status)
2945 gtk_widget_hide(uzbl.gui.mainbar);
2952 if (verbose_override > uzbl.state.verbose)
2953 uzbl.state.verbose = verbose_override;
2956 set_var_value("uri", uri_override);
2957 g_free(uri_override);
2958 } else if (uzbl.state.uri)
2964 return EXIT_SUCCESS;
2968 /* vi: set et ts=4: */