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};
89 /* an abbreviation to help keep the table's width humane */
90 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
95 } var_name_to_ptr[] = {
96 /* variable name pointer to variable in code type dump callback function */
97 /* --------------------------------------------------------------------------------------- */
98 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
99 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
118 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
119 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
120 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
121 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
122 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
123 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
124 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
125 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
126 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
127 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
128 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
129 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
130 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
131 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
132 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
133 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
134 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
135 /* exported WebKitWebSettings properties */
136 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
137 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
138 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
139 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
140 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
141 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
142 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
143 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
144 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
145 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
146 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
147 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
148 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
149 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
150 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
151 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
153 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
154 }, *n2v_p = var_name_to_ptr;
160 { "SHIFT", GDK_SHIFT_MASK }, // shift
161 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
162 { "CONTROL", GDK_CONTROL_MASK }, // control
163 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
164 { "MOD2", GDK_MOD2_MASK }, // 5th mod
165 { "MOD3", GDK_MOD3_MASK }, // 6th mod
166 { "MOD4", GDK_MOD4_MASK }, // 7th mod
167 { "MOD5", GDK_MOD5_MASK }, // 8th mod
168 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
169 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
170 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
171 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
172 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
173 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
174 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
175 { "META", GDK_META_MASK }, // meta (since 2.10)
180 /* construct a hash from the var_name_to_ptr array for quick access */
182 make_var_to_name_hash() {
183 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
185 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
190 /* --- UTILITY FUNCTIONS --- */
192 expand_vars(char *s) {
195 char ret[256], *vend;
196 GString *buf = g_string_new("");
201 g_string_append_c(buf, *++s);
209 if( (vend = strchr(s, upto)) ||
210 (vend = strchr(s, '\0')) ) {
211 strncpy(ret, s, vend-s);
213 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
214 if(c->type == TYPE_STR)
215 g_string_append(buf, (gchar *)*c->ptr);
216 else if(c->type == TYPE_INT) {
217 char *b = itos((int)*c->ptr);
218 g_string_append(buf, b);
222 if(upto == ' ') s = vend;
228 g_string_append_c(buf, *s);
233 return g_string_free(buf, FALSE);
240 snprintf(tmp, sizeof(tmp), "%i", val);
241 return g_strdup(tmp);
245 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
248 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
251 str_replace (const char* search, const char* replace, const char* string) {
255 buf = g_strsplit (string, search, -1);
256 ret = g_strjoinv (replace, buf);
257 g_strfreev(buf); // somebody said this segfaults
263 read_file_by_line (gchar *path) {
264 GIOChannel *chan = NULL;
265 gchar *readbuf = NULL;
267 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
270 chan = g_io_channel_new_file(path, "r", NULL);
273 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
274 const gchar* val = g_strdup (readbuf);
275 g_array_append_val (lines, val);
280 g_io_channel_unref (chan);
282 fprintf(stderr, "File '%s' not be read.\n", path);
289 gchar* parseenv (char* string) {
290 extern char** environ;
291 gchar* tmpstr = NULL;
295 while (environ[i] != NULL) {
296 gchar** env = g_strsplit (environ[i], "=", 2);
297 gchar* envname = g_strconcat ("$", env[0], NULL);
299 if (g_strrstr (string, envname) != NULL) {
300 tmpstr = g_strdup(string);
302 string = str_replace(envname, env[1], tmpstr);
307 g_strfreev (env); // somebody said this breaks uzbl
315 setup_signal(int signr, sigfunc *shandler) {
316 struct sigaction nh, oh;
318 nh.sa_handler = shandler;
319 sigemptyset(&nh.sa_mask);
322 if(sigaction(signr, &nh, &oh) < 0)
330 if (uzbl.behave.fifo_dir)
331 unlink (uzbl.comm.fifo_path);
332 if (uzbl.behave.socket_dir)
333 unlink (uzbl.comm.socket_path);
335 g_free(uzbl.state.executable_path);
336 g_string_free(uzbl.state.keycmd, TRUE);
337 g_hash_table_destroy(uzbl.bindings);
338 g_hash_table_destroy(uzbl.behave.commands);
341 /* used for html_mode_timeout
342 * be sure to extend this function to use
343 * more timers if needed in other places
346 set_timeout(int seconds) {
348 memset(&t, 0, sizeof t);
350 t.it_value.tv_sec = seconds;
351 t.it_value.tv_usec = 0;
352 setitimer(ITIMER_REAL, &t, NULL);
355 /* --- SIGNAL HANDLER --- */
358 catch_sigterm(int s) {
364 catch_sigint(int s) {
374 set_var_value("mode", "0");
379 /* --- CALLBACKS --- */
382 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
385 (void) navigation_action;
386 (void) policy_decision;
388 const gchar* uri = webkit_network_request_get_uri (request);
389 if (uzbl.state.verbose)
390 printf("New window requested -> %s \n", uri);
391 new_window_load_uri(uri);
396 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
401 /* If we can display it, let's display it... */
402 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
403 webkit_web_policy_decision_use (policy_decision);
407 /* ...everything we can't displayed is downloaded */
408 webkit_web_policy_decision_download (policy_decision);
413 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
417 if (uzbl.state.selected_url != NULL) {
418 if (uzbl.state.verbose)
419 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
420 new_window_load_uri(uzbl.state.selected_url);
422 if (uzbl.state.verbose)
423 printf("New web view -> %s\n","Nothing to open, exiting");
429 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
432 if (uzbl.behave.download_handler) {
433 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
434 if (uzbl.state.verbose)
435 printf("Download -> %s\n",uri);
436 /* if urls not escaped, we may have to escape and quote uri before this call */
437 run_handler(uzbl.behave.download_handler, uri);
442 /* scroll a bar in a given direction */
444 scroll (GtkAdjustment* bar, GArray *argv) {
448 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
449 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
450 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
454 scroll_begin(WebKitWebView* page, GArray *argv) {
455 (void) page; (void) argv;
456 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
460 scroll_end(WebKitWebView* page, GArray *argv) {
461 (void) page; (void) argv;
462 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
463 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
467 scroll_vert(WebKitWebView* page, GArray *argv) {
469 scroll(uzbl.gui.bar_v, argv);
473 scroll_horz(WebKitWebView* page, GArray *argv) {
475 scroll(uzbl.gui.bar_h, argv);
480 if (!uzbl.behave.show_status) {
481 gtk_widget_hide(uzbl.gui.mainbar);
483 gtk_widget_show(uzbl.gui.mainbar);
489 toggle_status_cb (WebKitWebView* page, GArray *argv) {
493 if (uzbl.behave.show_status) {
494 gtk_widget_hide(uzbl.gui.mainbar);
496 gtk_widget_show(uzbl.gui.mainbar);
498 uzbl.behave.show_status = !uzbl.behave.show_status;
503 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
507 //Set selected_url state variable
508 g_free(uzbl.state.selected_url);
509 uzbl.state.selected_url = NULL;
511 uzbl.state.selected_url = g_strdup(link);
517 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
521 if (uzbl.gui.main_title)
522 g_free (uzbl.gui.main_title);
523 uzbl.gui.main_title = g_strdup (title);
528 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
531 uzbl.gui.sbar.load_progress = progress;
536 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
540 if (uzbl.behave.load_finish_handler)
541 run_handler(uzbl.behave.load_finish_handler, "");
545 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
549 uzbl.gui.sbar.load_progress = 0;
550 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
551 if (uzbl.behave.load_start_handler)
552 run_handler(uzbl.behave.load_start_handler, "");
556 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
559 g_free (uzbl.state.uri);
560 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
561 uzbl.state.uri = g_string_free (newuri, FALSE);
562 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
563 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
566 if (uzbl.behave.load_commit_handler)
567 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
571 destroy_cb (GtkWidget* widget, gpointer data) {
579 if (uzbl.behave.history_handler) {
581 struct tm * timeinfo;
584 timeinfo = localtime ( &rawtime );
585 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
586 run_handler(uzbl.behave.history_handler, date);
591 /* VIEW funcs (little webkit wrappers) */
592 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
594 VIEWFUNC(reload_bypass_cache)
595 VIEWFUNC(stop_loading)
602 /* -- command to callback/function map for things we cannot attach to any signals */
603 static struct {char *name; Command command[2];} cmdlist[] =
604 { /* key function no_split */
605 { "back", {view_go_back, 0} },
606 { "forward", {view_go_forward, 0} },
607 { "scroll_vert", {scroll_vert, 0} },
608 { "scroll_horz", {scroll_horz, 0} },
609 { "scroll_begin", {scroll_begin, 0} },
610 { "scroll_end", {scroll_end, 0} },
611 { "reload", {view_reload, 0}, },
612 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
613 { "stop", {view_stop_loading, 0}, },
614 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
615 { "zoom_out", {view_zoom_out, 0}, },
616 { "reset_zoom", {reset_zoom_level, 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 reset_zoom_level (WebKitWebView *page, GArray *argv) {
819 webkit_web_view_set_zoom_level (page, 1.0);
823 dehilight (WebKitWebView *page, GArray *argv) {
825 webkit_web_view_set_highlight_text_matches (page, FALSE);
830 new_window_load_uri (const gchar * uri) {
831 GString* to_execute = g_string_new ("");
832 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
834 for (i = 0; entries[i].long_name != NULL; i++) {
835 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
836 gchar** str = (gchar**)entries[i].arg_data;
838 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
842 if (uzbl.state.verbose)
843 printf("\n%s\n", to_execute->str);
844 g_spawn_command_line_async (to_execute->str, NULL);
845 g_string_free (to_execute, TRUE);
849 chain (WebKitWebView *page, GArray *argv) {
852 gchar **parts = NULL;
854 while ((a = argv_idx(argv, i++))) {
855 parts = g_strsplit (a, " ", 2);
856 parse_command(parts[0], parts[1]);
862 keycmd (WebKitWebView *page, GArray *argv) {
865 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
871 keycmd_nl (WebKitWebView *page, GArray *argv) {
874 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
880 keycmd_bs (WebKitWebView *page, GArray *argv) {
883 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
888 close_uzbl (WebKitWebView *page, GArray *argv) {
894 /* --Statusbar functions-- */
896 build_progressbar_ascii(int percent) {
897 int width=uzbl.gui.sbar.progress_w;
900 GString *bar = g_string_new("");
902 l = (double)percent*((double)width/100.);
903 l = (int)(l+.5)>=(int)l ? l+.5 : l;
905 for(i=0; i<(int)l; i++)
906 g_string_append(bar, uzbl.gui.sbar.progress_s);
909 g_string_append(bar, uzbl.gui.sbar.progress_u);
911 return g_string_free(bar, FALSE);
916 const GScannerConfig scan_config = {
919 ) /* cset_skip_characters */,
924 ) /* cset_identifier_first */,
931 ) /* cset_identifier_nth */,
932 ( "" ) /* cpair_comment_single */,
934 TRUE /* case_sensitive */,
936 FALSE /* skip_comment_multi */,
937 FALSE /* skip_comment_single */,
938 FALSE /* scan_comment_multi */,
939 TRUE /* scan_identifier */,
940 TRUE /* scan_identifier_1char */,
941 FALSE /* scan_identifier_NULL */,
942 TRUE /* scan_symbols */,
943 FALSE /* scan_binary */,
944 FALSE /* scan_octal */,
945 FALSE /* scan_float */,
946 FALSE /* scan_hex */,
947 FALSE /* scan_hex_dollar */,
948 FALSE /* scan_string_sq */,
949 FALSE /* scan_string_dq */,
950 TRUE /* numbers_2_int */,
951 FALSE /* int_2_float */,
952 FALSE /* identifier_2_string */,
953 FALSE /* char_2_token */,
954 FALSE /* symbol_2_token */,
955 TRUE /* scope_0_fallback */,
960 uzbl.scan = g_scanner_new(&scan_config);
961 while(symp->symbol_name) {
962 g_scanner_scope_add_symbol(uzbl.scan, 0,
964 GINT_TO_POINTER(symp->symbol_token));
970 expand_template(const char *template, gboolean escape_markup) {
971 if(!template) return NULL;
973 GTokenType token = G_TOKEN_NONE;
974 GString *ret = g_string_new("");
978 g_scanner_input_text(uzbl.scan, template, strlen(template));
979 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
980 token = g_scanner_get_next_token(uzbl.scan);
982 if(token == G_TOKEN_SYMBOL) {
983 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
987 buf = uzbl.state.uri?
988 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
989 g_string_append(ret, buf);
993 g_string_append(ret, uzbl.state.uri?
994 uzbl.state.uri:g_strdup(""));
997 buf = itos(uzbl.gui.sbar.load_progress);
998 g_string_append(ret, buf);
1001 case SYM_LOADPRGSBAR:
1002 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1003 g_string_append(ret, buf);
1008 buf = uzbl.gui.main_title?
1009 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1010 g_string_append(ret, buf);
1014 g_string_append(ret, uzbl.gui.main_title?
1015 uzbl.gui.main_title:g_strdup(""));
1017 case SYM_SELECTED_URI:
1019 buf = uzbl.state.selected_url?
1020 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1021 g_string_append(ret, buf);
1025 g_string_append(ret, uzbl.state.selected_url?
1026 uzbl.state.selected_url:g_strdup(""));
1029 buf = itos(uzbl.xwin);
1030 g_string_append(ret,
1031 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1036 buf = uzbl.state.keycmd->str?
1037 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1038 g_string_append(ret, buf);
1042 g_string_append(ret, uzbl.state.keycmd->str?
1043 uzbl.state.keycmd->str:g_strdup(""));
1046 g_string_append(ret,
1047 uzbl.behave.insert_mode?
1048 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1051 g_string_append(ret,
1052 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1054 /* useragent syms */
1056 buf = itos(WEBKIT_MAJOR_VERSION);
1057 g_string_append(ret, buf);
1061 buf = itos(WEBKIT_MINOR_VERSION);
1062 g_string_append(ret, buf);
1066 buf = itos(WEBKIT_MICRO_VERSION);
1067 g_string_append(ret, buf);
1071 g_string_append(ret, uzbl.state.unameinfo.sysname);
1074 g_string_append(ret, uzbl.state.unameinfo.nodename);
1077 g_string_append(ret, uzbl.state.unameinfo.release);
1080 g_string_append(ret, uzbl.state.unameinfo.version);
1083 g_string_append(ret, uzbl.state.unameinfo.machine);
1086 g_string_append(ret, ARCH);
1089 case SYM_DOMAINNAME:
1090 g_string_append(ret, uzbl.state.unameinfo.domainname);
1094 g_string_append(ret, COMMIT);
1100 else if(token == G_TOKEN_INT) {
1101 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1102 g_string_append(ret, buf);
1105 else if(token == G_TOKEN_IDENTIFIER) {
1106 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1108 else if(token == G_TOKEN_CHAR) {
1109 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1113 return g_string_free(ret, FALSE);
1115 /* --End Statusbar functions-- */
1118 sharg_append(GArray *a, const gchar *str) {
1119 const gchar *s = (str ? str : "");
1120 g_array_append_val(a, s);
1123 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1125 run_command (const gchar *command, const guint npre, const gchar **args,
1126 const gboolean sync, char **output_stdout) {
1127 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1130 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1131 gchar *pid = itos(getpid());
1132 gchar *xwin = itos(uzbl.xwin);
1134 sharg_append(a, command);
1135 for (i = 0; i < npre; i++) /* add n args before the default vars */
1136 sharg_append(a, args[i]);
1137 sharg_append(a, uzbl.state.config_file);
1138 sharg_append(a, pid);
1139 sharg_append(a, xwin);
1140 sharg_append(a, uzbl.comm.fifo_path);
1141 sharg_append(a, uzbl.comm.socket_path);
1142 sharg_append(a, uzbl.state.uri);
1143 sharg_append(a, uzbl.gui.main_title);
1145 for (i = npre; i < g_strv_length((gchar**)args); i++)
1146 sharg_append(a, args[i]);
1150 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1152 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1153 NULL, NULL, output_stdout, NULL, NULL, &err);
1154 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1155 NULL, NULL, NULL, &err);
1157 if (uzbl.state.verbose) {
1158 GString *s = g_string_new("spawned:");
1159 for (i = 0; i < (a->len); i++) {
1160 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1161 g_string_append_printf(s, " %s", qarg);
1164 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1165 printf("%s\n", s->str);
1166 g_string_free(s, TRUE);
1168 printf("Stdout: %s\n", *output_stdout);
1172 g_printerr("error on run_command: %s\n", err->message);
1177 g_array_free (a, TRUE);
1182 split_quoted(const gchar* src, const gboolean unquote) {
1183 /* split on unquoted space, return array of strings;
1184 remove a layer of quotes and backslashes if unquote */
1185 if (!src) return NULL;
1187 gboolean dq = FALSE;
1188 gboolean sq = FALSE;
1189 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1190 GString *s = g_string_new ("");
1194 for (p = src; *p != '\0'; p++) {
1195 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1196 else if (*p == '\\') { g_string_append_c(s, *p++);
1197 g_string_append_c(s, *p); }
1198 else if ((*p == '"') && unquote && !sq) dq = !dq;
1199 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1201 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1202 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1204 else if ((*p == ' ') && !dq && !sq) {
1205 dup = g_strdup(s->str);
1206 g_array_append_val(a, dup);
1207 g_string_truncate(s, 0);
1208 } else g_string_append_c(s, *p);
1210 dup = g_strdup(s->str);
1211 g_array_append_val(a, dup);
1212 ret = (gchar**)a->data;
1213 g_array_free (a, FALSE);
1214 g_string_free (s, TRUE);
1219 spawn(WebKitWebView *web_view, GArray *argv) {
1221 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1222 if (argv_idx(argv, 0))
1223 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1227 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1230 if (argv_idx(argv, 0))
1231 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1232 TRUE, &uzbl.comm.sync_stdout);
1236 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1238 if (!uzbl.behave.shell_cmd) {
1239 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1244 gchar *spacer = g_strdup("");
1245 g_array_insert_val(argv, 1, spacer);
1246 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1248 for (i = 1; i < g_strv_length(cmd); i++)
1249 g_array_prepend_val(argv, cmd[i]);
1251 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1257 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1259 if (!uzbl.behave.shell_cmd) {
1260 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1265 gchar *spacer = g_strdup("");
1266 g_array_insert_val(argv, 1, spacer);
1267 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1269 for (i = 1; i < g_strv_length(cmd); i++)
1270 g_array_prepend_val(argv, cmd[i]);
1272 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1273 TRUE, &uzbl.comm.sync_stdout);
1279 parse_command(const char *cmd, const char *param) {
1282 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1285 gchar **par = split_quoted(param, TRUE);
1286 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1288 if (c[1] == NOSPLIT) { /* don't split */
1289 sharg_append(a, param);
1291 for (i = 0; i < g_strv_length(par); i++)
1292 sharg_append(a, par[i]);
1294 c[0](uzbl.gui.web_view, a);
1296 g_array_free (a, TRUE);
1299 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1306 if(*uzbl.net.proxy_url == ' '
1307 || uzbl.net.proxy_url == NULL) {
1308 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1309 (GType) SOUP_SESSION_PROXY_URI);
1312 suri = soup_uri_new(uzbl.net.proxy_url);
1313 g_object_set(G_OBJECT(uzbl.net.soup_session),
1314 SOUP_SESSION_PROXY_URI,
1316 soup_uri_free(suri);
1323 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1324 g_array_append_val (a, uzbl.state.uri);
1325 load_uri(uzbl.gui.web_view, a);
1326 g_array_free (a, TRUE);
1330 cmd_always_insert_mode() {
1331 uzbl.behave.insert_mode =
1332 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1338 g_object_set(G_OBJECT(uzbl.net.soup_session),
1339 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1343 cmd_max_conns_host() {
1344 g_object_set(G_OBJECT(uzbl.net.soup_session),
1345 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1350 soup_session_remove_feature
1351 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1352 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1353 /*g_free(uzbl.net.soup_logger);*/
1355 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1356 soup_session_add_feature(uzbl.net.soup_session,
1357 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1360 static WebKitWebSettings*
1362 return webkit_web_view_get_settings(uzbl.gui.web_view);
1367 WebKitWebSettings *ws = view_settings();
1368 if (uzbl.behave.font_size > 0) {
1369 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1372 if (uzbl.behave.monospace_size > 0) {
1373 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1374 uzbl.behave.monospace_size, NULL);
1376 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1377 uzbl.behave.font_size, NULL);
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 // This extra check is an alternative to recursively calling init_fifo() or using goto
1692 if (file_exists(path)) {
1694 g_warning ("init_fifo: can't delete %s: %s", path, strerror(errno));
1697 if (!file_exists(path)) {
1698 if (mkfifo (path, 0666) == 0) {
1699 // 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.
1700 chan = g_io_channel_new_file(path, "r+", &error);
1702 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1703 if (uzbl.state.verbose)
1704 printf ("init_fifo: created successfully as %s\n", path);
1705 uzbl.comm.fifo_path = path;
1707 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1708 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1709 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1710 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1712 /* if we got this far, there was an error; cleanup */
1713 if (error) g_error_free (error);
1720 control_stdin(GIOChannel *gio, GIOCondition condition) {
1722 gchar *ctl_line = NULL;
1725 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1726 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1729 parse_cmd_line(ctl_line);
1737 GIOChannel *chan = NULL;
1738 GError *error = NULL;
1740 chan = g_io_channel_unix_new(fileno(stdin));
1742 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1743 g_error ("Stdin: could not add watch\n");
1745 if (uzbl.state.verbose)
1746 printf ("Stdin: watch added successfully\n");
1749 g_error ("Stdin: Error while opening: %s\n", error->message);
1751 if (error) g_error_free (error);
1755 control_socket(GIOChannel *chan) {
1756 struct sockaddr_un remote;
1757 char buffer[512], *ctl_line;
1759 int sock, clientsock, n, done;
1762 sock = g_io_channel_unix_get_fd(chan);
1764 memset (buffer, 0, sizeof (buffer));
1766 t = sizeof (remote);
1767 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1771 memset (temp, 0, sizeof (temp));
1772 n = recv (clientsock, temp, 128, 0);
1774 buffer[strlen (buffer)] = '\0';
1778 strcat (buffer, temp);
1781 if (strcmp (buffer, "\n") < 0) {
1782 buffer[strlen (buffer) - 1] = '\0';
1784 buffer[strlen (buffer)] = '\0';
1787 ctl_line = g_strdup(buffer);
1788 parse_cmd_line (ctl_line);
1791 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1792 GError *error = NULL;
1795 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1796 if (ret == G_IO_STATUS_ERROR)
1797 g_error ("Error reading: %s\n", error->message);
1799 printf("Got line %s (%u bytes) \n",ctl_line, len);
1801 parse_line(ctl_line);
1809 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1810 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1811 if (unlink(uzbl.comm.socket_path) == -1)
1812 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1813 g_free(uzbl.comm.socket_path);
1814 uzbl.comm.socket_path = NULL;
1822 GIOChannel *chan = NULL;
1824 struct sockaddr_un local;
1825 gchar *path = build_stream_name(SOCKET, dir);
1827 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1829 local.sun_family = AF_UNIX;
1830 strcpy (local.sun_path, path);
1831 unlink (local.sun_path);
1833 len = strlen (local.sun_path) + sizeof (local.sun_family);
1834 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1835 if (uzbl.state.verbose)
1836 printf ("init_socket: opened in %s\n", path);
1839 if( (chan = g_io_channel_unix_new(sock)) ) {
1840 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1841 uzbl.comm.socket_path = path;
1844 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1846 /* if we got this far, there was an error; cleanup */
1853 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1854 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1856 // this function may be called very early when the templates are not set (yet), hence the checks
1858 update_title (void) {
1859 Behaviour *b = &uzbl.behave;
1862 if (b->show_status) {
1863 if (b->title_format_short) {
1864 parsed = expand_template(b->title_format_short, FALSE);
1865 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1868 if (b->status_format) {
1869 parsed = expand_template(b->status_format, TRUE);
1870 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1873 if (b->status_background) {
1875 gdk_color_parse (b->status_background, &color);
1876 //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)
1877 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1880 if (b->title_format_long) {
1881 parsed = expand_template(b->title_format_long, FALSE);
1882 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1889 key_press_cb (GtkWidget* window, GdkEventKey* event)
1891 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1895 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1896 || 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)
1899 /* turn off insert mode (if always_insert_mode is not used) */
1900 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1901 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1906 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1909 if (event->keyval == GDK_Escape) {
1910 g_string_truncate(uzbl.state.keycmd, 0);
1912 dehilight(uzbl.gui.web_view, NULL);
1916 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1917 if (event->keyval == GDK_Insert) {
1919 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1920 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1922 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1925 g_string_append (uzbl.state.keycmd, str);
1932 if (event->keyval == GDK_BackSpace)
1933 keycmd_bs(NULL, NULL);
1935 gboolean key_ret = FALSE;
1936 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1938 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1940 run_keycmd(key_ret);
1942 if (key_ret) return (!uzbl.behave.insert_mode);
1947 run_keycmd(const gboolean key_ret) {
1948 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1950 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1951 g_string_truncate(uzbl.state.keycmd, 0);
1952 parse_command(act->name, act->param);
1956 /* try if it's an incremental keycmd or one that takes args, and run it */
1957 GString* short_keys = g_string_new ("");
1958 GString* short_keys_inc = g_string_new ("");
1960 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1961 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1962 g_string_assign(short_keys_inc, short_keys->str);
1963 g_string_append_c(short_keys, '_');
1964 g_string_append_c(short_keys_inc, '*');
1966 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1967 /* run normal cmds only if return was pressed */
1968 exec_paramcmd(act, i);
1969 g_string_truncate(uzbl.state.keycmd, 0);
1971 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1972 if (key_ret) /* just quit the incremental command on return */
1973 g_string_truncate(uzbl.state.keycmd, 0);
1974 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1978 g_string_truncate(short_keys, short_keys->len - 1);
1980 g_string_free (short_keys, TRUE);
1981 g_string_free (short_keys_inc, TRUE);
1985 exec_paramcmd(const Action *act, const guint i) {
1986 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1987 GString *actionname = g_string_new ("");
1988 GString *actionparam = g_string_new ("");
1989 g_string_erase (parampart, 0, i+1);
1991 g_string_printf (actionname, act->name, parampart->str);
1993 g_string_printf (actionparam, act->param, parampart->str);
1994 parse_command(actionname->str, actionparam->str);
1995 g_string_free(actionname, TRUE);
1996 g_string_free(actionparam, TRUE);
1997 g_string_free(parampart, TRUE);
2005 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2006 //main_window_ref = g_object_ref(scrolled_window);
2007 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
2009 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2010 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2012 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2014 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2015 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2016 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2017 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2018 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2020 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2021 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2022 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2024 return scrolled_window;
2031 g->mainbar = gtk_hbox_new (FALSE, 0);
2033 /* keep a reference to the bar so we can re-pack it at runtime*/
2034 //sbar_ref = g_object_ref(g->mainbar);
2036 g->mainbar_label = gtk_label_new ("");
2037 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2038 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2039 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2040 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2041 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2042 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2047 GtkWidget* create_window () {
2048 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2049 gchar* uzbl_icon = find_xdg_file(1, "/uzbl/uzbl.png");
2050 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2051 gtk_widget_set_name (window, "Uzbl browser");
2052 gtk_window_set_icon_from_file (GTK_WINDOW (window), uzbl_icon, NULL);
2053 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2054 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2062 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2064 If actname is one that calls an external command, this function will inject
2065 newargs in front of the user-provided args in that command line. They will
2066 come become after the body of the script (in sh) or after the name of
2067 the command to execute (in spawn).
2068 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2069 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2071 The return value consist of two strings: the action (sh, ...) and its args.
2073 If act is not one that calls an external command, then the given action merely
2076 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2077 gchar *actdup = g_strdup(actname);
2078 g_array_append_val(rets, actdup);
2080 if ((g_strcmp0(actname, "spawn") == 0) ||
2081 (g_strcmp0(actname, "sh") == 0) ||
2082 (g_strcmp0(actname, "sync_spawn") == 0) ||
2083 (g_strcmp0(actname, "sync_sh") == 0)) {
2085 GString *a = g_string_new("");
2086 gchar **spawnparts = split_quoted(origargs, FALSE);
2087 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2088 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2090 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2091 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2093 g_array_append_val(rets, a->str);
2094 g_string_free(a, FALSE);
2095 g_strfreev(spawnparts);
2097 gchar *origdup = g_strdup(origargs);
2098 g_array_append_val(rets, origdup);
2100 return (gchar**)g_array_free(rets, FALSE);
2104 run_handler (const gchar *act, const gchar *args) {
2105 /* Consider this code a temporary hack to make the handlers usable.
2106 In practice, all this splicing, injection, and reconstruction is
2107 inefficient, annoying and hard to manage. Potential pitfalls arise
2108 when the handler specific args 1) are not quoted (the handler
2109 callbacks should take care of this) 2) are quoted but interfere
2110 with the users' own quotation. A more ideal solution is
2111 to refactor parse_command so that it doesn't just take a string
2112 and execute it; rather than that, we should have a function which
2113 returns the argument vector parsed from the string. This vector
2114 could be modified (e.g. insert additional args into it) before
2115 passing it to the next function that actually executes it. Though
2116 it still isn't perfect for chain actions.. will reconsider & re-
2117 factor when I have the time. -duc */
2119 char **parts = g_strsplit(act, " ", 2);
2121 if (g_strcmp0(parts[0], "chain") == 0) {
2122 GString *newargs = g_string_new("");
2123 gchar **chainparts = split_quoted(parts[1], FALSE);
2125 /* for every argument in the chain, inject the handler args
2126 and make sure the new parts are wrapped in quotes */
2127 gchar **cp = chainparts;
2129 gchar *quotless = NULL;
2130 gchar **spliced_quotless = NULL; // sigh -_-;
2131 gchar **inpart = NULL;
2134 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2136 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2137 } else quotless = g_strdup(*cp);
2139 spliced_quotless = g_strsplit(quotless, " ", 2);
2140 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2141 g_strfreev(spliced_quotless);
2143 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2149 parse_command(parts[0], &(newargs->str[1]));
2150 g_string_free(newargs, TRUE);
2151 g_strfreev(chainparts);
2154 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2155 parse_command(inparts[0], inparts[1]);
2163 add_binding (const gchar *key, const gchar *act) {
2164 char **parts = g_strsplit(act, " ", 2);
2171 if (uzbl.state.verbose)
2172 printf ("Binding %-10s : %s\n", key, act);
2173 action = new_action(parts[0], parts[1]);
2175 if (g_hash_table_remove (uzbl.bindings, key))
2176 g_warning ("Overwriting existing binding for \"%s\"", key);
2177 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2182 get_xdg_var (XDG_Var xdg) {
2183 const gchar* actual_value = getenv (xdg.environmental);
2184 const gchar* home = getenv ("HOME");
2185 gchar* return_value;
2187 if (! actual_value || strcmp (actual_value, "") == 0) {
2188 if (xdg.default_value) {
2189 return_value = str_replace ("~", home, xdg.default_value);
2191 return_value = NULL;
2194 return_value = str_replace("~", home, actual_value);
2197 return return_value;
2201 find_xdg_file (int xdg_type, char* filename) {
2202 /* xdg_type = 0 => config
2203 xdg_type = 1 => data
2204 xdg_type = 2 => cache*/
2206 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2207 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2210 gchar* temporary_string;
2214 if (! file_exists (temporary_file) && xdg_type != 2) {
2215 buf = get_xdg_var (XDG[3 + xdg_type]);
2216 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2219 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2220 g_free (temporary_file);
2221 temporary_file = g_strconcat (temporary_string, filename, NULL);
2225 //g_free (temporary_string); - segfaults.
2227 if (file_exists (temporary_file)) {
2228 return temporary_file;
2235 State *s = &uzbl.state;
2236 Network *n = &uzbl.net;
2238 for (i = 0; default_config[i].command != NULL; i++) {
2239 parse_cmd_line(default_config[i].command);
2242 if (!s->config_file) {
2243 s->config_file = find_xdg_file (0, "/uzbl/config");
2246 if (s->config_file) {
2247 GArray* lines = read_file_by_line (s->config_file);
2251 while ((line = g_array_index(lines, gchar*, i))) {
2252 parse_cmd_line (line);
2256 g_array_free (lines, TRUE);
2258 if (uzbl.state.verbose)
2259 printf ("No configuration file loaded.\n");
2262 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2265 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2268 if (!uzbl.behave.cookie_handler)
2271 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2272 GString *s = g_string_new ("");
2273 SoupURI * soup_uri = soup_message_get_uri(msg);
2274 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2275 run_handler(uzbl.behave.cookie_handler, s->str);
2277 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2278 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2279 if ( p != NULL ) *p = '\0';
2280 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2282 if (uzbl.comm.sync_stdout)
2283 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2285 g_string_free(s, TRUE);
2289 save_cookies (SoupMessage *msg, gpointer user_data){
2293 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2294 cookie = soup_cookie_to_set_cookie_header(ck->data);
2295 SoupURI * soup_uri = soup_message_get_uri(msg);
2296 GString *s = g_string_new ("");
2297 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2298 run_handler(uzbl.behave.cookie_handler, s->str);
2300 g_string_free(s, TRUE);
2305 /* --- WEBINSPECTOR --- */
2307 hide_window_cb(GtkWidget *widget, gpointer data) {
2310 gtk_widget_hide(widget);
2313 static WebKitWebView*
2314 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2317 (void) web_inspector;
2318 GtkWidget* scrolled_window;
2319 GtkWidget* new_web_view;
2322 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2323 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2324 G_CALLBACK(hide_window_cb), NULL);
2326 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2327 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2328 gtk_widget_show(g->inspector_window);
2330 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2331 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2332 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2333 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2334 gtk_widget_show(scrolled_window);
2336 new_web_view = webkit_web_view_new();
2337 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2339 return WEBKIT_WEB_VIEW(new_web_view);
2343 inspector_show_window_cb (WebKitWebInspector* inspector){
2345 gtk_widget_show(uzbl.gui.inspector_window);
2349 /* TODO: Add variables and code to make use of these functions */
2351 inspector_close_window_cb (WebKitWebInspector* inspector){
2357 inspector_attach_window_cb (WebKitWebInspector* inspector){
2363 inspector_detach_window_cb (WebKitWebInspector* inspector){
2369 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2375 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2381 set_up_inspector() {
2383 WebKitWebSettings *settings = view_settings();
2384 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2386 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2387 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2388 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2389 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2390 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2391 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2392 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2394 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2398 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2400 uzbl_cmdprop *c = v;
2405 if(c->type == TYPE_STR)
2406 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2407 else if(c->type == TYPE_INT)
2408 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2412 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2416 printf("bind %s = %s %s\n", (char *)k ,
2417 (char *)a->name, a->param?(char *)a->param:"");
2422 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2423 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2428 main (int argc, char* argv[]) {
2429 gtk_init (&argc, &argv);
2430 if (!g_thread_supported ())
2431 g_thread_init (NULL);
2432 uzbl.state.executable_path = g_strdup(argv[0]);
2433 uzbl.state.selected_url = NULL;
2434 uzbl.state.searchtx = NULL;
2436 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2437 g_option_context_add_main_entries (context, entries, NULL);
2438 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2439 g_option_context_parse (context, &argc, &argv, NULL);
2440 g_option_context_free(context);
2442 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2443 gboolean verbose_override = uzbl.state.verbose;
2445 /* initialize hash table */
2446 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2448 uzbl.net.soup_session = webkit_get_default_session();
2449 uzbl.state.keycmd = g_string_new("");
2451 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2452 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2453 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2454 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2455 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2456 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2459 if(uname(&uzbl.state.unameinfo) == -1)
2460 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2462 uzbl.gui.sbar.progress_s = g_strdup("=");
2463 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2464 uzbl.gui.sbar.progress_w = 10;
2466 /* HTML mode defaults*/
2467 uzbl.behave.html_buffer = g_string_new("");
2468 uzbl.behave.html_endmarker = g_strdup(".");
2469 uzbl.behave.html_timeout = 60;
2470 uzbl.behave.base_url = g_strdup("http://invalid");
2472 /* default mode indicators */
2473 uzbl.behave.insert_indicator = g_strdup("I");
2474 uzbl.behave.cmd_indicator = g_strdup("C");
2478 make_var_to_name_hash();
2480 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2482 uzbl.gui.scrolled_win = create_browser();
2485 /* initial packing */
2486 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2487 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2489 uzbl.gui.main_window = create_window ();
2490 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2493 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2494 gtk_widget_show_all (uzbl.gui.main_window);
2495 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2497 if (uzbl.state.verbose) {
2498 printf("Uzbl start location: %s\n", argv[0]);
2499 printf("window_id %i\n",(int) uzbl.xwin);
2500 printf("pid %i\n", getpid ());
2501 printf("name: %s\n", uzbl.state.instance_name);
2504 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2505 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2506 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2507 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2508 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2512 if (!uzbl.behave.show_status)
2513 gtk_widget_hide(uzbl.gui.mainbar);
2522 if (verbose_override > uzbl.state.verbose)
2523 uzbl.state.verbose = verbose_override;
2526 set_var_value("uri", uri_override);
2527 g_free(uri_override);
2528 } else if (uzbl.state.uri)
2529 cmd_load_uri(uzbl.gui.web_view, NULL);
2534 return EXIT_SUCCESS;
2537 /* vi: set et ts=4: */