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 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1104 g_string_append(ret, buf);
1107 else if(token == G_TOKEN_IDENTIFIER) {
1108 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1110 else if(token == G_TOKEN_CHAR) {
1111 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1115 return g_string_free(ret, FALSE);
1117 /* --End Statusbar functions-- */
1120 sharg_append(GArray *a, const gchar *str) {
1121 const gchar *s = (str ? str : "");
1122 g_array_append_val(a, s);
1125 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1127 run_command (const gchar *command, const guint npre, const gchar **args,
1128 const gboolean sync, char **output_stdout) {
1129 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1132 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1133 gchar *pid = itos(getpid());
1134 gchar *xwin = itos(uzbl.xwin);
1136 sharg_append(a, command);
1137 for (i = 0; i < npre; i++) /* add n args before the default vars */
1138 sharg_append(a, args[i]);
1139 sharg_append(a, uzbl.state.config_file);
1140 sharg_append(a, pid);
1141 sharg_append(a, xwin);
1142 sharg_append(a, uzbl.comm.fifo_path);
1143 sharg_append(a, uzbl.comm.socket_path);
1144 sharg_append(a, uzbl.state.uri);
1145 sharg_append(a, uzbl.gui.main_title);
1147 for (i = npre; i < g_strv_length((gchar**)args); i++)
1148 sharg_append(a, args[i]);
1152 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1154 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1155 NULL, NULL, output_stdout, NULL, NULL, &err);
1156 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1157 NULL, NULL, NULL, &err);
1159 if (uzbl.state.verbose) {
1160 GString *s = g_string_new("spawned:");
1161 for (i = 0; i < (a->len); i++) {
1162 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1163 g_string_append_printf(s, " %s", qarg);
1166 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1167 printf("%s\n", s->str);
1168 g_string_free(s, TRUE);
1170 printf("Stdout: %s\n", *output_stdout);
1174 g_printerr("error on run_command: %s\n", err->message);
1179 g_array_free (a, TRUE);
1184 split_quoted(const gchar* src, const gboolean unquote) {
1185 /* split on unquoted space, return array of strings;
1186 remove a layer of quotes and backslashes if unquote */
1187 if (!src) return NULL;
1189 gboolean dq = FALSE;
1190 gboolean sq = FALSE;
1191 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1192 GString *s = g_string_new ("");
1196 for (p = src; *p != '\0'; p++) {
1197 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1198 else if (*p == '\\') { g_string_append_c(s, *p++);
1199 g_string_append_c(s, *p); }
1200 else if ((*p == '"') && unquote && !sq) dq = !dq;
1201 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1203 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1204 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1206 else if ((*p == ' ') && !dq && !sq) {
1207 dup = g_strdup(s->str);
1208 g_array_append_val(a, dup);
1209 g_string_truncate(s, 0);
1210 } else g_string_append_c(s, *p);
1212 dup = g_strdup(s->str);
1213 g_array_append_val(a, dup);
1214 ret = (gchar**)a->data;
1215 g_array_free (a, FALSE);
1216 g_string_free (s, TRUE);
1221 spawn(WebKitWebView *web_view, GArray *argv) {
1223 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1224 if (argv_idx(argv, 0))
1225 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1229 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1232 if (argv_idx(argv, 0))
1233 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1234 TRUE, &uzbl.comm.sync_stdout);
1238 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1240 if (!uzbl.behave.shell_cmd) {
1241 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1246 gchar *spacer = g_strdup("");
1247 g_array_insert_val(argv, 1, spacer);
1248 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1250 for (i = 1; i < g_strv_length(cmd); i++)
1251 g_array_prepend_val(argv, cmd[i]);
1253 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1259 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1261 if (!uzbl.behave.shell_cmd) {
1262 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1267 gchar *spacer = g_strdup("");
1268 g_array_insert_val(argv, 1, spacer);
1269 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1271 for (i = 1; i < g_strv_length(cmd); i++)
1272 g_array_prepend_val(argv, cmd[i]);
1274 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1275 TRUE, &uzbl.comm.sync_stdout);
1281 parse_command(const char *cmd, const char *param) {
1284 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1287 gchar **par = split_quoted(param, TRUE);
1288 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1290 if (c[1] == NOSPLIT) { /* don't split */
1291 sharg_append(a, param);
1293 for (i = 0; i < g_strv_length(par); i++)
1294 sharg_append(a, par[i]);
1296 c[0](uzbl.gui.web_view, a);
1298 g_array_free (a, TRUE);
1301 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1308 if(*uzbl.net.proxy_url == ' '
1309 || uzbl.net.proxy_url == NULL) {
1310 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1311 (GType) SOUP_SESSION_PROXY_URI);
1314 suri = soup_uri_new(uzbl.net.proxy_url);
1315 g_object_set(G_OBJECT(uzbl.net.soup_session),
1316 SOUP_SESSION_PROXY_URI,
1318 soup_uri_free(suri);
1325 if(file_exists(uzbl.gui.icon)) {
1326 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1328 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1334 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1335 g_array_append_val (a, uzbl.state.uri);
1336 load_uri(uzbl.gui.web_view, a);
1337 g_array_free (a, TRUE);
1341 cmd_always_insert_mode() {
1342 uzbl.behave.insert_mode =
1343 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1349 g_object_set(G_OBJECT(uzbl.net.soup_session),
1350 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1354 cmd_max_conns_host() {
1355 g_object_set(G_OBJECT(uzbl.net.soup_session),
1356 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1361 soup_session_remove_feature
1362 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1363 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1364 /*g_free(uzbl.net.soup_logger);*/
1366 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1367 soup_session_add_feature(uzbl.net.soup_session,
1368 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1371 static WebKitWebSettings*
1373 return webkit_web_view_get_settings(uzbl.gui.web_view);
1378 WebKitWebSettings *ws = view_settings();
1379 if (uzbl.behave.font_size > 0) {
1380 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1383 if (uzbl.behave.monospace_size > 0) {
1384 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1385 uzbl.behave.monospace_size, NULL);
1387 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1388 uzbl.behave.font_size, NULL);
1394 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1398 cmd_disable_plugins() {
1399 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1400 !uzbl.behave.disable_plugins, NULL);
1404 cmd_disable_scripts() {
1405 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1406 !uzbl.behave.disable_scripts, NULL);
1410 cmd_minimum_font_size() {
1411 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1412 uzbl.behave.minimum_font_size, NULL);
1415 cmd_autoload_img() {
1416 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1417 uzbl.behave.autoload_img, NULL);
1422 cmd_autoshrink_img() {
1423 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1424 uzbl.behave.autoshrink_img, NULL);
1429 cmd_enable_spellcheck() {
1430 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1431 uzbl.behave.enable_spellcheck, NULL);
1435 cmd_enable_private() {
1436 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1437 uzbl.behave.enable_private, NULL);
1442 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1443 uzbl.behave.print_bg, NULL);
1448 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1449 uzbl.behave.style_uri, NULL);
1453 cmd_resizable_txt() {
1454 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1455 uzbl.behave.resizable_txt, NULL);
1459 cmd_default_encoding() {
1460 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1461 uzbl.behave.default_encoding, NULL);
1465 cmd_enforce_96dpi() {
1466 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1467 uzbl.behave.enforce_96dpi, NULL);
1471 cmd_caret_browsing() {
1472 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1473 uzbl.behave.caret_browsing, NULL);
1477 cmd_cookie_handler() {
1478 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1479 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1480 if ((g_strcmp0(split[0], "sh") == 0) ||
1481 (g_strcmp0(split[0], "spawn") == 0)) {
1482 g_free (uzbl.behave.cookie_handler);
1483 uzbl.behave.cookie_handler =
1484 g_strdup_printf("sync_%s %s", split[0], split[1]);
1491 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1496 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1501 if(uzbl.behave.inject_html) {
1502 webkit_web_view_load_html_string (uzbl.gui.web_view,
1503 uzbl.behave.inject_html, NULL);
1512 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1513 uzbl.behave.modmask = 0;
1515 if(uzbl.behave.modkey)
1516 g_free(uzbl.behave.modkey);
1517 uzbl.behave.modkey = buf;
1519 for (i = 0; modkeys[i].key != NULL; i++) {
1520 if (g_strrstr(buf, modkeys[i].key))
1521 uzbl.behave.modmask |= modkeys[i].mask;
1527 if (*uzbl.net.useragent == ' ') {
1528 g_free (uzbl.net.useragent);
1529 uzbl.net.useragent = NULL;
1531 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1533 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1534 g_free(uzbl.net.useragent);
1535 uzbl.net.useragent = ua;
1541 gtk_widget_ref(uzbl.gui.scrolled_win);
1542 gtk_widget_ref(uzbl.gui.mainbar);
1543 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1544 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1546 if(uzbl.behave.status_top) {
1547 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1548 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1551 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1552 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1554 gtk_widget_unref(uzbl.gui.scrolled_win);
1555 gtk_widget_unref(uzbl.gui.mainbar);
1556 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1561 set_var_value(gchar *name, gchar *val) {
1562 uzbl_cmdprop *c = NULL;
1566 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1567 /* check for the variable type */
1568 if (c->type == TYPE_STR) {
1569 buf = expand_vars(val);
1572 } else if(c->type == TYPE_INT) {
1573 int *ip = (int *)c->ptr;
1574 buf = expand_vars(val);
1575 *ip = (int)strtoul(buf, &endp, 10);
1577 } else if (c->type == TYPE_FLOAT) {
1578 float *fp = (float *)c->ptr;
1579 buf = expand_vars(val);
1580 *fp = strtod(buf, &endp);
1584 /* invoke a command specific function */
1585 if(c->func) c->func();
1592 Behaviour *b = &uzbl.behave;
1594 if(b->html_buffer->str) {
1595 webkit_web_view_load_html_string (uzbl.gui.web_view,
1596 b->html_buffer->str, b->base_url);
1597 g_string_free(b->html_buffer, TRUE);
1598 b->html_buffer = g_string_new("");
1602 enum {M_CMD, M_HTML};
1604 parse_cmd_line(const char *ctl_line) {
1605 Behaviour *b = &uzbl.behave;
1608 if(b->mode == M_HTML) {
1609 len = strlen(b->html_endmarker);
1610 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1611 if(len == strlen(ctl_line)-1 &&
1612 !strncmp(b->html_endmarker, ctl_line, len)) {
1614 set_var_value("mode", "0");
1619 set_timeout(b->html_timeout);
1620 g_string_append(b->html_buffer, ctl_line);
1623 else if((ctl_line[0] == '#') /* Comments */
1624 || (ctl_line[0] == ' ')
1625 || (ctl_line[0] == '\n'))
1626 ; /* ignore these lines */
1627 else { /* parse a command */
1629 gchar **tokens = NULL;
1630 len = strlen(ctl_line);
1632 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1633 ctlstrip = g_strndup(ctl_line, len - 1);
1634 else ctlstrip = g_strdup(ctl_line);
1636 tokens = g_strsplit(ctlstrip, " ", 2);
1637 parse_command(tokens[0], tokens[1]);
1644 build_stream_name(int type, const gchar* dir) {
1646 State *s = &uzbl.state;
1649 xwin_str = itos((int)uzbl.xwin);
1651 str = g_strdup_printf
1652 ("%s/uzbl_fifo_%s", dir,
1653 s->instance_name ? s->instance_name : xwin_str);
1654 } else if (type == SOCKET) {
1655 str = g_strdup_printf
1656 ("%s/uzbl_socket_%s", dir,
1657 s->instance_name ? s->instance_name : xwin_str );
1664 control_fifo(GIOChannel *gio, GIOCondition condition) {
1665 if (uzbl.state.verbose)
1666 printf("triggered\n");
1671 if (condition & G_IO_HUP)
1672 g_error ("Fifo: Read end of pipe died!\n");
1675 g_error ("Fifo: GIOChannel broke\n");
1677 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1678 if (ret == G_IO_STATUS_ERROR) {
1679 g_error ("Fifo: Error reading: %s\n", err->message);
1683 parse_cmd_line(ctl_line);
1690 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1691 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1692 if (unlink(uzbl.comm.fifo_path) == -1)
1693 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1694 g_free(uzbl.comm.fifo_path);
1695 uzbl.comm.fifo_path = NULL;
1698 if (*dir == ' ') { /* space unsets the variable */
1703 GIOChannel *chan = NULL;
1704 GError *error = NULL;
1705 gchar *path = build_stream_name(FIFO, dir);
1707 if (!file_exists(path)) {
1708 if (mkfifo (path, 0666) == 0) {
1709 // 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.
1710 chan = g_io_channel_new_file(path, "r+", &error);
1712 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1713 if (uzbl.state.verbose)
1714 printf ("init_fifo: created successfully as %s\n", path);
1715 uzbl.comm.fifo_path = path;
1717 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1718 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1719 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1720 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1722 /* if we got this far, there was an error; cleanup */
1723 if (error) g_error_free (error);
1730 control_stdin(GIOChannel *gio, GIOCondition condition) {
1732 gchar *ctl_line = NULL;
1735 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1736 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1739 parse_cmd_line(ctl_line);
1747 GIOChannel *chan = NULL;
1748 GError *error = NULL;
1750 chan = g_io_channel_unix_new(fileno(stdin));
1752 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1753 g_error ("Stdin: could not add watch\n");
1755 if (uzbl.state.verbose)
1756 printf ("Stdin: watch added successfully\n");
1759 g_error ("Stdin: Error while opening: %s\n", error->message);
1761 if (error) g_error_free (error);
1765 control_socket(GIOChannel *chan) {
1766 struct sockaddr_un remote;
1767 char buffer[512], *ctl_line;
1769 int sock, clientsock, n, done;
1772 sock = g_io_channel_unix_get_fd(chan);
1774 memset (buffer, 0, sizeof (buffer));
1776 t = sizeof (remote);
1777 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1781 memset (temp, 0, sizeof (temp));
1782 n = recv (clientsock, temp, 128, 0);
1784 buffer[strlen (buffer)] = '\0';
1788 strcat (buffer, temp);
1791 if (strcmp (buffer, "\n") < 0) {
1792 buffer[strlen (buffer) - 1] = '\0';
1794 buffer[strlen (buffer)] = '\0';
1797 ctl_line = g_strdup(buffer);
1798 parse_cmd_line (ctl_line);
1801 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1802 GError *error = NULL;
1805 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1806 if (ret == G_IO_STATUS_ERROR)
1807 g_error ("Error reading: %s\n", error->message);
1809 printf("Got line %s (%u bytes) \n",ctl_line, len);
1811 parse_line(ctl_line);
1819 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1820 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1821 if (unlink(uzbl.comm.socket_path) == -1)
1822 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1823 g_free(uzbl.comm.socket_path);
1824 uzbl.comm.socket_path = NULL;
1832 GIOChannel *chan = NULL;
1834 struct sockaddr_un local;
1835 gchar *path = build_stream_name(SOCKET, dir);
1837 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1839 local.sun_family = AF_UNIX;
1840 strcpy (local.sun_path, path);
1841 unlink (local.sun_path);
1843 len = strlen (local.sun_path) + sizeof (local.sun_family);
1844 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1845 if (uzbl.state.verbose)
1846 printf ("init_socket: opened in %s\n", path);
1849 if( (chan = g_io_channel_unix_new(sock)) ) {
1850 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1851 uzbl.comm.socket_path = path;
1854 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1856 /* if we got this far, there was an error; cleanup */
1863 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1864 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1866 // this function may be called very early when the templates are not set (yet), hence the checks
1868 update_title (void) {
1869 Behaviour *b = &uzbl.behave;
1872 if (b->show_status) {
1873 if (b->title_format_short) {
1874 parsed = expand_template(b->title_format_short, FALSE);
1875 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1878 if (b->status_format) {
1879 parsed = expand_template(b->status_format, TRUE);
1880 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1883 if (b->status_background) {
1885 gdk_color_parse (b->status_background, &color);
1886 //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)
1887 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1890 if (b->title_format_long) {
1891 parsed = expand_template(b->title_format_long, FALSE);
1892 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1899 key_press_cb (GtkWidget* window, GdkEventKey* event)
1901 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1905 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1906 || 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)
1909 /* turn off insert mode (if always_insert_mode is not used) */
1910 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1911 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1916 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1919 if (event->keyval == GDK_Escape) {
1920 g_string_truncate(uzbl.state.keycmd, 0);
1922 dehilight(uzbl.gui.web_view, NULL);
1926 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1927 if (event->keyval == GDK_Insert) {
1929 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1930 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1932 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1935 g_string_append (uzbl.state.keycmd, str);
1942 if (event->keyval == GDK_BackSpace)
1943 keycmd_bs(NULL, NULL);
1945 gboolean key_ret = FALSE;
1946 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1948 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1950 run_keycmd(key_ret);
1952 if (key_ret) return (!uzbl.behave.insert_mode);
1957 run_keycmd(const gboolean key_ret) {
1958 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1960 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1961 g_string_truncate(uzbl.state.keycmd, 0);
1962 parse_command(act->name, act->param);
1966 /* try if it's an incremental keycmd or one that takes args, and run it */
1967 GString* short_keys = g_string_new ("");
1968 GString* short_keys_inc = g_string_new ("");
1970 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1971 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1972 g_string_assign(short_keys_inc, short_keys->str);
1973 g_string_append_c(short_keys, '_');
1974 g_string_append_c(short_keys_inc, '*');
1976 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1977 /* run normal cmds only if return was pressed */
1978 exec_paramcmd(act, i);
1979 g_string_truncate(uzbl.state.keycmd, 0);
1981 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1982 if (key_ret) /* just quit the incremental command on return */
1983 g_string_truncate(uzbl.state.keycmd, 0);
1984 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1988 g_string_truncate(short_keys, short_keys->len - 1);
1990 g_string_free (short_keys, TRUE);
1991 g_string_free (short_keys_inc, TRUE);
1995 exec_paramcmd(const Action *act, const guint i) {
1996 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1997 GString *actionname = g_string_new ("");
1998 GString *actionparam = g_string_new ("");
1999 g_string_erase (parampart, 0, i+1);
2001 g_string_printf (actionname, act->name, parampart->str);
2003 g_string_printf (actionparam, act->param, parampart->str);
2004 parse_command(actionname->str, actionparam->str);
2005 g_string_free(actionname, TRUE);
2006 g_string_free(actionparam, TRUE);
2007 g_string_free(parampart, TRUE);
2015 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2016 //main_window_ref = g_object_ref(scrolled_window);
2017 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
2019 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2020 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2022 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2023 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2024 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2025 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2026 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2027 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2028 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2029 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2030 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2034 return scrolled_window;
2041 g->mainbar = gtk_hbox_new (FALSE, 0);
2043 /* keep a reference to the bar so we can re-pack it at runtime*/
2044 //sbar_ref = g_object_ref(g->mainbar);
2046 g->mainbar_label = gtk_label_new ("");
2047 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2048 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2049 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2050 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2051 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2052 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2057 GtkWidget* create_window () {
2058 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2059 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2060 gtk_widget_set_name (window, "Uzbl browser");
2061 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2062 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2068 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2070 If actname is one that calls an external command, this function will inject
2071 newargs in front of the user-provided args in that command line. They will
2072 come become after the body of the script (in sh) or after the name of
2073 the command to execute (in spawn).
2074 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2075 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2077 The return value consist of two strings: the action (sh, ...) and its args.
2079 If act is not one that calls an external command, then the given action merely
2082 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2083 gchar *actdup = g_strdup(actname);
2084 g_array_append_val(rets, actdup);
2086 if ((g_strcmp0(actname, "spawn") == 0) ||
2087 (g_strcmp0(actname, "sh") == 0) ||
2088 (g_strcmp0(actname, "sync_spawn") == 0) ||
2089 (g_strcmp0(actname, "sync_sh") == 0)) {
2091 GString *a = g_string_new("");
2092 gchar **spawnparts = split_quoted(origargs, FALSE);
2093 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2094 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2096 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2097 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2099 g_array_append_val(rets, a->str);
2100 g_string_free(a, FALSE);
2101 g_strfreev(spawnparts);
2103 gchar *origdup = g_strdup(origargs);
2104 g_array_append_val(rets, origdup);
2106 return (gchar**)g_array_free(rets, FALSE);
2110 run_handler (const gchar *act, const gchar *args) {
2111 /* Consider this code a temporary hack to make the handlers usable.
2112 In practice, all this splicing, injection, and reconstruction is
2113 inefficient, annoying and hard to manage. Potential pitfalls arise
2114 when the handler specific args 1) are not quoted (the handler
2115 callbacks should take care of this) 2) are quoted but interfere
2116 with the users' own quotation. A more ideal solution is
2117 to refactor parse_command so that it doesn't just take a string
2118 and execute it; rather than that, we should have a function which
2119 returns the argument vector parsed from the string. This vector
2120 could be modified (e.g. insert additional args into it) before
2121 passing it to the next function that actually executes it. Though
2122 it still isn't perfect for chain actions.. will reconsider & re-
2123 factor when I have the time. -duc */
2125 char **parts = g_strsplit(act, " ", 2);
2127 if (g_strcmp0(parts[0], "chain") == 0) {
2128 GString *newargs = g_string_new("");
2129 gchar **chainparts = split_quoted(parts[1], FALSE);
2131 /* for every argument in the chain, inject the handler args
2132 and make sure the new parts are wrapped in quotes */
2133 gchar **cp = chainparts;
2135 gchar *quotless = NULL;
2136 gchar **spliced_quotless = NULL; // sigh -_-;
2137 gchar **inpart = NULL;
2140 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2142 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2143 } else quotless = g_strdup(*cp);
2145 spliced_quotless = g_strsplit(quotless, " ", 2);
2146 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2147 g_strfreev(spliced_quotless);
2149 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2155 parse_command(parts[0], &(newargs->str[1]));
2156 g_string_free(newargs, TRUE);
2157 g_strfreev(chainparts);
2160 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2161 parse_command(inparts[0], inparts[1]);
2169 add_binding (const gchar *key, const gchar *act) {
2170 char **parts = g_strsplit(act, " ", 2);
2177 if (uzbl.state.verbose)
2178 printf ("Binding %-10s : %s\n", key, act);
2179 action = new_action(parts[0], parts[1]);
2181 if (g_hash_table_remove (uzbl.bindings, key))
2182 g_warning ("Overwriting existing binding for \"%s\"", key);
2183 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2188 get_xdg_var (XDG_Var xdg) {
2189 const gchar* actual_value = getenv (xdg.environmental);
2190 const gchar* home = getenv ("HOME");
2191 gchar* return_value;
2193 if (! actual_value || strcmp (actual_value, "") == 0) {
2194 if (xdg.default_value) {
2195 return_value = str_replace ("~", home, xdg.default_value);
2197 return_value = NULL;
2200 return_value = str_replace("~", home, actual_value);
2203 return return_value;
2207 find_xdg_file (int xdg_type, char* filename) {
2208 /* xdg_type = 0 => config
2209 xdg_type = 1 => data
2210 xdg_type = 2 => cache*/
2212 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2213 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2216 gchar* temporary_string;
2220 if (! file_exists (temporary_file) && xdg_type != 2) {
2221 buf = get_xdg_var (XDG[3 + xdg_type]);
2222 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2225 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2226 g_free (temporary_file);
2227 temporary_file = g_strconcat (temporary_string, filename, NULL);
2231 //g_free (temporary_string); - segfaults.
2233 if (file_exists (temporary_file)) {
2234 return temporary_file;
2241 State *s = &uzbl.state;
2242 Network *n = &uzbl.net;
2244 for (i = 0; default_config[i].command != NULL; i++) {
2245 parse_cmd_line(default_config[i].command);
2248 if (!s->config_file) {
2249 s->config_file = find_xdg_file (0, "/uzbl/config");
2252 if (s->config_file) {
2253 GArray* lines = read_file_by_line (s->config_file);
2257 while ((line = g_array_index(lines, gchar*, i))) {
2258 parse_cmd_line (line);
2262 g_array_free (lines, TRUE);
2264 if (uzbl.state.verbose)
2265 printf ("No configuration file loaded.\n");
2268 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2271 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2274 if (!uzbl.behave.cookie_handler)
2277 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2278 GString *s = g_string_new ("");
2279 SoupURI * soup_uri = soup_message_get_uri(msg);
2280 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2281 run_handler(uzbl.behave.cookie_handler, s->str);
2283 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2284 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2285 if ( p != NULL ) *p = '\0';
2286 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2288 if (uzbl.comm.sync_stdout)
2289 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2291 g_string_free(s, TRUE);
2295 save_cookies (SoupMessage *msg, gpointer user_data){
2299 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2300 cookie = soup_cookie_to_set_cookie_header(ck->data);
2301 SoupURI * soup_uri = soup_message_get_uri(msg);
2302 GString *s = g_string_new ("");
2303 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2304 run_handler(uzbl.behave.cookie_handler, s->str);
2306 g_string_free(s, TRUE);
2311 /* --- WEBINSPECTOR --- */
2313 hide_window_cb(GtkWidget *widget, gpointer data) {
2316 gtk_widget_hide(widget);
2319 static WebKitWebView*
2320 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2323 (void) web_inspector;
2324 GtkWidget* scrolled_window;
2325 GtkWidget* new_web_view;
2328 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2329 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2330 G_CALLBACK(hide_window_cb), NULL);
2332 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2333 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2334 gtk_widget_show(g->inspector_window);
2336 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2337 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2338 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2339 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2340 gtk_widget_show(scrolled_window);
2342 new_web_view = webkit_web_view_new();
2343 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2345 return WEBKIT_WEB_VIEW(new_web_view);
2349 inspector_show_window_cb (WebKitWebInspector* inspector){
2351 gtk_widget_show(uzbl.gui.inspector_window);
2355 /* TODO: Add variables and code to make use of these functions */
2357 inspector_close_window_cb (WebKitWebInspector* inspector){
2363 inspector_attach_window_cb (WebKitWebInspector* inspector){
2369 inspector_detach_window_cb (WebKitWebInspector* inspector){
2375 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2381 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2387 set_up_inspector() {
2389 WebKitWebSettings *settings = view_settings();
2390 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2392 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2393 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2394 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2395 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2396 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2397 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2398 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2400 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2404 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2406 uzbl_cmdprop *c = v;
2411 if(c->type == TYPE_STR)
2412 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2413 else if(c->type == TYPE_INT)
2414 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2415 else if(c->type == TYPE_FLOAT)
2416 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2420 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2424 printf("bind %s = %s %s\n", (char *)k ,
2425 (char *)a->name, a->param?(char *)a->param:"");
2430 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2431 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2436 main (int argc, char* argv[]) {
2437 gtk_init (&argc, &argv);
2438 if (!g_thread_supported ())
2439 g_thread_init (NULL);
2440 uzbl.state.executable_path = g_strdup(argv[0]);
2441 uzbl.state.selected_url = NULL;
2442 uzbl.state.searchtx = NULL;
2444 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2445 g_option_context_add_main_entries (context, entries, NULL);
2446 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2447 g_option_context_parse (context, &argc, &argv, NULL);
2448 g_option_context_free(context);
2450 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2451 gboolean verbose_override = uzbl.state.verbose;
2453 /* initialize hash table */
2454 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2456 uzbl.net.soup_session = webkit_get_default_session();
2457 uzbl.state.keycmd = g_string_new("");
2459 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2460 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2461 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2462 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2463 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2464 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2467 if(uname(&uzbl.state.unameinfo) == -1)
2468 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2470 uzbl.gui.sbar.progress_s = g_strdup("=");
2471 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2472 uzbl.gui.sbar.progress_w = 10;
2474 /* HTML mode defaults*/
2475 uzbl.behave.html_buffer = g_string_new("");
2476 uzbl.behave.html_endmarker = g_strdup(".");
2477 uzbl.behave.html_timeout = 60;
2478 uzbl.behave.base_url = g_strdup("http://invalid");
2480 /* default mode indicators */
2481 uzbl.behave.insert_indicator = g_strdup("I");
2482 uzbl.behave.cmd_indicator = g_strdup("C");
2486 make_var_to_name_hash();
2488 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2490 uzbl.gui.scrolled_win = create_browser();
2493 /* initial packing */
2494 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2495 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2497 uzbl.gui.main_window = create_window ();
2498 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2501 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2502 gtk_widget_show_all (uzbl.gui.main_window);
2503 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2505 if (uzbl.state.verbose) {
2506 printf("Uzbl start location: %s\n", argv[0]);
2507 printf("window_id %i\n",(int) uzbl.xwin);
2508 printf("pid %i\n", getpid ());
2509 printf("name: %s\n", uzbl.state.instance_name);
2512 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2513 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2514 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2515 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2516 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2520 if (!uzbl.behave.show_status)
2521 gtk_widget_hide(uzbl.gui.mainbar);
2530 if (verbose_override > uzbl.state.verbose)
2531 uzbl.state.verbose = verbose_override;
2534 set_var_value("uri", uri_override);
2535 g_free(uri_override);
2536 } else if (uzbl.state.uri)
2537 cmd_load_uri(uzbl.gui.web_view, NULL);
2542 return EXIT_SUCCESS;
2545 /* vi: set et ts=4: */