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 */
91 /* TODO: Make this ambiguous void **ptr into a union { char *char_p; int *int_p; float *float_p; } val;
92 the PTR() macro is kind of preventing this change at the moment. */
101 /*@null@*/ void (*func)(void);
104 /* abbreviations to help keep the table's width humane */
105 #define PTR_V_STR(var, d, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = d, .writeable = 1, .func = fun }
106 #define PTR_V_INT(var, d, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = d, .writeable = 1, .func = fun }
107 #define PTR_V_FLOAT(var, d, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = d, .writeable = 1, .func = fun }
108 #define PTR_C_STR(var, fun) { .ptr.s = &(var), .type = TYPE_STR, .dump = 0, .writeable = 0, .func = fun }
109 #define PTR_C_INT(var, fun) { .ptr.i = (int*)&(var), .type = TYPE_INT, .dump = 0, .writeable = 0, .func = fun }
110 #define PTR_C_FLOAT(var, fun) { .ptr.f = &(var), .type = TYPE_FLOAT, .dump = 0, .writeable = 0, .func = fun }
112 const struct var_name_to_ptr_t {
115 } var_name_to_ptr[] = {
116 /* variable name pointer to variable in code dump callback function */
117 /* ---------------------------------------------------------------------------------------------- */
118 { "uri", PTR_V_STR(uzbl.state.uri, 1, cmd_load_uri)},
119 { "verbose", PTR_V_INT(uzbl.state.verbose, 1, NULL)},
120 { "mode", PTR_V_INT(uzbl.behave.mode, 0, NULL)},
121 { "inject_html", PTR_V_STR(uzbl.behave.inject_html, 0, cmd_inject_html)},
122 { "base_url", PTR_V_STR(uzbl.behave.base_url, 1, NULL)},
123 { "html_endmarker", PTR_V_STR(uzbl.behave.html_endmarker, 1, NULL)},
124 { "html_mode_timeout", PTR_V_INT(uzbl.behave.html_timeout, 1, NULL)},
125 { "keycmd", PTR_V_STR(uzbl.state.keycmd, 1, set_keycmd)},
126 { "status_message", PTR_V_STR(uzbl.gui.sbar.msg, 1, update_title)},
127 { "show_status", PTR_V_INT(uzbl.behave.show_status, 1, cmd_set_status)},
128 { "status_top", PTR_V_INT(uzbl.behave.status_top, 1, move_statusbar)},
129 { "status_format", PTR_V_STR(uzbl.behave.status_format, 1, update_title)},
130 { "status_pbar_done", PTR_V_STR(uzbl.gui.sbar.progress_s, 1, update_title)},
131 { "status_pbar_pending", PTR_V_STR(uzbl.gui.sbar.progress_u, 1, update_title)},
132 { "status_pbar_width", PTR_V_INT(uzbl.gui.sbar.progress_w, 1, update_title)},
133 { "status_background", PTR_V_STR(uzbl.behave.status_background, 1, update_title)},
134 { "insert_indicator", PTR_V_STR(uzbl.behave.insert_indicator, 1, update_indicator)},
135 { "command_indicator", PTR_V_STR(uzbl.behave.cmd_indicator, 1, update_indicator)},
136 { "title_format_long", PTR_V_STR(uzbl.behave.title_format_long, 1, update_title)},
137 { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, update_title)},
138 { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)},
139 { "insert_mode", PTR_V_INT(uzbl.behave.insert_mode, 1, set_mode_indicator)},
140 { "always_insert_mode", PTR_V_INT(uzbl.behave.always_insert_mode, 1, cmd_always_insert_mode)},
141 { "reset_command_mode", PTR_V_INT(uzbl.behave.reset_command_mode, 1, NULL)},
142 { "modkey", PTR_V_STR(uzbl.behave.modkey, 1, cmd_modkey)},
143 { "load_finish_handler", PTR_V_STR(uzbl.behave.load_finish_handler, 1, NULL)},
144 { "load_start_handler", PTR_V_STR(uzbl.behave.load_start_handler, 1, NULL)},
145 { "load_commit_handler", PTR_V_STR(uzbl.behave.load_commit_handler, 1, NULL)},
146 { "history_handler", PTR_V_STR(uzbl.behave.history_handler, 1, NULL)},
147 { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)},
148 { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_cookie_handler)},
149 { "new_window", PTR_V_STR(uzbl.behave.new_window, 1, cmd_new_window)},
150 { "fifo_dir", PTR_V_STR(uzbl.behave.fifo_dir, 1, cmd_fifo_dir)},
151 { "socket_dir", PTR_V_STR(uzbl.behave.socket_dir, 1, cmd_socket_dir)},
152 { "http_debug", PTR_V_INT(uzbl.behave.http_debug, 1, cmd_http_debug)},
153 { "shell_cmd", PTR_V_STR(uzbl.behave.shell_cmd, 1, NULL)},
154 { "proxy_url", PTR_V_STR(uzbl.net.proxy_url, 1, set_proxy_url)},
155 { "max_conns", PTR_V_INT(uzbl.net.max_conns, 1, cmd_max_conns)},
156 { "max_conns_host", PTR_V_INT(uzbl.net.max_conns_host, 1, cmd_max_conns_host)},
157 { "useragent", PTR_V_STR(uzbl.net.useragent, 1, cmd_useragent)},
159 /* exported WebKitWebSettings properties */
160 { "zoom_level", PTR_V_FLOAT(uzbl.behave.zoom_level, 1, cmd_zoom_level)},
161 { "font_size", PTR_V_INT(uzbl.behave.font_size, 1, cmd_font_size)},
162 { "default_font_family", PTR_V_STR(uzbl.behave.default_font_family, 1, cmd_default_font_family)},
163 { "monospace_font_family", PTR_V_STR(uzbl.behave.monospace_font_family, 1, cmd_monospace_font_family)},
164 { "cursive_font_family", PTR_V_STR(uzbl.behave.cursive_font_family, 1, cmd_cursive_font_family)},
165 { "sans_serif_font_family", PTR_V_STR(uzbl.behave.sans_serif_font_family, 1, cmd_sans_serif_font_family)},
166 { "serif_font_family", PTR_V_STR(uzbl.behave.serif_font_family, 1, cmd_serif_font_family)},
167 { "fantasy_font_family", PTR_V_STR(uzbl.behave.fantasy_font_family, 1, cmd_fantasy_font_family)},
168 { "monospace_size", PTR_V_INT(uzbl.behave.monospace_size, 1, cmd_font_size)},
169 { "minimum_font_size", PTR_V_INT(uzbl.behave.minimum_font_size, 1, cmd_minimum_font_size)},
170 { "disable_plugins", PTR_V_INT(uzbl.behave.disable_plugins, 1, cmd_disable_plugins)},
171 { "disable_scripts", PTR_V_INT(uzbl.behave.disable_scripts, 1, cmd_disable_scripts)},
172 { "autoload_images", PTR_V_INT(uzbl.behave.autoload_img, 1, cmd_autoload_img)},
173 { "autoshrink_images", PTR_V_INT(uzbl.behave.autoshrink_img, 1, cmd_autoshrink_img)},
174 { "enable_spellcheck", PTR_V_INT(uzbl.behave.enable_spellcheck, 1, cmd_enable_spellcheck)},
175 { "enable_private", PTR_V_INT(uzbl.behave.enable_private, 1, cmd_enable_private)},
176 { "print_backgrounds", PTR_V_INT(uzbl.behave.print_bg, 1, cmd_print_bg)},
177 { "stylesheet_uri", PTR_V_STR(uzbl.behave.style_uri, 1, cmd_style_uri)},
178 { "resizable_text_areas", PTR_V_INT(uzbl.behave.resizable_txt, 1, cmd_resizable_txt)},
179 { "default_encoding", PTR_V_STR(uzbl.behave.default_encoding, 1, cmd_default_encoding)},
180 { "enforce_96_dpi", PTR_V_INT(uzbl.behave.enforce_96dpi, 1, cmd_enforce_96dpi)},
181 { "caret_browsing", PTR_V_INT(uzbl.behave.caret_browsing, 1, cmd_caret_browsing)},
183 /* constants (not dumpable or writeable) */
184 { "WEBKIT_MAJOR", PTR_C_INT(uzbl.info.webkit_major, NULL)},
185 { "WEBKIT_MINOR", PTR_C_INT(uzbl.info.webkit_minor, NULL)},
186 { "WEBKIT_MICRO", PTR_C_INT(uzbl.info.webkit_micro, NULL)},
187 { "ARCH_UZBL", PTR_C_STR(uzbl.info.arch, NULL)},
188 { "COMMIT", PTR_C_STR(uzbl.info.commit, NULL)},
189 { "LOAD_PROGRESS", PTR_C_INT(uzbl.gui.sbar.load_progress, NULL)},
190 { "LOAD_PROGRESSBAR", PTR_C_STR(uzbl.gui.sbar.progress_bar, NULL)},
191 { "TITLE", PTR_C_STR(uzbl.gui.main_title, NULL)},
192 { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)},
193 { "MODE", PTR_C_STR(uzbl.gui.sbar.mode_indicator, NULL)},
194 { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)},
196 { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}}
201 /*@null@*/ char *key;
204 { "SHIFT", GDK_SHIFT_MASK }, // shift
205 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
206 { "CONTROL", GDK_CONTROL_MASK }, // control
207 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
208 { "MOD2", GDK_MOD2_MASK }, // 5th mod
209 { "MOD3", GDK_MOD3_MASK }, // 6th mod
210 { "MOD4", GDK_MOD4_MASK }, // 7th mod
211 { "MOD5", GDK_MOD5_MASK }, // 8th mod
212 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
213 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
214 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
215 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
216 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
217 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
218 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
219 { "META", GDK_META_MASK }, // meta (since 2.10)
224 /* construct a hash from the var_name_to_ptr array for quick access */
226 make_var_to_name_hash() {
227 const struct var_name_to_ptr_t *n2v_p = var_name_to_ptr;
228 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
230 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (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');
311 ret = g_strndup(s, vend-s);
313 if(etype == EXP_SIMPLE_VAR ||
314 etype == EXP_BRACED_VAR) {
315 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
316 if(c->type == TYPE_STR && *c->ptr.s != NULL) {
317 g_string_append(buf, (gchar *)*c->ptr.s);
318 } else if(c->type == TYPE_INT) {
319 g_string_append_printf(buf, "%d", *c->ptr.i);
321 else if(c->type == TYPE_FLOAT) {
322 g_string_append_printf(buf, "%f", *c->ptr.f);
326 if(etype == EXP_SIMPLE_VAR)
331 else if(recurse != 1 &&
333 mycmd = expand(ret, 1);
334 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
338 g_printerr("error on running command: %s\n", err->message);
341 else if (*cmd_stdout) {
342 size_t len = strlen(cmd_stdout);
344 if(len > 0 && cmd_stdout[len-1] == '\n')
345 cmd_stdout[--len] = '\0'; /* strip trailing newline */
347 g_string_append(buf, cmd_stdout);
352 else if(recurse != 2 &&
354 mycmd = expand(ret, 2);
355 eval_js(uzbl.gui.web_view, mycmd, js_ret);
359 g_string_append(buf, js_ret->str);
360 g_string_free(js_ret, TRUE);
361 js_ret = g_string_new("");
365 else if(etype == EXP_ESCAPE) {
366 mycmd = expand(ret, 0);
367 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
369 g_string_append(buf, escaped);
381 g_string_append_c(buf, *s);
386 g_string_free(js_ret, TRUE);
387 return g_string_free(buf, FALSE);
394 snprintf(tmp, sizeof(tmp), "%i", val);
395 return g_strdup(tmp);
399 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
402 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
405 str_replace (const char* search, const char* replace, const char* string) {
409 buf = g_strsplit (string, search, -1);
410 ret = g_strjoinv (replace, buf);
411 g_strfreev(buf); // somebody said this segfaults
417 read_file_by_line (const gchar *path) {
418 GIOChannel *chan = NULL;
419 gchar *readbuf = NULL;
421 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
424 chan = g_io_channel_new_file(path, "r", NULL);
427 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
428 const gchar* val = g_strdup (readbuf);
429 g_array_append_val (lines, val);
434 g_io_channel_unref (chan);
436 fprintf(stderr, "File '%s' not be read.\n", path);
443 parseenv (char* string) {
444 extern char** environ;
445 gchar* tmpstr = NULL;
449 while (environ[i] != NULL) {
450 gchar** env = g_strsplit (environ[i], "=", 2);
451 gchar* envname = g_strconcat ("$", env[0], NULL);
453 if (g_strrstr (string, envname) != NULL) {
454 tmpstr = g_strdup(string);
456 string = str_replace(envname, env[1], tmpstr);
461 g_strfreev (env); // somebody said this breaks uzbl
469 setup_signal(int signr, sigfunc *shandler) {
470 struct sigaction nh, oh;
472 nh.sa_handler = shandler;
473 sigemptyset(&nh.sa_mask);
476 if(sigaction(signr, &nh, &oh) < 0)
484 if (uzbl.behave.fifo_dir)
485 unlink (uzbl.comm.fifo_path);
486 if (uzbl.behave.socket_dir)
487 unlink (uzbl.comm.socket_path);
489 g_free(uzbl.state.executable_path);
490 g_free(uzbl.state.keycmd);
491 g_hash_table_destroy(uzbl.bindings);
492 g_hash_table_destroy(uzbl.behave.commands);
495 /* used for html_mode_timeout
496 * be sure to extend this function to use
497 * more timers if needed in other places
500 set_timeout(int seconds) {
502 memset(&t, 0, sizeof t);
504 t.it_value.tv_sec = seconds;
505 t.it_value.tv_usec = 0;
506 setitimer(ITIMER_REAL, &t, NULL);
509 /* --- SIGNAL HANDLER --- */
512 catch_sigterm(int s) {
518 catch_sigint(int s) {
528 set_var_value("mode", "0");
533 /* --- CALLBACKS --- */
536 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
539 (void) navigation_action;
540 (void) policy_decision;
542 const gchar* uri = webkit_network_request_get_uri (request);
543 if (uzbl.state.verbose)
544 printf("New window requested -> %s \n", uri);
545 webkit_web_policy_decision_use(policy_decision);
550 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
555 /* If we can display it, let's display it... */
556 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
557 webkit_web_policy_decision_use (policy_decision);
561 /* ...everything we can't displayed is downloaded */
562 webkit_web_policy_decision_download (policy_decision);
566 /*@null@*/ WebKitWebView*
567 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
571 if (uzbl.state.selected_url != NULL) {
572 if (uzbl.state.verbose)
573 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
574 new_window_load_uri(uzbl.state.selected_url);
576 if (uzbl.state.verbose)
577 printf("New web view -> %s\n","Nothing to open, exiting");
583 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
586 if (uzbl.behave.download_handler) {
587 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
588 if (uzbl.state.verbose)
589 printf("Download -> %s\n",uri);
590 /* if urls not escaped, we may have to escape and quote uri before this call */
591 run_handler(uzbl.behave.download_handler, uri);
596 /* scroll a bar in a given direction */
598 scroll (GtkAdjustment* bar, GArray *argv) {
602 gdouble page_size = gtk_adjustment_get_page_size(bar);
603 gdouble value = gtk_adjustment_get_value(bar);
604 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
607 value += page_size * amount * 0.01;
611 max_value = gtk_adjustment_get_upper(bar) - page_size;
613 if (value > max_value)
614 value = max_value; /* don't scroll past the end of the page */
616 gtk_adjustment_set_value (bar, value);
620 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
621 (void) page; (void) argv; (void) result;
622 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
626 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
627 (void) page; (void) argv; (void) result;
628 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
629 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
633 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
634 (void) page; (void) result;
635 scroll(uzbl.gui.bar_v, argv);
639 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
640 (void) page; (void) result;
641 scroll(uzbl.gui.bar_h, argv);
646 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
647 if(uzbl.state.verbose)
648 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
650 /* update geometry var with the actual geometry
651 this is necessary as some WMs don't seem to honour
652 the above setting and we don't want to end up with
653 wrong geometry information
660 if (!uzbl.behave.show_status) {
661 gtk_widget_hide(uzbl.gui.mainbar);
663 gtk_widget_show(uzbl.gui.mainbar);
669 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
674 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
678 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
683 if (uzbl.behave.show_status) {
684 gtk_widget_hide(uzbl.gui.mainbar);
686 gtk_widget_show(uzbl.gui.mainbar);
688 uzbl.behave.show_status = !uzbl.behave.show_status;
693 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
697 //Set selected_url state variable
698 g_free(uzbl.state.selected_url);
699 uzbl.state.selected_url = NULL;
701 uzbl.state.selected_url = g_strdup(link);
707 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
710 const gchar *title = webkit_web_view_get_title(web_view);
711 if (uzbl.gui.main_title)
712 g_free (uzbl.gui.main_title);
713 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
718 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
721 uzbl.gui.sbar.load_progress = progress;
723 g_free(uzbl.gui.sbar.progress_bar);
724 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
730 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
734 if (uzbl.behave.load_finish_handler)
735 run_handler(uzbl.behave.load_finish_handler, "");
738 void clear_keycmd() {
739 g_free(uzbl.state.keycmd);
740 uzbl.state.keycmd = g_strdup("");
744 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
748 uzbl.gui.sbar.load_progress = 0;
749 clear_keycmd(); // don't need old commands to remain on new page?
750 if (uzbl.behave.load_start_handler)
751 run_handler(uzbl.behave.load_start_handler, "");
755 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
758 g_free (uzbl.state.uri);
759 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
760 uzbl.state.uri = g_string_free (newuri, FALSE);
761 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
762 set_insert_mode(uzbl.behave.always_insert_mode);
765 if (uzbl.behave.load_commit_handler)
766 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
770 destroy_cb (GtkWidget* widget, gpointer data) {
778 if (uzbl.behave.history_handler) {
780 struct tm * timeinfo;
783 timeinfo = localtime ( &rawtime );
784 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
785 run_handler(uzbl.behave.history_handler, date);
790 /* VIEW funcs (little webkit wrappers) */
791 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
793 VIEWFUNC(reload_bypass_cache)
794 VIEWFUNC(stop_loading)
801 /* -- command to callback/function map for things we cannot attach to any signals */
802 struct {const char *key; CommandInfo value;} cmdlist[] =
803 { /* key function no_split */
804 { "back", {view_go_back, 0} },
805 { "forward", {view_go_forward, 0} },
806 { "scroll_vert", {scroll_vert, 0} },
807 { "scroll_horz", {scroll_horz, 0} },
808 { "scroll_begin", {scroll_begin, 0} },
809 { "scroll_end", {scroll_end, 0} },
810 { "reload", {view_reload, 0}, },
811 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
812 { "stop", {view_stop_loading, 0}, },
813 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
814 { "zoom_out", {view_zoom_out, 0}, },
815 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
816 { "uri", {load_uri, TRUE} },
817 { "js", {run_js, TRUE} },
818 { "script", {run_external_js, 0} },
819 { "toggle_status", {toggle_status_cb, 0} },
820 { "spawn", {spawn, 0} },
821 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
822 { "sh", {spawn_sh, 0} },
823 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
824 { "talk_to_socket", {talk_to_socket, 0} },
825 { "exit", {close_uzbl, 0} },
826 { "search", {search_forward_text, TRUE} },
827 { "search_reverse", {search_reverse_text, TRUE} },
828 { "dehilight", {dehilight, 0} },
829 { "toggle_insert_mode", {toggle_insert_mode, 0} },
830 { "set", {set_var, TRUE} },
831 //{ "get", {get_var, TRUE} },
832 { "bind", {act_bind, TRUE} },
833 { "dump_config", {act_dump_config, 0} },
834 { "keycmd", {keycmd, TRUE} },
835 { "keycmd_nl", {keycmd_nl, TRUE} },
836 { "keycmd_bs", {keycmd_bs, 0} },
837 { "chain", {chain, 0} },
838 { "print", {print, TRUE} },
839 { "update_gui", {update_gui, TRUE} }
846 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
848 for (i = 0; i < LENGTH(cmdlist); i++)
849 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].key, &cmdlist[i].value);
852 /* -- CORE FUNCTIONS -- */
855 free_action(gpointer act) {
856 Action *action = (Action*)act;
857 g_free(action->name);
859 g_free(action->param);
864 new_action(const gchar *name, const gchar *param) {
865 Action *action = g_new(Action, 1);
867 action->name = g_strdup(name);
869 action->param = g_strdup(param);
871 action->param = NULL;
877 file_exists (const char * filename) {
878 return (access(filename, F_OK) == 0);
882 set_var(WebKitWebView *page, GArray *argv, GString *result) {
883 (void) page; (void) result;
884 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
885 if (split[0] != NULL) {
886 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
887 set_var_value(g_strstrip(split[0]), value);
894 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
895 (void) page; (void) argv; (void) result;
901 print(WebKitWebView *page, GArray *argv, GString *result) {
902 (void) page; (void) result;
905 buf = expand(argv_idx(argv, 0), 0);
906 g_string_assign(result, buf);
911 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
912 (void) page; (void) result;
913 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
914 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
915 add_binding(g_strstrip(split[0]), value);
933 set_mode_indicator() {
934 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
935 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
940 set_mode_indicator();
945 set_insert_mode(gboolean mode) {
946 uzbl.behave.insert_mode = mode;
947 set_mode_indicator();
951 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
952 (void) page; (void) result;
954 if (argv_idx(argv, 0)) {
955 if (strcmp (argv_idx(argv, 0), "0") == 0) {
956 set_insert_mode(FALSE);
958 set_insert_mode(TRUE);
961 set_insert_mode( !uzbl.behave.insert_mode );
968 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
971 if (argv_idx(argv, 0)) {
972 GString* newuri = g_string_new (argv_idx(argv, 0));
973 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
974 run_js(web_view, argv, NULL);
977 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
978 g_string_prepend (newuri, "http://");
979 /* if we do handle cookies, ask our handler for them */
980 webkit_web_view_load_uri (web_view, newuri->str);
981 g_string_free (newuri, TRUE);
988 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
989 size_t argumentCount, const JSValueRef arguments[],
990 JSValueRef* exception) {
995 JSStringRef js_result_string;
996 GString *result = g_string_new("");
998 if (argumentCount >= 1) {
999 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1000 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1001 char ctl_line[arg_size];
1002 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1004 parse_cmd_line(ctl_line, result);
1006 JSStringRelease(arg);
1008 js_result_string = JSStringCreateWithUTF8CString(result->str);
1010 g_string_free(result, TRUE);
1012 return JSValueMakeString(ctx, js_result_string);
1015 JSStaticFunction js_static_functions[] = {
1016 {"run", js_run_command, kJSPropertyAttributeNone},
1021 /* This function creates the class and its definition, only once */
1022 if (!uzbl.js.initialized) {
1023 /* it would be pretty cool to make this dynamic */
1024 uzbl.js.classdef = kJSClassDefinitionEmpty;
1025 uzbl.js.classdef.staticFunctions = js_static_functions;
1027 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1033 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1034 WebKitWebFrame *frame;
1035 JSGlobalContextRef context;
1036 JSObjectRef globalobject;
1037 JSStringRef var_name;
1039 JSStringRef js_script;
1040 JSValueRef js_result;
1041 JSStringRef js_result_string;
1042 size_t js_result_size;
1046 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1047 context = webkit_web_frame_get_global_context(frame);
1048 globalobject = JSContextGetGlobalObject(context);
1050 /* uzbl javascript namespace */
1051 var_name = JSStringCreateWithUTF8CString("Uzbl");
1052 JSObjectSetProperty(context, globalobject, var_name,
1053 JSObjectMake(context, uzbl.js.classref, NULL),
1054 kJSClassAttributeNone, NULL);
1056 /* evaluate the script and get return value*/
1057 js_script = JSStringCreateWithUTF8CString(script);
1058 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1059 if (js_result && !JSValueIsUndefined(context, js_result)) {
1060 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1061 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1063 if (js_result_size) {
1064 char js_result_utf8[js_result_size];
1065 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1066 g_string_assign(result, js_result_utf8);
1069 JSStringRelease(js_result_string);
1073 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1075 JSStringRelease(var_name);
1076 JSStringRelease(js_script);
1080 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1081 if (argv_idx(argv, 0))
1082 eval_js(web_view, argv_idx(argv, 0), result);
1086 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1088 if (argv_idx(argv, 0)) {
1089 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1094 while ((line = g_array_index(lines, gchar*, i))) {
1096 js = g_strdup (line);
1098 gchar* newjs = g_strconcat (js, line, NULL);
1105 if (uzbl.state.verbose)
1106 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1108 if (argv_idx (argv, 1)) {
1109 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1113 eval_js (web_view, js, result);
1115 g_array_free (lines, TRUE);
1120 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1121 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1122 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1123 webkit_web_view_unmark_text_matches (page);
1124 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1125 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1129 if (uzbl.state.searchtx) {
1130 if (uzbl.state.verbose)
1131 printf ("Searching: %s\n", uzbl.state.searchtx);
1132 webkit_web_view_set_highlight_text_matches (page, TRUE);
1133 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1138 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1140 search_text(page, argv, TRUE);
1144 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1146 search_text(page, argv, FALSE);
1150 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1151 (void) argv; (void) result;
1152 webkit_web_view_set_highlight_text_matches (page, FALSE);
1157 new_window_load_uri (const gchar * uri) {
1158 if (uzbl.behave.new_window) {
1159 GString *s = g_string_new ("");
1160 g_string_printf(s, "'%s'", uri);
1161 run_handler(uzbl.behave.new_window, s->str);
1164 GString* to_execute = g_string_new ("");
1165 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1167 for (i = 0; entries[i].long_name != NULL; i++) {
1168 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1169 gchar** str = (gchar**)entries[i].arg_data;
1171 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1175 if (uzbl.state.verbose)
1176 printf("\n%s\n", to_execute->str);
1177 g_spawn_command_line_async (to_execute->str, NULL);
1178 g_string_free (to_execute, TRUE);
1182 chain (WebKitWebView *page, GArray *argv, GString *result) {
1183 (void) page; (void) result;
1185 gchar **parts = NULL;
1187 while ((a = argv_idx(argv, i++))) {
1188 parts = g_strsplit (a, " ", 2);
1190 parse_command(parts[0], parts[1], result);
1196 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1200 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1206 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1210 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1216 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1221 int len = strlen(uzbl.state.keycmd);
1222 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1224 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1229 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1236 /* --Statusbar functions-- */
1238 build_progressbar_ascii(int percent) {
1239 int width=uzbl.gui.sbar.progress_w;
1242 GString *bar = g_string_new("");
1244 l = (double)percent*((double)width/100.);
1245 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1247 for(i=0; i<(int)l; i++)
1248 g_string_append(bar, uzbl.gui.sbar.progress_s);
1251 g_string_append(bar, uzbl.gui.sbar.progress_u);
1253 return g_string_free(bar, FALSE);
1255 /* --End Statusbar functions-- */
1258 sharg_append(GArray *a, const gchar *str) {
1259 const gchar *s = (str ? str : "");
1260 g_array_append_val(a, s);
1263 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1265 run_command (const gchar *command, const guint npre, const gchar **args,
1266 const gboolean sync, char **output_stdout) {
1267 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1270 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1271 gchar *pid = itos(getpid());
1272 gchar *xwin = itos(uzbl.xwin);
1274 sharg_append(a, command);
1275 for (i = 0; i < npre; i++) /* add n args before the default vars */
1276 sharg_append(a, args[i]);
1277 sharg_append(a, uzbl.state.config_file);
1278 sharg_append(a, pid);
1279 sharg_append(a, xwin);
1280 sharg_append(a, uzbl.comm.fifo_path);
1281 sharg_append(a, uzbl.comm.socket_path);
1282 sharg_append(a, uzbl.state.uri);
1283 sharg_append(a, uzbl.gui.main_title);
1285 for (i = npre; i < g_strv_length((gchar**)args); i++)
1286 sharg_append(a, args[i]);
1290 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1292 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1293 NULL, NULL, output_stdout, NULL, NULL, &err);
1294 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1295 NULL, NULL, NULL, &err);
1297 if (uzbl.state.verbose) {
1298 GString *s = g_string_new("spawned:");
1299 for (i = 0; i < (a->len); i++) {
1300 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1301 g_string_append_printf(s, " %s", qarg);
1304 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1305 printf("%s\n", s->str);
1306 g_string_free(s, TRUE);
1308 printf("Stdout: %s\n", *output_stdout);
1312 g_printerr("error on run_command: %s\n", err->message);
1317 g_array_free (a, TRUE);
1322 split_quoted(const gchar* src, const gboolean unquote) {
1323 /* split on unquoted space, return array of strings;
1324 remove a layer of quotes and backslashes if unquote */
1325 if (!src) return NULL;
1327 gboolean dq = FALSE;
1328 gboolean sq = FALSE;
1329 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1330 GString *s = g_string_new ("");
1334 for (p = src; *p != '\0'; p++) {
1335 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1336 else if (*p == '\\') { g_string_append_c(s, *p++);
1337 g_string_append_c(s, *p); }
1338 else if ((*p == '"') && unquote && !sq) dq = !dq;
1339 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1341 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1342 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1344 else if ((*p == ' ') && !dq && !sq) {
1345 dup = g_strdup(s->str);
1346 g_array_append_val(a, dup);
1347 g_string_truncate(s, 0);
1348 } else g_string_append_c(s, *p);
1350 dup = g_strdup(s->str);
1351 g_array_append_val(a, dup);
1352 ret = (gchar**)a->data;
1353 g_array_free (a, FALSE);
1354 g_string_free (s, TRUE);
1359 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1360 (void)web_view; (void)result;
1361 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1362 if (argv_idx(argv, 0))
1363 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1367 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1368 (void)web_view; (void)result;
1370 if (argv_idx(argv, 0))
1371 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1372 TRUE, &uzbl.comm.sync_stdout);
1376 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1377 (void)web_view; (void)result;
1378 if (!uzbl.behave.shell_cmd) {
1379 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1384 gchar *spacer = g_strdup("");
1385 g_array_insert_val(argv, 1, spacer);
1386 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1388 for (i = 1; i < g_strv_length(cmd); i++)
1389 g_array_prepend_val(argv, cmd[i]);
1391 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1397 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1398 (void)web_view; (void)result;
1399 if (!uzbl.behave.shell_cmd) {
1400 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1405 gchar *spacer = g_strdup("");
1406 g_array_insert_val(argv, 1, spacer);
1407 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1409 for (i = 1; i < g_strv_length(cmd); i++)
1410 g_array_prepend_val(argv, cmd[i]);
1412 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1413 TRUE, &uzbl.comm.sync_stdout);
1419 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1420 (void)web_view; (void)result;
1423 struct sockaddr_un sa;
1430 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1432 /* This function could be optimised by storing a hash table of socket paths
1433 and associated connected file descriptors rather than closing and
1434 re-opening for every call. Also we could launch a script if socket connect
1437 /* First element argv[0] is path to socket. Following elements are tokens to
1438 write to the socket. We write them as a single packet with each token
1439 separated by an ASCII nul (\0). */
1441 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1446 /* copy socket path, null terminate result */
1447 sockpath = g_array_index(argv, char*, 0);
1448 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1449 sa.sun_family = AF_UNIX;
1451 /* create socket file descriptor and connect it to path */
1452 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1454 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1457 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1458 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1463 /* build request vector */
1464 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1466 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1470 for(i = 1; i < argv->len; ++i) {
1471 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1472 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1476 ret = writev(fd, iov, argv->len - 1);
1479 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1484 /* wait for a response, with a 500ms timeout */
1486 pfd.events = POLLIN;
1488 ret = poll(&pfd, 1, 500);
1490 if(ret == 0) errno = ETIMEDOUT;
1491 if(errno == EINTR) continue;
1492 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1498 /* get length of response */
1499 if(ioctl(fd, FIONREAD, &len) == -1) {
1500 g_printerr("talk_to_socket: cannot find daemon response length, "
1501 "ioctl failed (%s)\n", strerror(errno));
1506 /* if there is a response, read it */
1508 uzbl.comm.sync_stdout = g_malloc(len + 1);
1509 if(!uzbl.comm.sync_stdout) {
1510 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1514 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1516 ret = read(fd, uzbl.comm.sync_stdout, len);
1518 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1531 parse_command(const char *cmd, const char *param, GString *result) {
1534 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1536 gchar **par = split_quoted(param, TRUE);
1537 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1539 if (c->no_split) { /* don't split */
1540 sharg_append(a, param);
1542 for (i = 0; i < g_strv_length(par); i++)
1543 sharg_append(a, par[i]);
1546 if (result == NULL) {
1547 GString *result_print = g_string_new("");
1549 c->function(uzbl.gui.web_view, a, result_print);
1550 if (result_print->len)
1551 printf("%*s\n", (int)result_print->len, result_print->str);
1553 g_string_free(result_print, TRUE);
1555 c->function(uzbl.gui.web_view, a, result);
1558 g_array_free (a, TRUE);
1561 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1568 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1569 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1570 (GType) SOUP_SESSION_PROXY_URI);
1573 suri = soup_uri_new(uzbl.net.proxy_url);
1574 g_object_set(G_OBJECT(uzbl.net.soup_session),
1575 SOUP_SESSION_PROXY_URI,
1577 soup_uri_free(suri);
1584 if(file_exists(uzbl.gui.icon)) {
1585 if (uzbl.gui.main_window)
1586 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1588 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1594 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1595 g_array_append_val (a, uzbl.state.uri);
1596 load_uri(uzbl.gui.web_view, a, NULL);
1597 g_array_free (a, TRUE);
1601 cmd_always_insert_mode() {
1602 set_insert_mode(uzbl.behave.always_insert_mode);
1608 g_object_set(G_OBJECT(uzbl.net.soup_session),
1609 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1613 cmd_max_conns_host() {
1614 g_object_set(G_OBJECT(uzbl.net.soup_session),
1615 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1620 soup_session_remove_feature
1621 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1622 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1623 /*g_free(uzbl.net.soup_logger);*/
1625 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1626 soup_session_add_feature(uzbl.net.soup_session,
1627 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1632 return webkit_web_view_get_settings(uzbl.gui.web_view);
1637 WebKitWebSettings *ws = view_settings();
1638 if (uzbl.behave.font_size > 0) {
1639 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1642 if (uzbl.behave.monospace_size > 0) {
1643 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1644 uzbl.behave.monospace_size, NULL);
1646 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1647 uzbl.behave.font_size, NULL);
1652 cmd_default_font_family() {
1653 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1654 uzbl.behave.default_font_family, NULL);
1658 cmd_monospace_font_family() {
1659 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1660 uzbl.behave.monospace_font_family, NULL);
1664 cmd_sans_serif_font_family() {
1665 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1666 uzbl.behave.sans_serif_font_family, NULL);
1670 cmd_serif_font_family() {
1671 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1672 uzbl.behave.serif_font_family, NULL);
1676 cmd_cursive_font_family() {
1677 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1678 uzbl.behave.cursive_font_family, NULL);
1682 cmd_fantasy_font_family() {
1683 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1684 uzbl.behave.fantasy_font_family, NULL);
1689 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1693 cmd_disable_plugins() {
1694 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1695 !uzbl.behave.disable_plugins, NULL);
1699 cmd_disable_scripts() {
1700 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1701 !uzbl.behave.disable_scripts, NULL);
1705 cmd_minimum_font_size() {
1706 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1707 uzbl.behave.minimum_font_size, NULL);
1710 cmd_autoload_img() {
1711 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1712 uzbl.behave.autoload_img, NULL);
1717 cmd_autoshrink_img() {
1718 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1719 uzbl.behave.autoshrink_img, NULL);
1724 cmd_enable_spellcheck() {
1725 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1726 uzbl.behave.enable_spellcheck, NULL);
1730 cmd_enable_private() {
1731 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1732 uzbl.behave.enable_private, NULL);
1737 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1738 uzbl.behave.print_bg, NULL);
1743 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1744 uzbl.behave.style_uri, NULL);
1748 cmd_resizable_txt() {
1749 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1750 uzbl.behave.resizable_txt, NULL);
1754 cmd_default_encoding() {
1755 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1756 uzbl.behave.default_encoding, NULL);
1760 cmd_enforce_96dpi() {
1761 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1762 uzbl.behave.enforce_96dpi, NULL);
1766 cmd_caret_browsing() {
1767 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1768 uzbl.behave.caret_browsing, NULL);
1772 cmd_cookie_handler() {
1773 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1774 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1775 if ((g_strcmp0(split[0], "sh") == 0) ||
1776 (g_strcmp0(split[0], "spawn") == 0)) {
1777 g_free (uzbl.behave.cookie_handler);
1778 uzbl.behave.cookie_handler =
1779 g_strdup_printf("sync_%s %s", split[0], split[1]);
1786 gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
1787 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1788 if ((g_strcmp0(split[0], "sh") == 0) ||
1789 (g_strcmp0(split[0], "spawn") == 0)) {
1790 g_free (uzbl.behave.new_window);
1791 uzbl.behave.new_window =
1792 g_strdup_printf("%s %s", split[0], split[1]);
1799 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1804 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1809 if(uzbl.behave.inject_html) {
1810 webkit_web_view_load_html_string (uzbl.gui.web_view,
1811 uzbl.behave.inject_html, NULL);
1820 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1821 uzbl.behave.modmask = 0;
1823 if(uzbl.behave.modkey)
1824 g_free(uzbl.behave.modkey);
1825 uzbl.behave.modkey = buf;
1827 for (i = 0; modkeys[i].key != NULL; i++) {
1828 if (g_strrstr(buf, modkeys[i].key))
1829 uzbl.behave.modmask |= modkeys[i].mask;
1835 if (*uzbl.net.useragent == ' ') {
1836 g_free (uzbl.net.useragent);
1837 uzbl.net.useragent = NULL;
1839 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1840 uzbl.net.useragent, NULL);
1846 if (!uzbl.gui.scrolled_win &&
1850 gtk_widget_ref(uzbl.gui.scrolled_win);
1851 gtk_widget_ref(uzbl.gui.mainbar);
1852 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1853 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1855 if(uzbl.behave.status_top) {
1856 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1857 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1860 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1861 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1863 gtk_widget_unref(uzbl.gui.scrolled_win);
1864 gtk_widget_unref(uzbl.gui.mainbar);
1865 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1870 set_var_value(const gchar *name, gchar *val) {
1871 uzbl_cmdprop *c = NULL;
1874 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1876 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1877 if(!c->writeable) return FALSE;
1879 /* check for the variable type */
1880 if (c->type == TYPE_STR) {
1881 buf = expand(val, 0);
1884 } else if(c->type == TYPE_INT) {
1885 buf = expand(val, 0);
1886 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1888 } else if (c->type == TYPE_FLOAT) {
1889 buf = expand(val, 0);
1890 *c->ptr.f = strtod(buf, &endp);
1894 /* invoke a command specific function */
1895 if(c->func) c->func();
1897 /* check wether name violates our naming scheme */
1898 if(strpbrk(name, invalid_chars)) {
1899 if (uzbl.state.verbose)
1900 printf("Invalid variable name\n");
1905 c = malloc(sizeof(uzbl_cmdprop));
1910 buf = expand(val, 0);
1911 c->ptr.s = malloc(sizeof(char *));
1913 g_hash_table_insert(uzbl.comm.proto_var,
1914 g_strdup(name), (gpointer) c);
1921 Behaviour *b = &uzbl.behave;
1923 if(b->html_buffer->str) {
1924 webkit_web_view_load_html_string (uzbl.gui.web_view,
1925 b->html_buffer->str, b->base_url);
1926 g_string_free(b->html_buffer, TRUE);
1927 b->html_buffer = g_string_new("");
1931 enum {M_CMD, M_HTML};
1933 parse_cmd_line(const char *ctl_line, GString *result) {
1934 Behaviour *b = &uzbl.behave;
1937 if(b->mode == M_HTML) {
1938 len = strlen(b->html_endmarker);
1939 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1940 if(len == strlen(ctl_line)-1 &&
1941 !strncmp(b->html_endmarker, ctl_line, len)) {
1943 set_var_value("mode", "0");
1948 set_timeout(b->html_timeout);
1949 g_string_append(b->html_buffer, ctl_line);
1952 else if((ctl_line[0] == '#') /* Comments */
1953 || (ctl_line[0] == ' ')
1954 || (ctl_line[0] == '\n'))
1955 ; /* ignore these lines */
1956 else { /* parse a command */
1958 gchar **tokens = NULL;
1959 len = strlen(ctl_line);
1961 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1962 ctlstrip = g_strndup(ctl_line, len - 1);
1963 else ctlstrip = g_strdup(ctl_line);
1965 tokens = g_strsplit(ctlstrip, " ", 2);
1966 parse_command(tokens[0], tokens[1], result);
1973 build_stream_name(int type, const gchar* dir) {
1974 State *s = &uzbl.state;
1978 str = g_strdup_printf
1979 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1980 } else if (type == SOCKET) {
1981 str = g_strdup_printf
1982 ("%s/uzbl_socket_%s", dir, s->instance_name);
1988 control_fifo(GIOChannel *gio, GIOCondition condition) {
1989 if (uzbl.state.verbose)
1990 printf("triggered\n");
1995 if (condition & G_IO_HUP)
1996 g_error ("Fifo: Read end of pipe died!\n");
1999 g_error ("Fifo: GIOChannel broke\n");
2001 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2002 if (ret == G_IO_STATUS_ERROR) {
2003 g_error ("Fifo: Error reading: %s\n", err->message);
2007 parse_cmd_line(ctl_line, NULL);
2014 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2015 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2016 if (unlink(uzbl.comm.fifo_path) == -1)
2017 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2018 g_free(uzbl.comm.fifo_path);
2019 uzbl.comm.fifo_path = NULL;
2022 GIOChannel *chan = NULL;
2023 GError *error = NULL;
2024 gchar *path = build_stream_name(FIFO, dir);
2026 if (!file_exists(path)) {
2027 if (mkfifo (path, 0666) == 0) {
2028 // 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.
2029 chan = g_io_channel_new_file(path, "r+", &error);
2031 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2032 if (uzbl.state.verbose)
2033 printf ("init_fifo: created successfully as %s\n", path);
2034 uzbl.comm.fifo_path = path;
2036 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2037 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2038 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2039 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2041 /* if we got this far, there was an error; cleanup */
2042 if (error) g_error_free (error);
2049 control_stdin(GIOChannel *gio, GIOCondition condition) {
2051 gchar *ctl_line = NULL;
2054 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2055 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2058 parse_cmd_line(ctl_line, NULL);
2066 GIOChannel *chan = NULL;
2067 GError *error = NULL;
2069 chan = g_io_channel_unix_new(fileno(stdin));
2071 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2072 g_error ("Stdin: could not add watch\n");
2074 if (uzbl.state.verbose)
2075 printf ("Stdin: watch added successfully\n");
2078 g_error ("Stdin: Error while opening: %s\n", error->message);
2080 if (error) g_error_free (error);
2084 control_socket(GIOChannel *chan) {
2085 struct sockaddr_un remote;
2086 unsigned int t = sizeof(remote);
2088 GIOChannel *clientchan;
2090 clientsock = accept (g_io_channel_unix_get_fd(chan),
2091 (struct sockaddr *) &remote, &t);
2093 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2094 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2095 (GIOFunc) control_client_socket, clientchan);
2102 control_client_socket(GIOChannel *clientchan) {
2104 GString *result = g_string_new("");
2105 GError *error = NULL;
2109 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2110 if (ret == G_IO_STATUS_ERROR) {
2111 g_warning ("Error reading: %s\n", error->message);
2112 g_io_channel_shutdown(clientchan, TRUE, &error);
2114 } else if (ret == G_IO_STATUS_EOF) {
2115 /* shutdown and remove channel watch from main loop */
2116 g_io_channel_shutdown(clientchan, TRUE, &error);
2121 parse_cmd_line (ctl_line, result);
2122 g_string_append_c(result, '\n');
2123 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2125 if (ret == G_IO_STATUS_ERROR) {
2126 g_warning ("Error writing: %s", error->message);
2128 g_io_channel_flush(clientchan, &error);
2131 if (error) g_error_free (error);
2132 g_string_free(result, TRUE);
2138 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2139 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2140 if (unlink(uzbl.comm.socket_path) == -1)
2141 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2142 g_free(uzbl.comm.socket_path);
2143 uzbl.comm.socket_path = NULL;
2151 GIOChannel *chan = NULL;
2153 struct sockaddr_un local;
2154 gchar *path = build_stream_name(SOCKET, dir);
2156 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2158 local.sun_family = AF_UNIX;
2159 strcpy (local.sun_path, path);
2160 unlink (local.sun_path);
2162 len = strlen (local.sun_path) + sizeof (local.sun_family);
2163 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2164 if (uzbl.state.verbose)
2165 printf ("init_socket: opened in %s\n", path);
2168 if( (chan = g_io_channel_unix_new(sock)) ) {
2169 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2170 uzbl.comm.socket_path = path;
2173 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2175 /* if we got this far, there was an error; cleanup */
2182 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2183 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2185 // this function may be called very early when the templates are not set (yet), hence the checks
2187 update_title (void) {
2188 Behaviour *b = &uzbl.behave;
2191 if (b->show_status) {
2192 if (b->title_format_short) {
2193 parsed = expand(b->title_format_short, 0);
2194 if (uzbl.gui.main_window)
2195 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2198 if (b->status_format) {
2199 parsed = expand(b->status_format, 0);
2200 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2203 if (b->status_background) {
2205 gdk_color_parse (b->status_background, &color);
2206 //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)
2207 if (uzbl.gui.main_window)
2208 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2209 else if (uzbl.gui.plug)
2210 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2213 if (b->title_format_long) {
2214 parsed = expand(b->title_format_long, 0);
2215 if (uzbl.gui.main_window)
2216 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2223 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2227 retrieve_geometry();
2232 key_press_cb (GtkWidget* window, GdkEventKey* event)
2234 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2238 if (event->type != GDK_KEY_PRESS ||
2239 event->keyval == GDK_Page_Up ||
2240 event->keyval == GDK_Page_Down ||
2241 event->keyval == GDK_Up ||
2242 event->keyval == GDK_Down ||
2243 event->keyval == GDK_Left ||
2244 event->keyval == GDK_Right ||
2245 event->keyval == GDK_Shift_L ||
2246 event->keyval == GDK_Shift_R)
2249 /* turn off insert mode (if always_insert_mode is not used) */
2250 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2251 set_insert_mode(uzbl.behave.always_insert_mode);
2256 if (uzbl.behave.insert_mode &&
2257 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2258 (!uzbl.behave.modmask)
2263 if (event->keyval == GDK_Escape) {
2266 dehilight(uzbl.gui.web_view, NULL, NULL);
2270 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2271 if (event->keyval == GDK_Insert) {
2273 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2274 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2276 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2279 GString* keycmd = g_string_new(uzbl.state.keycmd);
2280 g_string_append (keycmd, str);
2281 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2288 if (event->keyval == GDK_BackSpace)
2289 keycmd_bs(NULL, NULL, NULL);
2291 gboolean key_ret = FALSE;
2292 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2295 GString* keycmd = g_string_new(uzbl.state.keycmd);
2296 g_string_append(keycmd, event->string);
2297 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2300 run_keycmd(key_ret);
2302 if (key_ret) return (!uzbl.behave.insert_mode);
2307 run_keycmd(const gboolean key_ret) {
2308 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2310 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2312 parse_command(act->name, act->param, NULL);
2316 /* try if it's an incremental keycmd or one that takes args, and run it */
2317 GString* short_keys = g_string_new ("");
2318 GString* short_keys_inc = g_string_new ("");
2320 guint len = strlen(uzbl.state.keycmd);
2321 for (i=0; i<len; i++) {
2322 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2323 g_string_assign(short_keys_inc, short_keys->str);
2324 g_string_append_c(short_keys, '_');
2325 g_string_append_c(short_keys_inc, '*');
2327 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2328 /* run normal cmds only if return was pressed */
2329 exec_paramcmd(act, i);
2332 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2333 if (key_ret) /* just quit the incremental command on return */
2335 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2339 g_string_truncate(short_keys, short_keys->len - 1);
2341 g_string_free (short_keys, TRUE);
2342 g_string_free (short_keys_inc, TRUE);
2346 exec_paramcmd(const Action *act, const guint i) {
2347 GString *parampart = g_string_new (uzbl.state.keycmd);
2348 GString *actionname = g_string_new ("");
2349 GString *actionparam = g_string_new ("");
2350 g_string_erase (parampart, 0, i+1);
2352 g_string_printf (actionname, act->name, parampart->str);
2354 g_string_printf (actionparam, act->param, parampart->str);
2355 parse_command(actionname->str, actionparam->str, NULL);
2356 g_string_free(actionname, TRUE);
2357 g_string_free(actionparam, TRUE);
2358 g_string_free(parampart, TRUE);
2366 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2368 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2369 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2370 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2371 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2372 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2373 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2374 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2378 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2385 g->mainbar = gtk_hbox_new (FALSE, 0);
2387 /* keep a reference to the bar so we can re-pack it at runtime*/
2388 //sbar_ref = g_object_ref(g->mainbar);
2390 g->mainbar_label = gtk_label_new ("");
2391 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2392 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2393 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2394 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2395 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2396 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2402 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2403 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2404 gtk_widget_set_name (window, "Uzbl browser");
2405 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2406 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2407 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2414 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2415 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2416 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2423 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2425 If actname is one that calls an external command, this function will inject
2426 newargs in front of the user-provided args in that command line. They will
2427 come become after the body of the script (in sh) or after the name of
2428 the command to execute (in spawn).
2429 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2430 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2432 The return value consist of two strings: the action (sh, ...) and its args.
2434 If act is not one that calls an external command, then the given action merely
2437 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2438 /* Arrr! Here be memory leaks */
2439 gchar *actdup = g_strdup(actname);
2440 g_array_append_val(rets, actdup);
2442 if ((g_strcmp0(actname, "spawn") == 0) ||
2443 (g_strcmp0(actname, "sh") == 0) ||
2444 (g_strcmp0(actname, "sync_spawn") == 0) ||
2445 (g_strcmp0(actname, "sync_sh") == 0) ||
2446 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2448 GString *a = g_string_new("");
2449 gchar **spawnparts = split_quoted(origargs, FALSE);
2450 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2451 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2453 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2454 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2456 g_array_append_val(rets, a->str);
2457 g_string_free(a, FALSE);
2458 g_strfreev(spawnparts);
2460 gchar *origdup = g_strdup(origargs);
2461 g_array_append_val(rets, origdup);
2463 return (gchar**)g_array_free(rets, FALSE);
2467 run_handler (const gchar *act, const gchar *args) {
2468 /* Consider this code a temporary hack to make the handlers usable.
2469 In practice, all this splicing, injection, and reconstruction is
2470 inefficient, annoying and hard to manage. Potential pitfalls arise
2471 when the handler specific args 1) are not quoted (the handler
2472 callbacks should take care of this) 2) are quoted but interfere
2473 with the users' own quotation. A more ideal solution is
2474 to refactor parse_command so that it doesn't just take a string
2475 and execute it; rather than that, we should have a function which
2476 returns the argument vector parsed from the string. This vector
2477 could be modified (e.g. insert additional args into it) before
2478 passing it to the next function that actually executes it. Though
2479 it still isn't perfect for chain actions.. will reconsider & re-
2480 factor when I have the time. -duc */
2482 char **parts = g_strsplit(act, " ", 2);
2484 if (g_strcmp0(parts[0], "chain") == 0) {
2485 GString *newargs = g_string_new("");
2486 gchar **chainparts = split_quoted(parts[1], FALSE);
2488 /* for every argument in the chain, inject the handler args
2489 and make sure the new parts are wrapped in quotes */
2490 gchar **cp = chainparts;
2492 gchar *quotless = NULL;
2493 gchar **spliced_quotless = NULL; // sigh -_-;
2494 gchar **inpart = NULL;
2497 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2499 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2500 } else quotless = g_strdup(*cp);
2502 spliced_quotless = g_strsplit(quotless, " ", 2);
2503 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2504 g_strfreev(spliced_quotless);
2506 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2512 parse_command(parts[0], &(newargs->str[1]), NULL);
2513 g_string_free(newargs, TRUE);
2514 g_strfreev(chainparts);
2517 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2518 parse_command(inparts[0], inparts[1], NULL);
2526 add_binding (const gchar *key, const gchar *act) {
2527 char **parts = g_strsplit(act, " ", 2);
2534 if (uzbl.state.verbose)
2535 printf ("Binding %-10s : %s\n", key, act);
2536 action = new_action(parts[0], parts[1]);
2538 if (g_hash_table_remove (uzbl.bindings, key))
2539 g_warning ("Overwriting existing binding for \"%s\"", key);
2540 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2545 get_xdg_var (XDG_Var xdg) {
2546 const gchar* actual_value = getenv (xdg.environmental);
2547 const gchar* home = getenv ("HOME");
2548 gchar* return_value;
2550 if (! actual_value || strcmp (actual_value, "") == 0) {
2551 if (xdg.default_value) {
2552 return_value = str_replace ("~", home, xdg.default_value);
2554 return_value = NULL;
2557 return_value = str_replace("~", home, actual_value);
2560 return return_value;
2564 find_xdg_file (int xdg_type, const char* filename) {
2565 /* xdg_type = 0 => config
2566 xdg_type = 1 => data
2567 xdg_type = 2 => cache*/
2569 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2570 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2573 gchar* temporary_string;
2577 if (! file_exists (temporary_file) && xdg_type != 2) {
2578 buf = get_xdg_var (XDG[3 + xdg_type]);
2579 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2582 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2583 g_free (temporary_file);
2584 temporary_file = g_strconcat (temporary_string, filename, NULL);
2588 //g_free (temporary_string); - segfaults.
2590 if (file_exists (temporary_file)) {
2591 return temporary_file;
2593 g_free(temporary_file);
2599 State *s = &uzbl.state;
2600 Network *n = &uzbl.net;
2602 for (i = 0; default_config[i].command != NULL; i++) {
2603 parse_cmd_line(default_config[i].command, NULL);
2606 if (g_strcmp0(s->config_file, "-") == 0) {
2607 s->config_file = NULL;
2611 else if (!s->config_file) {
2612 s->config_file = find_xdg_file (0, "/uzbl/config");
2615 if (s->config_file) {
2616 GArray* lines = read_file_by_line (s->config_file);
2620 while ((line = g_array_index(lines, gchar*, i))) {
2621 parse_cmd_line (line, NULL);
2625 g_array_free (lines, TRUE);
2627 if (uzbl.state.verbose)
2628 printf ("No configuration file loaded.\n");
2631 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2634 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2637 if (!uzbl.behave.cookie_handler)
2640 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2641 GString *s = g_string_new ("");
2642 SoupURI * soup_uri = soup_message_get_uri(msg);
2643 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2644 run_handler(uzbl.behave.cookie_handler, s->str);
2646 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2647 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2648 if ( p != NULL ) *p = '\0';
2649 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2651 if (uzbl.comm.sync_stdout)
2652 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2654 g_string_free(s, TRUE);
2658 save_cookies (SoupMessage *msg, gpointer user_data){
2662 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2663 cookie = soup_cookie_to_set_cookie_header(ck->data);
2664 SoupURI * soup_uri = soup_message_get_uri(msg);
2665 GString *s = g_string_new ("");
2666 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2667 run_handler(uzbl.behave.cookie_handler, s->str);
2669 g_string_free(s, TRUE);
2674 /* --- WEBINSPECTOR --- */
2676 hide_window_cb(GtkWidget *widget, gpointer data) {
2679 gtk_widget_hide(widget);
2683 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2686 (void) web_inspector;
2687 GtkWidget* scrolled_window;
2688 GtkWidget* new_web_view;
2691 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2692 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2693 G_CALLBACK(hide_window_cb), NULL);
2695 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2696 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2697 gtk_widget_show(g->inspector_window);
2699 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2700 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2701 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2702 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2703 gtk_widget_show(scrolled_window);
2705 new_web_view = webkit_web_view_new();
2706 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2708 return WEBKIT_WEB_VIEW(new_web_view);
2712 inspector_show_window_cb (WebKitWebInspector* inspector){
2714 gtk_widget_show(uzbl.gui.inspector_window);
2718 /* TODO: Add variables and code to make use of these functions */
2720 inspector_close_window_cb (WebKitWebInspector* inspector){
2726 inspector_attach_window_cb (WebKitWebInspector* inspector){
2732 inspector_detach_window_cb (WebKitWebInspector* inspector){
2738 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2744 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2750 set_up_inspector() {
2752 WebKitWebSettings *settings = view_settings();
2753 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2755 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2756 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2757 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2758 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2759 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2760 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2761 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2763 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2767 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2769 uzbl_cmdprop *c = v;
2774 if(c->type == TYPE_STR)
2775 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2776 else if(c->type == TYPE_INT)
2777 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2778 else if(c->type == TYPE_FLOAT)
2779 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2783 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2787 printf("bind %s = %s %s\n", (char *)k ,
2788 (char *)a->name, a->param?(char *)a->param:"");
2793 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2794 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2798 retrieve_geometry() {
2800 GString *buf = g_string_new("");
2802 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2803 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2805 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2807 if(uzbl.gui.geometry)
2808 g_free(uzbl.gui.geometry);
2809 uzbl.gui.geometry = g_string_free(buf, FALSE);
2812 /* set up gtk, gobject, variable defaults and other things that tests and other
2813 * external applications need to do anyhow */
2815 initialize(int argc, char *argv[]) {
2816 if (!g_thread_supported ())
2817 g_thread_init (NULL);
2818 uzbl.state.executable_path = g_strdup(argv[0]);
2819 uzbl.state.selected_url = NULL;
2820 uzbl.state.searchtx = NULL;
2822 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2823 g_option_context_add_main_entries (context, entries, NULL);
2824 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2825 g_option_context_parse (context, &argc, &argv, NULL);
2826 g_option_context_free(context);
2828 if (uzbl.behave.print_version) {
2829 printf("Commit: %s\n", COMMIT);
2833 /* initialize hash table */
2834 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2836 uzbl.net.soup_session = webkit_get_default_session();
2837 uzbl.state.keycmd = g_strdup("");
2839 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2840 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2841 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2842 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2843 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2844 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2846 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2847 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2848 uzbl.gui.sbar.progress_w = 10;
2850 /* HTML mode defaults*/
2851 uzbl.behave.html_buffer = g_string_new("");
2852 uzbl.behave.html_endmarker = g_strdup(".");
2853 uzbl.behave.html_timeout = 60;
2854 uzbl.behave.base_url = g_strdup("http://invalid");
2856 /* default mode indicators */
2857 uzbl.behave.insert_indicator = g_strdup("I");
2858 uzbl.behave.cmd_indicator = g_strdup("C");
2860 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2861 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2862 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2863 uzbl.info.arch = ARCH;
2864 uzbl.info.commit = COMMIT;
2867 make_var_to_name_hash();
2872 #ifndef UZBL_LIBRARY
2875 main (int argc, char* argv[]) {
2876 initialize(argc, argv);
2878 gtk_init (&argc, &argv);
2880 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2881 //main_window_ref = g_object_ref(scrolled_window);
2882 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2883 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2885 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2886 GTK_WIDGET (uzbl.gui.web_view));
2888 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2892 /* initial packing */
2893 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2894 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2896 if (uzbl.state.socket_id) {
2897 uzbl.gui.plug = create_plug ();
2898 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2899 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2901 uzbl.gui.main_window = create_window ();
2902 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2903 gtk_widget_show_all (uzbl.gui.main_window);
2904 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2907 if(!uzbl.state.instance_name)
2908 uzbl.state.instance_name = itos((int)uzbl.xwin);
2910 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2912 if (uzbl.state.verbose) {
2913 printf("Uzbl start location: %s\n", argv[0]);
2914 if (uzbl.state.socket_id)
2915 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2917 printf("window_id %i\n",(int) uzbl.xwin);
2918 printf("pid %i\n", getpid ());
2919 printf("name: %s\n", uzbl.state.instance_name);
2922 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2923 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2924 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2925 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2926 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2928 if(uzbl.gui.geometry)
2931 retrieve_geometry();
2933 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2934 if (argc > 1 && !uzbl.state.uri)
2935 uri_override = g_strdup(argv[1]);
2936 gboolean verbose_override = uzbl.state.verbose;
2939 set_insert_mode(FALSE);
2941 if (!uzbl.behave.show_status)
2942 gtk_widget_hide(uzbl.gui.mainbar);
2949 if (verbose_override > uzbl.state.verbose)
2950 uzbl.state.verbose = verbose_override;
2953 set_var_value("uri", uri_override);
2954 g_free(uri_override);
2955 } else if (uzbl.state.uri)
2961 return EXIT_SUCCESS;
2965 /* vi: set et ts=4: */