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 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);
343 g_scanner_destroy(uzbl.scan);
346 /* used for html_mode_timeout
347 * be sure to extend this function to use
348 * more timers if needed in other places
351 set_timeout(int seconds) {
353 memset(&t, 0, sizeof t);
355 t.it_value.tv_sec = seconds;
356 t.it_value.tv_usec = 0;
357 setitimer(ITIMER_REAL, &t, NULL);
360 /* --- SIGNAL HANDLER --- */
363 catch_sigterm(int s) {
369 catch_sigint(int s) {
379 set_var_value("mode", "0");
384 /* --- CALLBACKS --- */
387 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
390 (void) navigation_action;
391 (void) policy_decision;
393 const gchar* uri = webkit_network_request_get_uri (request);
394 if (uzbl.state.verbose)
395 printf("New window requested -> %s \n", uri);
396 new_window_load_uri(uri);
401 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
406 /* If we can display it, let's display it... */
407 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
408 webkit_web_policy_decision_use (policy_decision);
412 /* ...everything we can't displayed is downloaded */
413 webkit_web_policy_decision_download (policy_decision);
418 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
422 if (uzbl.state.selected_url != NULL) {
423 if (uzbl.state.verbose)
424 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
425 new_window_load_uri(uzbl.state.selected_url);
427 if (uzbl.state.verbose)
428 printf("New web view -> %s\n","Nothing to open, exiting");
434 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
437 if (uzbl.behave.download_handler) {
438 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
439 if (uzbl.state.verbose)
440 printf("Download -> %s\n",uri);
441 /* if urls not escaped, we may have to escape and quote uri before this call */
442 run_handler(uzbl.behave.download_handler, uri);
447 /* scroll a bar in a given direction */
449 scroll (GtkAdjustment* bar, GArray *argv) {
453 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
454 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
455 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
459 scroll_begin(WebKitWebView* page, GArray *argv) {
460 (void) page; (void) argv;
461 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
465 scroll_end(WebKitWebView* page, GArray *argv) {
466 (void) page; (void) argv;
467 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
468 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
472 scroll_vert(WebKitWebView* page, GArray *argv) {
474 scroll(uzbl.gui.bar_v, argv);
478 scroll_horz(WebKitWebView* page, GArray *argv) {
480 scroll(uzbl.gui.bar_h, argv);
485 if (!uzbl.behave.show_status) {
486 gtk_widget_hide(uzbl.gui.mainbar);
488 gtk_widget_show(uzbl.gui.mainbar);
494 toggle_status_cb (WebKitWebView* page, GArray *argv) {
498 if (uzbl.behave.show_status) {
499 gtk_widget_hide(uzbl.gui.mainbar);
501 gtk_widget_show(uzbl.gui.mainbar);
503 uzbl.behave.show_status = !uzbl.behave.show_status;
508 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
512 //Set selected_url state variable
513 g_free(uzbl.state.selected_url);
514 uzbl.state.selected_url = NULL;
516 uzbl.state.selected_url = g_strdup(link);
522 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
526 if (uzbl.gui.main_title)
527 g_free (uzbl.gui.main_title);
528 uzbl.gui.main_title = g_strdup (title);
533 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
536 uzbl.gui.sbar.load_progress = progress;
541 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
545 if (uzbl.behave.load_finish_handler)
546 run_handler(uzbl.behave.load_finish_handler, "");
550 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
554 uzbl.gui.sbar.load_progress = 0;
555 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
556 if (uzbl.behave.load_start_handler)
557 run_handler(uzbl.behave.load_start_handler, "");
561 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
564 g_free (uzbl.state.uri);
565 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
566 uzbl.state.uri = g_string_free (newuri, FALSE);
567 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
568 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
571 if (uzbl.behave.load_commit_handler)
572 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
576 destroy_cb (GtkWidget* widget, gpointer data) {
584 if (uzbl.behave.history_handler) {
588 g_get_current_time(&the_time);
589 /* no need to wrap this string with quotes since it contains no spaces.
590 format is like: 2009-06-26T20:02:05.262864Z */
591 date = g_time_val_to_iso8601(&the_time);
592 run_handler(uzbl.behave.history_handler, date);
598 /* VIEW funcs (little webkit wrappers) */
599 #define VIEWFUNC(name) void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
601 VIEWFUNC(reload_bypass_cache)
602 VIEWFUNC(stop_loading)
609 /* -- command to callback/function map for things we cannot attach to any signals */
610 struct {char *name; Command command[2];} cmdlist[] =
611 { /* key function no_split */
612 { "back", {view_go_back, 0} },
613 { "forward", {view_go_forward, 0} },
614 { "scroll_vert", {scroll_vert, 0} },
615 { "scroll_horz", {scroll_horz, 0} },
616 { "scroll_begin", {scroll_begin, 0} },
617 { "scroll_end", {scroll_end, 0} },
618 { "reload", {view_reload, 0}, },
619 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
620 { "stop", {view_stop_loading, 0}, },
621 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
622 { "zoom_out", {view_zoom_out, 0}, },
623 { "uri", {load_uri, NOSPLIT} },
624 { "js", {run_js, NOSPLIT} },
625 { "script", {run_external_js, 0} },
626 { "toggle_status", {toggle_status_cb, 0} },
627 { "spawn", {spawn, 0} },
628 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
629 { "sh", {spawn_sh, 0} },
630 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
631 { "exit", {close_uzbl, 0} },
632 { "quit", {close_uzbl, 0} },
633 { "search", {search_forward_text, NOSPLIT} },
634 { "search_reverse", {search_reverse_text, NOSPLIT} },
635 { "dehilight", {dehilight, 0} },
636 { "toggle_insert_mode", {toggle_insert_mode, 0} },
637 { "set", {set_var, NOSPLIT} },
638 //{ "get", {get_var, NOSPLIT} },
639 { "bind", {act_bind, NOSPLIT} },
640 { "dump_config", {act_dump_config, 0} },
641 { "keycmd", {keycmd, NOSPLIT} },
642 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
643 { "keycmd_bs", {keycmd_bs, 0} },
644 { "chain", {chain, 0} },
645 { "print", {print, NOSPLIT} }
652 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
654 for (i = 0; i < LENGTH(cmdlist); i++)
655 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
658 /* -- CORE FUNCTIONS -- */
661 free_action(gpointer act) {
662 Action *action = (Action*)act;
663 g_free(action->name);
665 g_free(action->param);
670 new_action(const gchar *name, const gchar *param) {
671 Action *action = g_new(Action, 1);
673 action->name = g_strdup(name);
675 action->param = g_strdup(param);
677 action->param = NULL;
683 file_exists (const char * filename) {
684 return (access(filename, F_OK) == 0);
688 set_var(WebKitWebView *page, GArray *argv) {
690 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
691 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
692 set_var_value(g_strstrip(split[0]), value);
698 print(WebKitWebView *page, GArray *argv) {
702 buf = expand_vars(argv_idx(argv, 0));
708 act_bind(WebKitWebView *page, GArray *argv) {
710 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
711 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
712 add_binding(g_strstrip(split[0]), value);
724 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
727 if (argv_idx(argv, 0)) {
728 if (strcmp (argv_idx(argv, 0), "0") == 0) {
729 uzbl.behave.insert_mode = FALSE;
731 uzbl.behave.insert_mode = TRUE;
734 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
741 load_uri (WebKitWebView *web_view, GArray *argv) {
742 if (argv_idx(argv, 0)) {
743 GString* newuri = g_string_new (argv_idx(argv, 0));
744 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
745 run_js(web_view, argv);
748 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
749 g_string_prepend (newuri, "http://");
750 /* if we do handle cookies, ask our handler for them */
751 webkit_web_view_load_uri (web_view, newuri->str);
752 g_string_free (newuri, TRUE);
757 run_js (WebKitWebView * web_view, GArray *argv) {
758 if (argv_idx(argv, 0))
759 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
763 run_external_js (WebKitWebView * web_view, GArray *argv) {
764 if (argv_idx(argv, 0)) {
765 GArray* lines = read_file_by_line (argv_idx (argv, 0));
770 while ((line = g_array_index(lines, gchar*, i))) {
772 js = g_strdup (line);
774 gchar* newjs = g_strconcat (js, line, NULL);
781 if (uzbl.state.verbose)
782 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
784 if (argv_idx (argv, 1)) {
785 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
789 webkit_web_view_execute_script (web_view, js);
791 g_array_free (lines, TRUE);
796 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
797 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
798 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
799 webkit_web_view_unmark_text_matches (page);
800 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
801 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
805 if (uzbl.state.searchtx) {
806 if (uzbl.state.verbose)
807 printf ("Searching: %s\n", uzbl.state.searchtx);
808 webkit_web_view_set_highlight_text_matches (page, TRUE);
809 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
814 search_forward_text (WebKitWebView *page, GArray *argv) {
815 search_text(page, argv, TRUE);
819 search_reverse_text (WebKitWebView *page, GArray *argv) {
820 search_text(page, argv, FALSE);
824 dehilight (WebKitWebView *page, GArray *argv) {
826 webkit_web_view_set_highlight_text_matches (page, FALSE);
831 new_window_load_uri (const gchar * uri) {
832 GString* to_execute = g_string_new ("");
833 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
835 for (i = 0; entries[i].long_name != NULL; i++) {
836 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
837 gchar** str = (gchar**)entries[i].arg_data;
839 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
843 if (uzbl.state.verbose)
844 printf("\n%s\n", to_execute->str);
845 g_spawn_command_line_async (to_execute->str, NULL);
846 g_string_free (to_execute, TRUE);
850 chain (WebKitWebView *page, GArray *argv) {
853 gchar **parts = NULL;
855 while ((a = argv_idx(argv, i++))) {
856 parts = g_strsplit (a, " ", 2);
857 parse_command(parts[0], parts[1]);
863 keycmd (WebKitWebView *page, GArray *argv) {
866 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
872 keycmd_nl (WebKitWebView *page, GArray *argv) {
875 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
881 keycmd_bs (WebKitWebView *page, GArray *argv) {
884 g_string_truncate(uzbl.state.keycmd,
885 /* Calculate the number of bytes to truncate...
886 * This is not simply (len-1) when dealing with UTF-8 string */
887 g_utf8_offset_to_pointer(uzbl.state.keycmd->str,
888 g_utf8_strlen(uzbl.state.keycmd->str, uzbl.state.keycmd->len) - 1)
889 - uzbl.state.keycmd->str);
894 close_uzbl (WebKitWebView *page, GArray *argv) {
900 /* --Statusbar functions-- */
902 build_progressbar_ascii(int percent) {
903 int width=uzbl.gui.sbar.progress_w;
906 GString *bar = g_string_new("");
908 l = (double)percent*((double)width/100.);
909 l = (int)(l+.5)>=(int)l ? l+.5 : l;
911 for(i=0; i<(int)l; i++)
912 g_string_append(bar, uzbl.gui.sbar.progress_s);
915 g_string_append(bar, uzbl.gui.sbar.progress_u);
917 return g_string_free(bar, FALSE);
922 const GScannerConfig scan_config = {
925 ) /* cset_skip_characters */,
930 ) /* cset_identifier_first */,
937 ) /* cset_identifier_nth */,
938 ( "" ) /* cpair_comment_single */,
940 TRUE /* case_sensitive */,
942 FALSE /* skip_comment_multi */,
943 FALSE /* skip_comment_single */,
944 FALSE /* scan_comment_multi */,
945 TRUE /* scan_identifier */,
946 TRUE /* scan_identifier_1char */,
947 FALSE /* scan_identifier_NULL */,
948 TRUE /* scan_symbols */,
949 FALSE /* scan_binary */,
950 FALSE /* scan_octal */,
951 FALSE /* scan_float */,
952 FALSE /* scan_hex */,
953 FALSE /* scan_hex_dollar */,
954 FALSE /* scan_string_sq */,
955 FALSE /* scan_string_dq */,
956 TRUE /* numbers_2_int */,
957 FALSE /* int_2_float */,
958 FALSE /* identifier_2_string */,
959 FALSE /* char_2_token */,
960 FALSE /* symbol_2_token */,
961 TRUE /* scope_0_fallback */,
966 uzbl.scan = g_scanner_new(&scan_config);
967 while(symp->symbol_name) {
968 g_scanner_scope_add_symbol(uzbl.scan, 0,
970 GINT_TO_POINTER(symp->symbol_token));
976 expand_template(const char *template, gboolean escape_markup) {
977 if(!template) return NULL;
979 GTokenType token = G_TOKEN_NONE;
980 GString *ret = g_string_new("");
984 g_scanner_input_text(uzbl.scan, template, strlen(template));
985 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
986 token = g_scanner_get_next_token(uzbl.scan);
988 if(token == G_TOKEN_SYMBOL) {
989 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
993 buf = uzbl.state.uri ?
994 g_markup_printf_escaped("%s", uzbl.state.uri) : g_strdup("");
995 g_string_append(ret, buf);
999 g_string_append(ret, uzbl.state.uri ?
1000 uzbl.state.uri : g_strdup(""));
1003 buf = itos(uzbl.gui.sbar.load_progress);
1004 g_string_append(ret, buf);
1007 case SYM_LOADPRGSBAR:
1008 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1009 g_string_append(ret, buf);
1014 buf = uzbl.gui.main_title ?
1015 g_markup_printf_escaped("%s", uzbl.gui.main_title) : g_strdup("");
1016 g_string_append(ret, buf);
1020 g_string_append(ret, uzbl.gui.main_title ?
1021 uzbl.gui.main_title : "");
1023 case SYM_SELECTED_URI:
1025 buf = uzbl.state.selected_url ?
1026 g_markup_printf_escaped("%s", uzbl.state.selected_url) : g_strdup("");
1027 g_string_append(ret, buf);
1031 g_string_append(ret, uzbl.state.selected_url ?
1032 uzbl.state.selected_url : "");
1035 buf = itos(uzbl.xwin);
1036 g_string_append(ret,
1037 uzbl.state.instance_name ? uzbl.state.instance_name : buf);
1042 buf = uzbl.state.keycmd->str ?
1043 g_markup_printf_escaped("%s", uzbl.state.keycmd->str) : g_strdup("");
1044 g_string_append(ret, buf);
1048 g_string_append(ret, uzbl.state.keycmd->str ?
1049 uzbl.state.keycmd->str : "");
1052 g_string_append(ret,
1053 uzbl.behave.insert_mode ?
1054 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
1057 g_string_append(ret,
1058 uzbl.gui.sbar.msg ? uzbl.gui.sbar.msg : "");
1060 /* useragent syms */
1062 buf = itos(WEBKIT_MAJOR_VERSION);
1063 g_string_append(ret, buf);
1067 buf = itos(WEBKIT_MINOR_VERSION);
1068 g_string_append(ret, buf);
1072 buf = itos(WEBKIT_MICRO_VERSION);
1073 g_string_append(ret, buf);
1077 g_string_append(ret, uzbl.state.unameinfo.sysname);
1080 g_string_append(ret, uzbl.state.unameinfo.nodename);
1083 g_string_append(ret, uzbl.state.unameinfo.release);
1086 g_string_append(ret, uzbl.state.unameinfo.version);
1089 g_string_append(ret, uzbl.state.unameinfo.machine);
1092 g_string_append(ret, ARCH);
1095 case SYM_DOMAINNAME:
1096 g_string_append(ret, uzbl.state.unameinfo.domainname);
1100 g_string_append(ret, COMMIT);
1106 else if(token == G_TOKEN_INT) {
1107 g_string_append_printf(ret, "%lu", g_scanner_cur_value(uzbl.scan).v_int);
1109 else if(token == G_TOKEN_IDENTIFIER) {
1110 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1112 else if(token == G_TOKEN_CHAR) {
1113 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1115 else if(token == G_TOKEN_ERROR) {
1116 g_scanner_error(uzbl.scan, "Token error in template ('%s') at line %d, column %d.",
1118 g_scanner_cur_line(uzbl.scan),
1119 g_scanner_cur_position(uzbl.scan));
1123 return g_string_free(ret, FALSE);
1125 /* --End Statusbar functions-- */
1128 sharg_append(GArray *a, const gchar *str) {
1129 const gchar *s = (str ? str : "");
1130 g_array_append_val(a, s);
1133 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1135 run_command (const gchar *command, const guint npre, const gchar **args,
1136 const gboolean sync, char **output_stdout) {
1137 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1140 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1141 gchar *pid = itos(getpid());
1142 gchar *xwin = itos(uzbl.xwin);
1144 sharg_append(a, command);
1145 for (i = 0; i < npre; i++) /* add n args before the default vars */
1146 sharg_append(a, args[i]);
1147 sharg_append(a, uzbl.state.config_file);
1148 sharg_append(a, pid);
1149 sharg_append(a, xwin);
1150 sharg_append(a, uzbl.comm.fifo_path);
1151 sharg_append(a, uzbl.comm.socket_path);
1152 sharg_append(a, uzbl.state.uri);
1153 sharg_append(a, uzbl.gui.main_title);
1155 for (i = npre; i < g_strv_length((gchar**)args); i++)
1156 sharg_append(a, args[i]);
1160 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1162 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1163 NULL, NULL, output_stdout, NULL, NULL, &err);
1164 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1165 NULL, NULL, NULL, &err);
1167 if (uzbl.state.verbose) {
1168 GString *s = g_string_new("spawned:");
1169 for (i = 0; i < (a->len); i++) {
1170 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1171 g_string_append_printf(s, " %s", qarg);
1174 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1175 printf("%s\n", s->str);
1176 g_string_free(s, TRUE);
1178 printf("Stdout: %s\n", *output_stdout);
1182 g_printerr("error on run_command: %s\n", err->message);
1187 g_array_free (a, TRUE);
1192 split_quoted(const gchar* src, const gboolean unquote) {
1193 /* split on unquoted space, return array of strings;
1194 remove a layer of quotes and backslashes if unquote */
1195 if (!src) return NULL;
1197 gboolean dq = FALSE;
1198 gboolean sq = FALSE;
1199 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1200 GString *s = g_string_new ("");
1204 for (p = src; *p != '\0'; p++) {
1205 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1206 else if (*p == '\\') { g_string_append_c(s, *p++);
1207 g_string_append_c(s, *p); }
1208 else if ((*p == '"') && unquote && !sq) dq = !dq;
1209 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1211 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1212 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1214 else if ((*p == ' ') && !dq && !sq) {
1215 dup = g_strdup(s->str);
1216 g_array_append_val(a, dup);
1217 g_string_truncate(s, 0);
1218 } else g_string_append_c(s, *p);
1220 dup = g_strdup(s->str);
1221 g_array_append_val(a, dup);
1222 ret = (gchar**)a->data;
1223 g_array_free (a, FALSE);
1224 g_string_free (s, TRUE);
1229 spawn(WebKitWebView *web_view, GArray *argv) {
1231 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1232 if (argv_idx(argv, 0))
1233 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1237 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1240 if (argv_idx(argv, 0))
1241 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1242 TRUE, &uzbl.comm.sync_stdout);
1246 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1248 if (!uzbl.behave.shell_cmd) {
1249 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1254 gchar *spacer = g_strdup("");
1255 g_array_insert_val(argv, 1, spacer);
1256 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1258 for (i = 1; i < g_strv_length(cmd); i++)
1259 g_array_prepend_val(argv, cmd[i]);
1261 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1267 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1269 if (!uzbl.behave.shell_cmd) {
1270 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1275 gchar *spacer = g_strdup("");
1276 g_array_insert_val(argv, 1, spacer);
1277 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1279 for (i = 1; i < g_strv_length(cmd); i++)
1280 g_array_prepend_val(argv, cmd[i]);
1282 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1283 TRUE, &uzbl.comm.sync_stdout);
1289 parse_command(const char *cmd, const char *param) {
1292 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1295 gchar **par = split_quoted(param, TRUE);
1296 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1298 if (c[1] == NOSPLIT) { /* don't split */
1299 sharg_append(a, param);
1301 for (i = 0; i < g_strv_length(par); i++)
1302 sharg_append(a, par[i]);
1304 c[0](uzbl.gui.web_view, a);
1306 g_array_free (a, TRUE);
1309 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1316 if(*uzbl.net.proxy_url == ' '
1317 || uzbl.net.proxy_url == NULL) {
1318 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1319 (GType) SOUP_SESSION_PROXY_URI);
1322 suri = soup_uri_new(uzbl.net.proxy_url);
1323 g_object_set(G_OBJECT(uzbl.net.soup_session),
1324 SOUP_SESSION_PROXY_URI,
1326 soup_uri_free(suri);
1333 if(file_exists(uzbl.gui.icon)) {
1334 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1336 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1342 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1343 g_array_append_val (a, uzbl.state.uri);
1344 load_uri(uzbl.gui.web_view, a);
1345 g_array_free (a, TRUE);
1349 cmd_always_insert_mode() {
1350 uzbl.behave.insert_mode =
1351 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1357 g_object_set(G_OBJECT(uzbl.net.soup_session),
1358 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1362 cmd_max_conns_host() {
1363 g_object_set(G_OBJECT(uzbl.net.soup_session),
1364 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1369 soup_session_remove_feature
1370 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1371 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1372 /*g_free(uzbl.net.soup_logger);*/
1374 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1375 soup_session_add_feature(uzbl.net.soup_session,
1376 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1381 return webkit_web_view_get_settings(uzbl.gui.web_view);
1386 WebKitWebSettings *ws = view_settings();
1387 if (uzbl.behave.font_size > 0) {
1388 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1391 if (uzbl.behave.monospace_size > 0) {
1392 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1393 uzbl.behave.monospace_size, NULL);
1395 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1396 uzbl.behave.font_size, NULL);
1402 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1406 cmd_disable_plugins() {
1407 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1408 !uzbl.behave.disable_plugins, NULL);
1412 cmd_disable_scripts() {
1413 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1414 !uzbl.behave.disable_scripts, NULL);
1418 cmd_minimum_font_size() {
1419 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1420 uzbl.behave.minimum_font_size, NULL);
1423 cmd_autoload_img() {
1424 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1425 uzbl.behave.autoload_img, NULL);
1430 cmd_autoshrink_img() {
1431 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1432 uzbl.behave.autoshrink_img, NULL);
1437 cmd_enable_spellcheck() {
1438 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1439 uzbl.behave.enable_spellcheck, NULL);
1443 cmd_enable_private() {
1444 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1445 uzbl.behave.enable_private, NULL);
1450 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1451 uzbl.behave.print_bg, NULL);
1456 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1457 uzbl.behave.style_uri, NULL);
1461 cmd_resizable_txt() {
1462 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1463 uzbl.behave.resizable_txt, NULL);
1467 cmd_default_encoding() {
1468 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1469 uzbl.behave.default_encoding, NULL);
1473 cmd_enforce_96dpi() {
1474 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1475 uzbl.behave.enforce_96dpi, NULL);
1479 cmd_caret_browsing() {
1480 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1481 uzbl.behave.caret_browsing, NULL);
1485 cmd_cookie_handler() {
1486 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1487 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1488 if ((g_strcmp0(split[0], "sh") == 0) ||
1489 (g_strcmp0(split[0], "spawn") == 0)) {
1490 g_free (uzbl.behave.cookie_handler);
1491 uzbl.behave.cookie_handler =
1492 g_strdup_printf("sync_%s %s", split[0], split[1]);
1499 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1504 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1509 if(uzbl.behave.inject_html) {
1510 webkit_web_view_load_html_string (uzbl.gui.web_view,
1511 uzbl.behave.inject_html, NULL);
1520 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1521 uzbl.behave.modmask = 0;
1523 if(uzbl.behave.modkey)
1524 g_free(uzbl.behave.modkey);
1525 uzbl.behave.modkey = buf;
1527 for (i = 0; modkeys[i].key != NULL; i++) {
1528 if (g_strrstr(buf, modkeys[i].key))
1529 uzbl.behave.modmask |= modkeys[i].mask;
1535 if (*uzbl.net.useragent == ' ') {
1536 g_free (uzbl.net.useragent);
1537 uzbl.net.useragent = NULL;
1539 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1541 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1542 g_free(uzbl.net.useragent);
1543 uzbl.net.useragent = ua;
1549 gtk_widget_ref(uzbl.gui.scrolled_win);
1550 gtk_widget_ref(uzbl.gui.mainbar);
1551 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1552 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1554 if(uzbl.behave.status_top) {
1555 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1556 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1559 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1560 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1562 gtk_widget_unref(uzbl.gui.scrolled_win);
1563 gtk_widget_unref(uzbl.gui.mainbar);
1564 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1569 set_var_value(gchar *name, gchar *val) {
1570 uzbl_cmdprop *c = NULL;
1574 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1575 /* check for the variable type */
1576 if (c->type == TYPE_STR) {
1577 buf = expand_vars(val);
1580 } else if(c->type == TYPE_INT) {
1581 int *ip = (int *)c->ptr;
1582 buf = expand_vars(val);
1583 *ip = (int)strtoul(buf, &endp, 10);
1585 } else if (c->type == TYPE_FLOAT) {
1586 float *fp = (float *)c->ptr;
1587 buf = expand_vars(val);
1588 *fp = strtod(buf, &endp);
1592 /* invoke a command specific function */
1593 if(c->func) c->func();
1600 Behaviour *b = &uzbl.behave;
1602 if(b->html_buffer->str) {
1603 webkit_web_view_load_html_string (uzbl.gui.web_view,
1604 b->html_buffer->str, b->base_url);
1605 g_string_free(b->html_buffer, TRUE);
1606 b->html_buffer = g_string_new("");
1610 enum {M_CMD, M_HTML};
1612 parse_cmd_line(const char *ctl_line) {
1613 Behaviour *b = &uzbl.behave;
1616 if(b->mode == M_HTML) {
1617 len = strlen(b->html_endmarker);
1618 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1619 if(len == strlen(ctl_line)-1 &&
1620 !strncmp(b->html_endmarker, ctl_line, len)) {
1622 set_var_value("mode", "0");
1627 set_timeout(b->html_timeout);
1628 g_string_append(b->html_buffer, ctl_line);
1631 else if((ctl_line[0] == '#') /* Comments */
1632 || (ctl_line[0] == ' ')
1633 || (ctl_line[0] == '\n'))
1634 ; /* ignore these lines */
1635 else { /* parse a command */
1637 gchar **tokens = NULL;
1638 len = strlen(ctl_line);
1640 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1641 ctlstrip = g_strndup(ctl_line, len - 1);
1642 else ctlstrip = g_strdup(ctl_line);
1644 tokens = g_strsplit(ctlstrip, " ", 2);
1645 parse_command(tokens[0], tokens[1]);
1652 build_stream_name(int type, const gchar* dir) {
1654 State *s = &uzbl.state;
1657 xwin_str = itos((int)uzbl.xwin);
1659 str = g_strdup_printf
1660 ("%s/uzbl_fifo_%s", dir,
1661 s->instance_name ? s->instance_name : xwin_str);
1662 } else if (type == SOCKET) {
1663 str = g_strdup_printf
1664 ("%s/uzbl_socket_%s", dir,
1665 s->instance_name ? s->instance_name : xwin_str );
1672 control_fifo(GIOChannel *gio, GIOCondition condition) {
1673 if (uzbl.state.verbose)
1674 printf("triggered\n");
1679 if (condition & G_IO_HUP)
1680 g_error ("Fifo: Read end of pipe died!\n");
1683 g_error ("Fifo: GIOChannel broke\n");
1685 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1686 if (ret == G_IO_STATUS_ERROR) {
1687 g_error ("Fifo: Error reading: %s\n", err->message);
1691 parse_cmd_line(ctl_line);
1698 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1699 GIOChannel *chan = NULL;
1700 GError *error = NULL;
1701 gchar *path = build_stream_name(FIFO, dir);
1703 if (!file_exists(path)) {
1704 if (mkfifo (path, 0666) == 0) {
1705 // 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.
1706 chan = g_io_channel_new_file(path, "r+", &error);
1708 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1709 if (uzbl.state.verbose)
1710 printf ("init_fifo: created successfully as %s\n", path);
1711 uzbl.comm.fifo_path = path;
1713 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1714 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1715 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1716 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1718 /* if we got this far, there was an error; cleanup */
1719 if (error) g_error_free (error);
1726 control_stdin(GIOChannel *gio, GIOCondition condition) {
1728 gchar *ctl_line = NULL;
1731 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1732 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1735 parse_cmd_line(ctl_line);
1743 GIOChannel *chan = NULL;
1744 GError *error = NULL;
1746 chan = g_io_channel_unix_new(fileno(stdin));
1748 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1749 g_error ("Stdin: could not add watch\n");
1751 if (uzbl.state.verbose)
1752 printf ("Stdin: watch added successfully\n");
1755 g_error ("Stdin: Error while opening: %s\n", error->message);
1757 if (error) g_error_free (error);
1761 control_socket(GIOChannel *chan) {
1762 struct sockaddr_un remote;
1763 char buffer[512], *ctl_line;
1765 int sock, clientsock, n, done;
1768 sock = g_io_channel_unix_get_fd(chan);
1770 memset (buffer, 0, sizeof (buffer));
1772 t = sizeof (remote);
1773 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1777 memset (temp, 0, sizeof (temp));
1778 n = recv (clientsock, temp, 128, 0);
1780 buffer[strlen (buffer)] = '\0';
1784 strcat (buffer, temp);
1787 if (strcmp (buffer, "\n") < 0) {
1788 buffer[strlen (buffer) - 1] = '\0';
1790 buffer[strlen (buffer)] = '\0';
1793 ctl_line = g_strdup(buffer);
1794 parse_cmd_line (ctl_line);
1797 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1798 GError *error = NULL;
1801 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1802 if (ret == G_IO_STATUS_ERROR)
1803 g_error ("Error reading: %s\n", error->message);
1805 printf("Got line %s (%u bytes) \n",ctl_line, len);
1807 parse_line(ctl_line);
1815 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1816 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1817 if (unlink(uzbl.comm.socket_path) == -1)
1818 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1819 g_free(uzbl.comm.socket_path);
1820 uzbl.comm.socket_path = NULL;
1828 GIOChannel *chan = NULL;
1830 struct sockaddr_un local;
1831 gchar *path = build_stream_name(SOCKET, dir);
1833 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1835 local.sun_family = AF_UNIX;
1836 strcpy (local.sun_path, path);
1837 unlink (local.sun_path);
1839 len = strlen (local.sun_path) + sizeof (local.sun_family);
1840 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1841 if (uzbl.state.verbose)
1842 printf ("init_socket: opened in %s\n", path);
1845 if( (chan = g_io_channel_unix_new(sock)) ) {
1846 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1847 uzbl.comm.socket_path = path;
1850 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1852 /* if we got this far, there was an error; cleanup */
1859 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1860 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1862 // this function may be called very early when the templates are not set (yet), hence the checks
1864 update_title (void) {
1865 Behaviour *b = &uzbl.behave;
1868 if (b->show_status) {
1869 if (b->title_format_short) {
1870 parsed = expand_template(b->title_format_short, FALSE);
1871 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1874 if (b->status_format) {
1875 parsed = expand_template(b->status_format, TRUE);
1876 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1879 if (b->status_background) {
1881 gdk_color_parse (b->status_background, &color);
1882 //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)
1883 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1886 if (b->title_format_long) {
1887 parsed = expand_template(b->title_format_long, FALSE);
1888 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1895 key_press_cb (GtkWidget* window, GdkEventKey* event)
1897 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1901 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1902 || 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)
1905 /* turn off insert mode (if always_insert_mode is not used) */
1906 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1907 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1912 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1915 if (event->keyval == GDK_Escape) {
1916 g_string_truncate(uzbl.state.keycmd, 0);
1918 dehilight(uzbl.gui.web_view, NULL);
1922 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1923 if (event->keyval == GDK_Insert) {
1925 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1926 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1928 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1931 g_string_append (uzbl.state.keycmd, str);
1938 if (event->keyval == GDK_BackSpace)
1939 keycmd_bs(NULL, NULL);
1941 gboolean key_ret = FALSE;
1942 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1944 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1946 run_keycmd(key_ret);
1948 if (key_ret) return (!uzbl.behave.insert_mode);
1953 run_keycmd(const gboolean key_ret) {
1954 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1956 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1957 g_string_truncate(uzbl.state.keycmd, 0);
1958 parse_command(act->name, act->param);
1962 /* try if it's an incremental keycmd or one that takes args, and run it */
1963 GString* short_keys = g_string_new ("");
1964 GString* short_keys_inc = g_string_new ("");
1966 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1967 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1968 g_string_assign(short_keys_inc, short_keys->str);
1969 g_string_append_c(short_keys, '_');
1970 g_string_append_c(short_keys_inc, '*');
1972 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1973 /* run normal cmds only if return was pressed */
1974 exec_paramcmd(act, i);
1975 g_string_truncate(uzbl.state.keycmd, 0);
1977 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1978 if (key_ret) /* just quit the incremental command on return */
1979 g_string_truncate(uzbl.state.keycmd, 0);
1980 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1984 g_string_truncate(short_keys, short_keys->len - 1);
1986 g_string_free (short_keys, TRUE);
1987 g_string_free (short_keys_inc, TRUE);
1991 exec_paramcmd(const Action *act, const guint i) {
1992 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1993 GString *actionname = g_string_new ("");
1994 GString *actionparam = g_string_new ("");
1995 g_string_erase (parampart, 0, i+1);
1997 g_string_printf (actionname, act->name, parampart->str);
1999 g_string_printf (actionparam, act->param, parampart->str);
2000 parse_command(actionname->str, actionparam->str);
2001 g_string_free(actionname, TRUE);
2002 g_string_free(actionparam, TRUE);
2003 g_string_free(parampart, TRUE);
2011 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2012 //main_window_ref = g_object_ref(scrolled_window);
2013 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
2015 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2016 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2018 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2020 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2021 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2022 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2023 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2024 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2025 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2026 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2027 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2028 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2030 return scrolled_window;
2037 g->mainbar = gtk_hbox_new (FALSE, 0);
2039 /* keep a reference to the bar so we can re-pack it at runtime*/
2040 //sbar_ref = g_object_ref(g->mainbar);
2042 g->mainbar_label = gtk_label_new ("");
2043 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2044 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2045 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2046 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2047 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2048 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2054 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2055 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2056 gtk_widget_set_name (window, "Uzbl browser");
2057 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2058 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2064 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2066 If actname is one that calls an external command, this function will inject
2067 newargs in front of the user-provided args in that command line. They will
2068 come become after the body of the script (in sh) or after the name of
2069 the command to execute (in spawn).
2070 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2071 spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2073 The return value consist of two strings: the action (sh, ...) and its args.
2075 If act is not one that calls an external command, then the given action merely
2078 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2079 /* Arrr! Here be memory leaks */
2080 gchar *actdup = g_strdup(actname);
2081 g_array_append_val(rets, actdup);
2083 if ((g_strcmp0(actname, "spawn") == 0) ||
2084 (g_strcmp0(actname, "sh") == 0) ||
2085 (g_strcmp0(actname, "sync_spawn") == 0) ||
2086 (g_strcmp0(actname, "sync_sh") == 0)) {
2088 GString *a = g_string_new("");
2089 gchar **spawnparts = split_quoted(origargs, FALSE);
2090 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2091 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2093 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2094 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2096 g_array_append_val(rets, a->str);
2097 g_string_free(a, FALSE);
2098 g_strfreev(spawnparts);
2100 gchar *origdup = g_strdup(origargs);
2101 g_array_append_val(rets, origdup);
2103 return (gchar**)g_array_free(rets, FALSE);
2107 run_handler (const gchar *act, const gchar *args) {
2108 /* Consider this code a temporary hack to make the handlers usable.
2109 In practice, all this splicing, injection, and reconstruction is
2110 inefficient, annoying and hard to manage. Potential pitfalls arise
2111 when the handler specific args 1) are not quoted (the handler
2112 callbacks should take care of this) 2) are quoted but interfere
2113 with the users' own quotation. A more ideal solution is
2114 to refactor parse_command so that it doesn't just take a string
2115 and execute it; rather than that, we should have a function which
2116 returns the argument vector parsed from the string. This vector
2117 could be modified (e.g. insert additional args into it) before
2118 passing it to the next function that actually executes it. Though
2119 it still isn't perfect for chain actions.. will reconsider & re-
2120 factor when I have the time. -duc */
2122 char **parts = g_strsplit(act, " ", 2);
2124 if (g_strcmp0(parts[0], "chain") == 0) {
2125 GString *newargs = g_string_new("");
2126 gchar **chainparts = split_quoted(parts[1], FALSE);
2128 /* for every argument in the chain, inject the handler args
2129 and make sure the new parts are wrapped in quotes */
2130 gchar **cp = chainparts;
2132 gchar *quotless = NULL;
2133 gchar **spliced_quotless = NULL; // sigh -_-;
2134 gchar **inpart = NULL;
2137 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2139 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2140 } else quotless = g_strdup(*cp);
2142 spliced_quotless = g_strsplit(quotless, " ", 2);
2143 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2144 g_strfreev(spliced_quotless);
2146 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2152 parse_command(parts[0], &(newargs->str[1]));
2153 g_string_free(newargs, TRUE);
2154 g_strfreev(chainparts);
2157 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2158 parse_command(inparts[0], inparts[1]);
2166 add_binding (const gchar *key, const gchar *act) {
2167 char **parts = g_strsplit(act, " ", 2);
2174 if (uzbl.state.verbose)
2175 printf ("Binding %-10s : %s\n", key, act);
2176 action = new_action(parts[0], parts[1]);
2178 if (g_hash_table_remove (uzbl.bindings, key))
2179 g_warning ("Overwriting existing binding for \"%s\"", key);
2180 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2185 get_xdg_var (XDG_Var xdg) {
2186 const gchar* actual_value = getenv (xdg.environmental);
2187 const gchar* home = getenv ("HOME");
2188 gchar* return_value;
2190 if (! actual_value || strcmp (actual_value, "") == 0) {
2191 if (xdg.default_value) {
2192 return_value = str_replace ("~", home, xdg.default_value);
2194 return_value = NULL;
2197 return_value = str_replace("~", home, actual_value);
2200 return return_value;
2204 find_xdg_file (int xdg_type, char* filename) {
2205 /* xdg_type = 0 => config
2206 xdg_type = 1 => data
2207 xdg_type = 2 => cache*/
2209 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2210 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2213 gchar* temporary_string;
2217 if (! file_exists (temporary_file) && xdg_type != 2) {
2218 buf = get_xdg_var (XDG[3 + xdg_type]);
2219 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2222 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2223 g_free (temporary_file);
2224 temporary_file = g_strconcat (temporary_string, filename, NULL);
2228 //g_free (temporary_string); - segfaults.
2230 if (file_exists (temporary_file)) {
2231 return temporary_file;
2238 State *s = &uzbl.state;
2239 Network *n = &uzbl.net;
2241 for (i = 0; default_config[i].command != NULL; i++) {
2242 parse_cmd_line(default_config[i].command);
2245 if (!s->config_file) {
2246 s->config_file = find_xdg_file (0, "/uzbl/config");
2249 if (s->config_file) {
2250 GArray* lines = read_file_by_line (s->config_file);
2254 while ((line = g_array_index(lines, gchar*, i))) {
2255 parse_cmd_line (line);
2259 g_array_free (lines, TRUE);
2261 if (uzbl.state.verbose)
2262 printf ("No configuration file loaded.\n");
2265 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2268 void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2271 if (!uzbl.behave.cookie_handler)
2274 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2275 GString *s = g_string_new ("");
2276 SoupURI * soup_uri = soup_message_get_uri(msg);
2277 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2278 run_handler(uzbl.behave.cookie_handler, s->str);
2280 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2281 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2282 if ( p != NULL ) *p = '\0';
2283 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2285 if (uzbl.comm.sync_stdout)
2286 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2288 g_string_free(s, TRUE);
2292 save_cookies (SoupMessage *msg, gpointer user_data){
2296 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2297 cookie = soup_cookie_to_set_cookie_header(ck->data);
2298 SoupURI * soup_uri = soup_message_get_uri(msg);
2299 GString *s = g_string_new ("");
2300 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2301 run_handler(uzbl.behave.cookie_handler, s->str);
2303 g_string_free(s, TRUE);
2308 /* --- WEBINSPECTOR --- */
2310 hide_window_cb(GtkWidget *widget, gpointer data) {
2313 gtk_widget_hide(widget);
2317 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2320 (void) web_inspector;
2321 GtkWidget* scrolled_window;
2322 GtkWidget* new_web_view;
2325 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2326 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2327 G_CALLBACK(hide_window_cb), NULL);
2329 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2330 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2331 gtk_widget_show(g->inspector_window);
2333 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2334 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2335 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2336 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2337 gtk_widget_show(scrolled_window);
2339 new_web_view = webkit_web_view_new();
2340 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2342 return WEBKIT_WEB_VIEW(new_web_view);
2346 inspector_show_window_cb (WebKitWebInspector* inspector){
2348 gtk_widget_show(uzbl.gui.inspector_window);
2352 /* TODO: Add variables and code to make use of these functions */
2354 inspector_close_window_cb (WebKitWebInspector* inspector){
2360 inspector_attach_window_cb (WebKitWebInspector* inspector){
2366 inspector_detach_window_cb (WebKitWebInspector* inspector){
2372 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2378 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2384 set_up_inspector() {
2386 WebKitWebSettings *settings = view_settings();
2387 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2389 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2390 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2391 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2392 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2393 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2394 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2395 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2397 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2401 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2403 uzbl_cmdprop *c = v;
2408 if(c->type == TYPE_STR)
2409 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2410 else if(c->type == TYPE_INT)
2411 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2412 else if(c->type == TYPE_FLOAT)
2413 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2417 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2421 printf("bind %s = %s %s\n", (char *)k ,
2422 (char *)a->name, a->param?(char *)a->param:"");
2427 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2428 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2431 #ifndef UZBL_LIBRARY
2434 main (int argc, char* argv[]) {
2435 gtk_init (&argc, &argv);
2436 if (!g_thread_supported ())
2437 g_thread_init (NULL);
2438 uzbl.state.executable_path = g_strdup(argv[0]);
2439 uzbl.state.selected_url = NULL;
2440 uzbl.state.searchtx = NULL;
2442 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2443 g_option_context_add_main_entries (context, entries, NULL);
2444 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2445 g_option_context_parse (context, &argc, &argv, NULL);
2446 g_option_context_free(context);
2448 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2449 gboolean verbose_override = uzbl.state.verbose;
2451 /* initialize hash table */
2452 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2454 uzbl.net.soup_session = webkit_get_default_session();
2455 uzbl.state.keycmd = g_string_new("");
2457 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2458 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2459 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2460 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2461 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2462 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2465 if(uname(&uzbl.state.unameinfo) == -1)
2466 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2468 uzbl.gui.sbar.progress_s = g_strdup("=");
2469 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2470 uzbl.gui.sbar.progress_w = 10;
2472 /* HTML mode defaults*/
2473 uzbl.behave.html_buffer = g_string_new("");
2474 uzbl.behave.html_endmarker = g_strdup(".");
2475 uzbl.behave.html_timeout = 60;
2476 uzbl.behave.base_url = g_strdup("http://invalid");
2478 /* default mode indicators */
2479 uzbl.behave.insert_indicator = g_strdup("I");
2480 uzbl.behave.cmd_indicator = g_strdup("C");
2484 make_var_to_name_hash();
2486 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2488 uzbl.gui.scrolled_win = create_browser();
2491 /* initial packing */
2492 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2493 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2495 uzbl.gui.main_window = create_window ();
2496 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2499 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2500 gtk_widget_show_all (uzbl.gui.main_window);
2501 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2503 if (uzbl.state.verbose) {
2504 printf("Uzbl start location: %s\n", argv[0]);
2505 printf("window_id %i\n",(int) uzbl.xwin);
2506 printf("pid %i\n", getpid ());
2507 printf("name: %s\n", uzbl.state.instance_name);
2510 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2511 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2512 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2513 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2514 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2518 if (!uzbl.behave.show_status)
2519 gtk_widget_hide(uzbl.gui.mainbar);
2528 if (verbose_override > uzbl.state.verbose)
2529 uzbl.state.verbose = verbose_override;
2532 set_var_value("uri", uri_override);
2533 g_free(uri_override);
2534 } else if (uzbl.state.uri)
2535 cmd_load_uri(uzbl.gui.web_view, NULL);
2540 return EXIT_SUCCESS;
2544 /* vi: set et ts=4: */