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 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
118 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
119 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
120 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
121 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
122 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
123 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
124 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
125 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
126 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
127 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
128 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
129 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
130 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
131 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
132 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
133 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
134 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
135 /* exported WebKitWebSettings properties*/
136 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
137 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
138 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
139 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
140 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
141 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
142 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
143 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
144 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
145 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
146 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
147 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
148 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
149 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
150 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
152 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
153 }, *n2v_p = var_name_to_ptr;
159 { "SHIFT", GDK_SHIFT_MASK }, // shift
160 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
161 { "CONTROL", GDK_CONTROL_MASK }, // control
162 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
163 { "MOD2", GDK_MOD2_MASK }, // 5th mod
164 { "MOD3", GDK_MOD3_MASK }, // 6th mod
165 { "MOD4", GDK_MOD4_MASK }, // 7th mod
166 { "MOD5", GDK_MOD5_MASK }, // 8th mod
167 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
168 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
169 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
170 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
171 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
172 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
173 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
174 { "META", GDK_META_MASK }, // meta (since 2.10)
179 /* construct a hash from the var_name_to_ptr array for quick access */
181 make_var_to_name_hash() {
182 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
184 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
190 /* --- UTILITY FUNCTIONS --- */
196 snprintf(tmp, sizeof(tmp), "%i", val);
197 return g_strdup(tmp);
201 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
204 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
207 str_replace (const char* search, const char* replace, const char* string) {
211 buf = g_strsplit (string, search, -1);
212 ret = g_strjoinv (replace, buf);
213 g_strfreev(buf); // somebody said this segfaults
219 read_file_by_line (gchar *path) {
220 GIOChannel *chan = NULL;
221 gchar *readbuf = NULL;
223 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
226 chan = g_io_channel_new_file(path, "r", NULL);
229 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
230 const gchar* val = g_strdup (readbuf);
231 g_array_append_val (lines, val);
236 g_io_channel_unref (chan);
238 fprintf(stderr, "File '%s' not be read.\n", path);
245 gchar* parseenv (char* string) {
246 extern char** environ;
247 gchar* tmpstr = NULL;
251 while (environ[i] != NULL) {
252 gchar** env = g_strsplit (environ[i], "=", 2);
253 gchar* envname = g_strconcat ("$", env[0], NULL);
255 if (g_strrstr (string, envname) != NULL) {
256 tmpstr = g_strdup(string);
258 string = str_replace(envname, env[1], tmpstr);
263 g_strfreev (env); // somebody said this breaks uzbl
271 setup_signal(int signr, sigfunc *shandler) {
272 struct sigaction nh, oh;
274 nh.sa_handler = shandler;
275 sigemptyset(&nh.sa_mask);
278 if(sigaction(signr, &nh, &oh) < 0)
286 if (uzbl.behave.fifo_dir)
287 unlink (uzbl.comm.fifo_path);
288 if (uzbl.behave.socket_dir)
289 unlink (uzbl.comm.socket_path);
291 g_free(uzbl.state.executable_path);
292 g_string_free(uzbl.state.keycmd, TRUE);
293 g_hash_table_destroy(uzbl.bindings);
294 g_hash_table_destroy(uzbl.behave.commands);
297 /* used for html_mode_timeout
298 * be sure to extend this function to use
299 * more timers if needed in other places
302 set_timeout(int seconds) {
304 memset(&t, 0, sizeof t);
306 t.it_value.tv_sec = seconds;
307 t.it_value.tv_usec = 0;
308 setitimer(ITIMER_REAL, &t, NULL);
311 /* --- SIGNAL HANDLER --- */
314 catch_sigterm(int s) {
320 catch_sigint(int s) {
330 set_var_value("mode", "0");
335 /* --- CALLBACKS --- */
338 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
341 (void) navigation_action;
342 (void) policy_decision;
344 const gchar* uri = webkit_network_request_get_uri (request);
345 if (uzbl.state.verbose)
346 printf("New window requested -> %s \n", uri);
347 new_window_load_uri(uri);
352 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
356 if (uzbl.state.selected_url != NULL) {
357 if (uzbl.state.verbose)
358 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
359 new_window_load_uri(uzbl.state.selected_url);
361 if (uzbl.state.verbose)
362 printf("New web view -> %s\n","Nothing to open, exiting");
368 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
371 if (uzbl.behave.download_handler) {
372 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
373 if (uzbl.state.verbose)
374 printf("Download -> %s\n",uri);
375 /* if urls not escaped, we may have to escape and quote uri before this call */
376 run_handler(uzbl.behave.download_handler, uri);
381 /* scroll a bar in a given direction */
383 scroll (GtkAdjustment* bar, GArray *argv) {
387 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
388 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
389 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
393 scroll_begin(WebKitWebView* page, GArray *argv) {
394 (void) page; (void) argv;
395 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
399 scroll_end(WebKitWebView* page, GArray *argv) {
400 (void) page; (void) argv;
401 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
402 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
406 scroll_vert(WebKitWebView* page, GArray *argv) {
408 scroll(uzbl.gui.bar_v, argv);
412 scroll_horz(WebKitWebView* page, GArray *argv) {
414 scroll(uzbl.gui.bar_h, argv);
419 if (!uzbl.behave.show_status) {
420 gtk_widget_hide(uzbl.gui.mainbar);
422 gtk_widget_show(uzbl.gui.mainbar);
428 toggle_status_cb (WebKitWebView* page, GArray *argv) {
432 if (uzbl.behave.show_status) {
433 gtk_widget_hide(uzbl.gui.mainbar);
435 gtk_widget_show(uzbl.gui.mainbar);
437 uzbl.behave.show_status = !uzbl.behave.show_status;
442 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
446 //Set selected_url state variable
447 g_free(uzbl.state.selected_url);
448 uzbl.state.selected_url = NULL;
450 uzbl.state.selected_url = g_strdup(link);
456 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
460 if (uzbl.gui.main_title)
461 g_free (uzbl.gui.main_title);
462 uzbl.gui.main_title = g_strdup (title);
467 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
470 uzbl.gui.sbar.load_progress = progress;
475 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
479 if (uzbl.behave.load_finish_handler)
480 run_handler(uzbl.behave.load_finish_handler, "");
484 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
488 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
489 if (uzbl.behave.load_start_handler)
490 run_handler(uzbl.behave.load_start_handler, "");
494 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
497 g_free (uzbl.state.uri);
498 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
499 uzbl.state.uri = g_string_free (newuri, FALSE);
500 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
501 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
504 if (uzbl.behave.load_commit_handler)
505 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
509 destroy_cb (GtkWidget* widget, gpointer data) {
517 if (uzbl.behave.history_handler) {
519 struct tm * timeinfo;
522 timeinfo = localtime ( &rawtime );
523 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
524 run_handler(uzbl.behave.history_handler, date);
529 /* VIEW funcs (little webkit wrappers) */
530 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
532 VIEWFUNC(reload_bypass_cache)
533 VIEWFUNC(stop_loading)
540 /* -- command to callback/function map for things we cannot attach to any signals */
542 static struct {char *name; Command command[2];} cmdlist[] =
543 { /* key function no_split */
544 { "back", {view_go_back, 0} },
545 { "forward", {view_go_forward, 0} },
546 { "scroll_vert", {scroll_vert, 0} },
547 { "scroll_horz", {scroll_horz, 0} },
548 { "scroll_begin", {scroll_begin, 0} },
549 { "scroll_end", {scroll_end, 0} },
550 { "reload", {view_reload, 0}, },
551 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
552 { "stop", {view_stop_loading, 0}, },
553 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
554 { "zoom_out", {view_zoom_out, 0}, },
555 { "uri", {load_uri, NOSPLIT} },
556 { "js", {run_js, NOSPLIT} },
557 { "script", {run_external_js, 0} },
558 { "toggle_status", {toggle_status_cb, 0} },
559 { "spawn", {spawn, 0} },
560 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
561 { "sh", {spawn_sh, 0} },
562 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
563 { "exit", {close_uzbl, 0} },
564 { "search", {search_forward_text, NOSPLIT} },
565 { "search_reverse", {search_reverse_text, NOSPLIT} },
566 { "dehilight", {dehilight, 0} },
567 { "toggle_insert_mode", {toggle_insert_mode, 0} },
568 { "runcmd", {runcmd, NOSPLIT} },
569 { "set", {set_var, NOSPLIT} },
570 { "dump_config", {act_dump_config, 0} }
577 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
579 for (i = 0; i < LENGTH(cmdlist); i++)
580 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
583 /* -- CORE FUNCTIONS -- */
586 free_action(gpointer act) {
587 Action *action = (Action*)act;
588 g_free(action->name);
590 g_free(action->param);
595 new_action(const gchar *name, const gchar *param) {
596 Action *action = g_new(Action, 1);
598 action->name = g_strdup(name);
600 action->param = g_strdup(param);
602 action->param = NULL;
608 file_exists (const char * filename) {
609 return (access(filename, F_OK) == 0);
613 set_var(WebKitWebView *page, GArray *argv) {
617 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
618 parse_cmd_line(ctl_line);
628 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
631 if (argv_idx(argv, 0)) {
632 if (strcmp (argv_idx(argv, 0), "0") == 0) {
633 uzbl.behave.insert_mode = FALSE;
635 uzbl.behave.insert_mode = TRUE;
638 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
645 load_uri (WebKitWebView *web_view, GArray *argv) {
646 if (argv_idx(argv, 0)) {
647 GString* newuri = g_string_new (argv_idx(argv, 0));
648 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
649 g_string_prepend (newuri, "http://");
650 /* if we do handle cookies, ask our handler for them */
651 webkit_web_view_load_uri (web_view, newuri->str);
652 g_string_free (newuri, TRUE);
657 run_js (WebKitWebView * web_view, GArray *argv) {
658 if (argv_idx(argv, 0))
659 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
663 run_external_js (WebKitWebView * web_view, GArray *argv) {
664 if (argv_idx(argv, 0)) {
665 GArray* lines = read_file_by_line (argv_idx (argv, 0));
670 while ((line = g_array_index(lines, gchar*, i))) {
672 js = g_strdup (line);
674 gchar* newjs = g_strconcat (js, line, NULL);
681 if (uzbl.state.verbose)
682 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
684 if (argv_idx (argv, 1)) {
685 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
689 webkit_web_view_execute_script (web_view, js);
691 g_array_free (lines, TRUE);
696 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
697 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
698 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
699 webkit_web_view_unmark_text_matches (page);
700 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
701 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
705 if (uzbl.state.searchtx) {
706 if (uzbl.state.verbose)
707 printf ("Searching: %s\n", uzbl.state.searchtx);
708 webkit_web_view_set_highlight_text_matches (page, TRUE);
709 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
714 search_forward_text (WebKitWebView *page, GArray *argv) {
715 search_text(page, argv, TRUE);
719 search_reverse_text (WebKitWebView *page, GArray *argv) {
720 search_text(page, argv, FALSE);
724 dehilight (WebKitWebView *page, GArray *argv) {
726 webkit_web_view_set_highlight_text_matches (page, FALSE);
731 new_window_load_uri (const gchar * uri) {
732 GString* to_execute = g_string_new ("");
733 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
735 for (i = 0; entries[i].long_name != NULL; i++) {
736 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
737 gchar** str = (gchar**)entries[i].arg_data;
739 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
743 if (uzbl.state.verbose)
744 printf("\n%s\n", to_execute->str);
745 g_spawn_command_line_async (to_execute->str, NULL);
746 g_string_free (to_execute, TRUE);
750 close_uzbl (WebKitWebView *page, GArray *argv) {
756 /* --Statusbar functions-- */
758 build_progressbar_ascii(int percent) {
759 int width=uzbl.gui.sbar.progress_w;
762 GString *bar = g_string_new("");
764 l = (double)percent*((double)width/100.);
765 l = (int)(l+.5)>=(int)l ? l+.5 : l;
767 for(i=0; i<(int)l; i++)
768 g_string_append(bar, uzbl.gui.sbar.progress_s);
771 g_string_append(bar, uzbl.gui.sbar.progress_u);
773 return g_string_free(bar, FALSE);
778 const GScannerConfig scan_config = {
781 ) /* cset_skip_characters */,
786 ) /* cset_identifier_first */,
793 ) /* cset_identifier_nth */,
794 ( "" ) /* cpair_comment_single */,
796 TRUE /* case_sensitive */,
798 FALSE /* skip_comment_multi */,
799 FALSE /* skip_comment_single */,
800 FALSE /* scan_comment_multi */,
801 TRUE /* scan_identifier */,
802 TRUE /* scan_identifier_1char */,
803 FALSE /* scan_identifier_NULL */,
804 TRUE /* scan_symbols */,
805 FALSE /* scan_binary */,
806 FALSE /* scan_octal */,
807 FALSE /* scan_float */,
808 FALSE /* scan_hex */,
809 FALSE /* scan_hex_dollar */,
810 FALSE /* scan_string_sq */,
811 FALSE /* scan_string_dq */,
812 TRUE /* numbers_2_int */,
813 FALSE /* int_2_float */,
814 FALSE /* identifier_2_string */,
815 FALSE /* char_2_token */,
816 FALSE /* symbol_2_token */,
817 TRUE /* scope_0_fallback */,
822 uzbl.scan = g_scanner_new(&scan_config);
823 while(symp->symbol_name) {
824 g_scanner_scope_add_symbol(uzbl.scan, 0,
826 GINT_TO_POINTER(symp->symbol_token));
832 expand_template(const char *template, gboolean escape_markup) {
833 if(!template) return NULL;
835 GTokenType token = G_TOKEN_NONE;
836 GString *ret = g_string_new("");
840 g_scanner_input_text(uzbl.scan, template, strlen(template));
841 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
842 token = g_scanner_get_next_token(uzbl.scan);
844 if(token == G_TOKEN_SYMBOL) {
845 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
849 buf = uzbl.state.uri?
850 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
851 g_string_append(ret, buf);
855 g_string_append(ret, uzbl.state.uri?
856 uzbl.state.uri:g_strdup(""));
859 buf = itos(uzbl.gui.sbar.load_progress);
860 g_string_append(ret, buf);
863 case SYM_LOADPRGSBAR:
864 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
865 g_string_append(ret, buf);
870 buf = uzbl.gui.main_title?
871 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
872 g_string_append(ret, buf);
876 g_string_append(ret, uzbl.gui.main_title?
877 uzbl.gui.main_title:g_strdup(""));
879 case SYM_SELECTED_URI:
881 buf = uzbl.state.selected_url?
882 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
883 g_string_append(ret, buf);
887 g_string_append(ret, uzbl.state.selected_url?
888 uzbl.state.selected_url:g_strdup(""));
891 buf = itos(uzbl.xwin);
893 uzbl.state.instance_name?uzbl.state.instance_name:buf);
898 buf = uzbl.state.keycmd->str?
899 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
900 g_string_append(ret, buf);
904 g_string_append(ret, uzbl.state.keycmd->str?
905 uzbl.state.keycmd->str:g_strdup(""));
909 uzbl.behave.insert_mode?
910 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
914 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
918 buf = itos(WEBKIT_MAJOR_VERSION);
919 g_string_append(ret, buf);
923 buf = itos(WEBKIT_MINOR_VERSION);
924 g_string_append(ret, buf);
928 buf = itos(WEBKIT_MICRO_VERSION);
929 g_string_append(ret, buf);
933 g_string_append(ret, uzbl.state.unameinfo.sysname);
936 g_string_append(ret, uzbl.state.unameinfo.nodename);
939 g_string_append(ret, uzbl.state.unameinfo.release);
942 g_string_append(ret, uzbl.state.unameinfo.version);
945 g_string_append(ret, uzbl.state.unameinfo.machine);
948 g_string_append(ret, ARCH);
952 g_string_append(ret, uzbl.state.unameinfo.domainname);
956 g_string_append(ret, COMMIT);
962 else if(token == G_TOKEN_INT) {
963 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
964 g_string_append(ret, buf);
967 else if(token == G_TOKEN_IDENTIFIER) {
968 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
970 else if(token == G_TOKEN_CHAR) {
971 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
975 return g_string_free(ret, FALSE);
977 /* --End Statusbar functions-- */
980 sharg_append(GArray *a, const gchar *str) {
981 const gchar *s = (str ? str : "");
982 g_array_append_val(a, s);
985 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
987 run_command (const gchar *command, const guint npre, const gchar **args,
988 const gboolean sync, char **stdout) {
989 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
992 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
993 gchar *pid = itos(getpid());
994 gchar *xwin = itos(uzbl.xwin);
996 sharg_append(a, command);
997 for (i = 0; i < npre; i++) /* add n args before the default vars */
998 sharg_append(a, args[i]);
999 sharg_append(a, uzbl.state.config_file);
1000 sharg_append(a, pid);
1001 sharg_append(a, xwin);
1002 sharg_append(a, uzbl.comm.fifo_path);
1003 sharg_append(a, uzbl.comm.socket_path);
1004 sharg_append(a, uzbl.state.uri);
1005 sharg_append(a, uzbl.gui.main_title);
1007 for (i = npre; i < g_strv_length((gchar**)args); i++)
1008 sharg_append(a, args[i]);
1012 if (*stdout) *stdout = strfree(*stdout);
1014 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1015 NULL, NULL, stdout, NULL, NULL, &err);
1016 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1017 NULL, NULL, NULL, &err);
1019 if (uzbl.state.verbose) {
1020 GString *s = g_string_new("spawned:");
1021 for (i = 0; i < (a->len); i++) {
1022 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1023 g_string_append_printf(s, " %s", qarg);
1026 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1027 printf("%s\n", s->str);
1028 g_string_free(s, TRUE);
1031 g_printerr("error on run_command: %s\n", err->message);
1036 g_array_free (a, TRUE);
1041 split_quoted(const gchar* src, const gboolean unquote) {
1042 /* split on unquoted space, return array of strings;
1043 remove a layer of quotes and backslashes if unquote */
1044 if (!src) return NULL;
1046 gboolean dq = FALSE;
1047 gboolean sq = FALSE;
1048 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1049 GString *s = g_string_new ("");
1053 for (p = src; *p != '\0'; p++) {
1054 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1055 else if (*p == '\\') { g_string_append_c(s, *p++);
1056 g_string_append_c(s, *p); }
1057 else if ((*p == '"') && unquote && !sq) dq = !dq;
1058 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1060 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1061 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1063 else if ((*p == ' ') && !dq && !sq) {
1064 dup = g_strdup(s->str);
1065 g_array_append_val(a, dup);
1066 g_string_truncate(s, 0);
1067 } else g_string_append_c(s, *p);
1069 dup = g_strdup(s->str);
1070 g_array_append_val(a, dup);
1071 ret = (gchar**)a->data;
1072 g_array_free (a, FALSE);
1073 g_string_free (s, TRUE);
1078 spawn(WebKitWebView *web_view, GArray *argv) {
1080 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1081 if (argv_idx(argv, 0))
1082 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1086 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1089 if (argv_idx(argv, 0))
1090 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1091 TRUE, &uzbl.comm.sync_stdout);
1095 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1097 if (!uzbl.behave.shell_cmd) {
1098 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1103 gchar *spacer = g_strdup("");
1104 g_array_insert_val(argv, 1, spacer);
1105 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1107 for (i = 1; i < g_strv_length(cmd); i++)
1108 g_array_prepend_val(argv, cmd[i]);
1110 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1116 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1118 if (!uzbl.behave.shell_cmd) {
1119 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1124 gchar *spacer = g_strdup("");
1125 g_array_insert_val(argv, 1, spacer);
1126 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1128 for (i = 1; i < g_strv_length(cmd); i++)
1129 g_array_prepend_val(argv, cmd[i]);
1131 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1132 TRUE, &uzbl.comm.sync_stdout);
1138 parse_command(const char *cmd, const char *param) {
1141 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1144 gchar **par = split_quoted(param, TRUE);
1145 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1147 if (c[1] == NOSPLIT) { /* don't split */
1148 sharg_append(a, param);
1150 for (i = 0; i < g_strv_length(par); i++)
1151 sharg_append(a, par[i]);
1153 c[0](uzbl.gui.web_view, a);
1155 g_array_free (a, TRUE);
1158 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1161 /* command parser */
1164 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1165 G_REGEX_OPTIMIZE, 0, NULL);
1166 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ \\t]+)\\s*=\\s*([^\\n].*)$",
1167 G_REGEX_OPTIMIZE, 0, NULL);
1168 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1169 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1170 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1171 G_REGEX_OPTIMIZE, 0, NULL);
1172 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1173 G_REGEX_OPTIMIZE, 0, NULL);
1177 get_var_value(gchar *name) {
1180 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1181 if(c->type == TYPE_STR)
1182 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1183 else if(c->type == TYPE_INT)
1184 printf("VAR: %s VALUE: %p\n", name, *c->ptr);
1193 if(*uzbl.net.proxy_url == ' '
1194 || uzbl.net.proxy_url == NULL) {
1195 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1196 (GType) SOUP_SESSION_PROXY_URI);
1199 suri = soup_uri_new(uzbl.net.proxy_url);
1200 g_object_set(G_OBJECT(uzbl.net.soup_session),
1201 SOUP_SESSION_PROXY_URI,
1203 soup_uri_free(suri);
1210 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1211 g_array_append_val (a, uzbl.state.uri);
1212 load_uri(uzbl.gui.web_view, a);
1213 g_array_free (a, TRUE);
1217 cmd_always_insert_mode() {
1218 uzbl.behave.insert_mode =
1219 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1225 g_object_set(G_OBJECT(uzbl.net.soup_session),
1226 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1230 cmd_max_conns_host() {
1231 g_object_set(G_OBJECT(uzbl.net.soup_session),
1232 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1237 soup_session_remove_feature
1238 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1239 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1240 /*g_free(uzbl.net.soup_logger);*/
1242 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1243 soup_session_add_feature(uzbl.net.soup_session,
1244 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1247 static WebKitWebSettings*
1249 return webkit_web_view_get_settings(uzbl.gui.web_view);
1254 WebKitWebSettings *ws = view_settings();
1255 if (uzbl.behave.font_size > 0) {
1256 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1259 if (uzbl.behave.monospace_size > 0) {
1260 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1261 uzbl.behave.monospace_size, NULL);
1263 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1264 uzbl.behave.font_size, NULL);
1269 cmd_disable_plugins() {
1270 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1271 !uzbl.behave.disable_plugins, NULL);
1275 cmd_disable_scripts() {
1276 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1277 !uzbl.behave.disable_plugins, NULL);
1281 cmd_minimum_font_size() {
1282 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1283 uzbl.behave.minimum_font_size, NULL);
1286 cmd_autoload_img() {
1287 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1288 uzbl.behave.autoload_img, NULL);
1293 cmd_autoshrink_img() {
1294 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1295 uzbl.behave.autoshrink_img, NULL);
1300 cmd_enable_spellcheck() {
1301 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1302 uzbl.behave.enable_spellcheck, NULL);
1306 cmd_enable_private() {
1307 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1308 uzbl.behave.enable_private, NULL);
1313 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1314 uzbl.behave.print_bg, NULL);
1319 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1320 uzbl.behave.style_uri, NULL);
1324 cmd_resizable_txt() {
1325 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1326 uzbl.behave.resizable_txt, NULL);
1330 cmd_default_encoding() {
1331 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1332 uzbl.behave.default_encoding, NULL);
1336 cmd_enforce_96dpi() {
1337 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1338 uzbl.behave.enforce_96dpi, NULL);
1342 cmd_caret_browsing() {
1343 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1344 uzbl.behave.caret_browsing, NULL);
1348 cmd_cookie_handler() {
1349 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1350 if ((g_strcmp0(split[0], "sh") == 0) ||
1351 (g_strcmp0(split[0], "spawn") == 0)) {
1352 g_free (uzbl.behave.cookie_handler);
1353 uzbl.behave.cookie_handler =
1354 g_strdup_printf("sync_%s %s", split[0], split[1]);
1361 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1366 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1371 if(uzbl.behave.inject_html) {
1372 webkit_web_view_load_html_string (uzbl.gui.web_view,
1373 uzbl.behave.inject_html, NULL);
1382 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1383 uzbl.behave.modmask = 0;
1385 if(uzbl.behave.modkey)
1386 g_free(uzbl.behave.modkey);
1387 uzbl.behave.modkey = buf;
1389 for (i = 0; modkeys[i].key != NULL; i++) {
1390 if (g_strrstr(buf, modkeys[i].key))
1391 uzbl.behave.modmask |= modkeys[i].mask;
1397 if (*uzbl.net.useragent == ' ') {
1398 g_free (uzbl.net.useragent);
1399 uzbl.net.useragent = NULL;
1401 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1403 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1404 g_free(uzbl.net.useragent);
1405 uzbl.net.useragent = ua;
1411 gtk_widget_ref(uzbl.gui.scrolled_win);
1412 gtk_widget_ref(uzbl.gui.mainbar);
1413 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1414 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1416 if(uzbl.behave.status_top) {
1417 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1418 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1421 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1422 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1424 gtk_widget_unref(uzbl.gui.scrolled_win);
1425 gtk_widget_unref(uzbl.gui.mainbar);
1426 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1431 set_var_value(gchar *name, gchar *val) {
1432 uzbl_cmdprop *c = NULL;
1435 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1436 /* check for the variable type */
1437 if (c->type == TYPE_STR) {
1439 *c->ptr = g_strdup(val);
1440 } else if(c->type == TYPE_INT) {
1441 int *ip = (int *) c->ptr;
1442 *ip = (int)strtoul(val, &endp, 10);
1445 /* invoke a command specific function */
1446 if(c->func) c->func();
1452 runcmd(WebKitWebView* page, GArray *argv) {
1454 parse_cmd_line(argv_idx(argv, 0));
1459 Behaviour *b = &uzbl.behave;
1461 if(b->html_buffer->str) {
1462 webkit_web_view_load_html_string (uzbl.gui.web_view,
1463 b->html_buffer->str, b->base_url);
1464 g_string_free(b->html_buffer, TRUE);
1465 b->html_buffer = g_string_new("");
1469 enum {M_CMD, M_HTML};
1471 parse_cmd_line(const char *ctl_line) {
1472 gchar **tokens = NULL;
1473 Behaviour *b = &uzbl.behave;
1476 if(b->mode == M_HTML) {
1477 len = strlen(b->html_endmarker);
1478 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1479 if(len == strlen(ctl_line)-1 &&
1480 !strncmp(b->html_endmarker, ctl_line, len)) {
1482 set_var_value("mode", "0");
1487 set_timeout(b->html_timeout);
1488 g_string_append(b->html_buffer, ctl_line);
1493 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1494 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1495 if(tokens[0][0] == 0) {
1496 gchar* value = parseenv(g_strdup(tokens[2]));
1497 set_var_value(tokens[1], value);
1501 printf("Error in command: %s\n", tokens[0]);
1504 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1505 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1506 if(tokens[0][0] == 0) {
1507 get_var_value(tokens[1]);
1510 printf("Error in command: %s\n", tokens[0]);
1513 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1514 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1515 if(tokens[0][0] == 0) {
1516 gchar* value = parseenv(g_strdup(tokens[2]));
1517 add_binding(tokens[1], value);
1521 printf("Error in command: %s\n", tokens[0]);
1524 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1525 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1526 if(tokens[0][0] == 0) {
1527 parse_command(tokens[1], tokens[2]);
1530 printf("Error in command: %s\n", tokens[0]);
1532 /* KEYCMD command */
1533 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1534 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1535 if(tokens[0][0] == 0) {
1536 /* should incremental commands want each individual "keystroke"
1537 sent in a loop or the whole string in one go like now? */
1538 g_string_assign(uzbl.state.keycmd, tokens[1]);
1540 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1546 else if( (ctl_line[0] == '#')
1547 || (ctl_line[0] == ' ')
1548 || (ctl_line[0] == '\n'))
1549 ; /* ignore these lines */
1551 printf("Command not understood (%s)\n", ctl_line);
1561 build_stream_name(int type, const gchar* dir) {
1563 State *s = &uzbl.state;
1566 xwin_str = itos((int)uzbl.xwin);
1568 str = g_strdup_printf
1569 ("%s/uzbl_fifo_%s", dir,
1570 s->instance_name ? s->instance_name : xwin_str);
1571 } else if (type == SOCKET) {
1572 str = g_strdup_printf
1573 ("%s/uzbl_socket_%s", dir,
1574 s->instance_name ? s->instance_name : xwin_str );
1581 control_fifo(GIOChannel *gio, GIOCondition condition) {
1582 if (uzbl.state.verbose)
1583 printf("triggered\n");
1588 if (condition & G_IO_HUP)
1589 g_error ("Fifo: Read end of pipe died!\n");
1592 g_error ("Fifo: GIOChannel broke\n");
1594 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1595 if (ret == G_IO_STATUS_ERROR) {
1596 g_error ("Fifo: Error reading: %s\n", err->message);
1600 parse_cmd_line(ctl_line);
1607 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1608 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1609 if (unlink(uzbl.comm.fifo_path) == -1)
1610 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1611 g_free(uzbl.comm.fifo_path);
1612 uzbl.comm.fifo_path = NULL;
1615 if (*dir == ' ') { /* space unsets the variable */
1620 GIOChannel *chan = NULL;
1621 GError *error = NULL;
1622 gchar *path = build_stream_name(FIFO, dir);
1624 if (!file_exists(path)) {
1625 if (mkfifo (path, 0666) == 0) {
1626 // 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.
1627 chan = g_io_channel_new_file(path, "r+", &error);
1629 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1630 if (uzbl.state.verbose)
1631 printf ("init_fifo: created successfully as %s\n", path);
1632 uzbl.comm.fifo_path = path;
1634 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1635 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1636 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1637 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1639 /* if we got this far, there was an error; cleanup */
1640 if (error) g_error_free (error);
1647 control_stdin(GIOChannel *gio, GIOCondition condition) {
1649 gchar *ctl_line = NULL;
1652 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1653 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1656 parse_cmd_line(ctl_line);
1664 GIOChannel *chan = NULL;
1665 GError *error = NULL;
1667 chan = g_io_channel_unix_new(fileno(stdin));
1669 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1670 g_error ("Stdin: could not add watch\n");
1672 if (uzbl.state.verbose)
1673 printf ("Stdin: watch added successfully\n");
1676 g_error ("Stdin: Error while opening: %s\n", error->message);
1678 if (error) g_error_free (error);
1682 control_socket(GIOChannel *chan) {
1683 struct sockaddr_un remote;
1684 char buffer[512], *ctl_line;
1686 int sock, clientsock, n, done;
1689 sock = g_io_channel_unix_get_fd(chan);
1691 memset (buffer, 0, sizeof (buffer));
1693 t = sizeof (remote);
1694 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1698 memset (temp, 0, sizeof (temp));
1699 n = recv (clientsock, temp, 128, 0);
1701 buffer[strlen (buffer)] = '\0';
1705 strcat (buffer, temp);
1708 if (strcmp (buffer, "\n") < 0) {
1709 buffer[strlen (buffer) - 1] = '\0';
1711 buffer[strlen (buffer)] = '\0';
1714 ctl_line = g_strdup(buffer);
1715 parse_cmd_line (ctl_line);
1718 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1719 GError *error = NULL;
1722 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1723 if (ret == G_IO_STATUS_ERROR)
1724 g_error ("Error reading: %s\n", error->message);
1726 printf("Got line %s (%u bytes) \n",ctl_line, len);
1728 parse_line(ctl_line);
1736 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1737 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1738 if (unlink(uzbl.comm.socket_path) == -1)
1739 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1740 g_free(uzbl.comm.socket_path);
1741 uzbl.comm.socket_path = NULL;
1749 GIOChannel *chan = NULL;
1751 struct sockaddr_un local;
1752 gchar *path = build_stream_name(SOCKET, dir);
1754 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1756 local.sun_family = AF_UNIX;
1757 strcpy (local.sun_path, path);
1758 unlink (local.sun_path);
1760 len = strlen (local.sun_path) + sizeof (local.sun_family);
1761 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1762 if (uzbl.state.verbose)
1763 printf ("init_socket: opened in %s\n", path);
1766 if( (chan = g_io_channel_unix_new(sock)) ) {
1767 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1768 uzbl.comm.socket_path = path;
1771 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1773 /* if we got this far, there was an error; cleanup */
1780 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1781 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1783 // this function may be called very early when the templates are not set (yet), hence the checks
1785 update_title (void) {
1786 Behaviour *b = &uzbl.behave;
1789 if (b->show_status) {
1790 if (b->title_format_short) {
1791 parsed = expand_template(b->title_format_short, FALSE);
1792 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1795 if (b->status_format) {
1796 parsed = expand_template(b->status_format, TRUE);
1797 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1800 if (b->status_background) {
1802 gdk_color_parse (b->status_background, &color);
1803 //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)
1804 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1807 if (b->title_format_long) {
1808 parsed = expand_template(b->title_format_long, FALSE);
1809 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1816 key_press_cb (GtkWidget* window, GdkEventKey* event)
1818 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1822 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1823 || 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)
1826 /* turn off insert mode (if always_insert_mode is not used) */
1827 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1828 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1833 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1836 if (event->keyval == GDK_Escape) {
1837 g_string_truncate(uzbl.state.keycmd, 0);
1839 dehilight(uzbl.gui.web_view, NULL);
1843 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1844 if (event->keyval == GDK_Insert) {
1846 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1847 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1849 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1852 g_string_append (uzbl.state.keycmd, str);
1859 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1860 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1864 gboolean key_ret = FALSE;
1865 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1867 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1869 run_keycmd(key_ret);
1871 if (key_ret) return (!uzbl.behave.insert_mode);
1876 run_keycmd(const gboolean key_ret) {
1877 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1879 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1880 g_string_truncate(uzbl.state.keycmd, 0);
1881 parse_command(act->name, act->param);
1885 /* try if it's an incremental keycmd or one that takes args, and run it */
1886 GString* short_keys = g_string_new ("");
1887 GString* short_keys_inc = g_string_new ("");
1889 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1890 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1891 g_string_assign(short_keys_inc, short_keys->str);
1892 g_string_append_c(short_keys, '_');
1893 g_string_append_c(short_keys_inc, '*');
1895 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1896 /* run normal cmds only if return was pressed */
1897 exec_paramcmd(act, i);
1898 g_string_truncate(uzbl.state.keycmd, 0);
1900 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1901 if (key_ret) /* just quit the incremental command on return */
1902 g_string_truncate(uzbl.state.keycmd, 0);
1903 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1907 g_string_truncate(short_keys, short_keys->len - 1);
1909 g_string_free (short_keys, TRUE);
1910 g_string_free (short_keys_inc, TRUE);
1914 exec_paramcmd(const Action *act, const guint i) {
1915 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1916 GString *actionname = g_string_new ("");
1917 GString *actionparam = g_string_new ("");
1918 g_string_erase (parampart, 0, i+1);
1920 g_string_printf (actionname, act->name, parampart->str);
1922 g_string_printf (actionparam, act->param, parampart->str);
1923 parse_command(actionname->str, actionparam->str);
1924 g_string_free(actionname, TRUE);
1925 g_string_free(actionparam, TRUE);
1926 g_string_free(parampart, TRUE);
1934 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1935 //main_window_ref = g_object_ref(scrolled_window);
1936 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
1938 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1939 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1941 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1942 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1943 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1944 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1945 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1946 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1947 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1948 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1949 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1950 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1952 return scrolled_window;
1959 g->mainbar = gtk_hbox_new (FALSE, 0);
1961 /* keep a reference to the bar so we can re-pack it at runtime*/
1962 //sbar_ref = g_object_ref(g->mainbar);
1964 g->mainbar_label = gtk_label_new ("");
1965 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1966 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1967 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1968 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1969 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1974 GtkWidget* create_window () {
1975 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1976 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1977 gtk_widget_set_name (window, "Uzbl browser");
1978 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1979 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1985 run_handler (const gchar *act, const gchar *args) {
1986 char **parts = g_strsplit(act, " ", 2);
1988 else if ((g_strcmp0(parts[0], "spawn") == 0)
1989 || (g_strcmp0(parts[0], "sh") == 0)
1990 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1991 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
1993 GString *a = g_string_new ("");
1995 spawnparts = split_quoted(parts[1], FALSE);
1996 g_string_append_printf(a, "%s", spawnparts[0]);
1997 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
1999 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2000 g_string_append_printf(a, " %s", spawnparts[i]);
2001 parse_command(parts[0], a->str);
2002 g_string_free (a, TRUE);
2003 g_strfreev (spawnparts);
2005 parse_command(parts[0], parts[1]);
2010 add_binding (const gchar *key, const gchar *act) {
2011 char **parts = g_strsplit(act, " ", 2);
2018 if (uzbl.state.verbose)
2019 printf ("Binding %-10s : %s\n", key, act);
2020 action = new_action(parts[0], parts[1]);
2022 if (g_hash_table_remove (uzbl.bindings, key))
2023 g_warning ("Overwriting existing binding for \"%s\"", key);
2024 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2029 get_xdg_var (XDG_Var xdg) {
2030 const gchar* actual_value = getenv (xdg.environmental);
2031 const gchar* home = getenv ("HOME");
2033 gchar* return_value = str_replace ("~", home, actual_value);
2035 if (! actual_value || strcmp (actual_value, "") == 0) {
2036 if (xdg.default_value) {
2037 return_value = str_replace ("~", home, xdg.default_value);
2039 return_value = NULL;
2042 return return_value;
2046 find_xdg_file (int xdg_type, char* filename) {
2047 /* xdg_type = 0 => config
2048 xdg_type = 1 => data
2049 xdg_type = 2 => cache*/
2051 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2052 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2055 gchar* temporary_string;
2059 if (! file_exists (temporary_file) && xdg_type != 2) {
2060 buf = get_xdg_var (XDG[3 + xdg_type]);
2061 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2064 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2065 g_free (temporary_file);
2066 temporary_file = g_strconcat (temporary_string, filename, NULL);
2070 //g_free (temporary_string); - segfaults.
2072 if (file_exists (temporary_file)) {
2073 return temporary_file;
2080 State *s = &uzbl.state;
2081 Network *n = &uzbl.net;
2083 for (i = 0; default_config[i].command != NULL; i++) {
2084 parse_cmd_line(default_config[i].command);
2087 if (!s->config_file) {
2088 s->config_file = find_xdg_file (0, "/uzbl/config");
2091 if (s->config_file) {
2092 GArray* lines = read_file_by_line (s->config_file);
2096 while ((line = g_array_index(lines, gchar*, i))) {
2097 parse_cmd_line (line);
2101 g_array_free (lines, TRUE);
2103 if (uzbl.state.verbose)
2104 printf ("No configuration file loaded.\n");
2107 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2110 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2113 if (!uzbl.behave.cookie_handler) return;
2115 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2116 GString *s = g_string_new ("");
2117 SoupURI * soup_uri = soup_message_get_uri(msg);
2118 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2119 run_handler(uzbl.behave.cookie_handler, s->str);
2121 if(uzbl.comm.sync_stdout)
2122 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2123 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2124 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2126 g_string_free(s, TRUE);
2130 save_cookies (SoupMessage *msg, gpointer user_data){
2134 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2135 cookie = soup_cookie_to_set_cookie_header(ck->data);
2136 SoupURI * soup_uri = soup_message_get_uri(msg);
2137 GString *s = g_string_new ("");
2138 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2139 run_handler(uzbl.behave.cookie_handler, s->str);
2141 g_string_free(s, TRUE);
2146 /* --- WEBINSPECTOR --- */
2148 hide_window_cb(GtkWidget *widget, gpointer data) {
2151 gtk_widget_hide(widget);
2154 static WebKitWebView*
2155 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2158 (void) web_inspector;
2159 GtkWidget* scrolled_window;
2160 GtkWidget* new_web_view;
2163 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2164 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2165 G_CALLBACK(hide_window_cb), NULL);
2167 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2168 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2169 gtk_widget_show(g->inspector_window);
2171 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2172 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2173 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2174 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2175 gtk_widget_show(scrolled_window);
2177 new_web_view = webkit_web_view_new();
2178 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2180 return WEBKIT_WEB_VIEW(new_web_view);
2184 inspector_show_window_cb (WebKitWebInspector* inspector){
2186 gtk_widget_show(uzbl.gui.inspector_window);
2190 /* TODO: Add variables and code to make use of these functions */
2192 inspector_close_window_cb (WebKitWebInspector* inspector){
2198 inspector_attach_window_cb (WebKitWebInspector* inspector){
2204 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2210 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2216 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2222 set_up_inspector() {
2224 WebKitWebSettings *settings = view_settings();
2225 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2227 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2228 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2229 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2230 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2231 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2232 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2233 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2235 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2239 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2241 uzbl_cmdprop *c = v;
2246 if(c->type == TYPE_STR)
2247 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2248 else if(c->type == TYPE_INT)
2249 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2253 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2257 printf("bind %s = %s %s\n", (char *)k ,
2258 (char *)a->name, a->param?(char *)a->param:"");
2263 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2264 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2269 main (int argc, char* argv[]) {
2270 gtk_init (&argc, &argv);
2271 if (!g_thread_supported ())
2272 g_thread_init (NULL);
2273 uzbl.state.executable_path = g_strdup(argv[0]);
2274 uzbl.state.selected_url = NULL;
2275 uzbl.state.searchtx = NULL;
2277 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2278 g_option_context_add_main_entries (context, entries, NULL);
2279 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2280 g_option_context_parse (context, &argc, &argv, NULL);
2281 g_option_context_free(context);
2282 /* initialize hash table */
2283 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2285 uzbl.net.soup_session = webkit_get_default_session();
2286 uzbl.state.keycmd = g_string_new("");
2288 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2289 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2290 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2291 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2292 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2293 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2296 if(uname(&uzbl.state.unameinfo) == -1)
2297 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2299 uzbl.gui.sbar.progress_s = g_strdup("=");
2300 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2301 uzbl.gui.sbar.progress_w = 10;
2303 /* HTML mode defaults*/
2304 uzbl.behave.html_buffer = g_string_new("");
2305 uzbl.behave.html_endmarker = g_strdup(".");
2306 uzbl.behave.html_timeout = 60;
2307 uzbl.behave.base_url = g_strdup("http://invalid");
2309 /* default mode indicators */
2310 uzbl.behave.insert_indicator = g_strdup("I");
2311 uzbl.behave.cmd_indicator = g_strdup("C");
2316 make_var_to_name_hash();
2318 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2320 uzbl.gui.scrolled_win = create_browser();
2323 /* initial packing */
2324 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2325 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2327 uzbl.gui.main_window = create_window ();
2328 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2331 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2332 gtk_widget_show_all (uzbl.gui.main_window);
2333 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2335 if (uzbl.state.verbose) {
2336 printf("Uzbl start location: %s\n", argv[0]);
2337 printf("window_id %i\n",(int) uzbl.xwin);
2338 printf("pid %i\n", getpid ());
2339 printf("name: %s\n", uzbl.state.instance_name);
2342 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2343 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2344 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2345 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2346 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2350 if (!uzbl.behave.show_status)
2351 gtk_widget_hide(uzbl.gui.mainbar);
2360 if(uzbl.state.uri) {
2361 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2362 g_array_append_val(a, uzbl.state.uri);
2363 load_uri (uzbl.gui.web_view, a);
2364 g_array_free (a, TRUE);
2370 return EXIT_SUCCESS;
2373 /* vi: set et ts=4: */