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 { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
77 "Socket ID", "SOCKET" },
78 { NULL, 0, 0, 0, NULL, NULL, NULL }
81 /* associate command names to their properties */
82 typedef const struct {
89 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
91 /* an abbreviation to help keep the table's width humane */
92 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
97 } var_name_to_ptr[] = {
98 /* variable name pointer to variable in code type dump callback function */
99 /* --------------------------------------------------------------------------------------- */
100 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
101 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
102 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
103 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
104 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
105 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
106 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
107 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
108 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
109 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
110 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
111 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
112 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
113 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
114 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
115 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
116 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
117 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
118 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
119 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
120 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
121 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
122 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
123 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
124 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
125 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
126 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
127 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
128 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
129 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
130 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
131 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
132 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
133 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
134 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
135 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
136 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
137 /* exported WebKitWebSettings properties */
138 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
139 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
140 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
141 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
142 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
143 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
144 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
145 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
146 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
147 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
148 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
149 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
150 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
151 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
152 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
153 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
155 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
156 }, *n2v_p = var_name_to_ptr;
162 { "SHIFT", GDK_SHIFT_MASK }, // shift
163 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
164 { "CONTROL", GDK_CONTROL_MASK }, // control
165 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
166 { "MOD2", GDK_MOD2_MASK }, // 5th mod
167 { "MOD3", GDK_MOD3_MASK }, // 6th mod
168 { "MOD4", GDK_MOD4_MASK }, // 7th mod
169 { "MOD5", GDK_MOD5_MASK }, // 8th mod
170 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
171 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
172 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
173 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
174 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
175 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
176 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
177 { "META", GDK_META_MASK }, // meta (since 2.10)
182 /* construct a hash from the var_name_to_ptr array for quick access */
184 make_var_to_name_hash() {
185 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
187 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
192 /* --- UTILITY FUNCTIONS --- */
194 expand_vars(char *s) {
197 char ret[256], *vend;
198 GString *buf = g_string_new("");
203 g_string_append_c(buf, *++s);
211 if( (vend = strchr(s, upto)) ||
212 (vend = strchr(s, '\0')) ) {
213 strncpy(ret, s, vend-s);
215 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
216 if(c->type == TYPE_STR)
217 g_string_append(buf, (gchar *)*c->ptr);
218 else if(c->type == TYPE_INT) {
219 char *b = itos((int)*c->ptr);
220 g_string_append(buf, b);
224 if(upto == ' ') s = vend;
230 g_string_append_c(buf, *s);
235 return g_string_free(buf, FALSE);
242 snprintf(tmp, sizeof(tmp), "%i", val);
243 return g_strdup(tmp);
247 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
250 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
253 str_replace (const char* search, const char* replace, const char* string) {
257 buf = g_strsplit (string, search, -1);
258 ret = g_strjoinv (replace, buf);
259 g_strfreev(buf); // somebody said this segfaults
265 read_file_by_line (gchar *path) {
266 GIOChannel *chan = NULL;
267 gchar *readbuf = NULL;
269 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
272 chan = g_io_channel_new_file(path, "r", NULL);
275 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
276 const gchar* val = g_strdup (readbuf);
277 g_array_append_val (lines, val);
282 g_io_channel_unref (chan);
284 fprintf(stderr, "File '%s' not be read.\n", path);
291 gchar* parseenv (char* string) {
292 extern char** environ;
293 gchar* tmpstr = NULL;
297 while (environ[i] != NULL) {
298 gchar** env = g_strsplit (environ[i], "=", 2);
299 gchar* envname = g_strconcat ("$", env[0], NULL);
301 if (g_strrstr (string, envname) != NULL) {
302 tmpstr = g_strdup(string);
304 string = str_replace(envname, env[1], tmpstr);
309 g_strfreev (env); // somebody said this breaks uzbl
317 setup_signal(int signr, sigfunc *shandler) {
318 struct sigaction nh, oh;
320 nh.sa_handler = shandler;
321 sigemptyset(&nh.sa_mask);
324 if(sigaction(signr, &nh, &oh) < 0)
332 if (uzbl.behave.fifo_dir)
333 unlink (uzbl.comm.fifo_path);
334 if (uzbl.behave.socket_dir)
335 unlink (uzbl.comm.socket_path);
337 g_free(uzbl.state.executable_path);
338 g_string_free(uzbl.state.keycmd, TRUE);
339 g_hash_table_destroy(uzbl.bindings);
340 g_hash_table_destroy(uzbl.behave.commands);
343 /* used for html_mode_timeout
344 * be sure to extend this function to use
345 * more timers if needed in other places
348 set_timeout(int seconds) {
350 memset(&t, 0, sizeof t);
352 t.it_value.tv_sec = seconds;
353 t.it_value.tv_usec = 0;
354 setitimer(ITIMER_REAL, &t, NULL);
357 /* --- SIGNAL HANDLER --- */
360 catch_sigterm(int s) {
366 catch_sigint(int s) {
376 set_var_value("mode", "0");
381 /* --- CALLBACKS --- */
384 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
387 (void) navigation_action;
388 (void) policy_decision;
390 const gchar* uri = webkit_network_request_get_uri (request);
391 if (uzbl.state.verbose)
392 printf("New window requested -> %s \n", uri);
393 new_window_load_uri(uri);
398 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
403 /* If we can display it, let's display it... */
404 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
405 webkit_web_policy_decision_use (policy_decision);
409 /* ...everything we can't displayed is downloaded */
410 webkit_web_policy_decision_download (policy_decision);
415 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
419 if (uzbl.state.selected_url != NULL) {
420 if (uzbl.state.verbose)
421 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
422 new_window_load_uri(uzbl.state.selected_url);
424 if (uzbl.state.verbose)
425 printf("New web view -> %s\n","Nothing to open, exiting");
431 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
434 if (uzbl.behave.download_handler) {
435 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
436 if (uzbl.state.verbose)
437 printf("Download -> %s\n",uri);
438 /* if urls not escaped, we may have to escape and quote uri before this call */
439 run_handler(uzbl.behave.download_handler, uri);
444 /* scroll a bar in a given direction */
446 scroll (GtkAdjustment* bar, GArray *argv) {
450 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
451 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
452 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
456 scroll_begin(WebKitWebView* page, GArray *argv) {
457 (void) page; (void) argv;
458 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
462 scroll_end(WebKitWebView* page, GArray *argv) {
463 (void) page; (void) argv;
464 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
465 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
469 scroll_vert(WebKitWebView* page, GArray *argv) {
471 scroll(uzbl.gui.bar_v, argv);
475 scroll_horz(WebKitWebView* page, GArray *argv) {
477 scroll(uzbl.gui.bar_h, argv);
482 if (!uzbl.behave.show_status) {
483 gtk_widget_hide(uzbl.gui.mainbar);
485 gtk_widget_show(uzbl.gui.mainbar);
491 toggle_status_cb (WebKitWebView* page, GArray *argv) {
495 if (uzbl.behave.show_status) {
496 gtk_widget_hide(uzbl.gui.mainbar);
498 gtk_widget_show(uzbl.gui.mainbar);
500 uzbl.behave.show_status = !uzbl.behave.show_status;
505 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
509 //Set selected_url state variable
510 g_free(uzbl.state.selected_url);
511 uzbl.state.selected_url = NULL;
513 uzbl.state.selected_url = g_strdup(link);
519 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
523 if (uzbl.gui.main_title)
524 g_free (uzbl.gui.main_title);
525 uzbl.gui.main_title = g_strdup (title);
530 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
533 uzbl.gui.sbar.load_progress = progress;
538 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
542 if (uzbl.behave.load_finish_handler)
543 run_handler(uzbl.behave.load_finish_handler, "");
547 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
551 uzbl.gui.sbar.load_progress = 0;
552 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
553 if (uzbl.behave.load_start_handler)
554 run_handler(uzbl.behave.load_start_handler, "");
558 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
561 g_free (uzbl.state.uri);
562 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
563 uzbl.state.uri = g_string_free (newuri, FALSE);
564 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
565 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
568 if (uzbl.behave.load_commit_handler)
569 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
573 destroy_cb (GtkWidget* widget, gpointer data) {
581 if (uzbl.behave.history_handler) {
583 struct tm * timeinfo;
586 timeinfo = localtime ( &rawtime );
587 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
588 run_handler(uzbl.behave.history_handler, date);
593 /* VIEW funcs (little webkit wrappers) */
594 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
596 VIEWFUNC(reload_bypass_cache)
597 VIEWFUNC(stop_loading)
604 /* -- command to callback/function map for things we cannot attach to any signals */
605 static struct {char *name; Command command[2];} cmdlist[] =
606 { /* key function no_split */
607 { "back", {view_go_back, 0} },
608 { "forward", {view_go_forward, 0} },
609 { "scroll_vert", {scroll_vert, 0} },
610 { "scroll_horz", {scroll_horz, 0} },
611 { "scroll_begin", {scroll_begin, 0} },
612 { "scroll_end", {scroll_end, 0} },
613 { "reload", {view_reload, 0}, },
614 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
615 { "stop", {view_stop_loading, 0}, },
616 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
617 { "zoom_out", {view_zoom_out, 0}, },
618 { "uri", {load_uri, NOSPLIT} },
619 { "js", {run_js, NOSPLIT} },
620 { "script", {run_external_js, 0} },
621 { "toggle_status", {toggle_status_cb, 0} },
622 { "spawn", {spawn, 0} },
623 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
624 { "sh", {spawn_sh, 0} },
625 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
626 { "exit", {close_uzbl, 0} },
627 { "search", {search_forward_text, NOSPLIT} },
628 { "search_reverse", {search_reverse_text, NOSPLIT} },
629 { "dehilight", {dehilight, 0} },
630 { "toggle_insert_mode", {toggle_insert_mode, 0} },
631 { "set", {set_var, NOSPLIT} },
632 //{ "get", {get_var, NOSPLIT} },
633 { "bind", {act_bind, NOSPLIT} },
634 { "dump_config", {act_dump_config, 0} },
635 { "keycmd", {keycmd, NOSPLIT} },
636 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
637 { "keycmd_bs", {keycmd_bs, 0} },
638 { "chain", {chain, 0} },
639 { "print", {print, NOSPLIT} }
646 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
648 for (i = 0; i < LENGTH(cmdlist); i++)
649 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
652 /* -- CORE FUNCTIONS -- */
655 free_action(gpointer act) {
656 Action *action = (Action*)act;
657 g_free(action->name);
659 g_free(action->param);
664 new_action(const gchar *name, const gchar *param) {
665 Action *action = g_new(Action, 1);
667 action->name = g_strdup(name);
669 action->param = g_strdup(param);
671 action->param = NULL;
677 file_exists (const char * filename) {
678 return (access(filename, F_OK) == 0);
682 set_var(WebKitWebView *page, GArray *argv) {
684 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
685 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
686 set_var_value(g_strstrip(split[0]), value);
692 print(WebKitWebView *page, GArray *argv) {
696 buf = expand_vars(argv_idx(argv, 0));
702 act_bind(WebKitWebView *page, GArray *argv) {
704 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
705 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
706 add_binding(g_strstrip(split[0]), value);
718 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
721 if (argv_idx(argv, 0)) {
722 if (strcmp (argv_idx(argv, 0), "0") == 0) {
723 uzbl.behave.insert_mode = FALSE;
725 uzbl.behave.insert_mode = TRUE;
728 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
735 load_uri (WebKitWebView *web_view, GArray *argv) {
736 if (argv_idx(argv, 0)) {
737 GString* newuri = g_string_new (argv_idx(argv, 0));
738 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
739 run_js(web_view, argv);
742 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
743 g_string_prepend (newuri, "http://");
744 /* if we do handle cookies, ask our handler for them */
745 webkit_web_view_load_uri (web_view, newuri->str);
746 g_string_free (newuri, TRUE);
751 run_js (WebKitWebView * web_view, GArray *argv) {
752 if (argv_idx(argv, 0))
753 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
757 run_external_js (WebKitWebView * web_view, GArray *argv) {
758 if (argv_idx(argv, 0)) {
759 GArray* lines = read_file_by_line (argv_idx (argv, 0));
764 while ((line = g_array_index(lines, gchar*, i))) {
766 js = g_strdup (line);
768 gchar* newjs = g_strconcat (js, line, NULL);
775 if (uzbl.state.verbose)
776 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
778 if (argv_idx (argv, 1)) {
779 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
783 webkit_web_view_execute_script (web_view, js);
785 g_array_free (lines, TRUE);
790 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
791 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
792 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
793 webkit_web_view_unmark_text_matches (page);
794 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
795 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
799 if (uzbl.state.searchtx) {
800 if (uzbl.state.verbose)
801 printf ("Searching: %s\n", uzbl.state.searchtx);
802 webkit_web_view_set_highlight_text_matches (page, TRUE);
803 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
808 search_forward_text (WebKitWebView *page, GArray *argv) {
809 search_text(page, argv, TRUE);
813 search_reverse_text (WebKitWebView *page, GArray *argv) {
814 search_text(page, argv, FALSE);
818 dehilight (WebKitWebView *page, GArray *argv) {
820 webkit_web_view_set_highlight_text_matches (page, FALSE);
825 new_window_load_uri (const gchar * uri) {
826 GString* to_execute = g_string_new ("");
827 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
829 for (i = 0; entries[i].long_name != NULL; i++) {
830 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
831 gchar** str = (gchar**)entries[i].arg_data;
833 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
837 if (uzbl.state.verbose)
838 printf("\n%s\n", to_execute->str);
839 g_spawn_command_line_async (to_execute->str, NULL);
840 g_string_free (to_execute, TRUE);
844 chain (WebKitWebView *page, GArray *argv) {
847 gchar **parts = NULL;
849 while ((a = argv_idx(argv, i++))) {
850 parts = g_strsplit (a, " ", 2);
851 parse_command(parts[0], parts[1]);
857 keycmd (WebKitWebView *page, GArray *argv) {
860 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
866 keycmd_nl (WebKitWebView *page, GArray *argv) {
869 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
875 keycmd_bs (WebKitWebView *page, GArray *argv) {
878 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
883 close_uzbl (WebKitWebView *page, GArray *argv) {
889 /* --Statusbar functions-- */
891 build_progressbar_ascii(int percent) {
892 int width=uzbl.gui.sbar.progress_w;
895 GString *bar = g_string_new("");
897 l = (double)percent*((double)width/100.);
898 l = (int)(l+.5)>=(int)l ? l+.5 : l;
900 for(i=0; i<(int)l; i++)
901 g_string_append(bar, uzbl.gui.sbar.progress_s);
904 g_string_append(bar, uzbl.gui.sbar.progress_u);
906 return g_string_free(bar, FALSE);
911 const GScannerConfig scan_config = {
914 ) /* cset_skip_characters */,
919 ) /* cset_identifier_first */,
926 ) /* cset_identifier_nth */,
927 ( "" ) /* cpair_comment_single */,
929 TRUE /* case_sensitive */,
931 FALSE /* skip_comment_multi */,
932 FALSE /* skip_comment_single */,
933 FALSE /* scan_comment_multi */,
934 TRUE /* scan_identifier */,
935 TRUE /* scan_identifier_1char */,
936 FALSE /* scan_identifier_NULL */,
937 TRUE /* scan_symbols */,
938 FALSE /* scan_binary */,
939 FALSE /* scan_octal */,
940 FALSE /* scan_float */,
941 FALSE /* scan_hex */,
942 FALSE /* scan_hex_dollar */,
943 FALSE /* scan_string_sq */,
944 FALSE /* scan_string_dq */,
945 TRUE /* numbers_2_int */,
946 FALSE /* int_2_float */,
947 FALSE /* identifier_2_string */,
948 FALSE /* char_2_token */,
949 FALSE /* symbol_2_token */,
950 TRUE /* scope_0_fallback */,
955 uzbl.scan = g_scanner_new(&scan_config);
956 while(symp->symbol_name) {
957 g_scanner_scope_add_symbol(uzbl.scan, 0,
959 GINT_TO_POINTER(symp->symbol_token));
965 expand_template(const char *template, gboolean escape_markup) {
966 if(!template) return NULL;
968 GTokenType token = G_TOKEN_NONE;
969 GString *ret = g_string_new("");
973 g_scanner_input_text(uzbl.scan, template, strlen(template));
974 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
975 token = g_scanner_get_next_token(uzbl.scan);
977 if(token == G_TOKEN_SYMBOL) {
978 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
982 buf = uzbl.state.uri?
983 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
984 g_string_append(ret, buf);
988 g_string_append(ret, uzbl.state.uri?
989 uzbl.state.uri:g_strdup(""));
992 buf = itos(uzbl.gui.sbar.load_progress);
993 g_string_append(ret, buf);
996 case SYM_LOADPRGSBAR:
997 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
998 g_string_append(ret, buf);
1003 buf = uzbl.gui.main_title?
1004 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1005 g_string_append(ret, buf);
1009 g_string_append(ret, uzbl.gui.main_title?
1010 uzbl.gui.main_title:g_strdup(""));
1012 case SYM_SELECTED_URI:
1014 buf = uzbl.state.selected_url?
1015 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1016 g_string_append(ret, buf);
1020 g_string_append(ret, uzbl.state.selected_url?
1021 uzbl.state.selected_url:g_strdup(""));
1024 buf = itos(uzbl.xwin);
1025 g_string_append(ret,
1026 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1031 buf = uzbl.state.keycmd->str?
1032 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1033 g_string_append(ret, buf);
1037 g_string_append(ret, uzbl.state.keycmd->str?
1038 uzbl.state.keycmd->str:g_strdup(""));
1041 g_string_append(ret,
1042 uzbl.behave.insert_mode?
1043 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1046 g_string_append(ret,
1047 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1049 /* useragent syms */
1051 buf = itos(WEBKIT_MAJOR_VERSION);
1052 g_string_append(ret, buf);
1056 buf = itos(WEBKIT_MINOR_VERSION);
1057 g_string_append(ret, buf);
1061 buf = itos(WEBKIT_MICRO_VERSION);
1062 g_string_append(ret, buf);
1066 g_string_append(ret, uzbl.state.unameinfo.sysname);
1069 g_string_append(ret, uzbl.state.unameinfo.nodename);
1072 g_string_append(ret, uzbl.state.unameinfo.release);
1075 g_string_append(ret, uzbl.state.unameinfo.version);
1078 g_string_append(ret, uzbl.state.unameinfo.machine);
1081 g_string_append(ret, ARCH);
1084 case SYM_DOMAINNAME:
1085 g_string_append(ret, uzbl.state.unameinfo.domainname);
1089 g_string_append(ret, COMMIT);
1095 else if(token == G_TOKEN_INT) {
1096 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1097 g_string_append(ret, buf);
1100 else if(token == G_TOKEN_IDENTIFIER) {
1101 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1103 else if(token == G_TOKEN_CHAR) {
1104 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1108 return g_string_free(ret, FALSE);
1110 /* --End Statusbar functions-- */
1113 sharg_append(GArray *a, const gchar *str) {
1114 const gchar *s = (str ? str : "");
1115 g_array_append_val(a, s);
1118 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1120 run_command (const gchar *command, const guint npre, const gchar **args,
1121 const gboolean sync, char **output_stdout) {
1122 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1125 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1126 gchar *pid = itos(getpid());
1127 gchar *xwin = itos(uzbl.xwin);
1129 sharg_append(a, command);
1130 for (i = 0; i < npre; i++) /* add n args before the default vars */
1131 sharg_append(a, args[i]);
1132 sharg_append(a, uzbl.state.config_file);
1133 sharg_append(a, pid);
1134 sharg_append(a, xwin);
1135 sharg_append(a, uzbl.comm.fifo_path);
1136 sharg_append(a, uzbl.comm.socket_path);
1137 sharg_append(a, uzbl.state.uri);
1138 sharg_append(a, uzbl.gui.main_title);
1140 for (i = npre; i < g_strv_length((gchar**)args); i++)
1141 sharg_append(a, args[i]);
1145 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1147 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1148 NULL, NULL, output_stdout, NULL, NULL, &err);
1149 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1150 NULL, NULL, NULL, &err);
1152 if (uzbl.state.verbose) {
1153 GString *s = g_string_new("spawned:");
1154 for (i = 0; i < (a->len); i++) {
1155 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1156 g_string_append_printf(s, " %s", qarg);
1159 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1160 printf("%s\n", s->str);
1161 g_string_free(s, TRUE);
1163 printf("Stdout: %s\n", *output_stdout);
1167 g_printerr("error on run_command: %s\n", err->message);
1172 g_array_free (a, TRUE);
1177 split_quoted(const gchar* src, const gboolean unquote) {
1178 /* split on unquoted space, return array of strings;
1179 remove a layer of quotes and backslashes if unquote */
1180 if (!src) return NULL;
1182 gboolean dq = FALSE;
1183 gboolean sq = FALSE;
1184 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1185 GString *s = g_string_new ("");
1189 for (p = src; *p != '\0'; p++) {
1190 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1191 else if (*p == '\\') { g_string_append_c(s, *p++);
1192 g_string_append_c(s, *p); }
1193 else if ((*p == '"') && unquote && !sq) dq = !dq;
1194 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1196 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1197 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1199 else if ((*p == ' ') && !dq && !sq) {
1200 dup = g_strdup(s->str);
1201 g_array_append_val(a, dup);
1202 g_string_truncate(s, 0);
1203 } else g_string_append_c(s, *p);
1205 dup = g_strdup(s->str);
1206 g_array_append_val(a, dup);
1207 ret = (gchar**)a->data;
1208 g_array_free (a, FALSE);
1209 g_string_free (s, TRUE);
1214 spawn(WebKitWebView *web_view, GArray *argv) {
1216 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1217 if (argv_idx(argv, 0))
1218 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1222 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1225 if (argv_idx(argv, 0))
1226 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1227 TRUE, &uzbl.comm.sync_stdout);
1231 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1233 if (!uzbl.behave.shell_cmd) {
1234 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1239 gchar *spacer = g_strdup("");
1240 g_array_insert_val(argv, 1, spacer);
1241 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1243 for (i = 1; i < g_strv_length(cmd); i++)
1244 g_array_prepend_val(argv, cmd[i]);
1246 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1252 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1254 if (!uzbl.behave.shell_cmd) {
1255 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1260 gchar *spacer = g_strdup("");
1261 g_array_insert_val(argv, 1, spacer);
1262 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1264 for (i = 1; i < g_strv_length(cmd); i++)
1265 g_array_prepend_val(argv, cmd[i]);
1267 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1268 TRUE, &uzbl.comm.sync_stdout);
1274 parse_command(const char *cmd, const char *param) {
1277 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1280 gchar **par = split_quoted(param, TRUE);
1281 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1283 if (c[1] == NOSPLIT) { /* don't split */
1284 sharg_append(a, param);
1286 for (i = 0; i < g_strv_length(par); i++)
1287 sharg_append(a, par[i]);
1289 c[0](uzbl.gui.web_view, a);
1291 g_array_free (a, TRUE);
1294 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1301 if(*uzbl.net.proxy_url == ' '
1302 || uzbl.net.proxy_url == NULL) {
1303 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1304 (GType) SOUP_SESSION_PROXY_URI);
1307 suri = soup_uri_new(uzbl.net.proxy_url);
1308 g_object_set(G_OBJECT(uzbl.net.soup_session),
1309 SOUP_SESSION_PROXY_URI,
1311 soup_uri_free(suri);
1318 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1319 g_array_append_val (a, uzbl.state.uri);
1320 load_uri(uzbl.gui.web_view, a);
1321 g_array_free (a, TRUE);
1325 cmd_always_insert_mode() {
1326 uzbl.behave.insert_mode =
1327 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1333 g_object_set(G_OBJECT(uzbl.net.soup_session),
1334 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1338 cmd_max_conns_host() {
1339 g_object_set(G_OBJECT(uzbl.net.soup_session),
1340 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1345 soup_session_remove_feature
1346 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1347 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1348 /*g_free(uzbl.net.soup_logger);*/
1350 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1351 soup_session_add_feature(uzbl.net.soup_session,
1352 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1355 static WebKitWebSettings*
1357 return webkit_web_view_get_settings(uzbl.gui.web_view);
1362 WebKitWebSettings *ws = view_settings();
1363 if (uzbl.behave.font_size > 0) {
1364 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1367 if (uzbl.behave.monospace_size > 0) {
1368 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1369 uzbl.behave.monospace_size, NULL);
1371 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1372 uzbl.behave.font_size, NULL);
1378 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1382 cmd_disable_plugins() {
1383 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1384 !uzbl.behave.disable_plugins, NULL);
1388 cmd_disable_scripts() {
1389 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1390 !uzbl.behave.disable_scripts, NULL);
1394 cmd_minimum_font_size() {
1395 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1396 uzbl.behave.minimum_font_size, NULL);
1399 cmd_autoload_img() {
1400 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1401 uzbl.behave.autoload_img, NULL);
1406 cmd_autoshrink_img() {
1407 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1408 uzbl.behave.autoshrink_img, NULL);
1413 cmd_enable_spellcheck() {
1414 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1415 uzbl.behave.enable_spellcheck, NULL);
1419 cmd_enable_private() {
1420 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1421 uzbl.behave.enable_private, NULL);
1426 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1427 uzbl.behave.print_bg, NULL);
1432 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1433 uzbl.behave.style_uri, NULL);
1437 cmd_resizable_txt() {
1438 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1439 uzbl.behave.resizable_txt, NULL);
1443 cmd_default_encoding() {
1444 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1445 uzbl.behave.default_encoding, NULL);
1449 cmd_enforce_96dpi() {
1450 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1451 uzbl.behave.enforce_96dpi, NULL);
1455 cmd_caret_browsing() {
1456 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1457 uzbl.behave.caret_browsing, NULL);
1461 cmd_cookie_handler() {
1462 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1463 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1464 if ((g_strcmp0(split[0], "sh") == 0) ||
1465 (g_strcmp0(split[0], "spawn") == 0)) {
1466 g_free (uzbl.behave.cookie_handler);
1467 uzbl.behave.cookie_handler =
1468 g_strdup_printf("sync_%s %s", split[0], split[1]);
1475 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1480 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1485 if(uzbl.behave.inject_html) {
1486 webkit_web_view_load_html_string (uzbl.gui.web_view,
1487 uzbl.behave.inject_html, NULL);
1496 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1497 uzbl.behave.modmask = 0;
1499 if(uzbl.behave.modkey)
1500 g_free(uzbl.behave.modkey);
1501 uzbl.behave.modkey = buf;
1503 for (i = 0; modkeys[i].key != NULL; i++) {
1504 if (g_strrstr(buf, modkeys[i].key))
1505 uzbl.behave.modmask |= modkeys[i].mask;
1511 if (*uzbl.net.useragent == ' ') {
1512 g_free (uzbl.net.useragent);
1513 uzbl.net.useragent = NULL;
1515 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1517 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1518 g_free(uzbl.net.useragent);
1519 uzbl.net.useragent = ua;
1525 gtk_widget_ref(uzbl.gui.scrolled_win);
1526 gtk_widget_ref(uzbl.gui.mainbar);
1527 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1528 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1530 if(uzbl.behave.status_top) {
1531 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1532 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1535 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1536 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1538 gtk_widget_unref(uzbl.gui.scrolled_win);
1539 gtk_widget_unref(uzbl.gui.mainbar);
1540 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1545 set_var_value(gchar *name, gchar *val) {
1546 uzbl_cmdprop *c = NULL;
1550 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1551 /* check for the variable type */
1552 if (c->type == TYPE_STR) {
1553 buf = expand_vars(val);
1556 } else if(c->type == TYPE_INT) {
1557 int *ip = (int *)c->ptr;
1558 buf = expand_vars(val);
1559 *ip = (int)strtoul(buf, &endp, 10);
1561 } else if (c->type == TYPE_FLOAT) {
1562 float *fp = (float *)c->ptr;
1563 buf = expand_vars(val);
1564 *fp = strtod(buf, &endp);
1568 /* invoke a command specific function */
1569 if(c->func) c->func();
1576 Behaviour *b = &uzbl.behave;
1578 if(b->html_buffer->str) {
1579 webkit_web_view_load_html_string (uzbl.gui.web_view,
1580 b->html_buffer->str, b->base_url);
1581 g_string_free(b->html_buffer, TRUE);
1582 b->html_buffer = g_string_new("");
1586 enum {M_CMD, M_HTML};
1588 parse_cmd_line(const char *ctl_line) {
1589 Behaviour *b = &uzbl.behave;
1592 if(b->mode == M_HTML) {
1593 len = strlen(b->html_endmarker);
1594 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1595 if(len == strlen(ctl_line)-1 &&
1596 !strncmp(b->html_endmarker, ctl_line, len)) {
1598 set_var_value("mode", "0");
1603 set_timeout(b->html_timeout);
1604 g_string_append(b->html_buffer, ctl_line);
1607 else if((ctl_line[0] == '#') /* Comments */
1608 || (ctl_line[0] == ' ')
1609 || (ctl_line[0] == '\n'))
1610 ; /* ignore these lines */
1611 else { /* parse a command */
1613 gchar **tokens = NULL;
1614 len = strlen(ctl_line);
1616 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1617 ctlstrip = g_strndup(ctl_line, len - 1);
1618 else ctlstrip = g_strdup(ctl_line);
1620 tokens = g_strsplit(ctlstrip, " ", 2);
1621 parse_command(tokens[0], tokens[1]);
1628 build_stream_name(int type, const gchar* dir) {
1630 State *s = &uzbl.state;
1633 xwin_str = itos((int)uzbl.xwin);
1635 str = g_strdup_printf
1636 ("%s/uzbl_fifo_%s", dir,
1637 s->instance_name ? s->instance_name : xwin_str);
1638 } else if (type == SOCKET) {
1639 str = g_strdup_printf
1640 ("%s/uzbl_socket_%s", dir,
1641 s->instance_name ? s->instance_name : xwin_str );
1648 control_fifo(GIOChannel *gio, GIOCondition condition) {
1649 if (uzbl.state.verbose)
1650 printf("triggered\n");
1655 if (condition & G_IO_HUP)
1656 g_error ("Fifo: Read end of pipe died!\n");
1659 g_error ("Fifo: GIOChannel broke\n");
1661 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1662 if (ret == G_IO_STATUS_ERROR) {
1663 g_error ("Fifo: Error reading: %s\n", err->message);
1667 parse_cmd_line(ctl_line);
1674 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1675 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1676 if (unlink(uzbl.comm.fifo_path) == -1)
1677 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1678 g_free(uzbl.comm.fifo_path);
1679 uzbl.comm.fifo_path = NULL;
1682 if (*dir == ' ') { /* space unsets the variable */
1687 GIOChannel *chan = NULL;
1688 GError *error = NULL;
1689 gchar *path = build_stream_name(FIFO, dir);
1691 if (!file_exists(path)) {
1692 if (mkfifo (path, 0666) == 0) {
1693 // 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.
1694 chan = g_io_channel_new_file(path, "r+", &error);
1696 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1697 if (uzbl.state.verbose)
1698 printf ("init_fifo: created successfully as %s\n", path);
1699 uzbl.comm.fifo_path = path;
1701 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1702 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1703 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1704 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1706 /* if we got this far, there was an error; cleanup */
1707 if (error) g_error_free (error);
1714 control_stdin(GIOChannel *gio, GIOCondition condition) {
1716 gchar *ctl_line = NULL;
1719 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1720 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1723 parse_cmd_line(ctl_line);
1731 GIOChannel *chan = NULL;
1732 GError *error = NULL;
1734 chan = g_io_channel_unix_new(fileno(stdin));
1736 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1737 g_error ("Stdin: could not add watch\n");
1739 if (uzbl.state.verbose)
1740 printf ("Stdin: watch added successfully\n");
1743 g_error ("Stdin: Error while opening: %s\n", error->message);
1745 if (error) g_error_free (error);
1749 control_socket(GIOChannel *chan) {
1750 struct sockaddr_un remote;
1751 char buffer[512], *ctl_line;
1753 int sock, clientsock, n, done;
1756 sock = g_io_channel_unix_get_fd(chan);
1758 memset (buffer, 0, sizeof (buffer));
1760 t = sizeof (remote);
1761 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1765 memset (temp, 0, sizeof (temp));
1766 n = recv (clientsock, temp, 128, 0);
1768 buffer[strlen (buffer)] = '\0';
1772 strcat (buffer, temp);
1775 if (strcmp (buffer, "\n") < 0) {
1776 buffer[strlen (buffer) - 1] = '\0';
1778 buffer[strlen (buffer)] = '\0';
1781 ctl_line = g_strdup(buffer);
1782 parse_cmd_line (ctl_line);
1785 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1786 GError *error = NULL;
1789 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1790 if (ret == G_IO_STATUS_ERROR)
1791 g_error ("Error reading: %s\n", error->message);
1793 printf("Got line %s (%u bytes) \n",ctl_line, len);
1795 parse_line(ctl_line);
1803 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1804 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1805 if (unlink(uzbl.comm.socket_path) == -1)
1806 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1807 g_free(uzbl.comm.socket_path);
1808 uzbl.comm.socket_path = NULL;
1816 GIOChannel *chan = NULL;
1818 struct sockaddr_un local;
1819 gchar *path = build_stream_name(SOCKET, dir);
1821 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1823 local.sun_family = AF_UNIX;
1824 strcpy (local.sun_path, path);
1825 unlink (local.sun_path);
1827 len = strlen (local.sun_path) + sizeof (local.sun_family);
1828 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1829 if (uzbl.state.verbose)
1830 printf ("init_socket: opened in %s\n", path);
1833 if( (chan = g_io_channel_unix_new(sock)) ) {
1834 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1835 uzbl.comm.socket_path = path;
1838 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1840 /* if we got this far, there was an error; cleanup */
1847 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1848 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1850 // this function may be called very early when the templates are not set (yet), hence the checks
1852 update_title (void) {
1853 Behaviour *b = &uzbl.behave;
1856 if (b->show_status) {
1857 if (b->title_format_short) {
1858 parsed = expand_template(b->title_format_short, FALSE);
1859 if (uzbl.gui.main_window)
1860 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1863 if (b->status_format) {
1864 parsed = expand_template(b->status_format, TRUE);
1865 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1868 if (b->status_background) {
1870 gdk_color_parse (b->status_background, &color);
1871 //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)
1872 if (uzbl.gui.main_window)
1873 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1876 if (b->title_format_long) {
1877 parsed = expand_template(b->title_format_long, FALSE);
1878 if (uzbl.gui.main_window)
1879 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1886 key_press_cb (GtkWidget* window, GdkEventKey* event)
1888 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1892 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1893 || 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)
1896 /* turn off insert mode (if always_insert_mode is not used) */
1897 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1898 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1903 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1906 if (event->keyval == GDK_Escape) {
1907 g_string_truncate(uzbl.state.keycmd, 0);
1909 dehilight(uzbl.gui.web_view, NULL);
1913 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1914 if (event->keyval == GDK_Insert) {
1916 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1917 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1919 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1922 g_string_append (uzbl.state.keycmd, str);
1929 if (event->keyval == GDK_BackSpace)
1930 keycmd_bs(NULL, NULL);
1932 gboolean key_ret = FALSE;
1933 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1935 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1937 run_keycmd(key_ret);
1939 if (key_ret) return (!uzbl.behave.insert_mode);
1944 run_keycmd(const gboolean key_ret) {
1945 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1947 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1948 g_string_truncate(uzbl.state.keycmd, 0);
1949 parse_command(act->name, act->param);
1953 /* try if it's an incremental keycmd or one that takes args, and run it */
1954 GString* short_keys = g_string_new ("");
1955 GString* short_keys_inc = g_string_new ("");
1957 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1958 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1959 g_string_assign(short_keys_inc, short_keys->str);
1960 g_string_append_c(short_keys, '_');
1961 g_string_append_c(short_keys_inc, '*');
1963 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1964 /* run normal cmds only if return was pressed */
1965 exec_paramcmd(act, i);
1966 g_string_truncate(uzbl.state.keycmd, 0);
1968 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1969 if (key_ret) /* just quit the incremental command on return */
1970 g_string_truncate(uzbl.state.keycmd, 0);
1971 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1975 g_string_truncate(short_keys, short_keys->len - 1);
1977 g_string_free (short_keys, TRUE);
1978 g_string_free (short_keys_inc, TRUE);
1982 exec_paramcmd(const Action *act, const guint i) {
1983 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1984 GString *actionname = g_string_new ("");
1985 GString *actionparam = g_string_new ("");
1986 g_string_erase (parampart, 0, i+1);
1988 g_string_printf (actionname, act->name, parampart->str);
1990 g_string_printf (actionparam, act->param, parampart->str);
1991 parse_command(actionname->str, actionparam->str);
1992 g_string_free(actionname, TRUE);
1993 g_string_free(actionparam, TRUE);
1994 g_string_free(parampart, TRUE);
2002 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2003 //main_window_ref = g_object_ref(scrolled_window);
2004 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
2006 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2007 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2009 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2011 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2012 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2014 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2015 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2016 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2017 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2018 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2021 return scrolled_window;
2028 g->mainbar = gtk_hbox_new (FALSE, 0);
2030 /* keep a reference to the bar so we can re-pack it at runtime*/
2031 //sbar_ref = g_object_ref(g->mainbar);
2033 g->mainbar_label = gtk_label_new ("");
2034 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2035 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2036 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2037 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2038 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2039 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2044 GtkWidget* create_window () {
2045 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2046 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2047 gtk_widget_set_name (window, "Uzbl browser");
2048 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2049 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2055 GtkPlug* create_plug () {
2056 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2057 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2058 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2065 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2067 If actname is one that calls an external command, this function will inject
2068 newargs in front of the user-provided args in that command line. They will
2069 come become after the body of the script (in sh) or after the name of
2070 the command to execute (in spawn).
2071 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2072 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2074 The return value consist of two strings: the action (sh, ...) and its args.
2076 If act is not one that calls an external command, then the given action merely
2079 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2080 gchar *actdup = g_strdup(actname);
2081 g_array_append_val(rets, actdup);
2083 if ((g_strcmp0(actname, "spawn") == 0) ||
2084 (g_strcmp0(actname, "sh") == 0) ||
2085 (g_strcmp0(actname, "sync_spawn") == 0) ||
2086 (g_strcmp0(actname, "sync_sh") == 0)) {
2088 GString *a = g_string_new("");
2089 gchar **spawnparts = split_quoted(origargs, FALSE);
2090 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2091 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2093 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2094 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2096 g_array_append_val(rets, a->str);
2097 g_string_free(a, FALSE);
2098 g_strfreev(spawnparts);
2100 gchar *origdup = g_strdup(origargs);
2101 g_array_append_val(rets, origdup);
2103 return (gchar**)g_array_free(rets, FALSE);
2107 run_handler (const gchar *act, const gchar *args) {
2108 /* Consider this code a temporary hack to make the handlers usable.
2109 In practice, all this splicing, injection, and reconstruction is
2110 inefficient, annoying and hard to manage. Potential pitfalls arise
2111 when the handler specific args 1) are not quoted (the handler
2112 callbacks should take care of this) 2) are quoted but interfere
2113 with the users' own quotation. A more ideal solution is
2114 to refactor parse_command so that it doesn't just take a string
2115 and execute it; rather than that, we should have a function which
2116 returns the argument vector parsed from the string. This vector
2117 could be modified (e.g. insert additional args into it) before
2118 passing it to the next function that actually executes it. Though
2119 it still isn't perfect for chain actions.. will reconsider & re-
2120 factor when I have the time. -duc */
2122 char **parts = g_strsplit(act, " ", 2);
2124 if (g_strcmp0(parts[0], "chain") == 0) {
2125 GString *newargs = g_string_new("");
2126 gchar **chainparts = split_quoted(parts[1], FALSE);
2128 /* for every argument in the chain, inject the handler args
2129 and make sure the new parts are wrapped in quotes */
2130 gchar **cp = chainparts;
2132 gchar *quotless = NULL;
2133 gchar **spliced_quotless = NULL; // sigh -_-;
2134 gchar **inpart = NULL;
2137 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2139 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2140 } else quotless = g_strdup(*cp);
2142 spliced_quotless = g_strsplit(quotless, " ", 2);
2143 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2144 g_strfreev(spliced_quotless);
2146 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2152 parse_command(parts[0], &(newargs->str[1]));
2153 g_string_free(newargs, TRUE);
2154 g_strfreev(chainparts);
2157 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2158 parse_command(inparts[0], inparts[1]);
2166 add_binding (const gchar *key, const gchar *act) {
2167 char **parts = g_strsplit(act, " ", 2);
2174 if (uzbl.state.verbose)
2175 printf ("Binding %-10s : %s\n", key, act);
2176 action = new_action(parts[0], parts[1]);
2178 if (g_hash_table_remove (uzbl.bindings, key))
2179 g_warning ("Overwriting existing binding for \"%s\"", key);
2180 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2185 get_xdg_var (XDG_Var xdg) {
2186 const gchar* actual_value = getenv (xdg.environmental);
2187 const gchar* home = getenv ("HOME");
2189 gchar* return_value = str_replace ("~", home, actual_value);
2191 if (! actual_value || strcmp (actual_value, "") == 0) {
2192 if (xdg.default_value) {
2193 return_value = str_replace ("~", home, xdg.default_value);
2195 return_value = NULL;
2198 return return_value;
2202 find_xdg_file (int xdg_type, char* filename) {
2203 /* xdg_type = 0 => config
2204 xdg_type = 1 => data
2205 xdg_type = 2 => cache*/
2207 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2208 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2211 gchar* temporary_string;
2215 if (! file_exists (temporary_file) && xdg_type != 2) {
2216 buf = get_xdg_var (XDG[3 + xdg_type]);
2217 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2220 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2221 g_free (temporary_file);
2222 temporary_file = g_strconcat (temporary_string, filename, NULL);
2226 //g_free (temporary_string); - segfaults.
2228 if (file_exists (temporary_file)) {
2229 return temporary_file;
2236 State *s = &uzbl.state;
2237 Network *n = &uzbl.net;
2239 for (i = 0; default_config[i].command != NULL; i++) {
2240 parse_cmd_line(default_config[i].command);
2243 if (!s->config_file) {
2244 s->config_file = find_xdg_file (0, "/uzbl/config");
2247 if (s->config_file) {
2248 GArray* lines = read_file_by_line (s->config_file);
2252 while ((line = g_array_index(lines, gchar*, i))) {
2253 parse_cmd_line (line);
2257 g_array_free (lines, TRUE);
2259 if (uzbl.state.verbose)
2260 printf ("No configuration file loaded.\n");
2263 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2266 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2269 if (!uzbl.behave.cookie_handler)
2272 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2273 GString *s = g_string_new ("");
2274 SoupURI * soup_uri = soup_message_get_uri(msg);
2275 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2276 run_handler(uzbl.behave.cookie_handler, s->str);
2278 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2279 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2280 if ( p != NULL ) *p = '\0';
2281 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2283 if (uzbl.comm.sync_stdout)
2284 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2286 g_string_free(s, TRUE);
2290 save_cookies (SoupMessage *msg, gpointer user_data){
2294 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2295 cookie = soup_cookie_to_set_cookie_header(ck->data);
2296 SoupURI * soup_uri = soup_message_get_uri(msg);
2297 GString *s = g_string_new ("");
2298 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2299 run_handler(uzbl.behave.cookie_handler, s->str);
2301 g_string_free(s, TRUE);
2306 /* --- WEBINSPECTOR --- */
2308 hide_window_cb(GtkWidget *widget, gpointer data) {
2311 gtk_widget_hide(widget);
2314 static WebKitWebView*
2315 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2318 (void) web_inspector;
2319 GtkWidget* scrolled_window;
2320 GtkWidget* new_web_view;
2323 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2324 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2325 G_CALLBACK(hide_window_cb), NULL);
2327 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2328 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2329 gtk_widget_show(g->inspector_window);
2331 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2332 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2333 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2334 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2335 gtk_widget_show(scrolled_window);
2337 new_web_view = webkit_web_view_new();
2338 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2340 return WEBKIT_WEB_VIEW(new_web_view);
2344 inspector_show_window_cb (WebKitWebInspector* inspector){
2346 gtk_widget_show(uzbl.gui.inspector_window);
2350 /* TODO: Add variables and code to make use of these functions */
2352 inspector_close_window_cb (WebKitWebInspector* inspector){
2358 inspector_attach_window_cb (WebKitWebInspector* inspector){
2364 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2370 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2376 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2382 set_up_inspector() {
2384 WebKitWebSettings *settings = view_settings();
2385 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2387 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2388 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2389 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2390 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2391 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2392 if (uzbl.gui.main_window) {
2393 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2394 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2397 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2401 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2403 uzbl_cmdprop *c = v;
2408 if(c->type == TYPE_STR)
2409 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2410 else if(c->type == TYPE_INT)
2411 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2415 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2419 printf("bind %s = %s %s\n", (char *)k ,
2420 (char *)a->name, a->param?(char *)a->param:"");
2425 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2426 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2431 main (int argc, char* argv[]) {
2432 gtk_init (&argc, &argv);
2433 if (!g_thread_supported ())
2434 g_thread_init (NULL);
2435 uzbl.state.executable_path = g_strdup(argv[0]);
2436 uzbl.state.selected_url = NULL;
2437 uzbl.state.searchtx = NULL;
2439 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2440 g_option_context_add_main_entries (context, entries, NULL);
2441 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2442 g_option_context_parse (context, &argc, &argv, NULL);
2443 g_option_context_free(context);
2445 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2446 gboolean verbose_override = uzbl.state.verbose;
2448 /* initialize hash table */
2449 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2451 uzbl.net.soup_session = webkit_get_default_session();
2452 uzbl.state.keycmd = g_string_new("");
2454 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2455 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2456 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2457 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2458 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2459 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2462 if(uname(&uzbl.state.unameinfo) == -1)
2463 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2465 uzbl.gui.sbar.progress_s = g_strdup("=");
2466 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2467 uzbl.gui.sbar.progress_w = 10;
2469 /* HTML mode defaults*/
2470 uzbl.behave.html_buffer = g_string_new("");
2471 uzbl.behave.html_endmarker = g_strdup(".");
2472 uzbl.behave.html_timeout = 60;
2473 uzbl.behave.base_url = g_strdup("http://invalid");
2475 /* default mode indicators */
2476 uzbl.behave.insert_indicator = g_strdup("I");
2477 uzbl.behave.cmd_indicator = g_strdup("C");
2481 make_var_to_name_hash();
2483 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2485 uzbl.gui.scrolled_win = create_browser();
2488 /* initial packing */
2489 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2490 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2492 if (uzbl.state.socket_id) {
2493 uzbl.gui.plug = create_plug ();
2494 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2495 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2497 uzbl.gui.main_window = create_window ();
2498 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2499 gtk_widget_show_all (uzbl.gui.main_window);
2500 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2503 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2505 if (uzbl.state.verbose) {
2506 printf("Uzbl start location: %s\n", argv[0]);
2507 if (uzbl.state.socket_id)
2508 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2510 printf("window_id %i\n",(int) uzbl.xwin);
2511 printf("pid %i\n", getpid ());
2512 printf("name: %s\n", uzbl.state.instance_name);
2515 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2516 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2517 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2518 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2519 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2523 if (!uzbl.behave.show_status)
2524 gtk_widget_hide(uzbl.gui.mainbar);
2533 if (verbose_override > uzbl.state.verbose)
2534 uzbl.state.verbose = verbose_override;
2537 set_var_value("uri", uri_override);
2538 g_free(uri_override);
2539 } else if (uzbl.state.uri)
2540 cmd_load_uri(uzbl.gui.web_view, NULL);
2545 return EXIT_SUCCESS;
2548 /* vi: set et ts=4: */