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])
34 #define MAX_BINDINGS 256
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
44 #include <webkit/webkit.h>
52 #include <sys/socket.h>
54 #include <libsoup/soup.h>
60 typedef void (*Command)(WebKitWebView*, GArray *argv);
62 /* commandline arguments (set initial values for the state variables) */
63 static GOptionEntry entries[] =
65 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
66 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", NULL },
67 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" },
68 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
69 { NULL, 0, 0, 0, NULL, NULL, NULL }
73 /* associate command names to their properties */
74 typedef const struct {
80 enum {TYPE_INT, TYPE_STR};
82 /* an abbreviation to help keep the table's width humane */
83 #define PTR(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .func = fun }
88 } var_name_to_ptr[] = {
89 /* variable name pointer to variable in code type callback function */
90 /* --------------------------------------------------------------------------------------- */
91 { "uri", PTR(uzbl.state.uri, STR, cmd_load_uri)},
92 { "status_message", PTR(uzbl.gui.sbar.msg, STR, update_title)},
93 { "show_status", PTR(uzbl.behave.show_status, INT, cmd_set_status)},
94 { "status_top", PTR(uzbl.behave.status_top, INT, move_statusbar)},
95 { "status_format", PTR(uzbl.behave.status_format, STR, update_title)},
96 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, update_title)},
97 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, update_title)},
98 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, update_title)},
99 { "status_background", PTR(uzbl.behave.status_background, STR, update_title)},
100 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, update_title)},
101 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, update_title)},
102 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, NULL)},
103 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, cmd_always_insert_mode)},
104 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, NULL)},
105 { "modkey", PTR(uzbl.behave.modkey, STR, cmd_modkey)},
106 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, NULL)},
107 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, NULL)},
108 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, NULL)},
109 { "history_handler", PTR(uzbl.behave.history_handler, STR, NULL)},
110 { "download_handler", PTR(uzbl.behave.download_handler, STR, NULL)},
111 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, cmd_cookie_handler)},
112 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, cmd_fifo_dir)},
113 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, cmd_socket_dir)},
114 { "http_debug", PTR(uzbl.behave.http_debug, INT, cmd_http_debug)},
115 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, NULL)},
116 { "proxy_url", PTR(uzbl.net.proxy_url, STR, set_proxy_url)},
117 { "max_conns", PTR(uzbl.net.max_conns, INT, cmd_max_conns)},
118 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, cmd_max_conns_host)},
119 { "useragent", PTR(uzbl.net.useragent, STR, cmd_useragent)},
120 /* exported WebKitWebSettings properties*/
121 { "font_size", PTR(uzbl.behave.font_size, INT, cmd_font_size)},
122 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, cmd_font_size)},
123 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, cmd_minimum_font_size)},
124 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, cmd_disable_plugins)},
125 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, cmd_disable_scripts)},
126 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, cmd_autoload_img)},
127 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, cmd_autoshrink_img)},
128 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, cmd_enable_spellcheck)},
129 { "enable_private", PTR(uzbl.behave.enable_private, INT, cmd_enable_private)},
130 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, cmd_print_bg)},
131 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, cmd_style_uri)},
132 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, cmd_resizable_txt)},
133 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, cmd_default_encoding)},
134 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, cmd_enforce_96dpi)},
136 { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}}
137 }, *n2v_p = var_name_to_ptr;
143 { "SHIFT", GDK_SHIFT_MASK }, // shift
144 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
145 { "CONTROL", GDK_CONTROL_MASK }, // control
146 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
147 { "MOD2", GDK_MOD2_MASK }, // 5th mod
148 { "MOD3", GDK_MOD3_MASK }, // 6th mod
149 { "MOD4", GDK_MOD4_MASK }, // 7th mod
150 { "MOD5", GDK_MOD5_MASK }, // 8th mod
151 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
152 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
153 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
154 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
155 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
156 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
157 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
158 { "META", GDK_META_MASK }, // meta (since 2.10)
163 /* construct a hash from the var_name_to_ptr array for quick access */
165 make_var_to_name_hash() {
166 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
168 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
174 /* --- UTILITY FUNCTIONS --- */
180 snprintf(tmp, sizeof(tmp), "%i", val);
181 return g_strdup(tmp);
185 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
188 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
191 str_replace (const char* search, const char* replace, const char* string) {
195 buf = g_strsplit (string, search, -1);
196 ret = g_strjoinv (replace, buf);
197 g_strfreev(buf); // somebody said this segfaults
203 read_file_by_line (gchar *path) {
204 GIOChannel *chan = NULL;
205 gchar *readbuf = NULL;
207 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
210 chan = g_io_channel_new_file(path, "r", NULL);
213 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
214 const gchar* val = g_strdup (readbuf);
215 g_array_append_val (lines, val);
220 g_io_channel_unref (chan);
222 fprintf(stderr, "File '%s' not be read.\n", path);
229 gchar* parseenv (char* string) {
230 extern char** environ;
231 gchar* tmpstr = NULL;
235 while (environ[i] != NULL) {
236 gchar** env = g_strsplit (environ[i], "=", 2);
237 gchar* envname = g_strconcat ("$", env[0], NULL);
239 if (g_strrstr (string, envname) != NULL) {
240 tmpstr = g_strdup(string);
242 string = str_replace(envname, env[1], tmpstr);
247 g_strfreev (env); // somebody said this breaks uzbl
255 setup_signal(int signr, sigfunc *shandler) {
256 struct sigaction nh, oh;
258 nh.sa_handler = shandler;
259 sigemptyset(&nh.sa_mask);
262 if(sigaction(signr, &nh, &oh) < 0)
270 if (uzbl.behave.fifo_dir)
271 unlink (uzbl.comm.fifo_path);
272 if (uzbl.behave.socket_dir)
273 unlink (uzbl.comm.socket_path);
275 g_free(uzbl.state.executable_path);
276 g_string_free(uzbl.state.keycmd, TRUE);
277 g_hash_table_destroy(uzbl.bindings);
278 g_hash_table_destroy(uzbl.behave.commands);
282 /* --- SIGNAL HANDLER --- */
285 catch_sigterm(int s) {
291 catch_sigint(int s) {
297 /* --- CALLBACKS --- */
300 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
303 (void) navigation_action;
304 (void) policy_decision;
306 const gchar* uri = webkit_network_request_get_uri (request);
307 if (uzbl.state.verbose)
308 printf("New window requested -> %s \n", uri);
309 new_window_load_uri(uri);
314 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
318 if (uzbl.state.selected_url != NULL) {
319 if (uzbl.state.verbose)
320 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
321 new_window_load_uri(uzbl.state.selected_url);
323 if (uzbl.state.verbose)
324 printf("New web view -> %s\n","Nothing to open, exiting");
330 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
333 if (uzbl.behave.download_handler) {
334 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
335 if (uzbl.state.verbose)
336 printf("Download -> %s\n",uri);
337 /* if urls not escaped, we may have to escape and quote uri before this call */
338 run_handler(uzbl.behave.download_handler, uri);
343 /* scroll a bar in a given direction */
345 scroll (GtkAdjustment* bar, GArray *argv) {
349 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
350 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
351 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
354 static void scroll_begin(WebKitWebView* page, GArray *argv) {
355 (void) page; (void) argv;
356 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
359 static void scroll_end(WebKitWebView* page, GArray *argv) {
360 (void) page; (void) argv;
361 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
362 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
365 static void scroll_vert(WebKitWebView* page, GArray *argv) {
367 scroll(uzbl.gui.bar_v, argv);
370 static void scroll_horz(WebKitWebView* page, GArray *argv) {
372 scroll(uzbl.gui.bar_h, argv);
377 if (!uzbl.behave.show_status) {
378 gtk_widget_hide(uzbl.gui.mainbar);
380 gtk_widget_show(uzbl.gui.mainbar);
386 toggle_status_cb (WebKitWebView* page, GArray *argv) {
390 if (uzbl.behave.show_status) {
391 gtk_widget_hide(uzbl.gui.mainbar);
393 gtk_widget_show(uzbl.gui.mainbar);
395 uzbl.behave.show_status = !uzbl.behave.show_status;
400 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
404 //Set selected_url state variable
405 g_free(uzbl.state.selected_url);
406 uzbl.state.selected_url = NULL;
408 uzbl.state.selected_url = g_strdup(link);
414 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
418 if (uzbl.gui.main_title)
419 g_free (uzbl.gui.main_title);
420 uzbl.gui.main_title = g_strdup (title);
425 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
428 uzbl.gui.sbar.load_progress = progress;
433 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
437 if (uzbl.behave.load_finish_handler)
438 run_handler(uzbl.behave.load_finish_handler, "");
442 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
446 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
447 if (uzbl.behave.load_start_handler)
448 run_handler(uzbl.behave.load_start_handler, "");
452 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
455 g_free (uzbl.state.uri);
456 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
457 uzbl.state.uri = g_string_free (newuri, FALSE);
458 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
459 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
462 if (uzbl.behave.load_commit_handler)
463 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
467 destroy_cb (GtkWidget* widget, gpointer data) {
475 if (uzbl.behave.history_handler) {
477 struct tm * timeinfo;
480 timeinfo = localtime ( &rawtime );
481 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
482 run_handler(uzbl.behave.history_handler, date);
487 /* VIEW funcs (little webkit wrappers) */
488 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
490 VIEWFUNC(reload_bypass_cache)
491 VIEWFUNC(stop_loading)
498 /* -- command to callback/function map for things we cannot attach to any signals */
500 static struct {char *name; Command command[2];} cmdlist[] =
501 { /* key function no_split */
502 { "back", {view_go_back, 0} },
503 { "forward", {view_go_forward, 0} },
504 { "scroll_vert", {scroll_vert, 0} },
505 { "scroll_horz", {scroll_horz, 0} },
506 { "scroll_begin", {scroll_begin, 0} },
507 { "scroll_end", {scroll_end, 0} },
508 { "reload", {view_reload, 0}, },
509 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
510 { "stop", {view_stop_loading, 0}, },
511 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
512 { "zoom_out", {view_zoom_out, 0}, },
513 { "uri", {load_uri, NOSPLIT} },
514 { "js", {run_js, NOSPLIT} },
515 { "script", {run_external_js, 0} },
516 { "toggle_status", {toggle_status_cb, 0} },
517 { "spawn", {spawn, 0} },
518 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
519 { "sh", {spawn_sh, 0} },
520 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
521 { "exit", {close_uzbl, 0} },
522 { "search", {search_forward_text, NOSPLIT} },
523 { "search_reverse", {search_reverse_text, NOSPLIT} },
524 { "toggle_insert_mode", {toggle_insert_mode, 0} },
525 { "runcmd", {runcmd, NOSPLIT} },
526 { "set", {set_var, NOSPLIT} }
533 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
535 for (i = 0; i < LENGTH(cmdlist); i++)
536 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
539 /* -- CORE FUNCTIONS -- */
542 free_action(gpointer act) {
543 Action *action = (Action*)act;
544 g_free(action->name);
546 g_free(action->param);
551 new_action(const gchar *name, const gchar *param) {
552 Action *action = g_new(Action, 1);
554 action->name = g_strdup(name);
556 action->param = g_strdup(param);
558 action->param = NULL;
564 file_exists (const char * filename) {
565 return (access(filename, F_OK) == 0);
569 set_var(WebKitWebView *page, GArray *argv) {
573 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
574 parse_cmd_line(ctl_line);
579 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
582 if (argv_idx(argv, 0)) {
583 if (strcmp (argv_idx(argv, 0), "0") == 0) {
584 uzbl.behave.insert_mode = FALSE;
586 uzbl.behave.insert_mode = TRUE;
589 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
596 load_uri (WebKitWebView *web_view, GArray *argv) {
597 if (argv_idx(argv, 0)) {
598 GString* newuri = g_string_new (argv_idx(argv, 0));
599 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
600 g_string_prepend (newuri, "http://");
601 /* if we do handle cookies, ask our handler for them */
602 webkit_web_view_load_uri (web_view, newuri->str);
603 g_string_free (newuri, TRUE);
608 run_js (WebKitWebView * web_view, GArray *argv) {
609 if (argv_idx(argv, 0))
610 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
614 run_external_js (WebKitWebView * web_view, GArray *argv) {
615 if (argv_idx(argv, 0)) {
616 GArray* lines = read_file_by_line (argv_idx (argv, 0));
621 while ((line = g_array_index(lines, gchar*, i))) {
623 js = g_strdup (line);
625 gchar* newjs = g_strconcat (js, line, NULL);
632 if (uzbl.state.verbose)
633 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
635 if (argv_idx (argv, 1)) {
636 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
640 webkit_web_view_execute_script (web_view, js);
642 g_array_free (lines, TRUE);
647 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
648 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
649 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
650 webkit_web_view_unmark_text_matches (page);
651 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
652 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
656 if (uzbl.state.searchtx) {
657 if (uzbl.state.verbose)
658 printf ("Searching: %s\n", uzbl.state.searchtx);
659 webkit_web_view_set_highlight_text_matches (page, TRUE);
660 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
665 search_forward_text (WebKitWebView *page, GArray *argv) {
666 search_text(page, argv, TRUE);
670 search_reverse_text (WebKitWebView *page, GArray *argv) {
671 search_text(page, argv, FALSE);
675 new_window_load_uri (const gchar * uri) {
676 GString* to_execute = g_string_new ("");
677 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
679 for (i = 0; entries[i].long_name != NULL; i++) {
680 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
681 gchar** str = (gchar**)entries[i].arg_data;
683 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
687 if (uzbl.state.verbose)
688 printf("\n%s\n", to_execute->str);
689 g_spawn_command_line_async (to_execute->str, NULL);
690 g_string_free (to_execute, TRUE);
694 close_uzbl (WebKitWebView *page, GArray *argv) {
700 /* --Statusbar functions-- */
702 build_progressbar_ascii(int percent) {
703 int width=uzbl.gui.sbar.progress_w;
706 GString *bar = g_string_new("");
708 l = (double)percent*((double)width/100.);
709 l = (int)(l+.5)>=(int)l ? l+.5 : l;
711 for(i=0; i<(int)l; i++)
712 g_string_append(bar, uzbl.gui.sbar.progress_s);
715 g_string_append(bar, uzbl.gui.sbar.progress_u);
717 return g_string_free(bar, FALSE);
722 const GScannerConfig scan_config = {
725 ) /* cset_skip_characters */,
730 ) /* cset_identifier_first */,
737 ) /* cset_identifier_nth */,
738 ( "" ) /* cpair_comment_single */,
740 TRUE /* case_sensitive */,
742 FALSE /* skip_comment_multi */,
743 FALSE /* skip_comment_single */,
744 FALSE /* scan_comment_multi */,
745 TRUE /* scan_identifier */,
746 TRUE /* scan_identifier_1char */,
747 FALSE /* scan_identifier_NULL */,
748 TRUE /* scan_symbols */,
749 FALSE /* scan_binary */,
750 FALSE /* scan_octal */,
751 FALSE /* scan_float */,
752 FALSE /* scan_hex */,
753 FALSE /* scan_hex_dollar */,
754 FALSE /* scan_string_sq */,
755 FALSE /* scan_string_dq */,
756 TRUE /* numbers_2_int */,
757 FALSE /* int_2_float */,
758 FALSE /* identifier_2_string */,
759 FALSE /* char_2_token */,
760 FALSE /* symbol_2_token */,
761 TRUE /* scope_0_fallback */,
766 uzbl.scan = g_scanner_new(&scan_config);
767 while(symp->symbol_name) {
768 g_scanner_scope_add_symbol(uzbl.scan, 0,
770 GINT_TO_POINTER(symp->symbol_token));
776 expand_template(const char *template, gboolean escape_markup) {
777 if(!template) return NULL;
779 GTokenType token = G_TOKEN_NONE;
780 GString *ret = g_string_new("");
784 g_scanner_input_text(uzbl.scan, template, strlen(template));
785 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
786 token = g_scanner_get_next_token(uzbl.scan);
788 if(token == G_TOKEN_SYMBOL) {
789 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
793 buf = uzbl.state.uri?
794 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
795 g_string_append(ret, buf);
799 g_string_append(ret, uzbl.state.uri?
800 uzbl.state.uri:g_strdup(""));
803 buf = itos(uzbl.gui.sbar.load_progress);
804 g_string_append(ret, buf);
807 case SYM_LOADPRGSBAR:
808 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
809 g_string_append(ret, buf);
814 buf = uzbl.gui.main_title?
815 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
816 g_string_append(ret, buf);
820 g_string_append(ret, uzbl.gui.main_title?
821 uzbl.gui.main_title:g_strdup(""));
823 case SYM_SELECTED_URI:
825 buf = uzbl.state.selected_url?
826 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
827 g_string_append(ret, buf);
831 g_string_append(ret, uzbl.state.selected_url?
832 uzbl.state.selected_url:g_strdup(""));
835 buf = itos(uzbl.xwin);
837 uzbl.state.instance_name?uzbl.state.instance_name:buf);
842 buf = uzbl.state.keycmd->str?
843 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
844 g_string_append(ret, buf);
848 g_string_append(ret, uzbl.state.keycmd->str?
849 uzbl.state.keycmd->str:g_strdup(""));
853 uzbl.behave.insert_mode?"[I]":"[C]");
857 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
861 buf = itos(WEBKIT_MAJOR_VERSION);
862 g_string_append(ret, buf);
866 buf = itos(WEBKIT_MINOR_VERSION);
867 g_string_append(ret, buf);
871 buf = itos(WEBKIT_MICRO_VERSION);
872 g_string_append(ret, buf);
876 g_string_append(ret, uzbl.state.unameinfo.sysname);
879 g_string_append(ret, uzbl.state.unameinfo.nodename);
882 g_string_append(ret, uzbl.state.unameinfo.release);
885 g_string_append(ret, uzbl.state.unameinfo.version);
888 g_string_append(ret, uzbl.state.unameinfo.machine);
891 g_string_append(ret, ARCH);
895 g_string_append(ret, uzbl.state.unameinfo.domainname);
899 g_string_append(ret, COMMIT);
905 else if(token == G_TOKEN_INT) {
906 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
907 g_string_append(ret, buf);
910 else if(token == G_TOKEN_IDENTIFIER) {
911 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
913 else if(token == G_TOKEN_CHAR) {
914 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
918 return g_string_free(ret, FALSE);
920 /* --End Statusbar functions-- */
923 sharg_append(GArray *a, const gchar *str) {
924 const gchar *s = (str ? str : "");
925 g_array_append_val(a, s);
928 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
930 run_command (const gchar *command, const guint npre, const gchar **args,
931 const gboolean sync, char **stdout) {
932 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
935 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
936 gchar *pid = itos(getpid());
937 gchar *xwin = itos(uzbl.xwin);
939 sharg_append(a, command);
940 for (i = 0; i < npre; i++) /* add n args before the default vars */
941 sharg_append(a, args[i]);
942 sharg_append(a, uzbl.state.config_file);
943 sharg_append(a, pid);
944 sharg_append(a, xwin);
945 sharg_append(a, uzbl.comm.fifo_path);
946 sharg_append(a, uzbl.comm.socket_path);
947 sharg_append(a, uzbl.state.uri);
948 sharg_append(a, uzbl.gui.main_title);
950 for (i = npre; i < g_strv_length((gchar**)args); i++)
951 sharg_append(a, args[i]);
955 if (*stdout) *stdout = strfree(*stdout);
957 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
958 NULL, NULL, stdout, NULL, NULL, &err);
959 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
960 NULL, NULL, NULL, &err);
962 if (uzbl.state.verbose) {
963 GString *s = g_string_new("spawned:");
964 for (i = 0; i < (a->len); i++) {
965 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
966 g_string_append_printf(s, " %s", qarg);
969 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
970 printf("%s\n", s->str);
971 g_string_free(s, TRUE);
974 g_printerr("error on run_command: %s\n", err->message);
979 g_array_free (a, TRUE);
984 split_quoted(const gchar* src, const gboolean unquote) {
985 /* split on unquoted space, return array of strings;
986 remove a layer of quotes and backslashes if unquote */
987 if (!src) return NULL;
991 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
992 GString *s = g_string_new ("");
996 for (p = src; *p != '\0'; p++) {
997 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
998 else if (*p == '\\') { g_string_append_c(s, *p++);
999 g_string_append_c(s, *p); }
1000 else if ((*p == '"') && unquote && !sq) dq = !dq;
1001 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1003 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1004 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1006 else if ((*p == ' ') && !dq && !sq) {
1007 dup = g_strdup(s->str);
1008 g_array_append_val(a, dup);
1009 g_string_truncate(s, 0);
1010 } else g_string_append_c(s, *p);
1012 dup = g_strdup(s->str);
1013 g_array_append_val(a, dup);
1014 ret = (gchar**)a->data;
1015 g_array_free (a, FALSE);
1016 g_string_free (s, TRUE);
1021 spawn(WebKitWebView *web_view, GArray *argv) {
1023 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1024 if (argv_idx(argv, 0))
1025 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1029 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1032 if (argv_idx(argv, 0))
1033 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1034 TRUE, &uzbl.comm.sync_stdout);
1038 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1040 if (!uzbl.behave.shell_cmd) {
1041 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1046 gchar *spacer = g_strdup("");
1047 g_array_insert_val(argv, 1, spacer);
1048 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1050 for (i = 1; i < g_strv_length(cmd); i++)
1051 g_array_prepend_val(argv, cmd[i]);
1053 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1059 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1061 if (!uzbl.behave.shell_cmd) {
1062 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1067 gchar *spacer = g_strdup("");
1068 g_array_insert_val(argv, 1, spacer);
1069 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1071 for (i = 1; i < g_strv_length(cmd); i++)
1072 g_array_prepend_val(argv, cmd[i]);
1074 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1075 TRUE, &uzbl.comm.sync_stdout);
1081 parse_command(const char *cmd, const char *param) {
1084 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1087 gchar **par = split_quoted(param, TRUE);
1088 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1090 if (c[1] == NOSPLIT) { /* don't split */
1091 sharg_append(a, param);
1093 for (i = 0; i < g_strv_length(par); i++)
1094 sharg_append(a, par[i]);
1096 c[0](uzbl.gui.web_view, a);
1098 g_array_free (a, TRUE);
1101 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1104 /* command parser */
1107 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1108 G_REGEX_OPTIMIZE, 0, NULL);
1109 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1110 G_REGEX_OPTIMIZE, 0, NULL);
1111 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1112 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1113 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1114 G_REGEX_OPTIMIZE, 0, NULL);
1115 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1116 G_REGEX_OPTIMIZE, 0, NULL);
1120 get_var_value(gchar *name) {
1123 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1124 if(c->type == TYPE_STR)
1125 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1126 else if(c->type == TYPE_INT)
1127 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1136 if(*uzbl.net.proxy_url == ' '
1137 || uzbl.net.proxy_url == NULL) {
1138 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1139 (GType) SOUP_SESSION_PROXY_URI);
1142 suri = soup_uri_new(uzbl.net.proxy_url);
1143 g_object_set(G_OBJECT(uzbl.net.soup_session),
1144 SOUP_SESSION_PROXY_URI,
1146 soup_uri_free(suri);
1153 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1154 g_array_append_val (a, uzbl.state.uri);
1155 load_uri(uzbl.gui.web_view, a);
1156 g_array_free (a, TRUE);
1160 cmd_always_insert_mode() {
1161 uzbl.behave.insert_mode =
1162 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1168 g_object_set(G_OBJECT(uzbl.net.soup_session),
1169 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1173 cmd_max_conns_host() {
1174 g_object_set(G_OBJECT(uzbl.net.soup_session),
1175 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1180 soup_session_remove_feature
1181 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1182 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1183 /*g_free(uzbl.net.soup_logger);*/
1185 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1186 soup_session_add_feature(uzbl.net.soup_session,
1187 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1190 static WebKitWebSettings*
1192 return webkit_web_view_get_settings(uzbl.gui.web_view);
1197 WebKitWebSettings *ws = view_settings();
1198 if (uzbl.behave.font_size > 0) {
1199 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1202 if (uzbl.behave.monospace_size > 0) {
1203 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1204 uzbl.behave.monospace_size, NULL);
1206 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1207 uzbl.behave.font_size, NULL);
1212 cmd_disable_plugins() {
1213 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1214 !uzbl.behave.disable_plugins, NULL);
1218 cmd_disable_scripts() {
1219 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1220 !uzbl.behave.disable_plugins, NULL);
1224 cmd_minimum_font_size() {
1225 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1226 uzbl.behave.minimum_font_size, NULL);
1229 cmd_autoload_img() {
1230 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1231 uzbl.behave.autoload_img, NULL);
1236 cmd_autoshrink_img() {
1237 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1238 uzbl.behave.autoshrink_img, NULL);
1243 cmd_enable_spellcheck() {
1244 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1245 uzbl.behave.enable_spellcheck, NULL);
1249 cmd_enable_private() {
1250 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1251 uzbl.behave.enable_private, NULL);
1256 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1257 uzbl.behave.print_bg, NULL);
1262 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1263 uzbl.behave.style_uri, NULL);
1267 cmd_resizable_txt() {
1268 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1269 uzbl.behave.resizable_txt, NULL);
1273 cmd_default_encoding() {
1274 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1275 uzbl.behave.default_encoding, NULL);
1279 cmd_enforce_96dpi() {
1280 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1281 uzbl.behave.enforce_96dpi, NULL);
1285 cmd_cookie_handler() {
1286 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1287 if ((g_strcmp0(split[0], "sh") == 0) ||
1288 (g_strcmp0(split[0], "spawn") == 0)) {
1289 g_free (uzbl.behave.cookie_handler);
1290 uzbl.behave.cookie_handler =
1291 g_strdup_printf("sync_%s %s", split[0], split[1]);
1298 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1303 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1311 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1312 uzbl.behave.modmask = 0;
1314 if(uzbl.behave.modkey)
1315 g_free(uzbl.behave.modkey);
1316 uzbl.behave.modkey = buf;
1318 for (i = 0; modkeys[i].key != NULL; i++) {
1319 if (g_strrstr(buf, modkeys[i].key))
1320 uzbl.behave.modmask |= modkeys[i].mask;
1326 if (*uzbl.net.useragent == ' ') {
1327 g_free (uzbl.net.useragent);
1328 uzbl.net.useragent = NULL;
1330 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1332 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1333 g_free(uzbl.net.useragent);
1334 uzbl.net.useragent = ua;
1340 gtk_widget_ref(uzbl.gui.scrolled_win);
1341 gtk_widget_ref(uzbl.gui.mainbar);
1342 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1343 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1345 if(uzbl.behave.status_top) {
1346 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1347 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1350 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1351 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1353 gtk_widget_unref(uzbl.gui.scrolled_win);
1354 gtk_widget_unref(uzbl.gui.mainbar);
1355 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1360 set_var_value(gchar *name, gchar *val) {
1361 uzbl_cmdprop *c = NULL;
1364 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1365 /* check for the variable type */
1366 if (c->type == TYPE_STR) {
1368 *c->ptr = g_strdup(val);
1369 } else if(c->type == TYPE_INT) {
1370 int *ip = GPOINTER_TO_INT(c->ptr);
1371 *ip = (int)strtoul(val, &endp, 10);
1374 /* invoke a command specific function */
1375 if(c->func) c->func();
1381 runcmd(WebKitWebView* page, GArray *argv) {
1383 parse_cmd_line(argv_idx(argv, 0));
1387 parse_cmd_line(const char *ctl_line) {
1388 gchar **tokens = NULL;
1391 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1392 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1393 if(tokens[0][0] == 0) {
1394 gchar* value = parseenv(g_strdup(tokens[2]));
1395 set_var_value(tokens[1], value);
1399 printf("Error in command: %s\n", tokens[0]);
1402 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1403 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1404 if(tokens[0][0] == 0) {
1405 get_var_value(tokens[1]);
1408 printf("Error in command: %s\n", tokens[0]);
1411 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1412 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1413 if(tokens[0][0] == 0) {
1414 gchar* value = parseenv(g_strdup(tokens[2]));
1415 add_binding(tokens[1], value);
1419 printf("Error in command: %s\n", tokens[0]);
1422 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1423 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1424 if(tokens[0][0] == 0) {
1425 parse_command(tokens[1], tokens[2]);
1428 printf("Error in command: %s\n", tokens[0]);
1430 /* KEYCMD command */
1431 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1432 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1433 if(tokens[0][0] == 0) {
1434 /* should incremental commands want each individual "keystroke"
1435 sent in a loop or the whole string in one go like now? */
1436 g_string_assign(uzbl.state.keycmd, tokens[1]);
1438 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1444 else if( (ctl_line[0] == '#')
1445 || (ctl_line[0] == ' ')
1446 || (ctl_line[0] == '\n'))
1447 ; /* ignore these lines */
1449 printf("Command not understood (%s)\n", ctl_line);
1458 build_stream_name(int type, const gchar* dir) {
1460 State *s = &uzbl.state;
1463 xwin_str = itos((int)uzbl.xwin);
1465 str = g_strdup_printf
1466 ("%s/uzbl_fifo_%s", dir,
1467 s->instance_name ? s->instance_name : xwin_str);
1468 } else if (type == SOCKET) {
1469 str = g_strdup_printf
1470 ("%s/uzbl_socket_%s", dir,
1471 s->instance_name ? s->instance_name : xwin_str );
1478 control_fifo(GIOChannel *gio, GIOCondition condition) {
1479 if (uzbl.state.verbose)
1480 printf("triggered\n");
1485 if (condition & G_IO_HUP)
1486 g_error ("Fifo: Read end of pipe died!\n");
1489 g_error ("Fifo: GIOChannel broke\n");
1491 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1492 if (ret == G_IO_STATUS_ERROR) {
1493 g_error ("Fifo: Error reading: %s\n", err->message);
1497 parse_cmd_line(ctl_line);
1504 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1505 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1506 if (unlink(uzbl.comm.fifo_path) == -1)
1507 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1508 g_free(uzbl.comm.fifo_path);
1509 uzbl.comm.fifo_path = NULL;
1512 if (*dir == ' ') { /* space unsets the variable */
1517 GIOChannel *chan = NULL;
1518 GError *error = NULL;
1519 gchar *path = build_stream_name(FIFO, dir);
1521 if (!file_exists(path)) {
1522 if (mkfifo (path, 0666) == 0) {
1523 // 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.
1524 chan = g_io_channel_new_file(path, "r+", &error);
1526 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1527 if (uzbl.state.verbose)
1528 printf ("init_fifo: created successfully as %s\n", path);
1529 uzbl.comm.fifo_path = path;
1531 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1532 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1533 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1534 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1536 /* if we got this far, there was an error; cleanup */
1537 if (error) g_error_free (error);
1544 control_stdin(GIOChannel *gio, GIOCondition condition) {
1546 gchar *ctl_line = NULL;
1549 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1550 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1553 parse_cmd_line(ctl_line);
1561 GIOChannel *chan = NULL;
1562 GError *error = NULL;
1564 chan = g_io_channel_unix_new(fileno(stdin));
1566 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1567 g_error ("Stdin: could not add watch\n");
1569 if (uzbl.state.verbose)
1570 printf ("Stdin: watch added successfully\n");
1573 g_error ("Stdin: Error while opening: %s\n", error->message);
1575 if (error) g_error_free (error);
1579 control_socket(GIOChannel *chan) {
1580 struct sockaddr_un remote;
1581 char buffer[512], *ctl_line;
1583 int sock, clientsock, n, done;
1586 sock = g_io_channel_unix_get_fd(chan);
1588 memset (buffer, 0, sizeof (buffer));
1590 t = sizeof (remote);
1591 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1595 memset (temp, 0, sizeof (temp));
1596 n = recv (clientsock, temp, 128, 0);
1598 buffer[strlen (buffer)] = '\0';
1602 strcat (buffer, temp);
1605 if (strcmp (buffer, "\n") < 0) {
1606 buffer[strlen (buffer) - 1] = '\0';
1608 buffer[strlen (buffer)] = '\0';
1611 ctl_line = g_strdup(buffer);
1612 parse_cmd_line (ctl_line);
1615 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1616 GError *error = NULL;
1619 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1620 if (ret == G_IO_STATUS_ERROR)
1621 g_error ("Error reading: %s\n", error->message);
1623 printf("Got line %s (%u bytes) \n",ctl_line, len);
1625 parse_line(ctl_line);
1633 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1634 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1635 if (unlink(uzbl.comm.socket_path) == -1)
1636 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1637 g_free(uzbl.comm.socket_path);
1638 uzbl.comm.socket_path = NULL;
1646 GIOChannel *chan = NULL;
1648 struct sockaddr_un local;
1649 gchar *path = build_stream_name(SOCKET, dir);
1651 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1653 local.sun_family = AF_UNIX;
1654 strcpy (local.sun_path, path);
1655 unlink (local.sun_path);
1657 len = strlen (local.sun_path) + sizeof (local.sun_family);
1658 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1659 if (uzbl.state.verbose)
1660 printf ("init_socket: opened in %s\n", path);
1663 if( (chan = g_io_channel_unix_new(sock)) ) {
1664 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1665 uzbl.comm.socket_path = path;
1668 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1670 /* if we got this far, there was an error; cleanup */
1677 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1678 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1680 // this function may be called very early when the templates are not set (yet), hence the checks
1682 update_title (void) {
1683 Behaviour *b = &uzbl.behave;
1686 if (b->show_status) {
1687 if (b->title_format_short) {
1688 parsed = expand_template(b->title_format_short, FALSE);
1689 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1692 if (b->status_format) {
1693 parsed = expand_template(b->status_format, TRUE);
1694 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1697 if (b->status_background) {
1699 gdk_color_parse (b->status_background, &color);
1700 //labels and hboxes do not draw their own background. applying this on the window is ok as we the statusbar is the only affected widget. (if not, we could also use GtkEventBox)
1701 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1704 if (b->title_format_long) {
1705 parsed = expand_template(b->title_format_long, FALSE);
1706 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1713 key_press_cb (GtkWidget* window, GdkEventKey* event)
1715 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1719 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1720 || event->keyval == GDK_Up || event->keyval == GDK_Down || event->keyval == GDK_Left || event->keyval == GDK_Right || event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R)
1723 /* turn off insert mode (if always_insert_mode is not used) */
1724 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1725 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1730 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1733 if (event->keyval == GDK_Escape) {
1734 g_string_truncate(uzbl.state.keycmd, 0);
1739 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1740 if (event->keyval == GDK_Insert) {
1742 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1743 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1745 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1748 g_string_append (uzbl.state.keycmd, str);
1755 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1756 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1760 gboolean key_ret = FALSE;
1761 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1763 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1765 run_keycmd(key_ret);
1767 if (key_ret) return (!uzbl.behave.insert_mode);
1772 run_keycmd(const gboolean key_ret) {
1773 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1775 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1776 g_string_truncate(uzbl.state.keycmd, 0);
1777 parse_command(action->name, action->param);
1781 /* try if it's an incremental keycmd or one that takes args, and run it */
1782 GString* short_keys = g_string_new ("");
1783 GString* short_keys_inc = g_string_new ("");
1785 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1786 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1787 g_string_assign(short_keys_inc, short_keys->str);
1788 g_string_append_c(short_keys, '_');
1789 g_string_append_c(short_keys_inc, '*');
1791 gboolean exec_now = FALSE;
1792 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1793 if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
1794 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1795 if (key_ret) { /* just quit the incremental command on return */
1796 g_string_truncate(uzbl.state.keycmd, 0);
1798 } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
1802 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1803 GString* actionname = g_string_new ("");
1804 GString* actionparam = g_string_new ("");
1805 g_string_erase (parampart, 0, i+1);
1807 g_string_printf (actionname, action->name, parampart->str);
1809 g_string_printf (actionparam, action->param, parampart->str);
1810 parse_command(actionname->str, actionparam->str);
1811 g_string_free (actionname, TRUE);
1812 g_string_free (actionparam, TRUE);
1813 g_string_free (parampart, TRUE);
1815 g_string_truncate(uzbl.state.keycmd, 0);
1819 g_string_truncate(short_keys, short_keys->len - 1);
1821 g_string_free (short_keys, TRUE);
1822 g_string_free (short_keys_inc, TRUE);
1829 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1830 //main_window_ref = g_object_ref(scrolled_window);
1831 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
1833 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1834 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1836 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1837 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1838 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1839 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1840 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1841 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1842 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1843 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1844 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1845 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1847 return scrolled_window;
1854 g->mainbar = gtk_hbox_new (FALSE, 0);
1856 /* keep a reference to the bar so we can re-pack it at runtime*/
1857 //sbar_ref = g_object_ref(g->mainbar);
1859 g->mainbar_label = gtk_label_new ("");
1860 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1861 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1862 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1863 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1864 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1869 GtkWidget* create_window () {
1870 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1871 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1872 gtk_widget_set_name (window, "Uzbl browser");
1873 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1874 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1880 run_handler (const gchar *act, const gchar *args) {
1881 char **parts = g_strsplit(act, " ", 2);
1883 else if ((g_strcmp0(parts[0], "spawn") == 0)
1884 || (g_strcmp0(parts[0], "sh") == 0)
1885 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1886 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1888 GString *a = g_string_new ("");
1890 spawnparts = split_quoted(parts[1], FALSE);
1891 g_string_append_printf(a, "%s", spawnparts[0]);
1892 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1894 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1895 g_string_append_printf(a, " %s", spawnparts[i]);
1896 parse_command(parts[0], a->str);
1897 g_string_free (a, TRUE);
1898 g_strfreev (spawnparts);
1900 parse_command(parts[0], parts[1]);
1905 add_binding (const gchar *key, const gchar *act) {
1906 char **parts = g_strsplit(act, " ", 2);
1913 if (uzbl.state.verbose)
1914 printf ("Binding %-10s : %s\n", key, act);
1915 action = new_action(parts[0], parts[1]);
1917 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
1922 get_xdg_var (XDG_Var xdg) {
1923 const gchar* actual_value = getenv (xdg.environmental);
1924 const gchar* home = getenv ("HOME");
1926 gchar* return_value = str_replace ("~", home, actual_value);
1928 if (! actual_value || strcmp (actual_value, "") == 0) {
1929 if (xdg.default_value) {
1930 return_value = str_replace ("~", home, xdg.default_value);
1932 return_value = NULL;
1935 return return_value;
1939 find_xdg_file (int xdg_type, char* filename) {
1940 /* xdg_type = 0 => config
1941 xdg_type = 1 => data
1942 xdg_type = 2 => cache*/
1944 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
1945 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
1948 gchar* temporary_string;
1952 if (! file_exists (temporary_file) && xdg_type != 2) {
1953 buf = get_xdg_var (XDG[3 + xdg_type]);
1954 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
1957 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
1958 g_free (temporary_file);
1959 temporary_file = g_strconcat (temporary_string, filename, NULL);
1963 //g_free (temporary_string); - segfaults.
1965 if (file_exists (temporary_file)) {
1966 return temporary_file;
1973 State *s = &uzbl.state;
1974 Network *n = &uzbl.net;
1976 for (i = 0; default_config[i].command != NULL; i++) {
1977 parse_cmd_line(default_config[i].command);
1980 if (!s->config_file) {
1981 s->config_file = find_xdg_file (0, "/uzbl/config");
1984 if (s->config_file) {
1985 GArray* lines = read_file_by_line (s->config_file);
1989 while ((line = g_array_index(lines, gchar*, i))) {
1990 parse_cmd_line (line);
1994 g_array_free (lines, TRUE);
1996 if (uzbl.state.verbose)
1997 printf ("No configuration file loaded.\n");
2000 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2003 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2006 if (!uzbl.behave.cookie_handler) return;
2008 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2009 GString *s = g_string_new ("");
2010 SoupURI * soup_uri = soup_message_get_uri(msg);
2011 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2012 run_handler(uzbl.behave.cookie_handler, s->str);
2014 if(uzbl.comm.sync_stdout)
2015 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2016 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2017 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2019 g_string_free(s, TRUE);
2023 save_cookies (SoupMessage *msg, gpointer user_data){
2027 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2028 cookie = soup_cookie_to_set_cookie_header(ck->data);
2029 SoupURI * soup_uri = soup_message_get_uri(msg);
2030 GString *s = g_string_new ("");
2031 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2032 run_handler(uzbl.behave.cookie_handler, s->str);
2034 g_string_free(s, TRUE);
2039 /* --- WEBINSPECTOR --- */
2041 hide_window_cb(GtkWidget *widget, gpointer data) {
2044 gtk_widget_hide(widget);
2047 static WebKitWebView*
2048 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2051 (void) web_inspector;
2052 GtkWidget* scrolled_window;
2053 GtkWidget* new_web_view;
2056 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2057 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2058 G_CALLBACK(hide_window_cb), NULL);
2060 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2061 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2062 gtk_widget_show(g->inspector_window);
2064 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2065 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2066 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2067 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2068 gtk_widget_show(scrolled_window);
2070 new_web_view = webkit_web_view_new();
2071 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2073 return WEBKIT_WEB_VIEW(new_web_view);
2077 inspector_show_window_cb (WebKitWebInspector* inspector){
2079 gtk_widget_show(uzbl.gui.inspector_window);
2083 /* TODO: Add variables and code to make use of these functions */
2085 inspector_close_window_cb (WebKitWebInspector* inspector){
2091 inspector_attach_window_cb (WebKitWebInspector* inspector){
2097 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2103 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2109 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2115 set_up_inspector() {
2117 WebKitWebSettings *settings = webkit_web_settings_new();
2118 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2119 webkit_web_view_set_settings(WEBKIT_WEB_VIEW(uzbl.gui.web_view), settings);
2122 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2123 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2124 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2125 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2126 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2127 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2128 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2130 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2137 main (int argc, char* argv[]) {
2138 gtk_init (&argc, &argv);
2139 if (!g_thread_supported ())
2140 g_thread_init (NULL);
2141 uzbl.state.executable_path = g_strdup(argv[0]);
2142 uzbl.state.selected_url = NULL;
2143 uzbl.state.searchtx = NULL;
2145 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2146 g_option_context_add_main_entries (context, entries, NULL);
2147 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2148 g_option_context_parse (context, &argc, &argv, NULL);
2149 g_option_context_free(context);
2150 /* initialize hash table */
2151 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2153 uzbl.net.soup_session = webkit_get_default_session();
2154 uzbl.state.keycmd = g_string_new("");
2156 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2157 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2158 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2159 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2161 if(uname(&uzbl.state.unameinfo) == -1)
2162 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2164 uzbl.gui.sbar.progress_s = g_strdup("=");
2165 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2166 uzbl.gui.sbar.progress_w = 10;
2171 make_var_to_name_hash();
2173 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2175 uzbl.gui.scrolled_win = create_browser();
2178 /* initial packing */
2179 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2180 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2182 uzbl.gui.main_window = create_window ();
2183 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2186 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2187 gtk_widget_show_all (uzbl.gui.main_window);
2188 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2190 if (uzbl.state.verbose) {
2191 printf("Uzbl start location: %s\n", argv[0]);
2192 printf("window_id %i\n",(int) uzbl.xwin);
2193 printf("pid %i\n", getpid ());
2194 printf("name: %s\n", uzbl.state.instance_name);
2197 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2198 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2199 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2200 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2201 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2205 if (!uzbl.behave.show_status)
2206 gtk_widget_hide(uzbl.gui.mainbar);
2215 if(uzbl.state.uri) {
2216 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2217 g_array_append_val(a, uzbl.state.uri);
2218 load_uri (uzbl.gui.web_view, a);
2219 g_array_free (a, TRUE);
2225 return EXIT_SUCCESS;
2228 /* vi: set et ts=4: */