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) {
888 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
893 close_uzbl (WebKitWebView *page, GArray *argv) {
899 /* --Statusbar functions-- */
901 build_progressbar_ascii(int percent) {
902 int width=uzbl.gui.sbar.progress_w;
905 GString *bar = g_string_new("");
907 l = (double)percent*((double)width/100.);
908 l = (int)(l+.5)>=(int)l ? l+.5 : l;
910 for(i=0; i<(int)l; i++)
911 g_string_append(bar, uzbl.gui.sbar.progress_s);
914 g_string_append(bar, uzbl.gui.sbar.progress_u);
916 return g_string_free(bar, FALSE);
921 const GScannerConfig scan_config = {
924 ) /* cset_skip_characters */,
929 ) /* cset_identifier_first */,
936 ) /* cset_identifier_nth */,
937 ( "" ) /* cpair_comment_single */,
939 TRUE /* case_sensitive */,
941 FALSE /* skip_comment_multi */,
942 FALSE /* skip_comment_single */,
943 FALSE /* scan_comment_multi */,
944 TRUE /* scan_identifier */,
945 TRUE /* scan_identifier_1char */,
946 FALSE /* scan_identifier_NULL */,
947 TRUE /* scan_symbols */,
948 FALSE /* scan_binary */,
949 FALSE /* scan_octal */,
950 FALSE /* scan_float */,
951 FALSE /* scan_hex */,
952 FALSE /* scan_hex_dollar */,
953 FALSE /* scan_string_sq */,
954 FALSE /* scan_string_dq */,
955 TRUE /* numbers_2_int */,
956 FALSE /* int_2_float */,
957 FALSE /* identifier_2_string */,
958 FALSE /* char_2_token */,
959 FALSE /* symbol_2_token */,
960 TRUE /* scope_0_fallback */,
965 uzbl.scan = g_scanner_new(&scan_config);
966 while(symp->symbol_name) {
967 g_scanner_scope_add_symbol(uzbl.scan, 0,
969 GINT_TO_POINTER(symp->symbol_token));
975 expand_template(const char *template, gboolean escape_markup) {
976 if(!template) return NULL;
978 GTokenType token = G_TOKEN_NONE;
979 GString *ret = g_string_new("");
983 g_scanner_input_text(uzbl.scan, template, strlen(template));
984 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
985 token = g_scanner_get_next_token(uzbl.scan);
987 if(token == G_TOKEN_SYMBOL) {
988 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
992 buf = uzbl.state.uri?
993 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
994 g_string_append(ret, buf);
998 g_string_append(ret, uzbl.state.uri?
999 uzbl.state.uri:g_strdup(""));
1002 buf = itos(uzbl.gui.sbar.load_progress);
1003 g_string_append(ret, buf);
1006 case SYM_LOADPRGSBAR:
1007 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1008 g_string_append(ret, buf);
1013 buf = uzbl.gui.main_title?
1014 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1015 g_string_append(ret, buf);
1019 g_string_append(ret, uzbl.gui.main_title?
1020 uzbl.gui.main_title:g_strdup(""));
1022 case SYM_SELECTED_URI:
1024 buf = uzbl.state.selected_url?
1025 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1026 g_string_append(ret, buf);
1030 g_string_append(ret, uzbl.state.selected_url?
1031 uzbl.state.selected_url:g_strdup(""));
1034 buf = itos(uzbl.xwin);
1035 g_string_append(ret,
1036 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1041 buf = uzbl.state.keycmd->str?
1042 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1043 g_string_append(ret, buf);
1047 g_string_append(ret, uzbl.state.keycmd->str?
1048 uzbl.state.keycmd->str:g_strdup(""));
1051 g_string_append(ret,
1052 uzbl.behave.insert_mode?
1053 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1056 g_string_append(ret,
1057 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1059 /* useragent syms */
1061 buf = itos(WEBKIT_MAJOR_VERSION);
1062 g_string_append(ret, buf);
1066 buf = itos(WEBKIT_MINOR_VERSION);
1067 g_string_append(ret, buf);
1071 buf = itos(WEBKIT_MICRO_VERSION);
1072 g_string_append(ret, buf);
1076 g_string_append(ret, uzbl.state.unameinfo.sysname);
1079 g_string_append(ret, uzbl.state.unameinfo.nodename);
1082 g_string_append(ret, uzbl.state.unameinfo.release);
1085 g_string_append(ret, uzbl.state.unameinfo.version);
1088 g_string_append(ret, uzbl.state.unameinfo.machine);
1091 g_string_append(ret, ARCH);
1094 case SYM_DOMAINNAME:
1095 g_string_append(ret, uzbl.state.unameinfo.domainname);
1099 g_string_append(ret, COMMIT);
1105 else if(token == G_TOKEN_INT) {
1106 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1107 g_string_append(ret, buf);
1110 else if(token == G_TOKEN_IDENTIFIER) {
1111 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1113 else if(token == G_TOKEN_CHAR) {
1114 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1118 return g_string_free(ret, FALSE);
1120 /* --End Statusbar functions-- */
1123 sharg_append(GArray *a, const gchar *str) {
1124 const gchar *s = (str ? str : "");
1125 g_array_append_val(a, s);
1128 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1130 run_command (const gchar *command, const guint npre, const gchar **args,
1131 const gboolean sync, char **output_stdout) {
1132 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1135 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1136 gchar *pid = itos(getpid());
1137 gchar *xwin = itos(uzbl.xwin);
1139 sharg_append(a, command);
1140 for (i = 0; i < npre; i++) /* add n args before the default vars */
1141 sharg_append(a, args[i]);
1142 sharg_append(a, uzbl.state.config_file);
1143 sharg_append(a, pid);
1144 sharg_append(a, xwin);
1145 sharg_append(a, uzbl.comm.fifo_path);
1146 sharg_append(a, uzbl.comm.socket_path);
1147 sharg_append(a, uzbl.state.uri);
1148 sharg_append(a, uzbl.gui.main_title);
1150 for (i = npre; i < g_strv_length((gchar**)args); i++)
1151 sharg_append(a, args[i]);
1155 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1157 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1158 NULL, NULL, output_stdout, NULL, NULL, &err);
1159 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1160 NULL, NULL, NULL, &err);
1162 if (uzbl.state.verbose) {
1163 GString *s = g_string_new("spawned:");
1164 for (i = 0; i < (a->len); i++) {
1165 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1166 g_string_append_printf(s, " %s", qarg);
1169 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1170 printf("%s\n", s->str);
1171 g_string_free(s, TRUE);
1173 printf("Stdout: %s\n", *output_stdout);
1177 g_printerr("error on run_command: %s\n", err->message);
1182 g_array_free (a, TRUE);
1187 split_quoted(const gchar* src, const gboolean unquote) {
1188 /* split on unquoted space, return array of strings;
1189 remove a layer of quotes and backslashes if unquote */
1190 if (!src) return NULL;
1192 gboolean dq = FALSE;
1193 gboolean sq = FALSE;
1194 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1195 GString *s = g_string_new ("");
1199 for (p = src; *p != '\0'; p++) {
1200 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1201 else if (*p == '\\') { g_string_append_c(s, *p++);
1202 g_string_append_c(s, *p); }
1203 else if ((*p == '"') && unquote && !sq) dq = !dq;
1204 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1206 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1207 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1209 else if ((*p == ' ') && !dq && !sq) {
1210 dup = g_strdup(s->str);
1211 g_array_append_val(a, dup);
1212 g_string_truncate(s, 0);
1213 } else g_string_append_c(s, *p);
1215 dup = g_strdup(s->str);
1216 g_array_append_val(a, dup);
1217 ret = (gchar**)a->data;
1218 g_array_free (a, FALSE);
1219 g_string_free (s, TRUE);
1224 spawn(WebKitWebView *web_view, GArray *argv) {
1226 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1227 if (argv_idx(argv, 0))
1228 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1232 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1235 if (argv_idx(argv, 0))
1236 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1237 TRUE, &uzbl.comm.sync_stdout);
1241 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1243 if (!uzbl.behave.shell_cmd) {
1244 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1249 gchar *spacer = g_strdup("");
1250 g_array_insert_val(argv, 1, spacer);
1251 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1253 for (i = 1; i < g_strv_length(cmd); i++)
1254 g_array_prepend_val(argv, cmd[i]);
1256 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1262 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1264 if (!uzbl.behave.shell_cmd) {
1265 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1270 gchar *spacer = g_strdup("");
1271 g_array_insert_val(argv, 1, spacer);
1272 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1274 for (i = 1; i < g_strv_length(cmd); i++)
1275 g_array_prepend_val(argv, cmd[i]);
1277 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1278 TRUE, &uzbl.comm.sync_stdout);
1284 parse_command(const char *cmd, const char *param) {
1287 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1290 gchar **par = split_quoted(param, TRUE);
1291 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1293 if (c[1] == NOSPLIT) { /* don't split */
1294 sharg_append(a, param);
1296 for (i = 0; i < g_strv_length(par); i++)
1297 sharg_append(a, par[i]);
1299 c[0](uzbl.gui.web_view, a);
1301 g_array_free (a, TRUE);
1304 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1311 if(*uzbl.net.proxy_url == ' '
1312 || uzbl.net.proxy_url == NULL) {
1313 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1314 (GType) SOUP_SESSION_PROXY_URI);
1317 suri = soup_uri_new(uzbl.net.proxy_url);
1318 g_object_set(G_OBJECT(uzbl.net.soup_session),
1319 SOUP_SESSION_PROXY_URI,
1321 soup_uri_free(suri);
1328 if(file_exists(uzbl.gui.icon)) {
1329 if (uzbl.gui.main_window)
1330 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1332 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1334 g_free (uzbl.gui.icon);
1339 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1340 g_array_append_val (a, uzbl.state.uri);
1341 load_uri(uzbl.gui.web_view, a);
1342 g_array_free (a, TRUE);
1346 cmd_always_insert_mode() {
1347 uzbl.behave.insert_mode =
1348 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1354 g_object_set(G_OBJECT(uzbl.net.soup_session),
1355 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1359 cmd_max_conns_host() {
1360 g_object_set(G_OBJECT(uzbl.net.soup_session),
1361 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1366 soup_session_remove_feature
1367 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1368 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1369 /*g_free(uzbl.net.soup_logger);*/
1371 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1372 soup_session_add_feature(uzbl.net.soup_session,
1373 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1376 static WebKitWebSettings*
1378 return webkit_web_view_get_settings(uzbl.gui.web_view);
1383 WebKitWebSettings *ws = view_settings();
1384 if (uzbl.behave.font_size > 0) {
1385 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1388 if (uzbl.behave.monospace_size > 0) {
1389 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1390 uzbl.behave.monospace_size, NULL);
1392 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1393 uzbl.behave.font_size, NULL);
1399 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1403 cmd_disable_plugins() {
1404 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1405 !uzbl.behave.disable_plugins, NULL);
1409 cmd_disable_scripts() {
1410 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1411 !uzbl.behave.disable_scripts, NULL);
1415 cmd_minimum_font_size() {
1416 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1417 uzbl.behave.minimum_font_size, NULL);
1420 cmd_autoload_img() {
1421 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1422 uzbl.behave.autoload_img, NULL);
1427 cmd_autoshrink_img() {
1428 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1429 uzbl.behave.autoshrink_img, NULL);
1434 cmd_enable_spellcheck() {
1435 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1436 uzbl.behave.enable_spellcheck, NULL);
1440 cmd_enable_private() {
1441 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1442 uzbl.behave.enable_private, NULL);
1447 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1448 uzbl.behave.print_bg, NULL);
1453 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1454 uzbl.behave.style_uri, NULL);
1458 cmd_resizable_txt() {
1459 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1460 uzbl.behave.resizable_txt, NULL);
1464 cmd_default_encoding() {
1465 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1466 uzbl.behave.default_encoding, NULL);
1470 cmd_enforce_96dpi() {
1471 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1472 uzbl.behave.enforce_96dpi, NULL);
1476 cmd_caret_browsing() {
1477 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1478 uzbl.behave.caret_browsing, NULL);
1482 cmd_cookie_handler() {
1483 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1484 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1485 if ((g_strcmp0(split[0], "sh") == 0) ||
1486 (g_strcmp0(split[0], "spawn") == 0)) {
1487 g_free (uzbl.behave.cookie_handler);
1488 uzbl.behave.cookie_handler =
1489 g_strdup_printf("sync_%s %s", split[0], split[1]);
1496 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1501 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1506 if(uzbl.behave.inject_html) {
1507 webkit_web_view_load_html_string (uzbl.gui.web_view,
1508 uzbl.behave.inject_html, NULL);
1517 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1518 uzbl.behave.modmask = 0;
1520 if(uzbl.behave.modkey)
1521 g_free(uzbl.behave.modkey);
1522 uzbl.behave.modkey = buf;
1524 for (i = 0; modkeys[i].key != NULL; i++) {
1525 if (g_strrstr(buf, modkeys[i].key))
1526 uzbl.behave.modmask |= modkeys[i].mask;
1532 if (*uzbl.net.useragent == ' ') {
1533 g_free (uzbl.net.useragent);
1534 uzbl.net.useragent = NULL;
1536 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1538 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1539 g_free(uzbl.net.useragent);
1540 uzbl.net.useragent = ua;
1546 gtk_widget_ref(uzbl.gui.scrolled_win);
1547 gtk_widget_ref(uzbl.gui.mainbar);
1548 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1549 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1551 if(uzbl.behave.status_top) {
1552 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1553 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1556 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1557 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1559 gtk_widget_unref(uzbl.gui.scrolled_win);
1560 gtk_widget_unref(uzbl.gui.mainbar);
1561 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1566 set_var_value(gchar *name, gchar *val) {
1567 uzbl_cmdprop *c = NULL;
1571 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1572 /* check for the variable type */
1573 if (c->type == TYPE_STR) {
1574 buf = expand_vars(val);
1577 } else if(c->type == TYPE_INT) {
1578 int *ip = (int *)c->ptr;
1579 buf = expand_vars(val);
1580 *ip = (int)strtoul(buf, &endp, 10);
1582 } else if (c->type == TYPE_FLOAT) {
1583 float *fp = (float *)c->ptr;
1584 buf = expand_vars(val);
1585 *fp = strtod(buf, &endp);
1589 /* invoke a command specific function */
1590 if(c->func) c->func();
1597 Behaviour *b = &uzbl.behave;
1599 if(b->html_buffer->str) {
1600 webkit_web_view_load_html_string (uzbl.gui.web_view,
1601 b->html_buffer->str, b->base_url);
1602 g_string_free(b->html_buffer, TRUE);
1603 b->html_buffer = g_string_new("");
1607 enum {M_CMD, M_HTML};
1609 parse_cmd_line(const char *ctl_line) {
1610 Behaviour *b = &uzbl.behave;
1613 if(b->mode == M_HTML) {
1614 len = strlen(b->html_endmarker);
1615 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1616 if(len == strlen(ctl_line)-1 &&
1617 !strncmp(b->html_endmarker, ctl_line, len)) {
1619 set_var_value("mode", "0");
1624 set_timeout(b->html_timeout);
1625 g_string_append(b->html_buffer, ctl_line);
1628 else if((ctl_line[0] == '#') /* Comments */
1629 || (ctl_line[0] == ' ')
1630 || (ctl_line[0] == '\n'))
1631 ; /* ignore these lines */
1632 else { /* parse a command */
1634 gchar **tokens = NULL;
1635 len = strlen(ctl_line);
1637 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1638 ctlstrip = g_strndup(ctl_line, len - 1);
1639 else ctlstrip = g_strdup(ctl_line);
1641 tokens = g_strsplit(ctlstrip, " ", 2);
1642 parse_command(tokens[0], tokens[1]);
1649 build_stream_name(int type, const gchar* dir) {
1651 State *s = &uzbl.state;
1654 xwin_str = itos((int)uzbl.xwin);
1656 str = g_strdup_printf
1657 ("%s/uzbl_fifo_%s", dir,
1658 s->instance_name ? s->instance_name : xwin_str);
1659 } else if (type == SOCKET) {
1660 str = g_strdup_printf
1661 ("%s/uzbl_socket_%s", dir,
1662 s->instance_name ? s->instance_name : xwin_str );
1669 control_fifo(GIOChannel *gio, GIOCondition condition) {
1670 if (uzbl.state.verbose)
1671 printf("triggered\n");
1676 if (condition & G_IO_HUP)
1677 g_error ("Fifo: Read end of pipe died!\n");
1680 g_error ("Fifo: GIOChannel broke\n");
1682 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1683 if (ret == G_IO_STATUS_ERROR) {
1684 g_error ("Fifo: Error reading: %s\n", err->message);
1688 parse_cmd_line(ctl_line);
1695 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1696 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1697 if (unlink(uzbl.comm.fifo_path) == -1)
1698 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1699 g_free(uzbl.comm.fifo_path);
1700 uzbl.comm.fifo_path = NULL;
1703 if (*dir == ' ') { /* space unsets the variable */
1708 GIOChannel *chan = NULL;
1709 GError *error = NULL;
1710 gchar *path = build_stream_name(FIFO, dir);
1712 if (!file_exists(path)) {
1713 if (mkfifo (path, 0666) == 0) {
1714 // we don't really need to write to the file, but if we open the file as 'r' we will block here, waiting for a writer to open the file.
1715 chan = g_io_channel_new_file(path, "r+", &error);
1717 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1718 if (uzbl.state.verbose)
1719 printf ("init_fifo: created successfully as %s\n", path);
1720 uzbl.comm.fifo_path = path;
1722 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1723 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1724 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1725 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1727 /* if we got this far, there was an error; cleanup */
1728 if (error) g_error_free (error);
1735 control_stdin(GIOChannel *gio, GIOCondition condition) {
1737 gchar *ctl_line = NULL;
1740 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1741 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1744 parse_cmd_line(ctl_line);
1752 GIOChannel *chan = NULL;
1753 GError *error = NULL;
1755 chan = g_io_channel_unix_new(fileno(stdin));
1757 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1758 g_error ("Stdin: could not add watch\n");
1760 if (uzbl.state.verbose)
1761 printf ("Stdin: watch added successfully\n");
1764 g_error ("Stdin: Error while opening: %s\n", error->message);
1766 if (error) g_error_free (error);
1770 control_socket(GIOChannel *chan) {
1771 struct sockaddr_un remote;
1772 char buffer[512], *ctl_line;
1774 int sock, clientsock, n, done;
1777 sock = g_io_channel_unix_get_fd(chan);
1779 memset (buffer, 0, sizeof (buffer));
1781 t = sizeof (remote);
1782 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1786 memset (temp, 0, sizeof (temp));
1787 n = recv (clientsock, temp, 128, 0);
1789 buffer[strlen (buffer)] = '\0';
1793 strcat (buffer, temp);
1796 if (strcmp (buffer, "\n") < 0) {
1797 buffer[strlen (buffer) - 1] = '\0';
1799 buffer[strlen (buffer)] = '\0';
1802 ctl_line = g_strdup(buffer);
1803 parse_cmd_line (ctl_line);
1806 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1807 GError *error = NULL;
1810 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1811 if (ret == G_IO_STATUS_ERROR)
1812 g_error ("Error reading: %s\n", error->message);
1814 printf("Got line %s (%u bytes) \n",ctl_line, len);
1816 parse_line(ctl_line);
1824 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1825 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1826 if (unlink(uzbl.comm.socket_path) == -1)
1827 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1828 g_free(uzbl.comm.socket_path);
1829 uzbl.comm.socket_path = NULL;
1837 GIOChannel *chan = NULL;
1839 struct sockaddr_un local;
1840 gchar *path = build_stream_name(SOCKET, dir);
1842 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1844 local.sun_family = AF_UNIX;
1845 strcpy (local.sun_path, path);
1846 unlink (local.sun_path);
1848 len = strlen (local.sun_path) + sizeof (local.sun_family);
1849 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1850 if (uzbl.state.verbose)
1851 printf ("init_socket: opened in %s\n", path);
1854 if( (chan = g_io_channel_unix_new(sock)) ) {
1855 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1856 uzbl.comm.socket_path = path;
1859 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1861 /* if we got this far, there was an error; cleanup */
1868 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1869 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1871 // this function may be called very early when the templates are not set (yet), hence the checks
1873 update_title (void) {
1874 Behaviour *b = &uzbl.behave;
1877 if (b->show_status) {
1878 if (b->title_format_short) {
1879 parsed = expand_template(b->title_format_short, FALSE);
1880 if (uzbl.gui.main_window)
1881 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1884 if (b->status_format) {
1885 parsed = expand_template(b->status_format, TRUE);
1886 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1889 if (b->status_background) {
1891 gdk_color_parse (b->status_background, &color);
1892 //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)
1893 if (uzbl.gui.main_window)
1894 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1897 if (b->title_format_long) {
1898 parsed = expand_template(b->title_format_long, FALSE);
1899 if (uzbl.gui.main_window)
1900 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1907 key_press_cb (GtkWidget* window, GdkEventKey* event)
1909 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1913 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1914 || 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)
1917 /* turn off insert mode (if always_insert_mode is not used) */
1918 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1919 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1924 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1927 if (event->keyval == GDK_Escape) {
1928 g_string_truncate(uzbl.state.keycmd, 0);
1930 dehilight(uzbl.gui.web_view, NULL);
1934 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1935 if (event->keyval == GDK_Insert) {
1937 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1938 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1940 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1943 g_string_append (uzbl.state.keycmd, str);
1950 if (event->keyval == GDK_BackSpace)
1951 keycmd_bs(NULL, NULL);
1953 gboolean key_ret = FALSE;
1954 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1956 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1958 run_keycmd(key_ret);
1960 if (key_ret) return (!uzbl.behave.insert_mode);
1965 run_keycmd(const gboolean key_ret) {
1966 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1968 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1969 g_string_truncate(uzbl.state.keycmd, 0);
1970 parse_command(act->name, act->param);
1974 /* try if it's an incremental keycmd or one that takes args, and run it */
1975 GString* short_keys = g_string_new ("");
1976 GString* short_keys_inc = g_string_new ("");
1978 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1979 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1980 g_string_assign(short_keys_inc, short_keys->str);
1981 g_string_append_c(short_keys, '_');
1982 g_string_append_c(short_keys_inc, '*');
1984 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1985 /* run normal cmds only if return was pressed */
1986 exec_paramcmd(act, i);
1987 g_string_truncate(uzbl.state.keycmd, 0);
1989 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1990 if (key_ret) /* just quit the incremental command on return */
1991 g_string_truncate(uzbl.state.keycmd, 0);
1992 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1996 g_string_truncate(short_keys, short_keys->len - 1);
1998 g_string_free (short_keys, TRUE);
1999 g_string_free (short_keys_inc, TRUE);
2003 exec_paramcmd(const Action *act, const guint i) {
2004 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2005 GString *actionname = g_string_new ("");
2006 GString *actionparam = g_string_new ("");
2007 g_string_erase (parampart, 0, i+1);
2009 g_string_printf (actionname, act->name, parampart->str);
2011 g_string_printf (actionparam, act->param, parampart->str);
2012 parse_command(actionname->str, actionparam->str);
2013 g_string_free(actionname, TRUE);
2014 g_string_free(actionparam, TRUE);
2015 g_string_free(parampart, TRUE);
2023 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2024 //main_window_ref = g_object_ref(scrolled_window);
2025 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
2027 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2028 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2030 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2031 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2032 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2033 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2034 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2035 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2036 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2037 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2038 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2039 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2040 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2042 return scrolled_window;
2049 g->mainbar = gtk_hbox_new (FALSE, 0);
2051 /* keep a reference to the bar so we can re-pack it at runtime*/
2052 //sbar_ref = g_object_ref(g->mainbar);
2054 g->mainbar_label = gtk_label_new ("");
2055 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2056 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2057 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2058 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2059 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2060 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2065 GtkWidget* create_window () {
2066 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2067 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2068 gtk_widget_set_name (window, "Uzbl browser");
2069 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2070 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2076 GtkPlug* create_plug () {
2077 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2078 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2079 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2086 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2088 If actname is one that calls an external command, this function will inject
2089 newargs in front of the user-provided args in that command line. They will
2090 come become after the body of the script (in sh) or after the name of
2091 the command to execute (in spawn).
2092 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2093 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2095 The return value consist of two strings: the action (sh, ...) and its args.
2097 If act is not one that calls an external command, then the given action merely
2100 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2101 gchar *actdup = g_strdup(actname);
2102 g_array_append_val(rets, actdup);
2104 if ((g_strcmp0(actname, "spawn") == 0) ||
2105 (g_strcmp0(actname, "sh") == 0) ||
2106 (g_strcmp0(actname, "sync_spawn") == 0) ||
2107 (g_strcmp0(actname, "sync_sh") == 0)) {
2109 GString *a = g_string_new("");
2110 gchar **spawnparts = split_quoted(origargs, FALSE);
2111 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2112 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2114 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2115 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2117 g_array_append_val(rets, a->str);
2118 g_string_free(a, FALSE);
2119 g_strfreev(spawnparts);
2121 gchar *origdup = g_strdup(origargs);
2122 g_array_append_val(rets, origdup);
2124 return (gchar**)g_array_free(rets, FALSE);
2128 run_handler (const gchar *act, const gchar *args) {
2129 /* Consider this code a temporary hack to make the handlers usable.
2130 In practice, all this splicing, injection, and reconstruction is
2131 inefficient, annoying and hard to manage. Potential pitfalls arise
2132 when the handler specific args 1) are not quoted (the handler
2133 callbacks should take care of this) 2) are quoted but interfere
2134 with the users' own quotation. A more ideal solution is
2135 to refactor parse_command so that it doesn't just take a string
2136 and execute it; rather than that, we should have a function which
2137 returns the argument vector parsed from the string. This vector
2138 could be modified (e.g. insert additional args into it) before
2139 passing it to the next function that actually executes it. Though
2140 it still isn't perfect for chain actions.. will reconsider & re-
2141 factor when I have the time. -duc */
2143 char **parts = g_strsplit(act, " ", 2);
2145 if (g_strcmp0(parts[0], "chain") == 0) {
2146 GString *newargs = g_string_new("");
2147 gchar **chainparts = split_quoted(parts[1], FALSE);
2149 /* for every argument in the chain, inject the handler args
2150 and make sure the new parts are wrapped in quotes */
2151 gchar **cp = chainparts;
2153 gchar *quotless = NULL;
2154 gchar **spliced_quotless = NULL; // sigh -_-;
2155 gchar **inpart = NULL;
2158 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2160 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2161 } else quotless = g_strdup(*cp);
2163 spliced_quotless = g_strsplit(quotless, " ", 2);
2164 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2165 g_strfreev(spliced_quotless);
2167 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2173 parse_command(parts[0], &(newargs->str[1]));
2174 g_string_free(newargs, TRUE);
2175 g_strfreev(chainparts);
2178 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2179 parse_command(inparts[0], inparts[1]);
2187 add_binding (const gchar *key, const gchar *act) {
2188 char **parts = g_strsplit(act, " ", 2);
2195 if (uzbl.state.verbose)
2196 printf ("Binding %-10s : %s\n", key, act);
2197 action = new_action(parts[0], parts[1]);
2199 if (g_hash_table_remove (uzbl.bindings, key))
2200 g_warning ("Overwriting existing binding for \"%s\"", key);
2201 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2206 get_xdg_var (XDG_Var xdg) {
2207 const gchar* actual_value = getenv (xdg.environmental);
2208 const gchar* home = getenv ("HOME");
2209 gchar* return_value;
2211 if (! actual_value || strcmp (actual_value, "") == 0) {
2212 if (xdg.default_value) {
2213 return_value = str_replace ("~", home, xdg.default_value);
2215 return_value = NULL;
2218 return_value = str_replace("~", home, actual_value);
2221 return return_value;
2225 find_xdg_file (int xdg_type, char* filename) {
2226 /* xdg_type = 0 => config
2227 xdg_type = 1 => data
2228 xdg_type = 2 => cache*/
2230 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2231 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2234 gchar* temporary_string;
2238 if (! file_exists (temporary_file) && xdg_type != 2) {
2239 buf = get_xdg_var (XDG[3 + xdg_type]);
2240 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2243 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2244 g_free (temporary_file);
2245 temporary_file = g_strconcat (temporary_string, filename, NULL);
2249 //g_free (temporary_string); - segfaults.
2251 if (file_exists (temporary_file)) {
2252 return temporary_file;
2259 State *s = &uzbl.state;
2260 Network *n = &uzbl.net;
2262 for (i = 0; default_config[i].command != NULL; i++) {
2263 parse_cmd_line(default_config[i].command);
2266 if (!s->config_file) {
2267 s->config_file = find_xdg_file (0, "/uzbl/config");
2270 if (s->config_file) {
2271 GArray* lines = read_file_by_line (s->config_file);
2275 while ((line = g_array_index(lines, gchar*, i))) {
2276 parse_cmd_line (line);
2280 g_array_free (lines, TRUE);
2282 if (uzbl.state.verbose)
2283 printf ("No configuration file loaded.\n");
2286 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2289 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2292 if (!uzbl.behave.cookie_handler)
2295 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2296 GString *s = g_string_new ("");
2297 SoupURI * soup_uri = soup_message_get_uri(msg);
2298 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2299 run_handler(uzbl.behave.cookie_handler, s->str);
2301 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2302 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2303 if ( p != NULL ) *p = '\0';
2304 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2306 if (uzbl.comm.sync_stdout)
2307 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2309 g_string_free(s, TRUE);
2313 save_cookies (SoupMessage *msg, gpointer user_data){
2317 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2318 cookie = soup_cookie_to_set_cookie_header(ck->data);
2319 SoupURI * soup_uri = soup_message_get_uri(msg);
2320 GString *s = g_string_new ("");
2321 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2322 run_handler(uzbl.behave.cookie_handler, s->str);
2324 g_string_free(s, TRUE);
2329 /* --- WEBINSPECTOR --- */
2331 hide_window_cb(GtkWidget *widget, gpointer data) {
2334 gtk_widget_hide(widget);
2337 static WebKitWebView*
2338 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2341 (void) web_inspector;
2342 GtkWidget* scrolled_window;
2343 GtkWidget* new_web_view;
2346 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2347 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2348 G_CALLBACK(hide_window_cb), NULL);
2350 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2351 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2352 gtk_widget_show(g->inspector_window);
2354 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2355 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2356 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2357 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2358 gtk_widget_show(scrolled_window);
2360 new_web_view = webkit_web_view_new();
2361 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2363 return WEBKIT_WEB_VIEW(new_web_view);
2367 inspector_show_window_cb (WebKitWebInspector* inspector){
2369 gtk_widget_show(uzbl.gui.inspector_window);
2373 /* TODO: Add variables and code to make use of these functions */
2375 inspector_close_window_cb (WebKitWebInspector* inspector){
2381 inspector_attach_window_cb (WebKitWebInspector* inspector){
2387 inspector_detach_window_cb (WebKitWebInspector* inspector){
2393 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2399 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2405 set_up_inspector() {
2407 WebKitWebSettings *settings = view_settings();
2408 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2410 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2411 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2412 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2413 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2414 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2415 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2416 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2418 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2422 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2424 uzbl_cmdprop *c = v;
2429 if(c->type == TYPE_STR)
2430 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2431 else if(c->type == TYPE_INT)
2432 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2436 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2440 printf("bind %s = %s %s\n", (char *)k ,
2441 (char *)a->name, a->param?(char *)a->param:"");
2446 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2447 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2452 main (int argc, char* argv[]) {
2453 gtk_init (&argc, &argv);
2454 if (!g_thread_supported ())
2455 g_thread_init (NULL);
2456 uzbl.state.executable_path = g_strdup(argv[0]);
2457 uzbl.state.selected_url = NULL;
2458 uzbl.state.searchtx = NULL;
2460 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2461 g_option_context_add_main_entries (context, entries, NULL);
2462 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2463 g_option_context_parse (context, &argc, &argv, NULL);
2464 g_option_context_free(context);
2466 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2467 gboolean verbose_override = uzbl.state.verbose;
2469 /* initialize hash table */
2470 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2472 uzbl.net.soup_session = webkit_get_default_session();
2473 uzbl.state.keycmd = g_string_new("");
2475 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2476 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2477 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2478 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2479 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2480 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2483 if(uname(&uzbl.state.unameinfo) == -1)
2484 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2486 uzbl.gui.sbar.progress_s = g_strdup("=");
2487 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2488 uzbl.gui.sbar.progress_w = 10;
2490 /* HTML mode defaults*/
2491 uzbl.behave.html_buffer = g_string_new("");
2492 uzbl.behave.html_endmarker = g_strdup(".");
2493 uzbl.behave.html_timeout = 60;
2494 uzbl.behave.base_url = g_strdup("http://invalid");
2496 /* default mode indicators */
2497 uzbl.behave.insert_indicator = g_strdup("I");
2498 uzbl.behave.cmd_indicator = g_strdup("C");
2502 make_var_to_name_hash();
2504 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2506 uzbl.gui.scrolled_win = create_browser();
2509 /* initial packing */
2510 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2511 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2513 if (uzbl.state.socket_id) {
2514 uzbl.gui.plug = create_plug ();
2515 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2516 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2518 uzbl.gui.main_window = create_window ();
2519 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2520 gtk_widget_show_all (uzbl.gui.main_window);
2521 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2524 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2526 if (uzbl.state.verbose) {
2527 printf("Uzbl start location: %s\n", argv[0]);
2528 if (uzbl.state.socket_id)
2529 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2531 printf("window_id %i\n",(int) uzbl.xwin);
2532 printf("pid %i\n", getpid ());
2533 printf("name: %s\n", uzbl.state.instance_name);
2536 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2537 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2538 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2539 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2540 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2544 if (!uzbl.behave.show_status)
2545 gtk_widget_hide(uzbl.gui.mainbar);
2554 if (verbose_override > uzbl.state.verbose)
2555 uzbl.state.verbose = verbose_override;
2558 set_var_value("uri", uri_override);
2559 g_free(uri_override);
2560 } else if (uzbl.state.uri)
2561 cmd_load_uri(uzbl.gui.web_view, NULL);
2566 return EXIT_SUCCESS;
2569 /* vi: set et ts=4: */