1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
45 #include <webkit/webkit.h>
53 #include <sys/socket.h>
55 #include <libsoup/soup.h>
61 typedef void (*Command)(WebKitWebView*, GArray *argv);
65 /* commandline arguments (set initial values for the state variables) */
67 GOptionEntry entries[] =
69 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
70 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
71 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
72 "Whether to print all messages or just errors.", NULL },
73 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
74 "Name of the current instance (defaults to Xorg window id)", "NAME" },
75 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
76 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
77 { NULL, 0, 0, 0, NULL, NULL, NULL }
80 /* associate command names to their properties */
81 typedef const struct {
88 enum {TYPE_INT, TYPE_STR};
90 /* an abbreviation to help keep the table's width humane */
91 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
96 } var_name_to_ptr[] = {
97 /* variable name pointer to variable in code type dump callback function */
98 /* --------------------------------------------------------------------------------------- */
99 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
118 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
119 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
120 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
121 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
122 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
123 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
124 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
125 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
126 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
127 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
128 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
129 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
130 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
131 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
132 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
133 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
134 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
135 /* exported WebKitWebSettings properties*/
136 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
137 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
138 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
139 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
140 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
141 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
142 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
143 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
144 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
145 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
146 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
147 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
148 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
149 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
150 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
152 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
153 }, *n2v_p = var_name_to_ptr;
159 { "SHIFT", GDK_SHIFT_MASK }, // shift
160 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
161 { "CONTROL", GDK_CONTROL_MASK }, // control
162 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
163 { "MOD2", GDK_MOD2_MASK }, // 5th mod
164 { "MOD3", GDK_MOD3_MASK }, // 6th mod
165 { "MOD4", GDK_MOD4_MASK }, // 7th mod
166 { "MOD5", GDK_MOD5_MASK }, // 8th mod
167 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
168 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
169 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
170 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
171 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
172 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
173 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
174 { "META", GDK_META_MASK }, // meta (since 2.10)
179 /* construct a hash from the var_name_to_ptr array for quick access */
181 make_var_to_name_hash() {
182 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
184 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
189 /* --- UTILITY FUNCTIONS --- */
191 expand_vars(char *s) {
192 char ret[256], /* 256 chars per var name should be safe */
196 GString *buf = g_string_new("");
199 /* found quotation char */
201 g_string_append_c(buf, *++s);
210 if( (vend = strchr(s, upto)) ||
211 (vend = strchr(s, '\0')) ) {
212 strncpy(ret, s, vend-s);
214 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
215 if(c->type == TYPE_STR)
216 g_string_append(buf, (gchar *)*c->ptr);
217 else if(c->type == TYPE_INT) {
218 char *b = itos((int)*c->ptr);
219 g_string_append(buf, b);
230 /* every other char */
232 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 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
403 if (uzbl.state.selected_url != NULL) {
404 if (uzbl.state.verbose)
405 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
406 new_window_load_uri(uzbl.state.selected_url);
408 if (uzbl.state.verbose)
409 printf("New web view -> %s\n","Nothing to open, exiting");
415 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
418 if (uzbl.behave.download_handler) {
419 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
420 if (uzbl.state.verbose)
421 printf("Download -> %s\n",uri);
422 /* if urls not escaped, we may have to escape and quote uri before this call */
423 run_handler(uzbl.behave.download_handler, uri);
428 /* scroll a bar in a given direction */
430 scroll (GtkAdjustment* bar, GArray *argv) {
434 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
435 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
436 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
440 scroll_begin(WebKitWebView* page, GArray *argv) {
441 (void) page; (void) argv;
442 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
446 scroll_end(WebKitWebView* page, GArray *argv) {
447 (void) page; (void) argv;
448 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
449 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
453 scroll_vert(WebKitWebView* page, GArray *argv) {
455 scroll(uzbl.gui.bar_v, argv);
459 scroll_horz(WebKitWebView* page, GArray *argv) {
461 scroll(uzbl.gui.bar_h, argv);
466 if (!uzbl.behave.show_status) {
467 gtk_widget_hide(uzbl.gui.mainbar);
469 gtk_widget_show(uzbl.gui.mainbar);
475 toggle_status_cb (WebKitWebView* page, GArray *argv) {
479 if (uzbl.behave.show_status) {
480 gtk_widget_hide(uzbl.gui.mainbar);
482 gtk_widget_show(uzbl.gui.mainbar);
484 uzbl.behave.show_status = !uzbl.behave.show_status;
489 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
493 //Set selected_url state variable
494 g_free(uzbl.state.selected_url);
495 uzbl.state.selected_url = NULL;
497 uzbl.state.selected_url = g_strdup(link);
503 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
507 if (uzbl.gui.main_title)
508 g_free (uzbl.gui.main_title);
509 uzbl.gui.main_title = g_strdup (title);
514 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
517 uzbl.gui.sbar.load_progress = progress;
522 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
526 if (uzbl.behave.load_finish_handler)
527 run_handler(uzbl.behave.load_finish_handler, "");
531 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
535 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
536 if (uzbl.behave.load_start_handler)
537 run_handler(uzbl.behave.load_start_handler, "");
541 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
544 g_free (uzbl.state.uri);
545 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
546 uzbl.state.uri = g_string_free (newuri, FALSE);
547 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
548 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
551 if (uzbl.behave.load_commit_handler)
552 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
556 destroy_cb (GtkWidget* widget, gpointer data) {
564 if (uzbl.behave.history_handler) {
566 struct tm * timeinfo;
569 timeinfo = localtime ( &rawtime );
570 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
571 run_handler(uzbl.behave.history_handler, date);
576 /* VIEW funcs (little webkit wrappers) */
577 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
579 VIEWFUNC(reload_bypass_cache)
580 VIEWFUNC(stop_loading)
587 /* -- command to callback/function map for things we cannot attach to any signals */
589 static struct {char *name; Command command[2];} cmdlist[] =
590 { /* key function no_split */
591 { "back", {view_go_back, 0} },
592 { "forward", {view_go_forward, 0} },
593 { "scroll_vert", {scroll_vert, 0} },
594 { "scroll_horz", {scroll_horz, 0} },
595 { "scroll_begin", {scroll_begin, 0} },
596 { "scroll_end", {scroll_end, 0} },
597 { "reload", {view_reload, 0}, },
598 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
599 { "stop", {view_stop_loading, 0}, },
600 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
601 { "zoom_out", {view_zoom_out, 0}, },
602 { "uri", {load_uri, NOSPLIT} },
603 { "js", {run_js, NOSPLIT} },
604 { "script", {run_external_js, 0} },
605 { "toggle_status", {toggle_status_cb, 0} },
606 { "spawn", {spawn, 0} },
607 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
608 { "sh", {spawn_sh, 0} },
609 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
610 { "exit", {close_uzbl, 0} },
611 { "search", {search_forward_text, NOSPLIT} },
612 { "search_reverse", {search_reverse_text, NOSPLIT} },
613 { "dehilight", {dehilight, 0} },
614 { "toggle_insert_mode", {toggle_insert_mode, 0} },
615 { "set", {set_var, NOSPLIT} },
616 { "get", {get_var, NOSPLIT} },
617 { "bind", {act_bind, NOSPLIT} },
618 { "dump_config", {act_dump_config, 0} },
619 { "keycmd", {keycmd, NOSPLIT} },
620 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
621 { "keycmd_bs", {keycmd_bs, 0} },
622 { "chain", {chain, 0} }
629 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
631 for (i = 0; i < LENGTH(cmdlist); i++)
632 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
635 /* -- CORE FUNCTIONS -- */
638 free_action(gpointer act) {
639 Action *action = (Action*)act;
640 g_free(action->name);
642 g_free(action->param);
647 new_action(const gchar *name, const gchar *param) {
648 Action *action = g_new(Action, 1);
650 action->name = g_strdup(name);
652 action->param = g_strdup(param);
654 action->param = NULL;
660 file_exists (const char * filename) {
661 return (access(filename, F_OK) == 0);
665 set_var(WebKitWebView *page, GArray *argv) {
667 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
668 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
669 set_var_value(g_strstrip(split[0]), value);
675 get_var(WebKitWebView *page, GArray *argv) {
677 get_var_value(argv_idx(argv, 0));
681 act_bind(WebKitWebView *page, GArray *argv) {
683 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
684 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
685 add_binding(g_strstrip(split[0]), value);
697 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
700 if (argv_idx(argv, 0)) {
701 if (strcmp (argv_idx(argv, 0), "0") == 0) {
702 uzbl.behave.insert_mode = FALSE;
704 uzbl.behave.insert_mode = TRUE;
707 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
714 load_uri (WebKitWebView *web_view, GArray *argv) {
715 if (argv_idx(argv, 0)) {
716 GString* newuri = g_string_new (argv_idx(argv, 0));
717 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
718 g_string_prepend (newuri, "http://");
719 /* if we do handle cookies, ask our handler for them */
720 webkit_web_view_load_uri (web_view, newuri->str);
721 g_string_free (newuri, TRUE);
726 run_js (WebKitWebView * web_view, GArray *argv) {
727 if (argv_idx(argv, 0))
728 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
732 run_external_js (WebKitWebView * web_view, GArray *argv) {
733 if (argv_idx(argv, 0)) {
734 GArray* lines = read_file_by_line (argv_idx (argv, 0));
739 while ((line = g_array_index(lines, gchar*, i))) {
741 js = g_strdup (line);
743 gchar* newjs = g_strconcat (js, line, NULL);
750 if (uzbl.state.verbose)
751 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
753 if (argv_idx (argv, 1)) {
754 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
758 webkit_web_view_execute_script (web_view, js);
760 g_array_free (lines, TRUE);
765 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
766 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
767 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
768 webkit_web_view_unmark_text_matches (page);
769 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
770 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
774 if (uzbl.state.searchtx) {
775 if (uzbl.state.verbose)
776 printf ("Searching: %s\n", uzbl.state.searchtx);
777 webkit_web_view_set_highlight_text_matches (page, TRUE);
778 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
783 search_forward_text (WebKitWebView *page, GArray *argv) {
784 search_text(page, argv, TRUE);
788 search_reverse_text (WebKitWebView *page, GArray *argv) {
789 search_text(page, argv, FALSE);
793 dehilight (WebKitWebView *page, GArray *argv) {
795 webkit_web_view_set_highlight_text_matches (page, FALSE);
800 new_window_load_uri (const gchar * uri) {
801 GString* to_execute = g_string_new ("");
802 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
804 for (i = 0; entries[i].long_name != NULL; i++) {
805 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
806 gchar** str = (gchar**)entries[i].arg_data;
808 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
812 if (uzbl.state.verbose)
813 printf("\n%s\n", to_execute->str);
814 g_spawn_command_line_async (to_execute->str, NULL);
815 g_string_free (to_execute, TRUE);
819 chain (WebKitWebView *page, GArray *argv) {
822 gchar **parts = NULL;
824 while ((a = argv_idx(argv, i++))) {
825 parts = g_strsplit (a, " ", 2);
826 parse_command(parts[0], parts[1]);
832 keycmd (WebKitWebView *page, GArray *argv) {
835 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
841 keycmd_nl (WebKitWebView *page, GArray *argv) {
844 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
850 keycmd_bs (WebKitWebView *page, GArray *argv) {
853 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
858 close_uzbl (WebKitWebView *page, GArray *argv) {
864 /* --Statusbar functions-- */
866 build_progressbar_ascii(int percent) {
867 int width=uzbl.gui.sbar.progress_w;
870 GString *bar = g_string_new("");
872 l = (double)percent*((double)width/100.);
873 l = (int)(l+.5)>=(int)l ? l+.5 : l;
875 for(i=0; i<(int)l; i++)
876 g_string_append(bar, uzbl.gui.sbar.progress_s);
879 g_string_append(bar, uzbl.gui.sbar.progress_u);
881 return g_string_free(bar, FALSE);
886 const GScannerConfig scan_config = {
889 ) /* cset_skip_characters */,
894 ) /* cset_identifier_first */,
901 ) /* cset_identifier_nth */,
902 ( "" ) /* cpair_comment_single */,
904 TRUE /* case_sensitive */,
906 FALSE /* skip_comment_multi */,
907 FALSE /* skip_comment_single */,
908 FALSE /* scan_comment_multi */,
909 TRUE /* scan_identifier */,
910 TRUE /* scan_identifier_1char */,
911 FALSE /* scan_identifier_NULL */,
912 TRUE /* scan_symbols */,
913 FALSE /* scan_binary */,
914 FALSE /* scan_octal */,
915 FALSE /* scan_float */,
916 FALSE /* scan_hex */,
917 FALSE /* scan_hex_dollar */,
918 FALSE /* scan_string_sq */,
919 FALSE /* scan_string_dq */,
920 TRUE /* numbers_2_int */,
921 FALSE /* int_2_float */,
922 FALSE /* identifier_2_string */,
923 FALSE /* char_2_token */,
924 FALSE /* symbol_2_token */,
925 TRUE /* scope_0_fallback */,
930 uzbl.scan = g_scanner_new(&scan_config);
931 while(symp->symbol_name) {
932 g_scanner_scope_add_symbol(uzbl.scan, 0,
934 GINT_TO_POINTER(symp->symbol_token));
940 expand_template(const char *template, gboolean escape_markup) {
941 if(!template) return NULL;
943 GTokenType token = G_TOKEN_NONE;
944 GString *ret = g_string_new("");
948 g_scanner_input_text(uzbl.scan, template, strlen(template));
949 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
950 token = g_scanner_get_next_token(uzbl.scan);
952 if(token == G_TOKEN_SYMBOL) {
953 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
957 buf = uzbl.state.uri?
958 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
959 g_string_append(ret, buf);
963 g_string_append(ret, uzbl.state.uri?
964 uzbl.state.uri:g_strdup(""));
967 buf = itos(uzbl.gui.sbar.load_progress);
968 g_string_append(ret, buf);
971 case SYM_LOADPRGSBAR:
972 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
973 g_string_append(ret, buf);
978 buf = uzbl.gui.main_title?
979 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
980 g_string_append(ret, buf);
984 g_string_append(ret, uzbl.gui.main_title?
985 uzbl.gui.main_title:g_strdup(""));
987 case SYM_SELECTED_URI:
989 buf = uzbl.state.selected_url?
990 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
991 g_string_append(ret, buf);
995 g_string_append(ret, uzbl.state.selected_url?
996 uzbl.state.selected_url:g_strdup(""));
999 buf = itos(uzbl.xwin);
1000 g_string_append(ret,
1001 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1006 buf = uzbl.state.keycmd->str?
1007 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1008 g_string_append(ret, buf);
1012 g_string_append(ret, uzbl.state.keycmd->str?
1013 uzbl.state.keycmd->str:g_strdup(""));
1016 g_string_append(ret,
1017 uzbl.behave.insert_mode?
1018 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1021 g_string_append(ret,
1022 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1024 /* useragent syms */
1026 buf = itos(WEBKIT_MAJOR_VERSION);
1027 g_string_append(ret, buf);
1031 buf = itos(WEBKIT_MINOR_VERSION);
1032 g_string_append(ret, buf);
1036 buf = itos(WEBKIT_MICRO_VERSION);
1037 g_string_append(ret, buf);
1041 g_string_append(ret, uzbl.state.unameinfo.sysname);
1044 g_string_append(ret, uzbl.state.unameinfo.nodename);
1047 g_string_append(ret, uzbl.state.unameinfo.release);
1050 g_string_append(ret, uzbl.state.unameinfo.version);
1053 g_string_append(ret, uzbl.state.unameinfo.machine);
1056 g_string_append(ret, ARCH);
1059 case SYM_DOMAINNAME:
1060 g_string_append(ret, uzbl.state.unameinfo.domainname);
1064 g_string_append(ret, COMMIT);
1070 else if(token == G_TOKEN_INT) {
1071 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1072 g_string_append(ret, buf);
1075 else if(token == G_TOKEN_IDENTIFIER) {
1076 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1078 else if(token == G_TOKEN_CHAR) {
1079 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1083 return g_string_free(ret, FALSE);
1085 /* --End Statusbar functions-- */
1088 sharg_append(GArray *a, const gchar *str) {
1089 const gchar *s = (str ? str : "");
1090 g_array_append_val(a, s);
1093 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1095 run_command (const gchar *command, const guint npre, const gchar **args,
1096 const gboolean sync, char **stdout) {
1097 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1100 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1101 gchar *pid = itos(getpid());
1102 gchar *xwin = itos(uzbl.xwin);
1104 sharg_append(a, command);
1105 for (i = 0; i < npre; i++) /* add n args before the default vars */
1106 sharg_append(a, args[i]);
1107 sharg_append(a, uzbl.state.config_file);
1108 sharg_append(a, pid);
1109 sharg_append(a, xwin);
1110 sharg_append(a, uzbl.comm.fifo_path);
1111 sharg_append(a, uzbl.comm.socket_path);
1112 sharg_append(a, uzbl.state.uri);
1113 sharg_append(a, uzbl.gui.main_title);
1115 for (i = npre; i < g_strv_length((gchar**)args); i++)
1116 sharg_append(a, args[i]);
1120 if (*stdout) *stdout = strfree(*stdout);
1122 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1123 NULL, NULL, stdout, NULL, NULL, &err);
1124 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1125 NULL, NULL, NULL, &err);
1127 if (uzbl.state.verbose) {
1128 GString *s = g_string_new("spawned:");
1129 for (i = 0; i < (a->len); i++) {
1130 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1131 g_string_append_printf(s, " %s", qarg);
1134 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1135 printf("%s\n", s->str);
1136 g_string_free(s, TRUE);
1139 g_printerr("error on run_command: %s\n", err->message);
1144 g_array_free (a, TRUE);
1149 split_quoted(const gchar* src, const gboolean unquote) {
1150 /* split on unquoted space, return array of strings;
1151 remove a layer of quotes and backslashes if unquote */
1152 if (!src) return NULL;
1154 gboolean dq = FALSE;
1155 gboolean sq = FALSE;
1156 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1157 GString *s = g_string_new ("");
1161 for (p = src; *p != '\0'; p++) {
1162 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1163 else if (*p == '\\') { g_string_append_c(s, *p++);
1164 g_string_append_c(s, *p); }
1165 else if ((*p == '"') && unquote && !sq) dq = !dq;
1166 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1168 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1169 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1171 else if ((*p == ' ') && !dq && !sq) {
1172 dup = g_strdup(s->str);
1173 g_array_append_val(a, dup);
1174 g_string_truncate(s, 0);
1175 } else g_string_append_c(s, *p);
1177 dup = g_strdup(s->str);
1178 g_array_append_val(a, dup);
1179 ret = (gchar**)a->data;
1180 g_array_free (a, FALSE);
1181 g_string_free (s, TRUE);
1186 spawn(WebKitWebView *web_view, GArray *argv) {
1188 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1189 if (argv_idx(argv, 0))
1190 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1194 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1197 if (argv_idx(argv, 0))
1198 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1199 TRUE, &uzbl.comm.sync_stdout);
1203 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1205 if (!uzbl.behave.shell_cmd) {
1206 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1211 gchar *spacer = g_strdup("");
1212 g_array_insert_val(argv, 1, spacer);
1213 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1215 for (i = 1; i < g_strv_length(cmd); i++)
1216 g_array_prepend_val(argv, cmd[i]);
1218 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1224 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1226 if (!uzbl.behave.shell_cmd) {
1227 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1232 gchar *spacer = g_strdup("");
1233 g_array_insert_val(argv, 1, spacer);
1234 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1236 for (i = 1; i < g_strv_length(cmd); i++)
1237 g_array_prepend_val(argv, cmd[i]);
1239 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1240 TRUE, &uzbl.comm.sync_stdout);
1246 parse_command(const char *cmd, const char *param) {
1249 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1252 gchar **par = split_quoted(param, TRUE);
1253 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1255 if (c[1] == NOSPLIT) { /* don't split */
1256 sharg_append(a, param);
1258 for (i = 0; i < g_strv_length(par); i++)
1259 sharg_append(a, par[i]);
1261 c[0](uzbl.gui.web_view, a);
1263 g_array_free (a, TRUE);
1266 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1270 get_var_value(const gchar *name) {
1273 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1274 if(c->type == TYPE_STR)
1275 printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr);
1276 else if(c->type == TYPE_INT)
1277 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1286 if(*uzbl.net.proxy_url == ' '
1287 || uzbl.net.proxy_url == NULL) {
1288 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1289 (GType) SOUP_SESSION_PROXY_URI);
1292 suri = soup_uri_new(uzbl.net.proxy_url);
1293 g_object_set(G_OBJECT(uzbl.net.soup_session),
1294 SOUP_SESSION_PROXY_URI,
1296 soup_uri_free(suri);
1303 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1304 g_array_append_val (a, uzbl.state.uri);
1305 load_uri(uzbl.gui.web_view, a);
1306 g_array_free (a, TRUE);
1310 cmd_always_insert_mode() {
1311 uzbl.behave.insert_mode =
1312 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1318 g_object_set(G_OBJECT(uzbl.net.soup_session),
1319 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1323 cmd_max_conns_host() {
1324 g_object_set(G_OBJECT(uzbl.net.soup_session),
1325 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1330 soup_session_remove_feature
1331 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1332 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1333 /*g_free(uzbl.net.soup_logger);*/
1335 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1336 soup_session_add_feature(uzbl.net.soup_session,
1337 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1340 static WebKitWebSettings*
1342 return webkit_web_view_get_settings(uzbl.gui.web_view);
1347 WebKitWebSettings *ws = view_settings();
1348 if (uzbl.behave.font_size > 0) {
1349 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1352 if (uzbl.behave.monospace_size > 0) {
1353 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1354 uzbl.behave.monospace_size, NULL);
1356 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1357 uzbl.behave.font_size, NULL);
1362 cmd_disable_plugins() {
1363 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1364 !uzbl.behave.disable_plugins, NULL);
1368 cmd_disable_scripts() {
1369 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1370 !uzbl.behave.disable_scripts, NULL);
1374 cmd_minimum_font_size() {
1375 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1376 uzbl.behave.minimum_font_size, NULL);
1379 cmd_autoload_img() {
1380 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1381 uzbl.behave.autoload_img, NULL);
1386 cmd_autoshrink_img() {
1387 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1388 uzbl.behave.autoshrink_img, NULL);
1393 cmd_enable_spellcheck() {
1394 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1395 uzbl.behave.enable_spellcheck, NULL);
1399 cmd_enable_private() {
1400 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1401 uzbl.behave.enable_private, NULL);
1406 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1407 uzbl.behave.print_bg, NULL);
1412 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1413 uzbl.behave.style_uri, NULL);
1417 cmd_resizable_txt() {
1418 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1419 uzbl.behave.resizable_txt, NULL);
1423 cmd_default_encoding() {
1424 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1425 uzbl.behave.default_encoding, NULL);
1429 cmd_enforce_96dpi() {
1430 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1431 uzbl.behave.enforce_96dpi, NULL);
1435 cmd_caret_browsing() {
1436 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1437 uzbl.behave.caret_browsing, NULL);
1441 cmd_cookie_handler() {
1442 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1443 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1444 if ((g_strcmp0(split[0], "sh") == 0) ||
1445 (g_strcmp0(split[0], "spawn") == 0)) {
1446 g_free (uzbl.behave.cookie_handler);
1447 uzbl.behave.cookie_handler =
1448 g_strdup_printf("sync_%s %s", split[0], split[1]);
1455 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1460 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1465 if(uzbl.behave.inject_html) {
1466 webkit_web_view_load_html_string (uzbl.gui.web_view,
1467 uzbl.behave.inject_html, NULL);
1476 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1477 uzbl.behave.modmask = 0;
1479 if(uzbl.behave.modkey)
1480 g_free(uzbl.behave.modkey);
1481 uzbl.behave.modkey = buf;
1483 for (i = 0; modkeys[i].key != NULL; i++) {
1484 if (g_strrstr(buf, modkeys[i].key))
1485 uzbl.behave.modmask |= modkeys[i].mask;
1491 if (*uzbl.net.useragent == ' ') {
1492 g_free (uzbl.net.useragent);
1493 uzbl.net.useragent = NULL;
1495 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1497 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1498 g_free(uzbl.net.useragent);
1499 uzbl.net.useragent = ua;
1505 gtk_widget_ref(uzbl.gui.scrolled_win);
1506 gtk_widget_ref(uzbl.gui.mainbar);
1507 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1508 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1510 if(uzbl.behave.status_top) {
1511 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1512 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1515 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1516 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1518 gtk_widget_unref(uzbl.gui.scrolled_win);
1519 gtk_widget_unref(uzbl.gui.mainbar);
1520 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1525 set_var_value(gchar *name, gchar *val) {
1526 uzbl_cmdprop *c = NULL;
1530 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1531 /* check for the variable type */
1532 if (c->type == TYPE_STR) {
1533 buf = expand_vars(val);
1536 } else if(c->type == TYPE_INT) {
1537 int *ip = (int *)c->ptr;
1538 buf = expand_vars(val);
1539 *ip = (int)strtoul(buf, &endp, 10);
1543 /* invoke a command specific function */
1544 if(c->func) c->func();
1551 Behaviour *b = &uzbl.behave;
1553 if(b->html_buffer->str) {
1554 webkit_web_view_load_html_string (uzbl.gui.web_view,
1555 b->html_buffer->str, b->base_url);
1556 g_string_free(b->html_buffer, TRUE);
1557 b->html_buffer = g_string_new("");
1561 enum {M_CMD, M_HTML};
1563 parse_cmd_line(const char *ctl_line) {
1564 Behaviour *b = &uzbl.behave;
1567 if(b->mode == M_HTML) {
1568 len = strlen(b->html_endmarker);
1569 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1570 if(len == strlen(ctl_line)-1 &&
1571 !strncmp(b->html_endmarker, ctl_line, len)) {
1573 set_var_value("mode", "0");
1578 set_timeout(b->html_timeout);
1579 g_string_append(b->html_buffer, ctl_line);
1582 else if((ctl_line[0] == '#') /* Comments */
1583 || (ctl_line[0] == ' ')
1584 || (ctl_line[0] == '\n'))
1585 ; /* ignore these lines */
1586 else { /* parse a command */
1588 gchar **tokens = NULL;
1590 if (ctl_line[strlen(ctl_line) - 1] == '\n') /* strip trailing newline */
1591 ctlstrip = g_strndup(ctl_line, strlen(ctl_line) - 1);
1592 else ctlstrip = g_strdup(ctl_line);
1594 tokens = g_strsplit(ctlstrip, " ", 2);
1595 parse_command(tokens[0], tokens[1]);
1602 build_stream_name(int type, const gchar* dir) {
1604 State *s = &uzbl.state;
1607 xwin_str = itos((int)uzbl.xwin);
1609 str = g_strdup_printf
1610 ("%s/uzbl_fifo_%s", dir,
1611 s->instance_name ? s->instance_name : xwin_str);
1612 } else if (type == SOCKET) {
1613 str = g_strdup_printf
1614 ("%s/uzbl_socket_%s", dir,
1615 s->instance_name ? s->instance_name : xwin_str );
1622 control_fifo(GIOChannel *gio, GIOCondition condition) {
1623 if (uzbl.state.verbose)
1624 printf("triggered\n");
1629 if (condition & G_IO_HUP)
1630 g_error ("Fifo: Read end of pipe died!\n");
1633 g_error ("Fifo: GIOChannel broke\n");
1635 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1636 if (ret == G_IO_STATUS_ERROR) {
1637 g_error ("Fifo: Error reading: %s\n", err->message);
1641 parse_cmd_line(ctl_line);
1648 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1649 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1650 if (unlink(uzbl.comm.fifo_path) == -1)
1651 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1652 g_free(uzbl.comm.fifo_path);
1653 uzbl.comm.fifo_path = NULL;
1656 if (*dir == ' ') { /* space unsets the variable */
1661 GIOChannel *chan = NULL;
1662 GError *error = NULL;
1663 gchar *path = build_stream_name(FIFO, dir);
1665 if (!file_exists(path)) {
1666 if (mkfifo (path, 0666) == 0) {
1667 // 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.
1668 chan = g_io_channel_new_file(path, "r+", &error);
1670 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1671 if (uzbl.state.verbose)
1672 printf ("init_fifo: created successfully as %s\n", path);
1673 uzbl.comm.fifo_path = path;
1675 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1676 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1677 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1678 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1680 /* if we got this far, there was an error; cleanup */
1681 if (error) g_error_free (error);
1688 control_stdin(GIOChannel *gio, GIOCondition condition) {
1690 gchar *ctl_line = NULL;
1693 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1694 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1697 parse_cmd_line(ctl_line);
1705 GIOChannel *chan = NULL;
1706 GError *error = NULL;
1708 chan = g_io_channel_unix_new(fileno(stdin));
1710 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1711 g_error ("Stdin: could not add watch\n");
1713 if (uzbl.state.verbose)
1714 printf ("Stdin: watch added successfully\n");
1717 g_error ("Stdin: Error while opening: %s\n", error->message);
1719 if (error) g_error_free (error);
1723 control_socket(GIOChannel *chan) {
1724 struct sockaddr_un remote;
1725 char buffer[512], *ctl_line;
1727 int sock, clientsock, n, done;
1730 sock = g_io_channel_unix_get_fd(chan);
1732 memset (buffer, 0, sizeof (buffer));
1734 t = sizeof (remote);
1735 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1739 memset (temp, 0, sizeof (temp));
1740 n = recv (clientsock, temp, 128, 0);
1742 buffer[strlen (buffer)] = '\0';
1746 strcat (buffer, temp);
1749 if (strcmp (buffer, "\n") < 0) {
1750 buffer[strlen (buffer) - 1] = '\0';
1752 buffer[strlen (buffer)] = '\0';
1755 ctl_line = g_strdup(buffer);
1756 parse_cmd_line (ctl_line);
1759 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1760 GError *error = NULL;
1763 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1764 if (ret == G_IO_STATUS_ERROR)
1765 g_error ("Error reading: %s\n", error->message);
1767 printf("Got line %s (%u bytes) \n",ctl_line, len);
1769 parse_line(ctl_line);
1777 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1778 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1779 if (unlink(uzbl.comm.socket_path) == -1)
1780 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1781 g_free(uzbl.comm.socket_path);
1782 uzbl.comm.socket_path = NULL;
1790 GIOChannel *chan = NULL;
1792 struct sockaddr_un local;
1793 gchar *path = build_stream_name(SOCKET, dir);
1795 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1797 local.sun_family = AF_UNIX;
1798 strcpy (local.sun_path, path);
1799 unlink (local.sun_path);
1801 len = strlen (local.sun_path) + sizeof (local.sun_family);
1802 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1803 if (uzbl.state.verbose)
1804 printf ("init_socket: opened in %s\n", path);
1807 if( (chan = g_io_channel_unix_new(sock)) ) {
1808 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1809 uzbl.comm.socket_path = path;
1812 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1814 /* if we got this far, there was an error; cleanup */
1821 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1822 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1824 // this function may be called very early when the templates are not set (yet), hence the checks
1826 update_title (void) {
1827 Behaviour *b = &uzbl.behave;
1830 if (b->show_status) {
1831 if (b->title_format_short) {
1832 parsed = expand_template(b->title_format_short, FALSE);
1833 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1836 if (b->status_format) {
1837 parsed = expand_template(b->status_format, TRUE);
1838 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1841 if (b->status_background) {
1843 gdk_color_parse (b->status_background, &color);
1844 //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)
1845 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1848 if (b->title_format_long) {
1849 parsed = expand_template(b->title_format_long, FALSE);
1850 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1857 key_press_cb (GtkWidget* window, GdkEventKey* event)
1859 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1863 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1864 || 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)
1867 /* turn off insert mode (if always_insert_mode is not used) */
1868 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1869 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1874 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1877 if (event->keyval == GDK_Escape) {
1878 g_string_truncate(uzbl.state.keycmd, 0);
1880 dehilight(uzbl.gui.web_view, NULL);
1884 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1885 if (event->keyval == GDK_Insert) {
1887 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1888 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1890 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1893 g_string_append (uzbl.state.keycmd, str);
1900 if (event->keyval == GDK_BackSpace)
1901 keycmd_bs(NULL, NULL);
1903 gboolean key_ret = FALSE;
1904 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1906 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1908 run_keycmd(key_ret);
1910 if (key_ret) return (!uzbl.behave.insert_mode);
1915 run_keycmd(const gboolean key_ret) {
1916 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1918 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1919 g_string_truncate(uzbl.state.keycmd, 0);
1920 parse_command(act->name, act->param);
1924 /* try if it's an incremental keycmd or one that takes args, and run it */
1925 GString* short_keys = g_string_new ("");
1926 GString* short_keys_inc = g_string_new ("");
1928 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1929 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1930 g_string_assign(short_keys_inc, short_keys->str);
1931 g_string_append_c(short_keys, '_');
1932 g_string_append_c(short_keys_inc, '*');
1934 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1935 /* run normal cmds only if return was pressed */
1936 exec_paramcmd(act, i);
1937 g_string_truncate(uzbl.state.keycmd, 0);
1939 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1940 if (key_ret) /* just quit the incremental command on return */
1941 g_string_truncate(uzbl.state.keycmd, 0);
1942 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1946 g_string_truncate(short_keys, short_keys->len - 1);
1948 g_string_free (short_keys, TRUE);
1949 g_string_free (short_keys_inc, TRUE);
1953 exec_paramcmd(const Action *act, const guint i) {
1954 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1955 GString *actionname = g_string_new ("");
1956 GString *actionparam = g_string_new ("");
1957 g_string_erase (parampart, 0, i+1);
1959 g_string_printf (actionname, act->name, parampart->str);
1961 g_string_printf (actionparam, act->param, parampart->str);
1962 parse_command(actionname->str, actionparam->str);
1963 g_string_free(actionname, TRUE);
1964 g_string_free(actionparam, TRUE);
1965 g_string_free(parampart, TRUE);
1973 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1974 //main_window_ref = g_object_ref(scrolled_window);
1975 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
1977 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1978 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1980 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1981 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1982 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1983 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1984 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1985 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1986 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1987 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1988 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1989 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1991 return scrolled_window;
1998 g->mainbar = gtk_hbox_new (FALSE, 0);
2000 /* keep a reference to the bar so we can re-pack it at runtime*/
2001 //sbar_ref = g_object_ref(g->mainbar);
2003 g->mainbar_label = gtk_label_new ("");
2004 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2005 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2006 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2007 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2008 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2013 GtkWidget* create_window () {
2014 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2015 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2016 gtk_widget_set_name (window, "Uzbl browser");
2017 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2018 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2024 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2026 If actname is one that calls an external command, this function will inject
2027 newargs in front of the user-provided args in that command line. They will
2028 come become after the body of the script (in sh) or after the name of
2029 the command to execute (in spawn).
2030 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2031 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2033 The return value consist of two strings: the action (sh, ...) and its args.
2035 If act is not one that calls an external command, then the given action merely
2038 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2039 gchar *actdup = g_strdup(actname);
2040 g_array_append_val(rets, actdup);
2042 if ((g_strcmp0(actname, "spawn") == 0) ||
2043 (g_strcmp0(actname, "sh") == 0) ||
2044 (g_strcmp0(actname, "sync_spawn") == 0) ||
2045 (g_strcmp0(actname, "sync_sh") == 0)) {
2047 GString *a = g_string_new("");
2048 gchar **spawnparts = split_quoted(origargs, FALSE);
2049 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2050 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2052 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2053 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2055 g_array_append_val(rets, a->str);
2056 g_string_free(a, FALSE);
2057 g_strfreev(spawnparts);
2059 gchar *origdup = g_strdup(origargs);
2060 g_array_append_val(rets, origdup);
2062 return (gchar**)g_array_free(rets, FALSE);
2066 run_handler (const gchar *act, const gchar *args) {
2067 /* Consider this code a temporary hack to make the handlers usable.
2068 In practice, all this splicing, injection, and reconstruction is
2069 inefficient, annoying and hard to manage. Potential pitfalls arise
2070 when the handler specific args 1) are not quoted (the handler
2071 callbacks should take care of this) 2) are quoted but interfere
2072 with the users' own quotation. A more ideal solution is
2073 to refactor parse_command so that it doesn't just take a string
2074 and execute it; rather than that, we should have a function which
2075 returns the argument vector parsed from the string. This vector
2076 could be modified (e.g. insert additional args into it) before
2077 passing it to the next function that actually executes it. Though
2078 it still isn't perfect for chain actions.. will reconsider & re-
2079 factor when I have the time. -duc */
2081 char **parts = g_strsplit(act, " ", 2);
2083 if (g_strcmp0(parts[0], "chain") == 0) {
2084 GString *newargs = g_string_new("");
2085 gchar **chainparts = split_quoted(parts[1], FALSE);
2087 /* for every argument in the chain, inject the handler args
2088 and make sure the new parts are wrapped in quotes */
2089 gchar **cp = chainparts;
2091 gchar *quotless = NULL;
2092 gchar **spliced_quotless = NULL; // sigh -_-;
2093 gchar **inpart = NULL;
2096 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2098 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2099 } else quotless = g_strdup(*cp);
2101 spliced_quotless = g_strsplit(quotless, " ", 2);
2102 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2103 g_strfreev(spliced_quotless);
2105 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2111 parse_command(parts[0], &(newargs->str[1]));
2112 g_string_free(newargs, TRUE);
2113 g_strfreev(chainparts);
2116 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2117 parse_command(inparts[0], inparts[1]);
2125 add_binding (const gchar *key, const gchar *act) {
2126 char **parts = g_strsplit(act, " ", 2);
2133 if (uzbl.state.verbose)
2134 printf ("Binding %-10s : %s\n", key, act);
2135 action = new_action(parts[0], parts[1]);
2137 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2142 get_xdg_var (XDG_Var xdg) {
2143 const gchar* actual_value = getenv (xdg.environmental);
2144 const gchar* home = getenv ("HOME");
2146 gchar* return_value = str_replace ("~", home, actual_value);
2148 if (! actual_value || strcmp (actual_value, "") == 0) {
2149 if (xdg.default_value) {
2150 return_value = str_replace ("~", home, xdg.default_value);
2152 return_value = NULL;
2155 return return_value;
2159 find_xdg_file (int xdg_type, char* filename) {
2160 /* xdg_type = 0 => config
2161 xdg_type = 1 => data
2162 xdg_type = 2 => cache*/
2164 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2165 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2168 gchar* temporary_string;
2172 if (! file_exists (temporary_file) && xdg_type != 2) {
2173 buf = get_xdg_var (XDG[3 + xdg_type]);
2174 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2177 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2178 g_free (temporary_file);
2179 temporary_file = g_strconcat (temporary_string, filename, NULL);
2183 //g_free (temporary_string); - segfaults.
2185 if (file_exists (temporary_file)) {
2186 return temporary_file;
2193 State *s = &uzbl.state;
2194 Network *n = &uzbl.net;
2196 for (i = 0; default_config[i].command != NULL; i++) {
2197 parse_cmd_line(default_config[i].command);
2200 if (!s->config_file) {
2201 s->config_file = find_xdg_file (0, "/uzbl/config");
2204 if (s->config_file) {
2205 GArray* lines = read_file_by_line (s->config_file);
2209 while ((line = g_array_index(lines, gchar*, i))) {
2210 parse_cmd_line (line);
2214 g_array_free (lines, TRUE);
2216 if (uzbl.state.verbose)
2217 printf ("No configuration file loaded.\n");
2220 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2223 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2226 if (!uzbl.behave.cookie_handler) return;
2228 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2229 GString *s = g_string_new ("");
2230 SoupURI * soup_uri = soup_message_get_uri(msg);
2231 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2232 run_handler(uzbl.behave.cookie_handler, s->str);
2234 if(uzbl.comm.sync_stdout)
2235 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2236 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2237 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2239 g_string_free(s, TRUE);
2243 save_cookies (SoupMessage *msg, gpointer user_data){
2247 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2248 cookie = soup_cookie_to_set_cookie_header(ck->data);
2249 SoupURI * soup_uri = soup_message_get_uri(msg);
2250 GString *s = g_string_new ("");
2251 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2252 run_handler(uzbl.behave.cookie_handler, s->str);
2254 g_string_free(s, TRUE);
2259 /* --- WEBINSPECTOR --- */
2261 hide_window_cb(GtkWidget *widget, gpointer data) {
2264 gtk_widget_hide(widget);
2267 static WebKitWebView*
2268 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2271 (void) web_inspector;
2272 GtkWidget* scrolled_window;
2273 GtkWidget* new_web_view;
2276 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2277 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2278 G_CALLBACK(hide_window_cb), NULL);
2280 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2281 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2282 gtk_widget_show(g->inspector_window);
2284 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2285 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2286 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2287 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2288 gtk_widget_show(scrolled_window);
2290 new_web_view = webkit_web_view_new();
2291 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2293 return WEBKIT_WEB_VIEW(new_web_view);
2297 inspector_show_window_cb (WebKitWebInspector* inspector){
2299 gtk_widget_show(uzbl.gui.inspector_window);
2303 /* TODO: Add variables and code to make use of these functions */
2305 inspector_close_window_cb (WebKitWebInspector* inspector){
2311 inspector_attach_window_cb (WebKitWebInspector* inspector){
2317 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2323 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2329 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2335 set_up_inspector() {
2337 WebKitWebSettings *settings = view_settings();
2338 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2340 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2341 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2342 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2343 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2344 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2345 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2346 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2348 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2352 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2354 uzbl_cmdprop *c = v;
2359 if(c->type == TYPE_STR)
2360 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2361 else if(c->type == TYPE_INT)
2362 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2366 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2370 printf("bind %s = %s %s\n", (char *)k ,
2371 (char *)a->name, a->param?(char *)a->param:"");
2376 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2377 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2382 main (int argc, char* argv[]) {
2383 gtk_init (&argc, &argv);
2384 if (!g_thread_supported ())
2385 g_thread_init (NULL);
2386 uzbl.state.executable_path = g_strdup(argv[0]);
2387 uzbl.state.selected_url = NULL;
2388 uzbl.state.searchtx = NULL;
2390 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2391 g_option_context_add_main_entries (context, entries, NULL);
2392 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2393 g_option_context_parse (context, &argc, &argv, NULL);
2394 g_option_context_free(context);
2395 /* initialize hash table */
2396 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2398 uzbl.net.soup_session = webkit_get_default_session();
2399 uzbl.state.keycmd = g_string_new("");
2401 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2402 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2403 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2404 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2405 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2406 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2409 if(uname(&uzbl.state.unameinfo) == -1)
2410 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2412 uzbl.gui.sbar.progress_s = g_strdup("=");
2413 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2414 uzbl.gui.sbar.progress_w = 10;
2416 /* HTML mode defaults*/
2417 uzbl.behave.html_buffer = g_string_new("");
2418 uzbl.behave.html_endmarker = g_strdup(".");
2419 uzbl.behave.html_timeout = 60;
2420 uzbl.behave.base_url = g_strdup("http://invalid");
2422 /* default mode indicators */
2423 uzbl.behave.insert_indicator = g_strdup("I");
2424 uzbl.behave.cmd_indicator = g_strdup("C");
2428 make_var_to_name_hash();
2430 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2432 uzbl.gui.scrolled_win = create_browser();
2435 /* initial packing */
2436 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2437 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2439 uzbl.gui.main_window = create_window ();
2440 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2443 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2444 gtk_widget_show_all (uzbl.gui.main_window);
2445 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2447 if (uzbl.state.verbose) {
2448 printf("Uzbl start location: %s\n", argv[0]);
2449 printf("window_id %i\n",(int) uzbl.xwin);
2450 printf("pid %i\n", getpid ());
2451 printf("name: %s\n", uzbl.state.instance_name);
2454 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2455 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2456 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2457 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2458 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2462 if (!uzbl.behave.show_status)
2463 gtk_widget_hide(uzbl.gui.mainbar);
2472 if(uzbl.state.uri) {
2473 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2474 g_array_append_val(a, uzbl.state.uri);
2475 load_uri (uzbl.gui.web_view, a);
2476 g_array_free (a, TRUE);
2482 return EXIT_SUCCESS;
2485 /* vi: set et ts=4: */