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 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
452 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
453 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
457 scroll_begin(WebKitWebView* page, GArray *argv) {
458 (void) page; (void) argv;
459 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
463 scroll_end(WebKitWebView* page, GArray *argv) {
464 (void) page; (void) argv;
465 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
466 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
470 scroll_vert(WebKitWebView* page, GArray *argv) {
472 scroll(uzbl.gui.bar_v, argv);
476 scroll_horz(WebKitWebView* page, GArray *argv) {
478 scroll(uzbl.gui.bar_h, argv);
483 if (!uzbl.behave.show_status) {
484 gtk_widget_hide(uzbl.gui.mainbar);
486 gtk_widget_show(uzbl.gui.mainbar);
492 toggle_zoom_type (WebKitWebView* page, GArray *argv) {
496 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
500 toggle_status_cb (WebKitWebView* page, GArray *argv) {
504 if (uzbl.behave.show_status) {
505 gtk_widget_hide(uzbl.gui.mainbar);
507 gtk_widget_show(uzbl.gui.mainbar);
509 uzbl.behave.show_status = !uzbl.behave.show_status;
514 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
518 //Set selected_url state variable
519 g_free(uzbl.state.selected_url);
520 uzbl.state.selected_url = NULL;
522 uzbl.state.selected_url = g_strdup(link);
528 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
532 if (uzbl.gui.main_title)
533 g_free (uzbl.gui.main_title);
534 uzbl.gui.main_title = g_strdup (title);
539 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
542 uzbl.gui.sbar.load_progress = progress;
547 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
551 if (uzbl.behave.load_finish_handler)
552 run_handler(uzbl.behave.load_finish_handler, "");
556 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
560 uzbl.gui.sbar.load_progress = 0;
561 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
562 if (uzbl.behave.load_start_handler)
563 run_handler(uzbl.behave.load_start_handler, "");
567 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
570 g_free (uzbl.state.uri);
571 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
572 uzbl.state.uri = g_string_free (newuri, FALSE);
573 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
574 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
577 if (uzbl.behave.load_commit_handler)
578 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
582 destroy_cb (GtkWidget* widget, gpointer data) {
590 if (uzbl.behave.history_handler) {
592 struct tm * timeinfo;
595 timeinfo = localtime ( &rawtime );
596 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
597 run_handler(uzbl.behave.history_handler, date);
602 /* VIEW funcs (little webkit wrappers) */
603 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
605 VIEWFUNC(reload_bypass_cache)
606 VIEWFUNC(stop_loading)
613 /* -- command to callback/function map for things we cannot attach to any signals */
614 static struct {char *name; Command command[2];} cmdlist[] =
615 { /* key function no_split */
616 { "back", {view_go_back, 0} },
617 { "forward", {view_go_forward, 0} },
618 { "scroll_vert", {scroll_vert, 0} },
619 { "scroll_horz", {scroll_horz, 0} },
620 { "scroll_begin", {scroll_begin, 0} },
621 { "scroll_end", {scroll_end, 0} },
622 { "reload", {view_reload, 0}, },
623 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
624 { "stop", {view_stop_loading, 0}, },
625 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
626 { "zoom_out", {view_zoom_out, 0}, },
627 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
628 { "uri", {load_uri, NOSPLIT} },
629 { "js", {run_js, NOSPLIT} },
630 { "script", {run_external_js, 0} },
631 { "toggle_status", {toggle_status_cb, 0} },
632 { "spawn", {spawn, 0} },
633 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
634 { "sh", {spawn_sh, 0} },
635 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
636 { "exit", {close_uzbl, 0} },
637 { "search", {search_forward_text, NOSPLIT} },
638 { "search_reverse", {search_reverse_text, NOSPLIT} },
639 { "dehilight", {dehilight, 0} },
640 { "toggle_insert_mode", {toggle_insert_mode, 0} },
641 { "set", {set_var, NOSPLIT} },
642 //{ "get", {get_var, NOSPLIT} },
643 { "bind", {act_bind, NOSPLIT} },
644 { "dump_config", {act_dump_config, 0} },
645 { "keycmd", {keycmd, NOSPLIT} },
646 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
647 { "keycmd_bs", {keycmd_bs, 0} },
648 { "chain", {chain, 0} },
649 { "print", {print, NOSPLIT} }
656 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
658 for (i = 0; i < LENGTH(cmdlist); i++)
659 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
662 /* -- CORE FUNCTIONS -- */
665 free_action(gpointer act) {
666 Action *action = (Action*)act;
667 g_free(action->name);
669 g_free(action->param);
674 new_action(const gchar *name, const gchar *param) {
675 Action *action = g_new(Action, 1);
677 action->name = g_strdup(name);
679 action->param = g_strdup(param);
681 action->param = NULL;
687 file_exists (const char * filename) {
688 return (access(filename, F_OK) == 0);
692 set_var(WebKitWebView *page, GArray *argv) {
694 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
695 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
696 set_var_value(g_strstrip(split[0]), value);
702 print(WebKitWebView *page, GArray *argv) {
706 buf = expand_vars(argv_idx(argv, 0));
712 act_bind(WebKitWebView *page, GArray *argv) {
714 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
715 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
716 add_binding(g_strstrip(split[0]), value);
728 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
731 if (argv_idx(argv, 0)) {
732 if (strcmp (argv_idx(argv, 0), "0") == 0) {
733 uzbl.behave.insert_mode = FALSE;
735 uzbl.behave.insert_mode = TRUE;
738 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
745 load_uri (WebKitWebView *web_view, GArray *argv) {
746 if (argv_idx(argv, 0)) {
747 GString* newuri = g_string_new (argv_idx(argv, 0));
748 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
749 run_js(web_view, argv);
752 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
753 g_string_prepend (newuri, "http://");
754 /* if we do handle cookies, ask our handler for them */
755 webkit_web_view_load_uri (web_view, newuri->str);
756 g_string_free (newuri, TRUE);
761 run_js (WebKitWebView * web_view, GArray *argv) {
762 if (argv_idx(argv, 0))
763 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
767 run_external_js (WebKitWebView * web_view, GArray *argv) {
768 if (argv_idx(argv, 0)) {
769 GArray* lines = read_file_by_line (argv_idx (argv, 0));
774 while ((line = g_array_index(lines, gchar*, i))) {
776 js = g_strdup (line);
778 gchar* newjs = g_strconcat (js, line, NULL);
785 if (uzbl.state.verbose)
786 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
788 if (argv_idx (argv, 1)) {
789 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
793 webkit_web_view_execute_script (web_view, js);
795 g_array_free (lines, TRUE);
800 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
801 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
802 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
803 webkit_web_view_unmark_text_matches (page);
804 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
805 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
809 if (uzbl.state.searchtx) {
810 if (uzbl.state.verbose)
811 printf ("Searching: %s\n", uzbl.state.searchtx);
812 webkit_web_view_set_highlight_text_matches (page, TRUE);
813 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
818 search_forward_text (WebKitWebView *page, GArray *argv) {
819 search_text(page, argv, TRUE);
823 search_reverse_text (WebKitWebView *page, GArray *argv) {
824 search_text(page, argv, FALSE);
828 dehilight (WebKitWebView *page, GArray *argv) {
830 webkit_web_view_set_highlight_text_matches (page, FALSE);
835 new_window_load_uri (const gchar * uri) {
836 GString* to_execute = g_string_new ("");
837 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
839 for (i = 0; entries[i].long_name != NULL; i++) {
840 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
841 gchar** str = (gchar**)entries[i].arg_data;
843 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
847 if (uzbl.state.verbose)
848 printf("\n%s\n", to_execute->str);
849 g_spawn_command_line_async (to_execute->str, NULL);
850 g_string_free (to_execute, TRUE);
854 chain (WebKitWebView *page, GArray *argv) {
857 gchar **parts = NULL;
859 while ((a = argv_idx(argv, i++))) {
860 parts = g_strsplit (a, " ", 2);
861 parse_command(parts[0], parts[1]);
867 keycmd (WebKitWebView *page, GArray *argv) {
870 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
876 keycmd_nl (WebKitWebView *page, GArray *argv) {
879 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
885 keycmd_bs (WebKitWebView *page, GArray *argv) {
889 prev = g_utf8_find_prev_char(uzbl.state.keycmd->str, uzbl.state.keycmd->str + uzbl.state.keycmd->len);
891 g_string_truncate(uzbl.state.keycmd, prev - uzbl.state.keycmd->str);
896 close_uzbl (WebKitWebView *page, GArray *argv) {
902 /* --Statusbar functions-- */
904 build_progressbar_ascii(int percent) {
905 int width=uzbl.gui.sbar.progress_w;
908 GString *bar = g_string_new("");
910 l = (double)percent*((double)width/100.);
911 l = (int)(l+.5)>=(int)l ? l+.5 : l;
913 for(i=0; i<(int)l; i++)
914 g_string_append(bar, uzbl.gui.sbar.progress_s);
917 g_string_append(bar, uzbl.gui.sbar.progress_u);
919 return g_string_free(bar, FALSE);
924 const GScannerConfig scan_config = {
927 ) /* cset_skip_characters */,
932 ) /* cset_identifier_first */,
939 ) /* cset_identifier_nth */,
940 ( "" ) /* cpair_comment_single */,
942 TRUE /* case_sensitive */,
944 FALSE /* skip_comment_multi */,
945 FALSE /* skip_comment_single */,
946 FALSE /* scan_comment_multi */,
947 TRUE /* scan_identifier */,
948 TRUE /* scan_identifier_1char */,
949 FALSE /* scan_identifier_NULL */,
950 TRUE /* scan_symbols */,
951 FALSE /* scan_binary */,
952 FALSE /* scan_octal */,
953 FALSE /* scan_float */,
954 FALSE /* scan_hex */,
955 FALSE /* scan_hex_dollar */,
956 FALSE /* scan_string_sq */,
957 FALSE /* scan_string_dq */,
958 TRUE /* numbers_2_int */,
959 FALSE /* int_2_float */,
960 FALSE /* identifier_2_string */,
961 FALSE /* char_2_token */,
962 FALSE /* symbol_2_token */,
963 TRUE /* scope_0_fallback */,
968 uzbl.scan = g_scanner_new(&scan_config);
969 while(symp->symbol_name) {
970 g_scanner_scope_add_symbol(uzbl.scan, 0,
972 GINT_TO_POINTER(symp->symbol_token));
978 expand_template(const char *template, gboolean escape_markup) {
979 if(!template) return NULL;
981 GTokenType token = G_TOKEN_NONE;
982 GString *ret = g_string_new("");
986 g_scanner_input_text(uzbl.scan, template, strlen(template));
987 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
988 token = g_scanner_get_next_token(uzbl.scan);
990 if(token == G_TOKEN_SYMBOL) {
991 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
995 buf = uzbl.state.uri?
996 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
997 g_string_append(ret, buf);
1001 g_string_append(ret, uzbl.state.uri?
1002 uzbl.state.uri:g_strdup(""));
1005 buf = itos(uzbl.gui.sbar.load_progress);
1006 g_string_append(ret, buf);
1009 case SYM_LOADPRGSBAR:
1010 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1011 g_string_append(ret, buf);
1016 buf = uzbl.gui.main_title?
1017 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1018 g_string_append(ret, buf);
1022 g_string_append(ret, uzbl.gui.main_title?
1023 uzbl.gui.main_title:g_strdup(""));
1025 case SYM_SELECTED_URI:
1027 buf = uzbl.state.selected_url?
1028 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1029 g_string_append(ret, buf);
1033 g_string_append(ret, uzbl.state.selected_url?
1034 uzbl.state.selected_url:g_strdup(""));
1037 buf = itos(uzbl.xwin);
1038 g_string_append(ret,
1039 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1044 buf = uzbl.state.keycmd->str?
1045 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1046 g_string_append(ret, buf);
1050 g_string_append(ret, uzbl.state.keycmd->str?
1051 uzbl.state.keycmd->str:g_strdup(""));
1054 g_string_append(ret,
1055 uzbl.behave.insert_mode?
1056 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1059 g_string_append(ret,
1060 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1062 /* useragent syms */
1064 buf = itos(WEBKIT_MAJOR_VERSION);
1065 g_string_append(ret, buf);
1069 buf = itos(WEBKIT_MINOR_VERSION);
1070 g_string_append(ret, buf);
1074 buf = itos(WEBKIT_MICRO_VERSION);
1075 g_string_append(ret, buf);
1079 g_string_append(ret, uzbl.state.unameinfo.sysname);
1082 g_string_append(ret, uzbl.state.unameinfo.nodename);
1085 g_string_append(ret, uzbl.state.unameinfo.release);
1088 g_string_append(ret, uzbl.state.unameinfo.version);
1091 g_string_append(ret, uzbl.state.unameinfo.machine);
1094 g_string_append(ret, ARCH);
1097 case SYM_DOMAINNAME:
1098 g_string_append(ret, uzbl.state.unameinfo.domainname);
1102 g_string_append(ret, COMMIT);
1108 else if(token == G_TOKEN_INT) {
1109 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1110 g_string_append(ret, buf);
1113 else if(token == G_TOKEN_IDENTIFIER) {
1114 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1116 else if(token == G_TOKEN_CHAR) {
1117 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1121 return g_string_free(ret, FALSE);
1123 /* --End Statusbar functions-- */
1126 sharg_append(GArray *a, const gchar *str) {
1127 const gchar *s = (str ? str : "");
1128 g_array_append_val(a, s);
1131 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1133 run_command (const gchar *command, const guint npre, const gchar **args,
1134 const gboolean sync, char **output_stdout) {
1135 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1138 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1139 gchar *pid = itos(getpid());
1140 gchar *xwin = itos(uzbl.xwin);
1142 sharg_append(a, command);
1143 for (i = 0; i < npre; i++) /* add n args before the default vars */
1144 sharg_append(a, args[i]);
1145 sharg_append(a, uzbl.state.config_file);
1146 sharg_append(a, pid);
1147 sharg_append(a, xwin);
1148 sharg_append(a, uzbl.comm.fifo_path);
1149 sharg_append(a, uzbl.comm.socket_path);
1150 sharg_append(a, uzbl.state.uri);
1151 sharg_append(a, uzbl.gui.main_title);
1153 for (i = npre; i < g_strv_length((gchar**)args); i++)
1154 sharg_append(a, args[i]);
1158 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1160 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1161 NULL, NULL, output_stdout, NULL, NULL, &err);
1162 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1163 NULL, NULL, NULL, &err);
1165 if (uzbl.state.verbose) {
1166 GString *s = g_string_new("spawned:");
1167 for (i = 0; i < (a->len); i++) {
1168 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1169 g_string_append_printf(s, " %s", qarg);
1172 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1173 printf("%s\n", s->str);
1174 g_string_free(s, TRUE);
1176 printf("Stdout: %s\n", *output_stdout);
1180 g_printerr("error on run_command: %s\n", err->message);
1185 g_array_free (a, TRUE);
1190 split_quoted(const gchar* src, const gboolean unquote) {
1191 /* split on unquoted space, return array of strings;
1192 remove a layer of quotes and backslashes if unquote */
1193 if (!src) return NULL;
1195 gboolean dq = FALSE;
1196 gboolean sq = FALSE;
1197 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1198 GString *s = g_string_new ("");
1202 for (p = src; *p != '\0'; p++) {
1203 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1204 else if (*p == '\\') { g_string_append_c(s, *p++);
1205 g_string_append_c(s, *p); }
1206 else if ((*p == '"') && unquote && !sq) dq = !dq;
1207 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1209 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1210 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1212 else if ((*p == ' ') && !dq && !sq) {
1213 dup = g_strdup(s->str);
1214 g_array_append_val(a, dup);
1215 g_string_truncate(s, 0);
1216 } else g_string_append_c(s, *p);
1218 dup = g_strdup(s->str);
1219 g_array_append_val(a, dup);
1220 ret = (gchar**)a->data;
1221 g_array_free (a, FALSE);
1222 g_string_free (s, TRUE);
1227 spawn(WebKitWebView *web_view, GArray *argv) {
1229 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1230 if (argv_idx(argv, 0))
1231 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1235 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1238 if (argv_idx(argv, 0))
1239 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1240 TRUE, &uzbl.comm.sync_stdout);
1244 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1246 if (!uzbl.behave.shell_cmd) {
1247 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1252 gchar *spacer = g_strdup("");
1253 g_array_insert_val(argv, 1, spacer);
1254 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1256 for (i = 1; i < g_strv_length(cmd); i++)
1257 g_array_prepend_val(argv, cmd[i]);
1259 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1265 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1267 if (!uzbl.behave.shell_cmd) {
1268 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1273 gchar *spacer = g_strdup("");
1274 g_array_insert_val(argv, 1, spacer);
1275 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1277 for (i = 1; i < g_strv_length(cmd); i++)
1278 g_array_prepend_val(argv, cmd[i]);
1280 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1281 TRUE, &uzbl.comm.sync_stdout);
1287 parse_command(const char *cmd, const char *param) {
1290 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1293 gchar **par = split_quoted(param, TRUE);
1294 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1296 if (c[1] == NOSPLIT) { /* don't split */
1297 sharg_append(a, param);
1299 for (i = 0; i < g_strv_length(par); i++)
1300 sharg_append(a, par[i]);
1302 c[0](uzbl.gui.web_view, a);
1304 g_array_free (a, TRUE);
1307 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1314 if(*uzbl.net.proxy_url == ' '
1315 || uzbl.net.proxy_url == NULL) {
1316 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1317 (GType) SOUP_SESSION_PROXY_URI);
1320 suri = soup_uri_new(uzbl.net.proxy_url);
1321 g_object_set(G_OBJECT(uzbl.net.soup_session),
1322 SOUP_SESSION_PROXY_URI,
1324 soup_uri_free(suri);
1331 if(file_exists(uzbl.gui.icon)) {
1332 if (uzbl.gui.main_window)
1333 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1335 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1337 g_free (uzbl.gui.icon);
1342 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1343 g_array_append_val (a, uzbl.state.uri);
1344 load_uri(uzbl.gui.web_view, a);
1345 g_array_free (a, TRUE);
1349 cmd_always_insert_mode() {
1350 uzbl.behave.insert_mode =
1351 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1357 g_object_set(G_OBJECT(uzbl.net.soup_session),
1358 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1362 cmd_max_conns_host() {
1363 g_object_set(G_OBJECT(uzbl.net.soup_session),
1364 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1369 soup_session_remove_feature
1370 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1371 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1372 /*g_free(uzbl.net.soup_logger);*/
1374 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1375 soup_session_add_feature(uzbl.net.soup_session,
1376 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1379 static WebKitWebSettings*
1381 return webkit_web_view_get_settings(uzbl.gui.web_view);
1386 WebKitWebSettings *ws = view_settings();
1387 if (uzbl.behave.font_size > 0) {
1388 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1391 if (uzbl.behave.monospace_size > 0) {
1392 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1393 uzbl.behave.monospace_size, NULL);
1395 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1396 uzbl.behave.font_size, NULL);
1402 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1406 cmd_disable_plugins() {
1407 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1408 !uzbl.behave.disable_plugins, NULL);
1412 cmd_disable_scripts() {
1413 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1414 !uzbl.behave.disable_scripts, NULL);
1418 cmd_minimum_font_size() {
1419 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1420 uzbl.behave.minimum_font_size, NULL);
1423 cmd_autoload_img() {
1424 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1425 uzbl.behave.autoload_img, NULL);
1430 cmd_autoshrink_img() {
1431 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1432 uzbl.behave.autoshrink_img, NULL);
1437 cmd_enable_spellcheck() {
1438 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1439 uzbl.behave.enable_spellcheck, NULL);
1443 cmd_enable_private() {
1444 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1445 uzbl.behave.enable_private, NULL);
1450 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1451 uzbl.behave.print_bg, NULL);
1456 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1457 uzbl.behave.style_uri, NULL);
1461 cmd_resizable_txt() {
1462 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1463 uzbl.behave.resizable_txt, NULL);
1467 cmd_default_encoding() {
1468 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1469 uzbl.behave.default_encoding, NULL);
1473 cmd_enforce_96dpi() {
1474 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1475 uzbl.behave.enforce_96dpi, NULL);
1479 cmd_caret_browsing() {
1480 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1481 uzbl.behave.caret_browsing, NULL);
1485 cmd_cookie_handler() {
1486 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1487 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1488 if ((g_strcmp0(split[0], "sh") == 0) ||
1489 (g_strcmp0(split[0], "spawn") == 0)) {
1490 g_free (uzbl.behave.cookie_handler);
1491 uzbl.behave.cookie_handler =
1492 g_strdup_printf("sync_%s %s", split[0], split[1]);
1499 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1504 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1509 if(uzbl.behave.inject_html) {
1510 webkit_web_view_load_html_string (uzbl.gui.web_view,
1511 uzbl.behave.inject_html, NULL);
1520 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1521 uzbl.behave.modmask = 0;
1523 if(uzbl.behave.modkey)
1524 g_free(uzbl.behave.modkey);
1525 uzbl.behave.modkey = buf;
1527 for (i = 0; modkeys[i].key != NULL; i++) {
1528 if (g_strrstr(buf, modkeys[i].key))
1529 uzbl.behave.modmask |= modkeys[i].mask;
1535 if (*uzbl.net.useragent == ' ') {
1536 g_free (uzbl.net.useragent);
1537 uzbl.net.useragent = NULL;
1539 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1541 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1542 g_free(uzbl.net.useragent);
1543 uzbl.net.useragent = ua;
1549 gtk_widget_ref(uzbl.gui.scrolled_win);
1550 gtk_widget_ref(uzbl.gui.mainbar);
1551 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1552 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1554 if(uzbl.behave.status_top) {
1555 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1556 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1559 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1560 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1562 gtk_widget_unref(uzbl.gui.scrolled_win);
1563 gtk_widget_unref(uzbl.gui.mainbar);
1564 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1569 set_var_value(gchar *name, gchar *val) {
1570 uzbl_cmdprop *c = NULL;
1574 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1575 /* check for the variable type */
1576 if (c->type == TYPE_STR) {
1577 buf = expand_vars(val);
1580 } else if(c->type == TYPE_INT) {
1581 int *ip = (int *)c->ptr;
1582 buf = expand_vars(val);
1583 *ip = (int)strtoul(buf, &endp, 10);
1585 } else if (c->type == TYPE_FLOAT) {
1586 float *fp = (float *)c->ptr;
1587 buf = expand_vars(val);
1588 *fp = strtod(buf, &endp);
1592 /* invoke a command specific function */
1593 if(c->func) c->func();
1600 Behaviour *b = &uzbl.behave;
1602 if(b->html_buffer->str) {
1603 webkit_web_view_load_html_string (uzbl.gui.web_view,
1604 b->html_buffer->str, b->base_url);
1605 g_string_free(b->html_buffer, TRUE);
1606 b->html_buffer = g_string_new("");
1610 enum {M_CMD, M_HTML};
1612 parse_cmd_line(const char *ctl_line) {
1613 Behaviour *b = &uzbl.behave;
1616 if(b->mode == M_HTML) {
1617 len = strlen(b->html_endmarker);
1618 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1619 if(len == strlen(ctl_line)-1 &&
1620 !strncmp(b->html_endmarker, ctl_line, len)) {
1622 set_var_value("mode", "0");
1627 set_timeout(b->html_timeout);
1628 g_string_append(b->html_buffer, ctl_line);
1631 else if((ctl_line[0] == '#') /* Comments */
1632 || (ctl_line[0] == ' ')
1633 || (ctl_line[0] == '\n'))
1634 ; /* ignore these lines */
1635 else { /* parse a command */
1637 gchar **tokens = NULL;
1638 len = strlen(ctl_line);
1640 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1641 ctlstrip = g_strndup(ctl_line, len - 1);
1642 else ctlstrip = g_strdup(ctl_line);
1644 tokens = g_strsplit(ctlstrip, " ", 2);
1645 parse_command(tokens[0], tokens[1]);
1652 build_stream_name(int type, const gchar* dir) {
1653 char *xwin_str = NULL;
1654 State *s = &uzbl.state;
1657 xwin_str = itos((int)uzbl.xwin);
1659 str = g_strdup_printf
1660 ("%s/uzbl_fifo_%s", dir,
1661 s->instance_name ? s->instance_name : xwin_str);
1662 } else if (type == SOCKET) {
1663 str = g_strdup_printf
1664 ("%s/uzbl_socket_%s", dir,
1665 s->instance_name ? s->instance_name : xwin_str );
1672 control_fifo(GIOChannel *gio, GIOCondition condition) {
1673 if (uzbl.state.verbose)
1674 printf("triggered\n");
1679 if (condition & G_IO_HUP)
1680 g_error ("Fifo: Read end of pipe died!\n");
1683 g_error ("Fifo: GIOChannel broke\n");
1685 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1686 if (ret == G_IO_STATUS_ERROR) {
1687 g_error ("Fifo: Error reading: %s\n", err->message);
1691 parse_cmd_line(ctl_line);
1698 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1699 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1700 if (unlink(uzbl.comm.fifo_path) == -1)
1701 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1702 g_free(uzbl.comm.fifo_path);
1703 uzbl.comm.fifo_path = NULL;
1706 if (*dir == ' ') { /* space unsets the variable */
1711 GIOChannel *chan = NULL;
1712 GError *error = NULL;
1713 gchar *path = build_stream_name(FIFO, dir);
1715 if (!file_exists(path)) {
1716 if (mkfifo (path, 0666) == 0) {
1717 // 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.
1718 chan = g_io_channel_new_file(path, "r+", &error);
1720 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1721 if (uzbl.state.verbose)
1722 printf ("init_fifo: created successfully as %s\n", path);
1723 uzbl.comm.fifo_path = path;
1725 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1726 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1727 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1728 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1730 /* if we got this far, there was an error; cleanup */
1731 if (error) g_error_free (error);
1738 control_stdin(GIOChannel *gio, GIOCondition condition) {
1740 gchar *ctl_line = NULL;
1743 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1744 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1747 parse_cmd_line(ctl_line);
1755 GIOChannel *chan = NULL;
1756 GError *error = NULL;
1758 chan = g_io_channel_unix_new(fileno(stdin));
1760 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1761 g_error ("Stdin: could not add watch\n");
1763 if (uzbl.state.verbose)
1764 printf ("Stdin: watch added successfully\n");
1767 g_error ("Stdin: Error while opening: %s\n", error->message);
1769 if (error) g_error_free (error);
1773 control_socket(GIOChannel *chan) {
1774 struct sockaddr_un remote;
1775 char buffer[512], *ctl_line;
1777 int sock, clientsock, n, done;
1780 sock = g_io_channel_unix_get_fd(chan);
1782 memset (buffer, 0, sizeof (buffer));
1784 t = sizeof (remote);
1785 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1789 memset (temp, 0, sizeof (temp));
1790 n = recv (clientsock, temp, 128, 0);
1792 buffer[strlen (buffer)] = '\0';
1796 strcat (buffer, temp);
1799 if (strcmp (buffer, "\n") < 0) {
1800 buffer[strlen (buffer) - 1] = '\0';
1802 buffer[strlen (buffer)] = '\0';
1805 ctl_line = g_strdup(buffer);
1806 parse_cmd_line (ctl_line);
1809 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1810 GError *error = NULL;
1813 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1814 if (ret == G_IO_STATUS_ERROR)
1815 g_error ("Error reading: %s\n", error->message);
1817 printf("Got line %s (%u bytes) \n",ctl_line, len);
1819 parse_line(ctl_line);
1827 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1828 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1829 if (unlink(uzbl.comm.socket_path) == -1)
1830 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1831 g_free(uzbl.comm.socket_path);
1832 uzbl.comm.socket_path = NULL;
1840 GIOChannel *chan = NULL;
1842 struct sockaddr_un local;
1843 gchar *path = build_stream_name(SOCKET, dir);
1845 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1847 local.sun_family = AF_UNIX;
1848 strcpy (local.sun_path, path);
1849 unlink (local.sun_path);
1851 len = strlen (local.sun_path) + sizeof (local.sun_family);
1852 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1853 if (uzbl.state.verbose)
1854 printf ("init_socket: opened in %s\n", path);
1857 if( (chan = g_io_channel_unix_new(sock)) ) {
1858 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1859 uzbl.comm.socket_path = path;
1862 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1864 /* if we got this far, there was an error; cleanup */
1871 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1872 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1874 // this function may be called very early when the templates are not set (yet), hence the checks
1876 update_title (void) {
1877 Behaviour *b = &uzbl.behave;
1880 if (b->show_status) {
1881 if (b->title_format_short) {
1882 parsed = expand_template(b->title_format_short, FALSE);
1883 if (uzbl.gui.main_window)
1884 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1887 if (b->status_format) {
1888 parsed = expand_template(b->status_format, TRUE);
1889 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1892 if (b->status_background) {
1894 gdk_color_parse (b->status_background, &color);
1895 //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)
1896 if (uzbl.gui.main_window)
1897 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1900 if (b->title_format_long) {
1901 parsed = expand_template(b->title_format_long, FALSE);
1902 if (uzbl.gui.main_window)
1903 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1910 key_press_cb (GtkWidget* window, GdkEventKey* event)
1912 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1916 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1917 || 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)
1920 /* turn off insert mode (if always_insert_mode is not used) */
1921 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1922 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1927 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1930 if (event->keyval == GDK_Escape) {
1931 g_string_truncate(uzbl.state.keycmd, 0);
1933 dehilight(uzbl.gui.web_view, NULL);
1937 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1938 if (event->keyval == GDK_Insert) {
1940 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1941 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1943 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1946 g_string_append (uzbl.state.keycmd, str);
1953 if (event->keyval == GDK_BackSpace)
1954 keycmd_bs(NULL, NULL);
1956 gboolean key_ret = FALSE;
1957 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1959 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1961 run_keycmd(key_ret);
1963 if (key_ret) return (!uzbl.behave.insert_mode);
1968 run_keycmd(const gboolean key_ret) {
1969 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1971 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1972 g_string_truncate(uzbl.state.keycmd, 0);
1973 parse_command(act->name, act->param);
1977 /* try if it's an incremental keycmd or one that takes args, and run it */
1978 GString* short_keys = g_string_new ("");
1979 GString* short_keys_inc = g_string_new ("");
1981 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1982 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1983 g_string_assign(short_keys_inc, short_keys->str);
1984 g_string_append_c(short_keys, '_');
1985 g_string_append_c(short_keys_inc, '*');
1987 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1988 /* run normal cmds only if return was pressed */
1989 exec_paramcmd(act, i);
1990 g_string_truncate(uzbl.state.keycmd, 0);
1992 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1993 if (key_ret) /* just quit the incremental command on return */
1994 g_string_truncate(uzbl.state.keycmd, 0);
1995 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1999 g_string_truncate(short_keys, short_keys->len - 1);
2001 g_string_free (short_keys, TRUE);
2002 g_string_free (short_keys_inc, TRUE);
2006 exec_paramcmd(const Action *act, const guint i) {
2007 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2008 GString *actionname = g_string_new ("");
2009 GString *actionparam = g_string_new ("");
2010 g_string_erase (parampart, 0, i+1);
2012 g_string_printf (actionname, act->name, parampart->str);
2014 g_string_printf (actionparam, act->param, parampart->str);
2015 parse_command(actionname->str, actionparam->str);
2016 g_string_free(actionname, TRUE);
2017 g_string_free(actionparam, TRUE);
2018 g_string_free(parampart, TRUE);
2026 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2027 //main_window_ref = g_object_ref(scrolled_window);
2028 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
2030 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2031 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2033 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2035 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2036 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2037 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2038 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2039 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2040 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2041 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2042 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2043 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2045 return scrolled_window;
2052 g->mainbar = gtk_hbox_new (FALSE, 0);
2054 /* keep a reference to the bar so we can re-pack it at runtime*/
2055 //sbar_ref = g_object_ref(g->mainbar);
2057 g->mainbar_label = gtk_label_new ("");
2058 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2059 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2060 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2061 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2062 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2063 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2068 GtkWidget* create_window () {
2069 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2070 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2071 gtk_widget_set_name (window, "Uzbl browser");
2072 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2073 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2079 GtkPlug* create_plug () {
2080 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2081 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2082 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2089 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2091 If actname is one that calls an external command, this function will inject
2092 newargs in front of the user-provided args in that command line. They will
2093 come become after the body of the script (in sh) or after the name of
2094 the command to execute (in spawn).
2095 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2096 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2098 The return value consist of two strings: the action (sh, ...) and its args.
2100 If act is not one that calls an external command, then the given action merely
2103 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2104 gchar *actdup = g_strdup(actname);
2105 g_array_append_val(rets, actdup);
2107 if ((g_strcmp0(actname, "spawn") == 0) ||
2108 (g_strcmp0(actname, "sh") == 0) ||
2109 (g_strcmp0(actname, "sync_spawn") == 0) ||
2110 (g_strcmp0(actname, "sync_sh") == 0)) {
2112 GString *a = g_string_new("");
2113 gchar **spawnparts = split_quoted(origargs, FALSE);
2114 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2115 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2117 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2118 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2120 g_array_append_val(rets, a->str);
2121 g_string_free(a, FALSE);
2122 g_strfreev(spawnparts);
2124 gchar *origdup = g_strdup(origargs);
2125 g_array_append_val(rets, origdup);
2127 return (gchar**)g_array_free(rets, FALSE);
2131 run_handler (const gchar *act, const gchar *args) {
2132 /* Consider this code a temporary hack to make the handlers usable.
2133 In practice, all this splicing, injection, and reconstruction is
2134 inefficient, annoying and hard to manage. Potential pitfalls arise
2135 when the handler specific args 1) are not quoted (the handler
2136 callbacks should take care of this) 2) are quoted but interfere
2137 with the users' own quotation. A more ideal solution is
2138 to refactor parse_command so that it doesn't just take a string
2139 and execute it; rather than that, we should have a function which
2140 returns the argument vector parsed from the string. This vector
2141 could be modified (e.g. insert additional args into it) before
2142 passing it to the next function that actually executes it. Though
2143 it still isn't perfect for chain actions.. will reconsider & re-
2144 factor when I have the time. -duc */
2146 char **parts = g_strsplit(act, " ", 2);
2148 if (g_strcmp0(parts[0], "chain") == 0) {
2149 GString *newargs = g_string_new("");
2150 gchar **chainparts = split_quoted(parts[1], FALSE);
2152 /* for every argument in the chain, inject the handler args
2153 and make sure the new parts are wrapped in quotes */
2154 gchar **cp = chainparts;
2156 gchar *quotless = NULL;
2157 gchar **spliced_quotless = NULL; // sigh -_-;
2158 gchar **inpart = NULL;
2161 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2163 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2164 } else quotless = g_strdup(*cp);
2166 spliced_quotless = g_strsplit(quotless, " ", 2);
2167 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2168 g_strfreev(spliced_quotless);
2170 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2176 parse_command(parts[0], &(newargs->str[1]));
2177 g_string_free(newargs, TRUE);
2178 g_strfreev(chainparts);
2181 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2182 parse_command(inparts[0], inparts[1]);
2190 add_binding (const gchar *key, const gchar *act) {
2191 char **parts = g_strsplit(act, " ", 2);
2198 if (uzbl.state.verbose)
2199 printf ("Binding %-10s : %s\n", key, act);
2200 action = new_action(parts[0], parts[1]);
2202 if (g_hash_table_remove (uzbl.bindings, key))
2203 g_warning ("Overwriting existing binding for \"%s\"", key);
2204 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2209 get_xdg_var (XDG_Var xdg) {
2210 const gchar* actual_value = getenv (xdg.environmental);
2211 const gchar* home = getenv ("HOME");
2212 gchar* return_value;
2214 if (! actual_value || strcmp (actual_value, "") == 0) {
2215 if (xdg.default_value) {
2216 return_value = str_replace ("~", home, xdg.default_value);
2218 return_value = NULL;
2221 return_value = str_replace("~", home, actual_value);
2224 return return_value;
2228 find_xdg_file (int xdg_type, char* filename) {
2229 /* xdg_type = 0 => config
2230 xdg_type = 1 => data
2231 xdg_type = 2 => cache*/
2233 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2234 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2237 gchar* temporary_string;
2241 if (! file_exists (temporary_file) && xdg_type != 2) {
2242 buf = get_xdg_var (XDG[3 + xdg_type]);
2243 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2246 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2247 g_free (temporary_file);
2248 temporary_file = g_strconcat (temporary_string, filename, NULL);
2252 //g_free (temporary_string); - segfaults.
2254 if (file_exists (temporary_file)) {
2255 return temporary_file;
2262 State *s = &uzbl.state;
2263 Network *n = &uzbl.net;
2265 for (i = 0; default_config[i].command != NULL; i++) {
2266 parse_cmd_line(default_config[i].command);
2269 if (!s->config_file) {
2270 s->config_file = find_xdg_file (0, "/uzbl/config");
2273 if (s->config_file) {
2274 GArray* lines = read_file_by_line (s->config_file);
2278 while ((line = g_array_index(lines, gchar*, i))) {
2279 parse_cmd_line (line);
2283 g_array_free (lines, TRUE);
2285 if (uzbl.state.verbose)
2286 printf ("No configuration file loaded.\n");
2289 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2292 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2295 if (!uzbl.behave.cookie_handler)
2298 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2299 GString *s = g_string_new ("");
2300 SoupURI * soup_uri = soup_message_get_uri(msg);
2301 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2302 run_handler(uzbl.behave.cookie_handler, s->str);
2304 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2305 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2306 if ( p != NULL ) *p = '\0';
2307 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2309 if (uzbl.comm.sync_stdout)
2310 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2312 g_string_free(s, TRUE);
2316 save_cookies (SoupMessage *msg, gpointer user_data){
2320 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2321 cookie = soup_cookie_to_set_cookie_header(ck->data);
2322 SoupURI * soup_uri = soup_message_get_uri(msg);
2323 GString *s = g_string_new ("");
2324 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2325 run_handler(uzbl.behave.cookie_handler, s->str);
2327 g_string_free(s, TRUE);
2332 /* --- WEBINSPECTOR --- */
2334 hide_window_cb(GtkWidget *widget, gpointer data) {
2337 gtk_widget_hide(widget);
2340 static WebKitWebView*
2341 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2344 (void) web_inspector;
2345 GtkWidget* scrolled_window;
2346 GtkWidget* new_web_view;
2349 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2350 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2351 G_CALLBACK(hide_window_cb), NULL);
2353 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2354 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2355 gtk_widget_show(g->inspector_window);
2357 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2358 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2359 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2360 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2361 gtk_widget_show(scrolled_window);
2363 new_web_view = webkit_web_view_new();
2364 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2366 return WEBKIT_WEB_VIEW(new_web_view);
2370 inspector_show_window_cb (WebKitWebInspector* inspector){
2372 gtk_widget_show(uzbl.gui.inspector_window);
2376 /* TODO: Add variables and code to make use of these functions */
2378 inspector_close_window_cb (WebKitWebInspector* inspector){
2384 inspector_attach_window_cb (WebKitWebInspector* inspector){
2390 inspector_detach_window_cb (WebKitWebInspector* inspector){
2396 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2402 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2408 set_up_inspector() {
2410 WebKitWebSettings *settings = view_settings();
2411 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2413 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2414 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2415 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2416 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2417 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2418 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2419 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2421 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2425 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2427 uzbl_cmdprop *c = v;
2432 if(c->type == TYPE_STR)
2433 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2434 else if(c->type == TYPE_INT)
2435 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2439 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2443 printf("bind %s = %s %s\n", (char *)k ,
2444 (char *)a->name, a->param?(char *)a->param:"");
2449 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2450 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2455 main (int argc, char* argv[]) {
2456 gtk_init (&argc, &argv);
2457 if (!g_thread_supported ())
2458 g_thread_init (NULL);
2459 uzbl.state.executable_path = g_strdup(argv[0]);
2460 uzbl.state.selected_url = NULL;
2461 uzbl.state.searchtx = NULL;
2463 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2464 g_option_context_add_main_entries (context, entries, NULL);
2465 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2466 g_option_context_parse (context, &argc, &argv, NULL);
2467 g_option_context_free(context);
2469 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2470 gboolean verbose_override = uzbl.state.verbose;
2472 /* initialize hash table */
2473 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2475 uzbl.net.soup_session = webkit_get_default_session();
2476 uzbl.state.keycmd = g_string_new("");
2478 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2479 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2480 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2481 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2482 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2483 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2486 if(uname(&uzbl.state.unameinfo) == -1)
2487 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2489 uzbl.gui.sbar.progress_s = g_strdup("=");
2490 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2491 uzbl.gui.sbar.progress_w = 10;
2493 /* HTML mode defaults*/
2494 uzbl.behave.html_buffer = g_string_new("");
2495 uzbl.behave.html_endmarker = g_strdup(".");
2496 uzbl.behave.html_timeout = 60;
2497 uzbl.behave.base_url = g_strdup("http://invalid");
2499 /* default mode indicators */
2500 uzbl.behave.insert_indicator = g_strdup("I");
2501 uzbl.behave.cmd_indicator = g_strdup("C");
2505 make_var_to_name_hash();
2507 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2509 uzbl.gui.scrolled_win = create_browser();
2512 /* initial packing */
2513 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2514 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2516 if (uzbl.state.socket_id) {
2517 uzbl.gui.plug = create_plug ();
2518 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2519 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2521 uzbl.gui.main_window = create_window ();
2522 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2523 gtk_widget_show_all (uzbl.gui.main_window);
2524 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2527 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2529 if (uzbl.state.verbose) {
2530 printf("Uzbl start location: %s\n", argv[0]);
2531 if (uzbl.state.socket_id)
2532 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2534 printf("window_id %i\n",(int) uzbl.xwin);
2535 printf("pid %i\n", getpid ());
2536 printf("name: %s\n", uzbl.state.instance_name);
2539 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2540 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2541 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2542 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2543 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2547 if (!uzbl.behave.show_status)
2548 gtk_widget_hide(uzbl.gui.mainbar);
2557 if (verbose_override > uzbl.state.verbose)
2558 uzbl.state.verbose = verbose_override;
2561 set_var_value("uri", uri_override);
2562 g_free(uri_override);
2563 } else if (uzbl.state.uri)
2564 cmd_load_uri(uzbl.gui.web_view, NULL);
2569 return EXIT_SUCCESS;
2572 /* vi: set et ts=4: */