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};
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 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, cmd_disable_plugins)},
137 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, cmd_disable_scripts)},
138 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, cmd_autoload_img)},
139 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, cmd_autoshrink_img)},
140 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, cmd_enable_spellcheck)},
141 { "enable_private", PTR(uzbl.behave.enable_private, INT, cmd_enable_private)},
142 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, cmd_print_bg)},
143 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, cmd_style_uri)},
144 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, cmd_resizable_txt)},
145 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, cmd_default_encoding)},
146 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, cmd_enforce_96dpi)},
147 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, cmd_caret_browsing)},
149 { NULL, {.ptr = NULL, .type = TYPE_INT, .func = NULL}}
150 }, *n2v_p = var_name_to_ptr;
156 { "SHIFT", GDK_SHIFT_MASK }, // shift
157 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
158 { "CONTROL", GDK_CONTROL_MASK }, // control
159 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
160 { "MOD2", GDK_MOD2_MASK }, // 5th mod
161 { "MOD3", GDK_MOD3_MASK }, // 6th mod
162 { "MOD4", GDK_MOD4_MASK }, // 7th mod
163 { "MOD5", GDK_MOD5_MASK }, // 8th mod
164 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
165 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
166 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
167 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
168 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
169 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
170 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
171 { "META", GDK_META_MASK }, // meta (since 2.10)
176 /* construct a hash from the var_name_to_ptr array for quick access */
178 make_var_to_name_hash() {
179 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
181 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
187 /* --- UTILITY FUNCTIONS --- */
193 snprintf(tmp, sizeof(tmp), "%i", val);
194 return g_strdup(tmp);
198 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
201 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
204 str_replace (const char* search, const char* replace, const char* string) {
208 buf = g_strsplit (string, search, -1);
209 ret = g_strjoinv (replace, buf);
210 g_strfreev(buf); // somebody said this segfaults
216 read_file_by_line (gchar *path) {
217 GIOChannel *chan = NULL;
218 gchar *readbuf = NULL;
220 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
223 chan = g_io_channel_new_file(path, "r", NULL);
226 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
227 const gchar* val = g_strdup (readbuf);
228 g_array_append_val (lines, val);
233 g_io_channel_unref (chan);
235 fprintf(stderr, "File '%s' not be read.\n", path);
242 gchar* parseenv (char* string) {
243 extern char** environ;
244 gchar* tmpstr = NULL;
248 while (environ[i] != NULL) {
249 gchar** env = g_strsplit (environ[i], "=", 2);
250 gchar* envname = g_strconcat ("$", env[0], NULL);
252 if (g_strrstr (string, envname) != NULL) {
253 tmpstr = g_strdup(string);
255 string = str_replace(envname, env[1], tmpstr);
260 g_strfreev (env); // somebody said this breaks uzbl
268 setup_signal(int signr, sigfunc *shandler) {
269 struct sigaction nh, oh;
271 nh.sa_handler = shandler;
272 sigemptyset(&nh.sa_mask);
275 if(sigaction(signr, &nh, &oh) < 0)
283 if (uzbl.behave.fifo_dir)
284 unlink (uzbl.comm.fifo_path);
285 if (uzbl.behave.socket_dir)
286 unlink (uzbl.comm.socket_path);
288 g_free(uzbl.state.executable_path);
289 g_string_free(uzbl.state.keycmd, TRUE);
290 g_hash_table_destroy(uzbl.bindings);
291 g_hash_table_destroy(uzbl.behave.commands);
294 /* used for html_mode_timeout
295 * be sure to extend this function to use
296 * more timers if needed in other places
299 set_timeout(int seconds) {
301 memset(&t, 0, sizeof t);
303 t.it_value.tv_sec = seconds;
304 t.it_value.tv_usec = 0;
305 setitimer(ITIMER_REAL, &t, NULL);
308 /* --- SIGNAL HANDLER --- */
311 catch_sigterm(int s) {
317 catch_sigint(int s) {
327 set_var_value("mode", "0");
332 /* --- CALLBACKS --- */
335 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
338 (void) navigation_action;
339 (void) policy_decision;
341 const gchar* uri = webkit_network_request_get_uri (request);
342 if (uzbl.state.verbose)
343 printf("New window requested -> %s \n", uri);
344 new_window_load_uri(uri);
349 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
353 if (uzbl.state.selected_url != NULL) {
354 if (uzbl.state.verbose)
355 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
356 new_window_load_uri(uzbl.state.selected_url);
358 if (uzbl.state.verbose)
359 printf("New web view -> %s\n","Nothing to open, exiting");
365 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
368 if (uzbl.behave.download_handler) {
369 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
370 if (uzbl.state.verbose)
371 printf("Download -> %s\n",uri);
372 /* if urls not escaped, we may have to escape and quote uri before this call */
373 run_handler(uzbl.behave.download_handler, uri);
378 /* scroll a bar in a given direction */
380 scroll (GtkAdjustment* bar, GArray *argv) {
384 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
385 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
386 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
389 static void scroll_begin(WebKitWebView* page, GArray *argv) {
390 (void) page; (void) argv;
391 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
394 static void scroll_end(WebKitWebView* page, GArray *argv) {
395 (void) page; (void) argv;
396 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
397 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
400 static void scroll_vert(WebKitWebView* page, GArray *argv) {
402 scroll(uzbl.gui.bar_v, argv);
405 static void scroll_horz(WebKitWebView* page, GArray *argv) {
407 scroll(uzbl.gui.bar_h, argv);
412 if (!uzbl.behave.show_status) {
413 gtk_widget_hide(uzbl.gui.mainbar);
415 gtk_widget_show(uzbl.gui.mainbar);
421 toggle_status_cb (WebKitWebView* page, GArray *argv) {
425 if (uzbl.behave.show_status) {
426 gtk_widget_hide(uzbl.gui.mainbar);
428 gtk_widget_show(uzbl.gui.mainbar);
430 uzbl.behave.show_status = !uzbl.behave.show_status;
435 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
439 //Set selected_url state variable
440 g_free(uzbl.state.selected_url);
441 uzbl.state.selected_url = NULL;
443 uzbl.state.selected_url = g_strdup(link);
449 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
453 if (uzbl.gui.main_title)
454 g_free (uzbl.gui.main_title);
455 uzbl.gui.main_title = g_strdup (title);
460 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
463 uzbl.gui.sbar.load_progress = progress;
468 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
472 if (uzbl.behave.load_finish_handler)
473 run_handler(uzbl.behave.load_finish_handler, "");
477 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
481 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
482 if (uzbl.behave.load_start_handler)
483 run_handler(uzbl.behave.load_start_handler, "");
487 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
490 g_free (uzbl.state.uri);
491 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
492 uzbl.state.uri = g_string_free (newuri, FALSE);
493 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
494 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
497 if (uzbl.behave.load_commit_handler)
498 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
502 destroy_cb (GtkWidget* widget, gpointer data) {
510 if (uzbl.behave.history_handler) {
512 struct tm * timeinfo;
515 timeinfo = localtime ( &rawtime );
516 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
517 run_handler(uzbl.behave.history_handler, date);
522 /* VIEW funcs (little webkit wrappers) */
523 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
525 VIEWFUNC(reload_bypass_cache)
526 VIEWFUNC(stop_loading)
533 /* -- command to callback/function map for things we cannot attach to any signals */
534 static struct {char *name; Command command[2];} cmdlist[] =
535 { /* key function no_split */
536 { "back", {view_go_back, 0} },
537 { "forward", {view_go_forward, 0} },
538 { "scroll_vert", {scroll_vert, 0} },
539 { "scroll_horz", {scroll_horz, 0} },
540 { "scroll_begin", {scroll_begin, 0} },
541 { "scroll_end", {scroll_end, 0} },
542 { "reload", {view_reload, 0}, },
543 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
544 { "stop", {view_stop_loading, 0}, },
545 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
546 { "zoom_out", {view_zoom_out, 0}, },
547 { "uri", {load_uri, NOSPLIT} },
548 { "js", {run_js, NOSPLIT} },
549 { "script", {run_external_js, 0} },
550 { "toggle_status", {toggle_status_cb, 0} },
551 { "spawn", {spawn, 0} },
552 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
553 { "sh", {spawn_sh, 0} },
554 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
555 { "exit", {close_uzbl, 0} },
556 { "search", {search_forward_text, NOSPLIT} },
557 { "search_reverse", {search_reverse_text, NOSPLIT} },
558 { "dehilight", {dehilight, 0} },
559 { "toggle_insert_mode", {toggle_insert_mode, 0} },
560 { "runcmd", {runcmd, NOSPLIT} },
561 { "set", {set_var, NOSPLIT} }
568 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
570 for (i = 0; i < LENGTH(cmdlist); i++)
571 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
574 /* -- CORE FUNCTIONS -- */
577 free_action(gpointer act) {
578 Action *action = (Action*)act;
579 g_free(action->name);
581 g_free(action->param);
586 new_action(const gchar *name, const gchar *param) {
587 Action *action = g_new(Action, 1);
589 action->name = g_strdup(name);
591 action->param = g_strdup(param);
593 action->param = NULL;
599 file_exists (const char * filename) {
600 return (access(filename, F_OK) == 0);
604 set_var(WebKitWebView *page, GArray *argv) {
608 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
609 parse_cmd_line(ctl_line);
614 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
617 if (argv_idx(argv, 0)) {
618 if (strcmp (argv_idx(argv, 0), "0") == 0) {
619 uzbl.behave.insert_mode = FALSE;
621 uzbl.behave.insert_mode = TRUE;
624 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
631 load_uri (WebKitWebView *web_view, GArray *argv) {
632 if (argv_idx(argv, 0)) {
633 GString* newuri = g_string_new (argv_idx(argv, 0));
634 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
635 g_string_prepend (newuri, "http://");
636 /* if we do handle cookies, ask our handler for them */
637 webkit_web_view_load_uri (web_view, newuri->str);
638 g_string_free (newuri, TRUE);
643 run_js (WebKitWebView * web_view, GArray *argv) {
644 if (argv_idx(argv, 0))
645 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
649 run_external_js (WebKitWebView * web_view, GArray *argv) {
650 if (argv_idx(argv, 0)) {
651 GArray* lines = read_file_by_line (argv_idx (argv, 0));
656 while ((line = g_array_index(lines, gchar*, i))) {
658 js = g_strdup (line);
660 gchar* newjs = g_strconcat (js, line, NULL);
667 if (uzbl.state.verbose)
668 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
670 if (argv_idx (argv, 1)) {
671 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
675 webkit_web_view_execute_script (web_view, js);
677 g_array_free (lines, TRUE);
682 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
683 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
684 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
685 webkit_web_view_unmark_text_matches (page);
686 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
687 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
691 if (uzbl.state.searchtx) {
692 if (uzbl.state.verbose)
693 printf ("Searching: %s\n", uzbl.state.searchtx);
694 webkit_web_view_set_highlight_text_matches (page, TRUE);
695 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
700 search_forward_text (WebKitWebView *page, GArray *argv) {
701 search_text(page, argv, TRUE);
705 search_reverse_text (WebKitWebView *page, GArray *argv) {
706 search_text(page, argv, FALSE);
710 dehilight (WebKitWebView *page, GArray *argv) {
712 webkit_web_view_set_highlight_text_matches (page, FALSE);
717 new_window_load_uri (const gchar * uri) {
718 GString* to_execute = g_string_new ("");
719 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
721 for (i = 0; entries[i].long_name != NULL; i++) {
722 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
723 gchar** str = (gchar**)entries[i].arg_data;
725 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
729 if (uzbl.state.verbose)
730 printf("\n%s\n", to_execute->str);
731 g_spawn_command_line_async (to_execute->str, NULL);
732 g_string_free (to_execute, TRUE);
736 close_uzbl (WebKitWebView *page, GArray *argv) {
742 /* --Statusbar functions-- */
744 build_progressbar_ascii(int percent) {
745 int width=uzbl.gui.sbar.progress_w;
748 GString *bar = g_string_new("");
750 l = (double)percent*((double)width/100.);
751 l = (int)(l+.5)>=(int)l ? l+.5 : l;
753 for(i=0; i<(int)l; i++)
754 g_string_append(bar, uzbl.gui.sbar.progress_s);
757 g_string_append(bar, uzbl.gui.sbar.progress_u);
759 return g_string_free(bar, FALSE);
764 const GScannerConfig scan_config = {
767 ) /* cset_skip_characters */,
772 ) /* cset_identifier_first */,
779 ) /* cset_identifier_nth */,
780 ( "" ) /* cpair_comment_single */,
782 TRUE /* case_sensitive */,
784 FALSE /* skip_comment_multi */,
785 FALSE /* skip_comment_single */,
786 FALSE /* scan_comment_multi */,
787 TRUE /* scan_identifier */,
788 TRUE /* scan_identifier_1char */,
789 FALSE /* scan_identifier_NULL */,
790 TRUE /* scan_symbols */,
791 FALSE /* scan_binary */,
792 FALSE /* scan_octal */,
793 FALSE /* scan_float */,
794 FALSE /* scan_hex */,
795 FALSE /* scan_hex_dollar */,
796 FALSE /* scan_string_sq */,
797 FALSE /* scan_string_dq */,
798 TRUE /* numbers_2_int */,
799 FALSE /* int_2_float */,
800 FALSE /* identifier_2_string */,
801 FALSE /* char_2_token */,
802 FALSE /* symbol_2_token */,
803 TRUE /* scope_0_fallback */,
808 uzbl.scan = g_scanner_new(&scan_config);
809 while(symp->symbol_name) {
810 g_scanner_scope_add_symbol(uzbl.scan, 0,
812 GINT_TO_POINTER(symp->symbol_token));
818 expand_template(const char *template, gboolean escape_markup) {
819 if(!template) return NULL;
821 GTokenType token = G_TOKEN_NONE;
822 GString *ret = g_string_new("");
826 g_scanner_input_text(uzbl.scan, template, strlen(template));
827 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
828 token = g_scanner_get_next_token(uzbl.scan);
830 if(token == G_TOKEN_SYMBOL) {
831 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
835 buf = uzbl.state.uri?
836 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
837 g_string_append(ret, buf);
841 g_string_append(ret, uzbl.state.uri?
842 uzbl.state.uri:g_strdup(""));
845 buf = itos(uzbl.gui.sbar.load_progress);
846 g_string_append(ret, buf);
849 case SYM_LOADPRGSBAR:
850 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
851 g_string_append(ret, buf);
856 buf = uzbl.gui.main_title?
857 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
858 g_string_append(ret, buf);
862 g_string_append(ret, uzbl.gui.main_title?
863 uzbl.gui.main_title:g_strdup(""));
865 case SYM_SELECTED_URI:
867 buf = uzbl.state.selected_url?
868 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
869 g_string_append(ret, buf);
873 g_string_append(ret, uzbl.state.selected_url?
874 uzbl.state.selected_url:g_strdup(""));
877 buf = itos(uzbl.xwin);
879 uzbl.state.instance_name?uzbl.state.instance_name:buf);
884 buf = uzbl.state.keycmd->str?
885 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
886 g_string_append(ret, buf);
890 g_string_append(ret, uzbl.state.keycmd->str?
891 uzbl.state.keycmd->str:g_strdup(""));
895 uzbl.behave.insert_mode?"[I]":"[C]");
899 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
903 buf = itos(WEBKIT_MAJOR_VERSION);
904 g_string_append(ret, buf);
908 buf = itos(WEBKIT_MINOR_VERSION);
909 g_string_append(ret, buf);
913 buf = itos(WEBKIT_MICRO_VERSION);
914 g_string_append(ret, buf);
918 g_string_append(ret, uzbl.state.unameinfo.sysname);
921 g_string_append(ret, uzbl.state.unameinfo.nodename);
924 g_string_append(ret, uzbl.state.unameinfo.release);
927 g_string_append(ret, uzbl.state.unameinfo.version);
930 g_string_append(ret, uzbl.state.unameinfo.machine);
933 g_string_append(ret, ARCH);
937 g_string_append(ret, uzbl.state.unameinfo.domainname);
941 g_string_append(ret, COMMIT);
947 else if(token == G_TOKEN_INT) {
948 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
949 g_string_append(ret, buf);
952 else if(token == G_TOKEN_IDENTIFIER) {
953 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
955 else if(token == G_TOKEN_CHAR) {
956 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
960 return g_string_free(ret, FALSE);
962 /* --End Statusbar functions-- */
965 sharg_append(GArray *a, const gchar *str) {
966 const gchar *s = (str ? str : "");
967 g_array_append_val(a, s);
970 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
972 run_command (const gchar *command, const guint npre, const gchar **args,
973 const gboolean sync, char **stdout) {
974 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
977 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
978 gchar *pid = itos(getpid());
979 gchar *xwin = itos(uzbl.xwin);
981 sharg_append(a, command);
982 for (i = 0; i < npre; i++) /* add n args before the default vars */
983 sharg_append(a, args[i]);
984 sharg_append(a, uzbl.state.config_file);
985 sharg_append(a, pid);
986 sharg_append(a, xwin);
987 sharg_append(a, uzbl.comm.fifo_path);
988 sharg_append(a, uzbl.comm.socket_path);
989 sharg_append(a, uzbl.state.uri);
990 sharg_append(a, uzbl.gui.main_title);
992 for (i = npre; i < g_strv_length((gchar**)args); i++)
993 sharg_append(a, args[i]);
997 if (*stdout) *stdout = strfree(*stdout);
999 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1000 NULL, NULL, stdout, NULL, NULL, &err);
1001 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1002 NULL, NULL, NULL, &err);
1004 if (uzbl.state.verbose) {
1005 GString *s = g_string_new("spawned:");
1006 for (i = 0; i < (a->len); i++) {
1007 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1008 g_string_append_printf(s, " %s", qarg);
1011 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1012 printf("%s\n", s->str);
1013 g_string_free(s, TRUE);
1016 g_printerr("error on run_command: %s\n", err->message);
1021 g_array_free (a, TRUE);
1026 split_quoted(const gchar* src, const gboolean unquote) {
1027 /* split on unquoted space, return array of strings;
1028 remove a layer of quotes and backslashes if unquote */
1029 if (!src) return NULL;
1031 gboolean dq = FALSE;
1032 gboolean sq = FALSE;
1033 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1034 GString *s = g_string_new ("");
1038 for (p = src; *p != '\0'; p++) {
1039 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1040 else if (*p == '\\') { g_string_append_c(s, *p++);
1041 g_string_append_c(s, *p); }
1042 else if ((*p == '"') && unquote && !sq) dq = !dq;
1043 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1045 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1046 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1048 else if ((*p == ' ') && !dq && !sq) {
1049 dup = g_strdup(s->str);
1050 g_array_append_val(a, dup);
1051 g_string_truncate(s, 0);
1052 } else g_string_append_c(s, *p);
1054 dup = g_strdup(s->str);
1055 g_array_append_val(a, dup);
1056 ret = (gchar**)a->data;
1057 g_array_free (a, FALSE);
1058 g_string_free (s, TRUE);
1063 spawn(WebKitWebView *web_view, GArray *argv) {
1065 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1066 if (argv_idx(argv, 0))
1067 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1071 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1074 if (argv_idx(argv, 0))
1075 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1076 TRUE, &uzbl.comm.sync_stdout);
1080 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1082 if (!uzbl.behave.shell_cmd) {
1083 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1088 gchar *spacer = g_strdup("");
1089 g_array_insert_val(argv, 1, spacer);
1090 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1092 for (i = 1; i < g_strv_length(cmd); i++)
1093 g_array_prepend_val(argv, cmd[i]);
1095 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1101 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1103 if (!uzbl.behave.shell_cmd) {
1104 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1109 gchar *spacer = g_strdup("");
1110 g_array_insert_val(argv, 1, spacer);
1111 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1113 for (i = 1; i < g_strv_length(cmd); i++)
1114 g_array_prepend_val(argv, cmd[i]);
1116 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1117 TRUE, &uzbl.comm.sync_stdout);
1123 parse_command(const char *cmd, const char *param) {
1126 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1129 gchar **par = split_quoted(param, TRUE);
1130 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1132 if (c[1] == NOSPLIT) { /* don't split */
1133 sharg_append(a, param);
1135 for (i = 0; i < g_strv_length(par); i++)
1136 sharg_append(a, par[i]);
1138 c[0](uzbl.gui.web_view, a);
1140 g_array_free (a, TRUE);
1143 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1146 /* command parser */
1149 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1150 G_REGEX_OPTIMIZE, 0, NULL);
1151 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1152 G_REGEX_OPTIMIZE, 0, NULL);
1153 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1154 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1155 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1156 G_REGEX_OPTIMIZE, 0, NULL);
1157 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1158 G_REGEX_OPTIMIZE, 0, NULL);
1162 get_var_value(gchar *name) {
1165 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1166 if(c->type == TYPE_STR)
1167 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1168 else if(c->type == TYPE_INT)
1169 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1178 if(*uzbl.net.proxy_url == ' '
1179 || uzbl.net.proxy_url == NULL) {
1180 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1181 (GType) SOUP_SESSION_PROXY_URI);
1184 suri = soup_uri_new(uzbl.net.proxy_url);
1185 g_object_set(G_OBJECT(uzbl.net.soup_session),
1186 SOUP_SESSION_PROXY_URI,
1188 soup_uri_free(suri);
1195 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1196 g_array_append_val (a, uzbl.state.uri);
1197 load_uri(uzbl.gui.web_view, a);
1198 g_array_free (a, TRUE);
1202 cmd_always_insert_mode() {
1203 uzbl.behave.insert_mode =
1204 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1210 g_object_set(G_OBJECT(uzbl.net.soup_session),
1211 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1215 cmd_max_conns_host() {
1216 g_object_set(G_OBJECT(uzbl.net.soup_session),
1217 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1222 soup_session_remove_feature
1223 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1224 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1225 /*g_free(uzbl.net.soup_logger);*/
1227 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1228 soup_session_add_feature(uzbl.net.soup_session,
1229 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1232 static WebKitWebSettings*
1234 return webkit_web_view_get_settings(uzbl.gui.web_view);
1239 WebKitWebSettings *ws = view_settings();
1240 if (uzbl.behave.font_size > 0) {
1241 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1244 if (uzbl.behave.monospace_size > 0) {
1245 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1246 uzbl.behave.monospace_size, NULL);
1248 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1249 uzbl.behave.font_size, NULL);
1254 cmd_disable_plugins() {
1255 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1256 !uzbl.behave.disable_plugins, NULL);
1260 cmd_disable_scripts() {
1261 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1262 !uzbl.behave.disable_plugins, NULL);
1266 cmd_minimum_font_size() {
1267 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1268 uzbl.behave.minimum_font_size, NULL);
1271 cmd_autoload_img() {
1272 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1273 uzbl.behave.autoload_img, NULL);
1278 cmd_autoshrink_img() {
1279 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1280 uzbl.behave.autoshrink_img, NULL);
1285 cmd_enable_spellcheck() {
1286 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1287 uzbl.behave.enable_spellcheck, NULL);
1291 cmd_enable_private() {
1292 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1293 uzbl.behave.enable_private, NULL);
1298 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1299 uzbl.behave.print_bg, NULL);
1304 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1305 uzbl.behave.style_uri, NULL);
1309 cmd_resizable_txt() {
1310 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1311 uzbl.behave.resizable_txt, NULL);
1315 cmd_default_encoding() {
1316 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1317 uzbl.behave.default_encoding, NULL);
1321 cmd_enforce_96dpi() {
1322 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1323 uzbl.behave.enforce_96dpi, NULL);
1327 cmd_caret_browsing() {
1328 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1329 uzbl.behave.caret_browsing, NULL);
1333 cmd_cookie_handler() {
1334 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1335 if ((g_strcmp0(split[0], "sh") == 0) ||
1336 (g_strcmp0(split[0], "spawn") == 0)) {
1337 g_free (uzbl.behave.cookie_handler);
1338 uzbl.behave.cookie_handler =
1339 g_strdup_printf("sync_%s %s", split[0], split[1]);
1346 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1351 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1356 if(uzbl.behave.inject_html) {
1357 webkit_web_view_load_html_string (uzbl.gui.web_view,
1358 uzbl.behave.inject_html, NULL);
1367 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1368 uzbl.behave.modmask = 0;
1370 if(uzbl.behave.modkey)
1371 g_free(uzbl.behave.modkey);
1372 uzbl.behave.modkey = buf;
1374 for (i = 0; modkeys[i].key != NULL; i++) {
1375 if (g_strrstr(buf, modkeys[i].key))
1376 uzbl.behave.modmask |= modkeys[i].mask;
1382 if (*uzbl.net.useragent == ' ') {
1383 g_free (uzbl.net.useragent);
1384 uzbl.net.useragent = NULL;
1386 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1388 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1389 g_free(uzbl.net.useragent);
1390 uzbl.net.useragent = ua;
1396 gtk_widget_ref(uzbl.gui.scrolled_win);
1397 gtk_widget_ref(uzbl.gui.mainbar);
1398 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1399 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1401 if(uzbl.behave.status_top) {
1402 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1403 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1406 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1407 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1409 gtk_widget_unref(uzbl.gui.scrolled_win);
1410 gtk_widget_unref(uzbl.gui.mainbar);
1411 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1416 set_var_value(gchar *name, gchar *val) {
1417 uzbl_cmdprop *c = NULL;
1420 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1421 /* check for the variable type */
1422 if (c->type == TYPE_STR) {
1424 *c->ptr = g_strdup(val);
1425 } else if(c->type == TYPE_INT) {
1426 int *ip = (int *)c->ptr;
1427 *ip = (int)strtoul(val, &endp, 10);
1430 /* invoke a command specific function */
1431 if(c->func) c->func();
1437 runcmd(WebKitWebView* page, GArray *argv) {
1439 parse_cmd_line(argv_idx(argv, 0));
1444 Behaviour *b = &uzbl.behave;
1446 if(b->html_buffer->str) {
1447 webkit_web_view_load_html_string (uzbl.gui.web_view,
1448 b->html_buffer->str, b->base_url);
1449 g_string_free(b->html_buffer, TRUE);
1450 b->html_buffer = g_string_new("");
1454 enum {M_CMD, M_HTML};
1456 parse_cmd_line(const char *ctl_line) {
1457 gchar **tokens = NULL;
1458 Behaviour *b = &uzbl.behave;
1460 if(b->mode == M_HTML) {
1462 if(!strncmp(b->html_endmarker, ctl_line, strlen(b->html_endmarker))) {
1464 set_var_value("mode", "0");
1469 /* set an alarm to kill us after the timeout */
1470 set_timeout(b->html_timeout);
1471 g_string_append(b->html_buffer, ctl_line);
1476 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1477 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1478 if(tokens[0][0] == 0) {
1479 gchar* value = parseenv(g_strdup(tokens[2]));
1480 set_var_value(tokens[1], value);
1484 printf("Error in command: %s\n", tokens[0]);
1487 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1488 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1489 if(tokens[0][0] == 0) {
1490 get_var_value(tokens[1]);
1493 printf("Error in command: %s\n", tokens[0]);
1496 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1497 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1498 if(tokens[0][0] == 0) {
1499 gchar* value = parseenv(g_strdup(tokens[2]));
1500 add_binding(tokens[1], value);
1504 printf("Error in command: %s\n", tokens[0]);
1507 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1508 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1509 if(tokens[0][0] == 0) {
1510 parse_command(tokens[1], tokens[2]);
1513 printf("Error in command: %s\n", tokens[0]);
1515 /* KEYCMD command */
1516 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1517 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1518 if(tokens[0][0] == 0) {
1519 /* should incremental commands want each individual "keystroke"
1520 sent in a loop or the whole string in one go like now? */
1521 g_string_assign(uzbl.state.keycmd, tokens[1]);
1523 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1529 else if( (ctl_line[0] == '#')
1530 || (ctl_line[0] == ' ')
1531 || (ctl_line[0] == '\n'))
1532 ; /* ignore these lines */
1534 printf("Command not understood (%s)\n", ctl_line);
1544 build_stream_name(int type, const gchar* dir) {
1546 State *s = &uzbl.state;
1549 xwin_str = itos((int)uzbl.xwin);
1551 str = g_strdup_printf
1552 ("%s/uzbl_fifo_%s", dir,
1553 s->instance_name ? s->instance_name : xwin_str);
1554 } else if (type == SOCKET) {
1555 str = g_strdup_printf
1556 ("%s/uzbl_socket_%s", dir,
1557 s->instance_name ? s->instance_name : xwin_str );
1564 control_fifo(GIOChannel *gio, GIOCondition condition) {
1565 if (uzbl.state.verbose)
1566 printf("triggered\n");
1571 if (condition & G_IO_HUP)
1572 g_error ("Fifo: Read end of pipe died!\n");
1575 g_error ("Fifo: GIOChannel broke\n");
1577 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1578 if (ret == G_IO_STATUS_ERROR) {
1579 g_error ("Fifo: Error reading: %s\n", err->message);
1583 parse_cmd_line(ctl_line);
1590 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1591 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1592 if (unlink(uzbl.comm.fifo_path) == -1)
1593 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1594 g_free(uzbl.comm.fifo_path);
1595 uzbl.comm.fifo_path = NULL;
1598 if (*dir == ' ') { /* space unsets the variable */
1603 GIOChannel *chan = NULL;
1604 GError *error = NULL;
1605 gchar *path = build_stream_name(FIFO, dir);
1607 if (!file_exists(path)) {
1608 if (mkfifo (path, 0666) == 0) {
1609 // 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.
1610 chan = g_io_channel_new_file(path, "r+", &error);
1612 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1613 if (uzbl.state.verbose)
1614 printf ("init_fifo: created successfully as %s\n", path);
1615 uzbl.comm.fifo_path = path;
1617 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1618 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1619 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1620 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1622 /* if we got this far, there was an error; cleanup */
1623 if (error) g_error_free (error);
1630 control_stdin(GIOChannel *gio, GIOCondition condition) {
1632 gchar *ctl_line = NULL;
1635 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1636 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1639 parse_cmd_line(ctl_line);
1647 GIOChannel *chan = NULL;
1648 GError *error = NULL;
1650 chan = g_io_channel_unix_new(fileno(stdin));
1652 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1653 g_error ("Stdin: could not add watch\n");
1655 if (uzbl.state.verbose)
1656 printf ("Stdin: watch added successfully\n");
1659 g_error ("Stdin: Error while opening: %s\n", error->message);
1661 if (error) g_error_free (error);
1665 control_socket(GIOChannel *chan) {
1666 struct sockaddr_un remote;
1667 char buffer[512], *ctl_line;
1669 int sock, clientsock, n, done;
1672 sock = g_io_channel_unix_get_fd(chan);
1674 memset (buffer, 0, sizeof (buffer));
1676 t = sizeof (remote);
1677 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1681 memset (temp, 0, sizeof (temp));
1682 n = recv (clientsock, temp, 128, 0);
1684 buffer[strlen (buffer)] = '\0';
1688 strcat (buffer, temp);
1691 if (strcmp (buffer, "\n") < 0) {
1692 buffer[strlen (buffer) - 1] = '\0';
1694 buffer[strlen (buffer)] = '\0';
1697 ctl_line = g_strdup(buffer);
1698 parse_cmd_line (ctl_line);
1701 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1702 GError *error = NULL;
1705 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1706 if (ret == G_IO_STATUS_ERROR)
1707 g_error ("Error reading: %s\n", error->message);
1709 printf("Got line %s (%u bytes) \n",ctl_line, len);
1711 parse_line(ctl_line);
1719 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1720 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1721 if (unlink(uzbl.comm.socket_path) == -1)
1722 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1723 g_free(uzbl.comm.socket_path);
1724 uzbl.comm.socket_path = NULL;
1732 GIOChannel *chan = NULL;
1734 struct sockaddr_un local;
1735 gchar *path = build_stream_name(SOCKET, dir);
1737 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1739 local.sun_family = AF_UNIX;
1740 strcpy (local.sun_path, path);
1741 unlink (local.sun_path);
1743 len = strlen (local.sun_path) + sizeof (local.sun_family);
1744 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1745 if (uzbl.state.verbose)
1746 printf ("init_socket: opened in %s\n", path);
1749 if( (chan = g_io_channel_unix_new(sock)) ) {
1750 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1751 uzbl.comm.socket_path = path;
1754 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1756 /* if we got this far, there was an error; cleanup */
1763 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1764 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1766 // this function may be called very early when the templates are not set (yet), hence the checks
1768 update_title (void) {
1769 Behaviour *b = &uzbl.behave;
1772 if (b->show_status) {
1773 if (b->title_format_short) {
1774 parsed = expand_template(b->title_format_short, FALSE);
1775 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1778 if (b->status_format) {
1779 parsed = expand_template(b->status_format, TRUE);
1780 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1783 if (b->status_background) {
1785 gdk_color_parse (b->status_background, &color);
1786 //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)
1787 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1790 if (b->title_format_long) {
1791 parsed = expand_template(b->title_format_long, FALSE);
1792 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1799 key_press_cb (GtkWidget* window, GdkEventKey* event)
1801 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1805 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1806 || 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)
1809 /* turn off insert mode (if always_insert_mode is not used) */
1810 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1811 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1816 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1819 if (event->keyval == GDK_Escape) {
1820 g_string_truncate(uzbl.state.keycmd, 0);
1822 dehilight(uzbl.gui.web_view, NULL);
1826 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1827 if (event->keyval == GDK_Insert) {
1829 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1830 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1832 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1835 g_string_append (uzbl.state.keycmd, str);
1842 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1843 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1847 gboolean key_ret = FALSE;
1848 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1850 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1852 run_keycmd(key_ret);
1854 if (key_ret) return (!uzbl.behave.insert_mode);
1859 run_keycmd(const gboolean key_ret) {
1860 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1862 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1863 g_string_truncate(uzbl.state.keycmd, 0);
1864 parse_command(act->name, act->param);
1868 /* try if it's an incremental keycmd or one that takes args, and run it */
1869 GString* short_keys = g_string_new ("");
1870 GString* short_keys_inc = g_string_new ("");
1872 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1873 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1874 g_string_assign(short_keys_inc, short_keys->str);
1875 g_string_append_c(short_keys, '_');
1876 g_string_append_c(short_keys_inc, '*');
1878 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1879 /* run normal cmds only if return was pressed */
1880 exec_paramcmd(act, i);
1881 g_string_truncate(uzbl.state.keycmd, 0);
1883 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1884 if (key_ret) /* just quit the incremental command on return */
1885 g_string_truncate(uzbl.state.keycmd, 0);
1886 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1890 g_string_truncate(short_keys, short_keys->len - 1);
1892 g_string_free (short_keys, TRUE);
1893 g_string_free (short_keys_inc, TRUE);
1897 exec_paramcmd(const Action *act, const guint i) {
1898 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1899 GString *actionname = g_string_new ("");
1900 GString *actionparam = g_string_new ("");
1901 g_string_erase (parampart, 0, i+1);
1903 g_string_printf (actionname, act->name, parampart->str);
1905 g_string_printf (actionparam, act->param, parampart->str);
1906 parse_command(actionname->str, actionparam->str);
1907 g_string_free(actionname, TRUE);
1908 g_string_free(actionparam, TRUE);
1909 g_string_free(parampart, TRUE);
1917 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1918 //main_window_ref = g_object_ref(scrolled_window);
1919 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
1921 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1922 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1924 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1925 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1926 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1927 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1928 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1929 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1930 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1931 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1932 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1933 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1935 return scrolled_window;
1942 g->mainbar = gtk_hbox_new (FALSE, 0);
1944 /* keep a reference to the bar so we can re-pack it at runtime*/
1945 //sbar_ref = g_object_ref(g->mainbar);
1947 g->mainbar_label = gtk_label_new ("");
1948 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1949 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1950 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1951 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1952 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1957 GtkWidget* create_window () {
1958 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1959 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1960 gtk_widget_set_name (window, "Uzbl browser");
1961 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1962 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1968 run_handler (const gchar *act, const gchar *args) {
1969 char **parts = g_strsplit(act, " ", 2);
1971 else if ((g_strcmp0(parts[0], "spawn") == 0)
1972 || (g_strcmp0(parts[0], "sh") == 0)
1973 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1974 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1976 GString *a = g_string_new ("");
1978 spawnparts = split_quoted(parts[1], FALSE);
1979 g_string_append_printf(a, "%s", spawnparts[0]);
1980 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1982 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1983 g_string_append_printf(a, " %s", spawnparts[i]);
1984 parse_command(parts[0], a->str);
1985 g_string_free (a, TRUE);
1986 g_strfreev (spawnparts);
1988 parse_command(parts[0], parts[1]);
1993 add_binding (const gchar *key, const gchar *act) {
1994 char **parts = g_strsplit(act, " ", 2);
2001 if (uzbl.state.verbose)
2002 printf ("Binding %-10s : %s\n", key, act);
2003 action = new_action(parts[0], parts[1]);
2005 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2010 get_xdg_var (XDG_Var xdg) {
2011 const gchar* actual_value = getenv (xdg.environmental);
2012 const gchar* home = getenv ("HOME");
2014 gchar* return_value = str_replace ("~", home, actual_value);
2016 if (! actual_value || strcmp (actual_value, "") == 0) {
2017 if (xdg.default_value) {
2018 return_value = str_replace ("~", home, xdg.default_value);
2020 return_value = NULL;
2023 return return_value;
2027 find_xdg_file (int xdg_type, char* filename) {
2028 /* xdg_type = 0 => config
2029 xdg_type = 1 => data
2030 xdg_type = 2 => cache*/
2032 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2033 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2036 gchar* temporary_string;
2040 if (! file_exists (temporary_file) && xdg_type != 2) {
2041 buf = get_xdg_var (XDG[3 + xdg_type]);
2042 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2045 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2046 g_free (temporary_file);
2047 temporary_file = g_strconcat (temporary_string, filename, NULL);
2051 //g_free (temporary_string); - segfaults.
2053 if (file_exists (temporary_file)) {
2054 return temporary_file;
2061 State *s = &uzbl.state;
2062 Network *n = &uzbl.net;
2064 for (i = 0; default_config[i].command != NULL; i++) {
2065 parse_cmd_line(default_config[i].command);
2068 if (!s->config_file) {
2069 s->config_file = find_xdg_file (0, "/uzbl/config");
2072 if (s->config_file) {
2073 GArray* lines = read_file_by_line (s->config_file);
2077 while ((line = g_array_index(lines, gchar*, i))) {
2078 parse_cmd_line (line);
2082 g_array_free (lines, TRUE);
2084 if (uzbl.state.verbose)
2085 printf ("No configuration file loaded.\n");
2088 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2091 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2094 if (!uzbl.behave.cookie_handler) return;
2096 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2097 GString *s = g_string_new ("");
2098 SoupURI * soup_uri = soup_message_get_uri(msg);
2099 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2100 run_handler(uzbl.behave.cookie_handler, s->str);
2102 if(uzbl.comm.sync_stdout)
2103 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2104 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2105 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2107 g_string_free(s, TRUE);
2111 save_cookies (SoupMessage *msg, gpointer user_data){
2115 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2116 cookie = soup_cookie_to_set_cookie_header(ck->data);
2117 SoupURI * soup_uri = soup_message_get_uri(msg);
2118 GString *s = g_string_new ("");
2119 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2120 run_handler(uzbl.behave.cookie_handler, s->str);
2122 g_string_free(s, TRUE);
2127 /* --- WEBINSPECTOR --- */
2129 hide_window_cb(GtkWidget *widget, gpointer data) {
2132 gtk_widget_hide(widget);
2135 static WebKitWebView*
2136 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2139 (void) web_inspector;
2140 GtkWidget* scrolled_window;
2141 GtkWidget* new_web_view;
2144 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2145 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2146 G_CALLBACK(hide_window_cb), NULL);
2148 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2149 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2150 gtk_widget_show(g->inspector_window);
2152 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2153 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2154 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2155 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2156 gtk_widget_show(scrolled_window);
2158 new_web_view = webkit_web_view_new();
2159 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2161 return WEBKIT_WEB_VIEW(new_web_view);
2165 inspector_show_window_cb (WebKitWebInspector* inspector){
2167 gtk_widget_show(uzbl.gui.inspector_window);
2171 /* TODO: Add variables and code to make use of these functions */
2173 inspector_close_window_cb (WebKitWebInspector* inspector){
2179 inspector_attach_window_cb (WebKitWebInspector* inspector){
2185 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2191 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2197 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2203 set_up_inspector() {
2205 WebKitWebSettings *settings = view_settings();
2206 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2208 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2209 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2210 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2211 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2212 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2213 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2214 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2216 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2223 main (int argc, char* argv[]) {
2224 gtk_init (&argc, &argv);
2225 if (!g_thread_supported ())
2226 g_thread_init (NULL);
2227 uzbl.state.executable_path = g_strdup(argv[0]);
2228 uzbl.state.selected_url = NULL;
2229 uzbl.state.searchtx = NULL;
2231 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2232 g_option_context_add_main_entries (context, entries, NULL);
2233 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2234 g_option_context_parse (context, &argc, &argv, NULL);
2235 g_option_context_free(context);
2236 /* initialize hash table */
2237 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2239 uzbl.net.soup_session = webkit_get_default_session();
2240 uzbl.state.keycmd = g_string_new("");
2242 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2243 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2244 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2245 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2246 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2247 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2250 if(uname(&uzbl.state.unameinfo) == -1)
2251 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2253 uzbl.gui.sbar.progress_s = g_strdup("=");
2254 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2255 uzbl.gui.sbar.progress_w = 10;
2257 /* HTML mode defaults*/
2258 uzbl.behave.html_buffer = g_string_new("");
2259 uzbl.behave.html_endmarker = g_strdup(".");
2260 uzbl.behave.html_timeout = 60;
2261 uzbl.behave.base_url = g_strdup("http://invalid");
2266 make_var_to_name_hash();
2268 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2270 uzbl.gui.scrolled_win = create_browser();
2273 /* initial packing */
2274 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2275 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2277 uzbl.gui.main_window = create_window ();
2278 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2281 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2282 gtk_widget_show_all (uzbl.gui.main_window);
2283 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2285 if (uzbl.state.verbose) {
2286 printf("Uzbl start location: %s\n", argv[0]);
2287 printf("window_id %i\n",(int) uzbl.xwin);
2288 printf("pid %i\n", getpid ());
2289 printf("name: %s\n", uzbl.state.instance_name);
2292 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2293 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2294 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2295 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2296 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2300 if (!uzbl.behave.show_status)
2301 gtk_widget_hide(uzbl.gui.mainbar);
2310 if(uzbl.state.uri) {
2311 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2312 g_array_append_val(a, uzbl.state.uri);
2313 load_uri (uzbl.gui.web_view, a);
2314 g_array_free (a, TRUE);
2320 return EXIT_SUCCESS;
2323 /* vi: set et ts=4: */