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 {
87 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
89 /* an abbreviation to help keep the table's width humane */
90 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
95 } var_name_to_ptr[] = {
96 /* variable name pointer to variable in code type dump callback function */
97 /* --------------------------------------------------------------------------------------- */
98 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
99 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
118 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
119 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
120 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
121 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
122 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
123 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
124 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
125 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
126 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
127 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
128 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
129 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
130 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
131 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
132 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
133 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
134 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
135 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
136 /* exported WebKitWebSettings properties */
137 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
138 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
139 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
140 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
141 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
142 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
143 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
144 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
145 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
146 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
147 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
148 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
149 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
150 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
151 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
152 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
154 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
155 }, *n2v_p = var_name_to_ptr;
161 { "SHIFT", GDK_SHIFT_MASK }, // shift
162 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
163 { "CONTROL", GDK_CONTROL_MASK }, // control
164 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
165 { "MOD2", GDK_MOD2_MASK }, // 5th mod
166 { "MOD3", GDK_MOD3_MASK }, // 6th mod
167 { "MOD4", GDK_MOD4_MASK }, // 7th mod
168 { "MOD5", GDK_MOD5_MASK }, // 8th mod
169 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
170 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
171 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
172 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
173 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
174 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
175 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
176 { "META", GDK_META_MASK }, // meta (since 2.10)
181 /* construct a hash from the var_name_to_ptr array for quick access */
183 make_var_to_name_hash() {
184 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
186 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
191 /* --- UTILITY FUNCTIONS --- */
193 expand_vars(char *s) {
196 char ret[256], *vend;
197 GString *buf = g_string_new("");
202 g_string_append_c(buf, *++s);
210 if( (vend = strchr(s, upto)) ||
211 (vend = strchr(s, '\0')) ) {
212 strncpy(ret, s, vend-s);
214 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
215 if(c->type == TYPE_STR)
216 g_string_append(buf, (gchar *)*c->ptr);
217 else if(c->type == TYPE_INT) {
218 char *b = itos((int)*c->ptr);
219 g_string_append(buf, b);
223 if(upto == ' ') s = vend;
229 g_string_append_c(buf, *s);
234 return g_string_free(buf, FALSE);
241 snprintf(tmp, sizeof(tmp), "%i", val);
242 return g_strdup(tmp);
246 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
249 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
252 str_replace (const char* search, const char* replace, const char* string) {
256 buf = g_strsplit (string, search, -1);
257 ret = g_strjoinv (replace, buf);
258 g_strfreev(buf); // somebody said this segfaults
264 read_file_by_line (gchar *path) {
265 GIOChannel *chan = NULL;
266 gchar *readbuf = NULL;
268 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
271 chan = g_io_channel_new_file(path, "r", NULL);
274 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
275 const gchar* val = g_strdup (readbuf);
276 g_array_append_val (lines, val);
281 g_io_channel_unref (chan);
283 fprintf(stderr, "File '%s' not be read.\n", path);
290 gchar* parseenv (char* string) {
291 extern char** environ;
292 gchar* tmpstr = NULL;
296 while (environ[i] != NULL) {
297 gchar** env = g_strsplit (environ[i], "=", 2);
298 gchar* envname = g_strconcat ("$", env[0], NULL);
300 if (g_strrstr (string, envname) != NULL) {
301 tmpstr = g_strdup(string);
303 string = str_replace(envname, env[1], tmpstr);
308 g_strfreev (env); // somebody said this breaks uzbl
316 setup_signal(int signr, sigfunc *shandler) {
317 struct sigaction nh, oh;
319 nh.sa_handler = shandler;
320 sigemptyset(&nh.sa_mask);
323 if(sigaction(signr, &nh, &oh) < 0)
331 if (uzbl.behave.fifo_dir)
332 unlink (uzbl.comm.fifo_path);
333 if (uzbl.behave.socket_dir)
334 unlink (uzbl.comm.socket_path);
336 g_free(uzbl.state.executable_path);
337 g_string_free(uzbl.state.keycmd, TRUE);
338 g_hash_table_destroy(uzbl.bindings);
339 g_hash_table_destroy(uzbl.behave.commands);
342 /* used for html_mode_timeout
343 * be sure to extend this function to use
344 * more timers if needed in other places
347 set_timeout(int seconds) {
349 memset(&t, 0, sizeof t);
351 t.it_value.tv_sec = seconds;
352 t.it_value.tv_usec = 0;
353 setitimer(ITIMER_REAL, &t, NULL);
356 /* --- SIGNAL HANDLER --- */
359 catch_sigterm(int s) {
365 catch_sigint(int s) {
375 set_var_value("mode", "0");
380 /* --- CALLBACKS --- */
383 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
386 (void) navigation_action;
387 (void) policy_decision;
389 const gchar* uri = webkit_network_request_get_uri (request);
390 if (uzbl.state.verbose)
391 printf("New window requested -> %s \n", uri);
392 new_window_load_uri(uri);
397 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
402 /* If we can display it, let's display it... */
403 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
404 webkit_web_policy_decision_use (policy_decision);
408 /* ...everything we can't displayed is downloaded */
409 webkit_web_policy_decision_download (policy_decision);
414 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
418 if (uzbl.state.selected_url != NULL) {
419 if (uzbl.state.verbose)
420 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
421 new_window_load_uri(uzbl.state.selected_url);
423 if (uzbl.state.verbose)
424 printf("New web view -> %s\n","Nothing to open, exiting");
430 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
433 if (uzbl.behave.download_handler) {
434 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
435 if (uzbl.state.verbose)
436 printf("Download -> %s\n",uri);
437 /* if urls not escaped, we may have to escape and quote uri before this call */
438 run_handler(uzbl.behave.download_handler, uri);
443 /* scroll a bar in a given direction */
445 scroll (GtkAdjustment* bar, GArray *argv) {
449 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
450 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
451 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
455 scroll_begin(WebKitWebView* page, GArray *argv) {
456 (void) page; (void) argv;
457 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
461 scroll_end(WebKitWebView* page, GArray *argv) {
462 (void) page; (void) argv;
463 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
464 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
468 scroll_vert(WebKitWebView* page, GArray *argv) {
470 scroll(uzbl.gui.bar_v, argv);
474 scroll_horz(WebKitWebView* page, GArray *argv) {
476 scroll(uzbl.gui.bar_h, argv);
481 if (!uzbl.behave.show_status) {
482 gtk_widget_hide(uzbl.gui.mainbar);
484 gtk_widget_show(uzbl.gui.mainbar);
490 toggle_zoom_type (WebKitWebView* page, GArray *argv) {
494 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
498 toggle_status_cb (WebKitWebView* page, GArray *argv) {
502 if (uzbl.behave.show_status) {
503 gtk_widget_hide(uzbl.gui.mainbar);
505 gtk_widget_show(uzbl.gui.mainbar);
507 uzbl.behave.show_status = !uzbl.behave.show_status;
512 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
516 //Set selected_url state variable
517 g_free(uzbl.state.selected_url);
518 uzbl.state.selected_url = NULL;
520 uzbl.state.selected_url = g_strdup(link);
526 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
530 if (uzbl.gui.main_title)
531 g_free (uzbl.gui.main_title);
532 uzbl.gui.main_title = g_strdup (title);
537 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
540 uzbl.gui.sbar.load_progress = progress;
545 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
549 if (uzbl.behave.load_finish_handler)
550 run_handler(uzbl.behave.load_finish_handler, "");
554 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
558 uzbl.gui.sbar.load_progress = 0;
559 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
560 if (uzbl.behave.load_start_handler)
561 run_handler(uzbl.behave.load_start_handler, "");
565 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
568 g_free (uzbl.state.uri);
569 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
570 uzbl.state.uri = g_string_free (newuri, FALSE);
571 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
572 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
575 if (uzbl.behave.load_commit_handler)
576 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
580 destroy_cb (GtkWidget* widget, gpointer data) {
588 if (uzbl.behave.history_handler) {
590 struct tm * timeinfo;
593 timeinfo = localtime ( &rawtime );
594 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
595 run_handler(uzbl.behave.history_handler, date);
600 /* VIEW funcs (little webkit wrappers) */
601 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
603 VIEWFUNC(reload_bypass_cache)
604 VIEWFUNC(stop_loading)
611 /* -- command to callback/function map for things we cannot attach to any signals */
612 static struct {char *name; Command command[2];} cmdlist[] =
613 { /* key function no_split */
614 { "back", {view_go_back, 0} },
615 { "forward", {view_go_forward, 0} },
616 { "scroll_vert", {scroll_vert, 0} },
617 { "scroll_horz", {scroll_horz, 0} },
618 { "scroll_begin", {scroll_begin, 0} },
619 { "scroll_end", {scroll_end, 0} },
620 { "reload", {view_reload, 0}, },
621 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
622 { "stop", {view_stop_loading, 0}, },
623 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
624 { "zoom_out", {view_zoom_out, 0}, },
625 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
626 { "uri", {load_uri, NOSPLIT} },
627 { "js", {run_js, NOSPLIT} },
628 { "script", {run_external_js, 0} },
629 { "toggle_status", {toggle_status_cb, 0} },
630 { "spawn", {spawn, 0} },
631 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
632 { "sh", {spawn_sh, 0} },
633 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
634 { "exit", {close_uzbl, 0} },
635 { "search", {search_forward_text, NOSPLIT} },
636 { "search_reverse", {search_reverse_text, NOSPLIT} },
637 { "dehilight", {dehilight, 0} },
638 { "toggle_insert_mode", {toggle_insert_mode, 0} },
639 { "set", {set_var, NOSPLIT} },
640 //{ "get", {get_var, NOSPLIT} },
641 { "bind", {act_bind, NOSPLIT} },
642 { "dump_config", {act_dump_config, 0} },
643 { "keycmd", {keycmd, NOSPLIT} },
644 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
645 { "keycmd_bs", {keycmd_bs, 0} },
646 { "chain", {chain, 0} },
647 { "print", {print, NOSPLIT} }
654 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
656 for (i = 0; i < LENGTH(cmdlist); i++)
657 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
660 /* -- CORE FUNCTIONS -- */
663 free_action(gpointer act) {
664 Action *action = (Action*)act;
665 g_free(action->name);
667 g_free(action->param);
672 new_action(const gchar *name, const gchar *param) {
673 Action *action = g_new(Action, 1);
675 action->name = g_strdup(name);
677 action->param = g_strdup(param);
679 action->param = NULL;
685 file_exists (const char * filename) {
686 return (access(filename, F_OK) == 0);
690 set_var(WebKitWebView *page, GArray *argv) {
692 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
693 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
694 set_var_value(g_strstrip(split[0]), value);
700 print(WebKitWebView *page, GArray *argv) {
704 buf = expand_vars(argv_idx(argv, 0));
710 act_bind(WebKitWebView *page, GArray *argv) {
712 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
713 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
714 add_binding(g_strstrip(split[0]), value);
726 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
729 if (argv_idx(argv, 0)) {
730 if (strcmp (argv_idx(argv, 0), "0") == 0) {
731 uzbl.behave.insert_mode = FALSE;
733 uzbl.behave.insert_mode = TRUE;
736 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
743 load_uri (WebKitWebView *web_view, GArray *argv) {
744 if (argv_idx(argv, 0)) {
745 GString* newuri = g_string_new (argv_idx(argv, 0));
746 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
747 run_js(web_view, argv);
750 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
751 g_string_prepend (newuri, "http://");
752 /* if we do handle cookies, ask our handler for them */
753 webkit_web_view_load_uri (web_view, newuri->str);
754 g_string_free (newuri, TRUE);
759 run_js (WebKitWebView * web_view, GArray *argv) {
760 if (argv_idx(argv, 0))
761 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
765 run_external_js (WebKitWebView * web_view, GArray *argv) {
766 if (argv_idx(argv, 0)) {
767 GArray* lines = read_file_by_line (argv_idx (argv, 0));
772 while ((line = g_array_index(lines, gchar*, i))) {
774 js = g_strdup (line);
776 gchar* newjs = g_strconcat (js, line, NULL);
783 if (uzbl.state.verbose)
784 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
786 if (argv_idx (argv, 1)) {
787 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
791 webkit_web_view_execute_script (web_view, js);
793 g_array_free (lines, TRUE);
798 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
799 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
800 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
801 webkit_web_view_unmark_text_matches (page);
802 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
803 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
807 if (uzbl.state.searchtx) {
808 if (uzbl.state.verbose)
809 printf ("Searching: %s\n", uzbl.state.searchtx);
810 webkit_web_view_set_highlight_text_matches (page, TRUE);
811 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
816 search_forward_text (WebKitWebView *page, GArray *argv) {
817 search_text(page, argv, TRUE);
821 search_reverse_text (WebKitWebView *page, GArray *argv) {
822 search_text(page, argv, FALSE);
826 dehilight (WebKitWebView *page, GArray *argv) {
828 webkit_web_view_set_highlight_text_matches (page, FALSE);
833 new_window_load_uri (const gchar * uri) {
834 GString* to_execute = g_string_new ("");
835 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
837 for (i = 0; entries[i].long_name != NULL; i++) {
838 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
839 gchar** str = (gchar**)entries[i].arg_data;
841 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
845 if (uzbl.state.verbose)
846 printf("\n%s\n", to_execute->str);
847 g_spawn_command_line_async (to_execute->str, NULL);
848 g_string_free (to_execute, TRUE);
852 chain (WebKitWebView *page, GArray *argv) {
855 gchar **parts = NULL;
857 while ((a = argv_idx(argv, i++))) {
858 parts = g_strsplit (a, " ", 2);
859 parse_command(parts[0], parts[1]);
865 keycmd (WebKitWebView *page, GArray *argv) {
868 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
874 keycmd_nl (WebKitWebView *page, GArray *argv) {
877 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
883 keycmd_bs (WebKitWebView *page, GArray *argv) {
886 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
891 close_uzbl (WebKitWebView *page, GArray *argv) {
897 /* --Statusbar functions-- */
899 build_progressbar_ascii(int percent) {
900 int width=uzbl.gui.sbar.progress_w;
903 GString *bar = g_string_new("");
905 l = (double)percent*((double)width/100.);
906 l = (int)(l+.5)>=(int)l ? l+.5 : l;
908 for(i=0; i<(int)l; i++)
909 g_string_append(bar, uzbl.gui.sbar.progress_s);
912 g_string_append(bar, uzbl.gui.sbar.progress_u);
914 return g_string_free(bar, FALSE);
919 const GScannerConfig scan_config = {
922 ) /* cset_skip_characters */,
927 ) /* cset_identifier_first */,
934 ) /* cset_identifier_nth */,
935 ( "" ) /* cpair_comment_single */,
937 TRUE /* case_sensitive */,
939 FALSE /* skip_comment_multi */,
940 FALSE /* skip_comment_single */,
941 FALSE /* scan_comment_multi */,
942 TRUE /* scan_identifier */,
943 TRUE /* scan_identifier_1char */,
944 FALSE /* scan_identifier_NULL */,
945 TRUE /* scan_symbols */,
946 FALSE /* scan_binary */,
947 FALSE /* scan_octal */,
948 FALSE /* scan_float */,
949 FALSE /* scan_hex */,
950 FALSE /* scan_hex_dollar */,
951 FALSE /* scan_string_sq */,
952 FALSE /* scan_string_dq */,
953 TRUE /* numbers_2_int */,
954 FALSE /* int_2_float */,
955 FALSE /* identifier_2_string */,
956 FALSE /* char_2_token */,
957 FALSE /* symbol_2_token */,
958 TRUE /* scope_0_fallback */,
963 uzbl.scan = g_scanner_new(&scan_config);
964 while(symp->symbol_name) {
965 g_scanner_scope_add_symbol(uzbl.scan, 0,
967 GINT_TO_POINTER(symp->symbol_token));
973 expand_template(const char *template, gboolean escape_markup) {
974 if(!template) return NULL;
976 GTokenType token = G_TOKEN_NONE;
977 GString *ret = g_string_new("");
981 g_scanner_input_text(uzbl.scan, template, strlen(template));
982 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
983 token = g_scanner_get_next_token(uzbl.scan);
985 if(token == G_TOKEN_SYMBOL) {
986 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
990 buf = uzbl.state.uri?
991 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
992 g_string_append(ret, buf);
996 g_string_append(ret, uzbl.state.uri?
997 uzbl.state.uri:g_strdup(""));
1000 buf = itos(uzbl.gui.sbar.load_progress);
1001 g_string_append(ret, buf);
1004 case SYM_LOADPRGSBAR:
1005 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1006 g_string_append(ret, buf);
1011 buf = uzbl.gui.main_title?
1012 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1013 g_string_append(ret, buf);
1017 g_string_append(ret, uzbl.gui.main_title?
1018 uzbl.gui.main_title:g_strdup(""));
1020 case SYM_SELECTED_URI:
1022 buf = uzbl.state.selected_url?
1023 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1024 g_string_append(ret, buf);
1028 g_string_append(ret, uzbl.state.selected_url?
1029 uzbl.state.selected_url:g_strdup(""));
1032 buf = itos(uzbl.xwin);
1033 g_string_append(ret,
1034 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1039 buf = uzbl.state.keycmd->str?
1040 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1041 g_string_append(ret, buf);
1045 g_string_append(ret, uzbl.state.keycmd->str?
1046 uzbl.state.keycmd->str:g_strdup(""));
1049 g_string_append(ret,
1050 uzbl.behave.insert_mode?
1051 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1054 g_string_append(ret,
1055 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1057 /* useragent syms */
1059 buf = itos(WEBKIT_MAJOR_VERSION);
1060 g_string_append(ret, buf);
1064 buf = itos(WEBKIT_MINOR_VERSION);
1065 g_string_append(ret, buf);
1069 buf = itos(WEBKIT_MICRO_VERSION);
1070 g_string_append(ret, buf);
1074 g_string_append(ret, uzbl.state.unameinfo.sysname);
1077 g_string_append(ret, uzbl.state.unameinfo.nodename);
1080 g_string_append(ret, uzbl.state.unameinfo.release);
1083 g_string_append(ret, uzbl.state.unameinfo.version);
1086 g_string_append(ret, uzbl.state.unameinfo.machine);
1089 g_string_append(ret, ARCH);
1092 case SYM_DOMAINNAME:
1093 g_string_append(ret, uzbl.state.unameinfo.domainname);
1097 g_string_append(ret, COMMIT);
1103 else if(token == G_TOKEN_INT) {
1104 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1105 g_string_append(ret, buf);
1108 else if(token == G_TOKEN_IDENTIFIER) {
1109 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1111 else if(token == G_TOKEN_CHAR) {
1112 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1116 return g_string_free(ret, FALSE);
1118 /* --End Statusbar functions-- */
1121 sharg_append(GArray *a, const gchar *str) {
1122 const gchar *s = (str ? str : "");
1123 g_array_append_val(a, s);
1126 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1128 run_command (const gchar *command, const guint npre, const gchar **args,
1129 const gboolean sync, char **output_stdout) {
1130 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1133 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1134 gchar *pid = itos(getpid());
1135 gchar *xwin = itos(uzbl.xwin);
1137 sharg_append(a, command);
1138 for (i = 0; i < npre; i++) /* add n args before the default vars */
1139 sharg_append(a, args[i]);
1140 sharg_append(a, uzbl.state.config_file);
1141 sharg_append(a, pid);
1142 sharg_append(a, xwin);
1143 sharg_append(a, uzbl.comm.fifo_path);
1144 sharg_append(a, uzbl.comm.socket_path);
1145 sharg_append(a, uzbl.state.uri);
1146 sharg_append(a, uzbl.gui.main_title);
1148 for (i = npre; i < g_strv_length((gchar**)args); i++)
1149 sharg_append(a, args[i]);
1153 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1155 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1156 NULL, NULL, output_stdout, NULL, NULL, &err);
1157 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1158 NULL, NULL, NULL, &err);
1160 if (uzbl.state.verbose) {
1161 GString *s = g_string_new("spawned:");
1162 for (i = 0; i < (a->len); i++) {
1163 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1164 g_string_append_printf(s, " %s", qarg);
1167 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1168 printf("%s\n", s->str);
1169 g_string_free(s, TRUE);
1171 printf("Stdout: %s\n", *output_stdout);
1175 g_printerr("error on run_command: %s\n", err->message);
1180 g_array_free (a, TRUE);
1185 split_quoted(const gchar* src, const gboolean unquote) {
1186 /* split on unquoted space, return array of strings;
1187 remove a layer of quotes and backslashes if unquote */
1188 if (!src) return NULL;
1190 gboolean dq = FALSE;
1191 gboolean sq = FALSE;
1192 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1193 GString *s = g_string_new ("");
1197 for (p = src; *p != '\0'; p++) {
1198 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1199 else if (*p == '\\') { g_string_append_c(s, *p++);
1200 g_string_append_c(s, *p); }
1201 else if ((*p == '"') && unquote && !sq) dq = !dq;
1202 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1204 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1205 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1207 else if ((*p == ' ') && !dq && !sq) {
1208 dup = g_strdup(s->str);
1209 g_array_append_val(a, dup);
1210 g_string_truncate(s, 0);
1211 } else g_string_append_c(s, *p);
1213 dup = g_strdup(s->str);
1214 g_array_append_val(a, dup);
1215 ret = (gchar**)a->data;
1216 g_array_free (a, FALSE);
1217 g_string_free (s, TRUE);
1222 spawn(WebKitWebView *web_view, GArray *argv) {
1224 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1225 if (argv_idx(argv, 0))
1226 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1230 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1233 if (argv_idx(argv, 0))
1234 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1235 TRUE, &uzbl.comm.sync_stdout);
1239 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1241 if (!uzbl.behave.shell_cmd) {
1242 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1247 gchar *spacer = g_strdup("");
1248 g_array_insert_val(argv, 1, spacer);
1249 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1251 for (i = 1; i < g_strv_length(cmd); i++)
1252 g_array_prepend_val(argv, cmd[i]);
1254 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1260 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1262 if (!uzbl.behave.shell_cmd) {
1263 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1268 gchar *spacer = g_strdup("");
1269 g_array_insert_val(argv, 1, spacer);
1270 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1272 for (i = 1; i < g_strv_length(cmd); i++)
1273 g_array_prepend_val(argv, cmd[i]);
1275 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1276 TRUE, &uzbl.comm.sync_stdout);
1282 parse_command(const char *cmd, const char *param) {
1285 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1288 gchar **par = split_quoted(param, TRUE);
1289 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1291 if (c[1] == NOSPLIT) { /* don't split */
1292 sharg_append(a, param);
1294 for (i = 0; i < g_strv_length(par); i++)
1295 sharg_append(a, par[i]);
1297 c[0](uzbl.gui.web_view, a);
1299 g_array_free (a, TRUE);
1302 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1309 if(*uzbl.net.proxy_url == ' '
1310 || uzbl.net.proxy_url == NULL) {
1311 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1312 (GType) SOUP_SESSION_PROXY_URI);
1315 suri = soup_uri_new(uzbl.net.proxy_url);
1316 g_object_set(G_OBJECT(uzbl.net.soup_session),
1317 SOUP_SESSION_PROXY_URI,
1319 soup_uri_free(suri);
1326 if(file_exists(uzbl.gui.icon)) {
1327 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1329 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1331 g_free (uzbl.gui.icon);
1336 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1337 g_array_append_val (a, uzbl.state.uri);
1338 load_uri(uzbl.gui.web_view, a);
1339 g_array_free (a, TRUE);
1343 cmd_always_insert_mode() {
1344 uzbl.behave.insert_mode =
1345 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1351 g_object_set(G_OBJECT(uzbl.net.soup_session),
1352 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1356 cmd_max_conns_host() {
1357 g_object_set(G_OBJECT(uzbl.net.soup_session),
1358 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1363 soup_session_remove_feature
1364 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1365 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1366 /*g_free(uzbl.net.soup_logger);*/
1368 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1369 soup_session_add_feature(uzbl.net.soup_session,
1370 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1373 static WebKitWebSettings*
1375 return webkit_web_view_get_settings(uzbl.gui.web_view);
1380 WebKitWebSettings *ws = view_settings();
1381 if (uzbl.behave.font_size > 0) {
1382 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1385 if (uzbl.behave.monospace_size > 0) {
1386 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1387 uzbl.behave.monospace_size, NULL);
1389 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1390 uzbl.behave.font_size, NULL);
1396 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1400 cmd_disable_plugins() {
1401 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1402 !uzbl.behave.disable_plugins, NULL);
1406 cmd_disable_scripts() {
1407 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1408 !uzbl.behave.disable_scripts, NULL);
1412 cmd_minimum_font_size() {
1413 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1414 uzbl.behave.minimum_font_size, NULL);
1417 cmd_autoload_img() {
1418 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1419 uzbl.behave.autoload_img, NULL);
1424 cmd_autoshrink_img() {
1425 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1426 uzbl.behave.autoshrink_img, NULL);
1431 cmd_enable_spellcheck() {
1432 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1433 uzbl.behave.enable_spellcheck, NULL);
1437 cmd_enable_private() {
1438 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1439 uzbl.behave.enable_private, NULL);
1444 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1445 uzbl.behave.print_bg, NULL);
1450 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1451 uzbl.behave.style_uri, NULL);
1455 cmd_resizable_txt() {
1456 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1457 uzbl.behave.resizable_txt, NULL);
1461 cmd_default_encoding() {
1462 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1463 uzbl.behave.default_encoding, NULL);
1467 cmd_enforce_96dpi() {
1468 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1469 uzbl.behave.enforce_96dpi, NULL);
1473 cmd_caret_browsing() {
1474 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1475 uzbl.behave.caret_browsing, NULL);
1479 cmd_cookie_handler() {
1480 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1481 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1482 if ((g_strcmp0(split[0], "sh") == 0) ||
1483 (g_strcmp0(split[0], "spawn") == 0)) {
1484 g_free (uzbl.behave.cookie_handler);
1485 uzbl.behave.cookie_handler =
1486 g_strdup_printf("sync_%s %s", split[0], split[1]);
1493 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1498 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1503 if(uzbl.behave.inject_html) {
1504 webkit_web_view_load_html_string (uzbl.gui.web_view,
1505 uzbl.behave.inject_html, NULL);
1514 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1515 uzbl.behave.modmask = 0;
1517 if(uzbl.behave.modkey)
1518 g_free(uzbl.behave.modkey);
1519 uzbl.behave.modkey = buf;
1521 for (i = 0; modkeys[i].key != NULL; i++) {
1522 if (g_strrstr(buf, modkeys[i].key))
1523 uzbl.behave.modmask |= modkeys[i].mask;
1529 if (*uzbl.net.useragent == ' ') {
1530 g_free (uzbl.net.useragent);
1531 uzbl.net.useragent = NULL;
1533 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1535 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1536 g_free(uzbl.net.useragent);
1537 uzbl.net.useragent = ua;
1543 gtk_widget_ref(uzbl.gui.scrolled_win);
1544 gtk_widget_ref(uzbl.gui.mainbar);
1545 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1546 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1548 if(uzbl.behave.status_top) {
1549 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1550 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1553 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1554 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1556 gtk_widget_unref(uzbl.gui.scrolled_win);
1557 gtk_widget_unref(uzbl.gui.mainbar);
1558 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1563 set_var_value(gchar *name, gchar *val) {
1564 uzbl_cmdprop *c = NULL;
1568 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1569 /* check for the variable type */
1570 if (c->type == TYPE_STR) {
1571 buf = expand_vars(val);
1574 } else if(c->type == TYPE_INT) {
1575 int *ip = (int *)c->ptr;
1576 buf = expand_vars(val);
1577 *ip = (int)strtoul(buf, &endp, 10);
1579 } else if (c->type == TYPE_FLOAT) {
1580 float *fp = (float *)c->ptr;
1581 buf = expand_vars(val);
1582 *fp = strtod(buf, &endp);
1586 /* invoke a command specific function */
1587 if(c->func) c->func();
1594 Behaviour *b = &uzbl.behave;
1596 if(b->html_buffer->str) {
1597 webkit_web_view_load_html_string (uzbl.gui.web_view,
1598 b->html_buffer->str, b->base_url);
1599 g_string_free(b->html_buffer, TRUE);
1600 b->html_buffer = g_string_new("");
1604 enum {M_CMD, M_HTML};
1606 parse_cmd_line(const char *ctl_line) {
1607 Behaviour *b = &uzbl.behave;
1610 if(b->mode == M_HTML) {
1611 len = strlen(b->html_endmarker);
1612 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1613 if(len == strlen(ctl_line)-1 &&
1614 !strncmp(b->html_endmarker, ctl_line, len)) {
1616 set_var_value("mode", "0");
1621 set_timeout(b->html_timeout);
1622 g_string_append(b->html_buffer, ctl_line);
1625 else if((ctl_line[0] == '#') /* Comments */
1626 || (ctl_line[0] == ' ')
1627 || (ctl_line[0] == '\n'))
1628 ; /* ignore these lines */
1629 else { /* parse a command */
1631 gchar **tokens = NULL;
1632 len = strlen(ctl_line);
1634 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1635 ctlstrip = g_strndup(ctl_line, len - 1);
1636 else ctlstrip = g_strdup(ctl_line);
1638 tokens = g_strsplit(ctlstrip, " ", 2);
1639 parse_command(tokens[0], tokens[1]);
1646 build_stream_name(int type, const gchar* dir) {
1648 State *s = &uzbl.state;
1651 xwin_str = itos((int)uzbl.xwin);
1653 str = g_strdup_printf
1654 ("%s/uzbl_fifo_%s", dir,
1655 s->instance_name ? s->instance_name : xwin_str);
1656 } else if (type == SOCKET) {
1657 str = g_strdup_printf
1658 ("%s/uzbl_socket_%s", dir,
1659 s->instance_name ? s->instance_name : xwin_str );
1666 control_fifo(GIOChannel *gio, GIOCondition condition) {
1667 if (uzbl.state.verbose)
1668 printf("triggered\n");
1673 if (condition & G_IO_HUP)
1674 g_error ("Fifo: Read end of pipe died!\n");
1677 g_error ("Fifo: GIOChannel broke\n");
1679 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1680 if (ret == G_IO_STATUS_ERROR) {
1681 g_error ("Fifo: Error reading: %s\n", err->message);
1685 parse_cmd_line(ctl_line);
1692 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1693 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1694 if (unlink(uzbl.comm.fifo_path) == -1)
1695 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1696 g_free(uzbl.comm.fifo_path);
1697 uzbl.comm.fifo_path = NULL;
1700 if (*dir == ' ') { /* space unsets the variable */
1705 GIOChannel *chan = NULL;
1706 GError *error = NULL;
1707 gchar *path = build_stream_name(FIFO, dir);
1709 if (!file_exists(path)) {
1710 if (mkfifo (path, 0666) == 0) {
1711 // 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.
1712 chan = g_io_channel_new_file(path, "r+", &error);
1714 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1715 if (uzbl.state.verbose)
1716 printf ("init_fifo: created successfully as %s\n", path);
1717 uzbl.comm.fifo_path = path;
1719 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1720 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1721 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1722 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1724 /* if we got this far, there was an error; cleanup */
1725 if (error) g_error_free (error);
1732 control_stdin(GIOChannel *gio, GIOCondition condition) {
1734 gchar *ctl_line = NULL;
1737 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1738 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1741 parse_cmd_line(ctl_line);
1749 GIOChannel *chan = NULL;
1750 GError *error = NULL;
1752 chan = g_io_channel_unix_new(fileno(stdin));
1754 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1755 g_error ("Stdin: could not add watch\n");
1757 if (uzbl.state.verbose)
1758 printf ("Stdin: watch added successfully\n");
1761 g_error ("Stdin: Error while opening: %s\n", error->message);
1763 if (error) g_error_free (error);
1767 control_socket(GIOChannel *chan) {
1768 struct sockaddr_un remote;
1769 char buffer[512], *ctl_line;
1771 int sock, clientsock, n, done;
1774 sock = g_io_channel_unix_get_fd(chan);
1776 memset (buffer, 0, sizeof (buffer));
1778 t = sizeof (remote);
1779 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1783 memset (temp, 0, sizeof (temp));
1784 n = recv (clientsock, temp, 128, 0);
1786 buffer[strlen (buffer)] = '\0';
1790 strcat (buffer, temp);
1793 if (strcmp (buffer, "\n") < 0) {
1794 buffer[strlen (buffer) - 1] = '\0';
1796 buffer[strlen (buffer)] = '\0';
1799 ctl_line = g_strdup(buffer);
1800 parse_cmd_line (ctl_line);
1803 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1804 GError *error = NULL;
1807 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1808 if (ret == G_IO_STATUS_ERROR)
1809 g_error ("Error reading: %s\n", error->message);
1811 printf("Got line %s (%u bytes) \n",ctl_line, len);
1813 parse_line(ctl_line);
1821 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1822 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1823 if (unlink(uzbl.comm.socket_path) == -1)
1824 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1825 g_free(uzbl.comm.socket_path);
1826 uzbl.comm.socket_path = NULL;
1834 GIOChannel *chan = NULL;
1836 struct sockaddr_un local;
1837 gchar *path = build_stream_name(SOCKET, dir);
1839 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1841 local.sun_family = AF_UNIX;
1842 strcpy (local.sun_path, path);
1843 unlink (local.sun_path);
1845 len = strlen (local.sun_path) + sizeof (local.sun_family);
1846 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1847 if (uzbl.state.verbose)
1848 printf ("init_socket: opened in %s\n", path);
1851 if( (chan = g_io_channel_unix_new(sock)) ) {
1852 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1853 uzbl.comm.socket_path = path;
1856 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1858 /* if we got this far, there was an error; cleanup */
1865 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1866 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1868 // this function may be called very early when the templates are not set (yet), hence the checks
1870 update_title (void) {
1871 Behaviour *b = &uzbl.behave;
1874 if (b->show_status) {
1875 if (b->title_format_short) {
1876 parsed = expand_template(b->title_format_short, FALSE);
1877 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1880 if (b->status_format) {
1881 parsed = expand_template(b->status_format, TRUE);
1882 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1885 if (b->status_background) {
1887 gdk_color_parse (b->status_background, &color);
1888 //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)
1889 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1892 if (b->title_format_long) {
1893 parsed = expand_template(b->title_format_long, FALSE);
1894 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1901 key_press_cb (GtkWidget* window, GdkEventKey* event)
1903 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1907 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1908 || 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)
1911 /* turn off insert mode (if always_insert_mode is not used) */
1912 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1913 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1918 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1921 if (event->keyval == GDK_Escape) {
1922 g_string_truncate(uzbl.state.keycmd, 0);
1924 dehilight(uzbl.gui.web_view, NULL);
1928 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1929 if (event->keyval == GDK_Insert) {
1931 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1932 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1934 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1937 g_string_append (uzbl.state.keycmd, str);
1944 if (event->keyval == GDK_BackSpace)
1945 keycmd_bs(NULL, NULL);
1947 gboolean key_ret = FALSE;
1948 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1950 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1952 run_keycmd(key_ret);
1954 if (key_ret) return (!uzbl.behave.insert_mode);
1959 run_keycmd(const gboolean key_ret) {
1960 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1962 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1963 g_string_truncate(uzbl.state.keycmd, 0);
1964 parse_command(act->name, act->param);
1968 /* try if it's an incremental keycmd or one that takes args, and run it */
1969 GString* short_keys = g_string_new ("");
1970 GString* short_keys_inc = g_string_new ("");
1972 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1973 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1974 g_string_assign(short_keys_inc, short_keys->str);
1975 g_string_append_c(short_keys, '_');
1976 g_string_append_c(short_keys_inc, '*');
1978 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1979 /* run normal cmds only if return was pressed */
1980 exec_paramcmd(act, i);
1981 g_string_truncate(uzbl.state.keycmd, 0);
1983 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1984 if (key_ret) /* just quit the incremental command on return */
1985 g_string_truncate(uzbl.state.keycmd, 0);
1986 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1990 g_string_truncate(short_keys, short_keys->len - 1);
1992 g_string_free (short_keys, TRUE);
1993 g_string_free (short_keys_inc, TRUE);
1997 exec_paramcmd(const Action *act, const guint i) {
1998 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1999 GString *actionname = g_string_new ("");
2000 GString *actionparam = g_string_new ("");
2001 g_string_erase (parampart, 0, i+1);
2003 g_string_printf (actionname, act->name, parampart->str);
2005 g_string_printf (actionparam, act->param, parampart->str);
2006 parse_command(actionname->str, actionparam->str);
2007 g_string_free(actionname, TRUE);
2008 g_string_free(actionparam, TRUE);
2009 g_string_free(parampart, TRUE);
2017 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2018 //main_window_ref = g_object_ref(scrolled_window);
2019 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
2021 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2022 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2024 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2025 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2026 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2027 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2028 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2029 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2030 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2033 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2036 return scrolled_window;
2043 g->mainbar = gtk_hbox_new (FALSE, 0);
2045 /* keep a reference to the bar so we can re-pack it at runtime*/
2046 //sbar_ref = g_object_ref(g->mainbar);
2048 g->mainbar_label = gtk_label_new ("");
2049 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2050 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2051 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2052 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2053 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2054 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2059 GtkWidget* create_window () {
2060 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2061 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2062 gtk_widget_set_name (window, "Uzbl browser");
2063 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2064 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2070 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2072 If actname is one that calls an external command, this function will inject
2073 newargs in front of the user-provided args in that command line. They will
2074 come become after the body of the script (in sh) or after the name of
2075 the command to execute (in spawn).
2076 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2077 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2079 The return value consist of two strings: the action (sh, ...) and its args.
2081 If act is not one that calls an external command, then the given action merely
2084 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2085 gchar *actdup = g_strdup(actname);
2086 g_array_append_val(rets, actdup);
2088 if ((g_strcmp0(actname, "spawn") == 0) ||
2089 (g_strcmp0(actname, "sh") == 0) ||
2090 (g_strcmp0(actname, "sync_spawn") == 0) ||
2091 (g_strcmp0(actname, "sync_sh") == 0)) {
2093 GString *a = g_string_new("");
2094 gchar **spawnparts = split_quoted(origargs, FALSE);
2095 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2096 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2098 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2099 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2101 g_array_append_val(rets, a->str);
2102 g_string_free(a, FALSE);
2103 g_strfreev(spawnparts);
2105 gchar *origdup = g_strdup(origargs);
2106 g_array_append_val(rets, origdup);
2108 return (gchar**)g_array_free(rets, FALSE);
2112 run_handler (const gchar *act, const gchar *args) {
2113 /* Consider this code a temporary hack to make the handlers usable.
2114 In practice, all this splicing, injection, and reconstruction is
2115 inefficient, annoying and hard to manage. Potential pitfalls arise
2116 when the handler specific args 1) are not quoted (the handler
2117 callbacks should take care of this) 2) are quoted but interfere
2118 with the users' own quotation. A more ideal solution is
2119 to refactor parse_command so that it doesn't just take a string
2120 and execute it; rather than that, we should have a function which
2121 returns the argument vector parsed from the string. This vector
2122 could be modified (e.g. insert additional args into it) before
2123 passing it to the next function that actually executes it. Though
2124 it still isn't perfect for chain actions.. will reconsider & re-
2125 factor when I have the time. -duc */
2127 char **parts = g_strsplit(act, " ", 2);
2129 if (g_strcmp0(parts[0], "chain") == 0) {
2130 GString *newargs = g_string_new("");
2131 gchar **chainparts = split_quoted(parts[1], FALSE);
2133 /* for every argument in the chain, inject the handler args
2134 and make sure the new parts are wrapped in quotes */
2135 gchar **cp = chainparts;
2137 gchar *quotless = NULL;
2138 gchar **spliced_quotless = NULL; // sigh -_-;
2139 gchar **inpart = NULL;
2142 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2144 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2145 } else quotless = g_strdup(*cp);
2147 spliced_quotless = g_strsplit(quotless, " ", 2);
2148 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2149 g_strfreev(spliced_quotless);
2151 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2157 parse_command(parts[0], &(newargs->str[1]));
2158 g_string_free(newargs, TRUE);
2159 g_strfreev(chainparts);
2162 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2163 parse_command(inparts[0], inparts[1]);
2171 add_binding (const gchar *key, const gchar *act) {
2172 char **parts = g_strsplit(act, " ", 2);
2179 if (uzbl.state.verbose)
2180 printf ("Binding %-10s : %s\n", key, act);
2181 action = new_action(parts[0], parts[1]);
2183 if (g_hash_table_remove (uzbl.bindings, key))
2184 g_warning ("Overwriting existing binding for \"%s\"", key);
2185 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2190 get_xdg_var (XDG_Var xdg) {
2191 const gchar* actual_value = getenv (xdg.environmental);
2192 const gchar* home = getenv ("HOME");
2193 gchar* return_value;
2195 if (! actual_value || strcmp (actual_value, "") == 0) {
2196 if (xdg.default_value) {
2197 return_value = str_replace ("~", home, xdg.default_value);
2199 return_value = NULL;
2202 return_value = str_replace("~", home, actual_value);
2205 return return_value;
2209 find_xdg_file (int xdg_type, char* filename) {
2210 /* xdg_type = 0 => config
2211 xdg_type = 1 => data
2212 xdg_type = 2 => cache*/
2214 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2215 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2218 gchar* temporary_string;
2222 if (! file_exists (temporary_file) && xdg_type != 2) {
2223 buf = get_xdg_var (XDG[3 + xdg_type]);
2224 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2227 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2228 g_free (temporary_file);
2229 temporary_file = g_strconcat (temporary_string, filename, NULL);
2233 //g_free (temporary_string); - segfaults.
2235 if (file_exists (temporary_file)) {
2236 return temporary_file;
2243 State *s = &uzbl.state;
2244 Network *n = &uzbl.net;
2246 for (i = 0; default_config[i].command != NULL; i++) {
2247 parse_cmd_line(default_config[i].command);
2250 if (!s->config_file) {
2251 s->config_file = find_xdg_file (0, "/uzbl/config");
2254 if (s->config_file) {
2255 GArray* lines = read_file_by_line (s->config_file);
2259 while ((line = g_array_index(lines, gchar*, i))) {
2260 parse_cmd_line (line);
2264 g_array_free (lines, TRUE);
2266 if (uzbl.state.verbose)
2267 printf ("No configuration file loaded.\n");
2270 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2273 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2276 if (!uzbl.behave.cookie_handler)
2279 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2280 GString *s = g_string_new ("");
2281 SoupURI * soup_uri = soup_message_get_uri(msg);
2282 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2283 run_handler(uzbl.behave.cookie_handler, s->str);
2285 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2286 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2287 if ( p != NULL ) *p = '\0';
2288 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2290 if (uzbl.comm.sync_stdout)
2291 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2293 g_string_free(s, TRUE);
2297 save_cookies (SoupMessage *msg, gpointer user_data){
2301 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2302 cookie = soup_cookie_to_set_cookie_header(ck->data);
2303 SoupURI * soup_uri = soup_message_get_uri(msg);
2304 GString *s = g_string_new ("");
2305 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2306 run_handler(uzbl.behave.cookie_handler, s->str);
2308 g_string_free(s, TRUE);
2313 /* --- WEBINSPECTOR --- */
2315 hide_window_cb(GtkWidget *widget, gpointer data) {
2318 gtk_widget_hide(widget);
2321 static WebKitWebView*
2322 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2325 (void) web_inspector;
2326 GtkWidget* scrolled_window;
2327 GtkWidget* new_web_view;
2330 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2331 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2332 G_CALLBACK(hide_window_cb), NULL);
2334 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2335 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2336 gtk_widget_show(g->inspector_window);
2338 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2339 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2340 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2341 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2342 gtk_widget_show(scrolled_window);
2344 new_web_view = webkit_web_view_new();
2345 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2347 return WEBKIT_WEB_VIEW(new_web_view);
2351 inspector_show_window_cb (WebKitWebInspector* inspector){
2353 gtk_widget_show(uzbl.gui.inspector_window);
2357 /* TODO: Add variables and code to make use of these functions */
2359 inspector_close_window_cb (WebKitWebInspector* inspector){
2365 inspector_attach_window_cb (WebKitWebInspector* inspector){
2371 inspector_detach_window_cb (WebKitWebInspector* inspector){
2377 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2383 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2389 set_up_inspector() {
2391 WebKitWebSettings *settings = view_settings();
2392 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2394 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2395 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2396 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2397 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2398 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2399 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2400 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2402 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2406 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2408 uzbl_cmdprop *c = v;
2413 if(c->type == TYPE_STR)
2414 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2415 else if(c->type == TYPE_INT)
2416 printf("set %s = %d\n", (char *)k, (int)*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: */