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 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
549 if (uzbl.behave.load_start_handler)
550 run_handler(uzbl.behave.load_start_handler, "");
554 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
557 g_free (uzbl.state.uri);
558 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
559 uzbl.state.uri = g_string_free (newuri, FALSE);
560 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
561 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
564 if (uzbl.behave.load_commit_handler)
565 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
569 destroy_cb (GtkWidget* widget, gpointer data) {
577 if (uzbl.behave.history_handler) {
579 struct tm * timeinfo;
582 timeinfo = localtime ( &rawtime );
583 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
584 run_handler(uzbl.behave.history_handler, date);
589 /* VIEW funcs (little webkit wrappers) */
590 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
592 VIEWFUNC(reload_bypass_cache)
593 VIEWFUNC(stop_loading)
600 /* -- command to callback/function map for things we cannot attach to any signals */
601 static struct {char *name; Command command[2];} cmdlist[] =
602 { /* key function no_split */
603 { "back", {view_go_back, 0} },
604 { "forward", {view_go_forward, 0} },
605 { "scroll_vert", {scroll_vert, 0} },
606 { "scroll_horz", {scroll_horz, 0} },
607 { "scroll_begin", {scroll_begin, 0} },
608 { "scroll_end", {scroll_end, 0} },
609 { "reload", {view_reload, 0}, },
610 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
611 { "stop", {view_stop_loading, 0}, },
612 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
613 { "zoom_out", {view_zoom_out, 0}, },
614 { "uri", {load_uri, NOSPLIT} },
615 { "js", {run_js, NOSPLIT} },
616 { "script", {run_external_js, 0} },
617 { "toggle_status", {toggle_status_cb, 0} },
618 { "spawn", {spawn, 0} },
619 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
620 { "sh", {spawn_sh, 0} },
621 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
622 { "exit", {close_uzbl, 0} },
623 { "search", {search_forward_text, NOSPLIT} },
624 { "search_reverse", {search_reverse_text, NOSPLIT} },
625 { "dehilight", {dehilight, 0} },
626 { "toggle_insert_mode", {toggle_insert_mode, 0} },
627 { "set", {set_var, NOSPLIT} },
628 //{ "get", {get_var, NOSPLIT} },
629 { "bind", {act_bind, NOSPLIT} },
630 { "dump_config", {act_dump_config, 0} },
631 { "keycmd", {keycmd, NOSPLIT} },
632 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
633 { "keycmd_bs", {keycmd_bs, 0} },
634 { "chain", {chain, 0} },
635 { "print", {print, NOSPLIT} }
642 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
644 for (i = 0; i < LENGTH(cmdlist); i++)
645 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
648 /* -- CORE FUNCTIONS -- */
651 free_action(gpointer act) {
652 Action *action = (Action*)act;
653 g_free(action->name);
655 g_free(action->param);
660 new_action(const gchar *name, const gchar *param) {
661 Action *action = g_new(Action, 1);
663 action->name = g_strdup(name);
665 action->param = g_strdup(param);
667 action->param = NULL;
673 file_exists (const char * filename) {
674 return (access(filename, F_OK) == 0);
678 set_var(WebKitWebView *page, GArray *argv) {
680 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
681 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
682 set_var_value(g_strstrip(split[0]), value);
688 print(WebKitWebView *page, GArray *argv) {
692 buf = expand_vars(argv_idx(argv, 0));
698 act_bind(WebKitWebView *page, GArray *argv) {
700 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
701 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
702 add_binding(g_strstrip(split[0]), value);
714 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
717 if (argv_idx(argv, 0)) {
718 if (strcmp (argv_idx(argv, 0), "0") == 0) {
719 uzbl.behave.insert_mode = FALSE;
721 uzbl.behave.insert_mode = TRUE;
724 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
731 load_uri (WebKitWebView *web_view, GArray *argv) {
732 if (argv_idx(argv, 0)) {
733 GString* newuri = g_string_new (argv_idx(argv, 0));
734 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
735 g_string_prepend (newuri, "http://");
736 /* if we do handle cookies, ask our handler for them */
737 webkit_web_view_load_uri (web_view, newuri->str);
738 g_string_free (newuri, TRUE);
743 run_js (WebKitWebView * web_view, GArray *argv) {
744 if (argv_idx(argv, 0))
745 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
749 run_external_js (WebKitWebView * web_view, GArray *argv) {
750 if (argv_idx(argv, 0)) {
751 GArray* lines = read_file_by_line (argv_idx (argv, 0));
756 while ((line = g_array_index(lines, gchar*, i))) {
758 js = g_strdup (line);
760 gchar* newjs = g_strconcat (js, line, NULL);
767 if (uzbl.state.verbose)
768 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
770 if (argv_idx (argv, 1)) {
771 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
775 webkit_web_view_execute_script (web_view, js);
777 g_array_free (lines, TRUE);
782 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
783 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
784 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
785 webkit_web_view_unmark_text_matches (page);
786 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
787 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
791 if (uzbl.state.searchtx) {
792 if (uzbl.state.verbose)
793 printf ("Searching: %s\n", uzbl.state.searchtx);
794 webkit_web_view_set_highlight_text_matches (page, TRUE);
795 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
800 search_forward_text (WebKitWebView *page, GArray *argv) {
801 search_text(page, argv, TRUE);
805 search_reverse_text (WebKitWebView *page, GArray *argv) {
806 search_text(page, argv, FALSE);
810 dehilight (WebKitWebView *page, GArray *argv) {
812 webkit_web_view_set_highlight_text_matches (page, FALSE);
817 new_window_load_uri (const gchar * uri) {
818 GString* to_execute = g_string_new ("");
819 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
821 for (i = 0; entries[i].long_name != NULL; i++) {
822 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
823 gchar** str = (gchar**)entries[i].arg_data;
825 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
829 if (uzbl.state.verbose)
830 printf("\n%s\n", to_execute->str);
831 g_spawn_command_line_async (to_execute->str, NULL);
832 g_string_free (to_execute, TRUE);
836 chain (WebKitWebView *page, GArray *argv) {
839 gchar **parts = NULL;
841 while ((a = argv_idx(argv, i++))) {
842 parts = g_strsplit (a, " ", 2);
843 parse_command(parts[0], parts[1]);
849 keycmd (WebKitWebView *page, GArray *argv) {
852 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
858 keycmd_nl (WebKitWebView *page, GArray *argv) {
861 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
867 keycmd_bs (WebKitWebView *page, GArray *argv) {
870 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
875 close_uzbl (WebKitWebView *page, GArray *argv) {
881 /* --Statusbar functions-- */
883 build_progressbar_ascii(int percent) {
884 int width=uzbl.gui.sbar.progress_w;
887 GString *bar = g_string_new("");
889 l = (double)percent*((double)width/100.);
890 l = (int)(l+.5)>=(int)l ? l+.5 : l;
892 for(i=0; i<(int)l; i++)
893 g_string_append(bar, uzbl.gui.sbar.progress_s);
896 g_string_append(bar, uzbl.gui.sbar.progress_u);
898 return g_string_free(bar, FALSE);
903 const GScannerConfig scan_config = {
906 ) /* cset_skip_characters */,
911 ) /* cset_identifier_first */,
918 ) /* cset_identifier_nth */,
919 ( "" ) /* cpair_comment_single */,
921 TRUE /* case_sensitive */,
923 FALSE /* skip_comment_multi */,
924 FALSE /* skip_comment_single */,
925 FALSE /* scan_comment_multi */,
926 TRUE /* scan_identifier */,
927 TRUE /* scan_identifier_1char */,
928 FALSE /* scan_identifier_NULL */,
929 TRUE /* scan_symbols */,
930 FALSE /* scan_binary */,
931 FALSE /* scan_octal */,
932 FALSE /* scan_float */,
933 FALSE /* scan_hex */,
934 FALSE /* scan_hex_dollar */,
935 FALSE /* scan_string_sq */,
936 FALSE /* scan_string_dq */,
937 TRUE /* numbers_2_int */,
938 FALSE /* int_2_float */,
939 FALSE /* identifier_2_string */,
940 FALSE /* char_2_token */,
941 FALSE /* symbol_2_token */,
942 TRUE /* scope_0_fallback */,
947 uzbl.scan = g_scanner_new(&scan_config);
948 while(symp->symbol_name) {
949 g_scanner_scope_add_symbol(uzbl.scan, 0,
951 GINT_TO_POINTER(symp->symbol_token));
957 expand_template(const char *template, gboolean escape_markup) {
958 if(!template) return NULL;
960 GTokenType token = G_TOKEN_NONE;
961 GString *ret = g_string_new("");
965 g_scanner_input_text(uzbl.scan, template, strlen(template));
966 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
967 token = g_scanner_get_next_token(uzbl.scan);
969 if(token == G_TOKEN_SYMBOL) {
970 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
974 buf = uzbl.state.uri?
975 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
976 g_string_append(ret, buf);
980 g_string_append(ret, uzbl.state.uri?
981 uzbl.state.uri:g_strdup(""));
984 buf = itos(uzbl.gui.sbar.load_progress);
985 g_string_append(ret, buf);
988 case SYM_LOADPRGSBAR:
989 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
990 g_string_append(ret, buf);
995 buf = uzbl.gui.main_title?
996 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
997 g_string_append(ret, buf);
1001 g_string_append(ret, uzbl.gui.main_title?
1002 uzbl.gui.main_title:g_strdup(""));
1004 case SYM_SELECTED_URI:
1006 buf = uzbl.state.selected_url?
1007 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1008 g_string_append(ret, buf);
1012 g_string_append(ret, uzbl.state.selected_url?
1013 uzbl.state.selected_url:g_strdup(""));
1016 buf = itos(uzbl.xwin);
1017 g_string_append(ret,
1018 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1023 buf = uzbl.state.keycmd->str?
1024 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1025 g_string_append(ret, buf);
1029 g_string_append(ret, uzbl.state.keycmd->str?
1030 uzbl.state.keycmd->str:g_strdup(""));
1033 g_string_append(ret,
1034 uzbl.behave.insert_mode?
1035 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1038 g_string_append(ret,
1039 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1041 /* useragent syms */
1043 buf = itos(WEBKIT_MAJOR_VERSION);
1044 g_string_append(ret, buf);
1048 buf = itos(WEBKIT_MINOR_VERSION);
1049 g_string_append(ret, buf);
1053 buf = itos(WEBKIT_MICRO_VERSION);
1054 g_string_append(ret, buf);
1058 g_string_append(ret, uzbl.state.unameinfo.sysname);
1061 g_string_append(ret, uzbl.state.unameinfo.nodename);
1064 g_string_append(ret, uzbl.state.unameinfo.release);
1067 g_string_append(ret, uzbl.state.unameinfo.version);
1070 g_string_append(ret, uzbl.state.unameinfo.machine);
1073 g_string_append(ret, ARCH);
1076 case SYM_DOMAINNAME:
1077 g_string_append(ret, uzbl.state.unameinfo.domainname);
1081 g_string_append(ret, COMMIT);
1087 else if(token == G_TOKEN_INT) {
1088 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1089 g_string_append(ret, buf);
1092 else if(token == G_TOKEN_IDENTIFIER) {
1093 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1095 else if(token == G_TOKEN_CHAR) {
1096 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1100 return g_string_free(ret, FALSE);
1102 /* --End Statusbar functions-- */
1105 sharg_append(GArray *a, const gchar *str) {
1106 const gchar *s = (str ? str : "");
1107 g_array_append_val(a, s);
1110 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1112 run_command (const gchar *command, const guint npre, const gchar **args,
1113 const gboolean sync, char **stdout) {
1114 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1117 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1118 gchar *pid = itos(getpid());
1119 gchar *xwin = itos(uzbl.xwin);
1121 sharg_append(a, command);
1122 for (i = 0; i < npre; i++) /* add n args before the default vars */
1123 sharg_append(a, args[i]);
1124 sharg_append(a, uzbl.state.config_file);
1125 sharg_append(a, pid);
1126 sharg_append(a, xwin);
1127 sharg_append(a, uzbl.comm.fifo_path);
1128 sharg_append(a, uzbl.comm.socket_path);
1129 sharg_append(a, uzbl.state.uri);
1130 sharg_append(a, uzbl.gui.main_title);
1132 for (i = npre; i < g_strv_length((gchar**)args); i++)
1133 sharg_append(a, args[i]);
1137 if (*stdout) *stdout = strfree(*stdout);
1139 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1140 NULL, NULL, stdout, NULL, NULL, &err);
1141 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1142 NULL, NULL, NULL, &err);
1144 if (uzbl.state.verbose) {
1145 GString *s = g_string_new("spawned:");
1146 for (i = 0; i < (a->len); i++) {
1147 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1148 g_string_append_printf(s, " %s", qarg);
1151 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1152 printf("%s\n", s->str);
1153 g_string_free(s, TRUE);
1155 printf("Stdout: %s\n", *stdout);
1159 g_printerr("error on run_command: %s\n", err->message);
1164 g_array_free (a, TRUE);
1169 split_quoted(const gchar* src, const gboolean unquote) {
1170 /* split on unquoted space, return array of strings;
1171 remove a layer of quotes and backslashes if unquote */
1172 if (!src) return NULL;
1174 gboolean dq = FALSE;
1175 gboolean sq = FALSE;
1176 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1177 GString *s = g_string_new ("");
1181 for (p = src; *p != '\0'; p++) {
1182 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1183 else if (*p == '\\') { g_string_append_c(s, *p++);
1184 g_string_append_c(s, *p); }
1185 else if ((*p == '"') && unquote && !sq) dq = !dq;
1186 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1188 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1189 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1191 else if ((*p == ' ') && !dq && !sq) {
1192 dup = g_strdup(s->str);
1193 g_array_append_val(a, dup);
1194 g_string_truncate(s, 0);
1195 } else g_string_append_c(s, *p);
1197 dup = g_strdup(s->str);
1198 g_array_append_val(a, dup);
1199 ret = (gchar**)a->data;
1200 g_array_free (a, FALSE);
1201 g_string_free (s, TRUE);
1206 spawn(WebKitWebView *web_view, GArray *argv) {
1208 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1209 if (argv_idx(argv, 0))
1210 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1214 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1217 if (argv_idx(argv, 0))
1218 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1219 TRUE, &uzbl.comm.sync_stdout);
1223 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1225 if (!uzbl.behave.shell_cmd) {
1226 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1231 gchar *spacer = g_strdup("");
1232 g_array_insert_val(argv, 1, spacer);
1233 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1235 for (i = 1; i < g_strv_length(cmd); i++)
1236 g_array_prepend_val(argv, cmd[i]);
1238 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1244 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1246 if (!uzbl.behave.shell_cmd) {
1247 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1252 gchar *spacer = g_strdup("");
1253 g_array_insert_val(argv, 1, spacer);
1254 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1256 for (i = 1; i < g_strv_length(cmd); i++)
1257 g_array_prepend_val(argv, cmd[i]);
1259 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1260 TRUE, &uzbl.comm.sync_stdout);
1266 parse_command(const char *cmd, const char *param) {
1269 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1272 gchar **par = split_quoted(param, TRUE);
1273 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1275 if (c[1] == NOSPLIT) { /* don't split */
1276 sharg_append(a, param);
1278 for (i = 0; i < g_strv_length(par); i++)
1279 sharg_append(a, par[i]);
1281 c[0](uzbl.gui.web_view, a);
1283 g_array_free (a, TRUE);
1286 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1293 if(*uzbl.net.proxy_url == ' '
1294 || uzbl.net.proxy_url == NULL) {
1295 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1296 (GType) SOUP_SESSION_PROXY_URI);
1299 suri = soup_uri_new(uzbl.net.proxy_url);
1300 g_object_set(G_OBJECT(uzbl.net.soup_session),
1301 SOUP_SESSION_PROXY_URI,
1303 soup_uri_free(suri);
1310 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1311 g_array_append_val (a, uzbl.state.uri);
1312 load_uri(uzbl.gui.web_view, a);
1313 g_array_free (a, TRUE);
1317 cmd_always_insert_mode() {
1318 uzbl.behave.insert_mode =
1319 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1325 g_object_set(G_OBJECT(uzbl.net.soup_session),
1326 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1330 cmd_max_conns_host() {
1331 g_object_set(G_OBJECT(uzbl.net.soup_session),
1332 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1337 soup_session_remove_feature
1338 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1339 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1340 /*g_free(uzbl.net.soup_logger);*/
1342 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1343 soup_session_add_feature(uzbl.net.soup_session,
1344 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1347 static WebKitWebSettings*
1349 return webkit_web_view_get_settings(uzbl.gui.web_view);
1354 WebKitWebSettings *ws = view_settings();
1355 if (uzbl.behave.font_size > 0) {
1356 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1359 if (uzbl.behave.monospace_size > 0) {
1360 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1361 uzbl.behave.monospace_size, NULL);
1363 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1364 uzbl.behave.font_size, NULL);
1370 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1374 cmd_disable_plugins() {
1375 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1376 !uzbl.behave.disable_plugins, NULL);
1380 cmd_disable_scripts() {
1381 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1382 !uzbl.behave.disable_scripts, NULL);
1386 cmd_minimum_font_size() {
1387 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1388 uzbl.behave.minimum_font_size, NULL);
1391 cmd_autoload_img() {
1392 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1393 uzbl.behave.autoload_img, NULL);
1398 cmd_autoshrink_img() {
1399 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1400 uzbl.behave.autoshrink_img, NULL);
1405 cmd_enable_spellcheck() {
1406 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1407 uzbl.behave.enable_spellcheck, NULL);
1411 cmd_enable_private() {
1412 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1413 uzbl.behave.enable_private, NULL);
1418 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1419 uzbl.behave.print_bg, NULL);
1424 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1425 uzbl.behave.style_uri, NULL);
1429 cmd_resizable_txt() {
1430 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1431 uzbl.behave.resizable_txt, NULL);
1435 cmd_default_encoding() {
1436 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1437 uzbl.behave.default_encoding, NULL);
1441 cmd_enforce_96dpi() {
1442 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1443 uzbl.behave.enforce_96dpi, NULL);
1447 cmd_caret_browsing() {
1448 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1449 uzbl.behave.caret_browsing, NULL);
1453 cmd_cookie_handler() {
1454 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1455 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1456 if ((g_strcmp0(split[0], "sh") == 0) ||
1457 (g_strcmp0(split[0], "spawn") == 0)) {
1458 g_free (uzbl.behave.cookie_handler);
1459 uzbl.behave.cookie_handler =
1460 g_strdup_printf("sync_%s %s", split[0], split[1]);
1467 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1472 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1477 if(uzbl.behave.inject_html) {
1478 webkit_web_view_load_html_string (uzbl.gui.web_view,
1479 uzbl.behave.inject_html, NULL);
1488 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1489 uzbl.behave.modmask = 0;
1491 if(uzbl.behave.modkey)
1492 g_free(uzbl.behave.modkey);
1493 uzbl.behave.modkey = buf;
1495 for (i = 0; modkeys[i].key != NULL; i++) {
1496 if (g_strrstr(buf, modkeys[i].key))
1497 uzbl.behave.modmask |= modkeys[i].mask;
1503 if (*uzbl.net.useragent == ' ') {
1504 g_free (uzbl.net.useragent);
1505 uzbl.net.useragent = NULL;
1507 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1509 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1510 g_free(uzbl.net.useragent);
1511 uzbl.net.useragent = ua;
1517 gtk_widget_ref(uzbl.gui.scrolled_win);
1518 gtk_widget_ref(uzbl.gui.mainbar);
1519 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1520 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1522 if(uzbl.behave.status_top) {
1523 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1524 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1527 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1528 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1530 gtk_widget_unref(uzbl.gui.scrolled_win);
1531 gtk_widget_unref(uzbl.gui.mainbar);
1532 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1537 set_var_value(gchar *name, gchar *val) {
1538 uzbl_cmdprop *c = NULL;
1542 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1543 /* check for the variable type */
1544 if (c->type == TYPE_STR) {
1545 buf = expand_vars(val);
1548 } else if(c->type == TYPE_INT) {
1549 int *ip = (int *)c->ptr;
1550 buf = expand_vars(val);
1551 *ip = (int)strtoul(buf, &endp, 10);
1553 } else if (c->type == TYPE_FLOAT) {
1554 float *fp = (float *)c->ptr;
1555 buf = expand_vars(val);
1556 *fp = strtof(buf, &endp);
1560 /* invoke a command specific function */
1561 if(c->func) c->func();
1568 Behaviour *b = &uzbl.behave;
1570 if(b->html_buffer->str) {
1571 webkit_web_view_load_html_string (uzbl.gui.web_view,
1572 b->html_buffer->str, b->base_url);
1573 g_string_free(b->html_buffer, TRUE);
1574 b->html_buffer = g_string_new("");
1578 enum {M_CMD, M_HTML};
1580 parse_cmd_line(const char *ctl_line) {
1581 Behaviour *b = &uzbl.behave;
1584 if(b->mode == M_HTML) {
1585 len = strlen(b->html_endmarker);
1586 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1587 if(len == strlen(ctl_line)-1 &&
1588 !strncmp(b->html_endmarker, ctl_line, len)) {
1590 set_var_value("mode", "0");
1595 set_timeout(b->html_timeout);
1596 g_string_append(b->html_buffer, ctl_line);
1599 else if((ctl_line[0] == '#') /* Comments */
1600 || (ctl_line[0] == ' ')
1601 || (ctl_line[0] == '\n'))
1602 ; /* ignore these lines */
1603 else { /* parse a command */
1605 gchar **tokens = NULL;
1606 len = strlen(ctl_line);
1608 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1609 ctlstrip = g_strndup(ctl_line, len - 1);
1610 else ctlstrip = g_strdup(ctl_line);
1612 tokens = g_strsplit(ctlstrip, " ", 2);
1613 parse_command(tokens[0], tokens[1]);
1620 build_stream_name(int type, const gchar* dir) {
1622 State *s = &uzbl.state;
1625 xwin_str = itos((int)uzbl.xwin);
1627 str = g_strdup_printf
1628 ("%s/uzbl_fifo_%s", dir,
1629 s->instance_name ? s->instance_name : xwin_str);
1630 } else if (type == SOCKET) {
1631 str = g_strdup_printf
1632 ("%s/uzbl_socket_%s", dir,
1633 s->instance_name ? s->instance_name : xwin_str );
1640 control_fifo(GIOChannel *gio, GIOCondition condition) {
1641 if (uzbl.state.verbose)
1642 printf("triggered\n");
1647 if (condition & G_IO_HUP)
1648 g_error ("Fifo: Read end of pipe died!\n");
1651 g_error ("Fifo: GIOChannel broke\n");
1653 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1654 if (ret == G_IO_STATUS_ERROR) {
1655 g_error ("Fifo: Error reading: %s\n", err->message);
1659 parse_cmd_line(ctl_line);
1666 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1667 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1668 if (unlink(uzbl.comm.fifo_path) == -1)
1669 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1670 g_free(uzbl.comm.fifo_path);
1671 uzbl.comm.fifo_path = NULL;
1674 if (*dir == ' ') { /* space unsets the variable */
1679 GIOChannel *chan = NULL;
1680 GError *error = NULL;
1681 gchar *path = build_stream_name(FIFO, dir);
1683 // This extra check is an alternative to recursively calling init_fifo() or using goto
1684 if (file_exists(path)) {
1686 g_warning ("init_fifo: can't delete %s: %s", path, strerror(errno));
1689 if (!file_exists(path)) {
1690 if (mkfifo (path, 0666) == 0) {
1691 // 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.
1692 chan = g_io_channel_new_file(path, "r+", &error);
1694 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1695 if (uzbl.state.verbose)
1696 printf ("init_fifo: created successfully as %s\n", path);
1697 uzbl.comm.fifo_path = path;
1699 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1700 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1701 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1702 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1704 /* if we got this far, there was an error; cleanup */
1705 if (error) g_error_free (error);
1712 control_stdin(GIOChannel *gio, GIOCondition condition) {
1714 gchar *ctl_line = NULL;
1717 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1718 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1721 parse_cmd_line(ctl_line);
1729 GIOChannel *chan = NULL;
1730 GError *error = NULL;
1732 chan = g_io_channel_unix_new(fileno(stdin));
1734 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1735 g_error ("Stdin: could not add watch\n");
1737 if (uzbl.state.verbose)
1738 printf ("Stdin: watch added successfully\n");
1741 g_error ("Stdin: Error while opening: %s\n", error->message);
1743 if (error) g_error_free (error);
1747 control_socket(GIOChannel *chan) {
1748 struct sockaddr_un remote;
1749 char buffer[512], *ctl_line;
1751 int sock, clientsock, n, done;
1754 sock = g_io_channel_unix_get_fd(chan);
1756 memset (buffer, 0, sizeof (buffer));
1758 t = sizeof (remote);
1759 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1763 memset (temp, 0, sizeof (temp));
1764 n = recv (clientsock, temp, 128, 0);
1766 buffer[strlen (buffer)] = '\0';
1770 strcat (buffer, temp);
1773 if (strcmp (buffer, "\n") < 0) {
1774 buffer[strlen (buffer) - 1] = '\0';
1776 buffer[strlen (buffer)] = '\0';
1779 ctl_line = g_strdup(buffer);
1780 parse_cmd_line (ctl_line);
1783 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1784 GError *error = NULL;
1787 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1788 if (ret == G_IO_STATUS_ERROR)
1789 g_error ("Error reading: %s\n", error->message);
1791 printf("Got line %s (%u bytes) \n",ctl_line, len);
1793 parse_line(ctl_line);
1801 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1802 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1803 if (unlink(uzbl.comm.socket_path) == -1)
1804 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1805 g_free(uzbl.comm.socket_path);
1806 uzbl.comm.socket_path = NULL;
1814 GIOChannel *chan = NULL;
1816 struct sockaddr_un local;
1817 gchar *path = build_stream_name(SOCKET, dir);
1819 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1821 local.sun_family = AF_UNIX;
1822 strcpy (local.sun_path, path);
1823 unlink (local.sun_path);
1825 len = strlen (local.sun_path) + sizeof (local.sun_family);
1826 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1827 if (uzbl.state.verbose)
1828 printf ("init_socket: opened in %s\n", path);
1831 if( (chan = g_io_channel_unix_new(sock)) ) {
1832 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1833 uzbl.comm.socket_path = path;
1836 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1838 /* if we got this far, there was an error; cleanup */
1845 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1846 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1848 // this function may be called very early when the templates are not set (yet), hence the checks
1850 update_title (void) {
1851 Behaviour *b = &uzbl.behave;
1854 if (b->show_status) {
1855 if (b->title_format_short) {
1856 parsed = expand_template(b->title_format_short, FALSE);
1857 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1860 if (b->status_format) {
1861 parsed = expand_template(b->status_format, TRUE);
1862 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1865 if (b->status_background) {
1867 gdk_color_parse (b->status_background, &color);
1868 //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)
1869 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1872 if (b->title_format_long) {
1873 parsed = expand_template(b->title_format_long, FALSE);
1874 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1881 key_press_cb (GtkWidget* window, GdkEventKey* event)
1883 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1887 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1888 || 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)
1891 /* turn off insert mode (if always_insert_mode is not used) */
1892 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1893 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1898 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1901 if (event->keyval == GDK_Escape) {
1902 g_string_truncate(uzbl.state.keycmd, 0);
1904 dehilight(uzbl.gui.web_view, NULL);
1908 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1909 if (event->keyval == GDK_Insert) {
1911 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1912 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1914 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1917 g_string_append (uzbl.state.keycmd, str);
1924 if (event->keyval == GDK_BackSpace)
1925 keycmd_bs(NULL, NULL);
1927 gboolean key_ret = FALSE;
1928 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1930 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1932 run_keycmd(key_ret);
1934 if (key_ret) return (!uzbl.behave.insert_mode);
1939 run_keycmd(const gboolean key_ret) {
1940 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1942 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1943 g_string_truncate(uzbl.state.keycmd, 0);
1944 parse_command(act->name, act->param);
1948 /* try if it's an incremental keycmd or one that takes args, and run it */
1949 GString* short_keys = g_string_new ("");
1950 GString* short_keys_inc = g_string_new ("");
1952 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1953 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1954 g_string_assign(short_keys_inc, short_keys->str);
1955 g_string_append_c(short_keys, '_');
1956 g_string_append_c(short_keys_inc, '*');
1958 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1959 /* run normal cmds only if return was pressed */
1960 exec_paramcmd(act, i);
1961 g_string_truncate(uzbl.state.keycmd, 0);
1963 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1964 if (key_ret) /* just quit the incremental command on return */
1965 g_string_truncate(uzbl.state.keycmd, 0);
1966 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1970 g_string_truncate(short_keys, short_keys->len - 1);
1972 g_string_free (short_keys, TRUE);
1973 g_string_free (short_keys_inc, TRUE);
1977 exec_paramcmd(const Action *act, const guint i) {
1978 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1979 GString *actionname = g_string_new ("");
1980 GString *actionparam = g_string_new ("");
1981 g_string_erase (parampart, 0, i+1);
1983 g_string_printf (actionname, act->name, parampart->str);
1985 g_string_printf (actionparam, act->param, parampart->str);
1986 parse_command(actionname->str, actionparam->str);
1987 g_string_free(actionname, TRUE);
1988 g_string_free(actionparam, TRUE);
1989 g_string_free(parampart, TRUE);
1997 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1998 //main_window_ref = g_object_ref(scrolled_window);
1999 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
2001 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2002 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2004 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2011 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2012 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2014 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2016 return scrolled_window;
2023 g->mainbar = gtk_hbox_new (FALSE, 0);
2025 /* keep a reference to the bar so we can re-pack it at runtime*/
2026 //sbar_ref = g_object_ref(g->mainbar);
2028 g->mainbar_label = gtk_label_new ("");
2029 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2030 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2031 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2032 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2033 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2038 GtkWidget* create_window () {
2039 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2040 gchar* uzbl_icon = g_strdup(find_xdg_file(1, "/uzbl/uzbl.png"));
2041 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2042 gtk_widget_set_name (window, "Uzbl browser");
2043 gtk_window_set_icon_from_file (GTK_WINDOW (window), uzbl_icon, NULL);
2044 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2045 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2053 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2055 If actname is one that calls an external command, this function will inject
2056 newargs in front of the user-provided args in that command line. They will
2057 come become after the body of the script (in sh) or after the name of
2058 the command to execute (in spawn).
2059 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2060 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2062 The return value consist of two strings: the action (sh, ...) and its args.
2064 If act is not one that calls an external command, then the given action merely
2067 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2068 gchar *actdup = g_strdup(actname);
2069 g_array_append_val(rets, actdup);
2071 if ((g_strcmp0(actname, "spawn") == 0) ||
2072 (g_strcmp0(actname, "sh") == 0) ||
2073 (g_strcmp0(actname, "sync_spawn") == 0) ||
2074 (g_strcmp0(actname, "sync_sh") == 0)) {
2076 GString *a = g_string_new("");
2077 gchar **spawnparts = split_quoted(origargs, FALSE);
2078 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2079 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2081 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2082 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2084 g_array_append_val(rets, a->str);
2085 g_string_free(a, FALSE);
2086 g_strfreev(spawnparts);
2088 gchar *origdup = g_strdup(origargs);
2089 g_array_append_val(rets, origdup);
2091 return (gchar**)g_array_free(rets, FALSE);
2095 run_handler (const gchar *act, const gchar *args) {
2096 /* Consider this code a temporary hack to make the handlers usable.
2097 In practice, all this splicing, injection, and reconstruction is
2098 inefficient, annoying and hard to manage. Potential pitfalls arise
2099 when the handler specific args 1) are not quoted (the handler
2100 callbacks should take care of this) 2) are quoted but interfere
2101 with the users' own quotation. A more ideal solution is
2102 to refactor parse_command so that it doesn't just take a string
2103 and execute it; rather than that, we should have a function which
2104 returns the argument vector parsed from the string. This vector
2105 could be modified (e.g. insert additional args into it) before
2106 passing it to the next function that actually executes it. Though
2107 it still isn't perfect for chain actions.. will reconsider & re-
2108 factor when I have the time. -duc */
2110 char **parts = g_strsplit(act, " ", 2);
2112 if (g_strcmp0(parts[0], "chain") == 0) {
2113 GString *newargs = g_string_new("");
2114 gchar **chainparts = split_quoted(parts[1], FALSE);
2116 /* for every argument in the chain, inject the handler args
2117 and make sure the new parts are wrapped in quotes */
2118 gchar **cp = chainparts;
2120 gchar *quotless = NULL;
2121 gchar **spliced_quotless = NULL; // sigh -_-;
2122 gchar **inpart = NULL;
2125 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2127 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2128 } else quotless = g_strdup(*cp);
2130 spliced_quotless = g_strsplit(quotless, " ", 2);
2131 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2132 g_strfreev(spliced_quotless);
2134 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2140 parse_command(parts[0], &(newargs->str[1]));
2141 g_string_free(newargs, TRUE);
2142 g_strfreev(chainparts);
2145 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2146 parse_command(inparts[0], inparts[1]);
2154 add_binding (const gchar *key, const gchar *act) {
2155 char **parts = g_strsplit(act, " ", 2);
2162 if (uzbl.state.verbose)
2163 printf ("Binding %-10s : %s\n", key, act);
2164 action = new_action(parts[0], parts[1]);
2166 if (g_hash_table_remove (uzbl.bindings, key))
2167 g_warning ("Overwriting existing binding for \"%s\"", key);
2168 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2173 get_xdg_var (XDG_Var xdg) {
2174 const gchar* actual_value = getenv (xdg.environmental);
2175 const gchar* home = getenv ("HOME");
2176 gchar* return_value;
2178 if (! actual_value || strcmp (actual_value, "") == 0) {
2179 if (xdg.default_value) {
2180 return_value = str_replace ("~", home, xdg.default_value);
2182 return_value = NULL;
2185 return_value = str_replace("~", home, actual_value);
2188 return return_value;
2192 find_xdg_file (int xdg_type, char* filename) {
2193 /* xdg_type = 0 => config
2194 xdg_type = 1 => data
2195 xdg_type = 2 => cache*/
2197 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2198 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2201 gchar* temporary_string;
2205 if (! file_exists (temporary_file) && xdg_type != 2) {
2206 buf = get_xdg_var (XDG[3 + xdg_type]);
2207 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2210 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2211 g_free (temporary_file);
2212 temporary_file = g_strconcat (temporary_string, filename, NULL);
2216 //g_free (temporary_string); - segfaults.
2218 if (file_exists (temporary_file)) {
2219 return temporary_file;
2226 State *s = &uzbl.state;
2227 Network *n = &uzbl.net;
2229 for (i = 0; default_config[i].command != NULL; i++) {
2230 parse_cmd_line(default_config[i].command);
2233 if (!s->config_file) {
2234 s->config_file = find_xdg_file (0, "/uzbl/config");
2237 if (s->config_file) {
2238 GArray* lines = read_file_by_line (s->config_file);
2242 while ((line = g_array_index(lines, gchar*, i))) {
2243 parse_cmd_line (line);
2247 g_array_free (lines, TRUE);
2249 if (uzbl.state.verbose)
2250 printf ("No configuration file loaded.\n");
2253 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2256 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2259 if (!uzbl.behave.cookie_handler)
2262 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2263 GString *s = g_string_new ("");
2264 SoupURI * soup_uri = soup_message_get_uri(msg);
2265 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2266 run_handler(uzbl.behave.cookie_handler, s->str);
2268 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2269 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2270 if ( p != NULL ) *p = '\0';
2271 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2273 if (uzbl.comm.sync_stdout)
2274 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2276 g_string_free(s, TRUE);
2280 save_cookies (SoupMessage *msg, gpointer user_data){
2284 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2285 cookie = soup_cookie_to_set_cookie_header(ck->data);
2286 SoupURI * soup_uri = soup_message_get_uri(msg);
2287 GString *s = g_string_new ("");
2288 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2289 run_handler(uzbl.behave.cookie_handler, s->str);
2291 g_string_free(s, TRUE);
2296 /* --- WEBINSPECTOR --- */
2298 hide_window_cb(GtkWidget *widget, gpointer data) {
2301 gtk_widget_hide(widget);
2304 static WebKitWebView*
2305 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2308 (void) web_inspector;
2309 GtkWidget* scrolled_window;
2310 GtkWidget* new_web_view;
2313 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2314 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2315 G_CALLBACK(hide_window_cb), NULL);
2317 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2318 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2319 gtk_widget_show(g->inspector_window);
2321 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2322 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2323 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2324 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2325 gtk_widget_show(scrolled_window);
2327 new_web_view = webkit_web_view_new();
2328 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2330 return WEBKIT_WEB_VIEW(new_web_view);
2334 inspector_show_window_cb (WebKitWebInspector* inspector){
2336 gtk_widget_show(uzbl.gui.inspector_window);
2340 /* TODO: Add variables and code to make use of these functions */
2342 inspector_close_window_cb (WebKitWebInspector* inspector){
2348 inspector_attach_window_cb (WebKitWebInspector* inspector){
2354 inspector_detach_window_cb (WebKitWebInspector* inspector){
2360 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2366 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2372 set_up_inspector() {
2374 WebKitWebSettings *settings = view_settings();
2375 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2377 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2378 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2379 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2380 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2381 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2382 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2383 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2385 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2389 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2391 uzbl_cmdprop *c = v;
2396 if(c->type == TYPE_STR)
2397 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2398 else if(c->type == TYPE_INT)
2399 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2403 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2407 printf("bind %s = %s %s\n", (char *)k ,
2408 (char *)a->name, a->param?(char *)a->param:"");
2413 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2414 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2419 main (int argc, char* argv[]) {
2420 gtk_init (&argc, &argv);
2421 if (!g_thread_supported ())
2422 g_thread_init (NULL);
2423 uzbl.state.executable_path = g_strdup(argv[0]);
2424 uzbl.state.selected_url = NULL;
2425 uzbl.state.searchtx = NULL;
2427 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2428 g_option_context_add_main_entries (context, entries, NULL);
2429 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2430 g_option_context_parse (context, &argc, &argv, NULL);
2431 g_option_context_free(context);
2433 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2434 gboolean verbose_override = uzbl.state.verbose;
2436 /* initialize hash table */
2437 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2439 uzbl.net.soup_session = webkit_get_default_session();
2440 uzbl.state.keycmd = g_string_new("");
2442 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2443 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2444 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2445 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2446 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2447 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2450 if(uname(&uzbl.state.unameinfo) == -1)
2451 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2453 uzbl.gui.sbar.progress_s = g_strdup("=");
2454 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2455 uzbl.gui.sbar.progress_w = 10;
2457 /* HTML mode defaults*/
2458 uzbl.behave.html_buffer = g_string_new("");
2459 uzbl.behave.html_endmarker = g_strdup(".");
2460 uzbl.behave.html_timeout = 60;
2461 uzbl.behave.base_url = g_strdup("http://invalid");
2463 /* default mode indicators */
2464 uzbl.behave.insert_indicator = g_strdup("I");
2465 uzbl.behave.cmd_indicator = g_strdup("C");
2469 make_var_to_name_hash();
2471 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2473 uzbl.gui.scrolled_win = create_browser();
2476 /* initial packing */
2477 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2478 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2480 uzbl.gui.main_window = create_window ();
2481 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2484 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2485 gtk_widget_show_all (uzbl.gui.main_window);
2486 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2488 if (uzbl.state.verbose) {
2489 printf("Uzbl start location: %s\n", argv[0]);
2490 printf("window_id %i\n",(int) uzbl.xwin);
2491 printf("pid %i\n", getpid ());
2492 printf("name: %s\n", uzbl.state.instance_name);
2495 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2496 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2497 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2498 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2499 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2503 if (!uzbl.behave.show_status)
2504 gtk_widget_hide(uzbl.gui.mainbar);
2513 if (verbose_override > uzbl.state.verbose)
2514 uzbl.state.verbose = verbose_override;
2517 set_var_value("uri", uri_override);
2518 g_free(uri_override);
2519 } else if (uzbl.state.uri)
2520 cmd_load_uri(uzbl.gui.web_view, NULL);
2525 return EXIT_SUCCESS;
2528 /* vi: set et ts=4: */