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
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
45 #include <webkit/webkit.h>
46 #include <libsoup/soup.h>
59 typedef void (*Command)(WebKitWebView*, GArray *argv);
63 /* commandline arguments (set initial values for the state variables) */
65 GOptionEntry entries[] =
67 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
68 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
69 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
70 "Whether to print all messages or just errors.", NULL },
71 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
72 "Name of the current instance (defaults to Xorg window id)", "NAME" },
73 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
74 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
75 { NULL, 0, 0, 0, NULL, NULL, NULL }
78 /* associate command names to their properties */
79 typedef const struct {
86 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
88 /* an abbreviation to help keep the table's width humane */
89 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
94 } var_name_to_ptr[] = {
95 /* variable name pointer to variable in code type dump callback function */
96 /* --------------------------------------------------------------------------------------- */
97 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
98 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
99 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
100 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
101 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
102 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
103 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
104 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
105 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
106 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
107 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
108 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
109 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
110 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
111 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
112 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
113 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
114 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
115 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
116 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
117 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
118 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
119 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
120 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
121 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
122 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
123 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
124 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
125 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
126 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
127 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
128 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
129 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
130 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
131 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
132 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
133 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
134 /* exported WebKitWebSettings properties */
135 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
136 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
137 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
138 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
139 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
140 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
141 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
142 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
143 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
144 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
145 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
146 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
147 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
148 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
149 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
150 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
152 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
153 }, *n2v_p = var_name_to_ptr;
159 { "SHIFT", GDK_SHIFT_MASK }, // shift
160 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
161 { "CONTROL", GDK_CONTROL_MASK }, // control
162 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
163 { "MOD2", GDK_MOD2_MASK }, // 5th mod
164 { "MOD3", GDK_MOD3_MASK }, // 6th mod
165 { "MOD4", GDK_MOD4_MASK }, // 7th mod
166 { "MOD5", GDK_MOD5_MASK }, // 8th mod
167 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
168 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
169 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
170 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
171 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
172 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
173 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
174 { "META", GDK_META_MASK }, // meta (since 2.10)
179 /* construct a hash from the var_name_to_ptr array for quick access */
181 make_var_to_name_hash() {
182 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
184 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
189 /* --- UTILITY FUNCTIONS --- */
191 expand_vars(char *s) {
194 char ret[256], *vend;
195 GString *buf = g_string_new("");
200 g_string_append_c(buf, *++s);
208 if( (vend = strchr(s, upto)) ||
209 (vend = strchr(s, '\0')) ) {
210 strncpy(ret, s, vend-s);
212 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
213 if(c->type == TYPE_STR)
214 g_string_append(buf, (gchar *)*c->ptr);
215 else if(c->type == TYPE_INT) {
216 char *b = itos((int)*c->ptr);
217 g_string_append(buf, b);
221 if(upto == ' ') s = vend;
227 g_string_append_c(buf, *s);
232 return g_string_free(buf, FALSE);
239 snprintf(tmp, sizeof(tmp), "%i", val);
240 return g_strdup(tmp);
244 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
247 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
250 str_replace (const char* search, const char* replace, const char* string) {
254 buf = g_strsplit (string, search, -1);
255 ret = g_strjoinv (replace, buf);
256 g_strfreev(buf); // somebody said this segfaults
262 read_file_by_line (gchar *path) {
263 GIOChannel *chan = NULL;
264 gchar *readbuf = NULL;
266 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
269 chan = g_io_channel_new_file(path, "r", NULL);
272 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
273 const gchar* val = g_strdup (readbuf);
274 g_array_append_val (lines, val);
279 g_io_channel_unref (chan);
281 fprintf(stderr, "File '%s' not be read.\n", path);
288 gchar* parseenv (char* string) {
289 extern char** environ;
290 gchar* tmpstr = NULL;
294 while (environ[i] != NULL) {
295 gchar** env = g_strsplit (environ[i], "=", 2);
296 gchar* envname = g_strconcat ("$", env[0], NULL);
298 if (g_strrstr (string, envname) != NULL) {
299 tmpstr = g_strdup(string);
301 string = str_replace(envname, env[1], tmpstr);
306 g_strfreev (env); // somebody said this breaks uzbl
314 setup_signal(int signr, sigfunc *shandler) {
315 struct sigaction nh, oh;
317 nh.sa_handler = shandler;
318 sigemptyset(&nh.sa_mask);
321 if(sigaction(signr, &nh, &oh) < 0)
329 if (uzbl.behave.fifo_dir)
330 unlink (uzbl.comm.fifo_path);
331 if (uzbl.behave.socket_dir)
332 unlink (uzbl.comm.socket_path);
334 g_free(uzbl.state.executable_path);
335 g_string_free(uzbl.state.keycmd, TRUE);
336 g_hash_table_destroy(uzbl.bindings);
337 g_hash_table_destroy(uzbl.behave.commands);
340 /* used for html_mode_timeout
341 * be sure to extend this function to use
342 * more timers if needed in other places
345 set_timeout(int seconds) {
347 memset(&t, 0, sizeof t);
349 t.it_value.tv_sec = seconds;
350 t.it_value.tv_usec = 0;
351 setitimer(ITIMER_REAL, &t, NULL);
354 /* --- SIGNAL HANDLER --- */
357 catch_sigterm(int s) {
363 catch_sigint(int s) {
373 set_var_value("mode", "0");
378 /* --- CALLBACKS --- */
381 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
384 (void) navigation_action;
385 (void) policy_decision;
387 const gchar* uri = webkit_network_request_get_uri (request);
388 if (uzbl.state.verbose)
389 printf("New window requested -> %s \n", uri);
390 new_window_load_uri(uri);
395 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
400 /* If we can display it, let's display it... */
401 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
402 webkit_web_policy_decision_use (policy_decision);
406 /* ...everything we can't displayed is downloaded */
407 webkit_web_policy_decision_download (policy_decision);
412 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
416 if (uzbl.state.selected_url != NULL) {
417 if (uzbl.state.verbose)
418 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
419 new_window_load_uri(uzbl.state.selected_url);
421 if (uzbl.state.verbose)
422 printf("New web view -> %s\n","Nothing to open, exiting");
428 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
431 if (uzbl.behave.download_handler) {
432 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
433 if (uzbl.state.verbose)
434 printf("Download -> %s\n",uri);
435 /* if urls not escaped, we may have to escape and quote uri before this call */
436 run_handler(uzbl.behave.download_handler, uri);
441 /* scroll a bar in a given direction */
443 scroll (GtkAdjustment* bar, GArray *argv) {
447 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
448 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
449 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
453 scroll_begin(WebKitWebView* page, GArray *argv) {
454 (void) page; (void) argv;
455 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
459 scroll_end(WebKitWebView* page, GArray *argv) {
460 (void) page; (void) argv;
461 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
462 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
466 scroll_vert(WebKitWebView* page, GArray *argv) {
468 scroll(uzbl.gui.bar_v, argv);
472 scroll_horz(WebKitWebView* page, GArray *argv) {
474 scroll(uzbl.gui.bar_h, argv);
479 if (!uzbl.behave.show_status) {
480 gtk_widget_hide(uzbl.gui.mainbar);
482 gtk_widget_show(uzbl.gui.mainbar);
488 toggle_status_cb (WebKitWebView* page, GArray *argv) {
492 if (uzbl.behave.show_status) {
493 gtk_widget_hide(uzbl.gui.mainbar);
495 gtk_widget_show(uzbl.gui.mainbar);
497 uzbl.behave.show_status = !uzbl.behave.show_status;
502 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
506 //Set selected_url state variable
507 g_free(uzbl.state.selected_url);
508 uzbl.state.selected_url = NULL;
510 uzbl.state.selected_url = g_strdup(link);
516 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
520 if (uzbl.gui.main_title)
521 g_free (uzbl.gui.main_title);
522 uzbl.gui.main_title = g_strdup (title);
527 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
530 uzbl.gui.sbar.load_progress = progress;
535 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
539 if (uzbl.behave.load_finish_handler)
540 run_handler(uzbl.behave.load_finish_handler, "");
544 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
548 uzbl.gui.sbar.load_progress = 0;
549 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
550 if (uzbl.behave.load_start_handler)
551 run_handler(uzbl.behave.load_start_handler, "");
555 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
558 g_free (uzbl.state.uri);
559 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
560 uzbl.state.uri = g_string_free (newuri, FALSE);
561 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
562 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
565 if (uzbl.behave.load_commit_handler)
566 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
570 destroy_cb (GtkWidget* widget, gpointer data) {
578 if (uzbl.behave.history_handler) {
580 struct tm * timeinfo;
583 timeinfo = localtime ( &rawtime );
584 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
585 run_handler(uzbl.behave.history_handler, date);
590 /* VIEW funcs (little webkit wrappers) */
591 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
593 VIEWFUNC(reload_bypass_cache)
594 VIEWFUNC(stop_loading)
601 /* -- command to callback/function map for things we cannot attach to any signals */
602 static struct {char *name; Command command[2];} cmdlist[] =
603 { /* key function no_split */
604 { "back", {view_go_back, 0} },
605 { "forward", {view_go_forward, 0} },
606 { "scroll_vert", {scroll_vert, 0} },
607 { "scroll_horz", {scroll_horz, 0} },
608 { "scroll_begin", {scroll_begin, 0} },
609 { "scroll_end", {scroll_end, 0} },
610 { "reload", {view_reload, 0}, },
611 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
612 { "stop", {view_stop_loading, 0}, },
613 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
614 { "zoom_out", {view_zoom_out, 0}, },
615 { "uri", {load_uri, NOSPLIT} },
616 { "js", {run_js, NOSPLIT} },
617 { "script", {run_external_js, 0} },
618 { "toggle_status", {toggle_status_cb, 0} },
619 { "spawn", {spawn, 0} },
620 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
621 { "sh", {spawn_sh, 0} },
622 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
623 { "exit", {close_uzbl, 0} },
624 { "search", {search_forward_text, NOSPLIT} },
625 { "search_reverse", {search_reverse_text, NOSPLIT} },
626 { "dehilight", {dehilight, 0} },
627 { "toggle_insert_mode", {toggle_insert_mode, 0} },
628 { "set", {set_var, NOSPLIT} },
629 //{ "get", {get_var, NOSPLIT} },
630 { "bind", {act_bind, NOSPLIT} },
631 { "dump_config", {act_dump_config, 0} },
632 { "keycmd", {keycmd, NOSPLIT} },
633 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
634 { "keycmd_bs", {keycmd_bs, 0} },
635 { "chain", {chain, 0} },
636 { "print", {print, NOSPLIT} }
643 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
645 for (i = 0; i < LENGTH(cmdlist); i++)
646 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
649 /* -- CORE FUNCTIONS -- */
652 free_action(gpointer act) {
653 Action *action = (Action*)act;
654 g_free(action->name);
656 g_free(action->param);
661 new_action(const gchar *name, const gchar *param) {
662 Action *action = g_new(Action, 1);
664 action->name = g_strdup(name);
666 action->param = g_strdup(param);
668 action->param = NULL;
674 file_exists (const char * filename) {
675 return (access(filename, F_OK) == 0);
679 set_var(WebKitWebView *page, GArray *argv) {
681 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
682 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
683 set_var_value(g_strstrip(split[0]), value);
689 print(WebKitWebView *page, GArray *argv) {
693 buf = expand_vars(argv_idx(argv, 0));
699 act_bind(WebKitWebView *page, GArray *argv) {
701 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
702 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
703 add_binding(g_strstrip(split[0]), value);
715 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
718 if (argv_idx(argv, 0)) {
719 if (strcmp (argv_idx(argv, 0), "0") == 0) {
720 uzbl.behave.insert_mode = FALSE;
722 uzbl.behave.insert_mode = TRUE;
725 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
732 load_uri (WebKitWebView *web_view, GArray *argv) {
733 if (argv_idx(argv, 0)) {
734 GString* newuri = g_string_new (argv_idx(argv, 0));
735 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
736 run_js(web_view, argv);
739 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
740 g_string_prepend (newuri, "http://");
741 /* if we do handle cookies, ask our handler for them */
742 webkit_web_view_load_uri (web_view, newuri->str);
743 g_string_free (newuri, TRUE);
748 run_js (WebKitWebView * web_view, GArray *argv) {
749 if (argv_idx(argv, 0))
750 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
754 run_external_js (WebKitWebView * web_view, GArray *argv) {
755 if (argv_idx(argv, 0)) {
756 GArray* lines = read_file_by_line (argv_idx (argv, 0));
761 while ((line = g_array_index(lines, gchar*, i))) {
763 js = g_strdup (line);
765 gchar* newjs = g_strconcat (js, line, NULL);
772 if (uzbl.state.verbose)
773 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
775 if (argv_idx (argv, 1)) {
776 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
780 webkit_web_view_execute_script (web_view, js);
782 g_array_free (lines, TRUE);
787 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
788 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
789 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
790 webkit_web_view_unmark_text_matches (page);
791 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
792 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
796 if (uzbl.state.searchtx) {
797 if (uzbl.state.verbose)
798 printf ("Searching: %s\n", uzbl.state.searchtx);
799 webkit_web_view_set_highlight_text_matches (page, TRUE);
800 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
805 search_forward_text (WebKitWebView *page, GArray *argv) {
806 search_text(page, argv, TRUE);
810 search_reverse_text (WebKitWebView *page, GArray *argv) {
811 search_text(page, argv, FALSE);
815 dehilight (WebKitWebView *page, GArray *argv) {
817 webkit_web_view_set_highlight_text_matches (page, FALSE);
822 new_window_load_uri (const gchar * uri) {
823 GString* to_execute = g_string_new ("");
824 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
826 for (i = 0; entries[i].long_name != NULL; i++) {
827 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
828 gchar** str = (gchar**)entries[i].arg_data;
830 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
834 if (uzbl.state.verbose)
835 printf("\n%s\n", to_execute->str);
836 g_spawn_command_line_async (to_execute->str, NULL);
837 g_string_free (to_execute, TRUE);
841 chain (WebKitWebView *page, GArray *argv) {
844 gchar **parts = NULL;
846 while ((a = argv_idx(argv, i++))) {
847 parts = g_strsplit (a, " ", 2);
848 parse_command(parts[0], parts[1]);
854 keycmd (WebKitWebView *page, GArray *argv) {
857 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
863 keycmd_nl (WebKitWebView *page, GArray *argv) {
866 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
872 keycmd_bs (WebKitWebView *page, GArray *argv) {
875 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
880 close_uzbl (WebKitWebView *page, GArray *argv) {
886 /* --Statusbar functions-- */
888 build_progressbar_ascii(int percent) {
889 int width=uzbl.gui.sbar.progress_w;
892 GString *bar = g_string_new("");
894 l = (double)percent*((double)width/100.);
895 l = (int)(l+.5)>=(int)l ? l+.5 : l;
897 for(i=0; i<(int)l; i++)
898 g_string_append(bar, uzbl.gui.sbar.progress_s);
901 g_string_append(bar, uzbl.gui.sbar.progress_u);
903 return g_string_free(bar, FALSE);
908 const GScannerConfig scan_config = {
911 ) /* cset_skip_characters */,
916 ) /* cset_identifier_first */,
923 ) /* cset_identifier_nth */,
924 ( "" ) /* cpair_comment_single */,
926 TRUE /* case_sensitive */,
928 FALSE /* skip_comment_multi */,
929 FALSE /* skip_comment_single */,
930 FALSE /* scan_comment_multi */,
931 TRUE /* scan_identifier */,
932 TRUE /* scan_identifier_1char */,
933 FALSE /* scan_identifier_NULL */,
934 TRUE /* scan_symbols */,
935 FALSE /* scan_binary */,
936 FALSE /* scan_octal */,
937 FALSE /* scan_float */,
938 FALSE /* scan_hex */,
939 FALSE /* scan_hex_dollar */,
940 FALSE /* scan_string_sq */,
941 FALSE /* scan_string_dq */,
942 TRUE /* numbers_2_int */,
943 FALSE /* int_2_float */,
944 FALSE /* identifier_2_string */,
945 FALSE /* char_2_token */,
946 FALSE /* symbol_2_token */,
947 TRUE /* scope_0_fallback */,
952 uzbl.scan = g_scanner_new(&scan_config);
953 while(symp->symbol_name) {
954 g_scanner_scope_add_symbol(uzbl.scan, 0,
956 GINT_TO_POINTER(symp->symbol_token));
962 expand_template(const char *template, gboolean escape_markup) {
963 if(!template) return NULL;
965 GTokenType token = G_TOKEN_NONE;
966 GString *ret = g_string_new("");
970 g_scanner_input_text(uzbl.scan, template, strlen(template));
971 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
972 token = g_scanner_get_next_token(uzbl.scan);
974 if(token == G_TOKEN_SYMBOL) {
975 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
979 buf = uzbl.state.uri?
980 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
981 g_string_append(ret, buf);
985 g_string_append(ret, uzbl.state.uri?
986 uzbl.state.uri:g_strdup(""));
989 buf = itos(uzbl.gui.sbar.load_progress);
990 g_string_append(ret, buf);
993 case SYM_LOADPRGSBAR:
994 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
995 g_string_append(ret, buf);
1000 buf = uzbl.gui.main_title?
1001 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1002 g_string_append(ret, buf);
1006 g_string_append(ret, uzbl.gui.main_title?
1007 uzbl.gui.main_title:g_strdup(""));
1009 case SYM_SELECTED_URI:
1011 buf = uzbl.state.selected_url?
1012 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1013 g_string_append(ret, buf);
1017 g_string_append(ret, uzbl.state.selected_url?
1018 uzbl.state.selected_url:g_strdup(""));
1021 buf = itos(uzbl.xwin);
1022 g_string_append(ret,
1023 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1028 buf = uzbl.state.keycmd->str?
1029 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1030 g_string_append(ret, buf);
1034 g_string_append(ret, uzbl.state.keycmd->str?
1035 uzbl.state.keycmd->str:g_strdup(""));
1038 g_string_append(ret,
1039 uzbl.behave.insert_mode?
1040 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1043 g_string_append(ret,
1044 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1046 /* useragent syms */
1048 buf = itos(WEBKIT_MAJOR_VERSION);
1049 g_string_append(ret, buf);
1053 buf = itos(WEBKIT_MINOR_VERSION);
1054 g_string_append(ret, buf);
1058 buf = itos(WEBKIT_MICRO_VERSION);
1059 g_string_append(ret, buf);
1063 g_string_append(ret, uzbl.state.unameinfo.sysname);
1066 g_string_append(ret, uzbl.state.unameinfo.nodename);
1069 g_string_append(ret, uzbl.state.unameinfo.release);
1072 g_string_append(ret, uzbl.state.unameinfo.version);
1075 g_string_append(ret, uzbl.state.unameinfo.machine);
1078 g_string_append(ret, ARCH);
1081 case SYM_DOMAINNAME:
1082 g_string_append(ret, uzbl.state.unameinfo.domainname);
1086 g_string_append(ret, COMMIT);
1092 else if(token == G_TOKEN_INT) {
1093 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1094 g_string_append(ret, buf);
1097 else if(token == G_TOKEN_IDENTIFIER) {
1098 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1100 else if(token == G_TOKEN_CHAR) {
1101 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1105 return g_string_free(ret, FALSE);
1107 /* --End Statusbar functions-- */
1110 sharg_append(GArray *a, const gchar *str) {
1111 const gchar *s = (str ? str : "");
1112 g_array_append_val(a, s);
1115 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1117 run_command (const gchar *command, const guint npre, const gchar **args,
1118 const gboolean sync, char **stdout) {
1119 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1122 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1123 gchar *pid = itos(getpid());
1124 gchar *xwin = itos(uzbl.xwin);
1126 sharg_append(a, command);
1127 for (i = 0; i < npre; i++) /* add n args before the default vars */
1128 sharg_append(a, args[i]);
1129 sharg_append(a, uzbl.state.config_file);
1130 sharg_append(a, pid);
1131 sharg_append(a, xwin);
1132 sharg_append(a, uzbl.comm.fifo_path);
1133 sharg_append(a, uzbl.comm.socket_path);
1134 sharg_append(a, uzbl.state.uri);
1135 sharg_append(a, uzbl.gui.main_title);
1137 for (i = npre; i < g_strv_length((gchar**)args); i++)
1138 sharg_append(a, args[i]);
1142 if (*stdout) *stdout = strfree(*stdout);
1144 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1145 NULL, NULL, stdout, NULL, NULL, &err);
1146 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1147 NULL, NULL, NULL, &err);
1149 if (uzbl.state.verbose) {
1150 GString *s = g_string_new("spawned:");
1151 for (i = 0; i < (a->len); i++) {
1152 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1153 g_string_append_printf(s, " %s", qarg);
1156 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1157 printf("%s\n", s->str);
1158 g_string_free(s, TRUE);
1160 printf("Stdout: %s\n", *stdout);
1164 g_printerr("error on run_command: %s\n", err->message);
1169 g_array_free (a, TRUE);
1174 split_quoted(const gchar* src, const gboolean unquote) {
1175 /* split on unquoted space, return array of strings;
1176 remove a layer of quotes and backslashes if unquote */
1177 if (!src) return NULL;
1179 gboolean dq = FALSE;
1180 gboolean sq = FALSE;
1181 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1182 GString *s = g_string_new ("");
1186 for (p = src; *p != '\0'; p++) {
1187 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1188 else if (*p == '\\') { g_string_append_c(s, *p++);
1189 g_string_append_c(s, *p); }
1190 else if ((*p == '"') && unquote && !sq) dq = !dq;
1191 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1193 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1194 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1196 else if ((*p == ' ') && !dq && !sq) {
1197 dup = g_strdup(s->str);
1198 g_array_append_val(a, dup);
1199 g_string_truncate(s, 0);
1200 } else g_string_append_c(s, *p);
1202 dup = g_strdup(s->str);
1203 g_array_append_val(a, dup);
1204 ret = (gchar**)a->data;
1205 g_array_free (a, FALSE);
1206 g_string_free (s, TRUE);
1211 spawn(WebKitWebView *web_view, GArray *argv) {
1213 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1214 if (argv_idx(argv, 0))
1215 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1219 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1222 if (argv_idx(argv, 0))
1223 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1224 TRUE, &uzbl.comm.sync_stdout);
1228 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1230 if (!uzbl.behave.shell_cmd) {
1231 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1236 gchar *spacer = g_strdup("");
1237 g_array_insert_val(argv, 1, spacer);
1238 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1240 for (i = 1; i < g_strv_length(cmd); i++)
1241 g_array_prepend_val(argv, cmd[i]);
1243 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1249 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1251 if (!uzbl.behave.shell_cmd) {
1252 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1257 gchar *spacer = g_strdup("");
1258 g_array_insert_val(argv, 1, spacer);
1259 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1261 for (i = 1; i < g_strv_length(cmd); i++)
1262 g_array_prepend_val(argv, cmd[i]);
1264 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1265 TRUE, &uzbl.comm.sync_stdout);
1271 parse_command(const char *cmd, const char *param) {
1274 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1277 gchar **par = split_quoted(param, TRUE);
1278 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1280 if (c[1] == NOSPLIT) { /* don't split */
1281 sharg_append(a, param);
1283 for (i = 0; i < g_strv_length(par); i++)
1284 sharg_append(a, par[i]);
1286 c[0](uzbl.gui.web_view, a);
1288 g_array_free (a, TRUE);
1291 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1298 if(*uzbl.net.proxy_url == ' '
1299 || uzbl.net.proxy_url == NULL) {
1300 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1301 (GType) SOUP_SESSION_PROXY_URI);
1304 suri = soup_uri_new(uzbl.net.proxy_url);
1305 g_object_set(G_OBJECT(uzbl.net.soup_session),
1306 SOUP_SESSION_PROXY_URI,
1308 soup_uri_free(suri);
1315 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1316 g_array_append_val (a, uzbl.state.uri);
1317 load_uri(uzbl.gui.web_view, a);
1318 g_array_free (a, TRUE);
1322 cmd_always_insert_mode() {
1323 uzbl.behave.insert_mode =
1324 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1330 g_object_set(G_OBJECT(uzbl.net.soup_session),
1331 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1335 cmd_max_conns_host() {
1336 g_object_set(G_OBJECT(uzbl.net.soup_session),
1337 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1342 soup_session_remove_feature
1343 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1344 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1345 /*g_free(uzbl.net.soup_logger);*/
1347 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1348 soup_session_add_feature(uzbl.net.soup_session,
1349 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1352 static WebKitWebSettings*
1354 return webkit_web_view_get_settings(uzbl.gui.web_view);
1359 WebKitWebSettings *ws = view_settings();
1360 if (uzbl.behave.font_size > 0) {
1361 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1364 if (uzbl.behave.monospace_size > 0) {
1365 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1366 uzbl.behave.monospace_size, NULL);
1368 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1369 uzbl.behave.font_size, NULL);
1375 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1379 cmd_disable_plugins() {
1380 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1381 !uzbl.behave.disable_plugins, NULL);
1385 cmd_disable_scripts() {
1386 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1387 !uzbl.behave.disable_scripts, NULL);
1391 cmd_minimum_font_size() {
1392 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1393 uzbl.behave.minimum_font_size, NULL);
1396 cmd_autoload_img() {
1397 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1398 uzbl.behave.autoload_img, NULL);
1403 cmd_autoshrink_img() {
1404 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1405 uzbl.behave.autoshrink_img, NULL);
1410 cmd_enable_spellcheck() {
1411 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1412 uzbl.behave.enable_spellcheck, NULL);
1416 cmd_enable_private() {
1417 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1418 uzbl.behave.enable_private, NULL);
1423 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1424 uzbl.behave.print_bg, NULL);
1429 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1430 uzbl.behave.style_uri, NULL);
1434 cmd_resizable_txt() {
1435 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1436 uzbl.behave.resizable_txt, NULL);
1440 cmd_default_encoding() {
1441 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1442 uzbl.behave.default_encoding, NULL);
1446 cmd_enforce_96dpi() {
1447 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1448 uzbl.behave.enforce_96dpi, NULL);
1452 cmd_caret_browsing() {
1453 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1454 uzbl.behave.caret_browsing, NULL);
1458 cmd_cookie_handler() {
1459 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1460 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1461 if ((g_strcmp0(split[0], "sh") == 0) ||
1462 (g_strcmp0(split[0], "spawn") == 0)) {
1463 g_free (uzbl.behave.cookie_handler);
1464 uzbl.behave.cookie_handler =
1465 g_strdup_printf("sync_%s %s", split[0], split[1]);
1472 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1477 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1482 if(uzbl.behave.inject_html) {
1483 webkit_web_view_load_html_string (uzbl.gui.web_view,
1484 uzbl.behave.inject_html, NULL);
1493 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1494 uzbl.behave.modmask = 0;
1496 if(uzbl.behave.modkey)
1497 g_free(uzbl.behave.modkey);
1498 uzbl.behave.modkey = buf;
1500 for (i = 0; modkeys[i].key != NULL; i++) {
1501 if (g_strrstr(buf, modkeys[i].key))
1502 uzbl.behave.modmask |= modkeys[i].mask;
1508 if (*uzbl.net.useragent == ' ') {
1509 g_free (uzbl.net.useragent);
1510 uzbl.net.useragent = NULL;
1512 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1514 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1515 g_free(uzbl.net.useragent);
1516 uzbl.net.useragent = ua;
1522 gtk_widget_ref(uzbl.gui.scrolled_win);
1523 gtk_widget_ref(uzbl.gui.mainbar);
1524 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1525 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1527 if(uzbl.behave.status_top) {
1528 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1529 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1532 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1533 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1535 gtk_widget_unref(uzbl.gui.scrolled_win);
1536 gtk_widget_unref(uzbl.gui.mainbar);
1537 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1542 set_var_value(gchar *name, gchar *val) {
1543 uzbl_cmdprop *c = NULL;
1547 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1548 /* check for the variable type */
1549 if (c->type == TYPE_STR) {
1550 buf = expand_vars(val);
1553 } else if(c->type == TYPE_INT) {
1554 int *ip = (int *)c->ptr;
1555 buf = expand_vars(val);
1556 *ip = (int)strtoul(buf, &endp, 10);
1558 } else if (c->type == TYPE_FLOAT) {
1559 float *fp = (float *)c->ptr;
1560 buf = expand_vars(val);
1565 /* invoke a command specific function */
1566 if(c->func) c->func();
1573 Behaviour *b = &uzbl.behave;
1575 if(b->html_buffer->str) {
1576 webkit_web_view_load_html_string (uzbl.gui.web_view,
1577 b->html_buffer->str, b->base_url);
1578 g_string_free(b->html_buffer, TRUE);
1579 b->html_buffer = g_string_new("");
1583 enum {M_CMD, M_HTML};
1585 parse_cmd_line(const char *ctl_line) {
1586 Behaviour *b = &uzbl.behave;
1589 if(b->mode == M_HTML) {
1590 len = strlen(b->html_endmarker);
1591 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1592 if(len == strlen(ctl_line)-1 &&
1593 !strncmp(b->html_endmarker, ctl_line, len)) {
1595 set_var_value("mode", "0");
1600 set_timeout(b->html_timeout);
1601 g_string_append(b->html_buffer, ctl_line);
1604 else if((ctl_line[0] == '#') /* Comments */
1605 || (ctl_line[0] == ' ')
1606 || (ctl_line[0] == '\n'))
1607 ; /* ignore these lines */
1608 else { /* parse a command */
1610 gchar **tokens = NULL;
1611 len = strlen(ctl_line);
1613 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1614 ctlstrip = g_strndup(ctl_line, len - 1);
1615 else ctlstrip = g_strdup(ctl_line);
1617 tokens = g_strsplit(ctlstrip, " ", 2);
1618 parse_command(tokens[0], tokens[1]);
1625 build_stream_name(int type, const gchar* dir) {
1627 State *s = &uzbl.state;
1630 xwin_str = itos((int)uzbl.xwin);
1632 str = g_strdup_printf
1633 ("%s/uzbl_fifo_%s", dir,
1634 s->instance_name ? s->instance_name : xwin_str);
1635 } else if (type == SOCKET) {
1636 str = g_strdup_printf
1637 ("%s/uzbl_socket_%s", dir,
1638 s->instance_name ? s->instance_name : xwin_str );
1645 control_fifo(GIOChannel *gio, GIOCondition condition) {
1646 if (uzbl.state.verbose)
1647 printf("triggered\n");
1652 if (condition & G_IO_HUP)
1653 g_error ("Fifo: Read end of pipe died!\n");
1656 g_error ("Fifo: GIOChannel broke\n");
1658 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1659 if (ret == G_IO_STATUS_ERROR) {
1660 g_error ("Fifo: Error reading: %s\n", err->message);
1664 parse_cmd_line(ctl_line);
1671 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1672 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1673 if (unlink(uzbl.comm.fifo_path) == -1)
1674 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1675 g_free(uzbl.comm.fifo_path);
1676 uzbl.comm.fifo_path = NULL;
1679 if (*dir == ' ') { /* space unsets the variable */
1684 GIOChannel *chan = NULL;
1685 GError *error = NULL;
1686 gchar *path = build_stream_name(FIFO, dir);
1688 if (!file_exists(path)) {
1689 if (mkfifo (path, 0666) == 0) {
1690 // 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.
1691 chan = g_io_channel_new_file(path, "r+", &error);
1693 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1694 if (uzbl.state.verbose)
1695 printf ("init_fifo: created successfully as %s\n", path);
1696 uzbl.comm.fifo_path = path;
1698 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1699 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1700 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1701 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1703 /* if we got this far, there was an error; cleanup */
1704 if (error) g_error_free (error);
1711 control_stdin(GIOChannel *gio, GIOCondition condition) {
1713 gchar *ctl_line = NULL;
1716 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1717 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1720 parse_cmd_line(ctl_line);
1728 GIOChannel *chan = NULL;
1729 GError *error = NULL;
1731 chan = g_io_channel_unix_new(fileno(stdin));
1733 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1734 g_error ("Stdin: could not add watch\n");
1736 if (uzbl.state.verbose)
1737 printf ("Stdin: watch added successfully\n");
1740 g_error ("Stdin: Error while opening: %s\n", error->message);
1742 if (error) g_error_free (error);
1746 control_socket(GIOChannel *chan) {
1747 struct sockaddr_un remote;
1748 char buffer[512], *ctl_line;
1750 int sock, clientsock, n, done;
1753 sock = g_io_channel_unix_get_fd(chan);
1755 memset (buffer, 0, sizeof (buffer));
1757 t = sizeof (remote);
1758 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1762 memset (temp, 0, sizeof (temp));
1763 n = recv (clientsock, temp, 128, 0);
1765 buffer[strlen (buffer)] = '\0';
1769 strcat (buffer, temp);
1772 if (strcmp (buffer, "\n") < 0) {
1773 buffer[strlen (buffer) - 1] = '\0';
1775 buffer[strlen (buffer)] = '\0';
1778 ctl_line = g_strdup(buffer);
1779 parse_cmd_line (ctl_line);
1782 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1783 GError *error = NULL;
1786 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1787 if (ret == G_IO_STATUS_ERROR)
1788 g_error ("Error reading: %s\n", error->message);
1790 printf("Got line %s (%u bytes) \n",ctl_line, len);
1792 parse_line(ctl_line);
1800 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1801 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1802 if (unlink(uzbl.comm.socket_path) == -1)
1803 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1804 g_free(uzbl.comm.socket_path);
1805 uzbl.comm.socket_path = NULL;
1813 GIOChannel *chan = NULL;
1815 struct sockaddr_un local;
1816 gchar *path = build_stream_name(SOCKET, dir);
1818 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1820 local.sun_family = AF_UNIX;
1821 strcpy (local.sun_path, path);
1822 unlink (local.sun_path);
1824 len = strlen (local.sun_path) + sizeof (local.sun_family);
1825 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1826 if (uzbl.state.verbose)
1827 printf ("init_socket: opened in %s\n", path);
1830 if( (chan = g_io_channel_unix_new(sock)) ) {
1831 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1832 uzbl.comm.socket_path = path;
1835 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1837 /* if we got this far, there was an error; cleanup */
1844 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1845 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1847 // this function may be called very early when the templates are not set (yet), hence the checks
1849 update_title (void) {
1850 Behaviour *b = &uzbl.behave;
1853 if (b->show_status) {
1854 if (b->title_format_short) {
1855 parsed = expand_template(b->title_format_short, FALSE);
1856 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1859 if (b->status_format) {
1860 parsed = expand_template(b->status_format, TRUE);
1861 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1864 if (b->status_background) {
1866 gdk_color_parse (b->status_background, &color);
1867 //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)
1868 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1871 if (b->title_format_long) {
1872 parsed = expand_template(b->title_format_long, FALSE);
1873 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1880 key_press_cb (GtkWidget* window, GdkEventKey* event)
1882 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1886 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1887 || 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)
1890 /* turn off insert mode (if always_insert_mode is not used) */
1891 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1892 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1897 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1900 if (event->keyval == GDK_Escape) {
1901 g_string_truncate(uzbl.state.keycmd, 0);
1903 dehilight(uzbl.gui.web_view, NULL);
1907 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1908 if (event->keyval == GDK_Insert) {
1910 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1911 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1913 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1916 g_string_append (uzbl.state.keycmd, str);
1923 if (event->keyval == GDK_BackSpace)
1924 keycmd_bs(NULL, NULL);
1926 gboolean key_ret = FALSE;
1927 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1929 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1931 run_keycmd(key_ret);
1933 if (key_ret) return (!uzbl.behave.insert_mode);
1938 run_keycmd(const gboolean key_ret) {
1939 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1941 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1942 g_string_truncate(uzbl.state.keycmd, 0);
1943 parse_command(act->name, act->param);
1947 /* try if it's an incremental keycmd or one that takes args, and run it */
1948 GString* short_keys = g_string_new ("");
1949 GString* short_keys_inc = g_string_new ("");
1951 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1952 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1953 g_string_assign(short_keys_inc, short_keys->str);
1954 g_string_append_c(short_keys, '_');
1955 g_string_append_c(short_keys_inc, '*');
1957 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1958 /* run normal cmds only if return was pressed */
1959 exec_paramcmd(act, i);
1960 g_string_truncate(uzbl.state.keycmd, 0);
1962 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1963 if (key_ret) /* just quit the incremental command on return */
1964 g_string_truncate(uzbl.state.keycmd, 0);
1965 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1969 g_string_truncate(short_keys, short_keys->len - 1);
1971 g_string_free (short_keys, TRUE);
1972 g_string_free (short_keys_inc, TRUE);
1976 exec_paramcmd(const Action *act, const guint i) {
1977 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1978 GString *actionname = g_string_new ("");
1979 GString *actionparam = g_string_new ("");
1980 g_string_erase (parampart, 0, i+1);
1982 g_string_printf (actionname, act->name, parampart->str);
1984 g_string_printf (actionparam, act->param, parampart->str);
1985 parse_command(actionname->str, actionparam->str);
1986 g_string_free(actionname, TRUE);
1987 g_string_free(actionparam, TRUE);
1988 g_string_free(parampart, TRUE);
1996 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1997 //main_window_ref = g_object_ref(scrolled_window);
1998 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
2000 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2001 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2003 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2004 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2011 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2012 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2015 return scrolled_window;
2022 g->mainbar = gtk_hbox_new (FALSE, 0);
2024 /* keep a reference to the bar so we can re-pack it at runtime*/
2025 //sbar_ref = g_object_ref(g->mainbar);
2027 g->mainbar_label = gtk_label_new ("");
2028 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2029 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2030 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2031 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2032 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2037 GtkWidget* create_window () {
2038 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2039 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2040 gtk_widget_set_name (window, "Uzbl browser");
2041 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2042 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2048 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2050 If actname is one that calls an external command, this function will inject
2051 newargs in front of the user-provided args in that command line. They will
2052 come become after the body of the script (in sh) or after the name of
2053 the command to execute (in spawn).
2054 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2055 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2057 The return value consist of two strings: the action (sh, ...) and its args.
2059 If act is not one that calls an external command, then the given action merely
2062 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2063 gchar *actdup = g_strdup(actname);
2064 g_array_append_val(rets, actdup);
2066 if ((g_strcmp0(actname, "spawn") == 0) ||
2067 (g_strcmp0(actname, "sh") == 0) ||
2068 (g_strcmp0(actname, "sync_spawn") == 0) ||
2069 (g_strcmp0(actname, "sync_sh") == 0)) {
2071 GString *a = g_string_new("");
2072 gchar **spawnparts = split_quoted(origargs, FALSE);
2073 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2074 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2076 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2077 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2079 g_array_append_val(rets, a->str);
2080 g_string_free(a, FALSE);
2081 g_strfreev(spawnparts);
2083 gchar *origdup = g_strdup(origargs);
2084 g_array_append_val(rets, origdup);
2086 return (gchar**)g_array_free(rets, FALSE);
2090 run_handler (const gchar *act, const gchar *args) {
2091 /* Consider this code a temporary hack to make the handlers usable.
2092 In practice, all this splicing, injection, and reconstruction is
2093 inefficient, annoying and hard to manage. Potential pitfalls arise
2094 when the handler specific args 1) are not quoted (the handler
2095 callbacks should take care of this) 2) are quoted but interfere
2096 with the users' own quotation. A more ideal solution is
2097 to refactor parse_command so that it doesn't just take a string
2098 and execute it; rather than that, we should have a function which
2099 returns the argument vector parsed from the string. This vector
2100 could be modified (e.g. insert additional args into it) before
2101 passing it to the next function that actually executes it. Though
2102 it still isn't perfect for chain actions.. will reconsider & re-
2103 factor when I have the time. -duc */
2105 char **parts = g_strsplit(act, " ", 2);
2107 if (g_strcmp0(parts[0], "chain") == 0) {
2108 GString *newargs = g_string_new("");
2109 gchar **chainparts = split_quoted(parts[1], FALSE);
2111 /* for every argument in the chain, inject the handler args
2112 and make sure the new parts are wrapped in quotes */
2113 gchar **cp = chainparts;
2115 gchar *quotless = NULL;
2116 gchar **spliced_quotless = NULL; // sigh -_-;
2117 gchar **inpart = NULL;
2120 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2122 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2123 } else quotless = g_strdup(*cp);
2125 spliced_quotless = g_strsplit(quotless, " ", 2);
2126 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2127 g_strfreev(spliced_quotless);
2129 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2135 parse_command(parts[0], &(newargs->str[1]));
2136 g_string_free(newargs, TRUE);
2137 g_strfreev(chainparts);
2140 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2141 parse_command(inparts[0], inparts[1]);
2149 add_binding (const gchar *key, const gchar *act) {
2150 char **parts = g_strsplit(act, " ", 2);
2157 if (uzbl.state.verbose)
2158 printf ("Binding %-10s : %s\n", key, act);
2159 action = new_action(parts[0], parts[1]);
2161 if (g_hash_table_remove (uzbl.bindings, key))
2162 g_warning ("Overwriting existing binding for \"%s\"", key);
2163 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2168 get_xdg_var (XDG_Var xdg) {
2169 const gchar* actual_value = getenv (xdg.environmental);
2170 const gchar* home = getenv ("HOME");
2172 gchar* return_value = str_replace ("~", home, actual_value);
2174 if (! actual_value || strcmp (actual_value, "") == 0) {
2175 if (xdg.default_value) {
2176 return_value = str_replace ("~", home, xdg.default_value);
2178 return_value = NULL;
2181 return return_value;
2185 find_xdg_file (int xdg_type, char* filename) {
2186 /* xdg_type = 0 => config
2187 xdg_type = 1 => data
2188 xdg_type = 2 => cache*/
2190 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2191 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2194 gchar* temporary_string;
2198 if (! file_exists (temporary_file) && xdg_type != 2) {
2199 buf = get_xdg_var (XDG[3 + xdg_type]);
2200 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2203 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2204 g_free (temporary_file);
2205 temporary_file = g_strconcat (temporary_string, filename, NULL);
2209 //g_free (temporary_string); - segfaults.
2211 if (file_exists (temporary_file)) {
2212 return temporary_file;
2219 State *s = &uzbl.state;
2220 Network *n = &uzbl.net;
2222 for (i = 0; default_config[i].command != NULL; i++) {
2223 parse_cmd_line(default_config[i].command);
2226 if (!s->config_file) {
2227 s->config_file = find_xdg_file (0, "/uzbl/config");
2230 if (s->config_file) {
2231 GArray* lines = read_file_by_line (s->config_file);
2235 while ((line = g_array_index(lines, gchar*, i))) {
2236 parse_cmd_line (line);
2240 g_array_free (lines, TRUE);
2242 if (uzbl.state.verbose)
2243 printf ("No configuration file loaded.\n");
2246 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2249 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2252 if (!uzbl.behave.cookie_handler)
2255 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2256 GString *s = g_string_new ("");
2257 SoupURI * soup_uri = soup_message_get_uri(msg);
2258 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2259 run_handler(uzbl.behave.cookie_handler, s->str);
2261 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2262 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2263 if ( p != NULL ) *p = '\0';
2264 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2266 if (uzbl.comm.sync_stdout)
2267 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2269 g_string_free(s, TRUE);
2273 save_cookies (SoupMessage *msg, gpointer user_data){
2277 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2278 cookie = soup_cookie_to_set_cookie_header(ck->data);
2279 SoupURI * soup_uri = soup_message_get_uri(msg);
2280 GString *s = g_string_new ("");
2281 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2282 run_handler(uzbl.behave.cookie_handler, s->str);
2284 g_string_free(s, TRUE);
2289 /* --- WEBINSPECTOR --- */
2291 hide_window_cb(GtkWidget *widget, gpointer data) {
2294 gtk_widget_hide(widget);
2297 static WebKitWebView*
2298 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2301 (void) web_inspector;
2302 GtkWidget* scrolled_window;
2303 GtkWidget* new_web_view;
2306 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2307 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2308 G_CALLBACK(hide_window_cb), NULL);
2310 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2311 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2312 gtk_widget_show(g->inspector_window);
2314 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2315 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2316 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2317 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2318 gtk_widget_show(scrolled_window);
2320 new_web_view = webkit_web_view_new();
2321 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2323 return WEBKIT_WEB_VIEW(new_web_view);
2327 inspector_show_window_cb (WebKitWebInspector* inspector){
2329 gtk_widget_show(uzbl.gui.inspector_window);
2333 /* TODO: Add variables and code to make use of these functions */
2335 inspector_close_window_cb (WebKitWebInspector* inspector){
2341 inspector_attach_window_cb (WebKitWebInspector* inspector){
2347 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2353 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2359 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2365 set_up_inspector() {
2367 WebKitWebSettings *settings = view_settings();
2368 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2370 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2371 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2372 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2373 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2374 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2375 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2376 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2378 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2382 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2384 uzbl_cmdprop *c = v;
2389 if(c->type == TYPE_STR)
2390 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2391 else if(c->type == TYPE_INT)
2392 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2396 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2400 printf("bind %s = %s %s\n", (char *)k ,
2401 (char *)a->name, a->param?(char *)a->param:"");
2406 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2407 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2412 main (int argc, char* argv[]) {
2413 gtk_init (&argc, &argv);
2414 if (!g_thread_supported ())
2415 g_thread_init (NULL);
2416 uzbl.state.executable_path = g_strdup(argv[0]);
2417 uzbl.state.selected_url = NULL;
2418 uzbl.state.searchtx = NULL;
2420 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2421 g_option_context_add_main_entries (context, entries, NULL);
2422 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2423 g_option_context_parse (context, &argc, &argv, NULL);
2424 g_option_context_free(context);
2426 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2427 gboolean verbose_override = uzbl.state.verbose;
2429 /* initialize hash table */
2430 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2432 uzbl.net.soup_session = webkit_get_default_session();
2433 uzbl.state.keycmd = g_string_new("");
2435 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2436 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2437 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2438 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2439 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2440 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2443 if(uname(&uzbl.state.unameinfo) == -1)
2444 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2446 uzbl.gui.sbar.progress_s = g_strdup("=");
2447 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2448 uzbl.gui.sbar.progress_w = 10;
2450 /* HTML mode defaults*/
2451 uzbl.behave.html_buffer = g_string_new("");
2452 uzbl.behave.html_endmarker = g_strdup(".");
2453 uzbl.behave.html_timeout = 60;
2454 uzbl.behave.base_url = g_strdup("http://invalid");
2456 /* default mode indicators */
2457 uzbl.behave.insert_indicator = g_strdup("I");
2458 uzbl.behave.cmd_indicator = g_strdup("C");
2462 make_var_to_name_hash();
2464 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2466 uzbl.gui.scrolled_win = create_browser();
2469 /* initial packing */
2470 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2471 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2473 uzbl.gui.main_window = create_window ();
2474 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2477 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2478 gtk_widget_show_all (uzbl.gui.main_window);
2479 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2481 if (uzbl.state.verbose) {
2482 printf("Uzbl start location: %s\n", argv[0]);
2483 printf("window_id %i\n",(int) uzbl.xwin);
2484 printf("pid %i\n", getpid ());
2485 printf("name: %s\n", uzbl.state.instance_name);
2488 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2489 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2490 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2491 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2492 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2496 if (!uzbl.behave.show_status)
2497 gtk_widget_hide(uzbl.gui.mainbar);
2506 if (verbose_override > uzbl.state.verbose)
2507 uzbl.state.verbose = verbose_override;
2510 set_var_value("uri", uri_override);
2511 g_free(uri_override);
2512 } else if (uzbl.state.uri)
2513 cmd_load_uri(uzbl.gui.web_view, NULL);
2518 return EXIT_SUCCESS;
2521 /* vi: set et ts=4: */