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
39 #include <gdk/gdkkeysyms.h>
40 #include <sys/socket.h>
42 #include <sys/types.h>
44 #include <sys/utsname.h>
46 #include <webkit/webkit.h>
47 #include <libsoup/soup.h>
60 typedef void (*Command)(WebKitWebView*, GArray *argv);
64 /* commandline arguments (set initial values for the state variables) */
66 GOptionEntry entries[] =
68 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
69 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
70 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
71 "Whether to print all messages or just errors.", NULL },
72 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
73 "Name of the current instance (defaults to Xorg window id)", "NAME" },
74 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
75 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
76 { NULL, 0, 0, 0, NULL, NULL, NULL }
79 /* associate command names to their properties */
80 typedef const struct {
81 /* TODO: Make this ambiguous void **ptr into a union { char *char_p; int *int_p; float *float_p; } val;
82 the PTR() macro is kind of preventing this change at the moment. */
89 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
91 /* an abbreviation to help keep the table's width humane */
92 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
97 } var_name_to_ptr[] = {
98 /* variable name pointer to variable in code type dump callback function */
99 /* --------------------------------------------------------------------------------------- */
100 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
101 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
102 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
103 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
104 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
105 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
106 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
107 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
108 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
109 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
110 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
111 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
112 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
113 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
114 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
115 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
116 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
117 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
118 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
119 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
120 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
121 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
122 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
123 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
124 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
125 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
126 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
127 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
128 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
129 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
130 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
131 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
132 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
133 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
134 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
135 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
136 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
137 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
138 /* exported WebKitWebSettings properties */
139 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
140 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
141 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
142 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
143 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
144 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
145 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
146 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
147 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
148 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
149 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
150 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
151 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
152 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
153 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
154 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
156 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
157 }, *n2v_p = var_name_to_ptr;
163 { "SHIFT", GDK_SHIFT_MASK }, // shift
164 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
165 { "CONTROL", GDK_CONTROL_MASK }, // control
166 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
167 { "MOD2", GDK_MOD2_MASK }, // 5th mod
168 { "MOD3", GDK_MOD3_MASK }, // 6th mod
169 { "MOD4", GDK_MOD4_MASK }, // 7th mod
170 { "MOD5", GDK_MOD5_MASK }, // 8th mod
171 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
172 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
173 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
174 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
175 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
176 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
177 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
178 { "META", GDK_META_MASK }, // meta (since 2.10)
183 /* construct a hash from the var_name_to_ptr array for quick access */
185 make_var_to_name_hash() {
186 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
188 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
193 /* --- UTILITY FUNCTIONS --- */
195 expand_vars(char *s) {
198 char ret[256], *vend;
199 GString *buf = g_string_new("");
204 g_string_append_c(buf, *++s);
212 if( (vend = strchr(s, upto)) ||
213 (vend = strchr(s, '\0')) ) {
214 strncpy(ret, s, vend-s);
216 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
217 if(c->type == TYPE_STR)
218 g_string_append(buf, (gchar *)*c->ptr);
219 else if(c->type == TYPE_INT) {
220 g_string_append_printf(buf, "%d", (int)*c->ptr);
222 else if(c->type == TYPE_FLOAT) {
223 g_string_append_printf(buf, "%f", *(float *)c->ptr);
226 if(upto == ' ') s = vend;
232 g_string_append_c(buf, *s);
237 return g_string_free(buf, FALSE);
244 snprintf(tmp, sizeof(tmp), "%i", val);
245 return g_strdup(tmp);
249 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
252 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
255 str_replace (const char* search, const char* replace, const char* string) {
259 buf = g_strsplit (string, search, -1);
260 ret = g_strjoinv (replace, buf);
261 g_strfreev(buf); // somebody said this segfaults
267 read_file_by_line (gchar *path) {
268 GIOChannel *chan = NULL;
269 gchar *readbuf = NULL;
271 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
274 chan = g_io_channel_new_file(path, "r", NULL);
277 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
278 const gchar* val = g_strdup (readbuf);
279 g_array_append_val (lines, val);
284 g_io_channel_unref (chan);
286 fprintf(stderr, "File '%s' not be read.\n", path);
293 gchar* parseenv (char* string) {
294 extern char** environ;
295 gchar* tmpstr = NULL;
299 while (environ[i] != NULL) {
300 gchar** env = g_strsplit (environ[i], "=", 2);
301 gchar* envname = g_strconcat ("$", env[0], NULL);
303 if (g_strrstr (string, envname) != NULL) {
304 tmpstr = g_strdup(string);
306 string = str_replace(envname, env[1], tmpstr);
311 g_strfreev (env); // somebody said this breaks uzbl
319 setup_signal(int signr, sigfunc *shandler) {
320 struct sigaction nh, oh;
322 nh.sa_handler = shandler;
323 sigemptyset(&nh.sa_mask);
326 if(sigaction(signr, &nh, &oh) < 0)
334 if (uzbl.behave.fifo_dir)
335 unlink (uzbl.comm.fifo_path);
336 if (uzbl.behave.socket_dir)
337 unlink (uzbl.comm.socket_path);
339 g_free(uzbl.state.executable_path);
340 g_string_free(uzbl.state.keycmd, TRUE);
341 g_hash_table_destroy(uzbl.bindings);
342 g_hash_table_destroy(uzbl.behave.commands);
345 /* used for html_mode_timeout
346 * be sure to extend this function to use
347 * more timers if needed in other places
350 set_timeout(int seconds) {
352 memset(&t, 0, sizeof t);
354 t.it_value.tv_sec = seconds;
355 t.it_value.tv_usec = 0;
356 setitimer(ITIMER_REAL, &t, NULL);
359 /* --- SIGNAL HANDLER --- */
362 catch_sigterm(int s) {
368 catch_sigint(int s) {
378 set_var_value("mode", "0");
383 /* --- CALLBACKS --- */
386 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
389 (void) navigation_action;
390 (void) policy_decision;
392 const gchar* uri = webkit_network_request_get_uri (request);
393 if (uzbl.state.verbose)
394 printf("New window requested -> %s \n", uri);
395 new_window_load_uri(uri);
400 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
405 /* If we can display it, let's display it... */
406 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
407 webkit_web_policy_decision_use (policy_decision);
411 /* ...everything we can't displayed is downloaded */
412 webkit_web_policy_decision_download (policy_decision);
417 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
421 if (uzbl.state.selected_url != NULL) {
422 if (uzbl.state.verbose)
423 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
424 new_window_load_uri(uzbl.state.selected_url);
426 if (uzbl.state.verbose)
427 printf("New web view -> %s\n","Nothing to open, exiting");
433 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
436 if (uzbl.behave.download_handler) {
437 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
438 if (uzbl.state.verbose)
439 printf("Download -> %s\n",uri);
440 /* if urls not escaped, we may have to escape and quote uri before this call */
441 run_handler(uzbl.behave.download_handler, uri);
446 /* scroll a bar in a given direction */
448 scroll (GtkAdjustment* bar, GArray *argv) {
452 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
453 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
454 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
458 scroll_begin(WebKitWebView* page, GArray *argv) {
459 (void) page; (void) argv;
460 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
464 scroll_end(WebKitWebView* page, GArray *argv) {
465 (void) page; (void) argv;
466 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
467 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
471 scroll_vert(WebKitWebView* page, GArray *argv) {
473 scroll(uzbl.gui.bar_v, argv);
477 scroll_horz(WebKitWebView* page, GArray *argv) {
479 scroll(uzbl.gui.bar_h, argv);
484 if (!uzbl.behave.show_status) {
485 gtk_widget_hide(uzbl.gui.mainbar);
487 gtk_widget_show(uzbl.gui.mainbar);
493 toggle_status_cb (WebKitWebView* page, GArray *argv) {
497 if (uzbl.behave.show_status) {
498 gtk_widget_hide(uzbl.gui.mainbar);
500 gtk_widget_show(uzbl.gui.mainbar);
502 uzbl.behave.show_status = !uzbl.behave.show_status;
507 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
511 //Set selected_url state variable
512 g_free(uzbl.state.selected_url);
513 uzbl.state.selected_url = NULL;
515 uzbl.state.selected_url = g_strdup(link);
521 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
525 if (uzbl.gui.main_title)
526 g_free (uzbl.gui.main_title);
527 uzbl.gui.main_title = g_strdup (title);
532 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
535 uzbl.gui.sbar.load_progress = progress;
540 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
544 if (uzbl.behave.load_finish_handler)
545 run_handler(uzbl.behave.load_finish_handler, "");
549 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
553 uzbl.gui.sbar.load_progress = 0;
554 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
555 if (uzbl.behave.load_start_handler)
556 run_handler(uzbl.behave.load_start_handler, "");
560 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
563 g_free (uzbl.state.uri);
564 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
565 uzbl.state.uri = g_string_free (newuri, FALSE);
566 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
567 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
570 if (uzbl.behave.load_commit_handler)
571 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
575 destroy_cb (GtkWidget* widget, gpointer data) {
583 if (uzbl.behave.history_handler) {
585 struct tm * timeinfo;
588 timeinfo = localtime ( &rawtime );
589 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
590 run_handler(uzbl.behave.history_handler, date);
595 /* VIEW funcs (little webkit wrappers) */
596 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
598 VIEWFUNC(reload_bypass_cache)
599 VIEWFUNC(stop_loading)
606 /* -- command to callback/function map for things we cannot attach to any signals */
607 static struct {char *name; Command command[2];} cmdlist[] =
608 { /* key function no_split */
609 { "back", {view_go_back, 0} },
610 { "forward", {view_go_forward, 0} },
611 { "scroll_vert", {scroll_vert, 0} },
612 { "scroll_horz", {scroll_horz, 0} },
613 { "scroll_begin", {scroll_begin, 0} },
614 { "scroll_end", {scroll_end, 0} },
615 { "reload", {view_reload, 0}, },
616 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
617 { "stop", {view_stop_loading, 0}, },
618 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
619 { "zoom_out", {view_zoom_out, 0}, },
620 { "uri", {load_uri, NOSPLIT} },
621 { "js", {run_js, NOSPLIT} },
622 { "script", {run_external_js, 0} },
623 { "toggle_status", {toggle_status_cb, 0} },
624 { "spawn", {spawn, 0} },
625 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
626 { "sh", {spawn_sh, 0} },
627 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
628 { "exit", {close_uzbl, 0} },
629 { "search", {search_forward_text, NOSPLIT} },
630 { "search_reverse", {search_reverse_text, NOSPLIT} },
631 { "dehilight", {dehilight, 0} },
632 { "toggle_insert_mode", {toggle_insert_mode, 0} },
633 { "set", {set_var, NOSPLIT} },
634 //{ "get", {get_var, NOSPLIT} },
635 { "bind", {act_bind, NOSPLIT} },
636 { "dump_config", {act_dump_config, 0} },
637 { "keycmd", {keycmd, NOSPLIT} },
638 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
639 { "keycmd_bs", {keycmd_bs, 0} },
640 { "chain", {chain, 0} },
641 { "print", {print, NOSPLIT} }
648 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
650 for (i = 0; i < LENGTH(cmdlist); i++)
651 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
654 /* -- CORE FUNCTIONS -- */
657 free_action(gpointer act) {
658 Action *action = (Action*)act;
659 g_free(action->name);
661 g_free(action->param);
666 new_action(const gchar *name, const gchar *param) {
667 Action *action = g_new(Action, 1);
669 action->name = g_strdup(name);
671 action->param = g_strdup(param);
673 action->param = NULL;
679 file_exists (const char * filename) {
680 return (access(filename, F_OK) == 0);
684 set_var(WebKitWebView *page, GArray *argv) {
686 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
687 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
688 set_var_value(g_strstrip(split[0]), value);
694 print(WebKitWebView *page, GArray *argv) {
698 buf = expand_vars(argv_idx(argv, 0));
704 act_bind(WebKitWebView *page, GArray *argv) {
706 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
707 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
708 add_binding(g_strstrip(split[0]), value);
720 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
723 if (argv_idx(argv, 0)) {
724 if (strcmp (argv_idx(argv, 0), "0") == 0) {
725 uzbl.behave.insert_mode = FALSE;
727 uzbl.behave.insert_mode = TRUE;
730 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
737 load_uri (WebKitWebView *web_view, GArray *argv) {
738 if (argv_idx(argv, 0)) {
739 GString* newuri = g_string_new (argv_idx(argv, 0));
740 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
741 run_js(web_view, argv);
744 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
745 g_string_prepend (newuri, "http://");
746 /* if we do handle cookies, ask our handler for them */
747 webkit_web_view_load_uri (web_view, newuri->str);
748 g_string_free (newuri, TRUE);
753 run_js (WebKitWebView * web_view, GArray *argv) {
754 if (argv_idx(argv, 0))
755 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
759 run_external_js (WebKitWebView * web_view, GArray *argv) {
760 if (argv_idx(argv, 0)) {
761 GArray* lines = read_file_by_line (argv_idx (argv, 0));
766 while ((line = g_array_index(lines, gchar*, i))) {
768 js = g_strdup (line);
770 gchar* newjs = g_strconcat (js, line, NULL);
777 if (uzbl.state.verbose)
778 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
780 if (argv_idx (argv, 1)) {
781 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
785 webkit_web_view_execute_script (web_view, js);
787 g_array_free (lines, TRUE);
792 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
793 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
794 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
795 webkit_web_view_unmark_text_matches (page);
796 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
797 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
801 if (uzbl.state.searchtx) {
802 if (uzbl.state.verbose)
803 printf ("Searching: %s\n", uzbl.state.searchtx);
804 webkit_web_view_set_highlight_text_matches (page, TRUE);
805 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
810 search_forward_text (WebKitWebView *page, GArray *argv) {
811 search_text(page, argv, TRUE);
815 search_reverse_text (WebKitWebView *page, GArray *argv) {
816 search_text(page, argv, FALSE);
820 dehilight (WebKitWebView *page, GArray *argv) {
822 webkit_web_view_set_highlight_text_matches (page, FALSE);
827 new_window_load_uri (const gchar * uri) {
828 GString* to_execute = g_string_new ("");
829 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
831 for (i = 0; entries[i].long_name != NULL; i++) {
832 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
833 gchar** str = (gchar**)entries[i].arg_data;
835 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
839 if (uzbl.state.verbose)
840 printf("\n%s\n", to_execute->str);
841 g_spawn_command_line_async (to_execute->str, NULL);
842 g_string_free (to_execute, TRUE);
846 chain (WebKitWebView *page, GArray *argv) {
849 gchar **parts = NULL;
851 while ((a = argv_idx(argv, i++))) {
852 parts = g_strsplit (a, " ", 2);
853 parse_command(parts[0], parts[1]);
859 keycmd (WebKitWebView *page, GArray *argv) {
862 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
868 keycmd_nl (WebKitWebView *page, GArray *argv) {
871 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
877 keycmd_bs (WebKitWebView *page, GArray *argv) {
880 g_string_truncate(uzbl.state.keycmd,
881 /* Calculate the number of bytes to truncate...
882 * This is not simply (len-1) when dealing with UTF-8 string */
883 g_utf8_offset_to_pointer(uzbl.state.keycmd->str,
884 g_utf8_strlen(uzbl.state.keycmd->str, uzbl.state.keycmd->len) - 1)
885 - uzbl.state.keycmd->str);
890 close_uzbl (WebKitWebView *page, GArray *argv) {
896 /* --Statusbar functions-- */
898 build_progressbar_ascii(int percent) {
899 int width=uzbl.gui.sbar.progress_w;
902 GString *bar = g_string_new("");
904 l = (double)percent*((double)width/100.);
905 l = (int)(l+.5)>=(int)l ? l+.5 : l;
907 for(i=0; i<(int)l; i++)
908 g_string_append(bar, uzbl.gui.sbar.progress_s);
911 g_string_append(bar, uzbl.gui.sbar.progress_u);
913 return g_string_free(bar, FALSE);
918 const GScannerConfig scan_config = {
921 ) /* cset_skip_characters */,
926 ) /* cset_identifier_first */,
933 ) /* cset_identifier_nth */,
934 ( "" ) /* cpair_comment_single */,
936 TRUE /* case_sensitive */,
938 FALSE /* skip_comment_multi */,
939 FALSE /* skip_comment_single */,
940 FALSE /* scan_comment_multi */,
941 TRUE /* scan_identifier */,
942 TRUE /* scan_identifier_1char */,
943 FALSE /* scan_identifier_NULL */,
944 TRUE /* scan_symbols */,
945 FALSE /* scan_binary */,
946 FALSE /* scan_octal */,
947 FALSE /* scan_float */,
948 FALSE /* scan_hex */,
949 FALSE /* scan_hex_dollar */,
950 FALSE /* scan_string_sq */,
951 FALSE /* scan_string_dq */,
952 TRUE /* numbers_2_int */,
953 FALSE /* int_2_float */,
954 FALSE /* identifier_2_string */,
955 FALSE /* char_2_token */,
956 FALSE /* symbol_2_token */,
957 TRUE /* scope_0_fallback */,
962 uzbl.scan = g_scanner_new(&scan_config);
963 while(symp->symbol_name) {
964 g_scanner_scope_add_symbol(uzbl.scan, 0,
966 GINT_TO_POINTER(symp->symbol_token));
972 expand_template(const char *template, gboolean escape_markup) {
973 if(!template) return NULL;
975 GTokenType token = G_TOKEN_NONE;
976 GString *ret = g_string_new("");
980 g_scanner_input_text(uzbl.scan, template, strlen(template));
981 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
982 token = g_scanner_get_next_token(uzbl.scan);
984 if(token == G_TOKEN_SYMBOL) {
985 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
989 buf = uzbl.state.uri ?
990 g_markup_printf_escaped("%s", uzbl.state.uri) : g_strdup("");
991 g_string_append(ret, buf);
995 g_string_append(ret, uzbl.state.uri ?
996 uzbl.state.uri : g_strdup(""));
999 buf = itos(uzbl.gui.sbar.load_progress);
1000 g_string_append(ret, buf);
1003 case SYM_LOADPRGSBAR:
1004 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1005 g_string_append(ret, buf);
1010 buf = uzbl.gui.main_title ?
1011 g_markup_printf_escaped("%s", uzbl.gui.main_title) : g_strdup("");
1012 g_string_append(ret, buf);
1016 g_string_append(ret, uzbl.gui.main_title ?
1017 uzbl.gui.main_title : g_strdup(""));
1019 case SYM_SELECTED_URI:
1021 buf = uzbl.state.selected_url ?
1022 g_markup_printf_escaped("%s", uzbl.state.selected_url) : g_strdup("");
1023 g_string_append(ret, buf);
1027 g_string_append(ret, uzbl.state.selected_url ?
1028 uzbl.state.selected_url : g_strdup(""));
1031 buf = itos(uzbl.xwin);
1032 g_string_append(ret,
1033 uzbl.state.instance_name ? uzbl.state.instance_name : buf);
1038 buf = uzbl.state.keycmd->str ?
1039 g_markup_printf_escaped("%s", uzbl.state.keycmd->str) : g_strdup("");
1040 g_string_append(ret, buf);
1044 g_string_append(ret, uzbl.state.keycmd->str ?
1045 uzbl.state.keycmd->str : g_strdup(""));
1048 g_string_append(ret,
1049 uzbl.behave.insert_mode ?
1050 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
1053 g_string_append(ret,
1054 uzbl.gui.sbar.msg ? uzbl.gui.sbar.msg : "");
1056 /* useragent syms */
1058 buf = itos(WEBKIT_MAJOR_VERSION);
1059 g_string_append(ret, buf);
1063 buf = itos(WEBKIT_MINOR_VERSION);
1064 g_string_append(ret, buf);
1068 buf = itos(WEBKIT_MICRO_VERSION);
1069 g_string_append(ret, buf);
1073 g_string_append(ret, uzbl.state.unameinfo.sysname);
1076 g_string_append(ret, uzbl.state.unameinfo.nodename);
1079 g_string_append(ret, uzbl.state.unameinfo.release);
1082 g_string_append(ret, uzbl.state.unameinfo.version);
1085 g_string_append(ret, uzbl.state.unameinfo.machine);
1088 g_string_append(ret, ARCH);
1091 case SYM_DOMAINNAME:
1092 g_string_append(ret, uzbl.state.unameinfo.domainname);
1096 g_string_append(ret, COMMIT);
1102 else if(token == G_TOKEN_INT) {
1103 g_string_append_printf(ret, "%lu", g_scanner_cur_value(uzbl.scan).v_int);
1105 else if(token == G_TOKEN_IDENTIFIER) {
1106 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1108 else if(token == G_TOKEN_CHAR) {
1109 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1111 else if(token == G_TOKEN_ERROR) {
1112 g_scanner_error(uzbl.scan, "Token error in template ('%s') at line %d, column %d.",
1114 g_scanner_cur_line(uzbl.scan),
1115 g_scanner_cur_position(uzbl.scan));
1119 return g_string_free(ret, FALSE);
1121 /* --End Statusbar functions-- */
1124 sharg_append(GArray *a, const gchar *str) {
1125 const gchar *s = (str ? str : "");
1126 g_array_append_val(a, s);
1129 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1131 run_command (const gchar *command, const guint npre, const gchar **args,
1132 const gboolean sync, char **output_stdout) {
1133 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1136 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1137 gchar *pid = itos(getpid());
1138 gchar *xwin = itos(uzbl.xwin);
1140 sharg_append(a, command);
1141 for (i = 0; i < npre; i++) /* add n args before the default vars */
1142 sharg_append(a, args[i]);
1143 sharg_append(a, uzbl.state.config_file);
1144 sharg_append(a, pid);
1145 sharg_append(a, xwin);
1146 sharg_append(a, uzbl.comm.fifo_path);
1147 sharg_append(a, uzbl.comm.socket_path);
1148 sharg_append(a, uzbl.state.uri);
1149 sharg_append(a, uzbl.gui.main_title);
1151 for (i = npre; i < g_strv_length((gchar**)args); i++)
1152 sharg_append(a, args[i]);
1156 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1158 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1159 NULL, NULL, output_stdout, NULL, NULL, &err);
1160 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1161 NULL, NULL, NULL, &err);
1163 if (uzbl.state.verbose) {
1164 GString *s = g_string_new("spawned:");
1165 for (i = 0; i < (a->len); i++) {
1166 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1167 g_string_append_printf(s, " %s", qarg);
1170 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1171 printf("%s\n", s->str);
1172 g_string_free(s, TRUE);
1174 printf("Stdout: %s\n", *output_stdout);
1178 g_printerr("error on run_command: %s\n", err->message);
1183 g_array_free (a, TRUE);
1188 split_quoted(const gchar* src, const gboolean unquote) {
1189 /* split on unquoted space, return array of strings;
1190 remove a layer of quotes and backslashes if unquote */
1191 if (!src) return NULL;
1193 gboolean dq = FALSE;
1194 gboolean sq = FALSE;
1195 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1196 GString *s = g_string_new ("");
1200 for (p = src; *p != '\0'; p++) {
1201 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1202 else if (*p == '\\') { g_string_append_c(s, *p++);
1203 g_string_append_c(s, *p); }
1204 else if ((*p == '"') && unquote && !sq) dq = !dq;
1205 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1207 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1208 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1210 else if ((*p == ' ') && !dq && !sq) {
1211 dup = g_strdup(s->str);
1212 g_array_append_val(a, dup);
1213 g_string_truncate(s, 0);
1214 } else g_string_append_c(s, *p);
1216 dup = g_strdup(s->str);
1217 g_array_append_val(a, dup);
1218 ret = (gchar**)a->data;
1219 g_array_free (a, FALSE);
1220 g_string_free (s, TRUE);
1225 spawn(WebKitWebView *web_view, GArray *argv) {
1227 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1228 if (argv_idx(argv, 0))
1229 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1233 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1236 if (argv_idx(argv, 0))
1237 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1238 TRUE, &uzbl.comm.sync_stdout);
1242 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1244 if (!uzbl.behave.shell_cmd) {
1245 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1250 gchar *spacer = g_strdup("");
1251 g_array_insert_val(argv, 1, spacer);
1252 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1254 for (i = 1; i < g_strv_length(cmd); i++)
1255 g_array_prepend_val(argv, cmd[i]);
1257 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1263 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1265 if (!uzbl.behave.shell_cmd) {
1266 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1271 gchar *spacer = g_strdup("");
1272 g_array_insert_val(argv, 1, spacer);
1273 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1275 for (i = 1; i < g_strv_length(cmd); i++)
1276 g_array_prepend_val(argv, cmd[i]);
1278 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1279 TRUE, &uzbl.comm.sync_stdout);
1285 parse_command(const char *cmd, const char *param) {
1288 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1291 gchar **par = split_quoted(param, TRUE);
1292 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1294 if (c[1] == NOSPLIT) { /* don't split */
1295 sharg_append(a, param);
1297 for (i = 0; i < g_strv_length(par); i++)
1298 sharg_append(a, par[i]);
1300 c[0](uzbl.gui.web_view, a);
1302 g_array_free (a, TRUE);
1305 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1312 if(*uzbl.net.proxy_url == ' '
1313 || uzbl.net.proxy_url == NULL) {
1314 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1315 (GType) SOUP_SESSION_PROXY_URI);
1318 suri = soup_uri_new(uzbl.net.proxy_url);
1319 g_object_set(G_OBJECT(uzbl.net.soup_session),
1320 SOUP_SESSION_PROXY_URI,
1322 soup_uri_free(suri);
1329 if(file_exists(uzbl.gui.icon)) {
1330 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1332 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1338 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1339 g_array_append_val (a, uzbl.state.uri);
1340 load_uri(uzbl.gui.web_view, a);
1341 g_array_free (a, TRUE);
1345 cmd_always_insert_mode() {
1346 uzbl.behave.insert_mode =
1347 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1353 g_object_set(G_OBJECT(uzbl.net.soup_session),
1354 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1358 cmd_max_conns_host() {
1359 g_object_set(G_OBJECT(uzbl.net.soup_session),
1360 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1365 soup_session_remove_feature
1366 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1367 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1368 /*g_free(uzbl.net.soup_logger);*/
1370 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1371 soup_session_add_feature(uzbl.net.soup_session,
1372 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1375 static WebKitWebSettings*
1377 return webkit_web_view_get_settings(uzbl.gui.web_view);
1382 WebKitWebSettings *ws = view_settings();
1383 if (uzbl.behave.font_size > 0) {
1384 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1387 if (uzbl.behave.monospace_size > 0) {
1388 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1389 uzbl.behave.monospace_size, NULL);
1391 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1392 uzbl.behave.font_size, NULL);
1398 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1402 cmd_disable_plugins() {
1403 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1404 !uzbl.behave.disable_plugins, NULL);
1408 cmd_disable_scripts() {
1409 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1410 !uzbl.behave.disable_scripts, NULL);
1414 cmd_minimum_font_size() {
1415 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1416 uzbl.behave.minimum_font_size, NULL);
1419 cmd_autoload_img() {
1420 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1421 uzbl.behave.autoload_img, NULL);
1426 cmd_autoshrink_img() {
1427 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1428 uzbl.behave.autoshrink_img, NULL);
1433 cmd_enable_spellcheck() {
1434 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1435 uzbl.behave.enable_spellcheck, NULL);
1439 cmd_enable_private() {
1440 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1441 uzbl.behave.enable_private, NULL);
1446 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1447 uzbl.behave.print_bg, NULL);
1452 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1453 uzbl.behave.style_uri, NULL);
1457 cmd_resizable_txt() {
1458 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1459 uzbl.behave.resizable_txt, NULL);
1463 cmd_default_encoding() {
1464 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1465 uzbl.behave.default_encoding, NULL);
1469 cmd_enforce_96dpi() {
1470 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1471 uzbl.behave.enforce_96dpi, NULL);
1475 cmd_caret_browsing() {
1476 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1477 uzbl.behave.caret_browsing, NULL);
1481 cmd_cookie_handler() {
1482 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1483 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1484 if ((g_strcmp0(split[0], "sh") == 0) ||
1485 (g_strcmp0(split[0], "spawn") == 0)) {
1486 g_free (uzbl.behave.cookie_handler);
1487 uzbl.behave.cookie_handler =
1488 g_strdup_printf("sync_%s %s", split[0], split[1]);
1495 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1500 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1505 if(uzbl.behave.inject_html) {
1506 webkit_web_view_load_html_string (uzbl.gui.web_view,
1507 uzbl.behave.inject_html, NULL);
1516 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1517 uzbl.behave.modmask = 0;
1519 if(uzbl.behave.modkey)
1520 g_free(uzbl.behave.modkey);
1521 uzbl.behave.modkey = buf;
1523 for (i = 0; modkeys[i].key != NULL; i++) {
1524 if (g_strrstr(buf, modkeys[i].key))
1525 uzbl.behave.modmask |= modkeys[i].mask;
1531 if (*uzbl.net.useragent == ' ') {
1532 g_free (uzbl.net.useragent);
1533 uzbl.net.useragent = NULL;
1535 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1537 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1538 g_free(uzbl.net.useragent);
1539 uzbl.net.useragent = ua;
1545 gtk_widget_ref(uzbl.gui.scrolled_win);
1546 gtk_widget_ref(uzbl.gui.mainbar);
1547 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1548 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1550 if(uzbl.behave.status_top) {
1551 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1552 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1555 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1556 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1558 gtk_widget_unref(uzbl.gui.scrolled_win);
1559 gtk_widget_unref(uzbl.gui.mainbar);
1560 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1565 set_var_value(gchar *name, gchar *val) {
1566 uzbl_cmdprop *c = NULL;
1570 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1571 /* check for the variable type */
1572 if (c->type == TYPE_STR) {
1573 buf = expand_vars(val);
1576 } else if(c->type == TYPE_INT) {
1577 int *ip = (int *)c->ptr;
1578 buf = expand_vars(val);
1579 *ip = (int)strtoul(buf, &endp, 10);
1581 } else if (c->type == TYPE_FLOAT) {
1582 float *fp = (float *)c->ptr;
1583 buf = expand_vars(val);
1584 *fp = strtod(buf, &endp);
1588 /* invoke a command specific function */
1589 if(c->func) c->func();
1596 Behaviour *b = &uzbl.behave;
1598 if(b->html_buffer->str) {
1599 webkit_web_view_load_html_string (uzbl.gui.web_view,
1600 b->html_buffer->str, b->base_url);
1601 g_string_free(b->html_buffer, TRUE);
1602 b->html_buffer = g_string_new("");
1606 enum {M_CMD, M_HTML};
1608 parse_cmd_line(const char *ctl_line) {
1609 Behaviour *b = &uzbl.behave;
1612 if(b->mode == M_HTML) {
1613 len = strlen(b->html_endmarker);
1614 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1615 if(len == strlen(ctl_line)-1 &&
1616 !strncmp(b->html_endmarker, ctl_line, len)) {
1618 set_var_value("mode", "0");
1623 set_timeout(b->html_timeout);
1624 g_string_append(b->html_buffer, ctl_line);
1627 else if((ctl_line[0] == '#') /* Comments */
1628 || (ctl_line[0] == ' ')
1629 || (ctl_line[0] == '\n'))
1630 ; /* ignore these lines */
1631 else { /* parse a command */
1633 gchar **tokens = NULL;
1634 len = strlen(ctl_line);
1636 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1637 ctlstrip = g_strndup(ctl_line, len - 1);
1638 else ctlstrip = g_strdup(ctl_line);
1640 tokens = g_strsplit(ctlstrip, " ", 2);
1641 parse_command(tokens[0], tokens[1]);
1648 build_stream_name(int type, const gchar* dir) {
1650 State *s = &uzbl.state;
1653 xwin_str = itos((int)uzbl.xwin);
1655 str = g_strdup_printf
1656 ("%s/uzbl_fifo_%s", dir,
1657 s->instance_name ? s->instance_name : xwin_str);
1658 } else if (type == SOCKET) {
1659 str = g_strdup_printf
1660 ("%s/uzbl_socket_%s", dir,
1661 s->instance_name ? s->instance_name : xwin_str );
1668 control_fifo(GIOChannel *gio, GIOCondition condition) {
1669 if (uzbl.state.verbose)
1670 printf("triggered\n");
1675 if (condition & G_IO_HUP)
1676 g_error ("Fifo: Read end of pipe died!\n");
1679 g_error ("Fifo: GIOChannel broke\n");
1681 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1682 if (ret == G_IO_STATUS_ERROR) {
1683 g_error ("Fifo: Error reading: %s\n", err->message);
1687 parse_cmd_line(ctl_line);
1694 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1695 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1696 if (unlink(uzbl.comm.fifo_path) == -1)
1697 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1698 g_free(uzbl.comm.fifo_path);
1699 uzbl.comm.fifo_path = NULL;
1702 if (*dir == ' ') { /* space unsets the variable */
1707 GIOChannel *chan = NULL;
1708 GError *error = NULL;
1709 gchar *path = build_stream_name(FIFO, dir);
1711 if (!file_exists(path)) {
1712 if (mkfifo (path, 0666) == 0) {
1713 // 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.
1714 chan = g_io_channel_new_file(path, "r+", &error);
1716 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1717 if (uzbl.state.verbose)
1718 printf ("init_fifo: created successfully as %s\n", path);
1719 uzbl.comm.fifo_path = path;
1721 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1722 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1723 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1724 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1726 /* if we got this far, there was an error; cleanup */
1727 if (error) g_error_free (error);
1734 control_stdin(GIOChannel *gio, GIOCondition condition) {
1736 gchar *ctl_line = NULL;
1739 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1740 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1743 parse_cmd_line(ctl_line);
1751 GIOChannel *chan = NULL;
1752 GError *error = NULL;
1754 chan = g_io_channel_unix_new(fileno(stdin));
1756 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1757 g_error ("Stdin: could not add watch\n");
1759 if (uzbl.state.verbose)
1760 printf ("Stdin: watch added successfully\n");
1763 g_error ("Stdin: Error while opening: %s\n", error->message);
1765 if (error) g_error_free (error);
1769 control_socket(GIOChannel *chan) {
1770 struct sockaddr_un remote;
1771 char buffer[512], *ctl_line;
1773 int sock, clientsock, n, done;
1776 sock = g_io_channel_unix_get_fd(chan);
1778 memset (buffer, 0, sizeof (buffer));
1780 t = sizeof (remote);
1781 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1785 memset (temp, 0, sizeof (temp));
1786 n = recv (clientsock, temp, 128, 0);
1788 buffer[strlen (buffer)] = '\0';
1792 strcat (buffer, temp);
1795 if (strcmp (buffer, "\n") < 0) {
1796 buffer[strlen (buffer) - 1] = '\0';
1798 buffer[strlen (buffer)] = '\0';
1801 ctl_line = g_strdup(buffer);
1802 parse_cmd_line (ctl_line);
1805 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1806 GError *error = NULL;
1809 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1810 if (ret == G_IO_STATUS_ERROR)
1811 g_error ("Error reading: %s\n", error->message);
1813 printf("Got line %s (%u bytes) \n",ctl_line, len);
1815 parse_line(ctl_line);
1823 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1824 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1825 if (unlink(uzbl.comm.socket_path) == -1)
1826 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1827 g_free(uzbl.comm.socket_path);
1828 uzbl.comm.socket_path = NULL;
1836 GIOChannel *chan = NULL;
1838 struct sockaddr_un local;
1839 gchar *path = build_stream_name(SOCKET, dir);
1841 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1843 local.sun_family = AF_UNIX;
1844 strcpy (local.sun_path, path);
1845 unlink (local.sun_path);
1847 len = strlen (local.sun_path) + sizeof (local.sun_family);
1848 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1849 if (uzbl.state.verbose)
1850 printf ("init_socket: opened in %s\n", path);
1853 if( (chan = g_io_channel_unix_new(sock)) ) {
1854 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1855 uzbl.comm.socket_path = path;
1858 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1860 /* if we got this far, there was an error; cleanup */
1867 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1868 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1870 // this function may be called very early when the templates are not set (yet), hence the checks
1872 update_title (void) {
1873 Behaviour *b = &uzbl.behave;
1876 if (b->show_status) {
1877 if (b->title_format_short) {
1878 parsed = expand_template(b->title_format_short, FALSE);
1879 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1882 if (b->status_format) {
1883 parsed = expand_template(b->status_format, TRUE);
1884 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1887 if (b->status_background) {
1889 gdk_color_parse (b->status_background, &color);
1890 //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)
1891 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1894 if (b->title_format_long) {
1895 parsed = expand_template(b->title_format_long, FALSE);
1896 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1903 key_press_cb (GtkWidget* window, GdkEventKey* event)
1905 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1909 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1910 || 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)
1913 /* turn off insert mode (if always_insert_mode is not used) */
1914 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1915 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1920 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1923 if (event->keyval == GDK_Escape) {
1924 g_string_truncate(uzbl.state.keycmd, 0);
1926 dehilight(uzbl.gui.web_view, NULL);
1930 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1931 if (event->keyval == GDK_Insert) {
1933 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1934 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1936 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1939 g_string_append (uzbl.state.keycmd, str);
1946 if (event->keyval == GDK_BackSpace)
1947 keycmd_bs(NULL, NULL);
1949 gboolean key_ret = FALSE;
1950 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1952 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1954 run_keycmd(key_ret);
1956 if (key_ret) return (!uzbl.behave.insert_mode);
1961 run_keycmd(const gboolean key_ret) {
1962 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1964 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1965 g_string_truncate(uzbl.state.keycmd, 0);
1966 parse_command(act->name, act->param);
1970 /* try if it's an incremental keycmd or one that takes args, and run it */
1971 GString* short_keys = g_string_new ("");
1972 GString* short_keys_inc = g_string_new ("");
1974 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1975 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1976 g_string_assign(short_keys_inc, short_keys->str);
1977 g_string_append_c(short_keys, '_');
1978 g_string_append_c(short_keys_inc, '*');
1980 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1981 /* run normal cmds only if return was pressed */
1982 exec_paramcmd(act, i);
1983 g_string_truncate(uzbl.state.keycmd, 0);
1985 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1986 if (key_ret) /* just quit the incremental command on return */
1987 g_string_truncate(uzbl.state.keycmd, 0);
1988 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1992 g_string_truncate(short_keys, short_keys->len - 1);
1994 g_string_free (short_keys, TRUE);
1995 g_string_free (short_keys_inc, TRUE);
1999 exec_paramcmd(const Action *act, const guint i) {
2000 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2001 GString *actionname = g_string_new ("");
2002 GString *actionparam = g_string_new ("");
2003 g_string_erase (parampart, 0, i+1);
2005 g_string_printf (actionname, act->name, parampart->str);
2007 g_string_printf (actionparam, act->param, parampart->str);
2008 parse_command(actionname->str, actionparam->str);
2009 g_string_free(actionname, TRUE);
2010 g_string_free(actionparam, TRUE);
2011 g_string_free(parampart, TRUE);
2019 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2020 //main_window_ref = g_object_ref(scrolled_window);
2021 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
2023 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2024 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2026 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2027 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2028 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2029 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2030 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2033 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2035 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2036 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2038 return scrolled_window;
2045 g->mainbar = gtk_hbox_new (FALSE, 0);
2047 /* keep a reference to the bar so we can re-pack it at runtime*/
2048 //sbar_ref = g_object_ref(g->mainbar);
2050 g->mainbar_label = gtk_label_new ("");
2051 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2052 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2053 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2054 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2055 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2056 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2061 GtkWidget* create_window () {
2062 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2063 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2064 gtk_widget_set_name (window, "Uzbl browser");
2065 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2066 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2072 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2074 If actname is one that calls an external command, this function will inject
2075 newargs in front of the user-provided args in that command line. They will
2076 come become after the body of the script (in sh) or after the name of
2077 the command to execute (in spawn).
2078 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2079 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2081 The return value consist of two strings: the action (sh, ...) and its args.
2083 If act is not one that calls an external command, then the given action merely
2086 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2087 gchar *actdup = g_strdup(actname);
2088 g_array_append_val(rets, actdup);
2090 if ((g_strcmp0(actname, "spawn") == 0) ||
2091 (g_strcmp0(actname, "sh") == 0) ||
2092 (g_strcmp0(actname, "sync_spawn") == 0) ||
2093 (g_strcmp0(actname, "sync_sh") == 0)) {
2095 GString *a = g_string_new("");
2096 gchar **spawnparts = split_quoted(origargs, FALSE);
2097 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2098 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2100 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2101 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2103 g_array_append_val(rets, a->str);
2104 g_string_free(a, FALSE);
2105 g_strfreev(spawnparts);
2107 gchar *origdup = g_strdup(origargs);
2108 g_array_append_val(rets, origdup);
2110 return (gchar**)g_array_free(rets, FALSE);
2114 run_handler (const gchar *act, const gchar *args) {
2115 /* Consider this code a temporary hack to make the handlers usable.
2116 In practice, all this splicing, injection, and reconstruction is
2117 inefficient, annoying and hard to manage. Potential pitfalls arise
2118 when the handler specific args 1) are not quoted (the handler
2119 callbacks should take care of this) 2) are quoted but interfere
2120 with the users' own quotation. A more ideal solution is
2121 to refactor parse_command so that it doesn't just take a string
2122 and execute it; rather than that, we should have a function which
2123 returns the argument vector parsed from the string. This vector
2124 could be modified (e.g. insert additional args into it) before
2125 passing it to the next function that actually executes it. Though
2126 it still isn't perfect for chain actions.. will reconsider & re-
2127 factor when I have the time. -duc */
2129 char **parts = g_strsplit(act, " ", 2);
2131 if (g_strcmp0(parts[0], "chain") == 0) {
2132 GString *newargs = g_string_new("");
2133 gchar **chainparts = split_quoted(parts[1], FALSE);
2135 /* for every argument in the chain, inject the handler args
2136 and make sure the new parts are wrapped in quotes */
2137 gchar **cp = chainparts;
2139 gchar *quotless = NULL;
2140 gchar **spliced_quotless = NULL; // sigh -_-;
2141 gchar **inpart = NULL;
2144 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2146 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2147 } else quotless = g_strdup(*cp);
2149 spliced_quotless = g_strsplit(quotless, " ", 2);
2150 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2151 g_strfreev(spliced_quotless);
2153 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2159 parse_command(parts[0], &(newargs->str[1]));
2160 g_string_free(newargs, TRUE);
2161 g_strfreev(chainparts);
2164 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2165 parse_command(inparts[0], inparts[1]);
2173 add_binding (const gchar *key, const gchar *act) {
2174 char **parts = g_strsplit(act, " ", 2);
2181 if (uzbl.state.verbose)
2182 printf ("Binding %-10s : %s\n", key, act);
2183 action = new_action(parts[0], parts[1]);
2185 if (g_hash_table_remove (uzbl.bindings, key))
2186 g_warning ("Overwriting existing binding for \"%s\"", key);
2187 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2192 get_xdg_var (XDG_Var xdg) {
2193 const gchar* actual_value = getenv (xdg.environmental);
2194 const gchar* home = getenv ("HOME");
2195 gchar* return_value;
2197 if (! actual_value || strcmp (actual_value, "") == 0) {
2198 if (xdg.default_value) {
2199 return_value = str_replace ("~", home, xdg.default_value);
2201 return_value = NULL;
2204 return_value = str_replace("~", home, actual_value);
2207 return return_value;
2211 find_xdg_file (int xdg_type, char* filename) {
2212 /* xdg_type = 0 => config
2213 xdg_type = 1 => data
2214 xdg_type = 2 => cache*/
2216 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2217 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2220 gchar* temporary_string;
2224 if (! file_exists (temporary_file) && xdg_type != 2) {
2225 buf = get_xdg_var (XDG[3 + xdg_type]);
2226 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2229 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2230 g_free (temporary_file);
2231 temporary_file = g_strconcat (temporary_string, filename, NULL);
2235 //g_free (temporary_string); - segfaults.
2237 if (file_exists (temporary_file)) {
2238 return temporary_file;
2245 State *s = &uzbl.state;
2246 Network *n = &uzbl.net;
2248 for (i = 0; default_config[i].command != NULL; i++) {
2249 parse_cmd_line(default_config[i].command);
2252 if (!s->config_file) {
2253 s->config_file = find_xdg_file (0, "/uzbl/config");
2256 if (s->config_file) {
2257 GArray* lines = read_file_by_line (s->config_file);
2261 while ((line = g_array_index(lines, gchar*, i))) {
2262 parse_cmd_line (line);
2266 g_array_free (lines, TRUE);
2268 if (uzbl.state.verbose)
2269 printf ("No configuration file loaded.\n");
2272 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2275 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2278 if (!uzbl.behave.cookie_handler)
2281 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2282 GString *s = g_string_new ("");
2283 SoupURI * soup_uri = soup_message_get_uri(msg);
2284 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2285 run_handler(uzbl.behave.cookie_handler, s->str);
2287 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2288 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2289 if ( p != NULL ) *p = '\0';
2290 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2292 if (uzbl.comm.sync_stdout)
2293 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2295 g_string_free(s, TRUE);
2299 save_cookies (SoupMessage *msg, gpointer user_data){
2303 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2304 cookie = soup_cookie_to_set_cookie_header(ck->data);
2305 SoupURI * soup_uri = soup_message_get_uri(msg);
2306 GString *s = g_string_new ("");
2307 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2308 run_handler(uzbl.behave.cookie_handler, s->str);
2310 g_string_free(s, TRUE);
2315 /* --- WEBINSPECTOR --- */
2317 hide_window_cb(GtkWidget *widget, gpointer data) {
2320 gtk_widget_hide(widget);
2323 static WebKitWebView*
2324 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2327 (void) web_inspector;
2328 GtkWidget* scrolled_window;
2329 GtkWidget* new_web_view;
2332 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2333 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2334 G_CALLBACK(hide_window_cb), NULL);
2336 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2337 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2338 gtk_widget_show(g->inspector_window);
2340 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2341 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2342 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2343 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2344 gtk_widget_show(scrolled_window);
2346 new_web_view = webkit_web_view_new();
2347 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2349 return WEBKIT_WEB_VIEW(new_web_view);
2353 inspector_show_window_cb (WebKitWebInspector* inspector){
2355 gtk_widget_show(uzbl.gui.inspector_window);
2359 /* TODO: Add variables and code to make use of these functions */
2361 inspector_close_window_cb (WebKitWebInspector* inspector){
2367 inspector_attach_window_cb (WebKitWebInspector* inspector){
2373 inspector_detach_window_cb (WebKitWebInspector* inspector){
2379 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2385 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2391 set_up_inspector() {
2393 WebKitWebSettings *settings = view_settings();
2394 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2396 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2397 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2398 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2399 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2400 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2401 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2402 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2404 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2408 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2410 uzbl_cmdprop *c = v;
2415 if(c->type == TYPE_STR)
2416 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2417 else if(c->type == TYPE_INT)
2418 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2419 else if(c->type == TYPE_FLOAT)
2420 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2424 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2428 printf("bind %s = %s %s\n", (char *)k ,
2429 (char *)a->name, a->param?(char *)a->param:"");
2434 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2435 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2440 main (int argc, char* argv[]) {
2441 gtk_init (&argc, &argv);
2442 if (!g_thread_supported ())
2443 g_thread_init (NULL);
2444 uzbl.state.executable_path = g_strdup(argv[0]);
2445 uzbl.state.selected_url = NULL;
2446 uzbl.state.searchtx = NULL;
2448 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2449 g_option_context_add_main_entries (context, entries, NULL);
2450 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2451 g_option_context_parse (context, &argc, &argv, NULL);
2452 g_option_context_free(context);
2454 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2455 gboolean verbose_override = uzbl.state.verbose;
2457 /* initialize hash table */
2458 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2460 uzbl.net.soup_session = webkit_get_default_session();
2461 uzbl.state.keycmd = g_string_new("");
2463 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2464 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2465 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2466 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2467 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2468 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2471 if(uname(&uzbl.state.unameinfo) == -1)
2472 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2474 uzbl.gui.sbar.progress_s = g_strdup("=");
2475 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2476 uzbl.gui.sbar.progress_w = 10;
2478 /* HTML mode defaults*/
2479 uzbl.behave.html_buffer = g_string_new("");
2480 uzbl.behave.html_endmarker = g_strdup(".");
2481 uzbl.behave.html_timeout = 60;
2482 uzbl.behave.base_url = g_strdup("http://invalid");
2484 /* default mode indicators */
2485 uzbl.behave.insert_indicator = g_strdup("I");
2486 uzbl.behave.cmd_indicator = g_strdup("C");
2490 make_var_to_name_hash();
2492 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2494 uzbl.gui.scrolled_win = create_browser();
2497 /* initial packing */
2498 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2499 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2501 uzbl.gui.main_window = create_window ();
2502 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2505 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2506 gtk_widget_show_all (uzbl.gui.main_window);
2507 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2509 if (uzbl.state.verbose) {
2510 printf("Uzbl start location: %s\n", argv[0]);
2511 printf("window_id %i\n",(int) uzbl.xwin);
2512 printf("pid %i\n", getpid ());
2513 printf("name: %s\n", uzbl.state.instance_name);
2516 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2517 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2518 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2519 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2520 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2524 if (!uzbl.behave.show_status)
2525 gtk_widget_hide(uzbl.gui.mainbar);
2534 if (verbose_override > uzbl.state.verbose)
2535 uzbl.state.verbose = verbose_override;
2538 set_var_value("uri", uri_override);
2539 g_free(uri_override);
2540 } else if (uzbl.state.uri)
2541 cmd_load_uri(uzbl.gui.web_view, NULL);
2546 return EXIT_SUCCESS;
2549 /* vi: set et ts=4: */