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>
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <sys/utsname.h>
47 #include <webkit/webkit.h>
48 #include <libsoup/soup.h>
61 typedef void (*Command)(WebKitWebView*, GArray *argv);
65 /* commandline arguments (set initial values for the state variables) */
67 GOptionEntry entries[] =
69 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
70 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
71 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
72 "Whether to print all messages or just errors.", NULL },
73 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
74 "Name of the current instance (defaults to Xorg window id)", "NAME" },
75 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
76 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
77 { NULL, 0, 0, 0, NULL, NULL, NULL }
80 /* associate command names to their properties */
81 typedef const struct {
87 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
89 /* an abbreviation to help keep the table's width humane */
90 #define PTR(var, t, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .func = fun }
95 } var_name_to_ptr[] = {
96 /* variable name pointer to variable in code type callback function */
97 /* --------------------------------------------------------------------------------------- */
98 { "uri", PTR(uzbl.state.uri, STR, cmd_load_uri)},
99 { "mode", PTR(uzbl.behave.mode, INT, NULL)},
100 { "inject_html", PTR(uzbl.behave.inject_html, STR, cmd_inject_html)},
101 { "base_url", PTR(uzbl.behave.base_url, STR, NULL)},
102 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, NULL)},
103 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, NULL)},
104 { "status_message", PTR(uzbl.gui.sbar.msg, STR, update_title)},
105 { "show_status", PTR(uzbl.behave.show_status, INT, cmd_set_status)},
106 { "status_top", PTR(uzbl.behave.status_top, INT, move_statusbar)},
107 { "status_format", PTR(uzbl.behave.status_format, STR, update_title)},
108 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, update_title)},
109 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, update_title)},
110 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, update_title)},
111 { "status_background", PTR(uzbl.behave.status_background, STR, update_title)},
112 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, update_title)},
113 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, update_title)},
114 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, NULL)},
115 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, cmd_always_insert_mode)},
116 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, NULL)},
117 { "modkey", PTR(uzbl.behave.modkey, STR, cmd_modkey)},
118 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, NULL)},
119 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, NULL)},
120 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, NULL)},
121 { "history_handler", PTR(uzbl.behave.history_handler, STR, NULL)},
122 { "download_handler", PTR(uzbl.behave.download_handler, STR, NULL)},
123 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, cmd_cookie_handler)},
124 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, cmd_fifo_dir)},
125 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, cmd_socket_dir)},
126 { "http_debug", PTR(uzbl.behave.http_debug, INT, cmd_http_debug)},
127 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, NULL)},
128 { "proxy_url", PTR(uzbl.net.proxy_url, STR, set_proxy_url)},
129 { "max_conns", PTR(uzbl.net.max_conns, INT, cmd_max_conns)},
130 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, cmd_max_conns_host)},
131 { "useragent", PTR(uzbl.net.useragent, STR, cmd_useragent)},
132 /* exported WebKitWebSettings properties */
133 { "font_size", PTR(uzbl.behave.font_size, INT, cmd_font_size)},
134 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, cmd_font_size)},
135 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, cmd_minimum_font_size)},
136 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT, cmd_zoom_level)},
137 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, cmd_disable_plugins)},
138 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, cmd_disable_scripts)},
139 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, cmd_autoload_img)},
140 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, cmd_autoshrink_img)},
141 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, cmd_enable_spellcheck)},
142 { "enable_private", PTR(uzbl.behave.enable_private, INT, cmd_enable_private)},
143 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, cmd_print_bg)},
144 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, cmd_style_uri)},
145 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, cmd_resizable_txt)},
146 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, cmd_default_encoding)},
147 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, cmd_enforce_96dpi)},
148 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, cmd_caret_browsing)},
150 { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}}
151 }, *n2v_p = var_name_to_ptr;
157 { "SHIFT", GDK_SHIFT_MASK }, // shift
158 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
159 { "CONTROL", GDK_CONTROL_MASK }, // control
160 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
161 { "MOD2", GDK_MOD2_MASK }, // 5th mod
162 { "MOD3", GDK_MOD3_MASK }, // 6th mod
163 { "MOD4", GDK_MOD4_MASK }, // 7th mod
164 { "MOD5", GDK_MOD5_MASK }, // 8th mod
165 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
166 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
167 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
168 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
169 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
170 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
171 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
172 { "META", GDK_META_MASK }, // meta (since 2.10)
177 /* construct a hash from the var_name_to_ptr array for quick access */
179 make_var_to_name_hash() {
180 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
182 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
188 /* --- UTILITY FUNCTIONS --- */
194 snprintf(tmp, sizeof(tmp), "%i", val);
195 return g_strdup(tmp);
199 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
202 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
205 str_replace (const char* search, const char* replace, const char* string) {
209 buf = g_strsplit (string, search, -1);
210 ret = g_strjoinv (replace, buf);
211 g_strfreev(buf); // somebody said this segfaults
217 read_file_by_line (gchar *path) {
218 GIOChannel *chan = NULL;
219 gchar *readbuf = NULL;
221 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
224 chan = g_io_channel_new_file(path, "r", NULL);
227 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
228 const gchar* val = g_strdup (readbuf);
229 g_array_append_val (lines, val);
234 g_io_channel_unref (chan);
236 fprintf(stderr, "File '%s' not be read.\n", path);
243 gchar* parseenv (char* string) {
244 extern char** environ;
245 gchar* tmpstr = NULL;
249 while (environ[i] != NULL) {
250 gchar** env = g_strsplit (environ[i], "=", 2);
251 gchar* envname = g_strconcat ("$", env[0], NULL);
253 if (g_strrstr (string, envname) != NULL) {
254 tmpstr = g_strdup(string);
256 string = str_replace(envname, env[1], tmpstr);
261 g_strfreev (env); // somebody said this breaks uzbl
269 setup_signal(int signr, sigfunc *shandler) {
270 struct sigaction nh, oh;
272 nh.sa_handler = shandler;
273 sigemptyset(&nh.sa_mask);
276 if(sigaction(signr, &nh, &oh) < 0)
284 if (uzbl.behave.fifo_dir)
285 unlink (uzbl.comm.fifo_path);
286 if (uzbl.behave.socket_dir)
287 unlink (uzbl.comm.socket_path);
289 g_free(uzbl.state.executable_path);
290 g_string_free(uzbl.state.keycmd, TRUE);
291 g_hash_table_destroy(uzbl.bindings);
292 g_hash_table_destroy(uzbl.behave.commands);
295 /* used for html_mode_timeout
296 * be sure to extend this function to use
297 * more timers if needed in other places
300 set_timeout(int seconds) {
302 memset(&t, 0, sizeof t);
304 t.it_value.tv_sec = seconds;
305 t.it_value.tv_usec = 0;
306 setitimer(ITIMER_REAL, &t, NULL);
309 /* --- SIGNAL HANDLER --- */
312 catch_sigterm(int s) {
318 catch_sigint(int s) {
328 set_var_value("mode", "0");
333 /* --- CALLBACKS --- */
336 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
339 (void) navigation_action;
340 (void) policy_decision;
342 const gchar* uri = webkit_network_request_get_uri (request);
343 if (uzbl.state.verbose)
344 printf("New window requested -> %s \n", uri);
345 new_window_load_uri(uri);
350 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
354 if (uzbl.state.selected_url != NULL) {
355 if (uzbl.state.verbose)
356 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
357 new_window_load_uri(uzbl.state.selected_url);
359 if (uzbl.state.verbose)
360 printf("New web view -> %s\n","Nothing to open, exiting");
366 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
369 if (uzbl.behave.download_handler) {
370 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
371 if (uzbl.state.verbose)
372 printf("Download -> %s\n",uri);
373 /* if urls not escaped, we may have to escape and quote uri before this call */
374 run_handler(uzbl.behave.download_handler, uri);
379 /* scroll a bar in a given direction */
381 scroll (GtkAdjustment* bar, GArray *argv) {
385 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
386 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
387 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
390 static void scroll_begin(WebKitWebView* page, GArray *argv) {
391 (void) page; (void) argv;
392 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
395 static void scroll_end(WebKitWebView* page, GArray *argv) {
396 (void) page; (void) argv;
397 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
398 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
401 static void scroll_vert(WebKitWebView* page, GArray *argv) {
403 scroll(uzbl.gui.bar_v, argv);
406 static void scroll_horz(WebKitWebView* page, GArray *argv) {
408 scroll(uzbl.gui.bar_h, argv);
413 if (!uzbl.behave.show_status) {
414 gtk_widget_hide(uzbl.gui.mainbar);
416 gtk_widget_show(uzbl.gui.mainbar);
422 toggle_status_cb (WebKitWebView* page, GArray *argv) {
426 if (uzbl.behave.show_status) {
427 gtk_widget_hide(uzbl.gui.mainbar);
429 gtk_widget_show(uzbl.gui.mainbar);
431 uzbl.behave.show_status = !uzbl.behave.show_status;
436 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
440 //Set selected_url state variable
441 g_free(uzbl.state.selected_url);
442 uzbl.state.selected_url = NULL;
444 uzbl.state.selected_url = g_strdup(link);
450 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
454 if (uzbl.gui.main_title)
455 g_free (uzbl.gui.main_title);
456 uzbl.gui.main_title = g_strdup (title);
461 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
464 uzbl.gui.sbar.load_progress = progress;
469 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
473 if (uzbl.behave.load_finish_handler)
474 run_handler(uzbl.behave.load_finish_handler, "");
478 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
482 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
483 if (uzbl.behave.load_start_handler)
484 run_handler(uzbl.behave.load_start_handler, "");
488 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
491 g_free (uzbl.state.uri);
492 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
493 uzbl.state.uri = g_string_free (newuri, FALSE);
494 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
495 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
498 if (uzbl.behave.load_commit_handler)
499 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
503 destroy_cb (GtkWidget* widget, gpointer data) {
511 if (uzbl.behave.history_handler) {
513 struct tm * timeinfo;
516 timeinfo = localtime ( &rawtime );
517 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
518 run_handler(uzbl.behave.history_handler, date);
523 /* VIEW funcs (little webkit wrappers) */
524 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
526 VIEWFUNC(reload_bypass_cache)
527 VIEWFUNC(stop_loading)
534 /* -- command to callback/function map for things we cannot attach to any signals */
535 static struct {char *name; Command command[2];} cmdlist[] =
536 { /* key function no_split */
537 { "back", {view_go_back, 0} },
538 { "forward", {view_go_forward, 0} },
539 { "scroll_vert", {scroll_vert, 0} },
540 { "scroll_horz", {scroll_horz, 0} },
541 { "scroll_begin", {scroll_begin, 0} },
542 { "scroll_end", {scroll_end, 0} },
543 { "reload", {view_reload, 0}, },
544 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
545 { "stop", {view_stop_loading, 0}, },
546 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
547 { "zoom_out", {view_zoom_out, 0}, },
548 { "uri", {load_uri, NOSPLIT} },
549 { "js", {run_js, NOSPLIT} },
550 { "script", {run_external_js, 0} },
551 { "toggle_status", {toggle_status_cb, 0} },
552 { "spawn", {spawn, 0} },
553 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
554 { "sh", {spawn_sh, 0} },
555 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
556 { "exit", {close_uzbl, 0} },
557 { "search", {search_forward_text, NOSPLIT} },
558 { "search_reverse", {search_reverse_text, NOSPLIT} },
559 { "dehilight", {dehilight, 0} },
560 { "toggle_insert_mode", {toggle_insert_mode, 0} },
561 { "runcmd", {runcmd, NOSPLIT} },
562 { "set", {set_var, NOSPLIT} }
569 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
571 for (i = 0; i < LENGTH(cmdlist); i++)
572 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
575 /* -- CORE FUNCTIONS -- */
578 free_action(gpointer act) {
579 Action *action = (Action*)act;
580 g_free(action->name);
582 g_free(action->param);
587 new_action(const gchar *name, const gchar *param) {
588 Action *action = g_new(Action, 1);
590 action->name = g_strdup(name);
592 action->param = g_strdup(param);
594 action->param = NULL;
600 file_exists (const char * filename) {
601 return (access(filename, F_OK) == 0);
605 set_var(WebKitWebView *page, GArray *argv) {
609 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
610 parse_cmd_line(ctl_line);
615 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
618 if (argv_idx(argv, 0)) {
619 if (strcmp (argv_idx(argv, 0), "0") == 0) {
620 uzbl.behave.insert_mode = FALSE;
622 uzbl.behave.insert_mode = TRUE;
625 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
632 load_uri (WebKitWebView *web_view, GArray *argv) {
633 if (argv_idx(argv, 0)) {
634 GString* newuri = g_string_new (argv_idx(argv, 0));
635 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
636 g_string_prepend (newuri, "http://");
637 /* if we do handle cookies, ask our handler for them */
638 webkit_web_view_load_uri (web_view, newuri->str);
639 g_string_free (newuri, TRUE);
644 run_js (WebKitWebView * web_view, GArray *argv) {
645 if (argv_idx(argv, 0))
646 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
650 run_external_js (WebKitWebView * web_view, GArray *argv) {
651 if (argv_idx(argv, 0)) {
652 GArray* lines = read_file_by_line (argv_idx (argv, 0));
657 while ((line = g_array_index(lines, gchar*, i))) {
659 js = g_strdup (line);
661 gchar* newjs = g_strconcat (js, line, NULL);
668 if (uzbl.state.verbose)
669 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
671 if (argv_idx (argv, 1)) {
672 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
676 webkit_web_view_execute_script (web_view, js);
678 g_array_free (lines, TRUE);
683 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
684 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
685 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
686 webkit_web_view_unmark_text_matches (page);
687 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
688 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
692 if (uzbl.state.searchtx) {
693 if (uzbl.state.verbose)
694 printf ("Searching: %s\n", uzbl.state.searchtx);
695 webkit_web_view_set_highlight_text_matches (page, TRUE);
696 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
701 search_forward_text (WebKitWebView *page, GArray *argv) {
702 search_text(page, argv, TRUE);
706 search_reverse_text (WebKitWebView *page, GArray *argv) {
707 search_text(page, argv, FALSE);
711 dehilight (WebKitWebView *page, GArray *argv) {
713 webkit_web_view_set_highlight_text_matches (page, FALSE);
718 new_window_load_uri (const gchar * uri) {
719 GString* to_execute = g_string_new ("");
720 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
722 for (i = 0; entries[i].long_name != NULL; i++) {
723 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
724 gchar** str = (gchar**)entries[i].arg_data;
726 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
730 if (uzbl.state.verbose)
731 printf("\n%s\n", to_execute->str);
732 g_spawn_command_line_async (to_execute->str, NULL);
733 g_string_free (to_execute, TRUE);
737 close_uzbl (WebKitWebView *page, GArray *argv) {
743 /* --Statusbar functions-- */
745 build_progressbar_ascii(int percent) {
746 int width=uzbl.gui.sbar.progress_w;
749 GString *bar = g_string_new("");
751 l = (double)percent*((double)width/100.);
752 l = (int)(l+.5)>=(int)l ? l+.5 : l;
754 for(i=0; i<(int)l; i++)
755 g_string_append(bar, uzbl.gui.sbar.progress_s);
758 g_string_append(bar, uzbl.gui.sbar.progress_u);
760 return g_string_free(bar, FALSE);
765 const GScannerConfig scan_config = {
768 ) /* cset_skip_characters */,
773 ) /* cset_identifier_first */,
780 ) /* cset_identifier_nth */,
781 ( "" ) /* cpair_comment_single */,
783 TRUE /* case_sensitive */,
785 FALSE /* skip_comment_multi */,
786 FALSE /* skip_comment_single */,
787 FALSE /* scan_comment_multi */,
788 TRUE /* scan_identifier */,
789 TRUE /* scan_identifier_1char */,
790 FALSE /* scan_identifier_NULL */,
791 TRUE /* scan_symbols */,
792 FALSE /* scan_binary */,
793 FALSE /* scan_octal */,
794 FALSE /* scan_float */,
795 FALSE /* scan_hex */,
796 FALSE /* scan_hex_dollar */,
797 FALSE /* scan_string_sq */,
798 FALSE /* scan_string_dq */,
799 TRUE /* numbers_2_int */,
800 FALSE /* int_2_float */,
801 FALSE /* identifier_2_string */,
802 FALSE /* char_2_token */,
803 FALSE /* symbol_2_token */,
804 TRUE /* scope_0_fallback */,
809 uzbl.scan = g_scanner_new(&scan_config);
810 while(symp->symbol_name) {
811 g_scanner_scope_add_symbol(uzbl.scan, 0,
813 GINT_TO_POINTER(symp->symbol_token));
819 expand_template(const char *template, gboolean escape_markup) {
820 if(!template) return NULL;
822 GTokenType token = G_TOKEN_NONE;
823 GString *ret = g_string_new("");
827 g_scanner_input_text(uzbl.scan, template, strlen(template));
828 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
829 token = g_scanner_get_next_token(uzbl.scan);
831 if(token == G_TOKEN_SYMBOL) {
832 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
836 buf = uzbl.state.uri?
837 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
838 g_string_append(ret, buf);
842 g_string_append(ret, uzbl.state.uri?
843 uzbl.state.uri:g_strdup(""));
846 buf = itos(uzbl.gui.sbar.load_progress);
847 g_string_append(ret, buf);
850 case SYM_LOADPRGSBAR:
851 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
852 g_string_append(ret, buf);
857 buf = uzbl.gui.main_title?
858 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
859 g_string_append(ret, buf);
863 g_string_append(ret, uzbl.gui.main_title?
864 uzbl.gui.main_title:g_strdup(""));
866 case SYM_SELECTED_URI:
868 buf = uzbl.state.selected_url?
869 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
870 g_string_append(ret, buf);
874 g_string_append(ret, uzbl.state.selected_url?
875 uzbl.state.selected_url:g_strdup(""));
878 buf = itos(uzbl.xwin);
880 uzbl.state.instance_name?uzbl.state.instance_name:buf);
885 buf = uzbl.state.keycmd->str?
886 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
887 g_string_append(ret, buf);
891 g_string_append(ret, uzbl.state.keycmd->str?
892 uzbl.state.keycmd->str:g_strdup(""));
896 uzbl.behave.insert_mode?"[I]":"[C]");
900 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
904 buf = itos(WEBKIT_MAJOR_VERSION);
905 g_string_append(ret, buf);
909 buf = itos(WEBKIT_MINOR_VERSION);
910 g_string_append(ret, buf);
914 buf = itos(WEBKIT_MICRO_VERSION);
915 g_string_append(ret, buf);
919 g_string_append(ret, uzbl.state.unameinfo.sysname);
922 g_string_append(ret, uzbl.state.unameinfo.nodename);
925 g_string_append(ret, uzbl.state.unameinfo.release);
928 g_string_append(ret, uzbl.state.unameinfo.version);
931 g_string_append(ret, uzbl.state.unameinfo.machine);
934 g_string_append(ret, ARCH);
938 g_string_append(ret, uzbl.state.unameinfo.domainname);
942 g_string_append(ret, COMMIT);
948 else if(token == G_TOKEN_INT) {
949 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
950 g_string_append(ret, buf);
953 else if(token == G_TOKEN_IDENTIFIER) {
954 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
956 else if(token == G_TOKEN_CHAR) {
957 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
961 return g_string_free(ret, FALSE);
963 /* --End Statusbar functions-- */
966 sharg_append(GArray *a, const gchar *str) {
967 const gchar *s = (str ? str : "");
968 g_array_append_val(a, s);
971 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
973 run_command (const gchar *command, const guint npre, const gchar **args,
974 const gboolean sync, char **stdout) {
975 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
978 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
979 gchar *pid = itos(getpid());
980 gchar *xwin = itos(uzbl.xwin);
982 sharg_append(a, command);
983 for (i = 0; i < npre; i++) /* add n args before the default vars */
984 sharg_append(a, args[i]);
985 sharg_append(a, uzbl.state.config_file);
986 sharg_append(a, pid);
987 sharg_append(a, xwin);
988 sharg_append(a, uzbl.comm.fifo_path);
989 sharg_append(a, uzbl.comm.socket_path);
990 sharg_append(a, uzbl.state.uri);
991 sharg_append(a, uzbl.gui.main_title);
993 for (i = npre; i < g_strv_length((gchar**)args); i++)
994 sharg_append(a, args[i]);
998 if (*stdout) *stdout = strfree(*stdout);
1000 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1001 NULL, NULL, stdout, NULL, NULL, &err);
1002 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1003 NULL, NULL, NULL, &err);
1005 if (uzbl.state.verbose) {
1006 GString *s = g_string_new("spawned:");
1007 for (i = 0; i < (a->len); i++) {
1008 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1009 g_string_append_printf(s, " %s", qarg);
1012 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1013 printf("%s\n", s->str);
1014 g_string_free(s, TRUE);
1017 g_printerr("error on run_command: %s\n", err->message);
1022 g_array_free (a, TRUE);
1027 split_quoted(const gchar* src, const gboolean unquote) {
1028 /* split on unquoted space, return array of strings;
1029 remove a layer of quotes and backslashes if unquote */
1030 if (!src) return NULL;
1032 gboolean dq = FALSE;
1033 gboolean sq = FALSE;
1034 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1035 GString *s = g_string_new ("");
1039 for (p = src; *p != '\0'; p++) {
1040 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1041 else if (*p == '\\') { g_string_append_c(s, *p++);
1042 g_string_append_c(s, *p); }
1043 else if ((*p == '"') && unquote && !sq) dq = !dq;
1044 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1046 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1047 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1049 else if ((*p == ' ') && !dq && !sq) {
1050 dup = g_strdup(s->str);
1051 g_array_append_val(a, dup);
1052 g_string_truncate(s, 0);
1053 } else g_string_append_c(s, *p);
1055 dup = g_strdup(s->str);
1056 g_array_append_val(a, dup);
1057 ret = (gchar**)a->data;
1058 g_array_free (a, FALSE);
1059 g_string_free (s, TRUE);
1064 spawn(WebKitWebView *web_view, GArray *argv) {
1066 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1067 if (argv_idx(argv, 0))
1068 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1072 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1075 if (argv_idx(argv, 0))
1076 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1077 TRUE, &uzbl.comm.sync_stdout);
1081 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1083 if (!uzbl.behave.shell_cmd) {
1084 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1089 gchar *spacer = g_strdup("");
1090 g_array_insert_val(argv, 1, spacer);
1091 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1093 for (i = 1; i < g_strv_length(cmd); i++)
1094 g_array_prepend_val(argv, cmd[i]);
1096 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1102 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1104 if (!uzbl.behave.shell_cmd) {
1105 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1110 gchar *spacer = g_strdup("");
1111 g_array_insert_val(argv, 1, spacer);
1112 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1114 for (i = 1; i < g_strv_length(cmd); i++)
1115 g_array_prepend_val(argv, cmd[i]);
1117 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1118 TRUE, &uzbl.comm.sync_stdout);
1124 parse_command(const char *cmd, const char *param) {
1127 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1130 gchar **par = split_quoted(param, TRUE);
1131 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1133 if (c[1] == NOSPLIT) { /* don't split */
1134 sharg_append(a, param);
1136 for (i = 0; i < g_strv_length(par); i++)
1137 sharg_append(a, par[i]);
1139 c[0](uzbl.gui.web_view, a);
1141 g_array_free (a, TRUE);
1144 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1147 /* command parser */
1150 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1151 G_REGEX_OPTIMIZE, 0, NULL);
1152 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1153 G_REGEX_OPTIMIZE, 0, NULL);
1154 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1155 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1156 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1157 G_REGEX_OPTIMIZE, 0, NULL);
1158 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1159 G_REGEX_OPTIMIZE, 0, NULL);
1163 get_var_value(gchar *name) {
1166 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1167 if(c->type == TYPE_STR)
1168 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1169 else if(c->type == TYPE_INT)
1170 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1179 if(*uzbl.net.proxy_url == ' '
1180 || uzbl.net.proxy_url == NULL) {
1181 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1182 (GType) SOUP_SESSION_PROXY_URI);
1185 suri = soup_uri_new(uzbl.net.proxy_url);
1186 g_object_set(G_OBJECT(uzbl.net.soup_session),
1187 SOUP_SESSION_PROXY_URI,
1189 soup_uri_free(suri);
1196 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1197 g_array_append_val (a, uzbl.state.uri);
1198 load_uri(uzbl.gui.web_view, a);
1199 g_array_free (a, TRUE);
1203 cmd_always_insert_mode() {
1204 uzbl.behave.insert_mode =
1205 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1211 g_object_set(G_OBJECT(uzbl.net.soup_session),
1212 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1216 cmd_max_conns_host() {
1217 g_object_set(G_OBJECT(uzbl.net.soup_session),
1218 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1223 soup_session_remove_feature
1224 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1225 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1226 /*g_free(uzbl.net.soup_logger);*/
1228 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1229 soup_session_add_feature(uzbl.net.soup_session,
1230 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1233 static WebKitWebSettings*
1235 return webkit_web_view_get_settings(uzbl.gui.web_view);
1240 WebKitWebSettings *ws = view_settings();
1241 if (uzbl.behave.font_size > 0) {
1242 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1245 if (uzbl.behave.monospace_size > 0) {
1246 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1247 uzbl.behave.monospace_size, NULL);
1249 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1250 uzbl.behave.font_size, NULL);
1256 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1260 cmd_disable_plugins() {
1261 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1262 !uzbl.behave.disable_plugins, NULL);
1266 cmd_disable_scripts() {
1267 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1268 !uzbl.behave.disable_plugins, NULL);
1272 cmd_minimum_font_size() {
1273 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1274 uzbl.behave.minimum_font_size, NULL);
1277 cmd_autoload_img() {
1278 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1279 uzbl.behave.autoload_img, NULL);
1284 cmd_autoshrink_img() {
1285 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1286 uzbl.behave.autoshrink_img, NULL);
1291 cmd_enable_spellcheck() {
1292 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1293 uzbl.behave.enable_spellcheck, NULL);
1297 cmd_enable_private() {
1298 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1299 uzbl.behave.enable_private, NULL);
1304 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1305 uzbl.behave.print_bg, NULL);
1310 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1311 uzbl.behave.style_uri, NULL);
1315 cmd_resizable_txt() {
1316 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1317 uzbl.behave.resizable_txt, NULL);
1321 cmd_default_encoding() {
1322 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1323 uzbl.behave.default_encoding, NULL);
1327 cmd_enforce_96dpi() {
1328 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1329 uzbl.behave.enforce_96dpi, NULL);
1333 cmd_caret_browsing() {
1334 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1335 uzbl.behave.caret_browsing, NULL);
1339 cmd_cookie_handler() {
1340 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1341 if ((g_strcmp0(split[0], "sh") == 0) ||
1342 (g_strcmp0(split[0], "spawn") == 0)) {
1343 g_free (uzbl.behave.cookie_handler);
1344 uzbl.behave.cookie_handler =
1345 g_strdup_printf("sync_%s %s", split[0], split[1]);
1352 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1357 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1362 if(uzbl.behave.inject_html) {
1363 webkit_web_view_load_html_string (uzbl.gui.web_view,
1364 uzbl.behave.inject_html, NULL);
1373 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1374 uzbl.behave.modmask = 0;
1376 if(uzbl.behave.modkey)
1377 g_free(uzbl.behave.modkey);
1378 uzbl.behave.modkey = buf;
1380 for (i = 0; modkeys[i].key != NULL; i++) {
1381 if (g_strrstr(buf, modkeys[i].key))
1382 uzbl.behave.modmask |= modkeys[i].mask;
1388 if (*uzbl.net.useragent == ' ') {
1389 g_free (uzbl.net.useragent);
1390 uzbl.net.useragent = NULL;
1392 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1394 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1395 g_free(uzbl.net.useragent);
1396 uzbl.net.useragent = ua;
1402 gtk_widget_ref(uzbl.gui.scrolled_win);
1403 gtk_widget_ref(uzbl.gui.mainbar);
1404 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1405 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1407 if(uzbl.behave.status_top) {
1408 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1409 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1412 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1413 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1415 gtk_widget_unref(uzbl.gui.scrolled_win);
1416 gtk_widget_unref(uzbl.gui.mainbar);
1417 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1422 set_var_value(gchar *name, gchar *val) {
1423 uzbl_cmdprop *c = NULL;
1426 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1427 /* check for the variable type */
1428 if (c->type == TYPE_STR) {
1430 *c->ptr = g_strdup(val);
1431 } else if (c->type == TYPE_INT) {
1432 int *ip = (int *)c->ptr;
1433 *ip = (int)strtoul(val, &endp, 10);
1434 } else if (c->type == TYPE_FLOAT) {
1435 float *fp = (float *)c->ptr;
1436 *fp = strtof(val, &endp);
1439 /* invoke a command specific function */
1440 if(c->func) c->func();
1446 runcmd(WebKitWebView* page, GArray *argv) {
1448 parse_cmd_line(argv_idx(argv, 0));
1453 Behaviour *b = &uzbl.behave;
1455 if(b->html_buffer->str) {
1456 webkit_web_view_load_html_string (uzbl.gui.web_view,
1457 b->html_buffer->str, b->base_url);
1458 g_string_free(b->html_buffer, TRUE);
1459 b->html_buffer = g_string_new("");
1463 enum {M_CMD, M_HTML};
1465 parse_cmd_line(const char *ctl_line) {
1466 gchar **tokens = NULL;
1467 Behaviour *b = &uzbl.behave;
1469 if(b->mode == M_HTML) {
1471 if(!strncmp(b->html_endmarker, ctl_line, strlen(b->html_endmarker))) {
1473 set_var_value("mode", "0");
1478 /* set an alarm to kill us after the timeout */
1479 set_timeout(b->html_timeout);
1480 g_string_append(b->html_buffer, ctl_line);
1485 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1486 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1487 if(tokens[0][0] == 0) {
1488 gchar* value = parseenv(g_strdup(tokens[2]));
1489 set_var_value(tokens[1], value);
1493 printf("Error in command: %s\n", tokens[0]);
1496 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1497 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1498 if(tokens[0][0] == 0) {
1499 get_var_value(tokens[1]);
1502 printf("Error in command: %s\n", tokens[0]);
1505 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1506 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1507 if(tokens[0][0] == 0) {
1508 gchar* value = parseenv(g_strdup(tokens[2]));
1509 add_binding(tokens[1], value);
1513 printf("Error in command: %s\n", tokens[0]);
1516 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1517 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1518 if(tokens[0][0] == 0) {
1519 parse_command(tokens[1], tokens[2]);
1522 printf("Error in command: %s\n", tokens[0]);
1524 /* KEYCMD command */
1525 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1526 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1527 if(tokens[0][0] == 0) {
1528 /* should incremental commands want each individual "keystroke"
1529 sent in a loop or the whole string in one go like now? */
1530 g_string_assign(uzbl.state.keycmd, tokens[1]);
1532 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1538 else if( (ctl_line[0] == '#')
1539 || (ctl_line[0] == ' ')
1540 || (ctl_line[0] == '\n'))
1541 ; /* ignore these lines */
1543 printf("Command not understood (%s)\n", ctl_line);
1553 build_stream_name(int type, const gchar* dir) {
1555 State *s = &uzbl.state;
1558 xwin_str = itos((int)uzbl.xwin);
1560 str = g_strdup_printf
1561 ("%s/uzbl_fifo_%s", dir,
1562 s->instance_name ? s->instance_name : xwin_str);
1563 } else if (type == SOCKET) {
1564 str = g_strdup_printf
1565 ("%s/uzbl_socket_%s", dir,
1566 s->instance_name ? s->instance_name : xwin_str );
1573 control_fifo(GIOChannel *gio, GIOCondition condition) {
1574 if (uzbl.state.verbose)
1575 printf("triggered\n");
1580 if (condition & G_IO_HUP)
1581 g_error ("Fifo: Read end of pipe died!\n");
1584 g_error ("Fifo: GIOChannel broke\n");
1586 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1587 if (ret == G_IO_STATUS_ERROR) {
1588 g_error ("Fifo: Error reading: %s\n", err->message);
1592 parse_cmd_line(ctl_line);
1599 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1600 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1601 if (unlink(uzbl.comm.fifo_path) == -1)
1602 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1603 g_free(uzbl.comm.fifo_path);
1604 uzbl.comm.fifo_path = NULL;
1607 if (*dir == ' ') { /* space unsets the variable */
1612 GIOChannel *chan = NULL;
1613 GError *error = NULL;
1614 gchar *path = build_stream_name(FIFO, dir);
1616 if (!file_exists(path)) {
1617 if (mkfifo (path, 0666) == 0) {
1618 // 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.
1619 chan = g_io_channel_new_file(path, "r+", &error);
1621 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1622 if (uzbl.state.verbose)
1623 printf ("init_fifo: created successfully as %s\n", path);
1624 uzbl.comm.fifo_path = path;
1626 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1627 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1628 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1629 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1631 /* if we got this far, there was an error; cleanup */
1632 if (error) g_error_free (error);
1639 control_stdin(GIOChannel *gio, GIOCondition condition) {
1641 gchar *ctl_line = NULL;
1644 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1645 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1648 parse_cmd_line(ctl_line);
1656 GIOChannel *chan = NULL;
1657 GError *error = NULL;
1659 chan = g_io_channel_unix_new(fileno(stdin));
1661 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1662 g_error ("Stdin: could not add watch\n");
1664 if (uzbl.state.verbose)
1665 printf ("Stdin: watch added successfully\n");
1668 g_error ("Stdin: Error while opening: %s\n", error->message);
1670 if (error) g_error_free (error);
1674 control_socket(GIOChannel *chan) {
1675 struct sockaddr_un remote;
1676 char buffer[512], *ctl_line;
1678 int sock, clientsock, n, done;
1681 sock = g_io_channel_unix_get_fd(chan);
1683 memset (buffer, 0, sizeof (buffer));
1685 t = sizeof (remote);
1686 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1690 memset (temp, 0, sizeof (temp));
1691 n = recv (clientsock, temp, 128, 0);
1693 buffer[strlen (buffer)] = '\0';
1697 strcat (buffer, temp);
1700 if (strcmp (buffer, "\n") < 0) {
1701 buffer[strlen (buffer) - 1] = '\0';
1703 buffer[strlen (buffer)] = '\0';
1706 ctl_line = g_strdup(buffer);
1707 parse_cmd_line (ctl_line);
1710 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1711 GError *error = NULL;
1714 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1715 if (ret == G_IO_STATUS_ERROR)
1716 g_error ("Error reading: %s\n", error->message);
1718 printf("Got line %s (%u bytes) \n",ctl_line, len);
1720 parse_line(ctl_line);
1728 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1729 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1730 if (unlink(uzbl.comm.socket_path) == -1)
1731 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1732 g_free(uzbl.comm.socket_path);
1733 uzbl.comm.socket_path = NULL;
1741 GIOChannel *chan = NULL;
1743 struct sockaddr_un local;
1744 gchar *path = build_stream_name(SOCKET, dir);
1746 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1748 local.sun_family = AF_UNIX;
1749 strcpy (local.sun_path, path);
1750 unlink (local.sun_path);
1752 len = strlen (local.sun_path) + sizeof (local.sun_family);
1753 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1754 if (uzbl.state.verbose)
1755 printf ("init_socket: opened in %s\n", path);
1758 if( (chan = g_io_channel_unix_new(sock)) ) {
1759 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1760 uzbl.comm.socket_path = path;
1763 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1765 /* if we got this far, there was an error; cleanup */
1772 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1773 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1775 // this function may be called very early when the templates are not set (yet), hence the checks
1777 update_title (void) {
1778 Behaviour *b = &uzbl.behave;
1781 if (b->show_status) {
1782 if (b->title_format_short) {
1783 parsed = expand_template(b->title_format_short, FALSE);
1784 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1787 if (b->status_format) {
1788 parsed = expand_template(b->status_format, TRUE);
1789 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1792 if (b->status_background) {
1794 gdk_color_parse (b->status_background, &color);
1795 //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)
1796 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1799 if (b->title_format_long) {
1800 parsed = expand_template(b->title_format_long, FALSE);
1801 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1808 key_press_cb (GtkWidget* window, GdkEventKey* event)
1810 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1814 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1815 || 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)
1818 /* turn off insert mode (if always_insert_mode is not used) */
1819 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1820 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1825 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1828 if (event->keyval == GDK_Escape) {
1829 g_string_truncate(uzbl.state.keycmd, 0);
1831 dehilight(uzbl.gui.web_view, NULL);
1835 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1836 if (event->keyval == GDK_Insert) {
1838 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1839 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1841 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1844 g_string_append (uzbl.state.keycmd, str);
1851 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1852 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1856 gboolean key_ret = FALSE;
1857 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1859 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1861 run_keycmd(key_ret);
1863 if (key_ret) return (!uzbl.behave.insert_mode);
1868 run_keycmd(const gboolean key_ret) {
1869 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1871 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1872 g_string_truncate(uzbl.state.keycmd, 0);
1873 parse_command(act->name, act->param);
1877 /* try if it's an incremental keycmd or one that takes args, and run it */
1878 GString* short_keys = g_string_new ("");
1879 GString* short_keys_inc = g_string_new ("");
1881 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1882 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1883 g_string_assign(short_keys_inc, short_keys->str);
1884 g_string_append_c(short_keys, '_');
1885 g_string_append_c(short_keys_inc, '*');
1887 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1888 /* run normal cmds only if return was pressed */
1889 exec_paramcmd(act, i);
1890 g_string_truncate(uzbl.state.keycmd, 0);
1892 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1893 if (key_ret) /* just quit the incremental command on return */
1894 g_string_truncate(uzbl.state.keycmd, 0);
1895 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1899 g_string_truncate(short_keys, short_keys->len - 1);
1901 g_string_free (short_keys, TRUE);
1902 g_string_free (short_keys_inc, TRUE);
1906 exec_paramcmd(const Action *act, const guint i) {
1907 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1908 GString *actionname = g_string_new ("");
1909 GString *actionparam = g_string_new ("");
1910 g_string_erase (parampart, 0, i+1);
1912 g_string_printf (actionname, act->name, parampart->str);
1914 g_string_printf (actionparam, act->param, parampart->str);
1915 parse_command(actionname->str, actionparam->str);
1916 g_string_free(actionname, TRUE);
1917 g_string_free(actionparam, TRUE);
1918 g_string_free(parampart, TRUE);
1926 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1927 //main_window_ref = g_object_ref(scrolled_window);
1928 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
1930 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1931 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1933 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1934 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1935 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1936 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1937 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1938 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1939 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1940 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1941 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1942 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1944 return scrolled_window;
1951 g->mainbar = gtk_hbox_new (FALSE, 0);
1953 /* keep a reference to the bar so we can re-pack it at runtime*/
1954 //sbar_ref = g_object_ref(g->mainbar);
1956 g->mainbar_label = gtk_label_new ("");
1957 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1958 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1959 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1960 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1961 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1966 GtkWidget* create_window () {
1967 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1968 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1969 gtk_widget_set_name (window, "Uzbl browser");
1970 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1971 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1977 run_handler (const gchar *act, const gchar *args) {
1978 char **parts = g_strsplit(act, " ", 2);
1980 else if ((g_strcmp0(parts[0], "spawn") == 0)
1981 || (g_strcmp0(parts[0], "sh") == 0)
1982 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1983 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1985 GString *a = g_string_new ("");
1987 spawnparts = split_quoted(parts[1], FALSE);
1988 g_string_append_printf(a, "%s", spawnparts[0]);
1989 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1991 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1992 g_string_append_printf(a, " %s", spawnparts[i]);
1993 parse_command(parts[0], a->str);
1994 g_string_free (a, TRUE);
1995 g_strfreev (spawnparts);
1997 parse_command(parts[0], parts[1]);
2002 add_binding (const gchar *key, const gchar *act) {
2003 char **parts = g_strsplit(act, " ", 2);
2010 if (uzbl.state.verbose)
2011 printf ("Binding %-10s : %s\n", key, act);
2012 action = new_action(parts[0], parts[1]);
2014 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2019 get_xdg_var (XDG_Var xdg) {
2020 const gchar* actual_value = getenv (xdg.environmental);
2021 const gchar* home = getenv ("HOME");
2023 gchar* return_value = str_replace ("~", home, actual_value);
2025 if (! actual_value || strcmp (actual_value, "") == 0) {
2026 if (xdg.default_value) {
2027 return_value = str_replace ("~", home, xdg.default_value);
2029 return_value = NULL;
2032 return return_value;
2036 find_xdg_file (int xdg_type, char* filename) {
2037 /* xdg_type = 0 => config
2038 xdg_type = 1 => data
2039 xdg_type = 2 => cache*/
2041 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2042 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2045 gchar* temporary_string;
2049 if (! file_exists (temporary_file) && xdg_type != 2) {
2050 buf = get_xdg_var (XDG[3 + xdg_type]);
2051 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2054 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2055 g_free (temporary_file);
2056 temporary_file = g_strconcat (temporary_string, filename, NULL);
2060 //g_free (temporary_string); - segfaults.
2062 if (file_exists (temporary_file)) {
2063 return temporary_file;
2070 State *s = &uzbl.state;
2071 Network *n = &uzbl.net;
2073 for (i = 0; default_config[i].command != NULL; i++) {
2074 parse_cmd_line(default_config[i].command);
2077 if (!s->config_file) {
2078 s->config_file = find_xdg_file (0, "/uzbl/config");
2081 if (s->config_file) {
2082 GArray* lines = read_file_by_line (s->config_file);
2086 while ((line = g_array_index(lines, gchar*, i))) {
2087 parse_cmd_line (line);
2091 g_array_free (lines, TRUE);
2093 if (uzbl.state.verbose)
2094 printf ("No configuration file loaded.\n");
2097 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2100 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2103 if (!uzbl.behave.cookie_handler) return;
2105 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2106 GString *s = g_string_new ("");
2107 SoupURI * soup_uri = soup_message_get_uri(msg);
2108 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2109 run_handler(uzbl.behave.cookie_handler, s->str);
2111 if(uzbl.comm.sync_stdout)
2112 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2113 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2114 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2116 g_string_free(s, TRUE);
2120 save_cookies (SoupMessage *msg, gpointer user_data){
2124 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2125 cookie = soup_cookie_to_set_cookie_header(ck->data);
2126 SoupURI * soup_uri = soup_message_get_uri(msg);
2127 GString *s = g_string_new ("");
2128 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2129 run_handler(uzbl.behave.cookie_handler, s->str);
2131 g_string_free(s, TRUE);
2136 /* --- WEBINSPECTOR --- */
2138 hide_window_cb(GtkWidget *widget, gpointer data) {
2141 gtk_widget_hide(widget);
2144 static WebKitWebView*
2145 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2148 (void) web_inspector;
2149 GtkWidget* scrolled_window;
2150 GtkWidget* new_web_view;
2153 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2154 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2155 G_CALLBACK(hide_window_cb), NULL);
2157 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2158 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2159 gtk_widget_show(g->inspector_window);
2161 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2162 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2163 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2164 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2165 gtk_widget_show(scrolled_window);
2167 new_web_view = webkit_web_view_new();
2168 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2170 return WEBKIT_WEB_VIEW(new_web_view);
2174 inspector_show_window_cb (WebKitWebInspector* inspector){
2176 gtk_widget_show(uzbl.gui.inspector_window);
2180 /* TODO: Add variables and code to make use of these functions */
2182 inspector_close_window_cb (WebKitWebInspector* inspector){
2188 inspector_attach_window_cb (WebKitWebInspector* inspector){
2194 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2200 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2206 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2212 set_up_inspector() {
2214 WebKitWebSettings *settings = view_settings();
2215 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2217 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2218 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2219 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2220 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2221 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2222 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2223 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2225 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2232 main (int argc, char* argv[]) {
2233 gtk_init (&argc, &argv);
2234 if (!g_thread_supported ())
2235 g_thread_init (NULL);
2236 uzbl.state.executable_path = g_strdup(argv[0]);
2237 uzbl.state.selected_url = NULL;
2238 uzbl.state.searchtx = NULL;
2240 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2241 g_option_context_add_main_entries (context, entries, NULL);
2242 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2243 g_option_context_parse (context, &argc, &argv, NULL);
2244 g_option_context_free(context);
2245 /* initialize hash table */
2246 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2248 uzbl.net.soup_session = webkit_get_default_session();
2249 uzbl.state.keycmd = g_string_new("");
2251 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2252 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2253 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2254 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2255 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2256 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2259 if(uname(&uzbl.state.unameinfo) == -1)
2260 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2262 uzbl.gui.sbar.progress_s = g_strdup("=");
2263 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2264 uzbl.gui.sbar.progress_w = 10;
2266 /* HTML mode defaults*/
2267 uzbl.behave.html_buffer = g_string_new("");
2268 uzbl.behave.html_endmarker = g_strdup(".");
2269 uzbl.behave.html_timeout = 60;
2270 uzbl.behave.base_url = g_strdup("http://invalid");
2275 make_var_to_name_hash();
2277 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2279 uzbl.gui.scrolled_win = create_browser();
2282 /* initial packing */
2283 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2284 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2286 uzbl.gui.main_window = create_window ();
2287 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2290 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2291 gtk_widget_show_all (uzbl.gui.main_window);
2292 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2294 if (uzbl.state.verbose) {
2295 printf("Uzbl start location: %s\n", argv[0]);
2296 printf("window_id %i\n",(int) uzbl.xwin);
2297 printf("pid %i\n", getpid ());
2298 printf("name: %s\n", uzbl.state.instance_name);
2301 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2302 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2303 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2304 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2305 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2309 if (!uzbl.behave.show_status)
2310 gtk_widget_hide(uzbl.gui.mainbar);
2319 if(uzbl.state.uri) {
2320 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2321 g_array_append_val(a, uzbl.state.uri);
2322 load_uri (uzbl.gui.web_view, a);
2323 g_array_free (a, TRUE);
2329 return EXIT_SUCCESS;
2332 /* vi: set et ts=4: */