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 {
88 enum {TYPE_INT, TYPE_STR};
90 /* an abbreviation to help keep the table's width humane */
91 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d,.func = fun }
96 } var_name_to_ptr[] = {
97 /* variable name pointer to variable in code type dump callback function */
98 /* --------------------------------------------------------------------------------------- */
99 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
114 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
115 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
116 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
117 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
118 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
119 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
120 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
121 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
122 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
123 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
124 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
125 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
126 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
127 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
128 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
129 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
130 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
131 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
132 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
133 /* exported WebKitWebSettings properties*/
134 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
135 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
136 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
137 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
138 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
139 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
140 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
141 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
142 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
143 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
144 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
145 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
146 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
147 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
148 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
150 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
151 }, *n2v_p = var_name_to_ptr;
157 { "SHIFT", GDK_SHIFT_MASK }, // shift
158 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
159 { "CONTROL", GDK_CONTROL_MASK }, // control
160 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
161 { "MOD2", GDK_MOD2_MASK }, // 5th mod
162 { "MOD3", GDK_MOD3_MASK }, // 6th mod
163 { "MOD4", GDK_MOD4_MASK }, // 7th mod
164 { "MOD5", GDK_MOD5_MASK }, // 8th mod
165 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
166 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
167 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
168 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
169 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
170 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
171 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
172 { "META", GDK_META_MASK }, // meta (since 2.10)
177 /* construct a hash from the var_name_to_ptr array for quick access */
179 make_var_to_name_hash() {
180 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
182 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
188 /* --- UTILITY FUNCTIONS --- */
194 snprintf(tmp, sizeof(tmp), "%i", val);
195 return g_strdup(tmp);
199 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
202 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
205 str_replace (const char* search, const char* replace, const char* string) {
209 buf = g_strsplit (string, search, -1);
210 ret = g_strjoinv (replace, buf);
211 g_strfreev(buf); // somebody said this segfaults
217 read_file_by_line (gchar *path) {
218 GIOChannel *chan = NULL;
219 gchar *readbuf = NULL;
221 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
224 chan = g_io_channel_new_file(path, "r", NULL);
227 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
228 const gchar* val = g_strdup (readbuf);
229 g_array_append_val (lines, val);
234 g_io_channel_unref (chan);
236 fprintf(stderr, "File '%s' not be read.\n", path);
243 gchar* parseenv (char* string) {
244 extern char** environ;
245 gchar* tmpstr = NULL;
249 while (environ[i] != NULL) {
250 gchar** env = g_strsplit (environ[i], "=", 2);
251 gchar* envname = g_strconcat ("$", env[0], NULL);
253 if (g_strrstr (string, envname) != NULL) {
254 tmpstr = g_strdup(string);
256 string = str_replace(envname, env[1], tmpstr);
261 g_strfreev (env); // somebody said this breaks uzbl
269 setup_signal(int signr, sigfunc *shandler) {
270 struct sigaction nh, oh;
272 nh.sa_handler = shandler;
273 sigemptyset(&nh.sa_mask);
276 if(sigaction(signr, &nh, &oh) < 0)
284 if (uzbl.behave.fifo_dir)
285 unlink (uzbl.comm.fifo_path);
286 if (uzbl.behave.socket_dir)
287 unlink (uzbl.comm.socket_path);
289 g_free(uzbl.state.executable_path);
290 g_string_free(uzbl.state.keycmd, TRUE);
291 g_hash_table_destroy(uzbl.bindings);
292 g_hash_table_destroy(uzbl.behave.commands);
295 /* used for html_mode_timeout
296 * be sure to extend this function to use
297 * more timers if needed in other places
300 set_timeout(int seconds) {
302 memset(&t, 0, sizeof t);
304 t.it_value.tv_sec = seconds;
305 t.it_value.tv_usec = 0;
306 setitimer(ITIMER_REAL, &t, NULL);
309 /* --- SIGNAL HANDLER --- */
312 catch_sigterm(int s) {
318 catch_sigint(int s) {
328 set_var_value("mode", "0");
333 /* --- CALLBACKS --- */
336 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
339 (void) navigation_action;
340 (void) policy_decision;
342 const gchar* uri = webkit_network_request_get_uri (request);
343 if (uzbl.state.verbose)
344 printf("New window requested -> %s \n", uri);
345 new_window_load_uri(uri);
350 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
354 if (uzbl.state.selected_url != NULL) {
355 if (uzbl.state.verbose)
356 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
357 new_window_load_uri(uzbl.state.selected_url);
359 if (uzbl.state.verbose)
360 printf("New web view -> %s\n","Nothing to open, exiting");
366 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
369 if (uzbl.behave.download_handler) {
370 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
371 if (uzbl.state.verbose)
372 printf("Download -> %s\n",uri);
373 /* if urls not escaped, we may have to escape and quote uri before this call */
374 run_handler(uzbl.behave.download_handler, uri);
379 /* scroll a bar in a given direction */
381 scroll (GtkAdjustment* bar, GArray *argv) {
385 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
386 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
387 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
391 scroll_begin(WebKitWebView* page, GArray *argv) {
392 (void) page; (void) argv;
393 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
397 scroll_end(WebKitWebView* page, GArray *argv) {
398 (void) page; (void) argv;
399 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
400 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
404 scroll_vert(WebKitWebView* page, GArray *argv) {
406 scroll(uzbl.gui.bar_v, argv);
410 scroll_horz(WebKitWebView* page, GArray *argv) {
412 scroll(uzbl.gui.bar_h, argv);
417 if (!uzbl.behave.show_status) {
418 gtk_widget_hide(uzbl.gui.mainbar);
420 gtk_widget_show(uzbl.gui.mainbar);
426 toggle_status_cb (WebKitWebView* page, GArray *argv) {
430 if (uzbl.behave.show_status) {
431 gtk_widget_hide(uzbl.gui.mainbar);
433 gtk_widget_show(uzbl.gui.mainbar);
435 uzbl.behave.show_status = !uzbl.behave.show_status;
440 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
444 //Set selected_url state variable
445 g_free(uzbl.state.selected_url);
446 uzbl.state.selected_url = NULL;
448 uzbl.state.selected_url = g_strdup(link);
454 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
458 if (uzbl.gui.main_title)
459 g_free (uzbl.gui.main_title);
460 uzbl.gui.main_title = g_strdup (title);
465 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
468 uzbl.gui.sbar.load_progress = progress;
473 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
477 if (uzbl.behave.load_finish_handler)
478 run_handler(uzbl.behave.load_finish_handler, "");
482 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
486 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
487 if (uzbl.behave.load_start_handler)
488 run_handler(uzbl.behave.load_start_handler, "");
492 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
495 g_free (uzbl.state.uri);
496 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
497 uzbl.state.uri = g_string_free (newuri, FALSE);
498 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
499 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
502 if (uzbl.behave.load_commit_handler)
503 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
507 destroy_cb (GtkWidget* widget, gpointer data) {
515 if (uzbl.behave.history_handler) {
517 struct tm * timeinfo;
520 timeinfo = localtime ( &rawtime );
521 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
522 run_handler(uzbl.behave.history_handler, date);
527 /* VIEW funcs (little webkit wrappers) */
528 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
530 VIEWFUNC(reload_bypass_cache)
531 VIEWFUNC(stop_loading)
538 /* -- command to callback/function map for things we cannot attach to any signals */
540 static struct {char *name; Command command[2];} cmdlist[] =
541 { /* key function no_split */
542 { "back", {view_go_back, 0} },
543 { "forward", {view_go_forward, 0} },
544 { "scroll_vert", {scroll_vert, 0} },
545 { "scroll_horz", {scroll_horz, 0} },
546 { "scroll_begin", {scroll_begin, 0} },
547 { "scroll_end", {scroll_end, 0} },
548 { "reload", {view_reload, 0}, },
549 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
550 { "stop", {view_stop_loading, 0}, },
551 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
552 { "zoom_out", {view_zoom_out, 0}, },
553 { "uri", {load_uri, NOSPLIT} },
554 { "js", {run_js, NOSPLIT} },
555 { "script", {run_external_js, 0} },
556 { "toggle_status", {toggle_status_cb, 0} },
557 { "spawn", {spawn, 0} },
558 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
559 { "sh", {spawn_sh, 0} },
560 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
561 { "exit", {close_uzbl, 0} },
562 { "search", {search_forward_text, NOSPLIT} },
563 { "search_reverse", {search_reverse_text, NOSPLIT} },
564 { "dehilight", {dehilight, 0} },
565 { "toggle_insert_mode", {toggle_insert_mode, 0} },
566 { "runcmd", {runcmd, NOSPLIT} },
567 { "set", {set_var, NOSPLIT} },
568 { "dump_config", {act_dump_config, 0} }
575 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
577 for (i = 0; i < LENGTH(cmdlist); i++)
578 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
581 /* -- CORE FUNCTIONS -- */
584 free_action(gpointer act) {
585 Action *action = (Action*)act;
586 g_free(action->name);
588 g_free(action->param);
593 new_action(const gchar *name, const gchar *param) {
594 Action *action = g_new(Action, 1);
596 action->name = g_strdup(name);
598 action->param = g_strdup(param);
600 action->param = NULL;
606 file_exists (const char * filename) {
607 return (access(filename, F_OK) == 0);
611 set_var(WebKitWebView *page, GArray *argv) {
615 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
616 parse_cmd_line(ctl_line);
626 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
629 if (argv_idx(argv, 0)) {
630 if (strcmp (argv_idx(argv, 0), "0") == 0) {
631 uzbl.behave.insert_mode = FALSE;
633 uzbl.behave.insert_mode = TRUE;
636 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
643 load_uri (WebKitWebView *web_view, GArray *argv) {
644 if (argv_idx(argv, 0)) {
645 GString* newuri = g_string_new (argv_idx(argv, 0));
646 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
647 g_string_prepend (newuri, "http://");
648 /* if we do handle cookies, ask our handler for them */
649 webkit_web_view_load_uri (web_view, newuri->str);
650 g_string_free (newuri, TRUE);
655 run_js (WebKitWebView * web_view, GArray *argv) {
656 if (argv_idx(argv, 0))
657 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
661 run_external_js (WebKitWebView * web_view, GArray *argv) {
662 if (argv_idx(argv, 0)) {
663 GArray* lines = read_file_by_line (argv_idx (argv, 0));
668 while ((line = g_array_index(lines, gchar*, i))) {
670 js = g_strdup (line);
672 gchar* newjs = g_strconcat (js, line, NULL);
679 if (uzbl.state.verbose)
680 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
682 if (argv_idx (argv, 1)) {
683 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
687 webkit_web_view_execute_script (web_view, js);
689 g_array_free (lines, TRUE);
694 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
695 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
696 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
697 webkit_web_view_unmark_text_matches (page);
698 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
699 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
703 if (uzbl.state.searchtx) {
704 if (uzbl.state.verbose)
705 printf ("Searching: %s\n", uzbl.state.searchtx);
706 webkit_web_view_set_highlight_text_matches (page, TRUE);
707 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
712 search_forward_text (WebKitWebView *page, GArray *argv) {
713 search_text(page, argv, TRUE);
717 search_reverse_text (WebKitWebView *page, GArray *argv) {
718 search_text(page, argv, FALSE);
722 dehilight (WebKitWebView *page, GArray *argv) {
724 webkit_web_view_set_highlight_text_matches (page, FALSE);
729 new_window_load_uri (const gchar * uri) {
730 GString* to_execute = g_string_new ("");
731 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
733 for (i = 0; entries[i].long_name != NULL; i++) {
734 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
735 gchar** str = (gchar**)entries[i].arg_data;
737 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
741 if (uzbl.state.verbose)
742 printf("\n%s\n", to_execute->str);
743 g_spawn_command_line_async (to_execute->str, NULL);
744 g_string_free (to_execute, TRUE);
748 close_uzbl (WebKitWebView *page, GArray *argv) {
754 /* --Statusbar functions-- */
756 build_progressbar_ascii(int percent) {
757 int width=uzbl.gui.sbar.progress_w;
760 GString *bar = g_string_new("");
762 l = (double)percent*((double)width/100.);
763 l = (int)(l+.5)>=(int)l ? l+.5 : l;
765 for(i=0; i<(int)l; i++)
766 g_string_append(bar, uzbl.gui.sbar.progress_s);
769 g_string_append(bar, uzbl.gui.sbar.progress_u);
771 return g_string_free(bar, FALSE);
776 const GScannerConfig scan_config = {
779 ) /* cset_skip_characters */,
784 ) /* cset_identifier_first */,
791 ) /* cset_identifier_nth */,
792 ( "" ) /* cpair_comment_single */,
794 TRUE /* case_sensitive */,
796 FALSE /* skip_comment_multi */,
797 FALSE /* skip_comment_single */,
798 FALSE /* scan_comment_multi */,
799 TRUE /* scan_identifier */,
800 TRUE /* scan_identifier_1char */,
801 FALSE /* scan_identifier_NULL */,
802 TRUE /* scan_symbols */,
803 FALSE /* scan_binary */,
804 FALSE /* scan_octal */,
805 FALSE /* scan_float */,
806 FALSE /* scan_hex */,
807 FALSE /* scan_hex_dollar */,
808 FALSE /* scan_string_sq */,
809 FALSE /* scan_string_dq */,
810 TRUE /* numbers_2_int */,
811 FALSE /* int_2_float */,
812 FALSE /* identifier_2_string */,
813 FALSE /* char_2_token */,
814 FALSE /* symbol_2_token */,
815 TRUE /* scope_0_fallback */,
820 uzbl.scan = g_scanner_new(&scan_config);
821 while(symp->symbol_name) {
822 g_scanner_scope_add_symbol(uzbl.scan, 0,
824 GINT_TO_POINTER(symp->symbol_token));
830 expand_template(const char *template, gboolean escape_markup) {
831 if(!template) return NULL;
833 GTokenType token = G_TOKEN_NONE;
834 GString *ret = g_string_new("");
838 g_scanner_input_text(uzbl.scan, template, strlen(template));
839 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
840 token = g_scanner_get_next_token(uzbl.scan);
842 if(token == G_TOKEN_SYMBOL) {
843 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
847 buf = uzbl.state.uri?
848 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
849 g_string_append(ret, buf);
853 g_string_append(ret, uzbl.state.uri?
854 uzbl.state.uri:g_strdup(""));
857 buf = itos(uzbl.gui.sbar.load_progress);
858 g_string_append(ret, buf);
861 case SYM_LOADPRGSBAR:
862 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
863 g_string_append(ret, buf);
868 buf = uzbl.gui.main_title?
869 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
870 g_string_append(ret, buf);
874 g_string_append(ret, uzbl.gui.main_title?
875 uzbl.gui.main_title:g_strdup(""));
877 case SYM_SELECTED_URI:
879 buf = uzbl.state.selected_url?
880 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
881 g_string_append(ret, buf);
885 g_string_append(ret, uzbl.state.selected_url?
886 uzbl.state.selected_url:g_strdup(""));
889 buf = itos(uzbl.xwin);
891 uzbl.state.instance_name?uzbl.state.instance_name:buf);
896 buf = uzbl.state.keycmd->str?
897 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
898 g_string_append(ret, buf);
902 g_string_append(ret, uzbl.state.keycmd->str?
903 uzbl.state.keycmd->str:g_strdup(""));
907 uzbl.behave.insert_mode?"[I]":"[C]");
911 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
915 buf = itos(WEBKIT_MAJOR_VERSION);
916 g_string_append(ret, buf);
920 buf = itos(WEBKIT_MINOR_VERSION);
921 g_string_append(ret, buf);
925 buf = itos(WEBKIT_MICRO_VERSION);
926 g_string_append(ret, buf);
930 g_string_append(ret, uzbl.state.unameinfo.sysname);
933 g_string_append(ret, uzbl.state.unameinfo.nodename);
936 g_string_append(ret, uzbl.state.unameinfo.release);
939 g_string_append(ret, uzbl.state.unameinfo.version);
942 g_string_append(ret, uzbl.state.unameinfo.machine);
945 g_string_append(ret, ARCH);
949 g_string_append(ret, uzbl.state.unameinfo.domainname);
953 g_string_append(ret, COMMIT);
959 else if(token == G_TOKEN_INT) {
960 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
961 g_string_append(ret, buf);
964 else if(token == G_TOKEN_IDENTIFIER) {
965 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
967 else if(token == G_TOKEN_CHAR) {
968 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
972 return g_string_free(ret, FALSE);
974 /* --End Statusbar functions-- */
977 sharg_append(GArray *a, const gchar *str) {
978 const gchar *s = (str ? str : "");
979 g_array_append_val(a, s);
982 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
984 run_command (const gchar *command, const guint npre, const gchar **args,
985 const gboolean sync, char **stdout) {
986 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
989 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
990 gchar *pid = itos(getpid());
991 gchar *xwin = itos(uzbl.xwin);
993 sharg_append(a, command);
994 for (i = 0; i < npre; i++) /* add n args before the default vars */
995 sharg_append(a, args[i]);
996 sharg_append(a, uzbl.state.config_file);
997 sharg_append(a, pid);
998 sharg_append(a, xwin);
999 sharg_append(a, uzbl.comm.fifo_path);
1000 sharg_append(a, uzbl.comm.socket_path);
1001 sharg_append(a, uzbl.state.uri);
1002 sharg_append(a, uzbl.gui.main_title);
1004 for (i = npre; i < g_strv_length((gchar**)args); i++)
1005 sharg_append(a, args[i]);
1009 if (*stdout) *stdout = strfree(*stdout);
1011 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1012 NULL, NULL, stdout, NULL, NULL, &err);
1013 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1014 NULL, NULL, NULL, &err);
1016 if (uzbl.state.verbose) {
1017 GString *s = g_string_new("spawned:");
1018 for (i = 0; i < (a->len); i++) {
1019 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1020 g_string_append_printf(s, " %s", qarg);
1023 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1024 printf("%s\n", s->str);
1025 g_string_free(s, TRUE);
1028 g_printerr("error on run_command: %s\n", err->message);
1033 g_array_free (a, TRUE);
1038 split_quoted(const gchar* src, const gboolean unquote) {
1039 /* split on unquoted space, return array of strings;
1040 remove a layer of quotes and backslashes if unquote */
1041 if (!src) return NULL;
1043 gboolean dq = FALSE;
1044 gboolean sq = FALSE;
1045 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1046 GString *s = g_string_new ("");
1050 for (p = src; *p != '\0'; p++) {
1051 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1052 else if (*p == '\\') { g_string_append_c(s, *p++);
1053 g_string_append_c(s, *p); }
1054 else if ((*p == '"') && unquote && !sq) dq = !dq;
1055 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1057 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1058 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1060 else if ((*p == ' ') && !dq && !sq) {
1061 dup = g_strdup(s->str);
1062 g_array_append_val(a, dup);
1063 g_string_truncate(s, 0);
1064 } else g_string_append_c(s, *p);
1066 dup = g_strdup(s->str);
1067 g_array_append_val(a, dup);
1068 ret = (gchar**)a->data;
1069 g_array_free (a, FALSE);
1070 g_string_free (s, TRUE);
1075 spawn(WebKitWebView *web_view, GArray *argv) {
1077 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1078 if (argv_idx(argv, 0))
1079 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1083 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1086 if (argv_idx(argv, 0))
1087 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1088 TRUE, &uzbl.comm.sync_stdout);
1092 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1094 if (!uzbl.behave.shell_cmd) {
1095 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1100 gchar *spacer = g_strdup("");
1101 g_array_insert_val(argv, 1, spacer);
1102 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1104 for (i = 1; i < g_strv_length(cmd); i++)
1105 g_array_prepend_val(argv, cmd[i]);
1107 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1113 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1115 if (!uzbl.behave.shell_cmd) {
1116 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1121 gchar *spacer = g_strdup("");
1122 g_array_insert_val(argv, 1, spacer);
1123 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1125 for (i = 1; i < g_strv_length(cmd); i++)
1126 g_array_prepend_val(argv, cmd[i]);
1128 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1129 TRUE, &uzbl.comm.sync_stdout);
1135 parse_command(const char *cmd, const char *param) {
1138 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1141 gchar **par = split_quoted(param, TRUE);
1142 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1144 if (c[1] == NOSPLIT) { /* don't split */
1145 sharg_append(a, param);
1147 for (i = 0; i < g_strv_length(par); i++)
1148 sharg_append(a, par[i]);
1150 c[0](uzbl.gui.web_view, a);
1152 g_array_free (a, TRUE);
1155 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1158 /* command parser */
1161 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1162 G_REGEX_OPTIMIZE, 0, NULL);
1163 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1164 G_REGEX_OPTIMIZE, 0, NULL);
1165 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1166 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1167 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1168 G_REGEX_OPTIMIZE, 0, NULL);
1169 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1170 G_REGEX_OPTIMIZE, 0, NULL);
1174 get_var_value(gchar *name) {
1177 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1178 if(c->type == TYPE_STR)
1179 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1180 else if(c->type == TYPE_INT)
1181 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1190 if(*uzbl.net.proxy_url == ' '
1191 || uzbl.net.proxy_url == NULL) {
1192 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1193 (GType) SOUP_SESSION_PROXY_URI);
1196 suri = soup_uri_new(uzbl.net.proxy_url);
1197 g_object_set(G_OBJECT(uzbl.net.soup_session),
1198 SOUP_SESSION_PROXY_URI,
1200 soup_uri_free(suri);
1207 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1208 g_array_append_val (a, uzbl.state.uri);
1209 load_uri(uzbl.gui.web_view, a);
1210 g_array_free (a, TRUE);
1214 cmd_always_insert_mode() {
1215 uzbl.behave.insert_mode =
1216 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1222 g_object_set(G_OBJECT(uzbl.net.soup_session),
1223 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1227 cmd_max_conns_host() {
1228 g_object_set(G_OBJECT(uzbl.net.soup_session),
1229 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1234 soup_session_remove_feature
1235 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1236 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1237 /*g_free(uzbl.net.soup_logger);*/
1239 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1240 soup_session_add_feature(uzbl.net.soup_session,
1241 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1244 static WebKitWebSettings*
1246 return webkit_web_view_get_settings(uzbl.gui.web_view);
1251 WebKitWebSettings *ws = view_settings();
1252 if (uzbl.behave.font_size > 0) {
1253 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1256 if (uzbl.behave.monospace_size > 0) {
1257 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1258 uzbl.behave.monospace_size, NULL);
1260 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1261 uzbl.behave.font_size, NULL);
1266 cmd_disable_plugins() {
1267 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1268 !uzbl.behave.disable_plugins, NULL);
1272 cmd_disable_scripts() {
1273 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1274 !uzbl.behave.disable_plugins, NULL);
1278 cmd_minimum_font_size() {
1279 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1280 uzbl.behave.minimum_font_size, NULL);
1283 cmd_autoload_img() {
1284 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1285 uzbl.behave.autoload_img, NULL);
1290 cmd_autoshrink_img() {
1291 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1292 uzbl.behave.autoshrink_img, NULL);
1297 cmd_enable_spellcheck() {
1298 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1299 uzbl.behave.enable_spellcheck, NULL);
1303 cmd_enable_private() {
1304 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1305 uzbl.behave.enable_private, NULL);
1310 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1311 uzbl.behave.print_bg, NULL);
1316 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1317 uzbl.behave.style_uri, NULL);
1321 cmd_resizable_txt() {
1322 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1323 uzbl.behave.resizable_txt, NULL);
1327 cmd_default_encoding() {
1328 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1329 uzbl.behave.default_encoding, NULL);
1333 cmd_enforce_96dpi() {
1334 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1335 uzbl.behave.enforce_96dpi, NULL);
1339 cmd_caret_browsing() {
1340 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1341 uzbl.behave.caret_browsing, NULL);
1345 cmd_cookie_handler() {
1346 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1347 if ((g_strcmp0(split[0], "sh") == 0) ||
1348 (g_strcmp0(split[0], "spawn") == 0)) {
1349 g_free (uzbl.behave.cookie_handler);
1350 uzbl.behave.cookie_handler =
1351 g_strdup_printf("sync_%s %s", split[0], split[1]);
1358 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1363 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1368 if(uzbl.behave.inject_html) {
1369 webkit_web_view_load_html_string (uzbl.gui.web_view,
1370 uzbl.behave.inject_html, NULL);
1379 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1380 uzbl.behave.modmask = 0;
1382 if(uzbl.behave.modkey)
1383 g_free(uzbl.behave.modkey);
1384 uzbl.behave.modkey = buf;
1386 for (i = 0; modkeys[i].key != NULL; i++) {
1387 if (g_strrstr(buf, modkeys[i].key))
1388 uzbl.behave.modmask |= modkeys[i].mask;
1394 if (*uzbl.net.useragent == ' ') {
1395 g_free (uzbl.net.useragent);
1396 uzbl.net.useragent = NULL;
1398 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1400 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1401 g_free(uzbl.net.useragent);
1402 uzbl.net.useragent = ua;
1408 gtk_widget_ref(uzbl.gui.scrolled_win);
1409 gtk_widget_ref(uzbl.gui.mainbar);
1410 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1411 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1413 if(uzbl.behave.status_top) {
1414 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1415 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1418 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1419 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1421 gtk_widget_unref(uzbl.gui.scrolled_win);
1422 gtk_widget_unref(uzbl.gui.mainbar);
1423 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1428 set_var_value(gchar *name, gchar *val) {
1429 uzbl_cmdprop *c = NULL;
1432 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1433 /* check for the variable type */
1434 if (c->type == TYPE_STR) {
1436 *c->ptr = g_strdup(val);
1437 } else if(c->type == TYPE_INT) {
1438 int *ip = (int *)c->ptr;
1439 *ip = (int)strtoul(val, &endp, 10);
1442 /* invoke a command specific function */
1443 if(c->func) c->func();
1449 runcmd(WebKitWebView* page, GArray *argv) {
1451 parse_cmd_line(argv_idx(argv, 0));
1456 Behaviour *b = &uzbl.behave;
1458 if(b->html_buffer->str) {
1459 webkit_web_view_load_html_string (uzbl.gui.web_view,
1460 b->html_buffer->str, b->base_url);
1461 g_string_free(b->html_buffer, TRUE);
1462 b->html_buffer = g_string_new("");
1466 enum {M_CMD, M_HTML};
1468 parse_cmd_line(const char *ctl_line) {
1469 gchar **tokens = NULL;
1470 Behaviour *b = &uzbl.behave;
1472 if(b->mode == M_HTML) {
1473 if(!strncmp(b->html_endmarker, ctl_line, strlen(b->html_endmarker))) {
1475 set_var_value("mode", "0");
1480 set_timeout(b->html_timeout);
1481 g_string_append(b->html_buffer, ctl_line);
1486 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1487 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1488 if(tokens[0][0] == 0) {
1489 gchar* value = parseenv(g_strdup(tokens[2]));
1490 set_var_value(tokens[1], value);
1494 printf("Error in command: %s\n", tokens[0]);
1497 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1498 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1499 if(tokens[0][0] == 0) {
1500 get_var_value(tokens[1]);
1503 printf("Error in command: %s\n", tokens[0]);
1506 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1507 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1508 if(tokens[0][0] == 0) {
1509 gchar* value = parseenv(g_strdup(tokens[2]));
1510 add_binding(tokens[1], value);
1514 printf("Error in command: %s\n", tokens[0]);
1517 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1518 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1519 if(tokens[0][0] == 0) {
1520 parse_command(tokens[1], tokens[2]);
1523 printf("Error in command: %s\n", tokens[0]);
1525 /* KEYCMD command */
1526 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1527 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1528 if(tokens[0][0] == 0) {
1529 /* should incremental commands want each individual "keystroke"
1530 sent in a loop or the whole string in one go like now? */
1531 g_string_assign(uzbl.state.keycmd, tokens[1]);
1533 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1539 else if( (ctl_line[0] == '#')
1540 || (ctl_line[0] == ' ')
1541 || (ctl_line[0] == '\n'))
1542 ; /* ignore these lines */
1544 printf("Command not understood (%s)\n", ctl_line);
1554 build_stream_name(int type, const gchar* dir) {
1556 State *s = &uzbl.state;
1559 xwin_str = itos((int)uzbl.xwin);
1561 str = g_strdup_printf
1562 ("%s/uzbl_fifo_%s", dir,
1563 s->instance_name ? s->instance_name : xwin_str);
1564 } else if (type == SOCKET) {
1565 str = g_strdup_printf
1566 ("%s/uzbl_socket_%s", dir,
1567 s->instance_name ? s->instance_name : xwin_str );
1574 control_fifo(GIOChannel *gio, GIOCondition condition) {
1575 if (uzbl.state.verbose)
1576 printf("triggered\n");
1581 if (condition & G_IO_HUP)
1582 g_error ("Fifo: Read end of pipe died!\n");
1585 g_error ("Fifo: GIOChannel broke\n");
1587 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1588 if (ret == G_IO_STATUS_ERROR) {
1589 g_error ("Fifo: Error reading: %s\n", err->message);
1593 parse_cmd_line(ctl_line);
1600 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1601 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1602 if (unlink(uzbl.comm.fifo_path) == -1)
1603 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1604 g_free(uzbl.comm.fifo_path);
1605 uzbl.comm.fifo_path = NULL;
1608 if (*dir == ' ') { /* space unsets the variable */
1613 GIOChannel *chan = NULL;
1614 GError *error = NULL;
1615 gchar *path = build_stream_name(FIFO, dir);
1617 if (!file_exists(path)) {
1618 if (mkfifo (path, 0666) == 0) {
1619 // 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.
1620 chan = g_io_channel_new_file(path, "r+", &error);
1622 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1623 if (uzbl.state.verbose)
1624 printf ("init_fifo: created successfully as %s\n", path);
1625 uzbl.comm.fifo_path = path;
1627 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1628 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1629 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1630 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1632 /* if we got this far, there was an error; cleanup */
1633 if (error) g_error_free (error);
1640 control_stdin(GIOChannel *gio, GIOCondition condition) {
1642 gchar *ctl_line = NULL;
1645 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1646 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1649 parse_cmd_line(ctl_line);
1657 GIOChannel *chan = NULL;
1658 GError *error = NULL;
1660 chan = g_io_channel_unix_new(fileno(stdin));
1662 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1663 g_error ("Stdin: could not add watch\n");
1665 if (uzbl.state.verbose)
1666 printf ("Stdin: watch added successfully\n");
1669 g_error ("Stdin: Error while opening: %s\n", error->message);
1671 if (error) g_error_free (error);
1675 control_socket(GIOChannel *chan) {
1676 struct sockaddr_un remote;
1677 char buffer[512], *ctl_line;
1679 int sock, clientsock, n, done;
1682 sock = g_io_channel_unix_get_fd(chan);
1684 memset (buffer, 0, sizeof (buffer));
1686 t = sizeof (remote);
1687 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1691 memset (temp, 0, sizeof (temp));
1692 n = recv (clientsock, temp, 128, 0);
1694 buffer[strlen (buffer)] = '\0';
1698 strcat (buffer, temp);
1701 if (strcmp (buffer, "\n") < 0) {
1702 buffer[strlen (buffer) - 1] = '\0';
1704 buffer[strlen (buffer)] = '\0';
1707 ctl_line = g_strdup(buffer);
1708 parse_cmd_line (ctl_line);
1711 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1712 GError *error = NULL;
1715 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1716 if (ret == G_IO_STATUS_ERROR)
1717 g_error ("Error reading: %s\n", error->message);
1719 printf("Got line %s (%u bytes) \n",ctl_line, len);
1721 parse_line(ctl_line);
1729 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1730 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1731 if (unlink(uzbl.comm.socket_path) == -1)
1732 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1733 g_free(uzbl.comm.socket_path);
1734 uzbl.comm.socket_path = NULL;
1742 GIOChannel *chan = NULL;
1744 struct sockaddr_un local;
1745 gchar *path = build_stream_name(SOCKET, dir);
1747 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1749 local.sun_family = AF_UNIX;
1750 strcpy (local.sun_path, path);
1751 unlink (local.sun_path);
1753 len = strlen (local.sun_path) + sizeof (local.sun_family);
1754 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1755 if (uzbl.state.verbose)
1756 printf ("init_socket: opened in %s\n", path);
1759 if( (chan = g_io_channel_unix_new(sock)) ) {
1760 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1761 uzbl.comm.socket_path = path;
1764 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1766 /* if we got this far, there was an error; cleanup */
1773 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1774 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1776 // this function may be called very early when the templates are not set (yet), hence the checks
1778 update_title (void) {
1779 Behaviour *b = &uzbl.behave;
1782 if (b->show_status) {
1783 if (b->title_format_short) {
1784 parsed = expand_template(b->title_format_short, FALSE);
1785 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1788 if (b->status_format) {
1789 parsed = expand_template(b->status_format, TRUE);
1790 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1793 if (b->status_background) {
1795 gdk_color_parse (b->status_background, &color);
1796 //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)
1797 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1800 if (b->title_format_long) {
1801 parsed = expand_template(b->title_format_long, FALSE);
1802 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1809 key_press_cb (GtkWidget* window, GdkEventKey* event)
1811 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1815 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1816 || 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)
1819 /* turn off insert mode (if always_insert_mode is not used) */
1820 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1821 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1826 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1829 if (event->keyval == GDK_Escape) {
1830 g_string_truncate(uzbl.state.keycmd, 0);
1832 dehilight(uzbl.gui.web_view, NULL);
1836 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1837 if (event->keyval == GDK_Insert) {
1839 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1840 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1842 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1845 g_string_append (uzbl.state.keycmd, str);
1852 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1853 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1857 gboolean key_ret = FALSE;
1858 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1860 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1862 run_keycmd(key_ret);
1864 if (key_ret) return (!uzbl.behave.insert_mode);
1869 run_keycmd(const gboolean key_ret) {
1870 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1872 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1873 g_string_truncate(uzbl.state.keycmd, 0);
1874 parse_command(act->name, act->param);
1878 /* try if it's an incremental keycmd or one that takes args, and run it */
1879 GString* short_keys = g_string_new ("");
1880 GString* short_keys_inc = g_string_new ("");
1882 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1883 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1884 g_string_assign(short_keys_inc, short_keys->str);
1885 g_string_append_c(short_keys, '_');
1886 g_string_append_c(short_keys_inc, '*');
1888 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1889 /* run normal cmds only if return was pressed */
1890 exec_paramcmd(act, i);
1891 g_string_truncate(uzbl.state.keycmd, 0);
1893 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1894 if (key_ret) /* just quit the incremental command on return */
1895 g_string_truncate(uzbl.state.keycmd, 0);
1896 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1900 g_string_truncate(short_keys, short_keys->len - 1);
1902 g_string_free (short_keys, TRUE);
1903 g_string_free (short_keys_inc, TRUE);
1907 exec_paramcmd(const Action *act, const guint i) {
1908 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1909 GString *actionname = g_string_new ("");
1910 GString *actionparam = g_string_new ("");
1911 g_string_erase (parampart, 0, i+1);
1913 g_string_printf (actionname, act->name, parampart->str);
1915 g_string_printf (actionparam, act->param, parampart->str);
1916 parse_command(actionname->str, actionparam->str);
1917 g_string_free(actionname, TRUE);
1918 g_string_free(actionparam, TRUE);
1919 g_string_free(parampart, TRUE);
1927 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1928 //main_window_ref = g_object_ref(scrolled_window);
1929 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
1931 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1932 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1934 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1935 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1936 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1937 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1938 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1939 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1940 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1941 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1942 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1943 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1945 return scrolled_window;
1952 g->mainbar = gtk_hbox_new (FALSE, 0);
1954 /* keep a reference to the bar so we can re-pack it at runtime*/
1955 //sbar_ref = g_object_ref(g->mainbar);
1957 g->mainbar_label = gtk_label_new ("");
1958 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1959 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1960 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1961 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1962 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1967 GtkWidget* create_window () {
1968 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1969 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1970 gtk_widget_set_name (window, "Uzbl browser");
1971 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1972 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1978 run_handler (const gchar *act, const gchar *args) {
1979 char **parts = g_strsplit(act, " ", 2);
1981 else if ((g_strcmp0(parts[0], "spawn") == 0)
1982 || (g_strcmp0(parts[0], "sh") == 0)
1983 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1984 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1986 GString *a = g_string_new ("");
1988 spawnparts = split_quoted(parts[1], FALSE);
1989 g_string_append_printf(a, "%s", spawnparts[0]);
1990 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1992 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
1993 g_string_append_printf(a, " %s", spawnparts[i]);
1994 parse_command(parts[0], a->str);
1995 g_string_free (a, TRUE);
1996 g_strfreev (spawnparts);
1998 parse_command(parts[0], parts[1]);
2003 add_binding (const gchar *key, const gchar *act) {
2004 char **parts = g_strsplit(act, " ", 2);
2011 if (uzbl.state.verbose)
2012 printf ("Binding %-10s : %s\n", key, act);
2013 action = new_action(parts[0], parts[1]);
2015 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2020 get_xdg_var (XDG_Var xdg) {
2021 const gchar* actual_value = getenv (xdg.environmental);
2022 const gchar* home = getenv ("HOME");
2024 gchar* return_value = str_replace ("~", home, actual_value);
2026 if (! actual_value || strcmp (actual_value, "") == 0) {
2027 if (xdg.default_value) {
2028 return_value = str_replace ("~", home, xdg.default_value);
2030 return_value = NULL;
2033 return return_value;
2037 find_xdg_file (int xdg_type, char* filename) {
2038 /* xdg_type = 0 => config
2039 xdg_type = 1 => data
2040 xdg_type = 2 => cache*/
2042 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2043 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2046 gchar* temporary_string;
2050 if (! file_exists (temporary_file) && xdg_type != 2) {
2051 buf = get_xdg_var (XDG[3 + xdg_type]);
2052 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2055 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2056 g_free (temporary_file);
2057 temporary_file = g_strconcat (temporary_string, filename, NULL);
2061 //g_free (temporary_string); - segfaults.
2063 if (file_exists (temporary_file)) {
2064 return temporary_file;
2071 State *s = &uzbl.state;
2072 Network *n = &uzbl.net;
2074 for (i = 0; default_config[i].command != NULL; i++) {
2075 parse_cmd_line(default_config[i].command);
2078 if (!s->config_file) {
2079 s->config_file = find_xdg_file (0, "/uzbl/config");
2082 if (s->config_file) {
2083 GArray* lines = read_file_by_line (s->config_file);
2087 while ((line = g_array_index(lines, gchar*, i))) {
2088 parse_cmd_line (line);
2092 g_array_free (lines, TRUE);
2094 if (uzbl.state.verbose)
2095 printf ("No configuration file loaded.\n");
2098 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2101 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2104 if (!uzbl.behave.cookie_handler) return;
2106 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2107 GString *s = g_string_new ("");
2108 SoupURI * soup_uri = soup_message_get_uri(msg);
2109 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2110 run_handler(uzbl.behave.cookie_handler, s->str);
2112 if(uzbl.comm.sync_stdout)
2113 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2114 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2115 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2117 g_string_free(s, TRUE);
2121 save_cookies (SoupMessage *msg, gpointer user_data){
2125 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2126 cookie = soup_cookie_to_set_cookie_header(ck->data);
2127 SoupURI * soup_uri = soup_message_get_uri(msg);
2128 GString *s = g_string_new ("");
2129 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2130 run_handler(uzbl.behave.cookie_handler, s->str);
2132 g_string_free(s, TRUE);
2137 /* --- WEBINSPECTOR --- */
2139 hide_window_cb(GtkWidget *widget, gpointer data) {
2142 gtk_widget_hide(widget);
2145 static WebKitWebView*
2146 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2149 (void) web_inspector;
2150 GtkWidget* scrolled_window;
2151 GtkWidget* new_web_view;
2154 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2155 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2156 G_CALLBACK(hide_window_cb), NULL);
2158 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2159 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2160 gtk_widget_show(g->inspector_window);
2162 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2163 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2164 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2165 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2166 gtk_widget_show(scrolled_window);
2168 new_web_view = webkit_web_view_new();
2169 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2171 return WEBKIT_WEB_VIEW(new_web_view);
2175 inspector_show_window_cb (WebKitWebInspector* inspector){
2177 gtk_widget_show(uzbl.gui.inspector_window);
2181 /* TODO: Add variables and code to make use of these functions */
2183 inspector_close_window_cb (WebKitWebInspector* inspector){
2189 inspector_attach_window_cb (WebKitWebInspector* inspector){
2195 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2201 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2207 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2213 set_up_inspector() {
2215 WebKitWebSettings *settings = view_settings();
2216 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2218 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2219 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2220 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2221 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2222 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2223 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2224 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2226 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2230 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2232 uzbl_cmdprop *c = v;
2237 if(c->type == TYPE_STR)
2238 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2239 else if(c->type == TYPE_INT)
2240 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2244 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2248 printf("bind %s = %s %s\n", (char *)k ,
2249 (char *)a->name, a->param?(char *)a->param:"");
2254 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2255 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2260 main (int argc, char* argv[]) {
2261 gtk_init (&argc, &argv);
2262 if (!g_thread_supported ())
2263 g_thread_init (NULL);
2264 uzbl.state.executable_path = g_strdup(argv[0]);
2265 uzbl.state.selected_url = NULL;
2266 uzbl.state.searchtx = NULL;
2268 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2269 g_option_context_add_main_entries (context, entries, NULL);
2270 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2271 g_option_context_parse (context, &argc, &argv, NULL);
2272 g_option_context_free(context);
2273 /* initialize hash table */
2274 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2276 uzbl.net.soup_session = webkit_get_default_session();
2277 uzbl.state.keycmd = g_string_new("");
2279 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2280 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2281 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2282 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2283 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2284 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2287 if(uname(&uzbl.state.unameinfo) == -1)
2288 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2290 uzbl.gui.sbar.progress_s = g_strdup("=");
2291 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2292 uzbl.gui.sbar.progress_w = 10;
2294 /* HTML mode defaults*/
2295 uzbl.behave.html_buffer = g_string_new("");
2296 uzbl.behave.html_endmarker = g_strdup(".");
2297 uzbl.behave.html_timeout = 60;
2298 uzbl.behave.base_url = g_strdup("http://invalid");
2303 make_var_to_name_hash();
2305 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2307 uzbl.gui.scrolled_win = create_browser();
2310 /* initial packing */
2311 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2312 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2314 uzbl.gui.main_window = create_window ();
2315 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2318 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2319 gtk_widget_show_all (uzbl.gui.main_window);
2320 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2322 if (uzbl.state.verbose) {
2323 printf("Uzbl start location: %s\n", argv[0]);
2324 printf("window_id %i\n",(int) uzbl.xwin);
2325 printf("pid %i\n", getpid ());
2326 printf("name: %s\n", uzbl.state.instance_name);
2329 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2330 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2331 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2332 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2333 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2337 if (!uzbl.behave.show_status)
2338 gtk_widget_hide(uzbl.gui.mainbar);
2347 if(uzbl.state.uri) {
2348 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2349 g_array_append_val(a, uzbl.state.uri);
2350 load_uri (uzbl.gui.web_view, a);
2351 g_array_free (a, TRUE);
2357 return EXIT_SUCCESS;
2360 /* vi: set et ts=4: */