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 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
101 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
102 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
103 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
104 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
105 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
106 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
107 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
108 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
109 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
110 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
111 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
112 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
113 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
114 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
115 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
116 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
117 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
118 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
119 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
120 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
121 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
122 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
123 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
124 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
125 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
126 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
127 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
128 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
129 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
130 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
131 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
132 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
133 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
134 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
135 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
136 /* exported WebKitWebSettings properties*/
137 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
138 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
139 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
140 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
141 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
142 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
143 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
144 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
145 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
146 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
147 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
148 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
149 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
150 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
151 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
153 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
154 }, *n2v_p = var_name_to_ptr;
160 { "SHIFT", GDK_SHIFT_MASK }, // shift
161 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
162 { "CONTROL", GDK_CONTROL_MASK }, // control
163 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
164 { "MOD2", GDK_MOD2_MASK }, // 5th mod
165 { "MOD3", GDK_MOD3_MASK }, // 6th mod
166 { "MOD4", GDK_MOD4_MASK }, // 7th mod
167 { "MOD5", GDK_MOD5_MASK }, // 8th mod
168 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
169 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
170 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
171 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
172 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
173 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
174 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
175 { "META", GDK_META_MASK }, // meta (since 2.10)
180 /* construct a hash from the var_name_to_ptr array for quick access */
182 make_var_to_name_hash() {
183 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
185 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
190 /* --- UTILITY FUNCTIONS --- */
192 expand_vars(char *s) {
195 char ret[256], *vend;
196 GString *buf = g_string_new("");
201 g_string_append_c(buf, *++s);
209 if( (vend = strchr(s, upto)) ||
210 (vend = strchr(s, '\0')) ) {
211 strncpy(ret, s, vend-s);
213 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
214 if(c->type == TYPE_STR)
215 g_string_append(buf, (gchar *)*c->ptr);
216 else if(c->type == TYPE_INT) {
217 char *b = itos((int)*c->ptr);
218 g_string_append(buf, b);
222 if(upto == ' ') s = vend;
228 g_string_append_c(buf, *s);
233 return g_string_free(buf, FALSE);
240 snprintf(tmp, sizeof(tmp), "%i", val);
241 return g_strdup(tmp);
245 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
248 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
251 str_replace (const char* search, const char* replace, const char* string) {
255 buf = g_strsplit (string, search, -1);
256 ret = g_strjoinv (replace, buf);
257 g_strfreev(buf); // somebody said this segfaults
263 read_file_by_line (gchar *path) {
264 GIOChannel *chan = NULL;
265 gchar *readbuf = NULL;
267 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
270 chan = g_io_channel_new_file(path, "r", NULL);
273 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
274 const gchar* val = g_strdup (readbuf);
275 g_array_append_val (lines, val);
280 g_io_channel_unref (chan);
282 fprintf(stderr, "File '%s' not be read.\n", path);
289 gchar* parseenv (char* string) {
290 extern char** environ;
291 gchar* tmpstr = NULL;
295 while (environ[i] != NULL) {
296 gchar** env = g_strsplit (environ[i], "=", 2);
297 gchar* envname = g_strconcat ("$", env[0], NULL);
299 if (g_strrstr (string, envname) != NULL) {
300 tmpstr = g_strdup(string);
302 string = str_replace(envname, env[1], tmpstr);
307 g_strfreev (env); // somebody said this breaks uzbl
315 setup_signal(int signr, sigfunc *shandler) {
316 struct sigaction nh, oh;
318 nh.sa_handler = shandler;
319 sigemptyset(&nh.sa_mask);
322 if(sigaction(signr, &nh, &oh) < 0)
330 if (uzbl.behave.fifo_dir)
331 unlink (uzbl.comm.fifo_path);
332 if (uzbl.behave.socket_dir)
333 unlink (uzbl.comm.socket_path);
335 g_free(uzbl.state.executable_path);
336 g_string_free(uzbl.state.keycmd, TRUE);
337 g_hash_table_destroy(uzbl.bindings);
338 g_hash_table_destroy(uzbl.behave.commands);
341 /* used for html_mode_timeout
342 * be sure to extend this function to use
343 * more timers if needed in other places
346 set_timeout(int seconds) {
348 memset(&t, 0, sizeof t);
350 t.it_value.tv_sec = seconds;
351 t.it_value.tv_usec = 0;
352 setitimer(ITIMER_REAL, &t, NULL);
355 /* --- SIGNAL HANDLER --- */
358 catch_sigterm(int s) {
364 catch_sigint(int s) {
374 set_var_value("mode", "0");
379 /* --- CALLBACKS --- */
382 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
385 (void) navigation_action;
386 (void) policy_decision;
388 const gchar* uri = webkit_network_request_get_uri (request);
389 if (uzbl.state.verbose)
390 printf("New window requested -> %s \n", uri);
391 new_window_load_uri(uri);
396 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
401 /* If we can display it, let's display it... */
402 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
403 webkit_web_policy_decision_use (policy_decision);
407 /* ...everything we can't displayed is downloaded */
408 webkit_web_policy_decision_download (policy_decision);
413 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
417 if (uzbl.state.selected_url != NULL) {
418 if (uzbl.state.verbose)
419 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
420 new_window_load_uri(uzbl.state.selected_url);
422 if (uzbl.state.verbose)
423 printf("New web view -> %s\n","Nothing to open, exiting");
429 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
432 if (uzbl.behave.download_handler) {
433 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
434 if (uzbl.state.verbose)
435 printf("Download -> %s\n",uri);
436 /* if urls not escaped, we may have to escape and quote uri before this call */
437 run_handler(uzbl.behave.download_handler, uri);
442 /* scroll a bar in a given direction */
444 scroll (GtkAdjustment* bar, GArray *argv) {
448 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
449 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
450 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
454 scroll_begin(WebKitWebView* page, GArray *argv) {
455 (void) page; (void) argv;
456 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
460 scroll_end(WebKitWebView* page, GArray *argv) {
461 (void) page; (void) argv;
462 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
463 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
467 scroll_vert(WebKitWebView* page, GArray *argv) {
469 scroll(uzbl.gui.bar_v, argv);
473 scroll_horz(WebKitWebView* page, GArray *argv) {
475 scroll(uzbl.gui.bar_h, argv);
480 if (!uzbl.behave.show_status) {
481 gtk_widget_hide(uzbl.gui.mainbar);
483 gtk_widget_show(uzbl.gui.mainbar);
489 toggle_status_cb (WebKitWebView* page, GArray *argv) {
493 if (uzbl.behave.show_status) {
494 gtk_widget_hide(uzbl.gui.mainbar);
496 gtk_widget_show(uzbl.gui.mainbar);
498 uzbl.behave.show_status = !uzbl.behave.show_status;
503 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
507 //Set selected_url state variable
508 g_free(uzbl.state.selected_url);
509 uzbl.state.selected_url = NULL;
511 uzbl.state.selected_url = g_strdup(link);
517 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
521 if (uzbl.gui.main_title)
522 g_free (uzbl.gui.main_title);
523 uzbl.gui.main_title = g_strdup (title);
528 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
531 uzbl.gui.sbar.load_progress = progress;
536 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
540 if (uzbl.behave.load_finish_handler)
541 run_handler(uzbl.behave.load_finish_handler, "");
545 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
549 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
550 if (uzbl.behave.load_start_handler)
551 run_handler(uzbl.behave.load_start_handler, "");
555 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
558 g_free (uzbl.state.uri);
559 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
560 uzbl.state.uri = g_string_free (newuri, FALSE);
561 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
562 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
565 if (uzbl.behave.load_commit_handler)
566 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
570 destroy_cb (GtkWidget* widget, gpointer data) {
578 if (uzbl.behave.history_handler) {
580 struct tm * timeinfo;
583 timeinfo = localtime ( &rawtime );
584 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
585 run_handler(uzbl.behave.history_handler, date);
590 /* VIEW funcs (little webkit wrappers) */
591 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
593 VIEWFUNC(reload_bypass_cache)
594 VIEWFUNC(stop_loading)
601 /* -- command to callback/function map for things we cannot attach to any signals */
603 static struct {char *name; Command command[2];} cmdlist[] =
604 { /* key function no_split */
605 { "back", {view_go_back, 0} },
606 { "forward", {view_go_forward, 0} },
607 { "scroll_vert", {scroll_vert, 0} },
608 { "scroll_horz", {scroll_horz, 0} },
609 { "scroll_begin", {scroll_begin, 0} },
610 { "scroll_end", {scroll_end, 0} },
611 { "reload", {view_reload, 0}, },
612 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
613 { "stop", {view_stop_loading, 0}, },
614 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
615 { "zoom_out", {view_zoom_out, 0}, },
616 { "uri", {load_uri, NOSPLIT} },
617 { "js", {run_js, NOSPLIT} },
618 { "script", {run_external_js, 0} },
619 { "toggle_status", {toggle_status_cb, 0} },
620 { "spawn", {spawn, 0} },
621 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
622 { "sh", {spawn_sh, 0} },
623 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
624 { "exit", {close_uzbl, 0} },
625 { "search", {search_forward_text, NOSPLIT} },
626 { "search_reverse", {search_reverse_text, NOSPLIT} },
627 { "dehilight", {dehilight, 0} },
628 { "toggle_insert_mode", {toggle_insert_mode, 0} },
629 { "set", {set_var, NOSPLIT} },
630 //{ "get", {get_var, NOSPLIT} },
631 { "bind", {act_bind, NOSPLIT} },
632 { "dump_config", {act_dump_config, 0} },
633 { "keycmd", {keycmd, NOSPLIT} },
634 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
635 { "keycmd_bs", {keycmd_bs, 0} },
636 { "chain", {chain, 0} },
637 { "print", {print, NOSPLIT} }
644 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
646 for (i = 0; i < LENGTH(cmdlist); i++)
647 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
650 /* -- CORE FUNCTIONS -- */
653 free_action(gpointer act) {
654 Action *action = (Action*)act;
655 g_free(action->name);
657 g_free(action->param);
662 new_action(const gchar *name, const gchar *param) {
663 Action *action = g_new(Action, 1);
665 action->name = g_strdup(name);
667 action->param = g_strdup(param);
669 action->param = NULL;
675 file_exists (const char * filename) {
676 return (access(filename, F_OK) == 0);
680 set_var(WebKitWebView *page, GArray *argv) {
682 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
683 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
684 set_var_value(g_strstrip(split[0]), value);
690 print(WebKitWebView *page, GArray *argv) {
694 buf = expand_vars(argv_idx(argv, 0));
700 act_bind(WebKitWebView *page, GArray *argv) {
702 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
703 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
704 add_binding(g_strstrip(split[0]), value);
716 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
719 if (argv_idx(argv, 0)) {
720 if (strcmp (argv_idx(argv, 0), "0") == 0) {
721 uzbl.behave.insert_mode = FALSE;
723 uzbl.behave.insert_mode = TRUE;
726 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
733 load_uri (WebKitWebView *web_view, GArray *argv) {
734 if (argv_idx(argv, 0)) {
735 GString* newuri = g_string_new (argv_idx(argv, 0));
736 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
737 g_string_prepend (newuri, "http://");
738 /* if we do handle cookies, ask our handler for them */
739 webkit_web_view_load_uri (web_view, newuri->str);
740 g_string_free (newuri, TRUE);
745 run_js (WebKitWebView * web_view, GArray *argv) {
746 if (argv_idx(argv, 0))
747 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
751 run_external_js (WebKitWebView * web_view, GArray *argv) {
752 if (argv_idx(argv, 0)) {
753 GArray* lines = read_file_by_line (argv_idx (argv, 0));
758 while ((line = g_array_index(lines, gchar*, i))) {
760 js = g_strdup (line);
762 gchar* newjs = g_strconcat (js, line, NULL);
769 if (uzbl.state.verbose)
770 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
772 if (argv_idx (argv, 1)) {
773 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
777 webkit_web_view_execute_script (web_view, js);
779 g_array_free (lines, TRUE);
784 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
785 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
786 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
787 webkit_web_view_unmark_text_matches (page);
788 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
789 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
793 if (uzbl.state.searchtx) {
794 if (uzbl.state.verbose)
795 printf ("Searching: %s\n", uzbl.state.searchtx);
796 webkit_web_view_set_highlight_text_matches (page, TRUE);
797 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
802 search_forward_text (WebKitWebView *page, GArray *argv) {
803 search_text(page, argv, TRUE);
807 search_reverse_text (WebKitWebView *page, GArray *argv) {
808 search_text(page, argv, FALSE);
812 dehilight (WebKitWebView *page, GArray *argv) {
814 webkit_web_view_set_highlight_text_matches (page, FALSE);
819 new_window_load_uri (const gchar * uri) {
820 GString* to_execute = g_string_new ("");
821 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
823 for (i = 0; entries[i].long_name != NULL; i++) {
824 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
825 gchar** str = (gchar**)entries[i].arg_data;
827 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
831 if (uzbl.state.verbose)
832 printf("\n%s\n", to_execute->str);
833 g_spawn_command_line_async (to_execute->str, NULL);
834 g_string_free (to_execute, TRUE);
838 chain (WebKitWebView *page, GArray *argv) {
841 gchar **parts = NULL;
843 while ((a = argv_idx(argv, i++))) {
844 parts = g_strsplit (a, " ", 2);
845 parse_command(parts[0], parts[1]);
851 keycmd (WebKitWebView *page, GArray *argv) {
854 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
860 keycmd_nl (WebKitWebView *page, GArray *argv) {
863 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
869 keycmd_bs (WebKitWebView *page, GArray *argv) {
872 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
877 close_uzbl (WebKitWebView *page, GArray *argv) {
883 /* --Statusbar functions-- */
885 build_progressbar_ascii(int percent) {
886 int width=uzbl.gui.sbar.progress_w;
889 GString *bar = g_string_new("");
891 l = (double)percent*((double)width/100.);
892 l = (int)(l+.5)>=(int)l ? l+.5 : l;
894 for(i=0; i<(int)l; i++)
895 g_string_append(bar, uzbl.gui.sbar.progress_s);
898 g_string_append(bar, uzbl.gui.sbar.progress_u);
900 return g_string_free(bar, FALSE);
905 const GScannerConfig scan_config = {
908 ) /* cset_skip_characters */,
913 ) /* cset_identifier_first */,
920 ) /* cset_identifier_nth */,
921 ( "" ) /* cpair_comment_single */,
923 TRUE /* case_sensitive */,
925 FALSE /* skip_comment_multi */,
926 FALSE /* skip_comment_single */,
927 FALSE /* scan_comment_multi */,
928 TRUE /* scan_identifier */,
929 TRUE /* scan_identifier_1char */,
930 FALSE /* scan_identifier_NULL */,
931 TRUE /* scan_symbols */,
932 FALSE /* scan_binary */,
933 FALSE /* scan_octal */,
934 FALSE /* scan_float */,
935 FALSE /* scan_hex */,
936 FALSE /* scan_hex_dollar */,
937 FALSE /* scan_string_sq */,
938 FALSE /* scan_string_dq */,
939 TRUE /* numbers_2_int */,
940 FALSE /* int_2_float */,
941 FALSE /* identifier_2_string */,
942 FALSE /* char_2_token */,
943 FALSE /* symbol_2_token */,
944 TRUE /* scope_0_fallback */,
949 uzbl.scan = g_scanner_new(&scan_config);
950 while(symp->symbol_name) {
951 g_scanner_scope_add_symbol(uzbl.scan, 0,
953 GINT_TO_POINTER(symp->symbol_token));
959 expand_template(const char *template, gboolean escape_markup) {
960 if(!template) return NULL;
962 GTokenType token = G_TOKEN_NONE;
963 GString *ret = g_string_new("");
967 g_scanner_input_text(uzbl.scan, template, strlen(template));
968 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
969 token = g_scanner_get_next_token(uzbl.scan);
971 if(token == G_TOKEN_SYMBOL) {
972 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
976 buf = uzbl.state.uri?
977 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
978 g_string_append(ret, buf);
982 g_string_append(ret, uzbl.state.uri?
983 uzbl.state.uri:g_strdup(""));
986 buf = itos(uzbl.gui.sbar.load_progress);
987 g_string_append(ret, buf);
990 case SYM_LOADPRGSBAR:
991 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
992 g_string_append(ret, buf);
997 buf = uzbl.gui.main_title?
998 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
999 g_string_append(ret, buf);
1003 g_string_append(ret, uzbl.gui.main_title?
1004 uzbl.gui.main_title:g_strdup(""));
1006 case SYM_SELECTED_URI:
1008 buf = uzbl.state.selected_url?
1009 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1010 g_string_append(ret, buf);
1014 g_string_append(ret, uzbl.state.selected_url?
1015 uzbl.state.selected_url:g_strdup(""));
1018 buf = itos(uzbl.xwin);
1019 g_string_append(ret,
1020 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1025 buf = uzbl.state.keycmd->str?
1026 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1027 g_string_append(ret, buf);
1031 g_string_append(ret, uzbl.state.keycmd->str?
1032 uzbl.state.keycmd->str:g_strdup(""));
1035 g_string_append(ret,
1036 uzbl.behave.insert_mode?
1037 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1040 g_string_append(ret,
1041 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1043 /* useragent syms */
1045 buf = itos(WEBKIT_MAJOR_VERSION);
1046 g_string_append(ret, buf);
1050 buf = itos(WEBKIT_MINOR_VERSION);
1051 g_string_append(ret, buf);
1055 buf = itos(WEBKIT_MICRO_VERSION);
1056 g_string_append(ret, buf);
1060 g_string_append(ret, uzbl.state.unameinfo.sysname);
1063 g_string_append(ret, uzbl.state.unameinfo.nodename);
1066 g_string_append(ret, uzbl.state.unameinfo.release);
1069 g_string_append(ret, uzbl.state.unameinfo.version);
1072 g_string_append(ret, uzbl.state.unameinfo.machine);
1075 g_string_append(ret, ARCH);
1078 case SYM_DOMAINNAME:
1079 g_string_append(ret, uzbl.state.unameinfo.domainname);
1083 g_string_append(ret, COMMIT);
1089 else if(token == G_TOKEN_INT) {
1090 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1091 g_string_append(ret, buf);
1094 else if(token == G_TOKEN_IDENTIFIER) {
1095 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1097 else if(token == G_TOKEN_CHAR) {
1098 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1102 return g_string_free(ret, FALSE);
1104 /* --End Statusbar functions-- */
1107 sharg_append(GArray *a, const gchar *str) {
1108 const gchar *s = (str ? str : "");
1109 g_array_append_val(a, s);
1112 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1114 run_command (const gchar *command, const guint npre, const gchar **args,
1115 const gboolean sync, char **stdout) {
1116 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1119 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1120 gchar *pid = itos(getpid());
1121 gchar *xwin = itos(uzbl.xwin);
1123 sharg_append(a, command);
1124 for (i = 0; i < npre; i++) /* add n args before the default vars */
1125 sharg_append(a, args[i]);
1126 sharg_append(a, uzbl.state.config_file);
1127 sharg_append(a, pid);
1128 sharg_append(a, xwin);
1129 sharg_append(a, uzbl.comm.fifo_path);
1130 sharg_append(a, uzbl.comm.socket_path);
1131 sharg_append(a, uzbl.state.uri);
1132 sharg_append(a, uzbl.gui.main_title);
1134 for (i = npre; i < g_strv_length((gchar**)args); i++)
1135 sharg_append(a, args[i]);
1139 if (*stdout) *stdout = strfree(*stdout);
1141 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1142 NULL, NULL, stdout, NULL, NULL, &err);
1143 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1144 NULL, NULL, NULL, &err);
1146 if (uzbl.state.verbose) {
1147 GString *s = g_string_new("spawned:");
1148 for (i = 0; i < (a->len); i++) {
1149 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1150 g_string_append_printf(s, " %s", qarg);
1153 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1154 printf("%s\n", s->str);
1155 g_string_free(s, TRUE);
1157 printf("Stdout: %s\n", *stdout);
1161 g_printerr("error on run_command: %s\n", err->message);
1166 g_array_free (a, TRUE);
1171 split_quoted(const gchar* src, const gboolean unquote) {
1172 /* split on unquoted space, return array of strings;
1173 remove a layer of quotes and backslashes if unquote */
1174 if (!src) return NULL;
1176 gboolean dq = FALSE;
1177 gboolean sq = FALSE;
1178 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1179 GString *s = g_string_new ("");
1183 for (p = src; *p != '\0'; p++) {
1184 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1185 else if (*p == '\\') { g_string_append_c(s, *p++);
1186 g_string_append_c(s, *p); }
1187 else if ((*p == '"') && unquote && !sq) dq = !dq;
1188 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1190 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1191 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1193 else if ((*p == ' ') && !dq && !sq) {
1194 dup = g_strdup(s->str);
1195 g_array_append_val(a, dup);
1196 g_string_truncate(s, 0);
1197 } else g_string_append_c(s, *p);
1199 dup = g_strdup(s->str);
1200 g_array_append_val(a, dup);
1201 ret = (gchar**)a->data;
1202 g_array_free (a, FALSE);
1203 g_string_free (s, TRUE);
1208 spawn(WebKitWebView *web_view, GArray *argv) {
1210 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1211 if (argv_idx(argv, 0))
1212 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1216 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1219 if (argv_idx(argv, 0))
1220 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1221 TRUE, &uzbl.comm.sync_stdout);
1225 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1227 if (!uzbl.behave.shell_cmd) {
1228 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1233 gchar *spacer = g_strdup("");
1234 g_array_insert_val(argv, 1, spacer);
1235 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1237 for (i = 1; i < g_strv_length(cmd); i++)
1238 g_array_prepend_val(argv, cmd[i]);
1240 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1246 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1248 if (!uzbl.behave.shell_cmd) {
1249 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1254 gchar *spacer = g_strdup("");
1255 g_array_insert_val(argv, 1, spacer);
1256 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1258 for (i = 1; i < g_strv_length(cmd); i++)
1259 g_array_prepend_val(argv, cmd[i]);
1261 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1262 TRUE, &uzbl.comm.sync_stdout);
1268 parse_command(const char *cmd, const char *param) {
1271 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1274 gchar **par = split_quoted(param, TRUE);
1275 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1277 if (c[1] == NOSPLIT) { /* don't split */
1278 sharg_append(a, param);
1280 for (i = 0; i < g_strv_length(par); i++)
1281 sharg_append(a, par[i]);
1283 c[0](uzbl.gui.web_view, a);
1285 g_array_free (a, TRUE);
1288 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1295 if(*uzbl.net.proxy_url == ' '
1296 || uzbl.net.proxy_url == NULL) {
1297 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1298 (GType) SOUP_SESSION_PROXY_URI);
1301 suri = soup_uri_new(uzbl.net.proxy_url);
1302 g_object_set(G_OBJECT(uzbl.net.soup_session),
1303 SOUP_SESSION_PROXY_URI,
1305 soup_uri_free(suri);
1312 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1313 g_array_append_val (a, uzbl.state.uri);
1314 load_uri(uzbl.gui.web_view, a);
1315 g_array_free (a, TRUE);
1319 cmd_always_insert_mode() {
1320 uzbl.behave.insert_mode =
1321 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1327 g_object_set(G_OBJECT(uzbl.net.soup_session),
1328 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1332 cmd_max_conns_host() {
1333 g_object_set(G_OBJECT(uzbl.net.soup_session),
1334 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1339 soup_session_remove_feature
1340 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1341 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1342 /*g_free(uzbl.net.soup_logger);*/
1344 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1345 soup_session_add_feature(uzbl.net.soup_session,
1346 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1349 static WebKitWebSettings*
1351 return webkit_web_view_get_settings(uzbl.gui.web_view);
1356 WebKitWebSettings *ws = view_settings();
1357 if (uzbl.behave.font_size > 0) {
1358 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1361 if (uzbl.behave.monospace_size > 0) {
1362 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1363 uzbl.behave.monospace_size, NULL);
1365 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1366 uzbl.behave.font_size, NULL);
1371 cmd_disable_plugins() {
1372 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1373 !uzbl.behave.disable_plugins, NULL);
1377 cmd_disable_scripts() {
1378 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1379 !uzbl.behave.disable_scripts, NULL);
1383 cmd_minimum_font_size() {
1384 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1385 uzbl.behave.minimum_font_size, NULL);
1388 cmd_autoload_img() {
1389 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1390 uzbl.behave.autoload_img, NULL);
1395 cmd_autoshrink_img() {
1396 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1397 uzbl.behave.autoshrink_img, NULL);
1402 cmd_enable_spellcheck() {
1403 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1404 uzbl.behave.enable_spellcheck, NULL);
1408 cmd_enable_private() {
1409 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1410 uzbl.behave.enable_private, NULL);
1415 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1416 uzbl.behave.print_bg, NULL);
1421 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1422 uzbl.behave.style_uri, NULL);
1426 cmd_resizable_txt() {
1427 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1428 uzbl.behave.resizable_txt, NULL);
1432 cmd_default_encoding() {
1433 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1434 uzbl.behave.default_encoding, NULL);
1438 cmd_enforce_96dpi() {
1439 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1440 uzbl.behave.enforce_96dpi, NULL);
1444 cmd_caret_browsing() {
1445 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1446 uzbl.behave.caret_browsing, NULL);
1450 cmd_cookie_handler() {
1451 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1452 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1453 if ((g_strcmp0(split[0], "sh") == 0) ||
1454 (g_strcmp0(split[0], "spawn") == 0)) {
1455 g_free (uzbl.behave.cookie_handler);
1456 uzbl.behave.cookie_handler =
1457 g_strdup_printf("sync_%s %s", split[0], split[1]);
1464 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1469 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1474 if(uzbl.behave.inject_html) {
1475 webkit_web_view_load_html_string (uzbl.gui.web_view,
1476 uzbl.behave.inject_html, NULL);
1485 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1486 uzbl.behave.modmask = 0;
1488 if(uzbl.behave.modkey)
1489 g_free(uzbl.behave.modkey);
1490 uzbl.behave.modkey = buf;
1492 for (i = 0; modkeys[i].key != NULL; i++) {
1493 if (g_strrstr(buf, modkeys[i].key))
1494 uzbl.behave.modmask |= modkeys[i].mask;
1500 if (*uzbl.net.useragent == ' ') {
1501 g_free (uzbl.net.useragent);
1502 uzbl.net.useragent = NULL;
1504 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1506 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1507 g_free(uzbl.net.useragent);
1508 uzbl.net.useragent = ua;
1514 gtk_widget_ref(uzbl.gui.scrolled_win);
1515 gtk_widget_ref(uzbl.gui.mainbar);
1516 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1517 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1519 if(uzbl.behave.status_top) {
1520 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1521 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1524 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1525 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1527 gtk_widget_unref(uzbl.gui.scrolled_win);
1528 gtk_widget_unref(uzbl.gui.mainbar);
1529 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1534 set_var_value(gchar *name, gchar *val) {
1535 uzbl_cmdprop *c = NULL;
1539 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1540 /* check for the variable type */
1541 if (c->type == TYPE_STR) {
1542 buf = expand_vars(val);
1545 } else if(c->type == TYPE_INT) {
1546 int *ip = (int *)c->ptr;
1547 buf = expand_vars(val);
1548 *ip = (int)strtoul(buf, &endp, 10);
1552 /* invoke a command specific function */
1553 if(c->func) c->func();
1560 Behaviour *b = &uzbl.behave;
1562 if(b->html_buffer->str) {
1563 webkit_web_view_load_html_string (uzbl.gui.web_view,
1564 b->html_buffer->str, b->base_url);
1565 g_string_free(b->html_buffer, TRUE);
1566 b->html_buffer = g_string_new("");
1570 enum {M_CMD, M_HTML};
1572 parse_cmd_line(const char *ctl_line) {
1573 Behaviour *b = &uzbl.behave;
1576 if(b->mode == M_HTML) {
1577 len = strlen(b->html_endmarker);
1578 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1579 if(len == strlen(ctl_line)-1 &&
1580 !strncmp(b->html_endmarker, ctl_line, len)) {
1582 set_var_value("mode", "0");
1587 set_timeout(b->html_timeout);
1588 g_string_append(b->html_buffer, ctl_line);
1591 else if((ctl_line[0] == '#') /* Comments */
1592 || (ctl_line[0] == ' ')
1593 || (ctl_line[0] == '\n'))
1594 ; /* ignore these lines */
1595 else { /* parse a command */
1597 gchar **tokens = NULL;
1598 len = strlen(ctl_line);
1600 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1601 ctlstrip = g_strndup(ctl_line, len - 1);
1602 else ctlstrip = g_strdup(ctl_line);
1604 tokens = g_strsplit(ctlstrip, " ", 2);
1605 parse_command(tokens[0], tokens[1]);
1612 build_stream_name(int type, const gchar* dir) {
1614 State *s = &uzbl.state;
1617 xwin_str = itos((int)uzbl.xwin);
1619 str = g_strdup_printf
1620 ("%s/uzbl_fifo_%s", dir,
1621 s->instance_name ? s->instance_name : xwin_str);
1622 } else if (type == SOCKET) {
1623 str = g_strdup_printf
1624 ("%s/uzbl_socket_%s", dir,
1625 s->instance_name ? s->instance_name : xwin_str );
1632 control_fifo(GIOChannel *gio, GIOCondition condition) {
1633 if (uzbl.state.verbose)
1634 printf("triggered\n");
1639 if (condition & G_IO_HUP)
1640 g_error ("Fifo: Read end of pipe died!\n");
1643 g_error ("Fifo: GIOChannel broke\n");
1645 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1646 if (ret == G_IO_STATUS_ERROR) {
1647 g_error ("Fifo: Error reading: %s\n", err->message);
1651 parse_cmd_line(ctl_line);
1658 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1659 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1660 if (unlink(uzbl.comm.fifo_path) == -1)
1661 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1662 g_free(uzbl.comm.fifo_path);
1663 uzbl.comm.fifo_path = NULL;
1666 if (*dir == ' ') { /* space unsets the variable */
1671 GIOChannel *chan = NULL;
1672 GError *error = NULL;
1673 gchar *path = build_stream_name(FIFO, dir);
1675 if (!file_exists(path)) {
1676 if (mkfifo (path, 0666) == 0) {
1677 // 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.
1678 chan = g_io_channel_new_file(path, "r+", &error);
1680 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1681 if (uzbl.state.verbose)
1682 printf ("init_fifo: created successfully as %s\n", path);
1683 uzbl.comm.fifo_path = path;
1685 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1686 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1687 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1688 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1690 /* if we got this far, there was an error; cleanup */
1691 if (error) g_error_free (error);
1698 control_stdin(GIOChannel *gio, GIOCondition condition) {
1700 gchar *ctl_line = NULL;
1703 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1704 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1707 parse_cmd_line(ctl_line);
1715 GIOChannel *chan = NULL;
1716 GError *error = NULL;
1718 chan = g_io_channel_unix_new(fileno(stdin));
1720 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1721 g_error ("Stdin: could not add watch\n");
1723 if (uzbl.state.verbose)
1724 printf ("Stdin: watch added successfully\n");
1727 g_error ("Stdin: Error while opening: %s\n", error->message);
1729 if (error) g_error_free (error);
1733 control_socket(GIOChannel *chan) {
1734 struct sockaddr_un remote;
1735 char buffer[512], *ctl_line;
1737 int sock, clientsock, n, done;
1740 sock = g_io_channel_unix_get_fd(chan);
1742 memset (buffer, 0, sizeof (buffer));
1744 t = sizeof (remote);
1745 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1749 memset (temp, 0, sizeof (temp));
1750 n = recv (clientsock, temp, 128, 0);
1752 buffer[strlen (buffer)] = '\0';
1756 strcat (buffer, temp);
1759 if (strcmp (buffer, "\n") < 0) {
1760 buffer[strlen (buffer) - 1] = '\0';
1762 buffer[strlen (buffer)] = '\0';
1765 ctl_line = g_strdup(buffer);
1766 parse_cmd_line (ctl_line);
1769 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1770 GError *error = NULL;
1773 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1774 if (ret == G_IO_STATUS_ERROR)
1775 g_error ("Error reading: %s\n", error->message);
1777 printf("Got line %s (%u bytes) \n",ctl_line, len);
1779 parse_line(ctl_line);
1787 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1788 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1789 if (unlink(uzbl.comm.socket_path) == -1)
1790 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1791 g_free(uzbl.comm.socket_path);
1792 uzbl.comm.socket_path = NULL;
1800 GIOChannel *chan = NULL;
1802 struct sockaddr_un local;
1803 gchar *path = build_stream_name(SOCKET, dir);
1805 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1807 local.sun_family = AF_UNIX;
1808 strcpy (local.sun_path, path);
1809 unlink (local.sun_path);
1811 len = strlen (local.sun_path) + sizeof (local.sun_family);
1812 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1813 if (uzbl.state.verbose)
1814 printf ("init_socket: opened in %s\n", path);
1817 if( (chan = g_io_channel_unix_new(sock)) ) {
1818 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1819 uzbl.comm.socket_path = path;
1822 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1824 /* if we got this far, there was an error; cleanup */
1831 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1832 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1834 // this function may be called very early when the templates are not set (yet), hence the checks
1836 update_title (void) {
1837 Behaviour *b = &uzbl.behave;
1840 if (b->show_status) {
1841 if (b->title_format_short) {
1842 parsed = expand_template(b->title_format_short, FALSE);
1843 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1846 if (b->status_format) {
1847 parsed = expand_template(b->status_format, TRUE);
1848 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1851 if (b->status_background) {
1853 gdk_color_parse (b->status_background, &color);
1854 //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)
1855 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1858 if (b->title_format_long) {
1859 parsed = expand_template(b->title_format_long, FALSE);
1860 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1867 key_press_cb (GtkWidget* window, GdkEventKey* event)
1869 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1873 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1874 || 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)
1877 /* turn off insert mode (if always_insert_mode is not used) */
1878 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1879 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1884 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1887 if (event->keyval == GDK_Escape) {
1888 g_string_truncate(uzbl.state.keycmd, 0);
1890 dehilight(uzbl.gui.web_view, NULL);
1894 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1895 if (event->keyval == GDK_Insert) {
1897 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1898 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1900 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1903 g_string_append (uzbl.state.keycmd, str);
1910 if (event->keyval == GDK_BackSpace)
1911 keycmd_bs(NULL, NULL);
1913 gboolean key_ret = FALSE;
1914 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1916 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1918 run_keycmd(key_ret);
1920 if (key_ret) return (!uzbl.behave.insert_mode);
1925 run_keycmd(const gboolean key_ret) {
1926 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1928 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1929 g_string_truncate(uzbl.state.keycmd, 0);
1930 parse_command(act->name, act->param);
1934 /* try if it's an incremental keycmd or one that takes args, and run it */
1935 GString* short_keys = g_string_new ("");
1936 GString* short_keys_inc = g_string_new ("");
1938 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1939 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1940 g_string_assign(short_keys_inc, short_keys->str);
1941 g_string_append_c(short_keys, '_');
1942 g_string_append_c(short_keys_inc, '*');
1944 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1945 /* run normal cmds only if return was pressed */
1946 exec_paramcmd(act, i);
1947 g_string_truncate(uzbl.state.keycmd, 0);
1949 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1950 if (key_ret) /* just quit the incremental command on return */
1951 g_string_truncate(uzbl.state.keycmd, 0);
1952 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1956 g_string_truncate(short_keys, short_keys->len - 1);
1958 g_string_free (short_keys, TRUE);
1959 g_string_free (short_keys_inc, TRUE);
1963 exec_paramcmd(const Action *act, const guint i) {
1964 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1965 GString *actionname = g_string_new ("");
1966 GString *actionparam = g_string_new ("");
1967 g_string_erase (parampart, 0, i+1);
1969 g_string_printf (actionname, act->name, parampart->str);
1971 g_string_printf (actionparam, act->param, parampart->str);
1972 parse_command(actionname->str, actionparam->str);
1973 g_string_free(actionname, TRUE);
1974 g_string_free(actionparam, TRUE);
1975 g_string_free(parampart, TRUE);
1983 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1984 //main_window_ref = g_object_ref(scrolled_window);
1985 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
1987 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1988 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1990 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1991 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1992 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1993 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1994 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1995 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1996 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1997 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1998 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1999 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2000 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2002 return scrolled_window;
2009 g->mainbar = gtk_hbox_new (FALSE, 0);
2011 /* keep a reference to the bar so we can re-pack it at runtime*/
2012 //sbar_ref = g_object_ref(g->mainbar);
2014 g->mainbar_label = gtk_label_new ("");
2015 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2016 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2017 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2018 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2019 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2024 GtkWidget* create_window () {
2025 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2026 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2027 gtk_widget_set_name (window, "Uzbl browser");
2028 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2029 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2035 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2037 If actname is one that calls an external command, this function will inject
2038 newargs in front of the user-provided args in that command line. They will
2039 come become after the body of the script (in sh) or after the name of
2040 the command to execute (in spawn).
2041 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2042 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2044 The return value consist of two strings: the action (sh, ...) and its args.
2046 If act is not one that calls an external command, then the given action merely
2049 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2050 gchar *actdup = g_strdup(actname);
2051 g_array_append_val(rets, actdup);
2053 if ((g_strcmp0(actname, "spawn") == 0) ||
2054 (g_strcmp0(actname, "sh") == 0) ||
2055 (g_strcmp0(actname, "sync_spawn") == 0) ||
2056 (g_strcmp0(actname, "sync_sh") == 0)) {
2058 GString *a = g_string_new("");
2059 gchar **spawnparts = split_quoted(origargs, FALSE);
2060 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2061 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2063 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2064 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2066 g_array_append_val(rets, a->str);
2067 g_string_free(a, FALSE);
2068 g_strfreev(spawnparts);
2070 gchar *origdup = g_strdup(origargs);
2071 g_array_append_val(rets, origdup);
2073 return (gchar**)g_array_free(rets, FALSE);
2077 run_handler (const gchar *act, const gchar *args) {
2078 /* Consider this code a temporary hack to make the handlers usable.
2079 In practice, all this splicing, injection, and reconstruction is
2080 inefficient, annoying and hard to manage. Potential pitfalls arise
2081 when the handler specific args 1) are not quoted (the handler
2082 callbacks should take care of this) 2) are quoted but interfere
2083 with the users' own quotation. A more ideal solution is
2084 to refactor parse_command so that it doesn't just take a string
2085 and execute it; rather than that, we should have a function which
2086 returns the argument vector parsed from the string. This vector
2087 could be modified (e.g. insert additional args into it) before
2088 passing it to the next function that actually executes it. Though
2089 it still isn't perfect for chain actions.. will reconsider & re-
2090 factor when I have the time. -duc */
2092 char **parts = g_strsplit(act, " ", 2);
2094 if (g_strcmp0(parts[0], "chain") == 0) {
2095 GString *newargs = g_string_new("");
2096 gchar **chainparts = split_quoted(parts[1], FALSE);
2098 /* for every argument in the chain, inject the handler args
2099 and make sure the new parts are wrapped in quotes */
2100 gchar **cp = chainparts;
2102 gchar *quotless = NULL;
2103 gchar **spliced_quotless = NULL; // sigh -_-;
2104 gchar **inpart = NULL;
2107 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2109 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2110 } else quotless = g_strdup(*cp);
2112 spliced_quotless = g_strsplit(quotless, " ", 2);
2113 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2114 g_strfreev(spliced_quotless);
2116 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2122 parse_command(parts[0], &(newargs->str[1]));
2123 g_string_free(newargs, TRUE);
2124 g_strfreev(chainparts);
2127 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2128 parse_command(inparts[0], inparts[1]);
2136 add_binding (const gchar *key, const gchar *act) {
2137 char **parts = g_strsplit(act, " ", 2);
2144 if (uzbl.state.verbose)
2145 printf ("Binding %-10s : %s\n", key, act);
2146 action = new_action(parts[0], parts[1]);
2148 if (g_hash_table_remove (uzbl.bindings, key))
2149 g_warning ("Overwriting existing binding for \"%s\"", key);
2150 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2155 get_xdg_var (XDG_Var xdg) {
2156 const gchar* actual_value = getenv (xdg.environmental);
2157 const gchar* home = getenv ("HOME");
2159 gchar* return_value = str_replace ("~", home, actual_value);
2161 if (! actual_value || strcmp (actual_value, "") == 0) {
2162 if (xdg.default_value) {
2163 return_value = str_replace ("~", home, xdg.default_value);
2165 return_value = NULL;
2168 return return_value;
2172 find_xdg_file (int xdg_type, char* filename) {
2173 /* xdg_type = 0 => config
2174 xdg_type = 1 => data
2175 xdg_type = 2 => cache*/
2177 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2178 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2181 gchar* temporary_string;
2185 if (! file_exists (temporary_file) && xdg_type != 2) {
2186 buf = get_xdg_var (XDG[3 + xdg_type]);
2187 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2190 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2191 g_free (temporary_file);
2192 temporary_file = g_strconcat (temporary_string, filename, NULL);
2196 //g_free (temporary_string); - segfaults.
2198 if (file_exists (temporary_file)) {
2199 return temporary_file;
2206 State *s = &uzbl.state;
2207 Network *n = &uzbl.net;
2209 for (i = 0; default_config[i].command != NULL; i++) {
2210 parse_cmd_line(default_config[i].command);
2213 if (!s->config_file) {
2214 s->config_file = find_xdg_file (0, "/uzbl/config");
2217 if (s->config_file) {
2218 GArray* lines = read_file_by_line (s->config_file);
2222 while ((line = g_array_index(lines, gchar*, i))) {
2223 parse_cmd_line (line);
2227 g_array_free (lines, TRUE);
2229 if (uzbl.state.verbose)
2230 printf ("No configuration file loaded.\n");
2233 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2236 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2239 if (!uzbl.behave.cookie_handler)
2242 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2243 GString *s = g_string_new ("");
2244 SoupURI * soup_uri = soup_message_get_uri(msg);
2245 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2246 run_handler(uzbl.behave.cookie_handler, s->str);
2248 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2249 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2250 if ( p != NULL ) *p = '\0';
2251 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2253 if (uzbl.comm.sync_stdout)
2254 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2256 g_string_free(s, TRUE);
2260 save_cookies (SoupMessage *msg, gpointer user_data){
2264 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2265 cookie = soup_cookie_to_set_cookie_header(ck->data);
2266 SoupURI * soup_uri = soup_message_get_uri(msg);
2267 GString *s = g_string_new ("");
2268 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2269 run_handler(uzbl.behave.cookie_handler, s->str);
2271 g_string_free(s, TRUE);
2276 /* --- WEBINSPECTOR --- */
2278 hide_window_cb(GtkWidget *widget, gpointer data) {
2281 gtk_widget_hide(widget);
2284 static WebKitWebView*
2285 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2288 (void) web_inspector;
2289 GtkWidget* scrolled_window;
2290 GtkWidget* new_web_view;
2293 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2294 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2295 G_CALLBACK(hide_window_cb), NULL);
2297 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2298 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2299 gtk_widget_show(g->inspector_window);
2301 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2302 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2303 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2304 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2305 gtk_widget_show(scrolled_window);
2307 new_web_view = webkit_web_view_new();
2308 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2310 return WEBKIT_WEB_VIEW(new_web_view);
2314 inspector_show_window_cb (WebKitWebInspector* inspector){
2316 gtk_widget_show(uzbl.gui.inspector_window);
2320 /* TODO: Add variables and code to make use of these functions */
2322 inspector_close_window_cb (WebKitWebInspector* inspector){
2328 inspector_attach_window_cb (WebKitWebInspector* inspector){
2334 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2340 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2346 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2352 set_up_inspector() {
2354 WebKitWebSettings *settings = view_settings();
2355 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2357 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2358 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2359 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2360 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2361 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2362 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2363 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2365 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2369 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2371 uzbl_cmdprop *c = v;
2376 if(c->type == TYPE_STR)
2377 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2378 else if(c->type == TYPE_INT)
2379 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2383 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2387 printf("bind %s = %s %s\n", (char *)k ,
2388 (char *)a->name, a->param?(char *)a->param:"");
2393 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2394 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2399 main (int argc, char* argv[]) {
2400 gtk_init (&argc, &argv);
2401 if (!g_thread_supported ())
2402 g_thread_init (NULL);
2403 uzbl.state.executable_path = g_strdup(argv[0]);
2404 uzbl.state.selected_url = NULL;
2405 uzbl.state.searchtx = NULL;
2407 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2408 g_option_context_add_main_entries (context, entries, NULL);
2409 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2410 g_option_context_parse (context, &argc, &argv, NULL);
2411 g_option_context_free(context);
2413 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2414 gboolean verbose_override = uzbl.state.verbose;
2416 /* initialize hash table */
2417 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2419 uzbl.net.soup_session = webkit_get_default_session();
2420 uzbl.state.keycmd = g_string_new("");
2422 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2423 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2424 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2425 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2426 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2427 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2430 if(uname(&uzbl.state.unameinfo) == -1)
2431 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2433 uzbl.gui.sbar.progress_s = g_strdup("=");
2434 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2435 uzbl.gui.sbar.progress_w = 10;
2437 /* HTML mode defaults*/
2438 uzbl.behave.html_buffer = g_string_new("");
2439 uzbl.behave.html_endmarker = g_strdup(".");
2440 uzbl.behave.html_timeout = 60;
2441 uzbl.behave.base_url = g_strdup("http://invalid");
2443 /* default mode indicators */
2444 uzbl.behave.insert_indicator = g_strdup("I");
2445 uzbl.behave.cmd_indicator = g_strdup("C");
2449 make_var_to_name_hash();
2451 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2453 uzbl.gui.scrolled_win = create_browser();
2456 /* initial packing */
2457 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2458 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2460 uzbl.gui.main_window = create_window ();
2461 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2464 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2465 gtk_widget_show_all (uzbl.gui.main_window);
2466 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2468 if (uzbl.state.verbose) {
2469 printf("Uzbl start location: %s\n", argv[0]);
2470 printf("window_id %i\n",(int) uzbl.xwin);
2471 printf("pid %i\n", getpid ());
2472 printf("name: %s\n", uzbl.state.instance_name);
2475 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2476 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2477 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2478 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2479 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2483 if (!uzbl.behave.show_status)
2484 gtk_widget_hide(uzbl.gui.mainbar);
2493 if (verbose_override > uzbl.state.verbose)
2494 uzbl.state.verbose = verbose_override;
2497 set_var_value("uri", uri_override);
2498 g_free(uri_override);
2499 } else if (uzbl.state.uri)
2500 cmd_load_uri(uzbl.gui.web_view, NULL);
2505 return EXIT_SUCCESS;
2508 /* vi: set et ts=4: */