1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
45 #include <webkit/webkit.h>
53 #include <sys/socket.h>
55 #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 */
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);
1255 cmd_disable_plugins() {
1256 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1257 !uzbl.behave.disable_plugins, NULL);
1261 cmd_disable_scripts() {
1262 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1263 !uzbl.behave.disable_plugins, NULL);
1267 cmd_minimum_font_size() {
1268 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1269 uzbl.behave.minimum_font_size, NULL);
1272 cmd_autoload_img() {
1273 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1274 uzbl.behave.autoload_img, NULL);
1279 cmd_autoshrink_img() {
1280 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1281 uzbl.behave.autoshrink_img, NULL);
1286 cmd_enable_spellcheck() {
1287 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1288 uzbl.behave.enable_spellcheck, NULL);
1292 cmd_enable_private() {
1293 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1294 uzbl.behave.enable_private, NULL);
1299 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1300 uzbl.behave.print_bg, NULL);
1305 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1306 uzbl.behave.style_uri, NULL);
1310 cmd_resizable_txt() {
1311 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1312 uzbl.behave.resizable_txt, NULL);
1316 cmd_default_encoding() {
1317 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1318 uzbl.behave.default_encoding, NULL);
1322 cmd_enforce_96dpi() {
1323 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1324 uzbl.behave.enforce_96dpi, NULL);
1328 cmd_caret_browsing() {
1329 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1330 uzbl.behave.caret_browsing, NULL);
1334 cmd_cookie_handler() {
1335 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1336 if ((g_strcmp0(split[0], "sh") == 0) ||
1337 (g_strcmp0(split[0], "spawn") == 0)) {
1338 g_free (uzbl.behave.cookie_handler);
1339 uzbl.behave.cookie_handler =
1340 g_strdup_printf("sync_%s %s", split[0], split[1]);
1347 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1352 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1357 if(uzbl.behave.inject_html) {
1358 webkit_web_view_load_html_string (uzbl.gui.web_view,
1359 uzbl.behave.inject_html, NULL);
1368 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1369 uzbl.behave.modmask = 0;
1371 if(uzbl.behave.modkey)
1372 g_free(uzbl.behave.modkey);
1373 uzbl.behave.modkey = buf;
1375 for (i = 0; modkeys[i].key != NULL; i++) {
1376 if (g_strrstr(buf, modkeys[i].key))
1377 uzbl.behave.modmask |= modkeys[i].mask;
1383 if (*uzbl.net.useragent == ' ') {
1384 g_free (uzbl.net.useragent);
1385 uzbl.net.useragent = NULL;
1387 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1389 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1390 g_free(uzbl.net.useragent);
1391 uzbl.net.useragent = ua;
1397 gtk_widget_ref(uzbl.gui.scrolled_win);
1398 gtk_widget_ref(uzbl.gui.mainbar);
1399 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1400 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1402 if(uzbl.behave.status_top) {
1403 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1404 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.scrolled_win, TRUE, TRUE, 0);
1408 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1410 gtk_widget_unref(uzbl.gui.scrolled_win);
1411 gtk_widget_unref(uzbl.gui.mainbar);
1412 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1417 set_var_value(gchar *name, gchar *val) {
1418 uzbl_cmdprop *c = NULL;
1421 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1422 /* check for the variable type */
1423 if (c->type == TYPE_STR) {
1425 *c->ptr = g_strdup(val);
1426 } else if(c->type == TYPE_INT) {
1427 int *ip = (int *)c->ptr;
1428 *ip = (int)strtoul(val, &endp, 10);
1431 /* invoke a command specific function */
1432 if(c->func) c->func();
1438 runcmd(WebKitWebView* page, GArray *argv) {
1440 parse_cmd_line(argv_idx(argv, 0));
1445 Behaviour *b = &uzbl.behave;
1447 if(b->html_buffer->str) {
1448 webkit_web_view_load_html_string (uzbl.gui.web_view,
1449 b->html_buffer->str, b->base_url);
1450 g_string_free(b->html_buffer, TRUE);
1451 b->html_buffer = g_string_new("");
1455 enum {M_CMD, M_HTML};
1457 parse_cmd_line(const char *ctl_line) {
1458 gchar **tokens = NULL;
1459 Behaviour *b = &uzbl.behave;
1461 if(b->mode == M_HTML) {
1463 if(!strncmp(b->html_endmarker, ctl_line, strlen(b->html_endmarker))) {
1465 set_var_value("mode", "0");
1470 /* set an alarm to kill us after the timeout */
1471 set_timeout(b->html_timeout);
1472 g_string_append(b->html_buffer, ctl_line);
1477 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1478 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1479 if(tokens[0][0] == 0) {
1480 gchar* value = parseenv(g_strdup(tokens[2]));
1481 set_var_value(tokens[1], value);
1485 printf("Error in command: %s\n", tokens[0]);
1488 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1489 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1490 if(tokens[0][0] == 0) {
1491 get_var_value(tokens[1]);
1494 printf("Error in command: %s\n", tokens[0]);
1497 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1498 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1499 if(tokens[0][0] == 0) {
1500 gchar* value = parseenv(g_strdup(tokens[2]));
1501 add_binding(tokens[1], value);
1505 printf("Error in command: %s\n", tokens[0]);
1508 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1509 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1510 if(tokens[0][0] == 0) {
1511 parse_command(tokens[1], tokens[2]);
1514 printf("Error in command: %s\n", tokens[0]);
1516 /* KEYCMD command */
1517 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1518 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1519 if(tokens[0][0] == 0) {
1520 /* should incremental commands want each individual "keystroke"
1521 sent in a loop or the whole string in one go like now? */
1522 g_string_assign(uzbl.state.keycmd, tokens[1]);
1524 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1530 else if( (ctl_line[0] == '#')
1531 || (ctl_line[0] == ' ')
1532 || (ctl_line[0] == '\n'))
1533 ; /* ignore these lines */
1535 printf("Command not understood (%s)\n", ctl_line);
1545 build_stream_name(int type, const gchar* dir) {
1547 State *s = &uzbl.state;
1550 xwin_str = itos((int)uzbl.xwin);
1552 str = g_strdup_printf
1553 ("%s/uzbl_fifo_%s", dir,
1554 s->instance_name ? s->instance_name : xwin_str);
1555 } else if (type == SOCKET) {
1556 str = g_strdup_printf
1557 ("%s/uzbl_socket_%s", dir,
1558 s->instance_name ? s->instance_name : xwin_str );
1565 control_fifo(GIOChannel *gio, GIOCondition condition) {
1566 if (uzbl.state.verbose)
1567 printf("triggered\n");
1572 if (condition & G_IO_HUP)
1573 g_error ("Fifo: Read end of pipe died!\n");
1576 g_error ("Fifo: GIOChannel broke\n");
1578 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1579 if (ret == G_IO_STATUS_ERROR) {
1580 g_error ("Fifo: Error reading: %s\n", err->message);
1584 parse_cmd_line(ctl_line);
1591 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1592 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1593 if (unlink(uzbl.comm.fifo_path) == -1)
1594 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1595 g_free(uzbl.comm.fifo_path);
1596 uzbl.comm.fifo_path = NULL;
1599 if (*dir == ' ') { /* space unsets the variable */
1604 GIOChannel *chan = NULL;
1605 GError *error = NULL;
1606 gchar *path = build_stream_name(FIFO, dir);
1608 if (!file_exists(path)) {
1609 if (mkfifo (path, 0666) == 0) {
1610 // 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.
1611 chan = g_io_channel_new_file(path, "r+", &error);
1613 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1614 if (uzbl.state.verbose)
1615 printf ("init_fifo: created successfully as %s\n", path);
1616 uzbl.comm.fifo_path = path;
1618 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1619 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1620 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1621 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1623 /* if we got this far, there was an error; cleanup */
1624 if (error) g_error_free (error);
1631 control_stdin(GIOChannel *gio, GIOCondition condition) {
1633 gchar *ctl_line = NULL;
1636 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1637 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1640 parse_cmd_line(ctl_line);
1648 GIOChannel *chan = NULL;
1649 GError *error = NULL;
1651 chan = g_io_channel_unix_new(fileno(stdin));
1653 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1654 g_error ("Stdin: could not add watch\n");
1656 if (uzbl.state.verbose)
1657 printf ("Stdin: watch added successfully\n");
1660 g_error ("Stdin: Error while opening: %s\n", error->message);
1662 if (error) g_error_free (error);
1666 control_socket(GIOChannel *chan) {
1667 struct sockaddr_un remote;
1668 char buffer[512], *ctl_line;
1670 int sock, clientsock, n, done;
1673 sock = g_io_channel_unix_get_fd(chan);
1675 memset (buffer, 0, sizeof (buffer));
1677 t = sizeof (remote);
1678 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1682 memset (temp, 0, sizeof (temp));
1683 n = recv (clientsock, temp, 128, 0);
1685 buffer[strlen (buffer)] = '\0';
1689 strcat (buffer, temp);
1692 if (strcmp (buffer, "\n") < 0) {
1693 buffer[strlen (buffer) - 1] = '\0';
1695 buffer[strlen (buffer)] = '\0';
1698 ctl_line = g_strdup(buffer);
1699 parse_cmd_line (ctl_line);
1702 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1703 GError *error = NULL;
1706 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1707 if (ret == G_IO_STATUS_ERROR)
1708 g_error ("Error reading: %s\n", error->message);
1710 printf("Got line %s (%u bytes) \n",ctl_line, len);
1712 parse_line(ctl_line);
1720 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1721 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1722 if (unlink(uzbl.comm.socket_path) == -1)
1723 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1724 g_free(uzbl.comm.socket_path);
1725 uzbl.comm.socket_path = NULL;
1733 GIOChannel *chan = NULL;
1735 struct sockaddr_un local;
1736 gchar *path = build_stream_name(SOCKET, dir);
1738 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1740 local.sun_family = AF_UNIX;
1741 strcpy (local.sun_path, path);
1742 unlink (local.sun_path);
1744 len = strlen (local.sun_path) + sizeof (local.sun_family);
1745 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1746 if (uzbl.state.verbose)
1747 printf ("init_socket: opened in %s\n", path);
1750 if( (chan = g_io_channel_unix_new(sock)) ) {
1751 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1752 uzbl.comm.socket_path = path;
1755 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1757 /* if we got this far, there was an error; cleanup */
1764 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1765 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1767 // this function may be called very early when the templates are not set (yet), hence the checks
1769 update_title (void) {
1770 Behaviour *b = &uzbl.behave;
1773 if (b->show_status) {
1774 if (b->title_format_short) {
1775 parsed = expand_template(b->title_format_short, FALSE);
1776 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1779 if (b->status_format) {
1780 parsed = expand_template(b->status_format, TRUE);
1781 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1784 if (b->status_background) {
1786 gdk_color_parse (b->status_background, &color);
1787 //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)
1788 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1791 if (b->title_format_long) {
1792 parsed = expand_template(b->title_format_long, FALSE);
1793 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1800 key_press_cb (GtkWidget* window, GdkEventKey* event)
1802 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1806 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1807 || 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)
1810 /* turn off insert mode (if always_insert_mode is not used) */
1811 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1812 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1817 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1820 if (event->keyval == GDK_Escape) {
1821 g_string_truncate(uzbl.state.keycmd, 0);
1823 dehilight(uzbl.gui.web_view, NULL);
1827 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1828 if (event->keyval == GDK_Insert) {
1830 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1831 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1833 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1836 g_string_append (uzbl.state.keycmd, str);
1843 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1844 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1848 gboolean key_ret = FALSE;
1849 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1851 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1853 run_keycmd(key_ret);
1855 if (key_ret) return (!uzbl.behave.insert_mode);
1860 run_keycmd(const gboolean key_ret) {
1861 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1863 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1864 g_string_truncate(uzbl.state.keycmd, 0);
1865 parse_command(act->name, act->param);
1869 /* try if it's an incremental keycmd or one that takes args, and run it */
1870 GString* short_keys = g_string_new ("");
1871 GString* short_keys_inc = g_string_new ("");
1873 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1874 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1875 g_string_assign(short_keys_inc, short_keys->str);
1876 g_string_append_c(short_keys, '_');
1877 g_string_append_c(short_keys_inc, '*');
1879 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1880 /* run normal cmds only if return was pressed */
1881 exec_paramcmd(act, i);
1882 g_string_truncate(uzbl.state.keycmd, 0);
1884 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1885 if (key_ret) /* just quit the incremental command on return */
1886 g_string_truncate(uzbl.state.keycmd, 0);
1887 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1891 g_string_truncate(short_keys, short_keys->len - 1);
1893 g_string_free (short_keys, TRUE);
1894 g_string_free (short_keys_inc, TRUE);
1898 exec_paramcmd(const Action *act, const guint i) {
1899 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1900 GString *actionname = g_string_new ("");
1901 GString *actionparam = g_string_new ("");
1902 g_string_erase (parampart, 0, i+1);
1904 g_string_printf (actionname, act->name, parampart->str);
1906 g_string_printf (actionparam, act->param, parampart->str);
1907 parse_command(actionname->str, actionparam->str);
1908 g_string_free(actionname, TRUE);
1909 g_string_free(actionparam, TRUE);
1910 g_string_free(parampart, TRUE);
1918 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1919 //main_window_ref = g_object_ref(scrolled_window);
1920 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
1922 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1923 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1925 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1926 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1927 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1928 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1929 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1930 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1931 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1932 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1933 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1934 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1936 return scrolled_window;
1943 g->mainbar = gtk_hbox_new (FALSE, 0);
1945 /* keep a reference to the bar so we can re-pack it at runtime*/
1946 //sbar_ref = g_object_ref(g->mainbar);
1948 g->mainbar_label = gtk_label_new ("");
1949 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1950 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1951 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1952 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1953 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1958 GtkWidget* create_window () {
1959 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1960 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1961 gtk_widget_set_name (window, "Uzbl browser");
1962 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1963 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1969 run_handler (const gchar *act, const gchar *args) {
1970 char **parts = g_strsplit(act, " ", 2);
1972 else if ((g_strcmp0(parts[0], "spawn") == 0)
1973 || (g_strcmp0(parts[0], "sh") == 0)
1974 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1975 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1977 GString *a = g_string_new ("");
1979 spawnparts = split_quoted(parts[1], FALSE);
1980 g_string_append_printf(a, "%s", spawnparts[0]);
1981 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1983 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1984 g_string_append_printf(a, " %s", spawnparts[i]);
1985 parse_command(parts[0], a->str);
1986 g_string_free (a, TRUE);
1987 g_strfreev (spawnparts);
1989 parse_command(parts[0], parts[1]);
1994 add_binding (const gchar *key, const gchar *act) {
1995 char **parts = g_strsplit(act, " ", 2);
2002 if (uzbl.state.verbose)
2003 printf ("Binding %-10s : %s\n", key, act);
2004 action = new_action(parts[0], parts[1]);
2006 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2011 get_xdg_var (XDG_Var xdg) {
2012 const gchar* actual_value = getenv (xdg.environmental);
2013 const gchar* home = getenv ("HOME");
2015 gchar* return_value = str_replace ("~", home, actual_value);
2017 if (! actual_value || strcmp (actual_value, "") == 0) {
2018 if (xdg.default_value) {
2019 return_value = str_replace ("~", home, xdg.default_value);
2021 return_value = NULL;
2024 return return_value;
2028 find_xdg_file (int xdg_type, char* filename) {
2029 /* xdg_type = 0 => config
2030 xdg_type = 1 => data
2031 xdg_type = 2 => cache*/
2033 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2034 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2037 gchar* temporary_string;
2041 if (! file_exists (temporary_file) && xdg_type != 2) {
2042 buf = get_xdg_var (XDG[3 + xdg_type]);
2043 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2046 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2047 g_free (temporary_file);
2048 temporary_file = g_strconcat (temporary_string, filename, NULL);
2052 //g_free (temporary_string); - segfaults.
2054 if (file_exists (temporary_file)) {
2055 return temporary_file;
2062 State *s = &uzbl.state;
2063 Network *n = &uzbl.net;
2065 for (i = 0; default_config[i].command != NULL; i++) {
2066 parse_cmd_line(default_config[i].command);
2069 if (!s->config_file) {
2070 s->config_file = find_xdg_file (0, "/uzbl/config");
2073 if (s->config_file) {
2074 GArray* lines = read_file_by_line (s->config_file);
2078 while ((line = g_array_index(lines, gchar*, i))) {
2079 parse_cmd_line (line);
2083 g_array_free (lines, TRUE);
2085 if (uzbl.state.verbose)
2086 printf ("No configuration file loaded.\n");
2089 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2092 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2095 if (!uzbl.behave.cookie_handler) return;
2097 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2098 GString *s = g_string_new ("");
2099 SoupURI * soup_uri = soup_message_get_uri(msg);
2100 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2101 run_handler(uzbl.behave.cookie_handler, s->str);
2103 if(uzbl.comm.sync_stdout)
2104 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2105 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2106 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2108 g_string_free(s, TRUE);
2112 save_cookies (SoupMessage *msg, gpointer user_data){
2116 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2117 cookie = soup_cookie_to_set_cookie_header(ck->data);
2118 SoupURI * soup_uri = soup_message_get_uri(msg);
2119 GString *s = g_string_new ("");
2120 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2121 run_handler(uzbl.behave.cookie_handler, s->str);
2123 g_string_free(s, TRUE);
2128 /* --- WEBINSPECTOR --- */
2130 hide_window_cb(GtkWidget *widget, gpointer data) {
2133 gtk_widget_hide(widget);
2136 static WebKitWebView*
2137 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2140 (void) web_inspector;
2141 GtkWidget* scrolled_window;
2142 GtkWidget* new_web_view;
2145 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2146 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2147 G_CALLBACK(hide_window_cb), NULL);
2149 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2150 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2151 gtk_widget_show(g->inspector_window);
2153 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2154 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2155 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2156 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2157 gtk_widget_show(scrolled_window);
2159 new_web_view = webkit_web_view_new();
2160 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2162 return WEBKIT_WEB_VIEW(new_web_view);
2166 inspector_show_window_cb (WebKitWebInspector* inspector){
2168 gtk_widget_show(uzbl.gui.inspector_window);
2172 /* TODO: Add variables and code to make use of these functions */
2174 inspector_close_window_cb (WebKitWebInspector* inspector){
2180 inspector_attach_window_cb (WebKitWebInspector* inspector){
2186 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2192 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2198 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2204 set_up_inspector() {
2206 WebKitWebSettings *settings = webkit_web_settings_new();
2207 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2208 webkit_web_view_set_settings(WEBKIT_WEB_VIEW(uzbl.gui.web_view), settings);
2211 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2212 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2213 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2214 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2215 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2216 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2217 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2219 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2226 main (int argc, char* argv[]) {
2227 gtk_init (&argc, &argv);
2228 if (!g_thread_supported ())
2229 g_thread_init (NULL);
2230 uzbl.state.executable_path = g_strdup(argv[0]);
2231 uzbl.state.selected_url = NULL;
2232 uzbl.state.searchtx = NULL;
2234 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2235 g_option_context_add_main_entries (context, entries, NULL);
2236 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2237 g_option_context_parse (context, &argc, &argv, NULL);
2238 g_option_context_free(context);
2239 /* initialize hash table */
2240 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2242 uzbl.net.soup_session = webkit_get_default_session();
2243 uzbl.state.keycmd = g_string_new("");
2245 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2246 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2247 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2248 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2249 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2250 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2253 if(uname(&uzbl.state.unameinfo) == -1)
2254 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2256 uzbl.gui.sbar.progress_s = g_strdup("=");
2257 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2258 uzbl.gui.sbar.progress_w = 10;
2260 /* HTML mode defaults*/
2261 uzbl.behave.html_buffer = g_string_new("");
2262 uzbl.behave.html_endmarker = g_strdup(".");
2263 uzbl.behave.html_timeout = 60;
2264 uzbl.behave.base_url = g_strdup("http://invalid");
2269 make_var_to_name_hash();
2271 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2273 uzbl.gui.scrolled_win = create_browser();
2276 /* initial packing */
2277 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2278 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2280 uzbl.gui.main_window = create_window ();
2281 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2284 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2285 gtk_widget_show_all (uzbl.gui.main_window);
2286 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2288 if (uzbl.state.verbose) {
2289 printf("Uzbl start location: %s\n", argv[0]);
2290 printf("window_id %i\n",(int) uzbl.xwin);
2291 printf("pid %i\n", getpid ());
2292 printf("name: %s\n", uzbl.state.instance_name);
2295 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2296 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2297 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2298 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2299 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2303 if (!uzbl.behave.show_status)
2304 gtk_widget_hide(uzbl.gui.mainbar);
2313 if(uzbl.state.uri) {
2314 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2315 g_array_append_val(a, uzbl.state.uri);
2316 load_uri (uzbl.gui.web_view, a);
2317 g_array_free (a, TRUE);
2323 return EXIT_SUCCESS;
2326 /* vi: set et ts=4: */