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 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
118 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
119 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
120 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
121 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
122 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
123 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
124 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
125 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
126 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
127 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
128 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
129 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
130 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
131 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
132 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
133 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
134 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
135 /* exported WebKitWebSettings properties */
136 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
137 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
138 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
139 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
140 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
141 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
142 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
143 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
144 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
145 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
146 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
147 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
148 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
149 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
150 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
151 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
153 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
154 }, *n2v_p = var_name_to_ptr;
160 { "SHIFT", GDK_SHIFT_MASK }, // shift
161 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
162 { "CONTROL", GDK_CONTROL_MASK }, // control
163 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
164 { "MOD2", GDK_MOD2_MASK }, // 5th mod
165 { "MOD3", GDK_MOD3_MASK }, // 6th mod
166 { "MOD4", GDK_MOD4_MASK }, // 7th mod
167 { "MOD5", GDK_MOD5_MASK }, // 8th mod
168 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
169 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
170 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
171 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
172 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
173 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
174 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
175 { "META", GDK_META_MASK }, // meta (since 2.10)
180 /* construct a hash from the var_name_to_ptr array for quick access */
182 make_var_to_name_hash() {
183 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
185 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
190 /* --- UTILITY FUNCTIONS --- */
192 expand_vars(char *s) {
195 char ret[256], *vend;
196 GString *buf = g_string_new("");
201 g_string_append_c(buf, *++s);
209 if( (vend = strchr(s, upto)) ||
210 (vend = strchr(s, '\0')) ) {
211 strncpy(ret, s, vend-s);
213 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
214 if(c->type == TYPE_STR)
215 g_string_append(buf, (gchar *)*c->ptr);
216 else if(c->type == TYPE_INT) {
217 char *b = itos((int)*c->ptr);
218 g_string_append(buf, b);
222 if(upto == ' ') s = vend;
228 g_string_append_c(buf, *s);
233 return g_string_free(buf, FALSE);
240 snprintf(tmp, sizeof(tmp), "%i", val);
241 return g_strdup(tmp);
245 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
248 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
251 str_replace (const char* search, const char* replace, const char* string) {
255 buf = g_strsplit (string, search, -1);
256 ret = g_strjoinv (replace, buf);
257 g_strfreev(buf); // somebody said this segfaults
263 read_file_by_line (gchar *path) {
264 GIOChannel *chan = NULL;
265 gchar *readbuf = NULL;
267 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
270 chan = g_io_channel_new_file(path, "r", NULL);
273 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
274 const gchar* val = g_strdup (readbuf);
275 g_array_append_val (lines, val);
280 g_io_channel_unref (chan);
282 fprintf(stderr, "File '%s' not be read.\n", path);
289 gchar* parseenv (char* string) {
290 extern char** environ;
291 gchar* tmpstr = NULL;
295 while (environ[i] != NULL) {
296 gchar** env = g_strsplit (environ[i], "=", 2);
297 gchar* envname = g_strconcat ("$", env[0], NULL);
299 if (g_strrstr (string, envname) != NULL) {
300 tmpstr = g_strdup(string);
302 string = str_replace(envname, env[1], tmpstr);
307 g_strfreev (env); // somebody said this breaks uzbl
315 setup_signal(int signr, sigfunc *shandler) {
316 struct sigaction nh, oh;
318 nh.sa_handler = shandler;
319 sigemptyset(&nh.sa_mask);
322 if(sigaction(signr, &nh, &oh) < 0)
330 if (uzbl.behave.fifo_dir)
331 unlink (uzbl.comm.fifo_path);
332 if (uzbl.behave.socket_dir)
333 unlink (uzbl.comm.socket_path);
335 g_free(uzbl.state.executable_path);
336 g_string_free(uzbl.state.keycmd, TRUE);
337 g_hash_table_destroy(uzbl.bindings);
338 g_hash_table_destroy(uzbl.behave.commands);
341 /* used for html_mode_timeout
342 * be sure to extend this function to use
343 * more timers if needed in other places
346 set_timeout(int seconds) {
348 memset(&t, 0, sizeof t);
350 t.it_value.tv_sec = seconds;
351 t.it_value.tv_usec = 0;
352 setitimer(ITIMER_REAL, &t, NULL);
355 /* --- SIGNAL HANDLER --- */
358 catch_sigterm(int s) {
364 catch_sigint(int s) {
374 set_var_value("mode", "0");
379 /* --- CALLBACKS --- */
382 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
385 (void) navigation_action;
386 (void) policy_decision;
388 const gchar* uri = webkit_network_request_get_uri (request);
389 if (uzbl.state.verbose)
390 printf("New window requested -> %s \n", uri);
391 new_window_load_uri(uri);
396 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
401 /* If we can display it, let's display it... */
402 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
403 webkit_web_policy_decision_use (policy_decision);
407 /* ...everything we can't displayed is downloaded */
408 webkit_web_policy_decision_download (policy_decision);
413 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
417 if (uzbl.state.selected_url != NULL) {
418 if (uzbl.state.verbose)
419 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
420 new_window_load_uri(uzbl.state.selected_url);
422 if (uzbl.state.verbose)
423 printf("New web view -> %s\n","Nothing to open, exiting");
429 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
432 if (uzbl.behave.download_handler) {
433 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
434 if (uzbl.state.verbose)
435 printf("Download -> %s\n",uri);
436 /* if urls not escaped, we may have to escape and quote uri before this call */
437 run_handler(uzbl.behave.download_handler, uri);
442 /* scroll a bar in a given direction */
444 scroll (GtkAdjustment* bar, GArray *argv) {
448 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
449 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
450 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
454 scroll_begin(WebKitWebView* page, GArray *argv) {
455 (void) page; (void) argv;
456 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
460 scroll_end(WebKitWebView* page, GArray *argv) {
461 (void) page; (void) argv;
462 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
463 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
467 scroll_vert(WebKitWebView* page, GArray *argv) {
469 scroll(uzbl.gui.bar_v, argv);
473 scroll_horz(WebKitWebView* page, GArray *argv) {
475 scroll(uzbl.gui.bar_h, argv);
480 if (!uzbl.behave.show_status) {
481 gtk_widget_hide(uzbl.gui.mainbar);
483 gtk_widget_show(uzbl.gui.mainbar);
489 toggle_status_cb (WebKitWebView* page, GArray *argv) {
493 if (uzbl.behave.show_status) {
494 gtk_widget_hide(uzbl.gui.mainbar);
496 gtk_widget_show(uzbl.gui.mainbar);
498 uzbl.behave.show_status = !uzbl.behave.show_status;
503 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
507 //Set selected_url state variable
508 g_free(uzbl.state.selected_url);
509 uzbl.state.selected_url = NULL;
511 uzbl.state.selected_url = g_strdup(link);
517 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
521 if (uzbl.gui.main_title)
522 g_free (uzbl.gui.main_title);
523 uzbl.gui.main_title = g_strdup (title);
528 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
531 uzbl.gui.sbar.load_progress = progress;
536 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
540 if (uzbl.behave.load_finish_handler)
541 run_handler(uzbl.behave.load_finish_handler, "");
545 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
549 uzbl.gui.sbar.load_progress = 0;
550 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
551 if (uzbl.behave.load_start_handler)
552 run_handler(uzbl.behave.load_start_handler, "");
556 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
559 g_free (uzbl.state.uri);
560 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
561 uzbl.state.uri = g_string_free (newuri, FALSE);
562 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
563 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
566 if (uzbl.behave.load_commit_handler)
567 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
571 destroy_cb (GtkWidget* widget, gpointer data) {
579 if (uzbl.behave.history_handler) {
581 struct tm * timeinfo;
584 timeinfo = localtime ( &rawtime );
585 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
586 run_handler(uzbl.behave.history_handler, date);
591 /* VIEW funcs (little webkit wrappers) */
592 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
594 VIEWFUNC(reload_bypass_cache)
595 VIEWFUNC(stop_loading)
602 /* -- command to callback/function map for things we cannot attach to any signals */
603 static struct {char *name; Command command[2];} cmdlist[] =
604 { /* key function no_split */
605 { "back", {view_go_back, 0} },
606 { "forward", {view_go_forward, 0} },
607 { "scroll_vert", {scroll_vert, 0} },
608 { "scroll_horz", {scroll_horz, 0} },
609 { "scroll_begin", {scroll_begin, 0} },
610 { "scroll_end", {scroll_end, 0} },
611 { "reload", {view_reload, 0}, },
612 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
613 { "stop", {view_stop_loading, 0}, },
614 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
615 { "zoom_out", {view_zoom_out, 0}, },
616 { "uri", {load_uri, NOSPLIT} },
617 { "js", {run_js, NOSPLIT} },
618 { "script", {run_external_js, 0} },
619 { "toggle_status", {toggle_status_cb, 0} },
620 { "spawn", {spawn, 0} },
621 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
622 { "sh", {spawn_sh, 0} },
623 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
624 { "exit", {close_uzbl, 0} },
625 { "search", {search_forward_text, NOSPLIT} },
626 { "search_reverse", {search_reverse_text, NOSPLIT} },
627 { "dehilight", {dehilight, 0} },
628 { "toggle_insert_mode", {toggle_insert_mode, 0} },
629 { "set", {set_var, NOSPLIT} },
630 //{ "get", {get_var, NOSPLIT} },
631 { "bind", {act_bind, NOSPLIT} },
632 { "dump_config", {act_dump_config, 0} },
633 { "keycmd", {keycmd, NOSPLIT} },
634 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
635 { "keycmd_bs", {keycmd_bs, 0} },
636 { "chain", {chain, 0} },
637 { "print", {print, NOSPLIT} }
644 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
646 for (i = 0; i < LENGTH(cmdlist); i++)
647 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
650 /* -- CORE FUNCTIONS -- */
653 free_action(gpointer act) {
654 Action *action = (Action*)act;
655 g_free(action->name);
657 g_free(action->param);
662 new_action(const gchar *name, const gchar *param) {
663 Action *action = g_new(Action, 1);
665 action->name = g_strdup(name);
667 action->param = g_strdup(param);
669 action->param = NULL;
675 file_exists (const char * filename) {
676 return (access(filename, F_OK) == 0);
680 set_var(WebKitWebView *page, GArray *argv) {
682 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
683 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
684 set_var_value(g_strstrip(split[0]), value);
690 print(WebKitWebView *page, GArray *argv) {
694 buf = expand_vars(argv_idx(argv, 0));
700 act_bind(WebKitWebView *page, GArray *argv) {
702 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
703 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
704 add_binding(g_strstrip(split[0]), value);
716 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
719 if (argv_idx(argv, 0)) {
720 if (strcmp (argv_idx(argv, 0), "0") == 0) {
721 uzbl.behave.insert_mode = FALSE;
723 uzbl.behave.insert_mode = TRUE;
726 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
733 load_uri (WebKitWebView *web_view, GArray *argv) {
734 if (argv_idx(argv, 0)) {
735 GString* newuri = g_string_new (argv_idx(argv, 0));
736 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
737 run_js(web_view, argv);
740 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
741 g_string_prepend (newuri, "http://");
742 /* if we do handle cookies, ask our handler for them */
743 webkit_web_view_load_uri (web_view, newuri->str);
744 g_string_free (newuri, TRUE);
749 run_js (WebKitWebView * web_view, GArray *argv) {
750 if (argv_idx(argv, 0))
751 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
755 run_external_js (WebKitWebView * web_view, GArray *argv) {
756 if (argv_idx(argv, 0)) {
757 GArray* lines = read_file_by_line (argv_idx (argv, 0));
762 while ((line = g_array_index(lines, gchar*, i))) {
764 js = g_strdup (line);
766 gchar* newjs = g_strconcat (js, line, NULL);
773 if (uzbl.state.verbose)
774 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
776 if (argv_idx (argv, 1)) {
777 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
781 webkit_web_view_execute_script (web_view, js);
783 g_array_free (lines, TRUE);
788 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
789 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
790 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
791 webkit_web_view_unmark_text_matches (page);
792 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
793 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
797 if (uzbl.state.searchtx) {
798 if (uzbl.state.verbose)
799 printf ("Searching: %s\n", uzbl.state.searchtx);
800 webkit_web_view_set_highlight_text_matches (page, TRUE);
801 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
806 search_forward_text (WebKitWebView *page, GArray *argv) {
807 search_text(page, argv, TRUE);
811 search_reverse_text (WebKitWebView *page, GArray *argv) {
812 search_text(page, argv, FALSE);
816 dehilight (WebKitWebView *page, GArray *argv) {
818 webkit_web_view_set_highlight_text_matches (page, FALSE);
823 new_window_load_uri (const gchar * uri) {
824 GString* to_execute = g_string_new ("");
825 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
827 for (i = 0; entries[i].long_name != NULL; i++) {
828 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
829 gchar** str = (gchar**)entries[i].arg_data;
831 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
835 if (uzbl.state.verbose)
836 printf("\n%s\n", to_execute->str);
837 g_spawn_command_line_async (to_execute->str, NULL);
838 g_string_free (to_execute, TRUE);
842 chain (WebKitWebView *page, GArray *argv) {
845 gchar **parts = NULL;
847 while ((a = argv_idx(argv, i++))) {
848 parts = g_strsplit (a, " ", 2);
849 parse_command(parts[0], parts[1]);
855 keycmd (WebKitWebView *page, GArray *argv) {
858 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
864 keycmd_nl (WebKitWebView *page, GArray *argv) {
867 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
873 keycmd_bs (WebKitWebView *page, GArray *argv) {
876 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
881 close_uzbl (WebKitWebView *page, GArray *argv) {
887 /* --Statusbar functions-- */
889 build_progressbar_ascii(int percent) {
890 int width=uzbl.gui.sbar.progress_w;
893 GString *bar = g_string_new("");
895 l = (double)percent*((double)width/100.);
896 l = (int)(l+.5)>=(int)l ? l+.5 : l;
898 for(i=0; i<(int)l; i++)
899 g_string_append(bar, uzbl.gui.sbar.progress_s);
902 g_string_append(bar, uzbl.gui.sbar.progress_u);
904 return g_string_free(bar, FALSE);
909 const GScannerConfig scan_config = {
912 ) /* cset_skip_characters */,
917 ) /* cset_identifier_first */,
924 ) /* cset_identifier_nth */,
925 ( "" ) /* cpair_comment_single */,
927 TRUE /* case_sensitive */,
929 FALSE /* skip_comment_multi */,
930 FALSE /* skip_comment_single */,
931 FALSE /* scan_comment_multi */,
932 TRUE /* scan_identifier */,
933 TRUE /* scan_identifier_1char */,
934 FALSE /* scan_identifier_NULL */,
935 TRUE /* scan_symbols */,
936 FALSE /* scan_binary */,
937 FALSE /* scan_octal */,
938 FALSE /* scan_float */,
939 FALSE /* scan_hex */,
940 FALSE /* scan_hex_dollar */,
941 FALSE /* scan_string_sq */,
942 FALSE /* scan_string_dq */,
943 TRUE /* numbers_2_int */,
944 FALSE /* int_2_float */,
945 FALSE /* identifier_2_string */,
946 FALSE /* char_2_token */,
947 FALSE /* symbol_2_token */,
948 TRUE /* scope_0_fallback */,
953 uzbl.scan = g_scanner_new(&scan_config);
954 while(symp->symbol_name) {
955 g_scanner_scope_add_symbol(uzbl.scan, 0,
957 GINT_TO_POINTER(symp->symbol_token));
963 expand_template(const char *template, gboolean escape_markup) {
964 if(!template) return NULL;
966 GTokenType token = G_TOKEN_NONE;
967 GString *ret = g_string_new("");
971 g_scanner_input_text(uzbl.scan, template, strlen(template));
972 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
973 token = g_scanner_get_next_token(uzbl.scan);
975 if(token == G_TOKEN_SYMBOL) {
976 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
980 buf = uzbl.state.uri?
981 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
982 g_string_append(ret, buf);
986 g_string_append(ret, uzbl.state.uri?
987 uzbl.state.uri:g_strdup(""));
990 buf = itos(uzbl.gui.sbar.load_progress);
991 g_string_append(ret, buf);
994 case SYM_LOADPRGSBAR:
995 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
996 g_string_append(ret, buf);
1001 buf = uzbl.gui.main_title?
1002 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1003 g_string_append(ret, buf);
1007 g_string_append(ret, uzbl.gui.main_title?
1008 uzbl.gui.main_title:g_strdup(""));
1010 case SYM_SELECTED_URI:
1012 buf = uzbl.state.selected_url?
1013 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1014 g_string_append(ret, buf);
1018 g_string_append(ret, uzbl.state.selected_url?
1019 uzbl.state.selected_url:g_strdup(""));
1022 buf = itos(uzbl.xwin);
1023 g_string_append(ret,
1024 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1029 buf = uzbl.state.keycmd->str?
1030 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1031 g_string_append(ret, buf);
1035 g_string_append(ret, uzbl.state.keycmd->str?
1036 uzbl.state.keycmd->str:g_strdup(""));
1039 g_string_append(ret,
1040 uzbl.behave.insert_mode?
1041 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1044 g_string_append(ret,
1045 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1047 /* useragent syms */
1049 buf = itos(WEBKIT_MAJOR_VERSION);
1050 g_string_append(ret, buf);
1054 buf = itos(WEBKIT_MINOR_VERSION);
1055 g_string_append(ret, buf);
1059 buf = itos(WEBKIT_MICRO_VERSION);
1060 g_string_append(ret, buf);
1064 g_string_append(ret, uzbl.state.unameinfo.sysname);
1067 g_string_append(ret, uzbl.state.unameinfo.nodename);
1070 g_string_append(ret, uzbl.state.unameinfo.release);
1073 g_string_append(ret, uzbl.state.unameinfo.version);
1076 g_string_append(ret, uzbl.state.unameinfo.machine);
1079 g_string_append(ret, ARCH);
1082 case SYM_DOMAINNAME:
1083 g_string_append(ret, uzbl.state.unameinfo.domainname);
1087 g_string_append(ret, COMMIT);
1093 else if(token == G_TOKEN_INT) {
1094 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1095 g_string_append(ret, buf);
1098 else if(token == G_TOKEN_IDENTIFIER) {
1099 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1101 else if(token == G_TOKEN_CHAR) {
1102 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1106 return g_string_free(ret, FALSE);
1108 /* --End Statusbar functions-- */
1111 sharg_append(GArray *a, const gchar *str) {
1112 const gchar *s = (str ? str : "");
1113 g_array_append_val(a, s);
1116 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1118 run_command (const gchar *command, const guint npre, const gchar **args,
1119 const gboolean sync, char **output_stdout) {
1120 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1123 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1124 gchar *pid = itos(getpid());
1125 gchar *xwin = itos(uzbl.xwin);
1127 sharg_append(a, command);
1128 for (i = 0; i < npre; i++) /* add n args before the default vars */
1129 sharg_append(a, args[i]);
1130 sharg_append(a, uzbl.state.config_file);
1131 sharg_append(a, pid);
1132 sharg_append(a, xwin);
1133 sharg_append(a, uzbl.comm.fifo_path);
1134 sharg_append(a, uzbl.comm.socket_path);
1135 sharg_append(a, uzbl.state.uri);
1136 sharg_append(a, uzbl.gui.main_title);
1138 for (i = npre; i < g_strv_length((gchar**)args); i++)
1139 sharg_append(a, args[i]);
1143 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1145 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1146 NULL, NULL, output_stdout, NULL, NULL, &err);
1147 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1148 NULL, NULL, NULL, &err);
1150 if (uzbl.state.verbose) {
1151 GString *s = g_string_new("spawned:");
1152 for (i = 0; i < (a->len); i++) {
1153 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1154 g_string_append_printf(s, " %s", qarg);
1157 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1158 printf("%s\n", s->str);
1159 g_string_free(s, TRUE);
1161 printf("Stdout: %s\n", *output_stdout);
1165 g_printerr("error on run_command: %s\n", err->message);
1170 g_array_free (a, TRUE);
1175 split_quoted(const gchar* src, const gboolean unquote) {
1176 /* split on unquoted space, return array of strings;
1177 remove a layer of quotes and backslashes if unquote */
1178 if (!src) return NULL;
1180 gboolean dq = FALSE;
1181 gboolean sq = FALSE;
1182 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1183 GString *s = g_string_new ("");
1187 for (p = src; *p != '\0'; p++) {
1188 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1189 else if (*p == '\\') { g_string_append_c(s, *p++);
1190 g_string_append_c(s, *p); }
1191 else if ((*p == '"') && unquote && !sq) dq = !dq;
1192 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1194 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1195 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1197 else if ((*p == ' ') && !dq && !sq) {
1198 dup = g_strdup(s->str);
1199 g_array_append_val(a, dup);
1200 g_string_truncate(s, 0);
1201 } else g_string_append_c(s, *p);
1203 dup = g_strdup(s->str);
1204 g_array_append_val(a, dup);
1205 ret = (gchar**)a->data;
1206 g_array_free (a, FALSE);
1207 g_string_free (s, TRUE);
1212 spawn(WebKitWebView *web_view, GArray *argv) {
1214 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1215 if (argv_idx(argv, 0))
1216 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1220 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1223 if (argv_idx(argv, 0))
1224 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1225 TRUE, &uzbl.comm.sync_stdout);
1229 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1231 if (!uzbl.behave.shell_cmd) {
1232 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1237 gchar *spacer = g_strdup("");
1238 g_array_insert_val(argv, 1, spacer);
1239 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1241 for (i = 1; i < g_strv_length(cmd); i++)
1242 g_array_prepend_val(argv, cmd[i]);
1244 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1250 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1252 if (!uzbl.behave.shell_cmd) {
1253 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1258 gchar *spacer = g_strdup("");
1259 g_array_insert_val(argv, 1, spacer);
1260 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1262 for (i = 1; i < g_strv_length(cmd); i++)
1263 g_array_prepend_val(argv, cmd[i]);
1265 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1266 TRUE, &uzbl.comm.sync_stdout);
1272 parse_command(const char *cmd, const char *param) {
1275 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1278 gchar **par = split_quoted(param, TRUE);
1279 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1281 if (c[1] == NOSPLIT) { /* don't split */
1282 sharg_append(a, param);
1284 for (i = 0; i < g_strv_length(par); i++)
1285 sharg_append(a, par[i]);
1287 c[0](uzbl.gui.web_view, a);
1289 g_array_free (a, TRUE);
1292 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1299 if(*uzbl.net.proxy_url == ' '
1300 || uzbl.net.proxy_url == NULL) {
1301 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1302 (GType) SOUP_SESSION_PROXY_URI);
1305 suri = soup_uri_new(uzbl.net.proxy_url);
1306 g_object_set(G_OBJECT(uzbl.net.soup_session),
1307 SOUP_SESSION_PROXY_URI,
1309 soup_uri_free(suri);
1316 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1317 g_array_append_val (a, uzbl.state.uri);
1318 load_uri(uzbl.gui.web_view, a);
1319 g_array_free (a, TRUE);
1323 cmd_always_insert_mode() {
1324 uzbl.behave.insert_mode =
1325 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1331 g_object_set(G_OBJECT(uzbl.net.soup_session),
1332 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1336 cmd_max_conns_host() {
1337 g_object_set(G_OBJECT(uzbl.net.soup_session),
1338 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1343 soup_session_remove_feature
1344 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1345 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1346 /*g_free(uzbl.net.soup_logger);*/
1348 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1349 soup_session_add_feature(uzbl.net.soup_session,
1350 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1353 static WebKitWebSettings*
1355 return webkit_web_view_get_settings(uzbl.gui.web_view);
1360 WebKitWebSettings *ws = view_settings();
1361 if (uzbl.behave.font_size > 0) {
1362 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1365 if (uzbl.behave.monospace_size > 0) {
1366 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1367 uzbl.behave.monospace_size, NULL);
1369 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1370 uzbl.behave.font_size, NULL);
1376 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1380 cmd_disable_plugins() {
1381 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1382 !uzbl.behave.disable_plugins, NULL);
1386 cmd_disable_scripts() {
1387 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1388 !uzbl.behave.disable_scripts, NULL);
1392 cmd_minimum_font_size() {
1393 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1394 uzbl.behave.minimum_font_size, NULL);
1397 cmd_autoload_img() {
1398 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1399 uzbl.behave.autoload_img, NULL);
1404 cmd_autoshrink_img() {
1405 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1406 uzbl.behave.autoshrink_img, NULL);
1411 cmd_enable_spellcheck() {
1412 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1413 uzbl.behave.enable_spellcheck, NULL);
1417 cmd_enable_private() {
1418 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1419 uzbl.behave.enable_private, NULL);
1424 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1425 uzbl.behave.print_bg, NULL);
1430 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1431 uzbl.behave.style_uri, NULL);
1435 cmd_resizable_txt() {
1436 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1437 uzbl.behave.resizable_txt, NULL);
1441 cmd_default_encoding() {
1442 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1443 uzbl.behave.default_encoding, NULL);
1447 cmd_enforce_96dpi() {
1448 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1449 uzbl.behave.enforce_96dpi, NULL);
1453 cmd_caret_browsing() {
1454 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1455 uzbl.behave.caret_browsing, NULL);
1459 cmd_cookie_handler() {
1460 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1461 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1462 if ((g_strcmp0(split[0], "sh") == 0) ||
1463 (g_strcmp0(split[0], "spawn") == 0)) {
1464 g_free (uzbl.behave.cookie_handler);
1465 uzbl.behave.cookie_handler =
1466 g_strdup_printf("sync_%s %s", split[0], split[1]);
1473 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1478 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1483 if(uzbl.behave.inject_html) {
1484 webkit_web_view_load_html_string (uzbl.gui.web_view,
1485 uzbl.behave.inject_html, NULL);
1494 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1495 uzbl.behave.modmask = 0;
1497 if(uzbl.behave.modkey)
1498 g_free(uzbl.behave.modkey);
1499 uzbl.behave.modkey = buf;
1501 for (i = 0; modkeys[i].key != NULL; i++) {
1502 if (g_strrstr(buf, modkeys[i].key))
1503 uzbl.behave.modmask |= modkeys[i].mask;
1509 if (*uzbl.net.useragent == ' ') {
1510 g_free (uzbl.net.useragent);
1511 uzbl.net.useragent = NULL;
1513 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1515 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1516 g_free(uzbl.net.useragent);
1517 uzbl.net.useragent = ua;
1523 gtk_widget_ref(uzbl.gui.scrolled_win);
1524 gtk_widget_ref(uzbl.gui.mainbar);
1525 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1526 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1528 if(uzbl.behave.status_top) {
1529 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1530 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1533 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1534 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1536 gtk_widget_unref(uzbl.gui.scrolled_win);
1537 gtk_widget_unref(uzbl.gui.mainbar);
1538 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1543 set_var_value(gchar *name, gchar *val) {
1544 uzbl_cmdprop *c = NULL;
1548 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1549 /* check for the variable type */
1550 if (c->type == TYPE_STR) {
1551 buf = expand_vars(val);
1554 } else if(c->type == TYPE_INT) {
1555 int *ip = (int *)c->ptr;
1556 buf = expand_vars(val);
1557 *ip = (int)strtoul(buf, &endp, 10);
1559 } else if (c->type == TYPE_FLOAT) {
1560 float *fp = (float *)c->ptr;
1561 buf = expand_vars(val);
1562 *fp = strtod(buf, &endp);
1566 /* invoke a command specific function */
1567 if(c->func) c->func();
1574 Behaviour *b = &uzbl.behave;
1576 if(b->html_buffer->str) {
1577 webkit_web_view_load_html_string (uzbl.gui.web_view,
1578 b->html_buffer->str, b->base_url);
1579 g_string_free(b->html_buffer, TRUE);
1580 b->html_buffer = g_string_new("");
1584 enum {M_CMD, M_HTML};
1586 parse_cmd_line(const char *ctl_line) {
1587 Behaviour *b = &uzbl.behave;
1590 if(b->mode == M_HTML) {
1591 len = strlen(b->html_endmarker);
1592 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1593 if(len == strlen(ctl_line)-1 &&
1594 !strncmp(b->html_endmarker, ctl_line, len)) {
1596 set_var_value("mode", "0");
1601 set_timeout(b->html_timeout);
1602 g_string_append(b->html_buffer, ctl_line);
1605 else if((ctl_line[0] == '#') /* Comments */
1606 || (ctl_line[0] == ' ')
1607 || (ctl_line[0] == '\n'))
1608 ; /* ignore these lines */
1609 else { /* parse a command */
1611 gchar **tokens = NULL;
1612 len = strlen(ctl_line);
1614 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1615 ctlstrip = g_strndup(ctl_line, len - 1);
1616 else ctlstrip = g_strdup(ctl_line);
1618 tokens = g_strsplit(ctlstrip, " ", 2);
1619 parse_command(tokens[0], tokens[1]);
1626 build_stream_name(int type, const gchar* dir) {
1628 State *s = &uzbl.state;
1631 xwin_str = itos((int)uzbl.xwin);
1633 str = g_strdup_printf
1634 ("%s/uzbl_fifo_%s", dir,
1635 s->instance_name ? s->instance_name : xwin_str);
1636 } else if (type == SOCKET) {
1637 str = g_strdup_printf
1638 ("%s/uzbl_socket_%s", dir,
1639 s->instance_name ? s->instance_name : xwin_str );
1646 control_fifo(GIOChannel *gio, GIOCondition condition) {
1647 if (uzbl.state.verbose)
1648 printf("triggered\n");
1653 if (condition & G_IO_HUP)
1654 g_error ("Fifo: Read end of pipe died!\n");
1657 g_error ("Fifo: GIOChannel broke\n");
1659 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1660 if (ret == G_IO_STATUS_ERROR) {
1661 g_error ("Fifo: Error reading: %s\n", err->message);
1665 parse_cmd_line(ctl_line);
1672 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1673 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1674 if (unlink(uzbl.comm.fifo_path) == -1)
1675 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1676 g_free(uzbl.comm.fifo_path);
1677 uzbl.comm.fifo_path = NULL;
1680 if (*dir == ' ') { /* space unsets the variable */
1685 GIOChannel *chan = NULL;
1686 GError *error = NULL;
1687 gchar *path = build_stream_name(FIFO, dir);
1689 if (!file_exists(path)) {
1690 if (mkfifo (path, 0666) == 0) {
1691 // 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.
1692 chan = g_io_channel_new_file(path, "r+", &error);
1694 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1695 if (uzbl.state.verbose)
1696 printf ("init_fifo: created successfully as %s\n", path);
1697 uzbl.comm.fifo_path = path;
1699 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1700 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1701 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1702 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1704 /* if we got this far, there was an error; cleanup */
1705 if (error) g_error_free (error);
1712 control_stdin(GIOChannel *gio, GIOCondition condition) {
1714 gchar *ctl_line = NULL;
1717 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1718 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1721 parse_cmd_line(ctl_line);
1729 GIOChannel *chan = NULL;
1730 GError *error = NULL;
1732 chan = g_io_channel_unix_new(fileno(stdin));
1734 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1735 g_error ("Stdin: could not add watch\n");
1737 if (uzbl.state.verbose)
1738 printf ("Stdin: watch added successfully\n");
1741 g_error ("Stdin: Error while opening: %s\n", error->message);
1743 if (error) g_error_free (error);
1747 control_socket(GIOChannel *chan) {
1748 struct sockaddr_un remote;
1749 char buffer[512], *ctl_line;
1751 int sock, clientsock, n, done;
1754 sock = g_io_channel_unix_get_fd(chan);
1756 memset (buffer, 0, sizeof (buffer));
1758 t = sizeof (remote);
1759 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1763 memset (temp, 0, sizeof (temp));
1764 n = recv (clientsock, temp, 128, 0);
1766 buffer[strlen (buffer)] = '\0';
1770 strcat (buffer, temp);
1773 if (strcmp (buffer, "\n") < 0) {
1774 buffer[strlen (buffer) - 1] = '\0';
1776 buffer[strlen (buffer)] = '\0';
1779 ctl_line = g_strdup(buffer);
1780 parse_cmd_line (ctl_line);
1783 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1784 GError *error = NULL;
1787 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1788 if (ret == G_IO_STATUS_ERROR)
1789 g_error ("Error reading: %s\n", error->message);
1791 printf("Got line %s (%u bytes) \n",ctl_line, len);
1793 parse_line(ctl_line);
1801 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1802 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1803 if (unlink(uzbl.comm.socket_path) == -1)
1804 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1805 g_free(uzbl.comm.socket_path);
1806 uzbl.comm.socket_path = NULL;
1814 GIOChannel *chan = NULL;
1816 struct sockaddr_un local;
1817 gchar *path = build_stream_name(SOCKET, dir);
1819 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1821 local.sun_family = AF_UNIX;
1822 strcpy (local.sun_path, path);
1823 unlink (local.sun_path);
1825 len = strlen (local.sun_path) + sizeof (local.sun_family);
1826 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1827 if (uzbl.state.verbose)
1828 printf ("init_socket: opened in %s\n", path);
1831 if( (chan = g_io_channel_unix_new(sock)) ) {
1832 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1833 uzbl.comm.socket_path = path;
1836 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1838 /* if we got this far, there was an error; cleanup */
1845 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1846 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1848 // this function may be called very early when the templates are not set (yet), hence the checks
1850 update_title (void) {
1851 Behaviour *b = &uzbl.behave;
1854 if (b->show_status) {
1855 if (b->title_format_short) {
1856 parsed = expand_template(b->title_format_short, FALSE);
1857 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1860 if (b->status_format) {
1861 parsed = expand_template(b->status_format, TRUE);
1862 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1865 if (b->status_background) {
1867 gdk_color_parse (b->status_background, &color);
1868 //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)
1869 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1872 if (b->title_format_long) {
1873 parsed = expand_template(b->title_format_long, FALSE);
1874 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1881 key_press_cb (GtkWidget* window, GdkEventKey* event)
1883 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1887 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1888 || 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)
1891 /* turn off insert mode (if always_insert_mode is not used) */
1892 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1893 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1898 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1901 if (event->keyval == GDK_Escape) {
1902 g_string_truncate(uzbl.state.keycmd, 0);
1904 dehilight(uzbl.gui.web_view, NULL);
1908 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1909 if (event->keyval == GDK_Insert) {
1911 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1912 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1914 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1917 g_string_append (uzbl.state.keycmd, str);
1924 if (event->keyval == GDK_BackSpace)
1925 keycmd_bs(NULL, NULL);
1927 gboolean key_ret = FALSE;
1928 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1930 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1932 run_keycmd(key_ret);
1934 if (key_ret) return (!uzbl.behave.insert_mode);
1939 run_keycmd(const gboolean key_ret) {
1940 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1942 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1943 g_string_truncate(uzbl.state.keycmd, 0);
1944 parse_command(act->name, act->param);
1948 /* try if it's an incremental keycmd or one that takes args, and run it */
1949 GString* short_keys = g_string_new ("");
1950 GString* short_keys_inc = g_string_new ("");
1952 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1953 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1954 g_string_assign(short_keys_inc, short_keys->str);
1955 g_string_append_c(short_keys, '_');
1956 g_string_append_c(short_keys_inc, '*');
1958 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1959 /* run normal cmds only if return was pressed */
1960 exec_paramcmd(act, i);
1961 g_string_truncate(uzbl.state.keycmd, 0);
1963 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1964 if (key_ret) /* just quit the incremental command on return */
1965 g_string_truncate(uzbl.state.keycmd, 0);
1966 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1970 g_string_truncate(short_keys, short_keys->len - 1);
1972 g_string_free (short_keys, TRUE);
1973 g_string_free (short_keys_inc, TRUE);
1977 exec_paramcmd(const Action *act, const guint i) {
1978 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1979 GString *actionname = g_string_new ("");
1980 GString *actionparam = g_string_new ("");
1981 g_string_erase (parampart, 0, i+1);
1983 g_string_printf (actionname, act->name, parampart->str);
1985 g_string_printf (actionparam, act->param, parampart->str);
1986 parse_command(actionname->str, actionparam->str);
1987 g_string_free(actionname, TRUE);
1988 g_string_free(actionparam, TRUE);
1989 g_string_free(parampart, TRUE);
1997 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1998 //main_window_ref = g_object_ref(scrolled_window);
1999 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
2001 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2002 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2004 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2011 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2012 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2014 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2016 return scrolled_window;
2023 g->mainbar = gtk_hbox_new (FALSE, 0);
2025 /* keep a reference to the bar so we can re-pack it at runtime*/
2026 //sbar_ref = g_object_ref(g->mainbar);
2028 g->mainbar_label = gtk_label_new ("");
2029 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2030 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2031 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2032 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2033 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2034 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2039 GtkWidget* create_window () {
2040 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2041 gchar* uzbl_icon = find_xdg_file(1, "/uzbl/uzbl.png");
2042 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2043 gtk_widget_set_name (window, "Uzbl browser");
2044 gtk_window_set_icon_from_file (GTK_WINDOW (window), uzbl_icon, NULL);
2045 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2046 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2054 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2056 If actname is one that calls an external command, this function will inject
2057 newargs in front of the user-provided args in that command line. They will
2058 come become after the body of the script (in sh) or after the name of
2059 the command to execute (in spawn).
2060 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2061 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2063 The return value consist of two strings: the action (sh, ...) and its args.
2065 If act is not one that calls an external command, then the given action merely
2068 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2069 gchar *actdup = g_strdup(actname);
2070 g_array_append_val(rets, actdup);
2072 if ((g_strcmp0(actname, "spawn") == 0) ||
2073 (g_strcmp0(actname, "sh") == 0) ||
2074 (g_strcmp0(actname, "sync_spawn") == 0) ||
2075 (g_strcmp0(actname, "sync_sh") == 0)) {
2077 GString *a = g_string_new("");
2078 gchar **spawnparts = split_quoted(origargs, FALSE);
2079 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2080 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2082 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2083 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2085 g_array_append_val(rets, a->str);
2086 g_string_free(a, FALSE);
2087 g_strfreev(spawnparts);
2089 gchar *origdup = g_strdup(origargs);
2090 g_array_append_val(rets, origdup);
2092 return (gchar**)g_array_free(rets, FALSE);
2096 run_handler (const gchar *act, const gchar *args) {
2097 /* Consider this code a temporary hack to make the handlers usable.
2098 In practice, all this splicing, injection, and reconstruction is
2099 inefficient, annoying and hard to manage. Potential pitfalls arise
2100 when the handler specific args 1) are not quoted (the handler
2101 callbacks should take care of this) 2) are quoted but interfere
2102 with the users' own quotation. A more ideal solution is
2103 to refactor parse_command so that it doesn't just take a string
2104 and execute it; rather than that, we should have a function which
2105 returns the argument vector parsed from the string. This vector
2106 could be modified (e.g. insert additional args into it) before
2107 passing it to the next function that actually executes it. Though
2108 it still isn't perfect for chain actions.. will reconsider & re-
2109 factor when I have the time. -duc */
2111 char **parts = g_strsplit(act, " ", 2);
2113 if (g_strcmp0(parts[0], "chain") == 0) {
2114 GString *newargs = g_string_new("");
2115 gchar **chainparts = split_quoted(parts[1], FALSE);
2117 /* for every argument in the chain, inject the handler args
2118 and make sure the new parts are wrapped in quotes */
2119 gchar **cp = chainparts;
2121 gchar *quotless = NULL;
2122 gchar **spliced_quotless = NULL; // sigh -_-;
2123 gchar **inpart = NULL;
2126 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2128 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2129 } else quotless = g_strdup(*cp);
2131 spliced_quotless = g_strsplit(quotless, " ", 2);
2132 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2133 g_strfreev(spliced_quotless);
2135 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2141 parse_command(parts[0], &(newargs->str[1]));
2142 g_string_free(newargs, TRUE);
2143 g_strfreev(chainparts);
2146 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2147 parse_command(inparts[0], inparts[1]);
2155 add_binding (const gchar *key, const gchar *act) {
2156 char **parts = g_strsplit(act, " ", 2);
2163 if (uzbl.state.verbose)
2164 printf ("Binding %-10s : %s\n", key, act);
2165 action = new_action(parts[0], parts[1]);
2167 if (g_hash_table_remove (uzbl.bindings, key))
2168 g_warning ("Overwriting existing binding for \"%s\"", key);
2169 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2174 get_xdg_var (XDG_Var xdg) {
2175 const gchar* actual_value = getenv (xdg.environmental);
2176 const gchar* home = getenv ("HOME");
2177 gchar* return_value;
2179 if (! actual_value || strcmp (actual_value, "") == 0) {
2180 if (xdg.default_value) {
2181 return_value = str_replace ("~", home, xdg.default_value);
2183 return_value = NULL;
2186 return_value = str_replace("~", home, actual_value);
2189 return return_value;
2193 find_xdg_file (int xdg_type, char* filename) {
2194 /* xdg_type = 0 => config
2195 xdg_type = 1 => data
2196 xdg_type = 2 => cache*/
2198 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2199 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2202 gchar* temporary_string;
2206 if (! file_exists (temporary_file) && xdg_type != 2) {
2207 buf = get_xdg_var (XDG[3 + xdg_type]);
2208 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2211 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2212 g_free (temporary_file);
2213 temporary_file = g_strconcat (temporary_string, filename, NULL);
2217 //g_free (temporary_string); - segfaults.
2219 if (file_exists (temporary_file)) {
2220 return temporary_file;
2227 State *s = &uzbl.state;
2228 Network *n = &uzbl.net;
2230 for (i = 0; default_config[i].command != NULL; i++) {
2231 parse_cmd_line(default_config[i].command);
2234 if (!s->config_file) {
2235 s->config_file = find_xdg_file (0, "/uzbl/config");
2238 if (s->config_file) {
2239 GArray* lines = read_file_by_line (s->config_file);
2243 while ((line = g_array_index(lines, gchar*, i))) {
2244 parse_cmd_line (line);
2248 g_array_free (lines, TRUE);
2250 if (uzbl.state.verbose)
2251 printf ("No configuration file loaded.\n");
2254 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2257 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2260 if (!uzbl.behave.cookie_handler)
2263 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2264 GString *s = g_string_new ("");
2265 SoupURI * soup_uri = soup_message_get_uri(msg);
2266 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2267 run_handler(uzbl.behave.cookie_handler, s->str);
2269 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2270 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2271 if ( p != NULL ) *p = '\0';
2272 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2274 if (uzbl.comm.sync_stdout)
2275 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2277 g_string_free(s, TRUE);
2281 save_cookies (SoupMessage *msg, gpointer user_data){
2285 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2286 cookie = soup_cookie_to_set_cookie_header(ck->data);
2287 SoupURI * soup_uri = soup_message_get_uri(msg);
2288 GString *s = g_string_new ("");
2289 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2290 run_handler(uzbl.behave.cookie_handler, s->str);
2292 g_string_free(s, TRUE);
2297 /* --- WEBINSPECTOR --- */
2299 hide_window_cb(GtkWidget *widget, gpointer data) {
2302 gtk_widget_hide(widget);
2305 static WebKitWebView*
2306 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2309 (void) web_inspector;
2310 GtkWidget* scrolled_window;
2311 GtkWidget* new_web_view;
2314 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2315 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2316 G_CALLBACK(hide_window_cb), NULL);
2318 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2319 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2320 gtk_widget_show(g->inspector_window);
2322 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2323 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2324 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2325 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2326 gtk_widget_show(scrolled_window);
2328 new_web_view = webkit_web_view_new();
2329 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2331 return WEBKIT_WEB_VIEW(new_web_view);
2335 inspector_show_window_cb (WebKitWebInspector* inspector){
2337 gtk_widget_show(uzbl.gui.inspector_window);
2341 /* TODO: Add variables and code to make use of these functions */
2343 inspector_close_window_cb (WebKitWebInspector* inspector){
2349 inspector_attach_window_cb (WebKitWebInspector* inspector){
2355 inspector_detach_window_cb (WebKitWebInspector* inspector){
2361 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2367 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2373 set_up_inspector() {
2375 WebKitWebSettings *settings = view_settings();
2376 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2378 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2379 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2380 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2381 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2382 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2383 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2384 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2386 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2390 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2392 uzbl_cmdprop *c = v;
2397 if(c->type == TYPE_STR)
2398 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2399 else if(c->type == TYPE_INT)
2400 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2404 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2408 printf("bind %s = %s %s\n", (char *)k ,
2409 (char *)a->name, a->param?(char *)a->param:"");
2414 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2415 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2420 main (int argc, char* argv[]) {
2421 gtk_init (&argc, &argv);
2422 if (!g_thread_supported ())
2423 g_thread_init (NULL);
2424 uzbl.state.executable_path = g_strdup(argv[0]);
2425 uzbl.state.selected_url = NULL;
2426 uzbl.state.searchtx = NULL;
2428 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2429 g_option_context_add_main_entries (context, entries, NULL);
2430 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2431 g_option_context_parse (context, &argc, &argv, NULL);
2432 g_option_context_free(context);
2434 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2435 gboolean verbose_override = uzbl.state.verbose;
2437 /* initialize hash table */
2438 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2440 uzbl.net.soup_session = webkit_get_default_session();
2441 uzbl.state.keycmd = g_string_new("");
2443 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2444 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2445 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2446 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2447 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2448 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2451 if(uname(&uzbl.state.unameinfo) == -1)
2452 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2454 uzbl.gui.sbar.progress_s = g_strdup("=");
2455 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2456 uzbl.gui.sbar.progress_w = 10;
2458 /* HTML mode defaults*/
2459 uzbl.behave.html_buffer = g_string_new("");
2460 uzbl.behave.html_endmarker = g_strdup(".");
2461 uzbl.behave.html_timeout = 60;
2462 uzbl.behave.base_url = g_strdup("http://invalid");
2464 /* default mode indicators */
2465 uzbl.behave.insert_indicator = g_strdup("I");
2466 uzbl.behave.cmd_indicator = g_strdup("C");
2470 make_var_to_name_hash();
2472 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2474 uzbl.gui.scrolled_win = create_browser();
2477 /* initial packing */
2478 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2479 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2481 uzbl.gui.main_window = create_window ();
2482 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2485 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2486 gtk_widget_show_all (uzbl.gui.main_window);
2487 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2489 if (uzbl.state.verbose) {
2490 printf("Uzbl start location: %s\n", argv[0]);
2491 printf("window_id %i\n",(int) uzbl.xwin);
2492 printf("pid %i\n", getpid ());
2493 printf("name: %s\n", uzbl.state.instance_name);
2496 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2497 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2498 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2499 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2500 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2504 if (!uzbl.behave.show_status)
2505 gtk_widget_hide(uzbl.gui.mainbar);
2514 if (verbose_override > uzbl.state.verbose)
2515 uzbl.state.verbose = verbose_override;
2518 set_var_value("uri", uri_override);
2519 g_free(uri_override);
2520 } else if (uzbl.state.uri)
2521 cmd_load_uri(uzbl.gui.web_view, NULL);
2526 return EXIT_SUCCESS;
2529 /* vi: set et ts=4: */