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 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,
231 (gpointer) n2v_p->name,
232 (gpointer) &n2v_p->cp);
237 /* --- UTILITY FUNCTIONS --- */
238 enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE};
240 get_exp_type(const gchar *s) {
244 else if(*(s+1) == '{')
245 return EXP_BRACED_VAR;
246 else if(*(s+1) == '<')
248 else if(*(s+1) == '[')
251 return EXP_SIMPLE_VAR;
258 * recurse == 1: don't expand '@(command)@'
259 * recurse == 2: don't expand '@<java script>@'
262 expand(const char *s, guint recurse) {
265 char *end_simple_var = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
269 gchar *cmd_stdout = NULL;
271 GString *buf = g_string_new("");
272 GString *js_ret = g_string_new("");
277 g_string_append_c(buf, *++s);
282 etype = get_exp_type(s);
287 vend = strpbrk(s, end_simple_var);
288 if(!vend) vend = strchr(s, '\0');
292 vend = strchr(s, '}');
293 if(!vend) vend = strchr(s, '\0');
297 vend = strstr(s, ")@");
298 if(!vend) vend = strchr(s, '\0');
302 vend = strstr(s, ">@");
303 if(!vend) vend = strchr(s, '\0');
307 vend = strstr(s, "]@");
308 if(!vend) vend = strchr(s, '\0');
316 ret = g_strndup(s, vend-s);
318 if(etype == EXP_SIMPLE_VAR ||
319 etype == EXP_BRACED_VAR) {
320 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
321 if(c->type == TYPE_STR && *c->ptr.s != NULL) {
322 g_string_append(buf, (gchar *)*c->ptr.s);
323 } else if(c->type == TYPE_INT) {
324 g_string_append_printf(buf, "%d", *c->ptr.i);
326 else if(c->type == TYPE_FLOAT) {
327 g_string_append_printf(buf, "%f", *c->ptr.f);
331 if(etype == EXP_SIMPLE_VAR)
336 else if(recurse != 1 &&
338 mycmd = expand(ret, 1);
339 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
343 g_printerr("error on running command: %s\n", err->message);
346 else if (*cmd_stdout) {
347 size_t len = strlen(cmd_stdout);
349 if(len > 0 && cmd_stdout[len-1] == '\n')
350 cmd_stdout[--len] = '\0'; /* strip trailing newline */
352 g_string_append(buf, cmd_stdout);
357 else if(recurse != 2 &&
359 mycmd = expand(ret, 2);
360 eval_js(uzbl.gui.web_view, mycmd, js_ret);
364 g_string_append(buf, js_ret->str);
365 g_string_free(js_ret, TRUE);
366 js_ret = g_string_new("");
370 else if(etype == EXP_ESCAPE) {
371 mycmd = expand(ret, 0);
372 char *escaped = g_markup_escape_text(mycmd, strlen(mycmd));
374 g_string_append(buf, escaped);
386 g_string_append_c(buf, *s);
391 g_string_free(js_ret, TRUE);
392 return g_string_free(buf, FALSE);
399 snprintf(tmp, sizeof(tmp), "%i", val);
400 return g_strdup(tmp);
404 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
407 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
410 str_replace (const char* search, const char* replace, const char* string) {
414 buf = g_strsplit (string, search, -1);
415 ret = g_strjoinv (replace, buf);
416 g_strfreev(buf); // somebody said this segfaults
422 read_file_by_line (const gchar *path) {
423 GIOChannel *chan = NULL;
424 gchar *readbuf = NULL;
426 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
429 chan = g_io_channel_new_file(path, "r", NULL);
432 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
433 const gchar* val = g_strdup (readbuf);
434 g_array_append_val (lines, val);
439 g_io_channel_unref (chan);
441 fprintf(stderr, "File '%s' not be read.\n", path);
448 parseenv (char* string) {
449 extern char** environ;
450 gchar* tmpstr = NULL;
454 while (environ[i] != NULL) {
455 gchar** env = g_strsplit (environ[i], "=", 2);
456 gchar* envname = g_strconcat ("$", env[0], NULL);
458 if (g_strrstr (string, envname) != NULL) {
459 tmpstr = g_strdup(string);
461 string = str_replace(envname, env[1], tmpstr);
466 g_strfreev (env); // somebody said this breaks uzbl
474 setup_signal(int signr, sigfunc *shandler) {
475 struct sigaction nh, oh;
477 nh.sa_handler = shandler;
478 sigemptyset(&nh.sa_mask);
481 if(sigaction(signr, &nh, &oh) < 0)
489 if (uzbl.behave.fifo_dir)
490 unlink (uzbl.comm.fifo_path);
491 if (uzbl.behave.socket_dir)
492 unlink (uzbl.comm.socket_path);
494 g_free(uzbl.state.executable_path);
495 g_free(uzbl.state.keycmd);
496 g_hash_table_destroy(uzbl.bindings);
497 g_hash_table_destroy(uzbl.behave.commands);
500 /* used for html_mode_timeout
501 * be sure to extend this function to use
502 * more timers if needed in other places
505 set_timeout(int seconds) {
507 memset(&t, 0, sizeof t);
509 t.it_value.tv_sec = seconds;
510 t.it_value.tv_usec = 0;
511 setitimer(ITIMER_REAL, &t, NULL);
514 /* --- SIGNAL HANDLER --- */
517 catch_sigterm(int s) {
523 catch_sigint(int s) {
533 set_var_value("mode", "0");
538 /* --- CALLBACKS --- */
541 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
544 (void) navigation_action;
545 (void) policy_decision;
547 const gchar* uri = webkit_network_request_get_uri (request);
548 if (uzbl.state.verbose)
549 printf("New window requested -> %s \n", uri);
550 webkit_web_policy_decision_use(policy_decision);
555 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
560 /* If we can display it, let's display it... */
561 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
562 webkit_web_policy_decision_use (policy_decision);
566 /* ...everything we can't displayed is downloaded */
567 webkit_web_policy_decision_download (policy_decision);
571 /*@null@*/ WebKitWebView*
572 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
576 if (uzbl.state.selected_url != NULL) {
577 if (uzbl.state.verbose)
578 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
579 new_window_load_uri(uzbl.state.selected_url);
581 if (uzbl.state.verbose)
582 printf("New web view -> %s\n","Nothing to open, exiting");
588 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
591 if (uzbl.behave.download_handler) {
592 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
593 if (uzbl.state.verbose)
594 printf("Download -> %s\n",uri);
595 /* if urls not escaped, we may have to escape and quote uri before this call */
596 run_handler(uzbl.behave.download_handler, uri);
601 /* scroll a bar in a given direction */
603 scroll (GtkAdjustment* bar, GArray *argv) {
607 gdouble page_size = gtk_adjustment_get_page_size(bar);
608 gdouble value = gtk_adjustment_get_value(bar);
609 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
612 value += page_size * amount * 0.01;
616 max_value = gtk_adjustment_get_upper(bar) - page_size;
618 if (value > max_value)
619 value = max_value; /* don't scroll past the end of the page */
621 gtk_adjustment_set_value (bar, value);
625 scroll_begin(WebKitWebView* page, GArray *argv, GString *result) {
626 (void) page; (void) argv; (void) result;
627 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
631 scroll_end(WebKitWebView* page, GArray *argv, GString *result) {
632 (void) page; (void) argv; (void) result;
633 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
634 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
638 scroll_vert(WebKitWebView* page, GArray *argv, GString *result) {
639 (void) page; (void) result;
640 scroll(uzbl.gui.bar_v, argv);
644 scroll_horz(WebKitWebView* page, GArray *argv, GString *result) {
645 (void) page; (void) result;
646 scroll(uzbl.gui.bar_h, argv);
651 if(!gtk_window_parse_geometry(GTK_WINDOW(uzbl.gui.main_window), uzbl.gui.geometry)) {
652 if(uzbl.state.verbose)
653 printf("Error in geometry string: %s\n", uzbl.gui.geometry);
655 /* update geometry var with the actual geometry
656 this is necessary as some WMs don't seem to honour
657 the above setting and we don't want to end up with
658 wrong geometry information
665 if (!uzbl.behave.show_status) {
666 gtk_widget_hide(uzbl.gui.mainbar);
668 gtk_widget_show(uzbl.gui.mainbar);
674 toggle_zoom_type (WebKitWebView* page, GArray *argv, GString *result) {
679 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
683 toggle_status_cb (WebKitWebView* page, GArray *argv, GString *result) {
688 if (uzbl.behave.show_status) {
689 gtk_widget_hide(uzbl.gui.mainbar);
691 gtk_widget_show(uzbl.gui.mainbar);
693 uzbl.behave.show_status = !uzbl.behave.show_status;
698 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
702 //Set selected_url state variable
703 g_free(uzbl.state.selected_url);
704 uzbl.state.selected_url = NULL;
706 uzbl.state.selected_url = g_strdup(link);
712 title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) {
715 const gchar *title = webkit_web_view_get_title(web_view);
716 if (uzbl.gui.main_title)
717 g_free (uzbl.gui.main_title);
718 uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)");
723 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
726 uzbl.gui.sbar.load_progress = progress;
728 g_free(uzbl.gui.sbar.progress_bar);
729 uzbl.gui.sbar.progress_bar = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
735 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
739 if (uzbl.behave.load_finish_handler)
740 run_handler(uzbl.behave.load_finish_handler, "");
743 void clear_keycmd() {
744 g_free(uzbl.state.keycmd);
745 uzbl.state.keycmd = g_strdup("");
749 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
753 uzbl.gui.sbar.load_progress = 0;
754 clear_keycmd(); // don't need old commands to remain on new page?
755 if (uzbl.behave.load_start_handler)
756 run_handler(uzbl.behave.load_start_handler, "");
760 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
763 g_free (uzbl.state.uri);
764 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
765 uzbl.state.uri = g_string_free (newuri, FALSE);
766 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
767 set_insert_mode(uzbl.behave.always_insert_mode);
770 if (uzbl.behave.load_commit_handler)
771 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
775 destroy_cb (GtkWidget* widget, gpointer data) {
783 if (uzbl.behave.history_handler) {
785 struct tm * timeinfo;
788 timeinfo = localtime ( &rawtime );
789 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
790 run_handler(uzbl.behave.history_handler, date);
795 /* VIEW funcs (little webkit wrappers) */
796 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv, GString *result){(void)argv; (void)result; webkit_web_view_##name(page);}
798 VIEWFUNC(reload_bypass_cache)
799 VIEWFUNC(stop_loading)
806 /* -- command to callback/function map for things we cannot attach to any signals */
807 struct {const char *key; CommandInfo value;} cmdlist[] =
808 { /* key function no_split */
809 { "back", {view_go_back, 0} },
810 { "forward", {view_go_forward, 0} },
811 { "scroll_vert", {scroll_vert, 0} },
812 { "scroll_horz", {scroll_horz, 0} },
813 { "scroll_begin", {scroll_begin, 0} },
814 { "scroll_end", {scroll_end, 0} },
815 { "reload", {view_reload, 0}, },
816 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
817 { "stop", {view_stop_loading, 0}, },
818 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
819 { "zoom_out", {view_zoom_out, 0}, },
820 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
821 { "uri", {load_uri, TRUE} },
822 { "js", {run_js, TRUE} },
823 { "script", {run_external_js, 0} },
824 { "toggle_status", {toggle_status_cb, 0} },
825 { "spawn", {spawn, 0} },
826 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
827 { "sh", {spawn_sh, 0} },
828 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
829 { "talk_to_socket", {talk_to_socket, 0} },
830 { "exit", {close_uzbl, 0} },
831 { "search", {search_forward_text, TRUE} },
832 { "search_reverse", {search_reverse_text, TRUE} },
833 { "dehilight", {dehilight, 0} },
834 { "toggle_insert_mode", {toggle_insert_mode, 0} },
835 { "set", {set_var, TRUE} },
836 //{ "get", {get_var, TRUE} },
837 { "bind", {act_bind, TRUE} },
838 { "dump_config", {act_dump_config, 0} },
839 { "keycmd", {keycmd, TRUE} },
840 { "keycmd_nl", {keycmd_nl, TRUE} },
841 { "keycmd_bs", {keycmd_bs, 0} },
842 { "chain", {chain, 0} },
843 { "print", {print, TRUE} },
844 { "update_gui", {update_gui, TRUE} }
851 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
853 for (i = 0; i < LENGTH(cmdlist); i++)
854 g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value);
857 /* -- CORE FUNCTIONS -- */
860 free_action(gpointer act) {
861 Action *action = (Action*)act;
862 g_free(action->name);
864 g_free(action->param);
869 new_action(const gchar *name, const gchar *param) {
870 Action *action = g_new(Action, 1);
872 action->name = g_strdup(name);
874 action->param = g_strdup(param);
876 action->param = NULL;
882 file_exists (const char * filename) {
883 return (access(filename, F_OK) == 0);
887 set_var(WebKitWebView *page, GArray *argv, GString *result) {
888 (void) page; (void) result;
889 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
890 if (split[0] != NULL) {
891 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
892 set_var_value(g_strstrip(split[0]), value);
899 update_gui(WebKitWebView *page, GArray *argv, GString *result) {
900 (void) page; (void) argv; (void) result;
906 print(WebKitWebView *page, GArray *argv, GString *result) {
907 (void) page; (void) result;
910 buf = expand(argv_idx(argv, 0), 0);
911 g_string_assign(result, buf);
916 act_bind(WebKitWebView *page, GArray *argv, GString *result) {
917 (void) page; (void) result;
918 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
919 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
920 add_binding(g_strstrip(split[0]), value);
938 set_mode_indicator() {
939 uzbl.gui.sbar.mode_indicator = (uzbl.behave.insert_mode ?
940 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
945 set_mode_indicator();
950 set_insert_mode(gboolean mode) {
951 uzbl.behave.insert_mode = mode;
952 set_mode_indicator();
956 toggle_insert_mode(WebKitWebView *page, GArray *argv, GString *result) {
957 (void) page; (void) result;
959 if (argv_idx(argv, 0)) {
960 if (strcmp (argv_idx(argv, 0), "0") == 0) {
961 set_insert_mode(FALSE);
963 set_insert_mode(TRUE);
966 set_insert_mode( !uzbl.behave.insert_mode );
973 load_uri (WebKitWebView *web_view, GArray *argv, GString *result) {
976 if (argv_idx(argv, 0)) {
977 GString* newuri = g_string_new (argv_idx(argv, 0));
978 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
979 run_js(web_view, argv, NULL);
982 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
983 g_string_prepend (newuri, "http://");
984 /* if we do handle cookies, ask our handler for them */
985 webkit_web_view_load_uri (web_view, newuri->str);
986 g_string_free (newuri, TRUE);
993 js_run_command (JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject,
994 size_t argumentCount, const JSValueRef arguments[],
995 JSValueRef* exception) {
1000 JSStringRef js_result_string;
1001 GString *result = g_string_new("");
1003 if (argumentCount >= 1) {
1004 JSStringRef arg = JSValueToStringCopy(ctx, arguments[0], NULL);
1005 size_t arg_size = JSStringGetMaximumUTF8CStringSize(arg);
1006 char ctl_line[arg_size];
1007 JSStringGetUTF8CString(arg, ctl_line, arg_size);
1009 parse_cmd_line(ctl_line, result);
1011 JSStringRelease(arg);
1013 js_result_string = JSStringCreateWithUTF8CString(result->str);
1015 g_string_free(result, TRUE);
1017 return JSValueMakeString(ctx, js_result_string);
1020 JSStaticFunction js_static_functions[] = {
1021 {"run", js_run_command, kJSPropertyAttributeNone},
1026 /* This function creates the class and its definition, only once */
1027 if (!uzbl.js.initialized) {
1028 /* it would be pretty cool to make this dynamic */
1029 uzbl.js.classdef = kJSClassDefinitionEmpty;
1030 uzbl.js.classdef.staticFunctions = js_static_functions;
1032 uzbl.js.classref = JSClassCreate(&uzbl.js.classdef);
1038 eval_js(WebKitWebView * web_view, gchar *script, GString *result) {
1039 WebKitWebFrame *frame;
1040 JSGlobalContextRef context;
1041 JSObjectRef globalobject;
1042 JSStringRef var_name;
1044 JSStringRef js_script;
1045 JSValueRef js_result;
1046 JSStringRef js_result_string;
1047 size_t js_result_size;
1051 frame = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(web_view));
1052 context = webkit_web_frame_get_global_context(frame);
1053 globalobject = JSContextGetGlobalObject(context);
1055 /* uzbl javascript namespace */
1056 var_name = JSStringCreateWithUTF8CString("Uzbl");
1057 JSObjectSetProperty(context, globalobject, var_name,
1058 JSObjectMake(context, uzbl.js.classref, NULL),
1059 kJSClassAttributeNone, NULL);
1061 /* evaluate the script and get return value*/
1062 js_script = JSStringCreateWithUTF8CString(script);
1063 js_result = JSEvaluateScript(context, js_script, globalobject, NULL, 0, NULL);
1064 if (js_result && !JSValueIsUndefined(context, js_result)) {
1065 js_result_string = JSValueToStringCopy(context, js_result, NULL);
1066 js_result_size = JSStringGetMaximumUTF8CStringSize(js_result_string);
1068 if (js_result_size) {
1069 char js_result_utf8[js_result_size];
1070 JSStringGetUTF8CString(js_result_string, js_result_utf8, js_result_size);
1071 g_string_assign(result, js_result_utf8);
1074 JSStringRelease(js_result_string);
1078 JSObjectDeleteProperty(context, globalobject, var_name, NULL);
1080 JSStringRelease(var_name);
1081 JSStringRelease(js_script);
1085 run_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1086 if (argv_idx(argv, 0))
1087 eval_js(web_view, argv_idx(argv, 0), result);
1091 run_external_js (WebKitWebView * web_view, GArray *argv, GString *result) {
1093 if (argv_idx(argv, 0)) {
1094 GArray* lines = read_file_by_line (argv_idx (argv, 0));
1099 while ((line = g_array_index(lines, gchar*, i))) {
1101 js = g_strdup (line);
1103 gchar* newjs = g_strconcat (js, line, NULL);
1110 if (uzbl.state.verbose)
1111 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
1113 if (argv_idx (argv, 1)) {
1114 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
1118 eval_js (web_view, js, result);
1120 g_array_free (lines, TRUE);
1125 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
1126 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
1127 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
1128 webkit_web_view_unmark_text_matches (page);
1129 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
1130 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
1134 if (uzbl.state.searchtx) {
1135 if (uzbl.state.verbose)
1136 printf ("Searching: %s\n", uzbl.state.searchtx);
1137 webkit_web_view_set_highlight_text_matches (page, TRUE);
1138 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
1143 search_forward_text (WebKitWebView *page, GArray *argv, GString *result) {
1145 search_text(page, argv, TRUE);
1149 search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) {
1151 search_text(page, argv, FALSE);
1155 dehilight (WebKitWebView *page, GArray *argv, GString *result) {
1156 (void) argv; (void) result;
1157 webkit_web_view_set_highlight_text_matches (page, FALSE);
1162 new_window_load_uri (const gchar * uri) {
1163 if (uzbl.behave.new_window) {
1164 GString *s = g_string_new ("");
1165 g_string_printf(s, "'%s'", uri);
1166 run_handler(uzbl.behave.new_window, s->str);
1169 GString* to_execute = g_string_new ("");
1170 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
1172 for (i = 0; entries[i].long_name != NULL; i++) {
1173 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
1174 gchar** str = (gchar**)entries[i].arg_data;
1176 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
1180 if (uzbl.state.verbose)
1181 printf("\n%s\n", to_execute->str);
1182 g_spawn_command_line_async (to_execute->str, NULL);
1183 g_string_free (to_execute, TRUE);
1187 chain (WebKitWebView *page, GArray *argv, GString *result) {
1188 (void) page; (void) result;
1190 gchar **parts = NULL;
1192 while ((a = argv_idx(argv, i++))) {
1193 parts = g_strsplit (a, " ", 2);
1195 parse_command(parts[0], parts[1], result);
1201 keycmd (WebKitWebView *page, GArray *argv, GString *result) {
1205 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1211 keycmd_nl (WebKitWebView *page, GArray *argv, GString *result) {
1215 uzbl.state.keycmd = g_strdup(argv_idx(argv, 0));
1221 keycmd_bs (WebKitWebView *page, GArray *argv, GString *result) {
1226 int len = strlen(uzbl.state.keycmd);
1227 prev = g_utf8_find_prev_char(uzbl.state.keycmd, uzbl.state.keycmd + len);
1229 uzbl.state.keycmd[prev - uzbl.state.keycmd] = '\0';
1234 close_uzbl (WebKitWebView *page, GArray *argv, GString *result) {
1241 /* --Statusbar functions-- */
1243 build_progressbar_ascii(int percent) {
1244 int width=uzbl.gui.sbar.progress_w;
1247 GString *bar = g_string_new("");
1249 l = (double)percent*((double)width/100.);
1250 l = (int)(l+.5)>=(int)l ? l+.5 : l;
1252 for(i=0; i<(int)l; i++)
1253 g_string_append(bar, uzbl.gui.sbar.progress_s);
1256 g_string_append(bar, uzbl.gui.sbar.progress_u);
1258 return g_string_free(bar, FALSE);
1260 /* --End Statusbar functions-- */
1263 sharg_append(GArray *a, const gchar *str) {
1264 const gchar *s = (str ? str : "");
1265 g_array_append_val(a, s);
1268 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1270 run_command (const gchar *command, const guint npre, const gchar **args,
1271 const gboolean sync, char **output_stdout) {
1272 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1275 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1276 gchar *pid = itos(getpid());
1277 gchar *xwin = itos(uzbl.xwin);
1279 sharg_append(a, command);
1280 for (i = 0; i < npre; i++) /* add n args before the default vars */
1281 sharg_append(a, args[i]);
1282 sharg_append(a, uzbl.state.config_file);
1283 sharg_append(a, pid);
1284 sharg_append(a, xwin);
1285 sharg_append(a, uzbl.comm.fifo_path);
1286 sharg_append(a, uzbl.comm.socket_path);
1287 sharg_append(a, uzbl.state.uri);
1288 sharg_append(a, uzbl.gui.main_title);
1290 for (i = npre; i < g_strv_length((gchar**)args); i++)
1291 sharg_append(a, args[i]);
1295 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1297 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1298 NULL, NULL, output_stdout, NULL, NULL, &err);
1299 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1300 NULL, NULL, NULL, &err);
1302 if (uzbl.state.verbose) {
1303 GString *s = g_string_new("spawned:");
1304 for (i = 0; i < (a->len); i++) {
1305 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1306 g_string_append_printf(s, " %s", qarg);
1309 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1310 printf("%s\n", s->str);
1311 g_string_free(s, TRUE);
1313 printf("Stdout: %s\n", *output_stdout);
1317 g_printerr("error on run_command: %s\n", err->message);
1322 g_array_free (a, TRUE);
1327 split_quoted(const gchar* src, const gboolean unquote) {
1328 /* split on unquoted space, return array of strings;
1329 remove a layer of quotes and backslashes if unquote */
1330 if (!src) return NULL;
1332 gboolean dq = FALSE;
1333 gboolean sq = FALSE;
1334 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1335 GString *s = g_string_new ("");
1339 for (p = src; *p != '\0'; p++) {
1340 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1341 else if (*p == '\\') { g_string_append_c(s, *p++);
1342 g_string_append_c(s, *p); }
1343 else if ((*p == '"') && unquote && !sq) dq = !dq;
1344 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1346 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1347 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1349 else if ((*p == ' ') && !dq && !sq) {
1350 dup = g_strdup(s->str);
1351 g_array_append_val(a, dup);
1352 g_string_truncate(s, 0);
1353 } else g_string_append_c(s, *p);
1355 dup = g_strdup(s->str);
1356 g_array_append_val(a, dup);
1357 ret = (gchar**)a->data;
1358 g_array_free (a, FALSE);
1359 g_string_free (s, TRUE);
1364 spawn(WebKitWebView *web_view, GArray *argv, GString *result) {
1365 (void)web_view; (void)result;
1366 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1367 if (argv_idx(argv, 0))
1368 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1372 spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1373 (void)web_view; (void)result;
1375 if (argv_idx(argv, 0))
1376 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1377 TRUE, &uzbl.comm.sync_stdout);
1381 spawn_sh(WebKitWebView *web_view, GArray *argv, GString *result) {
1382 (void)web_view; (void)result;
1383 if (!uzbl.behave.shell_cmd) {
1384 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1389 gchar *spacer = g_strdup("");
1390 g_array_insert_val(argv, 1, spacer);
1391 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1393 for (i = 1; i < g_strv_length(cmd); i++)
1394 g_array_prepend_val(argv, cmd[i]);
1396 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1402 spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) {
1403 (void)web_view; (void)result;
1404 if (!uzbl.behave.shell_cmd) {
1405 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1410 gchar *spacer = g_strdup("");
1411 g_array_insert_val(argv, 1, spacer);
1412 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1414 for (i = 1; i < g_strv_length(cmd); i++)
1415 g_array_prepend_val(argv, cmd[i]);
1417 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1418 TRUE, &uzbl.comm.sync_stdout);
1424 talk_to_socket(WebKitWebView *web_view, GArray *argv, GString *result) {
1425 (void)web_view; (void)result;
1428 struct sockaddr_un sa;
1435 if(uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
1437 /* This function could be optimised by storing a hash table of socket paths
1438 and associated connected file descriptors rather than closing and
1439 re-opening for every call. Also we could launch a script if socket connect
1442 /* First element argv[0] is path to socket. Following elements are tokens to
1443 write to the socket. We write them as a single packet with each token
1444 separated by an ASCII nul (\0). */
1446 g_printerr("talk_to_socket called with only %d args (need at least two).\n",
1451 /* copy socket path, null terminate result */
1452 sockpath = g_array_index(argv, char*, 0);
1453 g_strlcpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
1454 sa.sun_family = AF_UNIX;
1456 /* create socket file descriptor and connect it to path */
1457 fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1459 g_printerr("talk_to_socket: creating socket failed (%s)\n", strerror(errno));
1462 if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) {
1463 g_printerr("talk_to_socket: connect failed (%s)\n", strerror(errno));
1468 /* build request vector */
1469 iov = g_malloc(sizeof(struct iovec) * (argv->len - 1));
1471 g_printerr("talk_to_socket: unable to allocated memory for token vector\n");
1475 for(i = 1; i < argv->len; ++i) {
1476 iov[i - 1].iov_base = g_array_index(argv, char*, i);
1477 iov[i - 1].iov_len = strlen(iov[i - 1].iov_base) + 1; /* string plus \0 */
1481 ret = writev(fd, iov, argv->len - 1);
1484 g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno));
1489 /* wait for a response, with a 500ms timeout */
1491 pfd.events = POLLIN;
1493 ret = poll(&pfd, 1, 500);
1495 if(ret == 0) errno = ETIMEDOUT;
1496 if(errno == EINTR) continue;
1497 g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n",
1503 /* get length of response */
1504 if(ioctl(fd, FIONREAD, &len) == -1) {
1505 g_printerr("talk_to_socket: cannot find daemon response length, "
1506 "ioctl failed (%s)\n", strerror(errno));
1511 /* if there is a response, read it */
1513 uzbl.comm.sync_stdout = g_malloc(len + 1);
1514 if(!uzbl.comm.sync_stdout) {
1515 g_printerr("talk_to_socket: failed to allocate %d bytes\n", len);
1519 uzbl.comm.sync_stdout[len] = 0; /* ensure result is null terminated */
1521 ret = read(fd, uzbl.comm.sync_stdout, len);
1523 g_printerr("talk_to_socket: failed to read from socket (%s)\n",
1536 parse_command(const char *cmd, const char *param, GString *result) {
1539 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1541 gchar **par = split_quoted(param, TRUE);
1542 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1544 if (c->no_split) { /* don't split */
1545 sharg_append(a, param);
1547 for (i = 0; i < g_strv_length(par); i++)
1548 sharg_append(a, par[i]);
1551 if (result == NULL) {
1552 GString *result_print = g_string_new("");
1554 c->function(uzbl.gui.web_view, a, result_print);
1555 if (result_print->len)
1556 printf("%*s\n", (int)result_print->len, result_print->str);
1558 g_string_free(result_print, TRUE);
1560 c->function(uzbl.gui.web_view, a, result);
1563 g_array_free (a, TRUE);
1566 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1573 if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') {
1574 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1575 (GType) SOUP_SESSION_PROXY_URI);
1578 suri = soup_uri_new(uzbl.net.proxy_url);
1579 g_object_set(G_OBJECT(uzbl.net.soup_session),
1580 SOUP_SESSION_PROXY_URI,
1582 soup_uri_free(suri);
1589 if(file_exists(uzbl.gui.icon)) {
1590 if (uzbl.gui.main_window)
1591 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1593 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1599 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1600 g_array_append_val (a, uzbl.state.uri);
1601 load_uri(uzbl.gui.web_view, a, NULL);
1602 g_array_free (a, TRUE);
1606 cmd_always_insert_mode() {
1607 set_insert_mode(uzbl.behave.always_insert_mode);
1613 g_object_set(G_OBJECT(uzbl.net.soup_session),
1614 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1618 cmd_max_conns_host() {
1619 g_object_set(G_OBJECT(uzbl.net.soup_session),
1620 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1625 soup_session_remove_feature
1626 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1627 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1628 /*g_free(uzbl.net.soup_logger);*/
1630 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1631 soup_session_add_feature(uzbl.net.soup_session,
1632 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1637 return webkit_web_view_get_settings(uzbl.gui.web_view);
1642 WebKitWebSettings *ws = view_settings();
1643 if (uzbl.behave.font_size > 0) {
1644 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1647 if (uzbl.behave.monospace_size > 0) {
1648 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1649 uzbl.behave.monospace_size, NULL);
1651 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1652 uzbl.behave.font_size, NULL);
1657 cmd_default_font_family() {
1658 g_object_set (G_OBJECT(view_settings()), "default-font-family",
1659 uzbl.behave.default_font_family, NULL);
1663 cmd_monospace_font_family() {
1664 g_object_set (G_OBJECT(view_settings()), "monospace-font-family",
1665 uzbl.behave.monospace_font_family, NULL);
1669 cmd_sans_serif_font_family() {
1670 g_object_set (G_OBJECT(view_settings()), "sans_serif-font-family",
1671 uzbl.behave.sans_serif_font_family, NULL);
1675 cmd_serif_font_family() {
1676 g_object_set (G_OBJECT(view_settings()), "serif-font-family",
1677 uzbl.behave.serif_font_family, NULL);
1681 cmd_cursive_font_family() {
1682 g_object_set (G_OBJECT(view_settings()), "cursive-font-family",
1683 uzbl.behave.cursive_font_family, NULL);
1687 cmd_fantasy_font_family() {
1688 g_object_set (G_OBJECT(view_settings()), "fantasy-font-family",
1689 uzbl.behave.fantasy_font_family, NULL);
1694 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1698 cmd_disable_plugins() {
1699 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1700 !uzbl.behave.disable_plugins, NULL);
1704 cmd_disable_scripts() {
1705 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1706 !uzbl.behave.disable_scripts, NULL);
1710 cmd_minimum_font_size() {
1711 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1712 uzbl.behave.minimum_font_size, NULL);
1715 cmd_autoload_img() {
1716 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1717 uzbl.behave.autoload_img, NULL);
1722 cmd_autoshrink_img() {
1723 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1724 uzbl.behave.autoshrink_img, NULL);
1729 cmd_enable_spellcheck() {
1730 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1731 uzbl.behave.enable_spellcheck, NULL);
1735 cmd_enable_private() {
1736 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1737 uzbl.behave.enable_private, NULL);
1742 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1743 uzbl.behave.print_bg, NULL);
1748 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1749 uzbl.behave.style_uri, NULL);
1753 cmd_resizable_txt() {
1754 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1755 uzbl.behave.resizable_txt, NULL);
1759 cmd_default_encoding() {
1760 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1761 uzbl.behave.default_encoding, NULL);
1765 cmd_enforce_96dpi() {
1766 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1767 uzbl.behave.enforce_96dpi, NULL);
1771 cmd_caret_browsing() {
1772 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1773 uzbl.behave.caret_browsing, NULL);
1777 cmd_cookie_handler() {
1778 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1779 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1780 if ((g_strcmp0(split[0], "sh") == 0) ||
1781 (g_strcmp0(split[0], "spawn") == 0)) {
1782 g_free (uzbl.behave.cookie_handler);
1783 uzbl.behave.cookie_handler =
1784 g_strdup_printf("sync_%s %s", split[0], split[1]);
1791 gchar **split = g_strsplit(uzbl.behave.new_window, " ", 2);
1792 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1793 if ((g_strcmp0(split[0], "sh") == 0) ||
1794 (g_strcmp0(split[0], "spawn") == 0)) {
1795 g_free (uzbl.behave.new_window);
1796 uzbl.behave.new_window =
1797 g_strdup_printf("%s %s", split[0], split[1]);
1804 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1809 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1814 if(uzbl.behave.inject_html) {
1815 webkit_web_view_load_html_string (uzbl.gui.web_view,
1816 uzbl.behave.inject_html, NULL);
1825 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1826 uzbl.behave.modmask = 0;
1828 if(uzbl.behave.modkey)
1829 g_free(uzbl.behave.modkey);
1830 uzbl.behave.modkey = buf;
1832 for (i = 0; modkeys[i].key != NULL; i++) {
1833 if (g_strrstr(buf, modkeys[i].key))
1834 uzbl.behave.modmask |= modkeys[i].mask;
1840 if (*uzbl.net.useragent == ' ') {
1841 g_free (uzbl.net.useragent);
1842 uzbl.net.useragent = NULL;
1844 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT,
1845 uzbl.net.useragent, NULL);
1851 if (!uzbl.gui.scrolled_win &&
1855 gtk_widget_ref(uzbl.gui.scrolled_win);
1856 gtk_widget_ref(uzbl.gui.mainbar);
1857 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1858 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1860 if(uzbl.behave.status_top) {
1861 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1862 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1865 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1866 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1868 gtk_widget_unref(uzbl.gui.scrolled_win);
1869 gtk_widget_unref(uzbl.gui.mainbar);
1870 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1875 set_var_value(const gchar *name, gchar *val) {
1876 uzbl_cmdprop *c = NULL;
1879 char *invalid_chars = "^ยฐ!\"ยง$%&/()=?'`'+~*'#-.:,;@<>| \\{}[]ยนยฒยณยผยฝ";
1881 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1882 if(!c->writeable) return FALSE;
1884 /* check for the variable type */
1885 if (c->type == TYPE_STR) {
1886 buf = expand(val, 0);
1889 } else if(c->type == TYPE_INT) {
1890 buf = expand(val, 0);
1891 *c->ptr.i = (int)strtoul(buf, &endp, 10);
1893 } else if (c->type == TYPE_FLOAT) {
1894 buf = expand(val, 0);
1895 *c->ptr.f = strtod(buf, &endp);
1899 /* invoke a command specific function */
1900 if(c->func) c->func();
1902 /* check wether name violates our naming scheme */
1903 if(strpbrk(name, invalid_chars)) {
1904 if (uzbl.state.verbose)
1905 printf("Invalid variable name\n");
1910 c = malloc(sizeof(uzbl_cmdprop));
1915 buf = expand(val, 0);
1916 c->ptr.s = malloc(sizeof(char *));
1918 g_hash_table_insert(uzbl.comm.proto_var,
1919 g_strdup(name), (gpointer) c);
1926 Behaviour *b = &uzbl.behave;
1928 if(b->html_buffer->str) {
1929 webkit_web_view_load_html_string (uzbl.gui.web_view,
1930 b->html_buffer->str, b->base_url);
1931 g_string_free(b->html_buffer, TRUE);
1932 b->html_buffer = g_string_new("");
1936 enum {M_CMD, M_HTML};
1938 parse_cmd_line(const char *ctl_line, GString *result) {
1939 Behaviour *b = &uzbl.behave;
1942 if(b->mode == M_HTML) {
1943 len = strlen(b->html_endmarker);
1944 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1945 if(len == strlen(ctl_line)-1 &&
1946 !strncmp(b->html_endmarker, ctl_line, len)) {
1948 set_var_value("mode", "0");
1953 set_timeout(b->html_timeout);
1954 g_string_append(b->html_buffer, ctl_line);
1957 else if((ctl_line[0] == '#') /* Comments */
1958 || (ctl_line[0] == ' ')
1959 || (ctl_line[0] == '\n'))
1960 ; /* ignore these lines */
1961 else { /* parse a command */
1963 gchar **tokens = NULL;
1964 len = strlen(ctl_line);
1966 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1967 ctlstrip = g_strndup(ctl_line, len - 1);
1968 else ctlstrip = g_strdup(ctl_line);
1970 tokens = g_strsplit(ctlstrip, " ", 2);
1971 parse_command(tokens[0], tokens[1], result);
1978 build_stream_name(int type, const gchar* dir) {
1979 State *s = &uzbl.state;
1983 str = g_strdup_printf
1984 ("%s/uzbl_fifo_%s", dir, s->instance_name);
1985 } else if (type == SOCKET) {
1986 str = g_strdup_printf
1987 ("%s/uzbl_socket_%s", dir, s->instance_name);
1993 control_fifo(GIOChannel *gio, GIOCondition condition) {
1994 if (uzbl.state.verbose)
1995 printf("triggered\n");
2000 if (condition & G_IO_HUP)
2001 g_error ("Fifo: Read end of pipe died!\n");
2004 g_error ("Fifo: GIOChannel broke\n");
2006 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
2007 if (ret == G_IO_STATUS_ERROR) {
2008 g_error ("Fifo: Error reading: %s\n", err->message);
2012 parse_cmd_line(ctl_line, NULL);
2019 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2020 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
2021 if (unlink(uzbl.comm.fifo_path) == -1)
2022 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
2023 g_free(uzbl.comm.fifo_path);
2024 uzbl.comm.fifo_path = NULL;
2027 GIOChannel *chan = NULL;
2028 GError *error = NULL;
2029 gchar *path = build_stream_name(FIFO, dir);
2031 if (!file_exists(path)) {
2032 if (mkfifo (path, 0666) == 0) {
2033 // 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.
2034 chan = g_io_channel_new_file(path, "r+", &error);
2036 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
2037 if (uzbl.state.verbose)
2038 printf ("init_fifo: created successfully as %s\n", path);
2039 uzbl.comm.fifo_path = path;
2041 } else g_warning ("init_fifo: could not add watch on %s\n", path);
2042 } else g_warning ("init_fifo: can't open: %s\n", error->message);
2043 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
2044 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
2046 /* if we got this far, there was an error; cleanup */
2047 if (error) g_error_free (error);
2054 control_stdin(GIOChannel *gio, GIOCondition condition) {
2056 gchar *ctl_line = NULL;
2059 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
2060 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
2063 parse_cmd_line(ctl_line, NULL);
2071 GIOChannel *chan = NULL;
2072 GError *error = NULL;
2074 chan = g_io_channel_unix_new(fileno(stdin));
2076 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
2077 g_error ("Stdin: could not add watch\n");
2079 if (uzbl.state.verbose)
2080 printf ("Stdin: watch added successfully\n");
2083 g_error ("Stdin: Error while opening: %s\n", error->message);
2085 if (error) g_error_free (error);
2089 control_socket(GIOChannel *chan) {
2090 struct sockaddr_un remote;
2091 unsigned int t = sizeof(remote);
2093 GIOChannel *clientchan;
2095 clientsock = accept (g_io_channel_unix_get_fd(chan),
2096 (struct sockaddr *) &remote, &t);
2098 if ((clientchan = g_io_channel_unix_new(clientsock))) {
2099 g_io_add_watch(clientchan, G_IO_IN|G_IO_HUP,
2100 (GIOFunc) control_client_socket, clientchan);
2107 control_client_socket(GIOChannel *clientchan) {
2109 GString *result = g_string_new("");
2110 GError *error = NULL;
2114 ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error);
2115 if (ret == G_IO_STATUS_ERROR) {
2116 g_warning ("Error reading: %s\n", error->message);
2117 g_io_channel_shutdown(clientchan, TRUE, &error);
2119 } else if (ret == G_IO_STATUS_EOF) {
2120 /* shutdown and remove channel watch from main loop */
2121 g_io_channel_shutdown(clientchan, TRUE, &error);
2126 parse_cmd_line (ctl_line, result);
2127 g_string_append_c(result, '\n');
2128 ret = g_io_channel_write_chars (clientchan, result->str, result->len,
2130 if (ret == G_IO_STATUS_ERROR) {
2131 g_warning ("Error writing: %s", error->message);
2133 g_io_channel_flush(clientchan, &error);
2136 if (error) g_error_free (error);
2137 g_string_free(result, TRUE);
2143 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
2144 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
2145 if (unlink(uzbl.comm.socket_path) == -1)
2146 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
2147 g_free(uzbl.comm.socket_path);
2148 uzbl.comm.socket_path = NULL;
2156 GIOChannel *chan = NULL;
2158 struct sockaddr_un local;
2159 gchar *path = build_stream_name(SOCKET, dir);
2161 sock = socket (AF_UNIX, SOCK_STREAM, 0);
2163 local.sun_family = AF_UNIX;
2164 strcpy (local.sun_path, path);
2165 unlink (local.sun_path);
2167 len = strlen (local.sun_path) + sizeof (local.sun_family);
2168 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
2169 if (uzbl.state.verbose)
2170 printf ("init_socket: opened in %s\n", path);
2173 if( (chan = g_io_channel_unix_new(sock)) ) {
2174 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
2175 uzbl.comm.socket_path = path;
2178 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
2180 /* if we got this far, there was an error; cleanup */
2187 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
2188 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
2190 // this function may be called very early when the templates are not set (yet), hence the checks
2192 update_title (void) {
2193 Behaviour *b = &uzbl.behave;
2196 if (b->show_status) {
2197 if (b->title_format_short) {
2198 parsed = expand(b->title_format_short, 0);
2199 if (uzbl.gui.main_window)
2200 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2203 if (b->status_format) {
2204 parsed = expand(b->status_format, 0);
2205 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
2208 if (b->status_background) {
2210 gdk_color_parse (b->status_background, &color);
2211 //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)
2212 if (uzbl.gui.main_window)
2213 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
2214 else if (uzbl.gui.plug)
2215 gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color);
2218 if (b->title_format_long) {
2219 parsed = expand(b->title_format_long, 0);
2220 if (uzbl.gui.main_window)
2221 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
2228 configure_event_cb(GtkWidget* window, GdkEventConfigure* event) {
2232 retrieve_geometry();
2237 key_press_cb (GtkWidget* window, GdkEventKey* event)
2239 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
2243 if (event->type != GDK_KEY_PRESS ||
2244 event->keyval == GDK_Page_Up ||
2245 event->keyval == GDK_Page_Down ||
2246 event->keyval == GDK_Up ||
2247 event->keyval == GDK_Down ||
2248 event->keyval == GDK_Left ||
2249 event->keyval == GDK_Right ||
2250 event->keyval == GDK_Shift_L ||
2251 event->keyval == GDK_Shift_R)
2254 /* turn off insert mode (if always_insert_mode is not used) */
2255 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
2256 set_insert_mode(uzbl.behave.always_insert_mode);
2261 if (uzbl.behave.insert_mode &&
2262 ( ((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) ||
2263 (!uzbl.behave.modmask)
2268 if (event->keyval == GDK_Escape) {
2271 dehilight(uzbl.gui.web_view, NULL, NULL);
2275 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
2276 if (event->keyval == GDK_Insert) {
2278 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
2279 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2281 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2284 GString* keycmd = g_string_new(uzbl.state.keycmd);
2285 g_string_append (keycmd, str);
2286 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2293 if (event->keyval == GDK_BackSpace)
2294 keycmd_bs(NULL, NULL, NULL);
2296 gboolean key_ret = FALSE;
2297 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2300 GString* keycmd = g_string_new(uzbl.state.keycmd);
2301 g_string_append(keycmd, event->string);
2302 uzbl.state.keycmd = g_string_free(keycmd, FALSE);
2305 run_keycmd(key_ret);
2307 if (key_ret) return (!uzbl.behave.insert_mode);
2312 run_keycmd(const gboolean key_ret) {
2313 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2315 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd))) {
2317 parse_command(act->name, act->param, NULL);
2321 /* try if it's an incremental keycmd or one that takes args, and run it */
2322 GString* short_keys = g_string_new ("");
2323 GString* short_keys_inc = g_string_new ("");
2325 guint len = strlen(uzbl.state.keycmd);
2326 for (i=0; i<len; i++) {
2327 g_string_append_c(short_keys, uzbl.state.keycmd[i]);
2328 g_string_assign(short_keys_inc, short_keys->str);
2329 g_string_append_c(short_keys, '_');
2330 g_string_append_c(short_keys_inc, '*');
2332 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2333 /* run normal cmds only if return was pressed */
2334 exec_paramcmd(act, i);
2337 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2338 if (key_ret) /* just quit the incremental command on return */
2340 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2344 g_string_truncate(short_keys, short_keys->len - 1);
2346 g_string_free (short_keys, TRUE);
2347 g_string_free (short_keys_inc, TRUE);
2351 exec_paramcmd(const Action *act, const guint i) {
2352 GString *parampart = g_string_new (uzbl.state.keycmd);
2353 GString *actionname = g_string_new ("");
2354 GString *actionparam = g_string_new ("");
2355 g_string_erase (parampart, 0, i+1);
2357 g_string_printf (actionname, act->name, parampart->str);
2359 g_string_printf (actionparam, act->param, parampart->str);
2360 parse_command(actionname->str, actionparam->str, NULL);
2361 g_string_free(actionname, TRUE);
2362 g_string_free(actionparam, TRUE);
2363 g_string_free(parampart, TRUE);
2371 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2373 g_signal_connect (G_OBJECT (g->web_view), "notify::title", G_CALLBACK (title_change_cb), NULL);
2374 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2375 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2376 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2377 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2378 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2379 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2380 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2381 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2382 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2383 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2390 g->mainbar = gtk_hbox_new (FALSE, 0);
2392 /* keep a reference to the bar so we can re-pack it at runtime*/
2393 //sbar_ref = g_object_ref(g->mainbar);
2395 g->mainbar_label = gtk_label_new ("");
2396 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2397 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2398 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2399 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2400 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2401 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2407 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2408 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2409 gtk_widget_set_name (window, "Uzbl browser");
2410 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2411 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2412 g_signal_connect (G_OBJECT (window), "configure-event", G_CALLBACK (configure_event_cb), NULL);
2419 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2420 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2421 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2428 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2430 If actname is one that calls an external command, this function will inject
2431 newargs in front of the user-provided args in that command line. They will
2432 come become after the body of the script (in sh) or after the name of
2433 the command to execute (in spawn).
2434 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2435 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2437 The return value consist of two strings: the action (sh, ...) and its args.
2439 If act is not one that calls an external command, then the given action merely
2442 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2443 /* Arrr! Here be memory leaks */
2444 gchar *actdup = g_strdup(actname);
2445 g_array_append_val(rets, actdup);
2447 if ((g_strcmp0(actname, "spawn") == 0) ||
2448 (g_strcmp0(actname, "sh") == 0) ||
2449 (g_strcmp0(actname, "sync_spawn") == 0) ||
2450 (g_strcmp0(actname, "sync_sh") == 0) ||
2451 (g_strcmp0(actname, "talk_to_socket") == 0)) {
2453 GString *a = g_string_new("");
2454 gchar **spawnparts = split_quoted(origargs, FALSE);
2455 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2456 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2458 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2459 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2461 g_array_append_val(rets, a->str);
2462 g_string_free(a, FALSE);
2463 g_strfreev(spawnparts);
2465 gchar *origdup = g_strdup(origargs);
2466 g_array_append_val(rets, origdup);
2468 return (gchar**)g_array_free(rets, FALSE);
2472 run_handler (const gchar *act, const gchar *args) {
2473 /* Consider this code a temporary hack to make the handlers usable.
2474 In practice, all this splicing, injection, and reconstruction is
2475 inefficient, annoying and hard to manage. Potential pitfalls arise
2476 when the handler specific args 1) are not quoted (the handler
2477 callbacks should take care of this) 2) are quoted but interfere
2478 with the users' own quotation. A more ideal solution is
2479 to refactor parse_command so that it doesn't just take a string
2480 and execute it; rather than that, we should have a function which
2481 returns the argument vector parsed from the string. This vector
2482 could be modified (e.g. insert additional args into it) before
2483 passing it to the next function that actually executes it. Though
2484 it still isn't perfect for chain actions.. will reconsider & re-
2485 factor when I have the time. -duc */
2487 char **parts = g_strsplit(act, " ", 2);
2489 if (g_strcmp0(parts[0], "chain") == 0) {
2490 GString *newargs = g_string_new("");
2491 gchar **chainparts = split_quoted(parts[1], FALSE);
2493 /* for every argument in the chain, inject the handler args
2494 and make sure the new parts are wrapped in quotes */
2495 gchar **cp = chainparts;
2497 gchar *quotless = NULL;
2498 gchar **spliced_quotless = NULL; // sigh -_-;
2499 gchar **inpart = NULL;
2502 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2504 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2505 } else quotless = g_strdup(*cp);
2507 spliced_quotless = g_strsplit(quotless, " ", 2);
2508 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2509 g_strfreev(spliced_quotless);
2511 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2517 parse_command(parts[0], &(newargs->str[1]), NULL);
2518 g_string_free(newargs, TRUE);
2519 g_strfreev(chainparts);
2522 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2523 parse_command(inparts[0], inparts[1], NULL);
2531 add_binding (const gchar *key, const gchar *act) {
2532 char **parts = g_strsplit(act, " ", 2);
2539 if (uzbl.state.verbose)
2540 printf ("Binding %-10s : %s\n", key, act);
2541 action = new_action(parts[0], parts[1]);
2543 if (g_hash_table_remove (uzbl.bindings, key))
2544 g_warning ("Overwriting existing binding for \"%s\"", key);
2545 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2550 get_xdg_var (XDG_Var xdg) {
2551 const gchar* actual_value = getenv (xdg.environmental);
2552 const gchar* home = getenv ("HOME");
2553 gchar* return_value;
2555 if (! actual_value || strcmp (actual_value, "") == 0) {
2556 if (xdg.default_value) {
2557 return_value = str_replace ("~", home, xdg.default_value);
2559 return_value = NULL;
2562 return_value = str_replace("~", home, actual_value);
2565 return return_value;
2569 find_xdg_file (int xdg_type, const char* filename) {
2570 /* xdg_type = 0 => config
2571 xdg_type = 1 => data
2572 xdg_type = 2 => cache*/
2574 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2575 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2578 gchar* temporary_string;
2582 if (! file_exists (temporary_file) && xdg_type != 2) {
2583 buf = get_xdg_var (XDG[3 + xdg_type]);
2584 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2587 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2588 g_free (temporary_file);
2589 temporary_file = g_strconcat (temporary_string, filename, NULL);
2593 //g_free (temporary_string); - segfaults.
2595 if (file_exists (temporary_file)) {
2596 return temporary_file;
2598 g_free(temporary_file);
2604 State *s = &uzbl.state;
2605 Network *n = &uzbl.net;
2607 for (i = 0; default_config[i].command != NULL; i++) {
2608 parse_cmd_line(default_config[i].command, NULL);
2611 if (g_strcmp0(s->config_file, "-") == 0) {
2612 s->config_file = NULL;
2616 else if (!s->config_file) {
2617 s->config_file = find_xdg_file (0, "/uzbl/config");
2620 if (s->config_file) {
2621 GArray* lines = read_file_by_line (s->config_file);
2625 while ((line = g_array_index(lines, gchar*, i))) {
2626 parse_cmd_line (line, NULL);
2630 g_array_free (lines, TRUE);
2632 if (uzbl.state.verbose)
2633 printf ("No configuration file loaded.\n");
2636 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2639 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2642 if (!uzbl.behave.cookie_handler)
2645 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2646 GString *s = g_string_new ("");
2647 SoupURI * soup_uri = soup_message_get_uri(msg);
2648 g_string_printf(s, "GET '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path);
2649 run_handler(uzbl.behave.cookie_handler, s->str);
2651 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2652 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2653 if ( p != NULL ) *p = '\0';
2654 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2656 if (uzbl.comm.sync_stdout)
2657 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2659 g_string_free(s, TRUE);
2663 save_cookies (SoupMessage *msg, gpointer user_data){
2667 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2668 cookie = soup_cookie_to_set_cookie_header(ck->data);
2669 SoupURI * soup_uri = soup_message_get_uri(msg);
2670 GString *s = g_string_new ("");
2671 g_string_printf(s, "PUT '%s' '%s' '%s' '%s'", soup_uri->scheme, soup_uri->host, soup_uri->path, cookie);
2672 run_handler(uzbl.behave.cookie_handler, s->str);
2674 g_string_free(s, TRUE);
2679 /* --- WEBINSPECTOR --- */
2681 hide_window_cb(GtkWidget *widget, gpointer data) {
2684 gtk_widget_hide(widget);
2688 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2691 (void) web_inspector;
2692 GtkWidget* scrolled_window;
2693 GtkWidget* new_web_view;
2696 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2697 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2698 G_CALLBACK(hide_window_cb), NULL);
2700 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2701 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2702 gtk_widget_show(g->inspector_window);
2704 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2705 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2706 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2707 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2708 gtk_widget_show(scrolled_window);
2710 new_web_view = webkit_web_view_new();
2711 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2713 return WEBKIT_WEB_VIEW(new_web_view);
2717 inspector_show_window_cb (WebKitWebInspector* inspector){
2719 gtk_widget_show(uzbl.gui.inspector_window);
2723 /* TODO: Add variables and code to make use of these functions */
2725 inspector_close_window_cb (WebKitWebInspector* inspector){
2731 inspector_attach_window_cb (WebKitWebInspector* inspector){
2737 inspector_detach_window_cb (WebKitWebInspector* inspector){
2743 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2749 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2755 set_up_inspector() {
2757 WebKitWebSettings *settings = view_settings();
2758 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2760 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2761 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2762 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2763 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2764 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2765 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2766 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2768 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2772 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2774 uzbl_cmdprop *c = v;
2779 if(c->type == TYPE_STR)
2780 printf("set %s = %s\n", (char *)k, *c->ptr.s ? *c->ptr.s : " ");
2781 else if(c->type == TYPE_INT)
2782 printf("set %s = %d\n", (char *)k, *c->ptr.i);
2783 else if(c->type == TYPE_FLOAT)
2784 printf("set %s = %f\n", (char *)k, *c->ptr.f);
2788 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2792 printf("bind %s = %s %s\n", (char *)k ,
2793 (char *)a->name, a->param?(char *)a->param:"");
2798 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2799 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2803 retrieve_geometry() {
2805 GString *buf = g_string_new("");
2807 gtk_window_get_size(GTK_WINDOW(uzbl.gui.main_window), &w, &h);
2808 gtk_window_get_position(GTK_WINDOW(uzbl.gui.main_window), &x, &y);
2810 g_string_printf(buf, "%dx%d+%d+%d", w, h, x, y);
2812 if(uzbl.gui.geometry)
2813 g_free(uzbl.gui.geometry);
2814 uzbl.gui.geometry = g_string_free(buf, FALSE);
2817 /* set up gtk, gobject, variable defaults and other things that tests and other
2818 * external applications need to do anyhow */
2820 initialize(int argc, char *argv[]) {
2821 if (!g_thread_supported ())
2822 g_thread_init (NULL);
2823 uzbl.state.executable_path = g_strdup(argv[0]);
2824 uzbl.state.selected_url = NULL;
2825 uzbl.state.searchtx = NULL;
2827 GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default");
2828 g_option_context_add_main_entries (context, entries, NULL);
2829 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2830 g_option_context_parse (context, &argc, &argv, NULL);
2831 g_option_context_free(context);
2833 if (uzbl.behave.print_version) {
2834 printf("Commit: %s\n", COMMIT);
2838 /* initialize hash table */
2839 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2841 uzbl.net.soup_session = webkit_get_default_session();
2842 uzbl.state.keycmd = g_strdup("");
2844 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2845 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2846 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2847 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2848 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2849 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2851 uzbl.gui.sbar.progress_s = g_strdup("="); //TODO: move these to config.h
2852 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2853 uzbl.gui.sbar.progress_w = 10;
2855 /* HTML mode defaults*/
2856 uzbl.behave.html_buffer = g_string_new("");
2857 uzbl.behave.html_endmarker = g_strdup(".");
2858 uzbl.behave.html_timeout = 60;
2859 uzbl.behave.base_url = g_strdup("http://invalid");
2861 /* default mode indicators */
2862 uzbl.behave.insert_indicator = g_strdup("I");
2863 uzbl.behave.cmd_indicator = g_strdup("C");
2865 uzbl.info.webkit_major = WEBKIT_MAJOR_VERSION;
2866 uzbl.info.webkit_minor = WEBKIT_MINOR_VERSION;
2867 uzbl.info.webkit_micro = WEBKIT_MICRO_VERSION;
2868 uzbl.info.arch = ARCH;
2869 uzbl.info.commit = COMMIT;
2872 make_var_to_name_hash();
2877 #ifndef UZBL_LIBRARY
2880 main (int argc, char* argv[]) {
2881 initialize(argc, argv);
2883 gtk_init (&argc, &argv);
2885 uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL);
2886 //main_window_ref = g_object_ref(scrolled_window);
2887 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win),
2888 GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
2890 gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win),
2891 GTK_WIDGET (uzbl.gui.web_view));
2893 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2897 /* initial packing */
2898 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2899 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2901 if (uzbl.state.socket_id) {
2902 uzbl.gui.plug = create_plug ();
2903 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2904 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2906 uzbl.gui.main_window = create_window ();
2907 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2908 gtk_widget_show_all (uzbl.gui.main_window);
2909 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2912 if(!uzbl.state.instance_name)
2913 uzbl.state.instance_name = itos((int)uzbl.xwin);
2915 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2917 if (uzbl.state.verbose) {
2918 printf("Uzbl start location: %s\n", argv[0]);
2919 if (uzbl.state.socket_id)
2920 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2922 printf("window_id %i\n",(int) uzbl.xwin);
2923 printf("pid %i\n", getpid ());
2924 printf("name: %s\n", uzbl.state.instance_name);
2927 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2928 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2929 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2930 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2931 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2933 if(uzbl.gui.geometry)
2936 retrieve_geometry();
2938 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2939 if (argc > 1 && !uzbl.state.uri)
2940 uri_override = g_strdup(argv[1]);
2941 gboolean verbose_override = uzbl.state.verbose;
2944 set_insert_mode(FALSE);
2946 if (!uzbl.behave.show_status)
2947 gtk_widget_hide(uzbl.gui.mainbar);
2954 if (verbose_override > uzbl.state.verbose)
2955 uzbl.state.verbose = verbose_override;
2958 set_var_value("uri", uri_override);
2959 g_free(uri_override);
2960 } else if (uzbl.state.uri)
2966 return EXIT_SUCCESS;
2970 /* vi: set et ts=4: */