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} },
571 { "keycmd_bs", {keycmd_bs, 0} }
578 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
580 for (i = 0; i < LENGTH(cmdlist); i++)
581 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
584 /* -- CORE FUNCTIONS -- */
587 free_action(gpointer act) {
588 Action *action = (Action*)act;
589 g_free(action->name);
591 g_free(action->param);
596 new_action(const gchar *name, const gchar *param) {
597 Action *action = g_new(Action, 1);
599 action->name = g_strdup(name);
601 action->param = g_strdup(param);
603 action->param = NULL;
609 file_exists (const char * filename) {
610 return (access(filename, F_OK) == 0);
614 set_var(WebKitWebView *page, GArray *argv) {
618 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
619 parse_cmd_line(ctl_line);
629 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
632 if (argv_idx(argv, 0)) {
633 if (strcmp (argv_idx(argv, 0), "0") == 0) {
634 uzbl.behave.insert_mode = FALSE;
636 uzbl.behave.insert_mode = TRUE;
639 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
646 load_uri (WebKitWebView *web_view, GArray *argv) {
647 if (argv_idx(argv, 0)) {
648 GString* newuri = g_string_new (argv_idx(argv, 0));
649 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
650 g_string_prepend (newuri, "http://");
651 /* if we do handle cookies, ask our handler for them */
652 webkit_web_view_load_uri (web_view, newuri->str);
653 g_string_free (newuri, TRUE);
658 run_js (WebKitWebView * web_view, GArray *argv) {
659 if (argv_idx(argv, 0))
660 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
664 run_external_js (WebKitWebView * web_view, GArray *argv) {
665 if (argv_idx(argv, 0)) {
666 GArray* lines = read_file_by_line (argv_idx (argv, 0));
671 while ((line = g_array_index(lines, gchar*, i))) {
673 js = g_strdup (line);
675 gchar* newjs = g_strconcat (js, line, NULL);
682 if (uzbl.state.verbose)
683 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
685 if (argv_idx (argv, 1)) {
686 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
690 webkit_web_view_execute_script (web_view, js);
692 g_array_free (lines, TRUE);
697 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
698 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
699 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
700 webkit_web_view_unmark_text_matches (page);
701 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
702 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
706 if (uzbl.state.searchtx) {
707 if (uzbl.state.verbose)
708 printf ("Searching: %s\n", uzbl.state.searchtx);
709 webkit_web_view_set_highlight_text_matches (page, TRUE);
710 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
715 search_forward_text (WebKitWebView *page, GArray *argv) {
716 search_text(page, argv, TRUE);
720 search_reverse_text (WebKitWebView *page, GArray *argv) {
721 search_text(page, argv, FALSE);
725 dehilight (WebKitWebView *page, GArray *argv) {
727 webkit_web_view_set_highlight_text_matches (page, FALSE);
732 new_window_load_uri (const gchar * uri) {
733 GString* to_execute = g_string_new ("");
734 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
736 for (i = 0; entries[i].long_name != NULL; i++) {
737 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
738 gchar** str = (gchar**)entries[i].arg_data;
740 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
744 if (uzbl.state.verbose)
745 printf("\n%s\n", to_execute->str);
746 g_spawn_command_line_async (to_execute->str, NULL);
747 g_string_free (to_execute, TRUE);
751 keycmd_bs (WebKitWebView *page, GArray *argv) {
754 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
759 close_uzbl (WebKitWebView *page, GArray *argv) {
765 /* --Statusbar functions-- */
767 build_progressbar_ascii(int percent) {
768 int width=uzbl.gui.sbar.progress_w;
771 GString *bar = g_string_new("");
773 l = (double)percent*((double)width/100.);
774 l = (int)(l+.5)>=(int)l ? l+.5 : l;
776 for(i=0; i<(int)l; i++)
777 g_string_append(bar, uzbl.gui.sbar.progress_s);
780 g_string_append(bar, uzbl.gui.sbar.progress_u);
782 return g_string_free(bar, FALSE);
787 const GScannerConfig scan_config = {
790 ) /* cset_skip_characters */,
795 ) /* cset_identifier_first */,
802 ) /* cset_identifier_nth */,
803 ( "" ) /* cpair_comment_single */,
805 TRUE /* case_sensitive */,
807 FALSE /* skip_comment_multi */,
808 FALSE /* skip_comment_single */,
809 FALSE /* scan_comment_multi */,
810 TRUE /* scan_identifier */,
811 TRUE /* scan_identifier_1char */,
812 FALSE /* scan_identifier_NULL */,
813 TRUE /* scan_symbols */,
814 FALSE /* scan_binary */,
815 FALSE /* scan_octal */,
816 FALSE /* scan_float */,
817 FALSE /* scan_hex */,
818 FALSE /* scan_hex_dollar */,
819 FALSE /* scan_string_sq */,
820 FALSE /* scan_string_dq */,
821 TRUE /* numbers_2_int */,
822 FALSE /* int_2_float */,
823 FALSE /* identifier_2_string */,
824 FALSE /* char_2_token */,
825 FALSE /* symbol_2_token */,
826 TRUE /* scope_0_fallback */,
831 uzbl.scan = g_scanner_new(&scan_config);
832 while(symp->symbol_name) {
833 g_scanner_scope_add_symbol(uzbl.scan, 0,
835 GINT_TO_POINTER(symp->symbol_token));
841 expand_template(const char *template, gboolean escape_markup) {
842 if(!template) return NULL;
844 GTokenType token = G_TOKEN_NONE;
845 GString *ret = g_string_new("");
849 g_scanner_input_text(uzbl.scan, template, strlen(template));
850 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
851 token = g_scanner_get_next_token(uzbl.scan);
853 if(token == G_TOKEN_SYMBOL) {
854 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
858 buf = uzbl.state.uri?
859 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
860 g_string_append(ret, buf);
864 g_string_append(ret, uzbl.state.uri?
865 uzbl.state.uri:g_strdup(""));
868 buf = itos(uzbl.gui.sbar.load_progress);
869 g_string_append(ret, buf);
872 case SYM_LOADPRGSBAR:
873 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
874 g_string_append(ret, buf);
879 buf = uzbl.gui.main_title?
880 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
881 g_string_append(ret, buf);
885 g_string_append(ret, uzbl.gui.main_title?
886 uzbl.gui.main_title:g_strdup(""));
888 case SYM_SELECTED_URI:
890 buf = uzbl.state.selected_url?
891 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
892 g_string_append(ret, buf);
896 g_string_append(ret, uzbl.state.selected_url?
897 uzbl.state.selected_url:g_strdup(""));
900 buf = itos(uzbl.xwin);
902 uzbl.state.instance_name?uzbl.state.instance_name:buf);
907 buf = uzbl.state.keycmd->str?
908 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
909 g_string_append(ret, buf);
913 g_string_append(ret, uzbl.state.keycmd->str?
914 uzbl.state.keycmd->str:g_strdup(""));
918 uzbl.behave.insert_mode?
919 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
923 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
927 buf = itos(WEBKIT_MAJOR_VERSION);
928 g_string_append(ret, buf);
932 buf = itos(WEBKIT_MINOR_VERSION);
933 g_string_append(ret, buf);
937 buf = itos(WEBKIT_MICRO_VERSION);
938 g_string_append(ret, buf);
942 g_string_append(ret, uzbl.state.unameinfo.sysname);
945 g_string_append(ret, uzbl.state.unameinfo.nodename);
948 g_string_append(ret, uzbl.state.unameinfo.release);
951 g_string_append(ret, uzbl.state.unameinfo.version);
954 g_string_append(ret, uzbl.state.unameinfo.machine);
957 g_string_append(ret, ARCH);
961 g_string_append(ret, uzbl.state.unameinfo.domainname);
965 g_string_append(ret, COMMIT);
971 else if(token == G_TOKEN_INT) {
972 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
973 g_string_append(ret, buf);
976 else if(token == G_TOKEN_IDENTIFIER) {
977 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
979 else if(token == G_TOKEN_CHAR) {
980 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
984 return g_string_free(ret, FALSE);
986 /* --End Statusbar functions-- */
989 sharg_append(GArray *a, const gchar *str) {
990 const gchar *s = (str ? str : "");
991 g_array_append_val(a, s);
994 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
996 run_command (const gchar *command, const guint npre, const gchar **args,
997 const gboolean sync, char **stdout) {
998 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1001 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1002 gchar *pid = itos(getpid());
1003 gchar *xwin = itos(uzbl.xwin);
1005 sharg_append(a, command);
1006 for (i = 0; i < npre; i++) /* add n args before the default vars */
1007 sharg_append(a, args[i]);
1008 sharg_append(a, uzbl.state.config_file);
1009 sharg_append(a, pid);
1010 sharg_append(a, xwin);
1011 sharg_append(a, uzbl.comm.fifo_path);
1012 sharg_append(a, uzbl.comm.socket_path);
1013 sharg_append(a, uzbl.state.uri);
1014 sharg_append(a, uzbl.gui.main_title);
1016 for (i = npre; i < g_strv_length((gchar**)args); i++)
1017 sharg_append(a, args[i]);
1021 if (*stdout) *stdout = strfree(*stdout);
1023 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1024 NULL, NULL, stdout, NULL, NULL, &err);
1025 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1026 NULL, NULL, NULL, &err);
1028 if (uzbl.state.verbose) {
1029 GString *s = g_string_new("spawned:");
1030 for (i = 0; i < (a->len); i++) {
1031 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1032 g_string_append_printf(s, " %s", qarg);
1035 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1036 printf("%s\n", s->str);
1037 g_string_free(s, TRUE);
1040 g_printerr("error on run_command: %s\n", err->message);
1045 g_array_free (a, TRUE);
1050 split_quoted(const gchar* src, const gboolean unquote) {
1051 /* split on unquoted space, return array of strings;
1052 remove a layer of quotes and backslashes if unquote */
1053 if (!src) return NULL;
1055 gboolean dq = FALSE;
1056 gboolean sq = FALSE;
1057 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1058 GString *s = g_string_new ("");
1062 for (p = src; *p != '\0'; p++) {
1063 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1064 else if (*p == '\\') { g_string_append_c(s, *p++);
1065 g_string_append_c(s, *p); }
1066 else if ((*p == '"') && unquote && !sq) dq = !dq;
1067 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1069 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1070 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1072 else if ((*p == ' ') && !dq && !sq) {
1073 dup = g_strdup(s->str);
1074 g_array_append_val(a, dup);
1075 g_string_truncate(s, 0);
1076 } else g_string_append_c(s, *p);
1078 dup = g_strdup(s->str);
1079 g_array_append_val(a, dup);
1080 ret = (gchar**)a->data;
1081 g_array_free (a, FALSE);
1082 g_string_free (s, TRUE);
1087 spawn(WebKitWebView *web_view, GArray *argv) {
1089 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1090 if (argv_idx(argv, 0))
1091 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1095 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1098 if (argv_idx(argv, 0))
1099 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1100 TRUE, &uzbl.comm.sync_stdout);
1104 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1106 if (!uzbl.behave.shell_cmd) {
1107 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1112 gchar *spacer = g_strdup("");
1113 g_array_insert_val(argv, 1, spacer);
1114 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1116 for (i = 1; i < g_strv_length(cmd); i++)
1117 g_array_prepend_val(argv, cmd[i]);
1119 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1125 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1127 if (!uzbl.behave.shell_cmd) {
1128 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1133 gchar *spacer = g_strdup("");
1134 g_array_insert_val(argv, 1, spacer);
1135 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1137 for (i = 1; i < g_strv_length(cmd); i++)
1138 g_array_prepend_val(argv, cmd[i]);
1140 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1141 TRUE, &uzbl.comm.sync_stdout);
1147 parse_command(const char *cmd, const char *param) {
1150 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1153 gchar **par = split_quoted(param, TRUE);
1154 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1156 if (c[1] == NOSPLIT) { /* don't split */
1157 sharg_append(a, param);
1159 for (i = 0; i < g_strv_length(par); i++)
1160 sharg_append(a, par[i]);
1162 c[0](uzbl.gui.web_view, a);
1164 g_array_free (a, TRUE);
1167 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1170 /* command parser */
1173 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1174 G_REGEX_OPTIMIZE, 0, NULL);
1175 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1176 G_REGEX_OPTIMIZE, 0, NULL);
1177 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1178 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1179 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1180 G_REGEX_OPTIMIZE, 0, NULL);
1181 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
1182 G_REGEX_OPTIMIZE, 0, NULL);
1186 get_var_value(gchar *name) {
1189 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1190 if(c->type == TYPE_STR)
1191 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1192 else if(c->type == TYPE_INT)
1193 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1202 if(*uzbl.net.proxy_url == ' '
1203 || uzbl.net.proxy_url == NULL) {
1204 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1205 (GType) SOUP_SESSION_PROXY_URI);
1208 suri = soup_uri_new(uzbl.net.proxy_url);
1209 g_object_set(G_OBJECT(uzbl.net.soup_session),
1210 SOUP_SESSION_PROXY_URI,
1212 soup_uri_free(suri);
1219 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1220 g_array_append_val (a, uzbl.state.uri);
1221 load_uri(uzbl.gui.web_view, a);
1222 g_array_free (a, TRUE);
1226 cmd_always_insert_mode() {
1227 uzbl.behave.insert_mode =
1228 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1234 g_object_set(G_OBJECT(uzbl.net.soup_session),
1235 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1239 cmd_max_conns_host() {
1240 g_object_set(G_OBJECT(uzbl.net.soup_session),
1241 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1246 soup_session_remove_feature
1247 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1248 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1249 /*g_free(uzbl.net.soup_logger);*/
1251 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1252 soup_session_add_feature(uzbl.net.soup_session,
1253 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1256 static WebKitWebSettings*
1258 return webkit_web_view_get_settings(uzbl.gui.web_view);
1263 WebKitWebSettings *ws = view_settings();
1264 if (uzbl.behave.font_size > 0) {
1265 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1268 if (uzbl.behave.monospace_size > 0) {
1269 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1270 uzbl.behave.monospace_size, NULL);
1272 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1273 uzbl.behave.font_size, NULL);
1278 cmd_disable_plugins() {
1279 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1280 !uzbl.behave.disable_plugins, NULL);
1284 cmd_disable_scripts() {
1285 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1286 !uzbl.behave.disable_plugins, NULL);
1290 cmd_minimum_font_size() {
1291 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1292 uzbl.behave.minimum_font_size, NULL);
1295 cmd_autoload_img() {
1296 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1297 uzbl.behave.autoload_img, NULL);
1302 cmd_autoshrink_img() {
1303 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1304 uzbl.behave.autoshrink_img, NULL);
1309 cmd_enable_spellcheck() {
1310 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1311 uzbl.behave.enable_spellcheck, NULL);
1315 cmd_enable_private() {
1316 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1317 uzbl.behave.enable_private, NULL);
1322 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1323 uzbl.behave.print_bg, NULL);
1328 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1329 uzbl.behave.style_uri, NULL);
1333 cmd_resizable_txt() {
1334 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1335 uzbl.behave.resizable_txt, NULL);
1339 cmd_default_encoding() {
1340 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1341 uzbl.behave.default_encoding, NULL);
1345 cmd_enforce_96dpi() {
1346 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1347 uzbl.behave.enforce_96dpi, NULL);
1351 cmd_caret_browsing() {
1352 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1353 uzbl.behave.caret_browsing, NULL);
1357 cmd_cookie_handler() {
1358 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1359 if ((g_strcmp0(split[0], "sh") == 0) ||
1360 (g_strcmp0(split[0], "spawn") == 0)) {
1361 g_free (uzbl.behave.cookie_handler);
1362 uzbl.behave.cookie_handler =
1363 g_strdup_printf("sync_%s %s", split[0], split[1]);
1370 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1375 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1380 if(uzbl.behave.inject_html) {
1381 webkit_web_view_load_html_string (uzbl.gui.web_view,
1382 uzbl.behave.inject_html, NULL);
1391 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1392 uzbl.behave.modmask = 0;
1394 if(uzbl.behave.modkey)
1395 g_free(uzbl.behave.modkey);
1396 uzbl.behave.modkey = buf;
1398 for (i = 0; modkeys[i].key != NULL; i++) {
1399 if (g_strrstr(buf, modkeys[i].key))
1400 uzbl.behave.modmask |= modkeys[i].mask;
1406 if (*uzbl.net.useragent == ' ') {
1407 g_free (uzbl.net.useragent);
1408 uzbl.net.useragent = NULL;
1410 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1412 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1413 g_free(uzbl.net.useragent);
1414 uzbl.net.useragent = ua;
1420 gtk_widget_ref(uzbl.gui.scrolled_win);
1421 gtk_widget_ref(uzbl.gui.mainbar);
1422 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1423 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1425 if(uzbl.behave.status_top) {
1426 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1427 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1430 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1431 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1433 gtk_widget_unref(uzbl.gui.scrolled_win);
1434 gtk_widget_unref(uzbl.gui.mainbar);
1435 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1440 set_var_value(gchar *name, gchar *val) {
1441 uzbl_cmdprop *c = NULL;
1444 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1445 /* check for the variable type */
1446 if (c->type == TYPE_STR) {
1448 *c->ptr = g_strdup(val);
1449 } else if(c->type == TYPE_INT) {
1450 int *ip = (int *)c->ptr;
1451 *ip = (int)strtoul(val, &endp, 10);
1454 /* invoke a command specific function */
1455 if(c->func) c->func();
1461 runcmd(WebKitWebView* page, GArray *argv) {
1463 parse_cmd_line(argv_idx(argv, 0));
1468 Behaviour *b = &uzbl.behave;
1470 if(b->html_buffer->str) {
1471 webkit_web_view_load_html_string (uzbl.gui.web_view,
1472 b->html_buffer->str, b->base_url);
1473 g_string_free(b->html_buffer, TRUE);
1474 b->html_buffer = g_string_new("");
1478 enum {M_CMD, M_HTML};
1480 parse_cmd_line(const char *ctl_line) {
1481 gchar **tokens = NULL;
1482 Behaviour *b = &uzbl.behave;
1485 if(b->mode == M_HTML) {
1486 len = strlen(b->html_endmarker);
1487 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1488 if(len == strlen(ctl_line)-1 &&
1489 !strncmp(b->html_endmarker, ctl_line, len)) {
1491 set_var_value("mode", "0");
1496 set_timeout(b->html_timeout);
1497 g_string_append(b->html_buffer, ctl_line);
1502 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1503 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1504 if(tokens[0][0] == 0) {
1505 gchar* value = parseenv(g_strdup(tokens[2]));
1506 set_var_value(tokens[1], value);
1510 printf("Error in command: %s\n", tokens[0]);
1513 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1514 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1515 if(tokens[0][0] == 0) {
1516 get_var_value(tokens[1]);
1519 printf("Error in command: %s\n", tokens[0]);
1522 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1523 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1524 if(tokens[0][0] == 0) {
1525 gchar* value = parseenv(g_strdup(tokens[2]));
1526 add_binding(tokens[1], value);
1530 printf("Error in command: %s\n", tokens[0]);
1533 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1534 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1535 if(tokens[0][0] == 0) {
1536 parse_command(tokens[1], tokens[2]);
1539 printf("Error in command: %s\n", tokens[0]);
1541 /* KEYCMD command */
1542 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1543 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1544 if(tokens[0][0] == 0) {
1545 /* should incremental commands want each individual "keystroke"
1546 sent in a loop or the whole string in one go like now? */
1547 g_string_assign(uzbl.state.keycmd, tokens[1]);
1549 if (g_strstr_len(ctl_line, 7, "n") || g_strstr_len(ctl_line, 7, "N"))
1555 else if( (ctl_line[0] == '#')
1556 || (ctl_line[0] == ' ')
1557 || (ctl_line[0] == '\n'))
1558 ; /* ignore these lines */
1560 printf("Command not understood (%s)\n", ctl_line);
1570 build_stream_name(int type, const gchar* dir) {
1572 State *s = &uzbl.state;
1575 xwin_str = itos((int)uzbl.xwin);
1577 str = g_strdup_printf
1578 ("%s/uzbl_fifo_%s", dir,
1579 s->instance_name ? s->instance_name : xwin_str);
1580 } else if (type == SOCKET) {
1581 str = g_strdup_printf
1582 ("%s/uzbl_socket_%s", dir,
1583 s->instance_name ? s->instance_name : xwin_str );
1590 control_fifo(GIOChannel *gio, GIOCondition condition) {
1591 if (uzbl.state.verbose)
1592 printf("triggered\n");
1597 if (condition & G_IO_HUP)
1598 g_error ("Fifo: Read end of pipe died!\n");
1601 g_error ("Fifo: GIOChannel broke\n");
1603 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1604 if (ret == G_IO_STATUS_ERROR) {
1605 g_error ("Fifo: Error reading: %s\n", err->message);
1609 parse_cmd_line(ctl_line);
1616 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1617 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1618 if (unlink(uzbl.comm.fifo_path) == -1)
1619 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1620 g_free(uzbl.comm.fifo_path);
1621 uzbl.comm.fifo_path = NULL;
1624 if (*dir == ' ') { /* space unsets the variable */
1629 GIOChannel *chan = NULL;
1630 GError *error = NULL;
1631 gchar *path = build_stream_name(FIFO, dir);
1633 if (!file_exists(path)) {
1634 if (mkfifo (path, 0666) == 0) {
1635 // 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.
1636 chan = g_io_channel_new_file(path, "r+", &error);
1638 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1639 if (uzbl.state.verbose)
1640 printf ("init_fifo: created successfully as %s\n", path);
1641 uzbl.comm.fifo_path = path;
1643 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1644 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1645 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1646 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1648 /* if we got this far, there was an error; cleanup */
1649 if (error) g_error_free (error);
1656 control_stdin(GIOChannel *gio, GIOCondition condition) {
1658 gchar *ctl_line = NULL;
1661 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1662 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1665 parse_cmd_line(ctl_line);
1673 GIOChannel *chan = NULL;
1674 GError *error = NULL;
1676 chan = g_io_channel_unix_new(fileno(stdin));
1678 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1679 g_error ("Stdin: could not add watch\n");
1681 if (uzbl.state.verbose)
1682 printf ("Stdin: watch added successfully\n");
1685 g_error ("Stdin: Error while opening: %s\n", error->message);
1687 if (error) g_error_free (error);
1691 control_socket(GIOChannel *chan) {
1692 struct sockaddr_un remote;
1693 char buffer[512], *ctl_line;
1695 int sock, clientsock, n, done;
1698 sock = g_io_channel_unix_get_fd(chan);
1700 memset (buffer, 0, sizeof (buffer));
1702 t = sizeof (remote);
1703 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1707 memset (temp, 0, sizeof (temp));
1708 n = recv (clientsock, temp, 128, 0);
1710 buffer[strlen (buffer)] = '\0';
1714 strcat (buffer, temp);
1717 if (strcmp (buffer, "\n") < 0) {
1718 buffer[strlen (buffer) - 1] = '\0';
1720 buffer[strlen (buffer)] = '\0';
1723 ctl_line = g_strdup(buffer);
1724 parse_cmd_line (ctl_line);
1727 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1728 GError *error = NULL;
1731 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1732 if (ret == G_IO_STATUS_ERROR)
1733 g_error ("Error reading: %s\n", error->message);
1735 printf("Got line %s (%u bytes) \n",ctl_line, len);
1737 parse_line(ctl_line);
1745 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1746 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1747 if (unlink(uzbl.comm.socket_path) == -1)
1748 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1749 g_free(uzbl.comm.socket_path);
1750 uzbl.comm.socket_path = NULL;
1758 GIOChannel *chan = NULL;
1760 struct sockaddr_un local;
1761 gchar *path = build_stream_name(SOCKET, dir);
1763 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1765 local.sun_family = AF_UNIX;
1766 strcpy (local.sun_path, path);
1767 unlink (local.sun_path);
1769 len = strlen (local.sun_path) + sizeof (local.sun_family);
1770 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1771 if (uzbl.state.verbose)
1772 printf ("init_socket: opened in %s\n", path);
1775 if( (chan = g_io_channel_unix_new(sock)) ) {
1776 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1777 uzbl.comm.socket_path = path;
1780 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1782 /* if we got this far, there was an error; cleanup */
1789 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1790 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1792 // this function may be called very early when the templates are not set (yet), hence the checks
1794 update_title (void) {
1795 Behaviour *b = &uzbl.behave;
1798 if (b->show_status) {
1799 if (b->title_format_short) {
1800 parsed = expand_template(b->title_format_short, FALSE);
1801 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1804 if (b->status_format) {
1805 parsed = expand_template(b->status_format, TRUE);
1806 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1809 if (b->status_background) {
1811 gdk_color_parse (b->status_background, &color);
1812 //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)
1813 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1816 if (b->title_format_long) {
1817 parsed = expand_template(b->title_format_long, FALSE);
1818 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1825 key_press_cb (GtkWidget* window, GdkEventKey* event)
1827 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1831 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1832 || 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)
1835 /* turn off insert mode (if always_insert_mode is not used) */
1836 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1837 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1842 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1845 if (event->keyval == GDK_Escape) {
1846 g_string_truncate(uzbl.state.keycmd, 0);
1848 dehilight(uzbl.gui.web_view, NULL);
1852 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1853 if (event->keyval == GDK_Insert) {
1855 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1856 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1858 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1861 g_string_append (uzbl.state.keycmd, str);
1868 if (event->keyval == GDK_BackSpace)
1869 keycmd_bs(NULL, NULL);
1871 gboolean key_ret = FALSE;
1872 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1874 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1876 run_keycmd(key_ret);
1878 if (key_ret) return (!uzbl.behave.insert_mode);
1883 run_keycmd(const gboolean key_ret) {
1884 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1886 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1887 g_string_truncate(uzbl.state.keycmd, 0);
1888 parse_command(act->name, act->param);
1892 /* try if it's an incremental keycmd or one that takes args, and run it */
1893 GString* short_keys = g_string_new ("");
1894 GString* short_keys_inc = g_string_new ("");
1896 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1897 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1898 g_string_assign(short_keys_inc, short_keys->str);
1899 g_string_append_c(short_keys, '_');
1900 g_string_append_c(short_keys_inc, '*');
1902 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1903 /* run normal cmds only if return was pressed */
1904 exec_paramcmd(act, i);
1905 g_string_truncate(uzbl.state.keycmd, 0);
1907 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1908 if (key_ret) /* just quit the incremental command on return */
1909 g_string_truncate(uzbl.state.keycmd, 0);
1910 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1914 g_string_truncate(short_keys, short_keys->len - 1);
1916 g_string_free (short_keys, TRUE);
1917 g_string_free (short_keys_inc, TRUE);
1921 exec_paramcmd(const Action *act, const guint i) {
1922 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1923 GString *actionname = g_string_new ("");
1924 GString *actionparam = g_string_new ("");
1925 g_string_erase (parampart, 0, i+1);
1927 g_string_printf (actionname, act->name, parampart->str);
1929 g_string_printf (actionparam, act->param, parampart->str);
1930 parse_command(actionname->str, actionparam->str);
1931 g_string_free(actionname, TRUE);
1932 g_string_free(actionparam, TRUE);
1933 g_string_free(parampart, TRUE);
1941 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1942 //main_window_ref = g_object_ref(scrolled_window);
1943 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
1945 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1946 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1948 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1949 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1950 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1951 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1952 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1953 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1954 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1955 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1956 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1957 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1959 return scrolled_window;
1966 g->mainbar = gtk_hbox_new (FALSE, 0);
1968 /* keep a reference to the bar so we can re-pack it at runtime*/
1969 //sbar_ref = g_object_ref(g->mainbar);
1971 g->mainbar_label = gtk_label_new ("");
1972 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1973 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1974 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1975 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1976 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1981 GtkWidget* create_window () {
1982 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1983 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1984 gtk_widget_set_name (window, "Uzbl browser");
1985 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1986 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
1992 run_handler (const gchar *act, const gchar *args) {
1993 char **parts = g_strsplit(act, " ", 2);
1995 else if ((g_strcmp0(parts[0], "spawn") == 0)
1996 || (g_strcmp0(parts[0], "sh") == 0)
1997 || (g_strcmp0(parts[0], "sync_spawn") == 0)
1998 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
2000 GString *a = g_string_new ("");
2002 spawnparts = split_quoted(parts[1], FALSE);
2003 g_string_append_printf(a, "%s", spawnparts[0]);
2004 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
2006 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2007 g_string_append_printf(a, " %s", spawnparts[i]);
2008 parse_command(parts[0], a->str);
2009 g_string_free (a, TRUE);
2010 g_strfreev (spawnparts);
2012 parse_command(parts[0], parts[1]);
2017 add_binding (const gchar *key, const gchar *act) {
2018 char **parts = g_strsplit(act, " ", 2);
2025 if (uzbl.state.verbose)
2026 printf ("Binding %-10s : %s\n", key, act);
2027 action = new_action(parts[0], parts[1]);
2029 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2034 get_xdg_var (XDG_Var xdg) {
2035 const gchar* actual_value = getenv (xdg.environmental);
2036 const gchar* home = getenv ("HOME");
2038 gchar* return_value = str_replace ("~", home, actual_value);
2040 if (! actual_value || strcmp (actual_value, "") == 0) {
2041 if (xdg.default_value) {
2042 return_value = str_replace ("~", home, xdg.default_value);
2044 return_value = NULL;
2047 return return_value;
2051 find_xdg_file (int xdg_type, char* filename) {
2052 /* xdg_type = 0 => config
2053 xdg_type = 1 => data
2054 xdg_type = 2 => cache*/
2056 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2057 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2060 gchar* temporary_string;
2064 if (! file_exists (temporary_file) && xdg_type != 2) {
2065 buf = get_xdg_var (XDG[3 + xdg_type]);
2066 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2069 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2070 g_free (temporary_file);
2071 temporary_file = g_strconcat (temporary_string, filename, NULL);
2075 //g_free (temporary_string); - segfaults.
2077 if (file_exists (temporary_file)) {
2078 return temporary_file;
2085 State *s = &uzbl.state;
2086 Network *n = &uzbl.net;
2088 for (i = 0; default_config[i].command != NULL; i++) {
2089 parse_cmd_line(default_config[i].command);
2092 if (!s->config_file) {
2093 s->config_file = find_xdg_file (0, "/uzbl/config");
2096 if (s->config_file) {
2097 GArray* lines = read_file_by_line (s->config_file);
2101 while ((line = g_array_index(lines, gchar*, i))) {
2102 parse_cmd_line (line);
2106 g_array_free (lines, TRUE);
2108 if (uzbl.state.verbose)
2109 printf ("No configuration file loaded.\n");
2112 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2115 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2118 if (!uzbl.behave.cookie_handler) return;
2120 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2121 GString *s = g_string_new ("");
2122 SoupURI * soup_uri = soup_message_get_uri(msg);
2123 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2124 run_handler(uzbl.behave.cookie_handler, s->str);
2126 if(uzbl.comm.sync_stdout)
2127 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2128 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2129 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2131 g_string_free(s, TRUE);
2135 save_cookies (SoupMessage *msg, gpointer user_data){
2139 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2140 cookie = soup_cookie_to_set_cookie_header(ck->data);
2141 SoupURI * soup_uri = soup_message_get_uri(msg);
2142 GString *s = g_string_new ("");
2143 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2144 run_handler(uzbl.behave.cookie_handler, s->str);
2146 g_string_free(s, TRUE);
2151 /* --- WEBINSPECTOR --- */
2153 hide_window_cb(GtkWidget *widget, gpointer data) {
2156 gtk_widget_hide(widget);
2159 static WebKitWebView*
2160 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2163 (void) web_inspector;
2164 GtkWidget* scrolled_window;
2165 GtkWidget* new_web_view;
2168 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2169 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2170 G_CALLBACK(hide_window_cb), NULL);
2172 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2173 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2174 gtk_widget_show(g->inspector_window);
2176 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2177 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2178 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2179 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2180 gtk_widget_show(scrolled_window);
2182 new_web_view = webkit_web_view_new();
2183 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2185 return WEBKIT_WEB_VIEW(new_web_view);
2189 inspector_show_window_cb (WebKitWebInspector* inspector){
2191 gtk_widget_show(uzbl.gui.inspector_window);
2195 /* TODO: Add variables and code to make use of these functions */
2197 inspector_close_window_cb (WebKitWebInspector* inspector){
2203 inspector_attach_window_cb (WebKitWebInspector* inspector){
2209 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2215 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2221 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2227 set_up_inspector() {
2229 WebKitWebSettings *settings = view_settings();
2230 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2232 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2233 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2234 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2235 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2236 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2237 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2238 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2240 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2244 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2246 uzbl_cmdprop *c = v;
2251 if(c->type == TYPE_STR)
2252 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2253 else if(c->type == TYPE_INT)
2254 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2258 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2262 printf("bind %s = %s %s\n", (char *)k ,
2263 (char *)a->name, a->param?(char *)a->param:"");
2268 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2269 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2274 main (int argc, char* argv[]) {
2275 gtk_init (&argc, &argv);
2276 if (!g_thread_supported ())
2277 g_thread_init (NULL);
2278 uzbl.state.executable_path = g_strdup(argv[0]);
2279 uzbl.state.selected_url = NULL;
2280 uzbl.state.searchtx = NULL;
2282 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2283 g_option_context_add_main_entries (context, entries, NULL);
2284 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2285 g_option_context_parse (context, &argc, &argv, NULL);
2286 g_option_context_free(context);
2287 /* initialize hash table */
2288 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2290 uzbl.net.soup_session = webkit_get_default_session();
2291 uzbl.state.keycmd = g_string_new("");
2293 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2294 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2295 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2296 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2297 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2298 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2301 if(uname(&uzbl.state.unameinfo) == -1)
2302 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2304 uzbl.gui.sbar.progress_s = g_strdup("=");
2305 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2306 uzbl.gui.sbar.progress_w = 10;
2308 /* HTML mode defaults*/
2309 uzbl.behave.html_buffer = g_string_new("");
2310 uzbl.behave.html_endmarker = g_strdup(".");
2311 uzbl.behave.html_timeout = 60;
2312 uzbl.behave.base_url = g_strdup("http://invalid");
2314 /* default mode indicators */
2315 uzbl.behave.insert_indicator = g_strdup("I");
2316 uzbl.behave.cmd_indicator = g_strdup("C");
2321 make_var_to_name_hash();
2323 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2325 uzbl.gui.scrolled_win = create_browser();
2328 /* initial packing */
2329 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2330 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2332 uzbl.gui.main_window = create_window ();
2333 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2336 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2337 gtk_widget_show_all (uzbl.gui.main_window);
2338 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2340 if (uzbl.state.verbose) {
2341 printf("Uzbl start location: %s\n", argv[0]);
2342 printf("window_id %i\n",(int) uzbl.xwin);
2343 printf("pid %i\n", getpid ());
2344 printf("name: %s\n", uzbl.state.instance_name);
2347 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2348 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2349 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2350 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2351 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2355 if (!uzbl.behave.show_status)
2356 gtk_widget_hide(uzbl.gui.mainbar);
2365 if(uzbl.state.uri) {
2366 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2367 g_array_append_val(a, uzbl.state.uri);
2368 load_uri (uzbl.gui.web_view, a);
2369 g_array_free (a, TRUE);
2375 return EXIT_SUCCESS;
2378 /* vi: set et ts=4: */