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 {
81 /* TODO: Make this ambiguous void **ptr into a union { char *char_p; int *int_p; float *float_p; } val;
82 the PTR() macro is kind of preventing this change at the moment. */
89 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
91 /* an abbreviation to help keep the table's width humane */
92 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
97 } var_name_to_ptr[] = {
98 /* variable name pointer to variable in code type dump callback function */
99 /* --------------------------------------------------------------------------------------- */
100 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
101 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
102 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
103 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
104 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
105 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
106 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
107 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
108 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
109 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
110 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
111 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
112 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
113 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
114 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
115 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
116 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
117 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
118 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
119 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
120 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
121 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
122 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
123 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
124 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
125 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
126 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
127 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
128 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
129 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
130 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
131 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
132 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
133 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
134 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
135 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
136 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
137 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
138 /* exported WebKitWebSettings properties */
139 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
140 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
141 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
142 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
143 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
144 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
145 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
146 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
147 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
148 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
149 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
150 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
151 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
152 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
153 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
154 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
156 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
157 }, *n2v_p = var_name_to_ptr;
163 { "SHIFT", GDK_SHIFT_MASK }, // shift
164 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
165 { "CONTROL", GDK_CONTROL_MASK }, // control
166 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
167 { "MOD2", GDK_MOD2_MASK }, // 5th mod
168 { "MOD3", GDK_MOD3_MASK }, // 6th mod
169 { "MOD4", GDK_MOD4_MASK }, // 7th mod
170 { "MOD5", GDK_MOD5_MASK }, // 8th mod
171 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
172 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
173 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
174 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
175 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
176 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
177 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
178 { "META", GDK_META_MASK }, // meta (since 2.10)
183 /* construct a hash from the var_name_to_ptr array for quick access */
185 make_var_to_name_hash() {
186 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
188 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
193 /* --- UTILITY FUNCTIONS --- */
195 expand_vars(char *s) {
198 char ret[256], *vend;
199 GString *buf = g_string_new("");
204 g_string_append_c(buf, *++s);
212 if( (vend = strchr(s, upto)) ||
213 (vend = strchr(s, '\0')) ) {
214 strncpy(ret, s, vend-s);
216 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
217 if(c->type == TYPE_STR)
218 g_string_append(buf, (gchar *)*c->ptr);
219 else if(c->type == TYPE_INT) {
220 g_string_append_printf(buf, "%d", (int)*c->ptr);
222 else if(c->type == TYPE_FLOAT) {
223 g_string_append_printf(buf, "%f", *(float *)c->ptr);
226 if(upto == ' ') s = vend;
232 g_string_append_c(buf, *s);
237 return g_string_free(buf, FALSE);
244 snprintf(tmp, sizeof(tmp), "%i", val);
245 return g_strdup(tmp);
249 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
252 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
255 str_replace (const char* search, const char* replace, const char* string) {
259 buf = g_strsplit (string, search, -1);
260 ret = g_strjoinv (replace, buf);
261 g_strfreev(buf); // somebody said this segfaults
267 read_file_by_line (gchar *path) {
268 GIOChannel *chan = NULL;
269 gchar *readbuf = NULL;
271 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
274 chan = g_io_channel_new_file(path, "r", NULL);
277 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
278 const gchar* val = g_strdup (readbuf);
279 g_array_append_val (lines, val);
284 g_io_channel_unref (chan);
286 fprintf(stderr, "File '%s' not be read.\n", path);
293 gchar* parseenv (char* string) {
294 extern char** environ;
295 gchar* tmpstr = NULL;
299 while (environ[i] != NULL) {
300 gchar** env = g_strsplit (environ[i], "=", 2);
301 gchar* envname = g_strconcat ("$", env[0], NULL);
303 if (g_strrstr (string, envname) != NULL) {
304 tmpstr = g_strdup(string);
306 string = str_replace(envname, env[1], tmpstr);
311 g_strfreev (env); // somebody said this breaks uzbl
319 setup_signal(int signr, sigfunc *shandler) {
320 struct sigaction nh, oh;
322 nh.sa_handler = shandler;
323 sigemptyset(&nh.sa_mask);
326 if(sigaction(signr, &nh, &oh) < 0)
334 if (uzbl.behave.fifo_dir)
335 unlink (uzbl.comm.fifo_path);
336 if (uzbl.behave.socket_dir)
337 unlink (uzbl.comm.socket_path);
339 g_free(uzbl.state.executable_path);
340 g_string_free(uzbl.state.keycmd, TRUE);
341 g_hash_table_destroy(uzbl.bindings);
342 g_hash_table_destroy(uzbl.behave.commands);
343 g_scanner_destroy(uzbl.scan);
346 /* used for html_mode_timeout
347 * be sure to extend this function to use
348 * more timers if needed in other places
351 set_timeout(int seconds) {
353 memset(&t, 0, sizeof t);
355 t.it_value.tv_sec = seconds;
356 t.it_value.tv_usec = 0;
357 setitimer(ITIMER_REAL, &t, NULL);
360 /* --- SIGNAL HANDLER --- */
363 catch_sigterm(int s) {
369 catch_sigint(int s) {
379 set_var_value("mode", "0");
384 /* --- CALLBACKS --- */
387 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
390 (void) navigation_action;
391 (void) policy_decision;
393 const gchar* uri = webkit_network_request_get_uri (request);
394 if (uzbl.state.verbose)
395 printf("New window requested -> %s \n", uri);
396 new_window_load_uri(uri);
401 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
406 /* If we can display it, let's display it... */
407 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
408 webkit_web_policy_decision_use (policy_decision);
412 /* ...everything we can't displayed is downloaded */
413 webkit_web_policy_decision_download (policy_decision);
418 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
422 if (uzbl.state.selected_url != NULL) {
423 if (uzbl.state.verbose)
424 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
425 new_window_load_uri(uzbl.state.selected_url);
427 if (uzbl.state.verbose)
428 printf("New web view -> %s\n","Nothing to open, exiting");
434 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
437 if (uzbl.behave.download_handler) {
438 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
439 if (uzbl.state.verbose)
440 printf("Download -> %s\n",uri);
441 /* if urls not escaped, we may have to escape and quote uri before this call */
442 run_handler(uzbl.behave.download_handler, uri);
447 /* scroll a bar in a given direction */
449 scroll (GtkAdjustment* bar, GArray *argv) {
453 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
454 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
455 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
459 scroll_begin(WebKitWebView* page, GArray *argv) {
460 (void) page; (void) argv;
461 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
465 scroll_end(WebKitWebView* page, GArray *argv) {
466 (void) page; (void) argv;
467 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
468 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
472 scroll_vert(WebKitWebView* page, GArray *argv) {
474 scroll(uzbl.gui.bar_v, argv);
478 scroll_horz(WebKitWebView* page, GArray *argv) {
480 scroll(uzbl.gui.bar_h, argv);
485 if (!uzbl.behave.show_status) {
486 gtk_widget_hide(uzbl.gui.mainbar);
488 gtk_widget_show(uzbl.gui.mainbar);
494 toggle_status_cb (WebKitWebView* page, GArray *argv) {
498 if (uzbl.behave.show_status) {
499 gtk_widget_hide(uzbl.gui.mainbar);
501 gtk_widget_show(uzbl.gui.mainbar);
503 uzbl.behave.show_status = !uzbl.behave.show_status;
508 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
512 //Set selected_url state variable
513 g_free(uzbl.state.selected_url);
514 uzbl.state.selected_url = NULL;
516 uzbl.state.selected_url = g_strdup(link);
522 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
526 if (uzbl.gui.main_title)
527 g_free (uzbl.gui.main_title);
528 uzbl.gui.main_title = g_strdup (title);
533 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
536 uzbl.gui.sbar.load_progress = progress;
541 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
545 if (uzbl.behave.load_finish_handler)
546 run_handler(uzbl.behave.load_finish_handler, "");
550 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
554 uzbl.gui.sbar.load_progress = 0;
555 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
556 if (uzbl.behave.load_start_handler)
557 run_handler(uzbl.behave.load_start_handler, "");
561 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
564 g_free (uzbl.state.uri);
565 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
566 uzbl.state.uri = g_string_free (newuri, FALSE);
567 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
568 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
571 if (uzbl.behave.load_commit_handler)
572 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
576 destroy_cb (GtkWidget* widget, gpointer data) {
584 if (uzbl.behave.history_handler) {
586 struct tm * timeinfo;
589 timeinfo = localtime ( &rawtime );
590 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
591 run_handler(uzbl.behave.history_handler, date);
596 /* VIEW funcs (little webkit wrappers) */
597 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
599 VIEWFUNC(reload_bypass_cache)
600 VIEWFUNC(stop_loading)
607 /* -- command to callback/function map for things we cannot attach to any signals */
608 static struct {char *name; Command command[2];} cmdlist[] =
609 { /* key function no_split */
610 { "back", {view_go_back, 0} },
611 { "forward", {view_go_forward, 0} },
612 { "scroll_vert", {scroll_vert, 0} },
613 { "scroll_horz", {scroll_horz, 0} },
614 { "scroll_begin", {scroll_begin, 0} },
615 { "scroll_end", {scroll_end, 0} },
616 { "reload", {view_reload, 0}, },
617 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
618 { "stop", {view_stop_loading, 0}, },
619 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
620 { "zoom_out", {view_zoom_out, 0}, },
621 { "uri", {load_uri, NOSPLIT} },
622 { "js", {run_js, NOSPLIT} },
623 { "script", {run_external_js, 0} },
624 { "toggle_status", {toggle_status_cb, 0} },
625 { "spawn", {spawn, 0} },
626 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
627 { "sh", {spawn_sh, 0} },
628 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
629 { "exit", {close_uzbl, 0} },
630 { "quit", {close_uzbl, 0} },
631 { "search", {search_forward_text, NOSPLIT} },
632 { "search_reverse", {search_reverse_text, NOSPLIT} },
633 { "dehilight", {dehilight, 0} },
634 { "toggle_insert_mode", {toggle_insert_mode, 0} },
635 { "set", {set_var, NOSPLIT} },
636 //{ "get", {get_var, NOSPLIT} },
637 { "bind", {act_bind, NOSPLIT} },
638 { "dump_config", {act_dump_config, 0} },
639 { "keycmd", {keycmd, NOSPLIT} },
640 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
641 { "keycmd_bs", {keycmd_bs, 0} },
642 { "chain", {chain, 0} },
643 { "print", {print, NOSPLIT} }
650 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
652 for (i = 0; i < LENGTH(cmdlist); i++)
653 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
656 /* -- CORE FUNCTIONS -- */
659 free_action(gpointer act) {
660 Action *action = (Action*)act;
661 g_free(action->name);
663 g_free(action->param);
668 new_action(const gchar *name, const gchar *param) {
669 Action *action = g_new(Action, 1);
671 action->name = g_strdup(name);
673 action->param = g_strdup(param);
675 action->param = NULL;
681 file_exists (const char * filename) {
682 return (access(filename, F_OK) == 0);
686 set_var(WebKitWebView *page, GArray *argv) {
688 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
689 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
690 set_var_value(g_strstrip(split[0]), value);
696 print(WebKitWebView *page, GArray *argv) {
700 buf = expand_vars(argv_idx(argv, 0));
706 act_bind(WebKitWebView *page, GArray *argv) {
708 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
709 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
710 add_binding(g_strstrip(split[0]), value);
722 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
725 if (argv_idx(argv, 0)) {
726 if (strcmp (argv_idx(argv, 0), "0") == 0) {
727 uzbl.behave.insert_mode = FALSE;
729 uzbl.behave.insert_mode = TRUE;
732 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
739 load_uri (WebKitWebView *web_view, GArray *argv) {
740 if (argv_idx(argv, 0)) {
741 GString* newuri = g_string_new (argv_idx(argv, 0));
742 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
743 run_js(web_view, argv);
746 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
747 g_string_prepend (newuri, "http://");
748 /* if we do handle cookies, ask our handler for them */
749 webkit_web_view_load_uri (web_view, newuri->str);
750 g_string_free (newuri, TRUE);
755 run_js (WebKitWebView * web_view, GArray *argv) {
756 if (argv_idx(argv, 0))
757 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
761 run_external_js (WebKitWebView * web_view, GArray *argv) {
762 if (argv_idx(argv, 0)) {
763 GArray* lines = read_file_by_line (argv_idx (argv, 0));
768 while ((line = g_array_index(lines, gchar*, i))) {
770 js = g_strdup (line);
772 gchar* newjs = g_strconcat (js, line, NULL);
779 if (uzbl.state.verbose)
780 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
782 if (argv_idx (argv, 1)) {
783 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
787 webkit_web_view_execute_script (web_view, js);
789 g_array_free (lines, TRUE);
794 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
795 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
796 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
797 webkit_web_view_unmark_text_matches (page);
798 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
799 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
803 if (uzbl.state.searchtx) {
804 if (uzbl.state.verbose)
805 printf ("Searching: %s\n", uzbl.state.searchtx);
806 webkit_web_view_set_highlight_text_matches (page, TRUE);
807 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
812 search_forward_text (WebKitWebView *page, GArray *argv) {
813 search_text(page, argv, TRUE);
817 search_reverse_text (WebKitWebView *page, GArray *argv) {
818 search_text(page, argv, FALSE);
822 dehilight (WebKitWebView *page, GArray *argv) {
824 webkit_web_view_set_highlight_text_matches (page, FALSE);
829 new_window_load_uri (const gchar * uri) {
830 GString* to_execute = g_string_new ("");
831 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
833 for (i = 0; entries[i].long_name != NULL; i++) {
834 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
835 gchar** str = (gchar**)entries[i].arg_data;
837 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
841 if (uzbl.state.verbose)
842 printf("\n%s\n", to_execute->str);
843 g_spawn_command_line_async (to_execute->str, NULL);
844 g_string_free (to_execute, TRUE);
848 chain (WebKitWebView *page, GArray *argv) {
851 gchar **parts = NULL;
853 while ((a = argv_idx(argv, i++))) {
854 parts = g_strsplit (a, " ", 2);
855 parse_command(parts[0], parts[1]);
861 keycmd (WebKitWebView *page, GArray *argv) {
864 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
870 keycmd_nl (WebKitWebView *page, GArray *argv) {
873 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
879 keycmd_bs (WebKitWebView *page, GArray *argv) {
882 g_string_truncate(uzbl.state.keycmd,
883 /* Calculate the number of bytes to truncate...
884 * This is not simply (len-1) when dealing with UTF-8 string */
885 g_utf8_offset_to_pointer(uzbl.state.keycmd->str,
886 g_utf8_strlen(uzbl.state.keycmd->str, uzbl.state.keycmd->len) - 1)
887 - uzbl.state.keycmd->str);
892 close_uzbl (WebKitWebView *page, GArray *argv) {
898 /* --Statusbar functions-- */
900 build_progressbar_ascii(int percent) {
901 int width=uzbl.gui.sbar.progress_w;
904 GString *bar = g_string_new("");
906 l = (double)percent*((double)width/100.);
907 l = (int)(l+.5)>=(int)l ? l+.5 : l;
909 for(i=0; i<(int)l; i++)
910 g_string_append(bar, uzbl.gui.sbar.progress_s);
913 g_string_append(bar, uzbl.gui.sbar.progress_u);
915 return g_string_free(bar, FALSE);
920 const GScannerConfig scan_config = {
923 ) /* cset_skip_characters */,
928 ) /* cset_identifier_first */,
935 ) /* cset_identifier_nth */,
936 ( "" ) /* cpair_comment_single */,
938 TRUE /* case_sensitive */,
940 FALSE /* skip_comment_multi */,
941 FALSE /* skip_comment_single */,
942 FALSE /* scan_comment_multi */,
943 TRUE /* scan_identifier */,
944 TRUE /* scan_identifier_1char */,
945 FALSE /* scan_identifier_NULL */,
946 TRUE /* scan_symbols */,
947 FALSE /* scan_binary */,
948 FALSE /* scan_octal */,
949 FALSE /* scan_float */,
950 FALSE /* scan_hex */,
951 FALSE /* scan_hex_dollar */,
952 FALSE /* scan_string_sq */,
953 FALSE /* scan_string_dq */,
954 TRUE /* numbers_2_int */,
955 FALSE /* int_2_float */,
956 FALSE /* identifier_2_string */,
957 FALSE /* char_2_token */,
958 FALSE /* symbol_2_token */,
959 TRUE /* scope_0_fallback */,
964 uzbl.scan = g_scanner_new(&scan_config);
965 while(symp->symbol_name) {
966 g_scanner_scope_add_symbol(uzbl.scan, 0,
968 GINT_TO_POINTER(symp->symbol_token));
974 expand_template(const char *template, gboolean escape_markup) {
975 if(!template) return NULL;
977 GTokenType token = G_TOKEN_NONE;
978 GString *ret = g_string_new("");
982 g_scanner_input_text(uzbl.scan, template, strlen(template));
983 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
984 token = g_scanner_get_next_token(uzbl.scan);
986 if(token == G_TOKEN_SYMBOL) {
987 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
991 buf = uzbl.state.uri ?
992 g_markup_printf_escaped("%s", uzbl.state.uri) : g_strdup("");
993 g_string_append(ret, buf);
997 g_string_append(ret, uzbl.state.uri ?
998 uzbl.state.uri : g_strdup(""));
1001 buf = itos(uzbl.gui.sbar.load_progress);
1002 g_string_append(ret, buf);
1005 case SYM_LOADPRGSBAR:
1006 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1007 g_string_append(ret, buf);
1012 buf = uzbl.gui.main_title ?
1013 g_markup_printf_escaped("%s", uzbl.gui.main_title) : g_strdup("");
1014 g_string_append(ret, buf);
1018 g_string_append(ret, uzbl.gui.main_title ?
1019 uzbl.gui.main_title : g_strdup(""));
1021 case SYM_SELECTED_URI:
1023 buf = uzbl.state.selected_url ?
1024 g_markup_printf_escaped("%s", uzbl.state.selected_url) : g_strdup("");
1025 g_string_append(ret, buf);
1029 g_string_append(ret, uzbl.state.selected_url ?
1030 uzbl.state.selected_url : g_strdup(""));
1033 buf = itos(uzbl.xwin);
1034 g_string_append(ret,
1035 uzbl.state.instance_name ? uzbl.state.instance_name : buf);
1040 buf = uzbl.state.keycmd->str ?
1041 g_markup_printf_escaped("%s", uzbl.state.keycmd->str) : g_strdup("");
1042 g_string_append(ret, buf);
1046 g_string_append(ret, uzbl.state.keycmd->str ?
1047 uzbl.state.keycmd->str : g_strdup(""));
1050 g_string_append(ret,
1051 uzbl.behave.insert_mode ?
1052 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
1055 g_string_append(ret,
1056 uzbl.gui.sbar.msg ? uzbl.gui.sbar.msg : "");
1058 /* useragent syms */
1060 buf = itos(WEBKIT_MAJOR_VERSION);
1061 g_string_append(ret, buf);
1065 buf = itos(WEBKIT_MINOR_VERSION);
1066 g_string_append(ret, buf);
1070 buf = itos(WEBKIT_MICRO_VERSION);
1071 g_string_append(ret, buf);
1075 g_string_append(ret, uzbl.state.unameinfo.sysname);
1078 g_string_append(ret, uzbl.state.unameinfo.nodename);
1081 g_string_append(ret, uzbl.state.unameinfo.release);
1084 g_string_append(ret, uzbl.state.unameinfo.version);
1087 g_string_append(ret, uzbl.state.unameinfo.machine);
1090 g_string_append(ret, ARCH);
1093 case SYM_DOMAINNAME:
1094 g_string_append(ret, uzbl.state.unameinfo.domainname);
1098 g_string_append(ret, COMMIT);
1104 else if(token == G_TOKEN_INT) {
1105 g_string_append_printf(ret, "%lu", g_scanner_cur_value(uzbl.scan).v_int);
1107 else if(token == G_TOKEN_IDENTIFIER) {
1108 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1110 else if(token == G_TOKEN_CHAR) {
1111 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1113 else if(token == G_TOKEN_ERROR) {
1114 g_scanner_error(uzbl.scan, "Token error in template ('%s') at line %d, column %d.",
1116 g_scanner_cur_line(uzbl.scan),
1117 g_scanner_cur_position(uzbl.scan));
1121 return g_string_free(ret, FALSE);
1123 /* --End Statusbar functions-- */
1126 sharg_append(GArray *a, const gchar *str) {
1127 const gchar *s = (str ? str : "");
1128 g_array_append_val(a, s);
1131 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1133 run_command (const gchar *command, const guint npre, const gchar **args,
1134 const gboolean sync, char **output_stdout) {
1135 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1138 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1139 gchar *pid = itos(getpid());
1140 gchar *xwin = itos(uzbl.xwin);
1142 sharg_append(a, command);
1143 for (i = 0; i < npre; i++) /* add n args before the default vars */
1144 sharg_append(a, args[i]);
1145 sharg_append(a, uzbl.state.config_file);
1146 sharg_append(a, pid);
1147 sharg_append(a, xwin);
1148 sharg_append(a, uzbl.comm.fifo_path);
1149 sharg_append(a, uzbl.comm.socket_path);
1150 sharg_append(a, uzbl.state.uri);
1151 sharg_append(a, uzbl.gui.main_title);
1153 for (i = npre; i < g_strv_length((gchar**)args); i++)
1154 sharg_append(a, args[i]);
1158 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1160 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1161 NULL, NULL, output_stdout, NULL, NULL, &err);
1162 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1163 NULL, NULL, NULL, &err);
1165 if (uzbl.state.verbose) {
1166 GString *s = g_string_new("spawned:");
1167 for (i = 0; i < (a->len); i++) {
1168 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1169 g_string_append_printf(s, " %s", qarg);
1172 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1173 printf("%s\n", s->str);
1174 g_string_free(s, TRUE);
1176 printf("Stdout: %s\n", *output_stdout);
1180 g_printerr("error on run_command: %s\n", err->message);
1185 g_array_free (a, TRUE);
1190 split_quoted(const gchar* src, const gboolean unquote) {
1191 /* split on unquoted space, return array of strings;
1192 remove a layer of quotes and backslashes if unquote */
1193 if (!src) return NULL;
1195 gboolean dq = FALSE;
1196 gboolean sq = FALSE;
1197 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1198 GString *s = g_string_new ("");
1202 for (p = src; *p != '\0'; p++) {
1203 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1204 else if (*p == '\\') { g_string_append_c(s, *p++);
1205 g_string_append_c(s, *p); }
1206 else if ((*p == '"') && unquote && !sq) dq = !dq;
1207 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1209 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1210 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1212 else if ((*p == ' ') && !dq && !sq) {
1213 dup = g_strdup(s->str);
1214 g_array_append_val(a, dup);
1215 g_string_truncate(s, 0);
1216 } else g_string_append_c(s, *p);
1218 dup = g_strdup(s->str);
1219 g_array_append_val(a, dup);
1220 ret = (gchar**)a->data;
1221 g_array_free (a, FALSE);
1222 g_string_free (s, TRUE);
1227 spawn(WebKitWebView *web_view, GArray *argv) {
1229 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1230 if (argv_idx(argv, 0))
1231 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1235 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1238 if (argv_idx(argv, 0))
1239 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1240 TRUE, &uzbl.comm.sync_stdout);
1244 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1246 if (!uzbl.behave.shell_cmd) {
1247 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1252 gchar *spacer = g_strdup("");
1253 g_array_insert_val(argv, 1, spacer);
1254 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1256 for (i = 1; i < g_strv_length(cmd); i++)
1257 g_array_prepend_val(argv, cmd[i]);
1259 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1265 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1267 if (!uzbl.behave.shell_cmd) {
1268 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1273 gchar *spacer = g_strdup("");
1274 g_array_insert_val(argv, 1, spacer);
1275 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1277 for (i = 1; i < g_strv_length(cmd); i++)
1278 g_array_prepend_val(argv, cmd[i]);
1280 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1281 TRUE, &uzbl.comm.sync_stdout);
1287 parse_command(const char *cmd, const char *param) {
1290 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1293 gchar **par = split_quoted(param, TRUE);
1294 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1296 if (c[1] == NOSPLIT) { /* don't split */
1297 sharg_append(a, param);
1299 for (i = 0; i < g_strv_length(par); i++)
1300 sharg_append(a, par[i]);
1302 c[0](uzbl.gui.web_view, a);
1304 g_array_free (a, TRUE);
1307 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1314 if(*uzbl.net.proxy_url == ' '
1315 || uzbl.net.proxy_url == NULL) {
1316 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1317 (GType) SOUP_SESSION_PROXY_URI);
1320 suri = soup_uri_new(uzbl.net.proxy_url);
1321 g_object_set(G_OBJECT(uzbl.net.soup_session),
1322 SOUP_SESSION_PROXY_URI,
1324 soup_uri_free(suri);
1331 if(file_exists(uzbl.gui.icon)) {
1332 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1334 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1340 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1341 g_array_append_val (a, uzbl.state.uri);
1342 load_uri(uzbl.gui.web_view, a);
1343 g_array_free (a, TRUE);
1347 cmd_always_insert_mode() {
1348 uzbl.behave.insert_mode =
1349 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1355 g_object_set(G_OBJECT(uzbl.net.soup_session),
1356 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1360 cmd_max_conns_host() {
1361 g_object_set(G_OBJECT(uzbl.net.soup_session),
1362 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1367 soup_session_remove_feature
1368 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1369 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1370 /*g_free(uzbl.net.soup_logger);*/
1372 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1373 soup_session_add_feature(uzbl.net.soup_session,
1374 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1377 static WebKitWebSettings*
1379 return webkit_web_view_get_settings(uzbl.gui.web_view);
1384 WebKitWebSettings *ws = view_settings();
1385 if (uzbl.behave.font_size > 0) {
1386 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1389 if (uzbl.behave.monospace_size > 0) {
1390 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1391 uzbl.behave.monospace_size, NULL);
1393 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1394 uzbl.behave.font_size, NULL);
1400 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1404 cmd_disable_plugins() {
1405 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1406 !uzbl.behave.disable_plugins, NULL);
1410 cmd_disable_scripts() {
1411 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1412 !uzbl.behave.disable_scripts, NULL);
1416 cmd_minimum_font_size() {
1417 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1418 uzbl.behave.minimum_font_size, NULL);
1421 cmd_autoload_img() {
1422 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1423 uzbl.behave.autoload_img, NULL);
1428 cmd_autoshrink_img() {
1429 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1430 uzbl.behave.autoshrink_img, NULL);
1435 cmd_enable_spellcheck() {
1436 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1437 uzbl.behave.enable_spellcheck, NULL);
1441 cmd_enable_private() {
1442 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1443 uzbl.behave.enable_private, NULL);
1448 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1449 uzbl.behave.print_bg, NULL);
1454 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1455 uzbl.behave.style_uri, NULL);
1459 cmd_resizable_txt() {
1460 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1461 uzbl.behave.resizable_txt, NULL);
1465 cmd_default_encoding() {
1466 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1467 uzbl.behave.default_encoding, NULL);
1471 cmd_enforce_96dpi() {
1472 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1473 uzbl.behave.enforce_96dpi, NULL);
1477 cmd_caret_browsing() {
1478 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1479 uzbl.behave.caret_browsing, NULL);
1483 cmd_cookie_handler() {
1484 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1485 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1486 if ((g_strcmp0(split[0], "sh") == 0) ||
1487 (g_strcmp0(split[0], "spawn") == 0)) {
1488 g_free (uzbl.behave.cookie_handler);
1489 uzbl.behave.cookie_handler =
1490 g_strdup_printf("sync_%s %s", split[0], split[1]);
1497 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1502 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1507 if(uzbl.behave.inject_html) {
1508 webkit_web_view_load_html_string (uzbl.gui.web_view,
1509 uzbl.behave.inject_html, NULL);
1518 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1519 uzbl.behave.modmask = 0;
1521 if(uzbl.behave.modkey)
1522 g_free(uzbl.behave.modkey);
1523 uzbl.behave.modkey = buf;
1525 for (i = 0; modkeys[i].key != NULL; i++) {
1526 if (g_strrstr(buf, modkeys[i].key))
1527 uzbl.behave.modmask |= modkeys[i].mask;
1533 if (*uzbl.net.useragent == ' ') {
1534 g_free (uzbl.net.useragent);
1535 uzbl.net.useragent = NULL;
1537 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1539 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1540 g_free(uzbl.net.useragent);
1541 uzbl.net.useragent = ua;
1547 gtk_widget_ref(uzbl.gui.scrolled_win);
1548 gtk_widget_ref(uzbl.gui.mainbar);
1549 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1550 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1552 if(uzbl.behave.status_top) {
1553 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1554 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1557 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1558 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1560 gtk_widget_unref(uzbl.gui.scrolled_win);
1561 gtk_widget_unref(uzbl.gui.mainbar);
1562 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1567 set_var_value(gchar *name, gchar *val) {
1568 uzbl_cmdprop *c = NULL;
1572 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1573 /* check for the variable type */
1574 if (c->type == TYPE_STR) {
1575 buf = expand_vars(val);
1578 } else if(c->type == TYPE_INT) {
1579 int *ip = (int *)c->ptr;
1580 buf = expand_vars(val);
1581 *ip = (int)strtoul(buf, &endp, 10);
1583 } else if (c->type == TYPE_FLOAT) {
1584 float *fp = (float *)c->ptr;
1585 buf = expand_vars(val);
1586 *fp = strtod(buf, &endp);
1590 /* invoke a command specific function */
1591 if(c->func) c->func();
1598 Behaviour *b = &uzbl.behave;
1600 if(b->html_buffer->str) {
1601 webkit_web_view_load_html_string (uzbl.gui.web_view,
1602 b->html_buffer->str, b->base_url);
1603 g_string_free(b->html_buffer, TRUE);
1604 b->html_buffer = g_string_new("");
1608 enum {M_CMD, M_HTML};
1610 parse_cmd_line(const char *ctl_line) {
1611 Behaviour *b = &uzbl.behave;
1614 if(b->mode == M_HTML) {
1615 len = strlen(b->html_endmarker);
1616 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1617 if(len == strlen(ctl_line)-1 &&
1618 !strncmp(b->html_endmarker, ctl_line, len)) {
1620 set_var_value("mode", "0");
1625 set_timeout(b->html_timeout);
1626 g_string_append(b->html_buffer, ctl_line);
1629 else if((ctl_line[0] == '#') /* Comments */
1630 || (ctl_line[0] == ' ')
1631 || (ctl_line[0] == '\n'))
1632 ; /* ignore these lines */
1633 else { /* parse a command */
1635 gchar **tokens = NULL;
1636 len = strlen(ctl_line);
1638 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1639 ctlstrip = g_strndup(ctl_line, len - 1);
1640 else ctlstrip = g_strdup(ctl_line);
1642 tokens = g_strsplit(ctlstrip, " ", 2);
1643 parse_command(tokens[0], tokens[1]);
1650 build_stream_name(int type, const gchar* dir) {
1652 State *s = &uzbl.state;
1655 xwin_str = itos((int)uzbl.xwin);
1657 str = g_strdup_printf
1658 ("%s/uzbl_fifo_%s", dir,
1659 s->instance_name ? s->instance_name : xwin_str);
1660 } else if (type == SOCKET) {
1661 str = g_strdup_printf
1662 ("%s/uzbl_socket_%s", dir,
1663 s->instance_name ? s->instance_name : xwin_str );
1670 control_fifo(GIOChannel *gio, GIOCondition condition) {
1671 if (uzbl.state.verbose)
1672 printf("triggered\n");
1677 if (condition & G_IO_HUP)
1678 g_error ("Fifo: Read end of pipe died!\n");
1681 g_error ("Fifo: GIOChannel broke\n");
1683 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1684 if (ret == G_IO_STATUS_ERROR) {
1685 g_error ("Fifo: Error reading: %s\n", err->message);
1689 parse_cmd_line(ctl_line);
1696 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1697 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1698 if (unlink(uzbl.comm.fifo_path) == -1)
1699 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1700 g_free(uzbl.comm.fifo_path);
1701 uzbl.comm.fifo_path = NULL;
1704 if (*dir == ' ') { /* space unsets the variable */
1709 GIOChannel *chan = NULL;
1710 GError *error = NULL;
1711 gchar *path = build_stream_name(FIFO, dir);
1713 if (!file_exists(path)) {
1714 if (mkfifo (path, 0666) == 0) {
1715 // 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.
1716 chan = g_io_channel_new_file(path, "r+", &error);
1718 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1719 if (uzbl.state.verbose)
1720 printf ("init_fifo: created successfully as %s\n", path);
1721 uzbl.comm.fifo_path = path;
1723 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1724 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1725 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1726 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1728 /* if we got this far, there was an error; cleanup */
1729 if (error) g_error_free (error);
1736 control_stdin(GIOChannel *gio, GIOCondition condition) {
1738 gchar *ctl_line = NULL;
1741 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1742 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1745 parse_cmd_line(ctl_line);
1753 GIOChannel *chan = NULL;
1754 GError *error = NULL;
1756 chan = g_io_channel_unix_new(fileno(stdin));
1758 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1759 g_error ("Stdin: could not add watch\n");
1761 if (uzbl.state.verbose)
1762 printf ("Stdin: watch added successfully\n");
1765 g_error ("Stdin: Error while opening: %s\n", error->message);
1767 if (error) g_error_free (error);
1771 control_socket(GIOChannel *chan) {
1772 struct sockaddr_un remote;
1773 char buffer[512], *ctl_line;
1775 int sock, clientsock, n, done;
1778 sock = g_io_channel_unix_get_fd(chan);
1780 memset (buffer, 0, sizeof (buffer));
1782 t = sizeof (remote);
1783 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1787 memset (temp, 0, sizeof (temp));
1788 n = recv (clientsock, temp, 128, 0);
1790 buffer[strlen (buffer)] = '\0';
1794 strcat (buffer, temp);
1797 if (strcmp (buffer, "\n") < 0) {
1798 buffer[strlen (buffer) - 1] = '\0';
1800 buffer[strlen (buffer)] = '\0';
1803 ctl_line = g_strdup(buffer);
1804 parse_cmd_line (ctl_line);
1807 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1808 GError *error = NULL;
1811 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1812 if (ret == G_IO_STATUS_ERROR)
1813 g_error ("Error reading: %s\n", error->message);
1815 printf("Got line %s (%u bytes) \n",ctl_line, len);
1817 parse_line(ctl_line);
1825 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1826 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1827 if (unlink(uzbl.comm.socket_path) == -1)
1828 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1829 g_free(uzbl.comm.socket_path);
1830 uzbl.comm.socket_path = NULL;
1838 GIOChannel *chan = NULL;
1840 struct sockaddr_un local;
1841 gchar *path = build_stream_name(SOCKET, dir);
1843 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1845 local.sun_family = AF_UNIX;
1846 strcpy (local.sun_path, path);
1847 unlink (local.sun_path);
1849 len = strlen (local.sun_path) + sizeof (local.sun_family);
1850 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1851 if (uzbl.state.verbose)
1852 printf ("init_socket: opened in %s\n", path);
1855 if( (chan = g_io_channel_unix_new(sock)) ) {
1856 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1857 uzbl.comm.socket_path = path;
1860 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1862 /* if we got this far, there was an error; cleanup */
1869 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1870 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1872 // this function may be called very early when the templates are not set (yet), hence the checks
1874 update_title (void) {
1875 Behaviour *b = &uzbl.behave;
1878 if (b->show_status) {
1879 if (b->title_format_short) {
1880 parsed = expand_template(b->title_format_short, FALSE);
1881 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1884 if (b->status_format) {
1885 parsed = expand_template(b->status_format, TRUE);
1886 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1889 if (b->status_background) {
1891 gdk_color_parse (b->status_background, &color);
1892 //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)
1893 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1896 if (b->title_format_long) {
1897 parsed = expand_template(b->title_format_long, FALSE);
1898 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1905 key_press_cb (GtkWidget* window, GdkEventKey* event)
1907 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1911 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1912 || 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)
1915 /* turn off insert mode (if always_insert_mode is not used) */
1916 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1917 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1922 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1925 if (event->keyval == GDK_Escape) {
1926 g_string_truncate(uzbl.state.keycmd, 0);
1928 dehilight(uzbl.gui.web_view, NULL);
1932 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1933 if (event->keyval == GDK_Insert) {
1935 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1936 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1938 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1941 g_string_append (uzbl.state.keycmd, str);
1948 if (event->keyval == GDK_BackSpace)
1949 keycmd_bs(NULL, NULL);
1951 gboolean key_ret = FALSE;
1952 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1954 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1956 run_keycmd(key_ret);
1958 if (key_ret) return (!uzbl.behave.insert_mode);
1963 run_keycmd(const gboolean key_ret) {
1964 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1966 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1967 g_string_truncate(uzbl.state.keycmd, 0);
1968 parse_command(act->name, act->param);
1972 /* try if it's an incremental keycmd or one that takes args, and run it */
1973 GString* short_keys = g_string_new ("");
1974 GString* short_keys_inc = g_string_new ("");
1976 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1977 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1978 g_string_assign(short_keys_inc, short_keys->str);
1979 g_string_append_c(short_keys, '_');
1980 g_string_append_c(short_keys_inc, '*');
1982 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1983 /* run normal cmds only if return was pressed */
1984 exec_paramcmd(act, i);
1985 g_string_truncate(uzbl.state.keycmd, 0);
1987 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1988 if (key_ret) /* just quit the incremental command on return */
1989 g_string_truncate(uzbl.state.keycmd, 0);
1990 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1994 g_string_truncate(short_keys, short_keys->len - 1);
1996 g_string_free (short_keys, TRUE);
1997 g_string_free (short_keys_inc, TRUE);
2001 exec_paramcmd(const Action *act, const guint i) {
2002 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2003 GString *actionname = g_string_new ("");
2004 GString *actionparam = g_string_new ("");
2005 g_string_erase (parampart, 0, i+1);
2007 g_string_printf (actionname, act->name, parampart->str);
2009 g_string_printf (actionparam, act->param, parampart->str);
2010 parse_command(actionname->str, actionparam->str);
2011 g_string_free(actionname, TRUE);
2012 g_string_free(actionparam, TRUE);
2013 g_string_free(parampart, TRUE);
2021 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2022 //main_window_ref = g_object_ref(scrolled_window);
2023 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
2025 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2026 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2028 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2029 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2030 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2033 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2035 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2036 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2037 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2038 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2040 return scrolled_window;
2047 g->mainbar = gtk_hbox_new (FALSE, 0);
2049 /* keep a reference to the bar so we can re-pack it at runtime*/
2050 //sbar_ref = g_object_ref(g->mainbar);
2052 g->mainbar_label = gtk_label_new ("");
2053 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2054 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2055 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2056 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2057 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2058 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2063 GtkWidget* create_window () {
2064 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2065 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2066 gtk_widget_set_name (window, "Uzbl browser");
2067 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2068 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2074 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2076 If actname is one that calls an external command, this function will inject
2077 newargs in front of the user-provided args in that command line. They will
2078 come become after the body of the script (in sh) or after the name of
2079 the command to execute (in spawn).
2080 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2081 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2083 The return value consist of two strings: the action (sh, ...) and its args.
2085 If act is not one that calls an external command, then the given action merely
2088 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2089 gchar *actdup = g_strdup(actname);
2090 g_array_append_val(rets, actdup);
2092 if ((g_strcmp0(actname, "spawn") == 0) ||
2093 (g_strcmp0(actname, "sh") == 0) ||
2094 (g_strcmp0(actname, "sync_spawn") == 0) ||
2095 (g_strcmp0(actname, "sync_sh") == 0)) {
2097 GString *a = g_string_new("");
2098 gchar **spawnparts = split_quoted(origargs, FALSE);
2099 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2100 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2102 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2103 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2105 g_array_append_val(rets, a->str);
2106 g_string_free(a, FALSE);
2107 g_strfreev(spawnparts);
2109 gchar *origdup = g_strdup(origargs);
2110 g_array_append_val(rets, origdup);
2112 return (gchar**)g_array_free(rets, FALSE);
2116 run_handler (const gchar *act, const gchar *args) {
2117 /* Consider this code a temporary hack to make the handlers usable.
2118 In practice, all this splicing, injection, and reconstruction is
2119 inefficient, annoying and hard to manage. Potential pitfalls arise
2120 when the handler specific args 1) are not quoted (the handler
2121 callbacks should take care of this) 2) are quoted but interfere
2122 with the users' own quotation. A more ideal solution is
2123 to refactor parse_command so that it doesn't just take a string
2124 and execute it; rather than that, we should have a function which
2125 returns the argument vector parsed from the string. This vector
2126 could be modified (e.g. insert additional args into it) before
2127 passing it to the next function that actually executes it. Though
2128 it still isn't perfect for chain actions.. will reconsider & re-
2129 factor when I have the time. -duc */
2131 char **parts = g_strsplit(act, " ", 2);
2133 if (g_strcmp0(parts[0], "chain") == 0) {
2134 GString *newargs = g_string_new("");
2135 gchar **chainparts = split_quoted(parts[1], FALSE);
2137 /* for every argument in the chain, inject the handler args
2138 and make sure the new parts are wrapped in quotes */
2139 gchar **cp = chainparts;
2141 gchar *quotless = NULL;
2142 gchar **spliced_quotless = NULL; // sigh -_-;
2143 gchar **inpart = NULL;
2146 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2148 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2149 } else quotless = g_strdup(*cp);
2151 spliced_quotless = g_strsplit(quotless, " ", 2);
2152 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2153 g_strfreev(spliced_quotless);
2155 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2161 parse_command(parts[0], &(newargs->str[1]));
2162 g_string_free(newargs, TRUE);
2163 g_strfreev(chainparts);
2166 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2167 parse_command(inparts[0], inparts[1]);
2175 add_binding (const gchar *key, const gchar *act) {
2176 char **parts = g_strsplit(act, " ", 2);
2183 if (uzbl.state.verbose)
2184 printf ("Binding %-10s : %s\n", key, act);
2185 action = new_action(parts[0], parts[1]);
2187 if (g_hash_table_remove (uzbl.bindings, key))
2188 g_warning ("Overwriting existing binding for \"%s\"", key);
2189 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2194 get_xdg_var (XDG_Var xdg) {
2195 const gchar* actual_value = getenv (xdg.environmental);
2196 const gchar* home = getenv ("HOME");
2197 gchar* return_value;
2199 if (! actual_value || strcmp (actual_value, "") == 0) {
2200 if (xdg.default_value) {
2201 return_value = str_replace ("~", home, xdg.default_value);
2203 return_value = NULL;
2206 return_value = str_replace("~", home, actual_value);
2209 return return_value;
2213 find_xdg_file (int xdg_type, char* filename) {
2214 /* xdg_type = 0 => config
2215 xdg_type = 1 => data
2216 xdg_type = 2 => cache*/
2218 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2219 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2222 gchar* temporary_string;
2226 if (! file_exists (temporary_file) && xdg_type != 2) {
2227 buf = get_xdg_var (XDG[3 + xdg_type]);
2228 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2231 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2232 g_free (temporary_file);
2233 temporary_file = g_strconcat (temporary_string, filename, NULL);
2237 //g_free (temporary_string); - segfaults.
2239 if (file_exists (temporary_file)) {
2240 return temporary_file;
2247 State *s = &uzbl.state;
2248 Network *n = &uzbl.net;
2250 for (i = 0; default_config[i].command != NULL; i++) {
2251 parse_cmd_line(default_config[i].command);
2254 if (!s->config_file) {
2255 s->config_file = find_xdg_file (0, "/uzbl/config");
2258 if (s->config_file) {
2259 GArray* lines = read_file_by_line (s->config_file);
2263 while ((line = g_array_index(lines, gchar*, i))) {
2264 parse_cmd_line (line);
2268 g_array_free (lines, TRUE);
2270 if (uzbl.state.verbose)
2271 printf ("No configuration file loaded.\n");
2274 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2277 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2280 if (!uzbl.behave.cookie_handler)
2283 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2284 GString *s = g_string_new ("");
2285 SoupURI * soup_uri = soup_message_get_uri(msg);
2286 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2287 run_handler(uzbl.behave.cookie_handler, s->str);
2289 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2290 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2291 if ( p != NULL ) *p = '\0';
2292 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2294 if (uzbl.comm.sync_stdout)
2295 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2297 g_string_free(s, TRUE);
2301 save_cookies (SoupMessage *msg, gpointer user_data){
2305 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2306 cookie = soup_cookie_to_set_cookie_header(ck->data);
2307 SoupURI * soup_uri = soup_message_get_uri(msg);
2308 GString *s = g_string_new ("");
2309 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2310 run_handler(uzbl.behave.cookie_handler, s->str);
2312 g_string_free(s, TRUE);
2317 /* --- WEBINSPECTOR --- */
2319 hide_window_cb(GtkWidget *widget, gpointer data) {
2322 gtk_widget_hide(widget);
2325 static WebKitWebView*
2326 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2329 (void) web_inspector;
2330 GtkWidget* scrolled_window;
2331 GtkWidget* new_web_view;
2334 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2335 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2336 G_CALLBACK(hide_window_cb), NULL);
2338 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2339 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2340 gtk_widget_show(g->inspector_window);
2342 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2343 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2344 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2345 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2346 gtk_widget_show(scrolled_window);
2348 new_web_view = webkit_web_view_new();
2349 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2351 return WEBKIT_WEB_VIEW(new_web_view);
2355 inspector_show_window_cb (WebKitWebInspector* inspector){
2357 gtk_widget_show(uzbl.gui.inspector_window);
2361 /* TODO: Add variables and code to make use of these functions */
2363 inspector_close_window_cb (WebKitWebInspector* inspector){
2369 inspector_attach_window_cb (WebKitWebInspector* inspector){
2375 inspector_detach_window_cb (WebKitWebInspector* inspector){
2381 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2387 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2393 set_up_inspector() {
2395 WebKitWebSettings *settings = view_settings();
2396 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2398 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2399 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2400 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2401 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2402 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2403 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2404 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2406 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2410 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2412 uzbl_cmdprop *c = v;
2417 if(c->type == TYPE_STR)
2418 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2419 else if(c->type == TYPE_INT)
2420 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2421 else if(c->type == TYPE_FLOAT)
2422 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2426 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2430 printf("bind %s = %s %s\n", (char *)k ,
2431 (char *)a->name, a->param?(char *)a->param:"");
2436 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2437 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2442 main (int argc, char* argv[]) {
2443 gtk_init (&argc, &argv);
2444 if (!g_thread_supported ())
2445 g_thread_init (NULL);
2446 uzbl.state.executable_path = g_strdup(argv[0]);
2447 uzbl.state.selected_url = NULL;
2448 uzbl.state.searchtx = NULL;
2450 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2451 g_option_context_add_main_entries (context, entries, NULL);
2452 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2453 g_option_context_parse (context, &argc, &argv, NULL);
2454 g_option_context_free(context);
2456 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2457 gboolean verbose_override = uzbl.state.verbose;
2459 /* initialize hash table */
2460 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2462 uzbl.net.soup_session = webkit_get_default_session();
2463 uzbl.state.keycmd = g_string_new("");
2465 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2466 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2467 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2468 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2469 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2470 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2473 if(uname(&uzbl.state.unameinfo) == -1)
2474 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2476 uzbl.gui.sbar.progress_s = g_strdup("=");
2477 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2478 uzbl.gui.sbar.progress_w = 10;
2480 /* HTML mode defaults*/
2481 uzbl.behave.html_buffer = g_string_new("");
2482 uzbl.behave.html_endmarker = g_strdup(".");
2483 uzbl.behave.html_timeout = 60;
2484 uzbl.behave.base_url = g_strdup("http://invalid");
2486 /* default mode indicators */
2487 uzbl.behave.insert_indicator = g_strdup("I");
2488 uzbl.behave.cmd_indicator = g_strdup("C");
2492 make_var_to_name_hash();
2494 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2496 uzbl.gui.scrolled_win = create_browser();
2499 /* initial packing */
2500 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2501 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2503 uzbl.gui.main_window = create_window ();
2504 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2507 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2508 gtk_widget_show_all (uzbl.gui.main_window);
2509 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2511 if (uzbl.state.verbose) {
2512 printf("Uzbl start location: %s\n", argv[0]);
2513 printf("window_id %i\n",(int) uzbl.xwin);
2514 printf("pid %i\n", getpid ());
2515 printf("name: %s\n", uzbl.state.instance_name);
2518 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2519 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2520 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2521 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2522 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2526 if (!uzbl.behave.show_status)
2527 gtk_widget_hide(uzbl.gui.mainbar);
2536 if (verbose_override > uzbl.state.verbose)
2537 uzbl.state.verbose = verbose_override;
2540 set_var_value("uri", uri_override);
2541 g_free(uri_override);
2542 } else if (uzbl.state.uri)
2543 cmd_load_uri(uzbl.gui.web_view, NULL);
2548 return EXIT_SUCCESS;
2551 /* vi: set et ts=4: */