1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
39 #include <gdk/gdkkeysyms.h>
40 #include <sys/socket.h>
42 #include <sys/types.h>
44 #include <sys/utsname.h>
46 #include <webkit/webkit.h>
47 #include <libsoup/soup.h>
60 typedef void (*Command)(WebKitWebView*, GArray *argv);
64 /* commandline arguments (set initial values for the state variables) */
66 GOptionEntry entries[] =
68 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
69 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
70 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
71 "Whether to print all messages or just errors.", NULL },
72 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
73 "Name of the current instance (defaults to Xorg window id)", "NAME" },
74 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
75 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
76 { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
77 "Socket ID", "SOCKET" },
78 { NULL, 0, 0, 0, NULL, NULL, NULL }
81 /* associate command names to their properties */
82 typedef const struct {
89 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
91 /* an abbreviation to help keep the table's width humane */
92 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
97 } var_name_to_ptr[] = {
98 /* variable name pointer to variable in code type dump callback function */
99 /* --------------------------------------------------------------------------------------- */
100 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
101 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
102 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
103 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
104 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
105 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
106 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
107 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
108 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
109 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
110 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
111 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
112 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
113 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
114 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
115 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
116 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
117 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
118 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
119 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
120 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
121 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
122 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
123 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
124 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
125 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
126 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
127 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
128 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
129 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
130 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
131 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
132 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
133 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
134 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
135 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
136 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
137 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
138 /* exported WebKitWebSettings properties */
139 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
140 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
141 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
142 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
143 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
144 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
145 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
146 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
147 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
148 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
149 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
150 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
151 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
152 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
153 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
154 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
156 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
157 }, *n2v_p = var_name_to_ptr;
163 { "SHIFT", GDK_SHIFT_MASK }, // shift
164 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
165 { "CONTROL", GDK_CONTROL_MASK }, // control
166 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
167 { "MOD2", GDK_MOD2_MASK }, // 5th mod
168 { "MOD3", GDK_MOD3_MASK }, // 6th mod
169 { "MOD4", GDK_MOD4_MASK }, // 7th mod
170 { "MOD5", GDK_MOD5_MASK }, // 8th mod
171 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
172 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
173 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
174 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
175 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
176 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
177 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
178 { "META", GDK_META_MASK }, // meta (since 2.10)
183 /* construct a hash from the var_name_to_ptr array for quick access */
185 make_var_to_name_hash() {
186 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
188 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
193 /* --- UTILITY FUNCTIONS --- */
195 expand_vars(char *s) {
198 char ret[256], *vend;
199 GString *buf = g_string_new("");
204 g_string_append_c(buf, *++s);
212 if( (vend = strchr(s, upto)) ||
213 (vend = strchr(s, '\0')) ) {
214 strncpy(ret, s, vend-s);
216 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
217 if(c->type == TYPE_STR)
218 g_string_append(buf, (gchar *)*c->ptr);
219 else if(c->type == TYPE_INT) {
220 char *b = itos((int)*c->ptr);
221 g_string_append(buf, b);
225 if(upto == ' ') s = vend;
231 g_string_append_c(buf, *s);
236 return g_string_free(buf, FALSE);
243 snprintf(tmp, sizeof(tmp), "%i", val);
244 return g_strdup(tmp);
248 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
251 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
254 str_replace (const char* search, const char* replace, const char* string) {
258 buf = g_strsplit (string, search, -1);
259 ret = g_strjoinv (replace, buf);
260 g_strfreev(buf); // somebody said this segfaults
266 read_file_by_line (gchar *path) {
267 GIOChannel *chan = NULL;
268 gchar *readbuf = NULL;
270 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
273 chan = g_io_channel_new_file(path, "r", NULL);
276 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
277 const gchar* val = g_strdup (readbuf);
278 g_array_append_val (lines, val);
283 g_io_channel_unref (chan);
285 fprintf(stderr, "File '%s' not be read.\n", path);
292 gchar* parseenv (char* string) {
293 extern char** environ;
294 gchar* tmpstr = NULL;
298 while (environ[i] != NULL) {
299 gchar** env = g_strsplit (environ[i], "=", 2);
300 gchar* envname = g_strconcat ("$", env[0], NULL);
302 if (g_strrstr (string, envname) != NULL) {
303 tmpstr = g_strdup(string);
305 string = str_replace(envname, env[1], tmpstr);
310 g_strfreev (env); // somebody said this breaks uzbl
318 setup_signal(int signr, sigfunc *shandler) {
319 struct sigaction nh, oh;
321 nh.sa_handler = shandler;
322 sigemptyset(&nh.sa_mask);
325 if(sigaction(signr, &nh, &oh) < 0)
333 if (uzbl.behave.fifo_dir)
334 unlink (uzbl.comm.fifo_path);
335 if (uzbl.behave.socket_dir)
336 unlink (uzbl.comm.socket_path);
338 g_free(uzbl.state.executable_path);
339 g_string_free(uzbl.state.keycmd, TRUE);
340 g_hash_table_destroy(uzbl.bindings);
341 g_hash_table_destroy(uzbl.behave.commands);
344 /* used for html_mode_timeout
345 * be sure to extend this function to use
346 * more timers if needed in other places
349 set_timeout(int seconds) {
351 memset(&t, 0, sizeof t);
353 t.it_value.tv_sec = seconds;
354 t.it_value.tv_usec = 0;
355 setitimer(ITIMER_REAL, &t, NULL);
358 /* --- SIGNAL HANDLER --- */
361 catch_sigterm(int s) {
367 catch_sigint(int s) {
377 set_var_value("mode", "0");
382 /* --- CALLBACKS --- */
385 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
388 (void) navigation_action;
389 (void) policy_decision;
391 const gchar* uri = webkit_network_request_get_uri (request);
392 if (uzbl.state.verbose)
393 printf("New window requested -> %s \n", uri);
394 new_window_load_uri(uri);
399 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
404 /* If we can display it, let's display it... */
405 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
406 webkit_web_policy_decision_use (policy_decision);
410 /* ...everything we can't displayed is downloaded */
411 webkit_web_policy_decision_download (policy_decision);
416 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
420 if (uzbl.state.selected_url != NULL) {
421 if (uzbl.state.verbose)
422 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
423 new_window_load_uri(uzbl.state.selected_url);
425 if (uzbl.state.verbose)
426 printf("New web view -> %s\n","Nothing to open, exiting");
432 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
435 if (uzbl.behave.download_handler) {
436 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
437 if (uzbl.state.verbose)
438 printf("Download -> %s\n",uri);
439 /* if urls not escaped, we may have to escape and quote uri before this call */
440 run_handler(uzbl.behave.download_handler, uri);
445 /* scroll a bar in a given direction */
447 scroll (GtkAdjustment* bar, GArray *argv) {
451 gdouble page_size = gtk_adjustment_get_page_size(bar);
452 gdouble value = gtk_adjustment_get_value(bar);
453 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
456 value += page_size * amount * 0.01;
460 max_value = gtk_adjustment_get_upper(bar) - page_size;
462 if (value > max_value)
463 value = max_value; /* don't scroll past the end of the page */
465 gtk_adjustment_set_value (bar, value);
469 scroll_begin(WebKitWebView* page, GArray *argv) {
470 (void) page; (void) argv;
471 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
475 scroll_end(WebKitWebView* page, GArray *argv) {
476 (void) page; (void) argv;
477 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
478 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
482 scroll_vert(WebKitWebView* page, GArray *argv) {
484 scroll(uzbl.gui.bar_v, argv);
488 scroll_horz(WebKitWebView* page, GArray *argv) {
490 scroll(uzbl.gui.bar_h, argv);
495 if (!uzbl.behave.show_status) {
496 gtk_widget_hide(uzbl.gui.mainbar);
498 gtk_widget_show(uzbl.gui.mainbar);
504 toggle_zoom_type (WebKitWebView* page, GArray *argv) {
508 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
512 toggle_status_cb (WebKitWebView* page, GArray *argv) {
516 if (uzbl.behave.show_status) {
517 gtk_widget_hide(uzbl.gui.mainbar);
519 gtk_widget_show(uzbl.gui.mainbar);
521 uzbl.behave.show_status = !uzbl.behave.show_status;
526 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
530 //Set selected_url state variable
531 g_free(uzbl.state.selected_url);
532 uzbl.state.selected_url = NULL;
534 uzbl.state.selected_url = g_strdup(link);
540 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
544 if (uzbl.gui.main_title)
545 g_free (uzbl.gui.main_title);
546 uzbl.gui.main_title = g_strdup (title);
551 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
554 uzbl.gui.sbar.load_progress = progress;
559 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
563 if (uzbl.behave.load_finish_handler)
564 run_handler(uzbl.behave.load_finish_handler, "");
568 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
572 uzbl.gui.sbar.load_progress = 0;
573 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
574 if (uzbl.behave.load_start_handler)
575 run_handler(uzbl.behave.load_start_handler, "");
579 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
582 g_free (uzbl.state.uri);
583 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
584 uzbl.state.uri = g_string_free (newuri, FALSE);
585 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
586 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
589 if (uzbl.behave.load_commit_handler)
590 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
594 destroy_cb (GtkWidget* widget, gpointer data) {
602 if (uzbl.behave.history_handler) {
604 struct tm * timeinfo;
607 timeinfo = localtime ( &rawtime );
608 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
609 run_handler(uzbl.behave.history_handler, date);
614 /* VIEW funcs (little webkit wrappers) */
615 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
617 VIEWFUNC(reload_bypass_cache)
618 VIEWFUNC(stop_loading)
625 /* -- command to callback/function map for things we cannot attach to any signals */
626 static struct {char *name; Command command[2];} cmdlist[] =
627 { /* key function no_split */
628 { "back", {view_go_back, 0} },
629 { "forward", {view_go_forward, 0} },
630 { "scroll_vert", {scroll_vert, 0} },
631 { "scroll_horz", {scroll_horz, 0} },
632 { "scroll_begin", {scroll_begin, 0} },
633 { "scroll_end", {scroll_end, 0} },
634 { "reload", {view_reload, 0}, },
635 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
636 { "stop", {view_stop_loading, 0}, },
637 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
638 { "zoom_out", {view_zoom_out, 0}, },
639 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
640 { "uri", {load_uri, NOSPLIT} },
641 { "js", {run_js, NOSPLIT} },
642 { "script", {run_external_js, 0} },
643 { "toggle_status", {toggle_status_cb, 0} },
644 { "spawn", {spawn, 0} },
645 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
646 { "sh", {spawn_sh, 0} },
647 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
648 { "exit", {close_uzbl, 0} },
649 { "search", {search_forward_text, NOSPLIT} },
650 { "search_reverse", {search_reverse_text, NOSPLIT} },
651 { "dehilight", {dehilight, 0} },
652 { "toggle_insert_mode", {toggle_insert_mode, 0} },
653 { "set", {set_var, NOSPLIT} },
654 //{ "get", {get_var, NOSPLIT} },
655 { "bind", {act_bind, NOSPLIT} },
656 { "dump_config", {act_dump_config, 0} },
657 { "keycmd", {keycmd, NOSPLIT} },
658 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
659 { "keycmd_bs", {keycmd_bs, 0} },
660 { "chain", {chain, 0} },
661 { "print", {print, NOSPLIT} }
668 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
670 for (i = 0; i < LENGTH(cmdlist); i++)
671 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
674 /* -- CORE FUNCTIONS -- */
677 free_action(gpointer act) {
678 Action *action = (Action*)act;
679 g_free(action->name);
681 g_free(action->param);
686 new_action(const gchar *name, const gchar *param) {
687 Action *action = g_new(Action, 1);
689 action->name = g_strdup(name);
691 action->param = g_strdup(param);
693 action->param = NULL;
699 file_exists (const char * filename) {
700 return (access(filename, F_OK) == 0);
704 set_var(WebKitWebView *page, GArray *argv) {
706 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
707 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
708 set_var_value(g_strstrip(split[0]), value);
714 print(WebKitWebView *page, GArray *argv) {
718 buf = expand_vars(argv_idx(argv, 0));
724 act_bind(WebKitWebView *page, GArray *argv) {
726 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
727 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
728 add_binding(g_strstrip(split[0]), value);
740 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
743 if (argv_idx(argv, 0)) {
744 if (strcmp (argv_idx(argv, 0), "0") == 0) {
745 uzbl.behave.insert_mode = FALSE;
747 uzbl.behave.insert_mode = TRUE;
750 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
757 load_uri (WebKitWebView *web_view, GArray *argv) {
758 if (argv_idx(argv, 0)) {
759 GString* newuri = g_string_new (argv_idx(argv, 0));
760 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
761 run_js(web_view, argv);
764 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
765 g_string_prepend (newuri, "http://");
766 /* if we do handle cookies, ask our handler for them */
767 webkit_web_view_load_uri (web_view, newuri->str);
768 g_string_free (newuri, TRUE);
773 run_js (WebKitWebView * web_view, GArray *argv) {
774 if (argv_idx(argv, 0))
775 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
779 run_external_js (WebKitWebView * web_view, GArray *argv) {
780 if (argv_idx(argv, 0)) {
781 GArray* lines = read_file_by_line (argv_idx (argv, 0));
786 while ((line = g_array_index(lines, gchar*, i))) {
788 js = g_strdup (line);
790 gchar* newjs = g_strconcat (js, line, NULL);
797 if (uzbl.state.verbose)
798 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
800 if (argv_idx (argv, 1)) {
801 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
805 webkit_web_view_execute_script (web_view, js);
807 g_array_free (lines, TRUE);
812 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
813 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
814 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
815 webkit_web_view_unmark_text_matches (page);
816 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
817 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
821 if (uzbl.state.searchtx) {
822 if (uzbl.state.verbose)
823 printf ("Searching: %s\n", uzbl.state.searchtx);
824 webkit_web_view_set_highlight_text_matches (page, TRUE);
825 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
830 search_forward_text (WebKitWebView *page, GArray *argv) {
831 search_text(page, argv, TRUE);
835 search_reverse_text (WebKitWebView *page, GArray *argv) {
836 search_text(page, argv, FALSE);
840 dehilight (WebKitWebView *page, GArray *argv) {
842 webkit_web_view_set_highlight_text_matches (page, FALSE);
847 new_window_load_uri (const gchar * uri) {
848 GString* to_execute = g_string_new ("");
849 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
851 for (i = 0; entries[i].long_name != NULL; i++) {
852 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
853 gchar** str = (gchar**)entries[i].arg_data;
855 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
859 if (uzbl.state.verbose)
860 printf("\n%s\n", to_execute->str);
861 g_spawn_command_line_async (to_execute->str, NULL);
862 g_string_free (to_execute, TRUE);
866 chain (WebKitWebView *page, GArray *argv) {
869 gchar **parts = NULL;
871 while ((a = argv_idx(argv, i++))) {
872 parts = g_strsplit (a, " ", 2);
873 parse_command(parts[0], parts[1]);
879 keycmd (WebKitWebView *page, GArray *argv) {
882 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
888 keycmd_nl (WebKitWebView *page, GArray *argv) {
891 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
897 keycmd_bs (WebKitWebView *page, GArray *argv) {
901 prev = g_utf8_find_prev_char(uzbl.state.keycmd->str, uzbl.state.keycmd->str + uzbl.state.keycmd->len);
903 g_string_truncate(uzbl.state.keycmd, prev - uzbl.state.keycmd->str);
908 close_uzbl (WebKitWebView *page, GArray *argv) {
914 /* --Statusbar functions-- */
916 build_progressbar_ascii(int percent) {
917 int width=uzbl.gui.sbar.progress_w;
920 GString *bar = g_string_new("");
922 l = (double)percent*((double)width/100.);
923 l = (int)(l+.5)>=(int)l ? l+.5 : l;
925 for(i=0; i<(int)l; i++)
926 g_string_append(bar, uzbl.gui.sbar.progress_s);
929 g_string_append(bar, uzbl.gui.sbar.progress_u);
931 return g_string_free(bar, FALSE);
936 const GScannerConfig scan_config = {
939 ) /* cset_skip_characters */,
944 ) /* cset_identifier_first */,
951 ) /* cset_identifier_nth */,
952 ( "" ) /* cpair_comment_single */,
954 TRUE /* case_sensitive */,
956 FALSE /* skip_comment_multi */,
957 FALSE /* skip_comment_single */,
958 FALSE /* scan_comment_multi */,
959 TRUE /* scan_identifier */,
960 TRUE /* scan_identifier_1char */,
961 FALSE /* scan_identifier_NULL */,
962 TRUE /* scan_symbols */,
963 FALSE /* scan_binary */,
964 FALSE /* scan_octal */,
965 FALSE /* scan_float */,
966 FALSE /* scan_hex */,
967 FALSE /* scan_hex_dollar */,
968 FALSE /* scan_string_sq */,
969 FALSE /* scan_string_dq */,
970 TRUE /* numbers_2_int */,
971 FALSE /* int_2_float */,
972 FALSE /* identifier_2_string */,
973 FALSE /* char_2_token */,
974 FALSE /* symbol_2_token */,
975 TRUE /* scope_0_fallback */,
980 uzbl.scan = g_scanner_new(&scan_config);
981 while(symp->symbol_name) {
982 g_scanner_scope_add_symbol(uzbl.scan, 0,
984 GINT_TO_POINTER(symp->symbol_token));
990 expand_template(const char *template, gboolean escape_markup) {
991 if(!template) return NULL;
993 GTokenType token = G_TOKEN_NONE;
994 GString *ret = g_string_new("");
998 g_scanner_input_text(uzbl.scan, template, strlen(template));
999 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
1000 token = g_scanner_get_next_token(uzbl.scan);
1002 if(token == G_TOKEN_SYMBOL) {
1003 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
1007 buf = uzbl.state.uri?
1008 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
1009 g_string_append(ret, buf);
1013 g_string_append(ret, uzbl.state.uri?
1014 uzbl.state.uri:g_strdup(""));
1017 buf = itos(uzbl.gui.sbar.load_progress);
1018 g_string_append(ret, buf);
1021 case SYM_LOADPRGSBAR:
1022 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1023 g_string_append(ret, buf);
1028 buf = uzbl.gui.main_title?
1029 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1030 g_string_append(ret, buf);
1034 g_string_append(ret, uzbl.gui.main_title?
1035 uzbl.gui.main_title:g_strdup(""));
1037 case SYM_SELECTED_URI:
1039 buf = uzbl.state.selected_url?
1040 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1041 g_string_append(ret, buf);
1045 g_string_append(ret, uzbl.state.selected_url?
1046 uzbl.state.selected_url:g_strdup(""));
1049 buf = itos(uzbl.xwin);
1050 g_string_append(ret,
1051 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1056 buf = uzbl.state.keycmd->str?
1057 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1058 g_string_append(ret, buf);
1062 g_string_append(ret, uzbl.state.keycmd->str?
1063 uzbl.state.keycmd->str:g_strdup(""));
1066 g_string_append(ret,
1067 uzbl.behave.insert_mode?
1068 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1071 g_string_append(ret,
1072 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1074 /* useragent syms */
1076 buf = itos(WEBKIT_MAJOR_VERSION);
1077 g_string_append(ret, buf);
1081 buf = itos(WEBKIT_MINOR_VERSION);
1082 g_string_append(ret, buf);
1086 buf = itos(WEBKIT_MICRO_VERSION);
1087 g_string_append(ret, buf);
1091 g_string_append(ret, uzbl.state.unameinfo.sysname);
1094 g_string_append(ret, uzbl.state.unameinfo.nodename);
1097 g_string_append(ret, uzbl.state.unameinfo.release);
1100 g_string_append(ret, uzbl.state.unameinfo.version);
1103 g_string_append(ret, uzbl.state.unameinfo.machine);
1106 g_string_append(ret, ARCH);
1109 case SYM_DOMAINNAME:
1110 g_string_append(ret, uzbl.state.unameinfo.domainname);
1114 g_string_append(ret, COMMIT);
1120 else if(token == G_TOKEN_INT) {
1121 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1122 g_string_append(ret, buf);
1125 else if(token == G_TOKEN_IDENTIFIER) {
1126 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1128 else if(token == G_TOKEN_CHAR) {
1129 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1133 return g_string_free(ret, FALSE);
1135 /* --End Statusbar functions-- */
1138 sharg_append(GArray *a, const gchar *str) {
1139 const gchar *s = (str ? str : "");
1140 g_array_append_val(a, s);
1143 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1145 run_command (const gchar *command, const guint npre, const gchar **args,
1146 const gboolean sync, char **output_stdout) {
1147 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1150 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1151 gchar *pid = itos(getpid());
1152 gchar *xwin = itos(uzbl.xwin);
1154 sharg_append(a, command);
1155 for (i = 0; i < npre; i++) /* add n args before the default vars */
1156 sharg_append(a, args[i]);
1157 sharg_append(a, uzbl.state.config_file);
1158 sharg_append(a, pid);
1159 sharg_append(a, xwin);
1160 sharg_append(a, uzbl.comm.fifo_path);
1161 sharg_append(a, uzbl.comm.socket_path);
1162 sharg_append(a, uzbl.state.uri);
1163 sharg_append(a, uzbl.gui.main_title);
1165 for (i = npre; i < g_strv_length((gchar**)args); i++)
1166 sharg_append(a, args[i]);
1170 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1172 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1173 NULL, NULL, output_stdout, NULL, NULL, &err);
1174 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1175 NULL, NULL, NULL, &err);
1177 if (uzbl.state.verbose) {
1178 GString *s = g_string_new("spawned:");
1179 for (i = 0; i < (a->len); i++) {
1180 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1181 g_string_append_printf(s, " %s", qarg);
1184 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1185 printf("%s\n", s->str);
1186 g_string_free(s, TRUE);
1188 printf("Stdout: %s\n", *output_stdout);
1192 g_printerr("error on run_command: %s\n", err->message);
1197 g_array_free (a, TRUE);
1202 split_quoted(const gchar* src, const gboolean unquote) {
1203 /* split on unquoted space, return array of strings;
1204 remove a layer of quotes and backslashes if unquote */
1205 if (!src) return NULL;
1207 gboolean dq = FALSE;
1208 gboolean sq = FALSE;
1209 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1210 GString *s = g_string_new ("");
1214 for (p = src; *p != '\0'; p++) {
1215 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1216 else if (*p == '\\') { g_string_append_c(s, *p++);
1217 g_string_append_c(s, *p); }
1218 else if ((*p == '"') && unquote && !sq) dq = !dq;
1219 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1221 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1222 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1224 else if ((*p == ' ') && !dq && !sq) {
1225 dup = g_strdup(s->str);
1226 g_array_append_val(a, dup);
1227 g_string_truncate(s, 0);
1228 } else g_string_append_c(s, *p);
1230 dup = g_strdup(s->str);
1231 g_array_append_val(a, dup);
1232 ret = (gchar**)a->data;
1233 g_array_free (a, FALSE);
1234 g_string_free (s, TRUE);
1239 spawn(WebKitWebView *web_view, GArray *argv) {
1241 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1242 if (argv_idx(argv, 0))
1243 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1247 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1250 if (argv_idx(argv, 0))
1251 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1252 TRUE, &uzbl.comm.sync_stdout);
1256 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1258 if (!uzbl.behave.shell_cmd) {
1259 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1264 gchar *spacer = g_strdup("");
1265 g_array_insert_val(argv, 1, spacer);
1266 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1268 for (i = 1; i < g_strv_length(cmd); i++)
1269 g_array_prepend_val(argv, cmd[i]);
1271 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1277 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1279 if (!uzbl.behave.shell_cmd) {
1280 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1285 gchar *spacer = g_strdup("");
1286 g_array_insert_val(argv, 1, spacer);
1287 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1289 for (i = 1; i < g_strv_length(cmd); i++)
1290 g_array_prepend_val(argv, cmd[i]);
1292 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1293 TRUE, &uzbl.comm.sync_stdout);
1299 parse_command(const char *cmd, const char *param) {
1302 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1305 gchar **par = split_quoted(param, TRUE);
1306 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1308 if (c[1] == NOSPLIT) { /* don't split */
1309 sharg_append(a, param);
1311 for (i = 0; i < g_strv_length(par); i++)
1312 sharg_append(a, par[i]);
1314 c[0](uzbl.gui.web_view, a);
1316 g_array_free (a, TRUE);
1319 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1326 if(*uzbl.net.proxy_url == ' '
1327 || uzbl.net.proxy_url == NULL) {
1328 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1329 (GType) SOUP_SESSION_PROXY_URI);
1332 suri = soup_uri_new(uzbl.net.proxy_url);
1333 g_object_set(G_OBJECT(uzbl.net.soup_session),
1334 SOUP_SESSION_PROXY_URI,
1336 soup_uri_free(suri);
1343 if(file_exists(uzbl.gui.icon)) {
1344 if (uzbl.gui.main_window)
1345 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1347 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1349 g_free (uzbl.gui.icon);
1354 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1355 g_array_append_val (a, uzbl.state.uri);
1356 load_uri(uzbl.gui.web_view, a);
1357 g_array_free (a, TRUE);
1361 cmd_always_insert_mode() {
1362 uzbl.behave.insert_mode =
1363 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1369 g_object_set(G_OBJECT(uzbl.net.soup_session),
1370 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1374 cmd_max_conns_host() {
1375 g_object_set(G_OBJECT(uzbl.net.soup_session),
1376 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1381 soup_session_remove_feature
1382 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1383 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1384 /*g_free(uzbl.net.soup_logger);*/
1386 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1387 soup_session_add_feature(uzbl.net.soup_session,
1388 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1391 static WebKitWebSettings*
1393 return webkit_web_view_get_settings(uzbl.gui.web_view);
1398 WebKitWebSettings *ws = view_settings();
1399 if (uzbl.behave.font_size > 0) {
1400 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1403 if (uzbl.behave.monospace_size > 0) {
1404 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1405 uzbl.behave.monospace_size, NULL);
1407 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1408 uzbl.behave.font_size, NULL);
1414 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1418 cmd_disable_plugins() {
1419 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1420 !uzbl.behave.disable_plugins, NULL);
1424 cmd_disable_scripts() {
1425 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1426 !uzbl.behave.disable_scripts, NULL);
1430 cmd_minimum_font_size() {
1431 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1432 uzbl.behave.minimum_font_size, NULL);
1435 cmd_autoload_img() {
1436 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1437 uzbl.behave.autoload_img, NULL);
1442 cmd_autoshrink_img() {
1443 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1444 uzbl.behave.autoshrink_img, NULL);
1449 cmd_enable_spellcheck() {
1450 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1451 uzbl.behave.enable_spellcheck, NULL);
1455 cmd_enable_private() {
1456 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1457 uzbl.behave.enable_private, NULL);
1462 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1463 uzbl.behave.print_bg, NULL);
1468 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1469 uzbl.behave.style_uri, NULL);
1473 cmd_resizable_txt() {
1474 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1475 uzbl.behave.resizable_txt, NULL);
1479 cmd_default_encoding() {
1480 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1481 uzbl.behave.default_encoding, NULL);
1485 cmd_enforce_96dpi() {
1486 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1487 uzbl.behave.enforce_96dpi, NULL);
1491 cmd_caret_browsing() {
1492 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1493 uzbl.behave.caret_browsing, NULL);
1497 cmd_cookie_handler() {
1498 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1499 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1500 if ((g_strcmp0(split[0], "sh") == 0) ||
1501 (g_strcmp0(split[0], "spawn") == 0)) {
1502 g_free (uzbl.behave.cookie_handler);
1503 uzbl.behave.cookie_handler =
1504 g_strdup_printf("sync_%s %s", split[0], split[1]);
1511 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1516 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1521 if(uzbl.behave.inject_html) {
1522 webkit_web_view_load_html_string (uzbl.gui.web_view,
1523 uzbl.behave.inject_html, NULL);
1532 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1533 uzbl.behave.modmask = 0;
1535 if(uzbl.behave.modkey)
1536 g_free(uzbl.behave.modkey);
1537 uzbl.behave.modkey = buf;
1539 for (i = 0; modkeys[i].key != NULL; i++) {
1540 if (g_strrstr(buf, modkeys[i].key))
1541 uzbl.behave.modmask |= modkeys[i].mask;
1547 if (*uzbl.net.useragent == ' ') {
1548 g_free (uzbl.net.useragent);
1549 uzbl.net.useragent = NULL;
1551 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1553 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1554 g_free(uzbl.net.useragent);
1555 uzbl.net.useragent = ua;
1561 gtk_widget_ref(uzbl.gui.scrolled_win);
1562 gtk_widget_ref(uzbl.gui.mainbar);
1563 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1564 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1566 if(uzbl.behave.status_top) {
1567 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1568 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1571 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1572 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1574 gtk_widget_unref(uzbl.gui.scrolled_win);
1575 gtk_widget_unref(uzbl.gui.mainbar);
1576 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1581 set_var_value(gchar *name, gchar *val) {
1582 uzbl_cmdprop *c = NULL;
1586 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1587 /* check for the variable type */
1588 if (c->type == TYPE_STR) {
1589 buf = expand_vars(val);
1592 } else if(c->type == TYPE_INT) {
1593 int *ip = (int *)c->ptr;
1594 buf = expand_vars(val);
1595 *ip = (int)strtoul(buf, &endp, 10);
1597 } else if (c->type == TYPE_FLOAT) {
1598 float *fp = (float *)c->ptr;
1599 buf = expand_vars(val);
1600 *fp = strtod(buf, &endp);
1604 /* invoke a command specific function */
1605 if(c->func) c->func();
1612 Behaviour *b = &uzbl.behave;
1614 if(b->html_buffer->str) {
1615 webkit_web_view_load_html_string (uzbl.gui.web_view,
1616 b->html_buffer->str, b->base_url);
1617 g_string_free(b->html_buffer, TRUE);
1618 b->html_buffer = g_string_new("");
1622 enum {M_CMD, M_HTML};
1624 parse_cmd_line(const char *ctl_line) {
1625 Behaviour *b = &uzbl.behave;
1628 if(b->mode == M_HTML) {
1629 len = strlen(b->html_endmarker);
1630 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1631 if(len == strlen(ctl_line)-1 &&
1632 !strncmp(b->html_endmarker, ctl_line, len)) {
1634 set_var_value("mode", "0");
1639 set_timeout(b->html_timeout);
1640 g_string_append(b->html_buffer, ctl_line);
1643 else if((ctl_line[0] == '#') /* Comments */
1644 || (ctl_line[0] == ' ')
1645 || (ctl_line[0] == '\n'))
1646 ; /* ignore these lines */
1647 else { /* parse a command */
1649 gchar **tokens = NULL;
1650 len = strlen(ctl_line);
1652 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1653 ctlstrip = g_strndup(ctl_line, len - 1);
1654 else ctlstrip = g_strdup(ctl_line);
1656 tokens = g_strsplit(ctlstrip, " ", 2);
1657 parse_command(tokens[0], tokens[1]);
1664 build_stream_name(int type, const gchar* dir) {
1665 char *xwin_str = NULL;
1666 State *s = &uzbl.state;
1669 xwin_str = itos((int)uzbl.xwin);
1671 str = g_strdup_printf
1672 ("%s/uzbl_fifo_%s", dir,
1673 s->instance_name ? s->instance_name : xwin_str);
1674 } else if (type == SOCKET) {
1675 str = g_strdup_printf
1676 ("%s/uzbl_socket_%s", dir,
1677 s->instance_name ? s->instance_name : xwin_str );
1684 control_fifo(GIOChannel *gio, GIOCondition condition) {
1685 if (uzbl.state.verbose)
1686 printf("triggered\n");
1691 if (condition & G_IO_HUP)
1692 g_error ("Fifo: Read end of pipe died!\n");
1695 g_error ("Fifo: GIOChannel broke\n");
1697 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1698 if (ret == G_IO_STATUS_ERROR) {
1699 g_error ("Fifo: Error reading: %s\n", err->message);
1703 parse_cmd_line(ctl_line);
1710 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1711 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1712 if (unlink(uzbl.comm.fifo_path) == -1)
1713 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1714 g_free(uzbl.comm.fifo_path);
1715 uzbl.comm.fifo_path = NULL;
1718 if (*dir == ' ') { /* space unsets the variable */
1723 GIOChannel *chan = NULL;
1724 GError *error = NULL;
1725 gchar *path = build_stream_name(FIFO, dir);
1727 if (!file_exists(path)) {
1728 if (mkfifo (path, 0666) == 0) {
1729 // 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.
1730 chan = g_io_channel_new_file(path, "r+", &error);
1732 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1733 if (uzbl.state.verbose)
1734 printf ("init_fifo: created successfully as %s\n", path);
1735 uzbl.comm.fifo_path = path;
1737 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1738 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1739 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1740 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1742 /* if we got this far, there was an error; cleanup */
1743 if (error) g_error_free (error);
1750 control_stdin(GIOChannel *gio, GIOCondition condition) {
1752 gchar *ctl_line = NULL;
1755 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1756 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1759 parse_cmd_line(ctl_line);
1767 GIOChannel *chan = NULL;
1768 GError *error = NULL;
1770 chan = g_io_channel_unix_new(fileno(stdin));
1772 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1773 g_error ("Stdin: could not add watch\n");
1775 if (uzbl.state.verbose)
1776 printf ("Stdin: watch added successfully\n");
1779 g_error ("Stdin: Error while opening: %s\n", error->message);
1781 if (error) g_error_free (error);
1785 control_socket(GIOChannel *chan) {
1786 struct sockaddr_un remote;
1787 char buffer[512], *ctl_line;
1789 int sock, clientsock, n, done;
1792 sock = g_io_channel_unix_get_fd(chan);
1794 memset (buffer, 0, sizeof (buffer));
1796 t = sizeof (remote);
1797 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1801 memset (temp, 0, sizeof (temp));
1802 n = recv (clientsock, temp, 128, 0);
1804 buffer[strlen (buffer)] = '\0';
1808 strcat (buffer, temp);
1811 if (strcmp (buffer, "\n") < 0) {
1812 buffer[strlen (buffer) - 1] = '\0';
1814 buffer[strlen (buffer)] = '\0';
1817 ctl_line = g_strdup(buffer);
1818 parse_cmd_line (ctl_line);
1821 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1822 GError *error = NULL;
1825 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1826 if (ret == G_IO_STATUS_ERROR)
1827 g_error ("Error reading: %s\n", error->message);
1829 printf("Got line %s (%u bytes) \n",ctl_line, len);
1831 parse_line(ctl_line);
1839 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1840 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1841 if (unlink(uzbl.comm.socket_path) == -1)
1842 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1843 g_free(uzbl.comm.socket_path);
1844 uzbl.comm.socket_path = NULL;
1852 GIOChannel *chan = NULL;
1854 struct sockaddr_un local;
1855 gchar *path = build_stream_name(SOCKET, dir);
1857 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1859 local.sun_family = AF_UNIX;
1860 strcpy (local.sun_path, path);
1861 unlink (local.sun_path);
1863 len = strlen (local.sun_path) + sizeof (local.sun_family);
1864 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1865 if (uzbl.state.verbose)
1866 printf ("init_socket: opened in %s\n", path);
1869 if( (chan = g_io_channel_unix_new(sock)) ) {
1870 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1871 uzbl.comm.socket_path = path;
1874 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1876 /* if we got this far, there was an error; cleanup */
1883 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1884 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1886 // this function may be called very early when the templates are not set (yet), hence the checks
1888 update_title (void) {
1889 Behaviour *b = &uzbl.behave;
1892 if (b->show_status) {
1893 if (b->title_format_short) {
1894 parsed = expand_template(b->title_format_short, FALSE);
1895 if (uzbl.gui.main_window)
1896 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1899 if (b->status_format) {
1900 parsed = expand_template(b->status_format, TRUE);
1901 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1904 if (b->status_background) {
1906 gdk_color_parse (b->status_background, &color);
1907 //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)
1908 if (uzbl.gui.main_window)
1909 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1912 if (b->title_format_long) {
1913 parsed = expand_template(b->title_format_long, FALSE);
1914 if (uzbl.gui.main_window)
1915 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1922 key_press_cb (GtkWidget* window, GdkEventKey* event)
1924 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1928 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1929 || 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)
1932 /* turn off insert mode (if always_insert_mode is not used) */
1933 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1934 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1939 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1942 if (event->keyval == GDK_Escape) {
1943 g_string_truncate(uzbl.state.keycmd, 0);
1945 dehilight(uzbl.gui.web_view, NULL);
1949 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1950 if (event->keyval == GDK_Insert) {
1952 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1953 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1955 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1958 g_string_append (uzbl.state.keycmd, str);
1965 if (event->keyval == GDK_BackSpace)
1966 keycmd_bs(NULL, NULL);
1968 gboolean key_ret = FALSE;
1969 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1971 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1973 run_keycmd(key_ret);
1975 if (key_ret) return (!uzbl.behave.insert_mode);
1980 run_keycmd(const gboolean key_ret) {
1981 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1983 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1984 g_string_truncate(uzbl.state.keycmd, 0);
1985 parse_command(act->name, act->param);
1989 /* try if it's an incremental keycmd or one that takes args, and run it */
1990 GString* short_keys = g_string_new ("");
1991 GString* short_keys_inc = g_string_new ("");
1993 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1994 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1995 g_string_assign(short_keys_inc, short_keys->str);
1996 g_string_append_c(short_keys, '_');
1997 g_string_append_c(short_keys_inc, '*');
1999 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2000 /* run normal cmds only if return was pressed */
2001 exec_paramcmd(act, i);
2002 g_string_truncate(uzbl.state.keycmd, 0);
2004 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2005 if (key_ret) /* just quit the incremental command on return */
2006 g_string_truncate(uzbl.state.keycmd, 0);
2007 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2011 g_string_truncate(short_keys, short_keys->len - 1);
2013 g_string_free (short_keys, TRUE);
2014 g_string_free (short_keys_inc, TRUE);
2018 exec_paramcmd(const Action *act, const guint i) {
2019 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2020 GString *actionname = g_string_new ("");
2021 GString *actionparam = g_string_new ("");
2022 g_string_erase (parampart, 0, i+1);
2024 g_string_printf (actionname, act->name, parampart->str);
2026 g_string_printf (actionparam, act->param, parampart->str);
2027 parse_command(actionname->str, actionparam->str);
2028 g_string_free(actionname, TRUE);
2029 g_string_free(actionparam, TRUE);
2030 g_string_free(parampart, TRUE);
2038 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2039 //main_window_ref = g_object_ref(scrolled_window);
2040 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
2042 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2043 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2045 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2046 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2047 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2048 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2049 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2050 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2051 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2052 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2053 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2054 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2055 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2057 return scrolled_window;
2064 g->mainbar = gtk_hbox_new (FALSE, 0);
2066 /* keep a reference to the bar so we can re-pack it at runtime*/
2067 //sbar_ref = g_object_ref(g->mainbar);
2069 g->mainbar_label = gtk_label_new ("");
2070 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2071 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2072 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2073 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2074 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2075 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2080 GtkWidget* create_window () {
2081 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2082 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2083 gtk_widget_set_name (window, "Uzbl browser");
2084 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2085 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2091 GtkPlug* create_plug () {
2092 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2093 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2094 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2101 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2103 If actname is one that calls an external command, this function will inject
2104 newargs in front of the user-provided args in that command line. They will
2105 come become after the body of the script (in sh) or after the name of
2106 the command to execute (in spawn).
2107 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2108 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2110 The return value consist of two strings: the action (sh, ...) and its args.
2112 If act is not one that calls an external command, then the given action merely
2115 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2116 gchar *actdup = g_strdup(actname);
2117 g_array_append_val(rets, actdup);
2119 if ((g_strcmp0(actname, "spawn") == 0) ||
2120 (g_strcmp0(actname, "sh") == 0) ||
2121 (g_strcmp0(actname, "sync_spawn") == 0) ||
2122 (g_strcmp0(actname, "sync_sh") == 0)) {
2124 GString *a = g_string_new("");
2125 gchar **spawnparts = split_quoted(origargs, FALSE);
2126 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2127 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2129 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2130 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2132 g_array_append_val(rets, a->str);
2133 g_string_free(a, FALSE);
2134 g_strfreev(spawnparts);
2136 gchar *origdup = g_strdup(origargs);
2137 g_array_append_val(rets, origdup);
2139 return (gchar**)g_array_free(rets, FALSE);
2143 run_handler (const gchar *act, const gchar *args) {
2144 /* Consider this code a temporary hack to make the handlers usable.
2145 In practice, all this splicing, injection, and reconstruction is
2146 inefficient, annoying and hard to manage. Potential pitfalls arise
2147 when the handler specific args 1) are not quoted (the handler
2148 callbacks should take care of this) 2) are quoted but interfere
2149 with the users' own quotation. A more ideal solution is
2150 to refactor parse_command so that it doesn't just take a string
2151 and execute it; rather than that, we should have a function which
2152 returns the argument vector parsed from the string. This vector
2153 could be modified (e.g. insert additional args into it) before
2154 passing it to the next function that actually executes it. Though
2155 it still isn't perfect for chain actions.. will reconsider & re-
2156 factor when I have the time. -duc */
2158 char **parts = g_strsplit(act, " ", 2);
2160 if (g_strcmp0(parts[0], "chain") == 0) {
2161 GString *newargs = g_string_new("");
2162 gchar **chainparts = split_quoted(parts[1], FALSE);
2164 /* for every argument in the chain, inject the handler args
2165 and make sure the new parts are wrapped in quotes */
2166 gchar **cp = chainparts;
2168 gchar *quotless = NULL;
2169 gchar **spliced_quotless = NULL; // sigh -_-;
2170 gchar **inpart = NULL;
2173 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2175 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2176 } else quotless = g_strdup(*cp);
2178 spliced_quotless = g_strsplit(quotless, " ", 2);
2179 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2180 g_strfreev(spliced_quotless);
2182 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2188 parse_command(parts[0], &(newargs->str[1]));
2189 g_string_free(newargs, TRUE);
2190 g_strfreev(chainparts);
2193 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2194 parse_command(inparts[0], inparts[1]);
2202 add_binding (const gchar *key, const gchar *act) {
2203 char **parts = g_strsplit(act, " ", 2);
2210 if (uzbl.state.verbose)
2211 printf ("Binding %-10s : %s\n", key, act);
2212 action = new_action(parts[0], parts[1]);
2214 if (g_hash_table_remove (uzbl.bindings, key))
2215 g_warning ("Overwriting existing binding for \"%s\"", key);
2216 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2221 get_xdg_var (XDG_Var xdg) {
2222 const gchar* actual_value = getenv (xdg.environmental);
2223 const gchar* home = getenv ("HOME");
2224 gchar* return_value;
2226 if (! actual_value || strcmp (actual_value, "") == 0) {
2227 if (xdg.default_value) {
2228 return_value = str_replace ("~", home, xdg.default_value);
2230 return_value = NULL;
2233 return_value = str_replace("~", home, actual_value);
2236 return return_value;
2240 find_xdg_file (int xdg_type, char* filename) {
2241 /* xdg_type = 0 => config
2242 xdg_type = 1 => data
2243 xdg_type = 2 => cache*/
2245 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2246 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2249 gchar* temporary_string;
2253 if (! file_exists (temporary_file) && xdg_type != 2) {
2254 buf = get_xdg_var (XDG[3 + xdg_type]);
2255 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2258 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2259 g_free (temporary_file);
2260 temporary_file = g_strconcat (temporary_string, filename, NULL);
2264 //g_free (temporary_string); - segfaults.
2266 if (file_exists (temporary_file)) {
2267 return temporary_file;
2274 State *s = &uzbl.state;
2275 Network *n = &uzbl.net;
2277 for (i = 0; default_config[i].command != NULL; i++) {
2278 parse_cmd_line(default_config[i].command);
2281 if (!s->config_file) {
2282 s->config_file = find_xdg_file (0, "/uzbl/config");
2285 if (s->config_file) {
2286 GArray* lines = read_file_by_line (s->config_file);
2290 while ((line = g_array_index(lines, gchar*, i))) {
2291 parse_cmd_line (line);
2295 g_array_free (lines, TRUE);
2297 if (uzbl.state.verbose)
2298 printf ("No configuration file loaded.\n");
2301 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2304 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2307 if (!uzbl.behave.cookie_handler)
2310 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2311 GString *s = g_string_new ("");
2312 SoupURI * soup_uri = soup_message_get_uri(msg);
2313 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2314 run_handler(uzbl.behave.cookie_handler, s->str);
2316 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2317 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2318 if ( p != NULL ) *p = '\0';
2319 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2321 if (uzbl.comm.sync_stdout)
2322 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2324 g_string_free(s, TRUE);
2328 save_cookies (SoupMessage *msg, gpointer user_data){
2332 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2333 cookie = soup_cookie_to_set_cookie_header(ck->data);
2334 SoupURI * soup_uri = soup_message_get_uri(msg);
2335 GString *s = g_string_new ("");
2336 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2337 run_handler(uzbl.behave.cookie_handler, s->str);
2339 g_string_free(s, TRUE);
2344 /* --- WEBINSPECTOR --- */
2346 hide_window_cb(GtkWidget *widget, gpointer data) {
2349 gtk_widget_hide(widget);
2352 static WebKitWebView*
2353 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2356 (void) web_inspector;
2357 GtkWidget* scrolled_window;
2358 GtkWidget* new_web_view;
2361 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2362 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2363 G_CALLBACK(hide_window_cb), NULL);
2365 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2366 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2367 gtk_widget_show(g->inspector_window);
2369 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2370 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2371 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2372 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2373 gtk_widget_show(scrolled_window);
2375 new_web_view = webkit_web_view_new();
2376 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2378 return WEBKIT_WEB_VIEW(new_web_view);
2382 inspector_show_window_cb (WebKitWebInspector* inspector){
2384 gtk_widget_show(uzbl.gui.inspector_window);
2388 /* TODO: Add variables and code to make use of these functions */
2390 inspector_close_window_cb (WebKitWebInspector* inspector){
2396 inspector_attach_window_cb (WebKitWebInspector* inspector){
2402 inspector_detach_window_cb (WebKitWebInspector* inspector){
2408 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2414 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2420 set_up_inspector() {
2422 WebKitWebSettings *settings = view_settings();
2423 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2425 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2426 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2427 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2428 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2429 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2430 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2431 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2433 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2437 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2439 uzbl_cmdprop *c = v;
2444 if(c->type == TYPE_STR)
2445 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2446 else if(c->type == TYPE_INT)
2447 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2451 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2455 printf("bind %s = %s %s\n", (char *)k ,
2456 (char *)a->name, a->param?(char *)a->param:"");
2461 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2462 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2467 main (int argc, char* argv[]) {
2468 gtk_init (&argc, &argv);
2469 if (!g_thread_supported ())
2470 g_thread_init (NULL);
2471 uzbl.state.executable_path = g_strdup(argv[0]);
2472 uzbl.state.selected_url = NULL;
2473 uzbl.state.searchtx = NULL;
2475 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2476 g_option_context_add_main_entries (context, entries, NULL);
2477 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2478 g_option_context_parse (context, &argc, &argv, NULL);
2479 g_option_context_free(context);
2481 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2482 gboolean verbose_override = uzbl.state.verbose;
2484 /* initialize hash table */
2485 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2487 uzbl.net.soup_session = webkit_get_default_session();
2488 uzbl.state.keycmd = g_string_new("");
2490 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2491 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2492 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2493 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2494 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2495 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2498 if(uname(&uzbl.state.unameinfo) == -1)
2499 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2501 uzbl.gui.sbar.progress_s = g_strdup("=");
2502 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2503 uzbl.gui.sbar.progress_w = 10;
2505 /* HTML mode defaults*/
2506 uzbl.behave.html_buffer = g_string_new("");
2507 uzbl.behave.html_endmarker = g_strdup(".");
2508 uzbl.behave.html_timeout = 60;
2509 uzbl.behave.base_url = g_strdup("http://invalid");
2511 /* default mode indicators */
2512 uzbl.behave.insert_indicator = g_strdup("I");
2513 uzbl.behave.cmd_indicator = g_strdup("C");
2517 make_var_to_name_hash();
2519 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2521 uzbl.gui.scrolled_win = create_browser();
2524 /* initial packing */
2525 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2526 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2528 if (uzbl.state.socket_id) {
2529 uzbl.gui.plug = create_plug ();
2530 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2531 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2533 uzbl.gui.main_window = create_window ();
2534 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2535 gtk_widget_show_all (uzbl.gui.main_window);
2536 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2539 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2541 if (uzbl.state.verbose) {
2542 printf("Uzbl start location: %s\n", argv[0]);
2543 if (uzbl.state.socket_id)
2544 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2546 printf("window_id %i\n",(int) uzbl.xwin);
2547 printf("pid %i\n", getpid ());
2548 printf("name: %s\n", uzbl.state.instance_name);
2551 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2552 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2553 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2554 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2555 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2559 if (!uzbl.behave.show_status)
2560 gtk_widget_hide(uzbl.gui.mainbar);
2569 if (verbose_override > uzbl.state.verbose)
2570 uzbl.state.verbose = verbose_override;
2573 set_var_value("uri", uri_override);
2574 g_free(uri_override);
2575 } else if (uzbl.state.uri)
2576 cmd_load_uri(uzbl.gui.web_view, NULL);
2581 return EXIT_SUCCESS;
2584 /* vi: set et ts=4: */