1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
39 #include <gdk/gdkkeysyms.h>
40 #include <sys/socket.h>
42 #include <sys/types.h>
44 #include <sys/utsname.h>
46 #include <webkit/webkit.h>
47 #include <libsoup/soup.h>
60 typedef void (*Command)(WebKitWebView*, GArray *argv);
64 /* commandline arguments (set initial values for the state variables) */
66 GOptionEntry entries[] =
68 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
69 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
70 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
71 "Whether to print all messages or just errors.", NULL },
72 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
73 "Name of the current instance (defaults to Xorg window id)", "NAME" },
74 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
75 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
76 { NULL, 0, 0, 0, NULL, NULL, NULL }
79 /* associate command names to their properties */
80 typedef const struct {
87 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
89 /* an abbreviation to help keep the table's width humane */
90 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
95 } var_name_to_ptr[] = {
96 /* variable name pointer to variable in code type dump callback function */
97 /* --------------------------------------------------------------------------------------- */
98 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
99 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
118 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
119 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
120 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
121 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
122 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
123 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
124 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
125 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
126 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
127 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
128 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
129 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
130 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
131 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
132 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
133 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
134 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
135 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
136 /* exported WebKitWebSettings properties */
137 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
138 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
139 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
140 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
141 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
142 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
143 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
144 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
145 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
146 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
147 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
148 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
149 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
150 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
151 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
152 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
154 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
155 }, *n2v_p = var_name_to_ptr;
161 { "SHIFT", GDK_SHIFT_MASK }, // shift
162 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
163 { "CONTROL", GDK_CONTROL_MASK }, // control
164 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
165 { "MOD2", GDK_MOD2_MASK }, // 5th mod
166 { "MOD3", GDK_MOD3_MASK }, // 6th mod
167 { "MOD4", GDK_MOD4_MASK }, // 7th mod
168 { "MOD5", GDK_MOD5_MASK }, // 8th mod
169 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
170 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
171 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
172 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
173 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
174 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
175 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
176 { "META", GDK_META_MASK }, // meta (since 2.10)
181 /* construct a hash from the var_name_to_ptr array for quick access */
183 make_var_to_name_hash() {
184 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
186 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
191 /* --- UTILITY FUNCTIONS --- */
193 expand_vars(char *s) {
196 char ret[256], *vend;
197 GString *buf = g_string_new("");
202 g_string_append_c(buf, *++s);
210 if( (vend = strchr(s, upto)) ||
211 (vend = strchr(s, '\0')) ) {
212 strncpy(ret, s, vend-s);
214 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
215 if(c->type == TYPE_STR)
216 g_string_append(buf, (gchar *)*c->ptr);
217 else if(c->type == TYPE_INT) {
218 char *b = itos((int)*c->ptr);
219 g_string_append(buf, b);
223 if(upto == ' ') s = vend;
229 g_string_append_c(buf, *s);
234 return g_string_free(buf, FALSE);
241 snprintf(tmp, sizeof(tmp), "%i", val);
242 return g_strdup(tmp);
246 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
249 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
252 str_replace (const char* search, const char* replace, const char* string) {
256 buf = g_strsplit (string, search, -1);
257 ret = g_strjoinv (replace, buf);
258 g_strfreev(buf); // somebody said this segfaults
264 read_file_by_line (gchar *path) {
265 GIOChannel *chan = NULL;
266 gchar *readbuf = NULL;
268 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
271 chan = g_io_channel_new_file(path, "r", NULL);
274 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
275 const gchar* val = g_strdup (readbuf);
276 g_array_append_val (lines, val);
281 g_io_channel_unref (chan);
283 fprintf(stderr, "File '%s' not be read.\n", path);
290 gchar* parseenv (char* string) {
291 extern char** environ;
292 gchar* tmpstr = NULL;
296 while (environ[i] != NULL) {
297 gchar** env = g_strsplit (environ[i], "=", 2);
298 gchar* envname = g_strconcat ("$", env[0], NULL);
300 if (g_strrstr (string, envname) != NULL) {
301 tmpstr = g_strdup(string);
303 string = str_replace(envname, env[1], tmpstr);
308 g_strfreev (env); // somebody said this breaks uzbl
316 setup_signal(int signr, sigfunc *shandler) {
317 struct sigaction nh, oh;
319 nh.sa_handler = shandler;
320 sigemptyset(&nh.sa_mask);
323 if(sigaction(signr, &nh, &oh) < 0)
331 if (uzbl.behave.fifo_dir)
332 unlink (uzbl.comm.fifo_path);
333 if (uzbl.behave.socket_dir)
334 unlink (uzbl.comm.socket_path);
336 g_free(uzbl.state.executable_path);
337 g_string_free(uzbl.state.keycmd, TRUE);
338 g_hash_table_destroy(uzbl.bindings);
339 g_hash_table_destroy(uzbl.behave.commands);
342 /* used for html_mode_timeout
343 * be sure to extend this function to use
344 * more timers if needed in other places
347 set_timeout(int seconds) {
349 memset(&t, 0, sizeof t);
351 t.it_value.tv_sec = seconds;
352 t.it_value.tv_usec = 0;
353 setitimer(ITIMER_REAL, &t, NULL);
356 /* --- SIGNAL HANDLER --- */
359 catch_sigterm(int s) {
365 catch_sigint(int s) {
375 set_var_value("mode", "0");
380 /* --- CALLBACKS --- */
383 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
386 (void) navigation_action;
387 (void) policy_decision;
389 const gchar* uri = webkit_network_request_get_uri (request);
390 if (uzbl.state.verbose)
391 printf("New window requested -> %s \n", uri);
392 new_window_load_uri(uri);
397 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
402 /* If we can display it, let's display it... */
403 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
404 webkit_web_policy_decision_use (policy_decision);
408 /* ...everything we can't displayed is downloaded */
409 webkit_web_policy_decision_download (policy_decision);
414 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
418 if (uzbl.state.selected_url != NULL) {
419 if (uzbl.state.verbose)
420 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
421 new_window_load_uri(uzbl.state.selected_url);
423 if (uzbl.state.verbose)
424 printf("New web view -> %s\n","Nothing to open, exiting");
430 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
433 if (uzbl.behave.download_handler) {
434 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
435 if (uzbl.state.verbose)
436 printf("Download -> %s\n",uri);
437 /* if urls not escaped, we may have to escape and quote uri before this call */
438 run_handler(uzbl.behave.download_handler, uri);
443 /* scroll a bar in a given direction */
445 scroll (GtkAdjustment* bar, GArray *argv) {
449 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
450 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
451 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
455 scroll_begin(WebKitWebView* page, GArray *argv) {
456 (void) page; (void) argv;
457 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
461 scroll_end(WebKitWebView* page, GArray *argv) {
462 (void) page; (void) argv;
463 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
464 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
468 scroll_vert(WebKitWebView* page, GArray *argv) {
470 scroll(uzbl.gui.bar_v, argv);
474 scroll_horz(WebKitWebView* page, GArray *argv) {
476 scroll(uzbl.gui.bar_h, argv);
481 if (!uzbl.behave.show_status) {
482 gtk_widget_hide(uzbl.gui.mainbar);
484 gtk_widget_show(uzbl.gui.mainbar);
490 toggle_status_cb (WebKitWebView* page, GArray *argv) {
494 if (uzbl.behave.show_status) {
495 gtk_widget_hide(uzbl.gui.mainbar);
497 gtk_widget_show(uzbl.gui.mainbar);
499 uzbl.behave.show_status = !uzbl.behave.show_status;
504 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
508 //Set selected_url state variable
509 g_free(uzbl.state.selected_url);
510 uzbl.state.selected_url = NULL;
512 uzbl.state.selected_url = g_strdup(link);
518 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
522 if (uzbl.gui.main_title)
523 g_free (uzbl.gui.main_title);
524 uzbl.gui.main_title = g_strdup (title);
529 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
532 uzbl.gui.sbar.load_progress = progress;
537 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
541 if (uzbl.behave.load_finish_handler)
542 run_handler(uzbl.behave.load_finish_handler, "");
546 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
550 uzbl.gui.sbar.load_progress = 0;
551 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
552 if (uzbl.behave.load_start_handler)
553 run_handler(uzbl.behave.load_start_handler, "");
557 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
560 g_free (uzbl.state.uri);
561 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
562 uzbl.state.uri = g_string_free (newuri, FALSE);
563 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
564 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
567 if (uzbl.behave.load_commit_handler)
568 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
572 destroy_cb (GtkWidget* widget, gpointer data) {
580 if (uzbl.behave.history_handler) {
582 struct tm * timeinfo;
585 timeinfo = localtime ( &rawtime );
586 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
587 run_handler(uzbl.behave.history_handler, date);
592 /* VIEW funcs (little webkit wrappers) */
593 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
595 VIEWFUNC(reload_bypass_cache)
596 VIEWFUNC(stop_loading)
603 /* -- command to callback/function map for things we cannot attach to any signals */
604 static struct {char *name; Command command[2];} cmdlist[] =
605 { /* key function no_split */
606 { "back", {view_go_back, 0} },
607 { "forward", {view_go_forward, 0} },
608 { "scroll_vert", {scroll_vert, 0} },
609 { "scroll_horz", {scroll_horz, 0} },
610 { "scroll_begin", {scroll_begin, 0} },
611 { "scroll_end", {scroll_end, 0} },
612 { "reload", {view_reload, 0}, },
613 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
614 { "stop", {view_stop_loading, 0}, },
615 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
616 { "zoom_out", {view_zoom_out, 0}, },
617 { "uri", {load_uri, NOSPLIT} },
618 { "js", {run_js, NOSPLIT} },
619 { "script", {run_external_js, 0} },
620 { "toggle_status", {toggle_status_cb, 0} },
621 { "spawn", {spawn, 0} },
622 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
623 { "sh", {spawn_sh, 0} },
624 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
625 { "exit", {close_uzbl, 0} },
626 { "search", {search_forward_text, NOSPLIT} },
627 { "search_reverse", {search_reverse_text, NOSPLIT} },
628 { "dehilight", {dehilight, 0} },
629 { "toggle_insert_mode", {toggle_insert_mode, 0} },
630 { "set", {set_var, NOSPLIT} },
631 //{ "get", {get_var, NOSPLIT} },
632 { "bind", {act_bind, NOSPLIT} },
633 { "dump_config", {act_dump_config, 0} },
634 { "keycmd", {keycmd, NOSPLIT} },
635 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
636 { "keycmd_bs", {keycmd_bs, 0} },
637 { "chain", {chain, 0} },
638 { "print", {print, NOSPLIT} }
645 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
647 for (i = 0; i < LENGTH(cmdlist); i++)
648 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
651 /* -- CORE FUNCTIONS -- */
654 free_action(gpointer act) {
655 Action *action = (Action*)act;
656 g_free(action->name);
658 g_free(action->param);
663 new_action(const gchar *name, const gchar *param) {
664 Action *action = g_new(Action, 1);
666 action->name = g_strdup(name);
668 action->param = g_strdup(param);
670 action->param = NULL;
676 file_exists (const char * filename) {
677 return (access(filename, F_OK) == 0);
681 set_var(WebKitWebView *page, GArray *argv) {
683 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
684 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
685 set_var_value(g_strstrip(split[0]), value);
691 print(WebKitWebView *page, GArray *argv) {
695 buf = expand_vars(argv_idx(argv, 0));
701 act_bind(WebKitWebView *page, GArray *argv) {
703 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
704 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
705 add_binding(g_strstrip(split[0]), value);
717 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
720 if (argv_idx(argv, 0)) {
721 if (strcmp (argv_idx(argv, 0), "0") == 0) {
722 uzbl.behave.insert_mode = FALSE;
724 uzbl.behave.insert_mode = TRUE;
727 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
734 load_uri (WebKitWebView *web_view, GArray *argv) {
735 if (argv_idx(argv, 0)) {
736 GString* newuri = g_string_new (argv_idx(argv, 0));
737 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
738 run_js(web_view, argv);
741 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
742 g_string_prepend (newuri, "http://");
743 /* if we do handle cookies, ask our handler for them */
744 webkit_web_view_load_uri (web_view, newuri->str);
745 g_string_free (newuri, TRUE);
750 run_js (WebKitWebView * web_view, GArray *argv) {
751 if (argv_idx(argv, 0))
752 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
756 run_external_js (WebKitWebView * web_view, GArray *argv) {
757 if (argv_idx(argv, 0)) {
758 GArray* lines = read_file_by_line (argv_idx (argv, 0));
763 while ((line = g_array_index(lines, gchar*, i))) {
765 js = g_strdup (line);
767 gchar* newjs = g_strconcat (js, line, NULL);
774 if (uzbl.state.verbose)
775 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
777 if (argv_idx (argv, 1)) {
778 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
782 webkit_web_view_execute_script (web_view, js);
784 g_array_free (lines, TRUE);
789 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
790 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
791 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
792 webkit_web_view_unmark_text_matches (page);
793 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
794 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
798 if (uzbl.state.searchtx) {
799 if (uzbl.state.verbose)
800 printf ("Searching: %s\n", uzbl.state.searchtx);
801 webkit_web_view_set_highlight_text_matches (page, TRUE);
802 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
807 search_forward_text (WebKitWebView *page, GArray *argv) {
808 search_text(page, argv, TRUE);
812 search_reverse_text (WebKitWebView *page, GArray *argv) {
813 search_text(page, argv, FALSE);
817 dehilight (WebKitWebView *page, GArray *argv) {
819 webkit_web_view_set_highlight_text_matches (page, FALSE);
824 new_window_load_uri (const gchar * uri) {
825 GString* to_execute = g_string_new ("");
826 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
828 for (i = 0; entries[i].long_name != NULL; i++) {
829 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
830 gchar** str = (gchar**)entries[i].arg_data;
832 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
836 if (uzbl.state.verbose)
837 printf("\n%s\n", to_execute->str);
838 g_spawn_command_line_async (to_execute->str, NULL);
839 g_string_free (to_execute, TRUE);
843 chain (WebKitWebView *page, GArray *argv) {
846 gchar **parts = NULL;
848 while ((a = argv_idx(argv, i++))) {
849 parts = g_strsplit (a, " ", 2);
850 parse_command(parts[0], parts[1]);
856 keycmd (WebKitWebView *page, GArray *argv) {
859 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
865 keycmd_nl (WebKitWebView *page, GArray *argv) {
868 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
874 keycmd_bs (WebKitWebView *page, GArray *argv) {
877 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
882 close_uzbl (WebKitWebView *page, GArray *argv) {
888 /* --Statusbar functions-- */
890 build_progressbar_ascii(int percent) {
891 int width=uzbl.gui.sbar.progress_w;
894 GString *bar = g_string_new("");
896 l = (double)percent*((double)width/100.);
897 l = (int)(l+.5)>=(int)l ? l+.5 : l;
899 for(i=0; i<(int)l; i++)
900 g_string_append(bar, uzbl.gui.sbar.progress_s);
903 g_string_append(bar, uzbl.gui.sbar.progress_u);
905 return g_string_free(bar, FALSE);
910 const GScannerConfig scan_config = {
913 ) /* cset_skip_characters */,
918 ) /* cset_identifier_first */,
925 ) /* cset_identifier_nth */,
926 ( "" ) /* cpair_comment_single */,
928 TRUE /* case_sensitive */,
930 FALSE /* skip_comment_multi */,
931 FALSE /* skip_comment_single */,
932 FALSE /* scan_comment_multi */,
933 TRUE /* scan_identifier */,
934 TRUE /* scan_identifier_1char */,
935 FALSE /* scan_identifier_NULL */,
936 TRUE /* scan_symbols */,
937 FALSE /* scan_binary */,
938 FALSE /* scan_octal */,
939 FALSE /* scan_float */,
940 FALSE /* scan_hex */,
941 FALSE /* scan_hex_dollar */,
942 FALSE /* scan_string_sq */,
943 FALSE /* scan_string_dq */,
944 TRUE /* numbers_2_int */,
945 FALSE /* int_2_float */,
946 FALSE /* identifier_2_string */,
947 FALSE /* char_2_token */,
948 FALSE /* symbol_2_token */,
949 TRUE /* scope_0_fallback */,
954 uzbl.scan = g_scanner_new(&scan_config);
955 while(symp->symbol_name) {
956 g_scanner_scope_add_symbol(uzbl.scan, 0,
958 GINT_TO_POINTER(symp->symbol_token));
964 expand_template(const char *template, gboolean escape_markup) {
965 if(!template) return NULL;
967 GTokenType token = G_TOKEN_NONE;
968 GString *ret = g_string_new("");
972 g_scanner_input_text(uzbl.scan, template, strlen(template));
973 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
974 token = g_scanner_get_next_token(uzbl.scan);
976 if(token == G_TOKEN_SYMBOL) {
977 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
981 buf = uzbl.state.uri?
982 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
983 g_string_append(ret, buf);
987 g_string_append(ret, uzbl.state.uri?
988 uzbl.state.uri:g_strdup(""));
991 buf = itos(uzbl.gui.sbar.load_progress);
992 g_string_append(ret, buf);
995 case SYM_LOADPRGSBAR:
996 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
997 g_string_append(ret, buf);
1002 buf = uzbl.gui.main_title?
1003 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1004 g_string_append(ret, buf);
1008 g_string_append(ret, uzbl.gui.main_title?
1009 uzbl.gui.main_title:g_strdup(""));
1011 case SYM_SELECTED_URI:
1013 buf = uzbl.state.selected_url?
1014 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1015 g_string_append(ret, buf);
1019 g_string_append(ret, uzbl.state.selected_url?
1020 uzbl.state.selected_url:g_strdup(""));
1023 buf = itos(uzbl.xwin);
1024 g_string_append(ret,
1025 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1030 buf = uzbl.state.keycmd->str?
1031 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1032 g_string_append(ret, buf);
1036 g_string_append(ret, uzbl.state.keycmd->str?
1037 uzbl.state.keycmd->str:g_strdup(""));
1040 g_string_append(ret,
1041 uzbl.behave.insert_mode?
1042 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1045 g_string_append(ret,
1046 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1048 /* useragent syms */
1050 buf = itos(WEBKIT_MAJOR_VERSION);
1051 g_string_append(ret, buf);
1055 buf = itos(WEBKIT_MINOR_VERSION);
1056 g_string_append(ret, buf);
1060 buf = itos(WEBKIT_MICRO_VERSION);
1061 g_string_append(ret, buf);
1065 g_string_append(ret, uzbl.state.unameinfo.sysname);
1068 g_string_append(ret, uzbl.state.unameinfo.nodename);
1071 g_string_append(ret, uzbl.state.unameinfo.release);
1074 g_string_append(ret, uzbl.state.unameinfo.version);
1077 g_string_append(ret, uzbl.state.unameinfo.machine);
1080 g_string_append(ret, ARCH);
1083 case SYM_DOMAINNAME:
1084 g_string_append(ret, uzbl.state.unameinfo.domainname);
1088 g_string_append(ret, COMMIT);
1094 else if(token == G_TOKEN_INT) {
1095 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1096 g_string_append(ret, buf);
1099 else if(token == G_TOKEN_IDENTIFIER) {
1100 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1102 else if(token == G_TOKEN_CHAR) {
1103 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1107 return g_string_free(ret, FALSE);
1109 /* --End Statusbar functions-- */
1112 sharg_append(GArray *a, const gchar *str) {
1113 const gchar *s = (str ? str : "");
1114 g_array_append_val(a, s);
1117 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1119 run_command (const gchar *command, const guint npre, const gchar **args,
1120 const gboolean sync, char **output_stdout) {
1121 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1124 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1125 gchar *pid = itos(getpid());
1126 gchar *xwin = itos(uzbl.xwin);
1128 sharg_append(a, command);
1129 for (i = 0; i < npre; i++) /* add n args before the default vars */
1130 sharg_append(a, args[i]);
1131 sharg_append(a, uzbl.state.config_file);
1132 sharg_append(a, pid);
1133 sharg_append(a, xwin);
1134 sharg_append(a, uzbl.comm.fifo_path);
1135 sharg_append(a, uzbl.comm.socket_path);
1136 sharg_append(a, uzbl.state.uri);
1137 sharg_append(a, uzbl.gui.main_title);
1139 for (i = npre; i < g_strv_length((gchar**)args); i++)
1140 sharg_append(a, args[i]);
1144 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1146 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1147 NULL, NULL, output_stdout, NULL, NULL, &err);
1148 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1149 NULL, NULL, NULL, &err);
1151 if (uzbl.state.verbose) {
1152 GString *s = g_string_new("spawned:");
1153 for (i = 0; i < (a->len); i++) {
1154 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1155 g_string_append_printf(s, " %s", qarg);
1158 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1159 printf("%s\n", s->str);
1160 g_string_free(s, TRUE);
1162 printf("Stdout: %s\n", *output_stdout);
1166 g_printerr("error on run_command: %s\n", err->message);
1171 g_array_free (a, TRUE);
1176 split_quoted(const gchar* src, const gboolean unquote) {
1177 /* split on unquoted space, return array of strings;
1178 remove a layer of quotes and backslashes if unquote */
1179 if (!src) return NULL;
1181 gboolean dq = FALSE;
1182 gboolean sq = FALSE;
1183 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1184 GString *s = g_string_new ("");
1188 for (p = src; *p != '\0'; p++) {
1189 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1190 else if (*p == '\\') { g_string_append_c(s, *p++);
1191 g_string_append_c(s, *p); }
1192 else if ((*p == '"') && unquote && !sq) dq = !dq;
1193 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1195 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1196 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1198 else if ((*p == ' ') && !dq && !sq) {
1199 dup = g_strdup(s->str);
1200 g_array_append_val(a, dup);
1201 g_string_truncate(s, 0);
1202 } else g_string_append_c(s, *p);
1204 dup = g_strdup(s->str);
1205 g_array_append_val(a, dup);
1206 ret = (gchar**)a->data;
1207 g_array_free (a, FALSE);
1208 g_string_free (s, TRUE);
1213 spawn(WebKitWebView *web_view, GArray *argv) {
1215 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1216 if (argv_idx(argv, 0))
1217 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1221 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1224 if (argv_idx(argv, 0))
1225 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1226 TRUE, &uzbl.comm.sync_stdout);
1230 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1232 if (!uzbl.behave.shell_cmd) {
1233 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1238 gchar *spacer = g_strdup("");
1239 g_array_insert_val(argv, 1, spacer);
1240 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1242 for (i = 1; i < g_strv_length(cmd); i++)
1243 g_array_prepend_val(argv, cmd[i]);
1245 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1251 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1253 if (!uzbl.behave.shell_cmd) {
1254 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1259 gchar *spacer = g_strdup("");
1260 g_array_insert_val(argv, 1, spacer);
1261 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1263 for (i = 1; i < g_strv_length(cmd); i++)
1264 g_array_prepend_val(argv, cmd[i]);
1266 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1267 TRUE, &uzbl.comm.sync_stdout);
1273 parse_command(const char *cmd, const char *param) {
1276 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1279 gchar **par = split_quoted(param, TRUE);
1280 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1282 if (c[1] == NOSPLIT) { /* don't split */
1283 sharg_append(a, param);
1285 for (i = 0; i < g_strv_length(par); i++)
1286 sharg_append(a, par[i]);
1288 c[0](uzbl.gui.web_view, a);
1290 g_array_free (a, TRUE);
1293 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1300 if(*uzbl.net.proxy_url == ' '
1301 || uzbl.net.proxy_url == NULL) {
1302 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1303 (GType) SOUP_SESSION_PROXY_URI);
1306 suri = soup_uri_new(uzbl.net.proxy_url);
1307 g_object_set(G_OBJECT(uzbl.net.soup_session),
1308 SOUP_SESSION_PROXY_URI,
1310 soup_uri_free(suri);
1317 if(file_exists(uzbl.gui.icon)) {
1318 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1320 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1322 g_free (uzbl.gui.icon);
1327 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1328 g_array_append_val (a, uzbl.state.uri);
1329 load_uri(uzbl.gui.web_view, a);
1330 g_array_free (a, TRUE);
1334 cmd_always_insert_mode() {
1335 uzbl.behave.insert_mode =
1336 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1342 g_object_set(G_OBJECT(uzbl.net.soup_session),
1343 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1347 cmd_max_conns_host() {
1348 g_object_set(G_OBJECT(uzbl.net.soup_session),
1349 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1354 soup_session_remove_feature
1355 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1356 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1357 /*g_free(uzbl.net.soup_logger);*/
1359 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1360 soup_session_add_feature(uzbl.net.soup_session,
1361 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1364 static WebKitWebSettings*
1366 return webkit_web_view_get_settings(uzbl.gui.web_view);
1371 WebKitWebSettings *ws = view_settings();
1372 if (uzbl.behave.font_size > 0) {
1373 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1376 if (uzbl.behave.monospace_size > 0) {
1377 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1378 uzbl.behave.monospace_size, NULL);
1380 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1381 uzbl.behave.font_size, NULL);
1387 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1391 cmd_disable_plugins() {
1392 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1393 !uzbl.behave.disable_plugins, NULL);
1397 cmd_disable_scripts() {
1398 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1399 !uzbl.behave.disable_scripts, NULL);
1403 cmd_minimum_font_size() {
1404 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1405 uzbl.behave.minimum_font_size, NULL);
1408 cmd_autoload_img() {
1409 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1410 uzbl.behave.autoload_img, NULL);
1415 cmd_autoshrink_img() {
1416 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1417 uzbl.behave.autoshrink_img, NULL);
1422 cmd_enable_spellcheck() {
1423 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1424 uzbl.behave.enable_spellcheck, NULL);
1428 cmd_enable_private() {
1429 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1430 uzbl.behave.enable_private, NULL);
1435 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1436 uzbl.behave.print_bg, NULL);
1441 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1442 uzbl.behave.style_uri, NULL);
1446 cmd_resizable_txt() {
1447 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1448 uzbl.behave.resizable_txt, NULL);
1452 cmd_default_encoding() {
1453 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1454 uzbl.behave.default_encoding, NULL);
1458 cmd_enforce_96dpi() {
1459 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1460 uzbl.behave.enforce_96dpi, NULL);
1464 cmd_caret_browsing() {
1465 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1466 uzbl.behave.caret_browsing, NULL);
1470 cmd_cookie_handler() {
1471 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1472 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1473 if ((g_strcmp0(split[0], "sh") == 0) ||
1474 (g_strcmp0(split[0], "spawn") == 0)) {
1475 g_free (uzbl.behave.cookie_handler);
1476 uzbl.behave.cookie_handler =
1477 g_strdup_printf("sync_%s %s", split[0], split[1]);
1484 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1489 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1494 if(uzbl.behave.inject_html) {
1495 webkit_web_view_load_html_string (uzbl.gui.web_view,
1496 uzbl.behave.inject_html, NULL);
1505 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1506 uzbl.behave.modmask = 0;
1508 if(uzbl.behave.modkey)
1509 g_free(uzbl.behave.modkey);
1510 uzbl.behave.modkey = buf;
1512 for (i = 0; modkeys[i].key != NULL; i++) {
1513 if (g_strrstr(buf, modkeys[i].key))
1514 uzbl.behave.modmask |= modkeys[i].mask;
1520 if (*uzbl.net.useragent == ' ') {
1521 g_free (uzbl.net.useragent);
1522 uzbl.net.useragent = NULL;
1524 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1526 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1527 g_free(uzbl.net.useragent);
1528 uzbl.net.useragent = ua;
1534 gtk_widget_ref(uzbl.gui.scrolled_win);
1535 gtk_widget_ref(uzbl.gui.mainbar);
1536 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1537 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1539 if(uzbl.behave.status_top) {
1540 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1541 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1544 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1545 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1547 gtk_widget_unref(uzbl.gui.scrolled_win);
1548 gtk_widget_unref(uzbl.gui.mainbar);
1549 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1554 set_var_value(gchar *name, gchar *val) {
1555 uzbl_cmdprop *c = NULL;
1559 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1560 /* check for the variable type */
1561 if (c->type == TYPE_STR) {
1562 buf = expand_vars(val);
1565 } else if(c->type == TYPE_INT) {
1566 int *ip = (int *)c->ptr;
1567 buf = expand_vars(val);
1568 *ip = (int)strtoul(buf, &endp, 10);
1570 } else if (c->type == TYPE_FLOAT) {
1571 float *fp = (float *)c->ptr;
1572 buf = expand_vars(val);
1573 *fp = strtod(buf, &endp);
1577 /* invoke a command specific function */
1578 if(c->func) c->func();
1585 Behaviour *b = &uzbl.behave;
1587 if(b->html_buffer->str) {
1588 webkit_web_view_load_html_string (uzbl.gui.web_view,
1589 b->html_buffer->str, b->base_url);
1590 g_string_free(b->html_buffer, TRUE);
1591 b->html_buffer = g_string_new("");
1595 enum {M_CMD, M_HTML};
1597 parse_cmd_line(const char *ctl_line) {
1598 Behaviour *b = &uzbl.behave;
1601 if(b->mode == M_HTML) {
1602 len = strlen(b->html_endmarker);
1603 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1604 if(len == strlen(ctl_line)-1 &&
1605 !strncmp(b->html_endmarker, ctl_line, len)) {
1607 set_var_value("mode", "0");
1612 set_timeout(b->html_timeout);
1613 g_string_append(b->html_buffer, ctl_line);
1616 else if((ctl_line[0] == '#') /* Comments */
1617 || (ctl_line[0] == ' ')
1618 || (ctl_line[0] == '\n'))
1619 ; /* ignore these lines */
1620 else { /* parse a command */
1622 gchar **tokens = NULL;
1623 len = strlen(ctl_line);
1625 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1626 ctlstrip = g_strndup(ctl_line, len - 1);
1627 else ctlstrip = g_strdup(ctl_line);
1629 tokens = g_strsplit(ctlstrip, " ", 2);
1630 parse_command(tokens[0], tokens[1]);
1637 build_stream_name(int type, const gchar* dir) {
1639 State *s = &uzbl.state;
1642 xwin_str = itos((int)uzbl.xwin);
1644 str = g_strdup_printf
1645 ("%s/uzbl_fifo_%s", dir,
1646 s->instance_name ? s->instance_name : xwin_str);
1647 } else if (type == SOCKET) {
1648 str = g_strdup_printf
1649 ("%s/uzbl_socket_%s", dir,
1650 s->instance_name ? s->instance_name : xwin_str );
1657 control_fifo(GIOChannel *gio, GIOCondition condition) {
1658 if (uzbl.state.verbose)
1659 printf("triggered\n");
1664 if (condition & G_IO_HUP)
1665 g_error ("Fifo: Read end of pipe died!\n");
1668 g_error ("Fifo: GIOChannel broke\n");
1670 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1671 if (ret == G_IO_STATUS_ERROR) {
1672 g_error ("Fifo: Error reading: %s\n", err->message);
1676 parse_cmd_line(ctl_line);
1683 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1684 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1685 if (unlink(uzbl.comm.fifo_path) == -1)
1686 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1687 g_free(uzbl.comm.fifo_path);
1688 uzbl.comm.fifo_path = NULL;
1691 if (*dir == ' ') { /* space unsets the variable */
1696 GIOChannel *chan = NULL;
1697 GError *error = NULL;
1698 gchar *path = build_stream_name(FIFO, dir);
1700 if (!file_exists(path)) {
1701 if (mkfifo (path, 0666) == 0) {
1702 // 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.
1703 chan = g_io_channel_new_file(path, "r+", &error);
1705 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1706 if (uzbl.state.verbose)
1707 printf ("init_fifo: created successfully as %s\n", path);
1708 uzbl.comm.fifo_path = path;
1710 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1711 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1712 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1713 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1715 /* if we got this far, there was an error; cleanup */
1716 if (error) g_error_free (error);
1723 control_stdin(GIOChannel *gio, GIOCondition condition) {
1725 gchar *ctl_line = NULL;
1728 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1729 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1732 parse_cmd_line(ctl_line);
1740 GIOChannel *chan = NULL;
1741 GError *error = NULL;
1743 chan = g_io_channel_unix_new(fileno(stdin));
1745 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1746 g_error ("Stdin: could not add watch\n");
1748 if (uzbl.state.verbose)
1749 printf ("Stdin: watch added successfully\n");
1752 g_error ("Stdin: Error while opening: %s\n", error->message);
1754 if (error) g_error_free (error);
1758 control_socket(GIOChannel *chan) {
1759 struct sockaddr_un remote;
1760 char buffer[512], *ctl_line;
1762 int sock, clientsock, n, done;
1765 sock = g_io_channel_unix_get_fd(chan);
1767 memset (buffer, 0, sizeof (buffer));
1769 t = sizeof (remote);
1770 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1774 memset (temp, 0, sizeof (temp));
1775 n = recv (clientsock, temp, 128, 0);
1777 buffer[strlen (buffer)] = '\0';
1781 strcat (buffer, temp);
1784 if (strcmp (buffer, "\n") < 0) {
1785 buffer[strlen (buffer) - 1] = '\0';
1787 buffer[strlen (buffer)] = '\0';
1790 ctl_line = g_strdup(buffer);
1791 parse_cmd_line (ctl_line);
1794 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1795 GError *error = NULL;
1798 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1799 if (ret == G_IO_STATUS_ERROR)
1800 g_error ("Error reading: %s\n", error->message);
1802 printf("Got line %s (%u bytes) \n",ctl_line, len);
1804 parse_line(ctl_line);
1812 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1813 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1814 if (unlink(uzbl.comm.socket_path) == -1)
1815 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1816 g_free(uzbl.comm.socket_path);
1817 uzbl.comm.socket_path = NULL;
1825 GIOChannel *chan = NULL;
1827 struct sockaddr_un local;
1828 gchar *path = build_stream_name(SOCKET, dir);
1830 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1832 local.sun_family = AF_UNIX;
1833 strcpy (local.sun_path, path);
1834 unlink (local.sun_path);
1836 len = strlen (local.sun_path) + sizeof (local.sun_family);
1837 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1838 if (uzbl.state.verbose)
1839 printf ("init_socket: opened in %s\n", path);
1842 if( (chan = g_io_channel_unix_new(sock)) ) {
1843 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1844 uzbl.comm.socket_path = path;
1847 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1849 /* if we got this far, there was an error; cleanup */
1856 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1857 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1859 // this function may be called very early when the templates are not set (yet), hence the checks
1861 update_title (void) {
1862 Behaviour *b = &uzbl.behave;
1865 if (b->show_status) {
1866 if (b->title_format_short) {
1867 parsed = expand_template(b->title_format_short, FALSE);
1868 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1871 if (b->status_format) {
1872 parsed = expand_template(b->status_format, TRUE);
1873 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1876 if (b->status_background) {
1878 gdk_color_parse (b->status_background, &color);
1879 //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)
1880 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1883 if (b->title_format_long) {
1884 parsed = expand_template(b->title_format_long, FALSE);
1885 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1892 key_press_cb (GtkWidget* window, GdkEventKey* event)
1894 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1898 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1899 || 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)
1902 /* turn off insert mode (if always_insert_mode is not used) */
1903 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1904 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1909 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1912 if (event->keyval == GDK_Escape) {
1913 g_string_truncate(uzbl.state.keycmd, 0);
1915 dehilight(uzbl.gui.web_view, NULL);
1919 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1920 if (event->keyval == GDK_Insert) {
1922 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1923 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1925 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1928 g_string_append (uzbl.state.keycmd, str);
1935 if (event->keyval == GDK_BackSpace)
1936 keycmd_bs(NULL, NULL);
1938 gboolean key_ret = FALSE;
1939 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1941 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1943 run_keycmd(key_ret);
1945 if (key_ret) return (!uzbl.behave.insert_mode);
1950 run_keycmd(const gboolean key_ret) {
1951 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1953 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1954 g_string_truncate(uzbl.state.keycmd, 0);
1955 parse_command(act->name, act->param);
1959 /* try if it's an incremental keycmd or one that takes args, and run it */
1960 GString* short_keys = g_string_new ("");
1961 GString* short_keys_inc = g_string_new ("");
1963 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1964 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1965 g_string_assign(short_keys_inc, short_keys->str);
1966 g_string_append_c(short_keys, '_');
1967 g_string_append_c(short_keys_inc, '*');
1969 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1970 /* run normal cmds only if return was pressed */
1971 exec_paramcmd(act, i);
1972 g_string_truncate(uzbl.state.keycmd, 0);
1974 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1975 if (key_ret) /* just quit the incremental command on return */
1976 g_string_truncate(uzbl.state.keycmd, 0);
1977 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1981 g_string_truncate(short_keys, short_keys->len - 1);
1983 g_string_free (short_keys, TRUE);
1984 g_string_free (short_keys_inc, TRUE);
1988 exec_paramcmd(const Action *act, const guint i) {
1989 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1990 GString *actionname = g_string_new ("");
1991 GString *actionparam = g_string_new ("");
1992 g_string_erase (parampart, 0, i+1);
1994 g_string_printf (actionname, act->name, parampart->str);
1996 g_string_printf (actionparam, act->param, parampart->str);
1997 parse_command(actionname->str, actionparam->str);
1998 g_string_free(actionname, TRUE);
1999 g_string_free(actionparam, TRUE);
2000 g_string_free(parampart, TRUE);
2008 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2009 //main_window_ref = g_object_ref(scrolled_window);
2010 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
2012 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2013 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2015 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2016 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2017 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2018 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2020 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2021 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2022 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2023 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2024 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2025 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2027 return scrolled_window;
2034 g->mainbar = gtk_hbox_new (FALSE, 0);
2036 /* keep a reference to the bar so we can re-pack it at runtime*/
2037 //sbar_ref = g_object_ref(g->mainbar);
2039 g->mainbar_label = gtk_label_new ("");
2040 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2041 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2042 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2043 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2044 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2045 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2050 GtkWidget* create_window () {
2051 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2052 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2053 gtk_widget_set_name (window, "Uzbl browser");
2054 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2055 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2061 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2063 If actname is one that calls an external command, this function will inject
2064 newargs in front of the user-provided args in that command line. They will
2065 come become after the body of the script (in sh) or after the name of
2066 the command to execute (in spawn).
2067 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2068 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2070 The return value consist of two strings: the action (sh, ...) and its args.
2072 If act is not one that calls an external command, then the given action merely
2075 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2076 gchar *actdup = g_strdup(actname);
2077 g_array_append_val(rets, actdup);
2079 if ((g_strcmp0(actname, "spawn") == 0) ||
2080 (g_strcmp0(actname, "sh") == 0) ||
2081 (g_strcmp0(actname, "sync_spawn") == 0) ||
2082 (g_strcmp0(actname, "sync_sh") == 0)) {
2084 GString *a = g_string_new("");
2085 gchar **spawnparts = split_quoted(origargs, FALSE);
2086 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2087 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2089 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2090 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2092 g_array_append_val(rets, a->str);
2093 g_string_free(a, FALSE);
2094 g_strfreev(spawnparts);
2096 gchar *origdup = g_strdup(origargs);
2097 g_array_append_val(rets, origdup);
2099 return (gchar**)g_array_free(rets, FALSE);
2103 run_handler (const gchar *act, const gchar *args) {
2104 /* Consider this code a temporary hack to make the handlers usable.
2105 In practice, all this splicing, injection, and reconstruction is
2106 inefficient, annoying and hard to manage. Potential pitfalls arise
2107 when the handler specific args 1) are not quoted (the handler
2108 callbacks should take care of this) 2) are quoted but interfere
2109 with the users' own quotation. A more ideal solution is
2110 to refactor parse_command so that it doesn't just take a string
2111 and execute it; rather than that, we should have a function which
2112 returns the argument vector parsed from the string. This vector
2113 could be modified (e.g. insert additional args into it) before
2114 passing it to the next function that actually executes it. Though
2115 it still isn't perfect for chain actions.. will reconsider & re-
2116 factor when I have the time. -duc */
2118 char **parts = g_strsplit(act, " ", 2);
2120 if (g_strcmp0(parts[0], "chain") == 0) {
2121 GString *newargs = g_string_new("");
2122 gchar **chainparts = split_quoted(parts[1], FALSE);
2124 /* for every argument in the chain, inject the handler args
2125 and make sure the new parts are wrapped in quotes */
2126 gchar **cp = chainparts;
2128 gchar *quotless = NULL;
2129 gchar **spliced_quotless = NULL; // sigh -_-;
2130 gchar **inpart = NULL;
2133 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2135 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2136 } else quotless = g_strdup(*cp);
2138 spliced_quotless = g_strsplit(quotless, " ", 2);
2139 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2140 g_strfreev(spliced_quotless);
2142 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2148 parse_command(parts[0], &(newargs->str[1]));
2149 g_string_free(newargs, TRUE);
2150 g_strfreev(chainparts);
2153 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2154 parse_command(inparts[0], inparts[1]);
2162 add_binding (const gchar *key, const gchar *act) {
2163 char **parts = g_strsplit(act, " ", 2);
2170 if (uzbl.state.verbose)
2171 printf ("Binding %-10s : %s\n", key, act);
2172 action = new_action(parts[0], parts[1]);
2174 if (g_hash_table_remove (uzbl.bindings, key))
2175 g_warning ("Overwriting existing binding for \"%s\"", key);
2176 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2181 get_xdg_var (XDG_Var xdg) {
2182 const gchar* actual_value = getenv (xdg.environmental);
2183 const gchar* home = getenv ("HOME");
2184 gchar* return_value;
2186 if (! actual_value || strcmp (actual_value, "") == 0) {
2187 if (xdg.default_value) {
2188 return_value = str_replace ("~", home, xdg.default_value);
2190 return_value = NULL;
2193 return_value = str_replace("~", home, actual_value);
2196 return return_value;
2200 find_xdg_file (int xdg_type, char* filename) {
2201 /* xdg_type = 0 => config
2202 xdg_type = 1 => data
2203 xdg_type = 2 => cache*/
2205 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2206 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2209 gchar* temporary_string;
2213 if (! file_exists (temporary_file) && xdg_type != 2) {
2214 buf = get_xdg_var (XDG[3 + xdg_type]);
2215 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2218 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2219 g_free (temporary_file);
2220 temporary_file = g_strconcat (temporary_string, filename, NULL);
2224 //g_free (temporary_string); - segfaults.
2226 if (file_exists (temporary_file)) {
2227 return temporary_file;
2234 State *s = &uzbl.state;
2235 Network *n = &uzbl.net;
2237 for (i = 0; default_config[i].command != NULL; i++) {
2238 parse_cmd_line(default_config[i].command);
2241 if (!s->config_file) {
2242 s->config_file = find_xdg_file (0, "/uzbl/config");
2245 if (s->config_file) {
2246 GArray* lines = read_file_by_line (s->config_file);
2250 while ((line = g_array_index(lines, gchar*, i))) {
2251 parse_cmd_line (line);
2255 g_array_free (lines, TRUE);
2257 if (uzbl.state.verbose)
2258 printf ("No configuration file loaded.\n");
2261 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2264 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2267 if (!uzbl.behave.cookie_handler)
2270 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2271 GString *s = g_string_new ("");
2272 SoupURI * soup_uri = soup_message_get_uri(msg);
2273 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2274 run_handler(uzbl.behave.cookie_handler, s->str);
2276 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2277 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2278 if ( p != NULL ) *p = '\0';
2279 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2281 if (uzbl.comm.sync_stdout)
2282 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2284 g_string_free(s, TRUE);
2288 save_cookies (SoupMessage *msg, gpointer user_data){
2292 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2293 cookie = soup_cookie_to_set_cookie_header(ck->data);
2294 SoupURI * soup_uri = soup_message_get_uri(msg);
2295 GString *s = g_string_new ("");
2296 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2297 run_handler(uzbl.behave.cookie_handler, s->str);
2299 g_string_free(s, TRUE);
2304 /* --- WEBINSPECTOR --- */
2306 hide_window_cb(GtkWidget *widget, gpointer data) {
2309 gtk_widget_hide(widget);
2312 static WebKitWebView*
2313 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2316 (void) web_inspector;
2317 GtkWidget* scrolled_window;
2318 GtkWidget* new_web_view;
2321 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2322 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2323 G_CALLBACK(hide_window_cb), NULL);
2325 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2326 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2327 gtk_widget_show(g->inspector_window);
2329 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2330 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2331 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2332 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2333 gtk_widget_show(scrolled_window);
2335 new_web_view = webkit_web_view_new();
2336 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2338 return WEBKIT_WEB_VIEW(new_web_view);
2342 inspector_show_window_cb (WebKitWebInspector* inspector){
2344 gtk_widget_show(uzbl.gui.inspector_window);
2348 /* TODO: Add variables and code to make use of these functions */
2350 inspector_close_window_cb (WebKitWebInspector* inspector){
2356 inspector_attach_window_cb (WebKitWebInspector* inspector){
2362 inspector_detach_window_cb (WebKitWebInspector* inspector){
2368 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2374 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2380 set_up_inspector() {
2382 WebKitWebSettings *settings = view_settings();
2383 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2385 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2386 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2387 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2388 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2389 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2390 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2391 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2393 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2397 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2399 uzbl_cmdprop *c = v;
2404 if(c->type == TYPE_STR)
2405 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2406 else if(c->type == TYPE_INT)
2407 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2411 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2415 printf("bind %s = %s %s\n", (char *)k ,
2416 (char *)a->name, a->param?(char *)a->param:"");
2421 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2422 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2427 main (int argc, char* argv[]) {
2428 gtk_init (&argc, &argv);
2429 if (!g_thread_supported ())
2430 g_thread_init (NULL);
2431 uzbl.state.executable_path = g_strdup(argv[0]);
2432 uzbl.state.selected_url = NULL;
2433 uzbl.state.searchtx = NULL;
2435 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2436 g_option_context_add_main_entries (context, entries, NULL);
2437 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2438 g_option_context_parse (context, &argc, &argv, NULL);
2439 g_option_context_free(context);
2441 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2442 gboolean verbose_override = uzbl.state.verbose;
2444 /* initialize hash table */
2445 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2447 uzbl.net.soup_session = webkit_get_default_session();
2448 uzbl.state.keycmd = g_string_new("");
2450 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2451 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2452 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2453 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2454 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2455 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2458 if(uname(&uzbl.state.unameinfo) == -1)
2459 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2461 uzbl.gui.sbar.progress_s = g_strdup("=");
2462 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2463 uzbl.gui.sbar.progress_w = 10;
2465 /* HTML mode defaults*/
2466 uzbl.behave.html_buffer = g_string_new("");
2467 uzbl.behave.html_endmarker = g_strdup(".");
2468 uzbl.behave.html_timeout = 60;
2469 uzbl.behave.base_url = g_strdup("http://invalid");
2471 /* default mode indicators */
2472 uzbl.behave.insert_indicator = g_strdup("I");
2473 uzbl.behave.cmd_indicator = g_strdup("C");
2477 make_var_to_name_hash();
2479 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2481 uzbl.gui.scrolled_win = create_browser();
2484 /* initial packing */
2485 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2486 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2488 uzbl.gui.main_window = create_window ();
2489 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2492 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2493 gtk_widget_show_all (uzbl.gui.main_window);
2494 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2496 if (uzbl.state.verbose) {
2497 printf("Uzbl start location: %s\n", argv[0]);
2498 printf("window_id %i\n",(int) uzbl.xwin);
2499 printf("pid %i\n", getpid ());
2500 printf("name: %s\n", uzbl.state.instance_name);
2503 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2504 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2505 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2506 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2507 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2511 if (!uzbl.behave.show_status)
2512 gtk_widget_hide(uzbl.gui.mainbar);
2521 if (verbose_override > uzbl.state.verbose)
2522 uzbl.state.verbose = verbose_override;
2525 set_var_value("uri", uri_override);
2526 g_free(uri_override);
2527 } else if (uzbl.state.uri)
2528 cmd_load_uri(uzbl.gui.web_view, NULL);
2533 return EXIT_SUCCESS;
2536 /* vi: set et ts=4: */