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 { "search", {search_forward_text, NOSPLIT} },
631 { "search_reverse", {search_reverse_text, NOSPLIT} },
632 { "dehilight", {dehilight, 0} },
633 { "toggle_insert_mode", {toggle_insert_mode, 0} },
634 { "set", {set_var, NOSPLIT} },
635 //{ "get", {get_var, NOSPLIT} },
636 { "bind", {act_bind, NOSPLIT} },
637 { "dump_config", {act_dump_config, 0} },
638 { "keycmd", {keycmd, NOSPLIT} },
639 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
640 { "keycmd_bs", {keycmd_bs, 0} },
641 { "chain", {chain, 0} },
642 { "print", {print, NOSPLIT} }
649 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
651 for (i = 0; i < LENGTH(cmdlist); i++)
652 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
655 /* -- CORE FUNCTIONS -- */
658 free_action(gpointer act) {
659 Action *action = (Action*)act;
660 g_free(action->name);
662 g_free(action->param);
667 new_action(const gchar *name, const gchar *param) {
668 Action *action = g_new(Action, 1);
670 action->name = g_strdup(name);
672 action->param = g_strdup(param);
674 action->param = NULL;
680 file_exists (const char * filename) {
681 return (access(filename, F_OK) == 0);
685 set_var(WebKitWebView *page, GArray *argv) {
687 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
688 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
689 set_var_value(g_strstrip(split[0]), value);
695 print(WebKitWebView *page, GArray *argv) {
699 buf = expand_vars(argv_idx(argv, 0));
705 act_bind(WebKitWebView *page, GArray *argv) {
707 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
708 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
709 add_binding(g_strstrip(split[0]), value);
721 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
724 if (argv_idx(argv, 0)) {
725 if (strcmp (argv_idx(argv, 0), "0") == 0) {
726 uzbl.behave.insert_mode = FALSE;
728 uzbl.behave.insert_mode = TRUE;
731 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
738 load_uri (WebKitWebView *web_view, GArray *argv) {
739 if (argv_idx(argv, 0)) {
740 GString* newuri = g_string_new (argv_idx(argv, 0));
741 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
742 run_js(web_view, argv);
745 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
746 g_string_prepend (newuri, "http://");
747 /* if we do handle cookies, ask our handler for them */
748 webkit_web_view_load_uri (web_view, newuri->str);
749 g_string_free (newuri, TRUE);
754 run_js (WebKitWebView * web_view, GArray *argv) {
755 if (argv_idx(argv, 0))
756 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
760 run_external_js (WebKitWebView * web_view, GArray *argv) {
761 if (argv_idx(argv, 0)) {
762 GArray* lines = read_file_by_line (argv_idx (argv, 0));
767 while ((line = g_array_index(lines, gchar*, i))) {
769 js = g_strdup (line);
771 gchar* newjs = g_strconcat (js, line, NULL);
778 if (uzbl.state.verbose)
779 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
781 if (argv_idx (argv, 1)) {
782 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
786 webkit_web_view_execute_script (web_view, js);
788 g_array_free (lines, TRUE);
793 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
794 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
795 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
796 webkit_web_view_unmark_text_matches (page);
797 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
798 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
802 if (uzbl.state.searchtx) {
803 if (uzbl.state.verbose)
804 printf ("Searching: %s\n", uzbl.state.searchtx);
805 webkit_web_view_set_highlight_text_matches (page, TRUE);
806 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
811 search_forward_text (WebKitWebView *page, GArray *argv) {
812 search_text(page, argv, TRUE);
816 search_reverse_text (WebKitWebView *page, GArray *argv) {
817 search_text(page, argv, FALSE);
821 dehilight (WebKitWebView *page, GArray *argv) {
823 webkit_web_view_set_highlight_text_matches (page, FALSE);
828 new_window_load_uri (const gchar * uri) {
829 GString* to_execute = g_string_new ("");
830 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
832 for (i = 0; entries[i].long_name != NULL; i++) {
833 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
834 gchar** str = (gchar**)entries[i].arg_data;
836 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
840 if (uzbl.state.verbose)
841 printf("\n%s\n", to_execute->str);
842 g_spawn_command_line_async (to_execute->str, NULL);
843 g_string_free (to_execute, TRUE);
847 chain (WebKitWebView *page, GArray *argv) {
850 gchar **parts = NULL;
852 while ((a = argv_idx(argv, i++))) {
853 parts = g_strsplit (a, " ", 2);
854 parse_command(parts[0], parts[1]);
860 keycmd (WebKitWebView *page, GArray *argv) {
863 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
869 keycmd_nl (WebKitWebView *page, GArray *argv) {
872 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
878 keycmd_bs (WebKitWebView *page, GArray *argv) {
881 g_string_truncate(uzbl.state.keycmd,
882 /* Calculate the number of bytes to truncate...
883 * This is not simply (len-1) when dealing with UTF-8 string */
884 g_utf8_offset_to_pointer(uzbl.state.keycmd->str,
885 g_utf8_strlen(uzbl.state.keycmd->str, uzbl.state.keycmd->len) - 1)
886 - uzbl.state.keycmd->str);
891 close_uzbl (WebKitWebView *page, GArray *argv) {
897 /* --Statusbar functions-- */
899 build_progressbar_ascii(int percent) {
900 int width=uzbl.gui.sbar.progress_w;
903 GString *bar = g_string_new("");
905 l = (double)percent*((double)width/100.);
906 l = (int)(l+.5)>=(int)l ? l+.5 : l;
908 for(i=0; i<(int)l; i++)
909 g_string_append(bar, uzbl.gui.sbar.progress_s);
912 g_string_append(bar, uzbl.gui.sbar.progress_u);
914 return g_string_free(bar, FALSE);
919 const GScannerConfig scan_config = {
922 ) /* cset_skip_characters */,
927 ) /* cset_identifier_first */,
934 ) /* cset_identifier_nth */,
935 ( "" ) /* cpair_comment_single */,
937 TRUE /* case_sensitive */,
939 FALSE /* skip_comment_multi */,
940 FALSE /* skip_comment_single */,
941 FALSE /* scan_comment_multi */,
942 TRUE /* scan_identifier */,
943 TRUE /* scan_identifier_1char */,
944 FALSE /* scan_identifier_NULL */,
945 TRUE /* scan_symbols */,
946 FALSE /* scan_binary */,
947 FALSE /* scan_octal */,
948 FALSE /* scan_float */,
949 FALSE /* scan_hex */,
950 FALSE /* scan_hex_dollar */,
951 FALSE /* scan_string_sq */,
952 FALSE /* scan_string_dq */,
953 TRUE /* numbers_2_int */,
954 FALSE /* int_2_float */,
955 FALSE /* identifier_2_string */,
956 FALSE /* char_2_token */,
957 FALSE /* symbol_2_token */,
958 TRUE /* scope_0_fallback */,
963 uzbl.scan = g_scanner_new(&scan_config);
964 while(symp->symbol_name) {
965 g_scanner_scope_add_symbol(uzbl.scan, 0,
967 GINT_TO_POINTER(symp->symbol_token));
973 expand_template(const char *template, gboolean escape_markup) {
974 if(!template) return NULL;
976 GTokenType token = G_TOKEN_NONE;
977 GString *ret = g_string_new("");
981 g_scanner_input_text(uzbl.scan, template, strlen(template));
982 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
983 token = g_scanner_get_next_token(uzbl.scan);
985 if(token == G_TOKEN_SYMBOL) {
986 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
990 buf = uzbl.state.uri ?
991 g_markup_printf_escaped("%s", uzbl.state.uri) : g_strdup("");
992 g_string_append(ret, buf);
996 g_string_append(ret, uzbl.state.uri ?
997 uzbl.state.uri : g_strdup(""));
1000 buf = itos(uzbl.gui.sbar.load_progress);
1001 g_string_append(ret, buf);
1004 case SYM_LOADPRGSBAR:
1005 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1006 g_string_append(ret, buf);
1011 buf = uzbl.gui.main_title ?
1012 g_markup_printf_escaped("%s", uzbl.gui.main_title) : g_strdup("");
1013 g_string_append(ret, buf);
1017 g_string_append(ret, uzbl.gui.main_title ?
1018 uzbl.gui.main_title : g_strdup(""));
1020 case SYM_SELECTED_URI:
1022 buf = uzbl.state.selected_url ?
1023 g_markup_printf_escaped("%s", uzbl.state.selected_url) : g_strdup("");
1024 g_string_append(ret, buf);
1028 g_string_append(ret, uzbl.state.selected_url ?
1029 uzbl.state.selected_url : g_strdup(""));
1032 buf = itos(uzbl.xwin);
1033 g_string_append(ret,
1034 uzbl.state.instance_name ? uzbl.state.instance_name : buf);
1039 buf = uzbl.state.keycmd->str ?
1040 g_markup_printf_escaped("%s", uzbl.state.keycmd->str) : g_strdup("");
1041 g_string_append(ret, buf);
1045 g_string_append(ret, uzbl.state.keycmd->str ?
1046 uzbl.state.keycmd->str : g_strdup(""));
1049 g_string_append(ret,
1050 uzbl.behave.insert_mode ?
1051 uzbl.behave.insert_indicator : uzbl.behave.cmd_indicator);
1054 g_string_append(ret,
1055 uzbl.gui.sbar.msg ? uzbl.gui.sbar.msg : "");
1057 /* useragent syms */
1059 buf = itos(WEBKIT_MAJOR_VERSION);
1060 g_string_append(ret, buf);
1064 buf = itos(WEBKIT_MINOR_VERSION);
1065 g_string_append(ret, buf);
1069 buf = itos(WEBKIT_MICRO_VERSION);
1070 g_string_append(ret, buf);
1074 g_string_append(ret, uzbl.state.unameinfo.sysname);
1077 g_string_append(ret, uzbl.state.unameinfo.nodename);
1080 g_string_append(ret, uzbl.state.unameinfo.release);
1083 g_string_append(ret, uzbl.state.unameinfo.version);
1086 g_string_append(ret, uzbl.state.unameinfo.machine);
1089 g_string_append(ret, ARCH);
1092 case SYM_DOMAINNAME:
1093 g_string_append(ret, uzbl.state.unameinfo.domainname);
1097 g_string_append(ret, COMMIT);
1103 else if(token == G_TOKEN_INT) {
1104 g_string_append_printf(ret, "%lu", g_scanner_cur_value(uzbl.scan).v_int);
1106 else if(token == G_TOKEN_IDENTIFIER) {
1107 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1109 else if(token == G_TOKEN_CHAR) {
1110 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1112 else if(token == G_TOKEN_ERROR) {
1113 g_scanner_error(uzbl.scan, "Token error in template ('%s') at line %d, column %d.",
1115 g_scanner_cur_line(uzbl.scan),
1116 g_scanner_cur_position(uzbl.scan));
1120 return g_string_free(ret, FALSE);
1122 /* --End Statusbar functions-- */
1125 sharg_append(GArray *a, const gchar *str) {
1126 const gchar *s = (str ? str : "");
1127 g_array_append_val(a, s);
1130 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1132 run_command (const gchar *command, const guint npre, const gchar **args,
1133 const gboolean sync, char **output_stdout) {
1134 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1137 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1138 gchar *pid = itos(getpid());
1139 gchar *xwin = itos(uzbl.xwin);
1141 sharg_append(a, command);
1142 for (i = 0; i < npre; i++) /* add n args before the default vars */
1143 sharg_append(a, args[i]);
1144 sharg_append(a, uzbl.state.config_file);
1145 sharg_append(a, pid);
1146 sharg_append(a, xwin);
1147 sharg_append(a, uzbl.comm.fifo_path);
1148 sharg_append(a, uzbl.comm.socket_path);
1149 sharg_append(a, uzbl.state.uri);
1150 sharg_append(a, uzbl.gui.main_title);
1152 for (i = npre; i < g_strv_length((gchar**)args); i++)
1153 sharg_append(a, args[i]);
1157 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1159 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1160 NULL, NULL, output_stdout, NULL, NULL, &err);
1161 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1162 NULL, NULL, NULL, &err);
1164 if (uzbl.state.verbose) {
1165 GString *s = g_string_new("spawned:");
1166 for (i = 0; i < (a->len); i++) {
1167 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1168 g_string_append_printf(s, " %s", qarg);
1171 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1172 printf("%s\n", s->str);
1173 g_string_free(s, TRUE);
1175 printf("Stdout: %s\n", *output_stdout);
1179 g_printerr("error on run_command: %s\n", err->message);
1184 g_array_free (a, TRUE);
1189 split_quoted(const gchar* src, const gboolean unquote) {
1190 /* split on unquoted space, return array of strings;
1191 remove a layer of quotes and backslashes if unquote */
1192 if (!src) return NULL;
1194 gboolean dq = FALSE;
1195 gboolean sq = FALSE;
1196 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1197 GString *s = g_string_new ("");
1201 for (p = src; *p != '\0'; p++) {
1202 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1203 else if (*p == '\\') { g_string_append_c(s, *p++);
1204 g_string_append_c(s, *p); }
1205 else if ((*p == '"') && unquote && !sq) dq = !dq;
1206 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1208 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1209 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1211 else if ((*p == ' ') && !dq && !sq) {
1212 dup = g_strdup(s->str);
1213 g_array_append_val(a, dup);
1214 g_string_truncate(s, 0);
1215 } else g_string_append_c(s, *p);
1217 dup = g_strdup(s->str);
1218 g_array_append_val(a, dup);
1219 ret = (gchar**)a->data;
1220 g_array_free (a, FALSE);
1221 g_string_free (s, TRUE);
1226 spawn(WebKitWebView *web_view, GArray *argv) {
1228 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1229 if (argv_idx(argv, 0))
1230 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1234 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1237 if (argv_idx(argv, 0))
1238 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1239 TRUE, &uzbl.comm.sync_stdout);
1243 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1245 if (!uzbl.behave.shell_cmd) {
1246 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1251 gchar *spacer = g_strdup("");
1252 g_array_insert_val(argv, 1, spacer);
1253 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1255 for (i = 1; i < g_strv_length(cmd); i++)
1256 g_array_prepend_val(argv, cmd[i]);
1258 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1264 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1266 if (!uzbl.behave.shell_cmd) {
1267 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1272 gchar *spacer = g_strdup("");
1273 g_array_insert_val(argv, 1, spacer);
1274 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1276 for (i = 1; i < g_strv_length(cmd); i++)
1277 g_array_prepend_val(argv, cmd[i]);
1279 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1280 TRUE, &uzbl.comm.sync_stdout);
1286 parse_command(const char *cmd, const char *param) {
1289 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1292 gchar **par = split_quoted(param, TRUE);
1293 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1295 if (c[1] == NOSPLIT) { /* don't split */
1296 sharg_append(a, param);
1298 for (i = 0; i < g_strv_length(par); i++)
1299 sharg_append(a, par[i]);
1301 c[0](uzbl.gui.web_view, a);
1303 g_array_free (a, TRUE);
1306 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1313 if(*uzbl.net.proxy_url == ' '
1314 || uzbl.net.proxy_url == NULL) {
1315 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1316 (GType) SOUP_SESSION_PROXY_URI);
1319 suri = soup_uri_new(uzbl.net.proxy_url);
1320 g_object_set(G_OBJECT(uzbl.net.soup_session),
1321 SOUP_SESSION_PROXY_URI,
1323 soup_uri_free(suri);
1330 if(file_exists(uzbl.gui.icon)) {
1331 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1333 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1339 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1340 g_array_append_val (a, uzbl.state.uri);
1341 load_uri(uzbl.gui.web_view, a);
1342 g_array_free (a, TRUE);
1346 cmd_always_insert_mode() {
1347 uzbl.behave.insert_mode =
1348 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1354 g_object_set(G_OBJECT(uzbl.net.soup_session),
1355 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1359 cmd_max_conns_host() {
1360 g_object_set(G_OBJECT(uzbl.net.soup_session),
1361 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1366 soup_session_remove_feature
1367 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1368 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1369 /*g_free(uzbl.net.soup_logger);*/
1371 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1372 soup_session_add_feature(uzbl.net.soup_session,
1373 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1376 static WebKitWebSettings*
1378 return webkit_web_view_get_settings(uzbl.gui.web_view);
1383 WebKitWebSettings *ws = view_settings();
1384 if (uzbl.behave.font_size > 0) {
1385 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1388 if (uzbl.behave.monospace_size > 0) {
1389 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1390 uzbl.behave.monospace_size, NULL);
1392 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1393 uzbl.behave.font_size, NULL);
1399 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1403 cmd_disable_plugins() {
1404 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1405 !uzbl.behave.disable_plugins, NULL);
1409 cmd_disable_scripts() {
1410 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1411 !uzbl.behave.disable_scripts, NULL);
1415 cmd_minimum_font_size() {
1416 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1417 uzbl.behave.minimum_font_size, NULL);
1420 cmd_autoload_img() {
1421 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1422 uzbl.behave.autoload_img, NULL);
1427 cmd_autoshrink_img() {
1428 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1429 uzbl.behave.autoshrink_img, NULL);
1434 cmd_enable_spellcheck() {
1435 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1436 uzbl.behave.enable_spellcheck, NULL);
1440 cmd_enable_private() {
1441 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1442 uzbl.behave.enable_private, NULL);
1447 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1448 uzbl.behave.print_bg, NULL);
1453 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1454 uzbl.behave.style_uri, NULL);
1458 cmd_resizable_txt() {
1459 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1460 uzbl.behave.resizable_txt, NULL);
1464 cmd_default_encoding() {
1465 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1466 uzbl.behave.default_encoding, NULL);
1470 cmd_enforce_96dpi() {
1471 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1472 uzbl.behave.enforce_96dpi, NULL);
1476 cmd_caret_browsing() {
1477 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1478 uzbl.behave.caret_browsing, NULL);
1482 cmd_cookie_handler() {
1483 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1484 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1485 if ((g_strcmp0(split[0], "sh") == 0) ||
1486 (g_strcmp0(split[0], "spawn") == 0)) {
1487 g_free (uzbl.behave.cookie_handler);
1488 uzbl.behave.cookie_handler =
1489 g_strdup_printf("sync_%s %s", split[0], split[1]);
1496 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1501 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1506 if(uzbl.behave.inject_html) {
1507 webkit_web_view_load_html_string (uzbl.gui.web_view,
1508 uzbl.behave.inject_html, NULL);
1517 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1518 uzbl.behave.modmask = 0;
1520 if(uzbl.behave.modkey)
1521 g_free(uzbl.behave.modkey);
1522 uzbl.behave.modkey = buf;
1524 for (i = 0; modkeys[i].key != NULL; i++) {
1525 if (g_strrstr(buf, modkeys[i].key))
1526 uzbl.behave.modmask |= modkeys[i].mask;
1532 if (*uzbl.net.useragent == ' ') {
1533 g_free (uzbl.net.useragent);
1534 uzbl.net.useragent = NULL;
1536 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1538 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1539 g_free(uzbl.net.useragent);
1540 uzbl.net.useragent = ua;
1546 gtk_widget_ref(uzbl.gui.scrolled_win);
1547 gtk_widget_ref(uzbl.gui.mainbar);
1548 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1549 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1551 if(uzbl.behave.status_top) {
1552 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1553 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1556 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.mainbar, FALSE, TRUE, 0);
1559 gtk_widget_unref(uzbl.gui.scrolled_win);
1560 gtk_widget_unref(uzbl.gui.mainbar);
1561 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1566 set_var_value(gchar *name, gchar *val) {
1567 uzbl_cmdprop *c = NULL;
1571 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1572 /* check for the variable type */
1573 if (c->type == TYPE_STR) {
1574 buf = expand_vars(val);
1577 } else if(c->type == TYPE_INT) {
1578 int *ip = (int *)c->ptr;
1579 buf = expand_vars(val);
1580 *ip = (int)strtoul(buf, &endp, 10);
1582 } else if (c->type == TYPE_FLOAT) {
1583 float *fp = (float *)c->ptr;
1584 buf = expand_vars(val);
1585 *fp = strtod(buf, &endp);
1589 /* invoke a command specific function */
1590 if(c->func) c->func();
1597 Behaviour *b = &uzbl.behave;
1599 if(b->html_buffer->str) {
1600 webkit_web_view_load_html_string (uzbl.gui.web_view,
1601 b->html_buffer->str, b->base_url);
1602 g_string_free(b->html_buffer, TRUE);
1603 b->html_buffer = g_string_new("");
1607 enum {M_CMD, M_HTML};
1609 parse_cmd_line(const char *ctl_line) {
1610 Behaviour *b = &uzbl.behave;
1613 if(b->mode == M_HTML) {
1614 len = strlen(b->html_endmarker);
1615 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1616 if(len == strlen(ctl_line)-1 &&
1617 !strncmp(b->html_endmarker, ctl_line, len)) {
1619 set_var_value("mode", "0");
1624 set_timeout(b->html_timeout);
1625 g_string_append(b->html_buffer, ctl_line);
1628 else if((ctl_line[0] == '#') /* Comments */
1629 || (ctl_line[0] == ' ')
1630 || (ctl_line[0] == '\n'))
1631 ; /* ignore these lines */
1632 else { /* parse a command */
1634 gchar **tokens = NULL;
1635 len = strlen(ctl_line);
1637 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1638 ctlstrip = g_strndup(ctl_line, len - 1);
1639 else ctlstrip = g_strdup(ctl_line);
1641 tokens = g_strsplit(ctlstrip, " ", 2);
1642 parse_command(tokens[0], tokens[1]);
1649 build_stream_name(int type, const gchar* dir) {
1651 State *s = &uzbl.state;
1654 xwin_str = itos((int)uzbl.xwin);
1656 str = g_strdup_printf
1657 ("%s/uzbl_fifo_%s", dir,
1658 s->instance_name ? s->instance_name : xwin_str);
1659 } else if (type == SOCKET) {
1660 str = g_strdup_printf
1661 ("%s/uzbl_socket_%s", dir,
1662 s->instance_name ? s->instance_name : xwin_str );
1669 control_fifo(GIOChannel *gio, GIOCondition condition) {
1670 if (uzbl.state.verbose)
1671 printf("triggered\n");
1676 if (condition & G_IO_HUP)
1677 g_error ("Fifo: Read end of pipe died!\n");
1680 g_error ("Fifo: GIOChannel broke\n");
1682 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1683 if (ret == G_IO_STATUS_ERROR) {
1684 g_error ("Fifo: Error reading: %s\n", err->message);
1688 parse_cmd_line(ctl_line);
1695 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1696 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1697 if (unlink(uzbl.comm.fifo_path) == -1)
1698 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1699 g_free(uzbl.comm.fifo_path);
1700 uzbl.comm.fifo_path = NULL;
1703 if (*dir == ' ') { /* space unsets the variable */
1708 GIOChannel *chan = NULL;
1709 GError *error = NULL;
1710 gchar *path = build_stream_name(FIFO, dir);
1712 if (!file_exists(path)) {
1713 if (mkfifo (path, 0666) == 0) {
1714 // 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.
1715 chan = g_io_channel_new_file(path, "r+", &error);
1717 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1718 if (uzbl.state.verbose)
1719 printf ("init_fifo: created successfully as %s\n", path);
1720 uzbl.comm.fifo_path = path;
1722 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1723 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1724 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1725 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1727 /* if we got this far, there was an error; cleanup */
1728 if (error) g_error_free (error);
1735 control_stdin(GIOChannel *gio, GIOCondition condition) {
1737 gchar *ctl_line = NULL;
1740 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1741 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1744 parse_cmd_line(ctl_line);
1752 GIOChannel *chan = NULL;
1753 GError *error = NULL;
1755 chan = g_io_channel_unix_new(fileno(stdin));
1757 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1758 g_error ("Stdin: could not add watch\n");
1760 if (uzbl.state.verbose)
1761 printf ("Stdin: watch added successfully\n");
1764 g_error ("Stdin: Error while opening: %s\n", error->message);
1766 if (error) g_error_free (error);
1770 control_socket(GIOChannel *chan) {
1771 struct sockaddr_un remote;
1772 char buffer[512], *ctl_line;
1774 int sock, clientsock, n, done;
1777 sock = g_io_channel_unix_get_fd(chan);
1779 memset (buffer, 0, sizeof (buffer));
1781 t = sizeof (remote);
1782 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1786 memset (temp, 0, sizeof (temp));
1787 n = recv (clientsock, temp, 128, 0);
1789 buffer[strlen (buffer)] = '\0';
1793 strcat (buffer, temp);
1796 if (strcmp (buffer, "\n") < 0) {
1797 buffer[strlen (buffer) - 1] = '\0';
1799 buffer[strlen (buffer)] = '\0';
1802 ctl_line = g_strdup(buffer);
1803 parse_cmd_line (ctl_line);
1806 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1807 GError *error = NULL;
1810 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1811 if (ret == G_IO_STATUS_ERROR)
1812 g_error ("Error reading: %s\n", error->message);
1814 printf("Got line %s (%u bytes) \n",ctl_line, len);
1816 parse_line(ctl_line);
1824 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1825 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1826 if (unlink(uzbl.comm.socket_path) == -1)
1827 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1828 g_free(uzbl.comm.socket_path);
1829 uzbl.comm.socket_path = NULL;
1837 GIOChannel *chan = NULL;
1839 struct sockaddr_un local;
1840 gchar *path = build_stream_name(SOCKET, dir);
1842 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1844 local.sun_family = AF_UNIX;
1845 strcpy (local.sun_path, path);
1846 unlink (local.sun_path);
1848 len = strlen (local.sun_path) + sizeof (local.sun_family);
1849 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1850 if (uzbl.state.verbose)
1851 printf ("init_socket: opened in %s\n", path);
1854 if( (chan = g_io_channel_unix_new(sock)) ) {
1855 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1856 uzbl.comm.socket_path = path;
1859 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1861 /* if we got this far, there was an error; cleanup */
1868 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1869 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1871 // this function may be called very early when the templates are not set (yet), hence the checks
1873 update_title (void) {
1874 Behaviour *b = &uzbl.behave;
1877 if (b->show_status) {
1878 if (b->title_format_short) {
1879 parsed = expand_template(b->title_format_short, FALSE);
1880 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1883 if (b->status_format) {
1884 parsed = expand_template(b->status_format, TRUE);
1885 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1888 if (b->status_background) {
1890 gdk_color_parse (b->status_background, &color);
1891 //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)
1892 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1895 if (b->title_format_long) {
1896 parsed = expand_template(b->title_format_long, FALSE);
1897 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1904 key_press_cb (GtkWidget* window, GdkEventKey* event)
1906 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1910 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1911 || 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)
1914 /* turn off insert mode (if always_insert_mode is not used) */
1915 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1916 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1921 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1924 if (event->keyval == GDK_Escape) {
1925 g_string_truncate(uzbl.state.keycmd, 0);
1927 dehilight(uzbl.gui.web_view, NULL);
1931 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1932 if (event->keyval == GDK_Insert) {
1934 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1935 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1937 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1940 g_string_append (uzbl.state.keycmd, str);
1947 if (event->keyval == GDK_BackSpace)
1948 keycmd_bs(NULL, NULL);
1950 gboolean key_ret = FALSE;
1951 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1953 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1955 run_keycmd(key_ret);
1957 if (key_ret) return (!uzbl.behave.insert_mode);
1962 run_keycmd(const gboolean key_ret) {
1963 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1965 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1966 g_string_truncate(uzbl.state.keycmd, 0);
1967 parse_command(act->name, act->param);
1971 /* try if it's an incremental keycmd or one that takes args, and run it */
1972 GString* short_keys = g_string_new ("");
1973 GString* short_keys_inc = g_string_new ("");
1975 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1976 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1977 g_string_assign(short_keys_inc, short_keys->str);
1978 g_string_append_c(short_keys, '_');
1979 g_string_append_c(short_keys_inc, '*');
1981 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1982 /* run normal cmds only if return was pressed */
1983 exec_paramcmd(act, i);
1984 g_string_truncate(uzbl.state.keycmd, 0);
1986 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1987 if (key_ret) /* just quit the incremental command on return */
1988 g_string_truncate(uzbl.state.keycmd, 0);
1989 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1993 g_string_truncate(short_keys, short_keys->len - 1);
1995 g_string_free (short_keys, TRUE);
1996 g_string_free (short_keys_inc, TRUE);
2000 exec_paramcmd(const Action *act, const guint i) {
2001 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2002 GString *actionname = g_string_new ("");
2003 GString *actionparam = g_string_new ("");
2004 g_string_erase (parampart, 0, i+1);
2006 g_string_printf (actionname, act->name, parampart->str);
2008 g_string_printf (actionparam, act->param, parampart->str);
2009 parse_command(actionname->str, actionparam->str);
2010 g_string_free(actionname, TRUE);
2011 g_string_free(actionparam, TRUE);
2012 g_string_free(parampart, TRUE);
2020 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2021 //main_window_ref = g_object_ref(scrolled_window);
2022 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
2024 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2025 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2027 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2028 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2029 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2030 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2033 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2035 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2036 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2037 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2039 return scrolled_window;
2046 g->mainbar = gtk_hbox_new (FALSE, 0);
2048 /* keep a reference to the bar so we can re-pack it at runtime*/
2049 //sbar_ref = g_object_ref(g->mainbar);
2051 g->mainbar_label = gtk_label_new ("");
2052 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2053 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2054 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2055 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2056 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2057 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2062 GtkWidget* create_window () {
2063 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2064 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2065 gtk_widget_set_name (window, "Uzbl browser");
2066 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2067 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2073 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2075 If actname is one that calls an external command, this function will inject
2076 newargs in front of the user-provided args in that command line. They will
2077 come become after the body of the script (in sh) or after the name of
2078 the command to execute (in spawn).
2079 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2080 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2082 The return value consist of two strings: the action (sh, ...) and its args.
2084 If act is not one that calls an external command, then the given action merely
2087 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2088 gchar *actdup = g_strdup(actname);
2089 g_array_append_val(rets, actdup);
2091 if ((g_strcmp0(actname, "spawn") == 0) ||
2092 (g_strcmp0(actname, "sh") == 0) ||
2093 (g_strcmp0(actname, "sync_spawn") == 0) ||
2094 (g_strcmp0(actname, "sync_sh") == 0)) {
2096 GString *a = g_string_new("");
2097 gchar **spawnparts = split_quoted(origargs, FALSE);
2098 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2099 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2101 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2102 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2104 g_array_append_val(rets, a->str);
2105 g_string_free(a, FALSE);
2106 g_strfreev(spawnparts);
2108 gchar *origdup = g_strdup(origargs);
2109 g_array_append_val(rets, origdup);
2111 return (gchar**)g_array_free(rets, FALSE);
2115 run_handler (const gchar *act, const gchar *args) {
2116 /* Consider this code a temporary hack to make the handlers usable.
2117 In practice, all this splicing, injection, and reconstruction is
2118 inefficient, annoying and hard to manage. Potential pitfalls arise
2119 when the handler specific args 1) are not quoted (the handler
2120 callbacks should take care of this) 2) are quoted but interfere
2121 with the users' own quotation. A more ideal solution is
2122 to refactor parse_command so that it doesn't just take a string
2123 and execute it; rather than that, we should have a function which
2124 returns the argument vector parsed from the string. This vector
2125 could be modified (e.g. insert additional args into it) before
2126 passing it to the next function that actually executes it. Though
2127 it still isn't perfect for chain actions.. will reconsider & re-
2128 factor when I have the time. -duc */
2130 char **parts = g_strsplit(act, " ", 2);
2132 if (g_strcmp0(parts[0], "chain") == 0) {
2133 GString *newargs = g_string_new("");
2134 gchar **chainparts = split_quoted(parts[1], FALSE);
2136 /* for every argument in the chain, inject the handler args
2137 and make sure the new parts are wrapped in quotes */
2138 gchar **cp = chainparts;
2140 gchar *quotless = NULL;
2141 gchar **spliced_quotless = NULL; // sigh -_-;
2142 gchar **inpart = NULL;
2145 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2147 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2148 } else quotless = g_strdup(*cp);
2150 spliced_quotless = g_strsplit(quotless, " ", 2);
2151 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2152 g_strfreev(spliced_quotless);
2154 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2160 parse_command(parts[0], &(newargs->str[1]));
2161 g_string_free(newargs, TRUE);
2162 g_strfreev(chainparts);
2165 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2166 parse_command(inparts[0], inparts[1]);
2174 add_binding (const gchar *key, const gchar *act) {
2175 char **parts = g_strsplit(act, " ", 2);
2182 if (uzbl.state.verbose)
2183 printf ("Binding %-10s : %s\n", key, act);
2184 action = new_action(parts[0], parts[1]);
2186 if (g_hash_table_remove (uzbl.bindings, key))
2187 g_warning ("Overwriting existing binding for \"%s\"", key);
2188 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2193 get_xdg_var (XDG_Var xdg) {
2194 const gchar* actual_value = getenv (xdg.environmental);
2195 const gchar* home = getenv ("HOME");
2196 gchar* return_value;
2198 if (! actual_value || strcmp (actual_value, "") == 0) {
2199 if (xdg.default_value) {
2200 return_value = str_replace ("~", home, xdg.default_value);
2202 return_value = NULL;
2205 return_value = str_replace("~", home, actual_value);
2208 return return_value;
2212 find_xdg_file (int xdg_type, char* filename) {
2213 /* xdg_type = 0 => config
2214 xdg_type = 1 => data
2215 xdg_type = 2 => cache*/
2217 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2218 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2221 gchar* temporary_string;
2225 if (! file_exists (temporary_file) && xdg_type != 2) {
2226 buf = get_xdg_var (XDG[3 + xdg_type]);
2227 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2230 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2231 g_free (temporary_file);
2232 temporary_file = g_strconcat (temporary_string, filename, NULL);
2236 //g_free (temporary_string); - segfaults.
2238 if (file_exists (temporary_file)) {
2239 return temporary_file;
2246 State *s = &uzbl.state;
2247 Network *n = &uzbl.net;
2249 for (i = 0; default_config[i].command != NULL; i++) {
2250 parse_cmd_line(default_config[i].command);
2253 if (!s->config_file) {
2254 s->config_file = find_xdg_file (0, "/uzbl/config");
2257 if (s->config_file) {
2258 GArray* lines = read_file_by_line (s->config_file);
2262 while ((line = g_array_index(lines, gchar*, i))) {
2263 parse_cmd_line (line);
2267 g_array_free (lines, TRUE);
2269 if (uzbl.state.verbose)
2270 printf ("No configuration file loaded.\n");
2273 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2276 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2279 if (!uzbl.behave.cookie_handler)
2282 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2283 GString *s = g_string_new ("");
2284 SoupURI * soup_uri = soup_message_get_uri(msg);
2285 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2286 run_handler(uzbl.behave.cookie_handler, s->str);
2288 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2289 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2290 if ( p != NULL ) *p = '\0';
2291 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2293 if (uzbl.comm.sync_stdout)
2294 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2296 g_string_free(s, TRUE);
2300 save_cookies (SoupMessage *msg, gpointer user_data){
2304 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2305 cookie = soup_cookie_to_set_cookie_header(ck->data);
2306 SoupURI * soup_uri = soup_message_get_uri(msg);
2307 GString *s = g_string_new ("");
2308 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2309 run_handler(uzbl.behave.cookie_handler, s->str);
2311 g_string_free(s, TRUE);
2316 /* --- WEBINSPECTOR --- */
2318 hide_window_cb(GtkWidget *widget, gpointer data) {
2321 gtk_widget_hide(widget);
2324 static WebKitWebView*
2325 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2328 (void) web_inspector;
2329 GtkWidget* scrolled_window;
2330 GtkWidget* new_web_view;
2333 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2334 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2335 G_CALLBACK(hide_window_cb), NULL);
2337 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2338 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2339 gtk_widget_show(g->inspector_window);
2341 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2342 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2343 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2344 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2345 gtk_widget_show(scrolled_window);
2347 new_web_view = webkit_web_view_new();
2348 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2350 return WEBKIT_WEB_VIEW(new_web_view);
2354 inspector_show_window_cb (WebKitWebInspector* inspector){
2356 gtk_widget_show(uzbl.gui.inspector_window);
2360 /* TODO: Add variables and code to make use of these functions */
2362 inspector_close_window_cb (WebKitWebInspector* inspector){
2368 inspector_attach_window_cb (WebKitWebInspector* inspector){
2374 inspector_detach_window_cb (WebKitWebInspector* inspector){
2380 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2386 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2392 set_up_inspector() {
2394 WebKitWebSettings *settings = view_settings();
2395 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2397 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2398 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2399 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2400 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2401 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2402 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2403 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2405 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2409 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2411 uzbl_cmdprop *c = v;
2416 if(c->type == TYPE_STR)
2417 printf("set %s = %s\n", (char *)k, *c->ptr ? (char *)*c->ptr : " ");
2418 else if(c->type == TYPE_INT)
2419 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2420 else if(c->type == TYPE_FLOAT)
2421 printf("set %s = %f\n", (char *)k, *(float *)c->ptr);
2425 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2429 printf("bind %s = %s %s\n", (char *)k ,
2430 (char *)a->name, a->param?(char *)a->param:"");
2435 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2436 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2441 main (int argc, char* argv[]) {
2442 gtk_init (&argc, &argv);
2443 if (!g_thread_supported ())
2444 g_thread_init (NULL);
2445 uzbl.state.executable_path = g_strdup(argv[0]);
2446 uzbl.state.selected_url = NULL;
2447 uzbl.state.searchtx = NULL;
2449 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2450 g_option_context_add_main_entries (context, entries, NULL);
2451 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2452 g_option_context_parse (context, &argc, &argv, NULL);
2453 g_option_context_free(context);
2455 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2456 gboolean verbose_override = uzbl.state.verbose;
2458 /* initialize hash table */
2459 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2461 uzbl.net.soup_session = webkit_get_default_session();
2462 uzbl.state.keycmd = g_string_new("");
2464 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2465 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2466 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2467 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2468 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2469 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2472 if(uname(&uzbl.state.unameinfo) == -1)
2473 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2475 uzbl.gui.sbar.progress_s = g_strdup("=");
2476 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2477 uzbl.gui.sbar.progress_w = 10;
2479 /* HTML mode defaults*/
2480 uzbl.behave.html_buffer = g_string_new("");
2481 uzbl.behave.html_endmarker = g_strdup(".");
2482 uzbl.behave.html_timeout = 60;
2483 uzbl.behave.base_url = g_strdup("http://invalid");
2485 /* default mode indicators */
2486 uzbl.behave.insert_indicator = g_strdup("I");
2487 uzbl.behave.cmd_indicator = g_strdup("C");
2491 make_var_to_name_hash();
2493 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2495 uzbl.gui.scrolled_win = create_browser();
2498 /* initial packing */
2499 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2500 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2502 uzbl.gui.main_window = create_window ();
2503 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2506 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2507 gtk_widget_show_all (uzbl.gui.main_window);
2508 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2510 if (uzbl.state.verbose) {
2511 printf("Uzbl start location: %s\n", argv[0]);
2512 printf("window_id %i\n",(int) uzbl.xwin);
2513 printf("pid %i\n", getpid ());
2514 printf("name: %s\n", uzbl.state.instance_name);
2517 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2518 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2519 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2520 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2521 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2525 if (!uzbl.behave.show_status)
2526 gtk_widget_hide(uzbl.gui.mainbar);
2535 if (verbose_override > uzbl.state.verbose)
2536 uzbl.state.verbose = verbose_override;
2539 set_var_value("uri", uri_override);
2540 g_free(uri_override);
2541 } else if (uzbl.state.uri)
2542 cmd_load_uri(uzbl.gui.web_view, NULL);
2547 return EXIT_SUCCESS;
2550 /* vi: set et ts=4: */