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 { "runcmd", {runcmd, NOSPLIT} },
616 { "set", {set_var, NOSPLIT} },
617 { "get", {get_var, NOSPLIT} },
618 { "bind", {act_bind, NOSPLIT} },
619 { "dump_config", {act_dump_config, 0} },
620 { "keycmd", {keycmd, NOSPLIT} },
621 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
622 { "keycmd_bs", {keycmd_bs, 0} },
623 { "chain", {chain, 0} }
630 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
632 for (i = 0; i < LENGTH(cmdlist); i++)
633 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
636 /* -- CORE FUNCTIONS -- */
639 free_action(gpointer act) {
640 Action *action = (Action*)act;
641 g_free(action->name);
643 g_free(action->param);
648 new_action(const gchar *name, const gchar *param) {
649 Action *action = g_new(Action, 1);
651 action->name = g_strdup(name);
653 action->param = g_strdup(param);
655 action->param = NULL;
661 file_exists (const char * filename) {
662 return (access(filename, F_OK) == 0);
666 set_var(WebKitWebView *page, GArray *argv) {
668 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
669 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
670 set_var_value(g_strstrip(split[0]), value);
676 get_var(WebKitWebView *page, GArray *argv) {
678 get_var_value(argv_idx(argv, 0));
682 act_bind(WebKitWebView *page, GArray *argv) {
684 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
685 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
686 add_binding(g_strstrip(split[0]), value);
698 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
701 if (argv_idx(argv, 0)) {
702 if (strcmp (argv_idx(argv, 0), "0") == 0) {
703 uzbl.behave.insert_mode = FALSE;
705 uzbl.behave.insert_mode = TRUE;
708 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
715 load_uri (WebKitWebView *web_view, GArray *argv) {
716 if (argv_idx(argv, 0)) {
717 GString* newuri = g_string_new (argv_idx(argv, 0));
718 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
719 g_string_prepend (newuri, "http://");
720 /* if we do handle cookies, ask our handler for them */
721 webkit_web_view_load_uri (web_view, newuri->str);
722 g_string_free (newuri, TRUE);
727 run_js (WebKitWebView * web_view, GArray *argv) {
728 if (argv_idx(argv, 0))
729 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
733 run_external_js (WebKitWebView * web_view, GArray *argv) {
734 if (argv_idx(argv, 0)) {
735 GArray* lines = read_file_by_line (argv_idx (argv, 0));
740 while ((line = g_array_index(lines, gchar*, i))) {
742 js = g_strdup (line);
744 gchar* newjs = g_strconcat (js, line, NULL);
751 if (uzbl.state.verbose)
752 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
754 if (argv_idx (argv, 1)) {
755 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
759 webkit_web_view_execute_script (web_view, js);
761 g_array_free (lines, TRUE);
766 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
767 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
768 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
769 webkit_web_view_unmark_text_matches (page);
770 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
771 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
775 if (uzbl.state.searchtx) {
776 if (uzbl.state.verbose)
777 printf ("Searching: %s\n", uzbl.state.searchtx);
778 webkit_web_view_set_highlight_text_matches (page, TRUE);
779 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
784 search_forward_text (WebKitWebView *page, GArray *argv) {
785 search_text(page, argv, TRUE);
789 search_reverse_text (WebKitWebView *page, GArray *argv) {
790 search_text(page, argv, FALSE);
794 dehilight (WebKitWebView *page, GArray *argv) {
796 webkit_web_view_set_highlight_text_matches (page, FALSE);
801 new_window_load_uri (const gchar * uri) {
802 GString* to_execute = g_string_new ("");
803 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
805 for (i = 0; entries[i].long_name != NULL; i++) {
806 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
807 gchar** str = (gchar**)entries[i].arg_data;
809 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
813 if (uzbl.state.verbose)
814 printf("\n%s\n", to_execute->str);
815 g_spawn_command_line_async (to_execute->str, NULL);
816 g_string_free (to_execute, TRUE);
820 chain (WebKitWebView *page, GArray *argv) {
823 gchar **parts = NULL;
825 while ((a = argv_idx(argv, i++))) {
826 parts = g_strsplit (a, " ", 2);
827 parse_command(parts[0], parts[1]);
833 keycmd (WebKitWebView *page, GArray *argv) {
836 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
842 keycmd_nl (WebKitWebView *page, GArray *argv) {
845 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
851 keycmd_bs (WebKitWebView *page, GArray *argv) {
854 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
859 close_uzbl (WebKitWebView *page, GArray *argv) {
865 /* --Statusbar functions-- */
867 build_progressbar_ascii(int percent) {
868 int width=uzbl.gui.sbar.progress_w;
871 GString *bar = g_string_new("");
873 l = (double)percent*((double)width/100.);
874 l = (int)(l+.5)>=(int)l ? l+.5 : l;
876 for(i=0; i<(int)l; i++)
877 g_string_append(bar, uzbl.gui.sbar.progress_s);
880 g_string_append(bar, uzbl.gui.sbar.progress_u);
882 return g_string_free(bar, FALSE);
887 const GScannerConfig scan_config = {
890 ) /* cset_skip_characters */,
895 ) /* cset_identifier_first */,
902 ) /* cset_identifier_nth */,
903 ( "" ) /* cpair_comment_single */,
905 TRUE /* case_sensitive */,
907 FALSE /* skip_comment_multi */,
908 FALSE /* skip_comment_single */,
909 FALSE /* scan_comment_multi */,
910 TRUE /* scan_identifier */,
911 TRUE /* scan_identifier_1char */,
912 FALSE /* scan_identifier_NULL */,
913 TRUE /* scan_symbols */,
914 FALSE /* scan_binary */,
915 FALSE /* scan_octal */,
916 FALSE /* scan_float */,
917 FALSE /* scan_hex */,
918 FALSE /* scan_hex_dollar */,
919 FALSE /* scan_string_sq */,
920 FALSE /* scan_string_dq */,
921 TRUE /* numbers_2_int */,
922 FALSE /* int_2_float */,
923 FALSE /* identifier_2_string */,
924 FALSE /* char_2_token */,
925 FALSE /* symbol_2_token */,
926 TRUE /* scope_0_fallback */,
931 uzbl.scan = g_scanner_new(&scan_config);
932 while(symp->symbol_name) {
933 g_scanner_scope_add_symbol(uzbl.scan, 0,
935 GINT_TO_POINTER(symp->symbol_token));
941 expand_template(const char *template, gboolean escape_markup) {
942 if(!template) return NULL;
944 GTokenType token = G_TOKEN_NONE;
945 GString *ret = g_string_new("");
949 g_scanner_input_text(uzbl.scan, template, strlen(template));
950 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
951 token = g_scanner_get_next_token(uzbl.scan);
953 if(token == G_TOKEN_SYMBOL) {
954 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
958 buf = uzbl.state.uri?
959 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
960 g_string_append(ret, buf);
964 g_string_append(ret, uzbl.state.uri?
965 uzbl.state.uri:g_strdup(""));
968 buf = itos(uzbl.gui.sbar.load_progress);
969 g_string_append(ret, buf);
972 case SYM_LOADPRGSBAR:
973 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
974 g_string_append(ret, buf);
979 buf = uzbl.gui.main_title?
980 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
981 g_string_append(ret, buf);
985 g_string_append(ret, uzbl.gui.main_title?
986 uzbl.gui.main_title:g_strdup(""));
988 case SYM_SELECTED_URI:
990 buf = uzbl.state.selected_url?
991 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
992 g_string_append(ret, buf);
996 g_string_append(ret, uzbl.state.selected_url?
997 uzbl.state.selected_url:g_strdup(""));
1000 buf = itos(uzbl.xwin);
1001 g_string_append(ret,
1002 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1007 buf = uzbl.state.keycmd->str?
1008 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1009 g_string_append(ret, buf);
1013 g_string_append(ret, uzbl.state.keycmd->str?
1014 uzbl.state.keycmd->str:g_strdup(""));
1017 g_string_append(ret,
1018 uzbl.behave.insert_mode?
1019 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1022 g_string_append(ret,
1023 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1025 /* useragent syms */
1027 buf = itos(WEBKIT_MAJOR_VERSION);
1028 g_string_append(ret, buf);
1032 buf = itos(WEBKIT_MINOR_VERSION);
1033 g_string_append(ret, buf);
1037 buf = itos(WEBKIT_MICRO_VERSION);
1038 g_string_append(ret, buf);
1042 g_string_append(ret, uzbl.state.unameinfo.sysname);
1045 g_string_append(ret, uzbl.state.unameinfo.nodename);
1048 g_string_append(ret, uzbl.state.unameinfo.release);
1051 g_string_append(ret, uzbl.state.unameinfo.version);
1054 g_string_append(ret, uzbl.state.unameinfo.machine);
1057 g_string_append(ret, ARCH);
1060 case SYM_DOMAINNAME:
1061 g_string_append(ret, uzbl.state.unameinfo.domainname);
1065 g_string_append(ret, COMMIT);
1071 else if(token == G_TOKEN_INT) {
1072 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1073 g_string_append(ret, buf);
1076 else if(token == G_TOKEN_IDENTIFIER) {
1077 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1079 else if(token == G_TOKEN_CHAR) {
1080 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1084 return g_string_free(ret, FALSE);
1086 /* --End Statusbar functions-- */
1089 sharg_append(GArray *a, const gchar *str) {
1090 const gchar *s = (str ? str : "");
1091 g_array_append_val(a, s);
1094 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1096 run_command (const gchar *command, const guint npre, const gchar **args,
1097 const gboolean sync, char **stdout) {
1098 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1101 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1102 gchar *pid = itos(getpid());
1103 gchar *xwin = itos(uzbl.xwin);
1105 sharg_append(a, command);
1106 for (i = 0; i < npre; i++) /* add n args before the default vars */
1107 sharg_append(a, args[i]);
1108 sharg_append(a, uzbl.state.config_file);
1109 sharg_append(a, pid);
1110 sharg_append(a, xwin);
1111 sharg_append(a, uzbl.comm.fifo_path);
1112 sharg_append(a, uzbl.comm.socket_path);
1113 sharg_append(a, uzbl.state.uri);
1114 sharg_append(a, uzbl.gui.main_title);
1116 for (i = npre; i < g_strv_length((gchar**)args); i++)
1117 sharg_append(a, args[i]);
1121 if (*stdout) *stdout = strfree(*stdout);
1123 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1124 NULL, NULL, stdout, NULL, NULL, &err);
1125 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1126 NULL, NULL, NULL, &err);
1128 if (uzbl.state.verbose) {
1129 GString *s = g_string_new("spawned:");
1130 for (i = 0; i < (a->len); i++) {
1131 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1132 g_string_append_printf(s, " %s", qarg);
1135 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1136 printf("%s\n", s->str);
1137 g_string_free(s, TRUE);
1140 g_printerr("error on run_command: %s\n", err->message);
1145 g_array_free (a, TRUE);
1150 split_quoted(const gchar* src, const gboolean unquote) {
1151 /* split on unquoted space, return array of strings;
1152 remove a layer of quotes and backslashes if unquote */
1153 if (!src) return NULL;
1155 gboolean dq = FALSE;
1156 gboolean sq = FALSE;
1157 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1158 GString *s = g_string_new ("");
1162 for (p = src; *p != '\0'; p++) {
1163 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1164 else if (*p == '\\') { g_string_append_c(s, *p++);
1165 g_string_append_c(s, *p); }
1166 else if ((*p == '"') && unquote && !sq) dq = !dq;
1167 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1169 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1170 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1172 else if ((*p == ' ') && !dq && !sq) {
1173 dup = g_strdup(s->str);
1174 g_array_append_val(a, dup);
1175 g_string_truncate(s, 0);
1176 } else g_string_append_c(s, *p);
1178 dup = g_strdup(s->str);
1179 g_array_append_val(a, dup);
1180 ret = (gchar**)a->data;
1181 g_array_free (a, FALSE);
1182 g_string_free (s, TRUE);
1187 spawn(WebKitWebView *web_view, GArray *argv) {
1189 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1190 if (argv_idx(argv, 0))
1191 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1195 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1198 if (argv_idx(argv, 0))
1199 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1200 TRUE, &uzbl.comm.sync_stdout);
1204 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1206 if (!uzbl.behave.shell_cmd) {
1207 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1212 gchar *spacer = g_strdup("");
1213 g_array_insert_val(argv, 1, spacer);
1214 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1216 for (i = 1; i < g_strv_length(cmd); i++)
1217 g_array_prepend_val(argv, cmd[i]);
1219 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1225 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1227 if (!uzbl.behave.shell_cmd) {
1228 g_printerr ("spawn_sh_sync: 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,
1241 TRUE, &uzbl.comm.sync_stdout);
1247 parse_command(const char *cmd, const char *param) {
1250 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1253 gchar **par = split_quoted(param, TRUE);
1254 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1256 if (c[1] == NOSPLIT) { /* don't split */
1257 sharg_append(a, param);
1259 for (i = 0; i < g_strv_length(par); i++)
1260 sharg_append(a, par[i]);
1262 c[0](uzbl.gui.web_view, a);
1264 g_array_free (a, TRUE);
1267 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1270 /* command parser */
1273 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1274 G_REGEX_OPTIMIZE, 0, NULL);
1278 get_var_value(const gchar *name) {
1281 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1282 if(c->type == TYPE_STR)
1283 printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr);
1284 else if(c->type == TYPE_INT)
1285 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1294 if(*uzbl.net.proxy_url == ' '
1295 || uzbl.net.proxy_url == NULL) {
1296 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1297 (GType) SOUP_SESSION_PROXY_URI);
1300 suri = soup_uri_new(uzbl.net.proxy_url);
1301 g_object_set(G_OBJECT(uzbl.net.soup_session),
1302 SOUP_SESSION_PROXY_URI,
1304 soup_uri_free(suri);
1311 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1312 g_array_append_val (a, uzbl.state.uri);
1313 load_uri(uzbl.gui.web_view, a);
1314 g_array_free (a, TRUE);
1318 cmd_always_insert_mode() {
1319 uzbl.behave.insert_mode =
1320 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1326 g_object_set(G_OBJECT(uzbl.net.soup_session),
1327 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1331 cmd_max_conns_host() {
1332 g_object_set(G_OBJECT(uzbl.net.soup_session),
1333 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1338 soup_session_remove_feature
1339 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1340 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1341 /*g_free(uzbl.net.soup_logger);*/
1343 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1344 soup_session_add_feature(uzbl.net.soup_session,
1345 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1348 static WebKitWebSettings*
1350 return webkit_web_view_get_settings(uzbl.gui.web_view);
1355 WebKitWebSettings *ws = view_settings();
1356 if (uzbl.behave.font_size > 0) {
1357 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1360 if (uzbl.behave.monospace_size > 0) {
1361 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1362 uzbl.behave.monospace_size, NULL);
1364 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1365 uzbl.behave.font_size, NULL);
1370 cmd_disable_plugins() {
1371 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1372 !uzbl.behave.disable_plugins, NULL);
1376 cmd_disable_scripts() {
1377 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1378 !uzbl.behave.disable_scripts, NULL);
1382 cmd_minimum_font_size() {
1383 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1384 uzbl.behave.minimum_font_size, NULL);
1387 cmd_autoload_img() {
1388 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1389 uzbl.behave.autoload_img, NULL);
1394 cmd_autoshrink_img() {
1395 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1396 uzbl.behave.autoshrink_img, NULL);
1401 cmd_enable_spellcheck() {
1402 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1403 uzbl.behave.enable_spellcheck, NULL);
1407 cmd_enable_private() {
1408 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1409 uzbl.behave.enable_private, NULL);
1414 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1415 uzbl.behave.print_bg, NULL);
1420 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1421 uzbl.behave.style_uri, NULL);
1425 cmd_resizable_txt() {
1426 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1427 uzbl.behave.resizable_txt, NULL);
1431 cmd_default_encoding() {
1432 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1433 uzbl.behave.default_encoding, NULL);
1437 cmd_enforce_96dpi() {
1438 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1439 uzbl.behave.enforce_96dpi, NULL);
1443 cmd_caret_browsing() {
1444 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1445 uzbl.behave.caret_browsing, NULL);
1449 cmd_cookie_handler() {
1450 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1451 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1452 if ((g_strcmp0(split[0], "sh") == 0) ||
1453 (g_strcmp0(split[0], "spawn") == 0)) {
1454 g_free (uzbl.behave.cookie_handler);
1455 uzbl.behave.cookie_handler =
1456 g_strdup_printf("sync_%s %s", split[0], split[1]);
1463 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1468 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1473 if(uzbl.behave.inject_html) {
1474 webkit_web_view_load_html_string (uzbl.gui.web_view,
1475 uzbl.behave.inject_html, NULL);
1484 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1485 uzbl.behave.modmask = 0;
1487 if(uzbl.behave.modkey)
1488 g_free(uzbl.behave.modkey);
1489 uzbl.behave.modkey = buf;
1491 for (i = 0; modkeys[i].key != NULL; i++) {
1492 if (g_strrstr(buf, modkeys[i].key))
1493 uzbl.behave.modmask |= modkeys[i].mask;
1499 if (*uzbl.net.useragent == ' ') {
1500 g_free (uzbl.net.useragent);
1501 uzbl.net.useragent = NULL;
1503 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1505 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1506 g_free(uzbl.net.useragent);
1507 uzbl.net.useragent = ua;
1513 gtk_widget_ref(uzbl.gui.scrolled_win);
1514 gtk_widget_ref(uzbl.gui.mainbar);
1515 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1516 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1518 if(uzbl.behave.status_top) {
1519 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1520 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1523 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.mainbar, FALSE, TRUE, 0);
1526 gtk_widget_unref(uzbl.gui.scrolled_win);
1527 gtk_widget_unref(uzbl.gui.mainbar);
1528 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1533 set_var_value(gchar *name, gchar *val) {
1534 uzbl_cmdprop *c = NULL;
1538 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1539 /* check for the variable type */
1540 if (c->type == TYPE_STR) {
1541 buf = expand_vars(val);
1544 } else if(c->type == TYPE_INT) {
1545 int *ip = (int *)c->ptr;
1546 buf = expand_vars(val);
1547 *ip = (int)strtoul(buf, &endp, 10);
1551 /* invoke a command specific function */
1552 if(c->func) c->func();
1558 runcmd(WebKitWebView* page, GArray *argv) {
1560 parse_cmd_line(argv_idx(argv, 0));
1565 Behaviour *b = &uzbl.behave;
1567 if(b->html_buffer->str) {
1568 webkit_web_view_load_html_string (uzbl.gui.web_view,
1569 b->html_buffer->str, b->base_url);
1570 g_string_free(b->html_buffer, TRUE);
1571 b->html_buffer = g_string_new("");
1575 enum {M_CMD, M_HTML};
1577 parse_cmd_line(const char *ctl_line) {
1578 gchar **tokens = NULL;
1579 Behaviour *b = &uzbl.behave;
1582 if(b->mode == M_HTML) {
1583 len = strlen(b->html_endmarker);
1584 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1585 if(len == strlen(ctl_line)-1 &&
1586 !strncmp(b->html_endmarker, ctl_line, len)) {
1588 set_var_value("mode", "0");
1593 set_timeout(b->html_timeout);
1594 g_string_append(b->html_buffer, ctl_line);
1599 if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1600 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1601 if(tokens[0][0] == 0) {
1602 parse_command(tokens[1], tokens[2]);
1605 printf("Error in command: %s\n", tokens[0]);
1608 else if( (ctl_line[0] == '#')
1609 || (ctl_line[0] == ' ')
1610 || (ctl_line[0] == '\n'))
1611 ; /* ignore these lines */
1613 printf("Command not understood (%s)\n", ctl_line);
1623 build_stream_name(int type, const gchar* dir) {
1625 State *s = &uzbl.state;
1628 xwin_str = itos((int)uzbl.xwin);
1630 str = g_strdup_printf
1631 ("%s/uzbl_fifo_%s", dir,
1632 s->instance_name ? s->instance_name : xwin_str);
1633 } else if (type == SOCKET) {
1634 str = g_strdup_printf
1635 ("%s/uzbl_socket_%s", dir,
1636 s->instance_name ? s->instance_name : xwin_str );
1643 control_fifo(GIOChannel *gio, GIOCondition condition) {
1644 if (uzbl.state.verbose)
1645 printf("triggered\n");
1650 if (condition & G_IO_HUP)
1651 g_error ("Fifo: Read end of pipe died!\n");
1654 g_error ("Fifo: GIOChannel broke\n");
1656 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1657 if (ret == G_IO_STATUS_ERROR) {
1658 g_error ("Fifo: Error reading: %s\n", err->message);
1662 parse_cmd_line(ctl_line);
1669 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1670 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1671 if (unlink(uzbl.comm.fifo_path) == -1)
1672 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1673 g_free(uzbl.comm.fifo_path);
1674 uzbl.comm.fifo_path = NULL;
1677 if (*dir == ' ') { /* space unsets the variable */
1682 GIOChannel *chan = NULL;
1683 GError *error = NULL;
1684 gchar *path = build_stream_name(FIFO, dir);
1686 if (!file_exists(path)) {
1687 if (mkfifo (path, 0666) == 0) {
1688 // 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.
1689 chan = g_io_channel_new_file(path, "r+", &error);
1691 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1692 if (uzbl.state.verbose)
1693 printf ("init_fifo: created successfully as %s\n", path);
1694 uzbl.comm.fifo_path = path;
1696 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1697 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1698 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1699 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1701 /* if we got this far, there was an error; cleanup */
1702 if (error) g_error_free (error);
1709 control_stdin(GIOChannel *gio, GIOCondition condition) {
1711 gchar *ctl_line = NULL;
1714 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1715 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1718 parse_cmd_line(ctl_line);
1726 GIOChannel *chan = NULL;
1727 GError *error = NULL;
1729 chan = g_io_channel_unix_new(fileno(stdin));
1731 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1732 g_error ("Stdin: could not add watch\n");
1734 if (uzbl.state.verbose)
1735 printf ("Stdin: watch added successfully\n");
1738 g_error ("Stdin: Error while opening: %s\n", error->message);
1740 if (error) g_error_free (error);
1744 control_socket(GIOChannel *chan) {
1745 struct sockaddr_un remote;
1746 char buffer[512], *ctl_line;
1748 int sock, clientsock, n, done;
1751 sock = g_io_channel_unix_get_fd(chan);
1753 memset (buffer, 0, sizeof (buffer));
1755 t = sizeof (remote);
1756 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1760 memset (temp, 0, sizeof (temp));
1761 n = recv (clientsock, temp, 128, 0);
1763 buffer[strlen (buffer)] = '\0';
1767 strcat (buffer, temp);
1770 if (strcmp (buffer, "\n") < 0) {
1771 buffer[strlen (buffer) - 1] = '\0';
1773 buffer[strlen (buffer)] = '\0';
1776 ctl_line = g_strdup(buffer);
1777 parse_cmd_line (ctl_line);
1780 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1781 GError *error = NULL;
1784 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1785 if (ret == G_IO_STATUS_ERROR)
1786 g_error ("Error reading: %s\n", error->message);
1788 printf("Got line %s (%u bytes) \n",ctl_line, len);
1790 parse_line(ctl_line);
1798 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1799 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1800 if (unlink(uzbl.comm.socket_path) == -1)
1801 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1802 g_free(uzbl.comm.socket_path);
1803 uzbl.comm.socket_path = NULL;
1811 GIOChannel *chan = NULL;
1813 struct sockaddr_un local;
1814 gchar *path = build_stream_name(SOCKET, dir);
1816 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1818 local.sun_family = AF_UNIX;
1819 strcpy (local.sun_path, path);
1820 unlink (local.sun_path);
1822 len = strlen (local.sun_path) + sizeof (local.sun_family);
1823 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1824 if (uzbl.state.verbose)
1825 printf ("init_socket: opened in %s\n", path);
1828 if( (chan = g_io_channel_unix_new(sock)) ) {
1829 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1830 uzbl.comm.socket_path = path;
1833 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1835 /* if we got this far, there was an error; cleanup */
1842 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1843 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1845 // this function may be called very early when the templates are not set (yet), hence the checks
1847 update_title (void) {
1848 Behaviour *b = &uzbl.behave;
1851 if (b->show_status) {
1852 if (b->title_format_short) {
1853 parsed = expand_template(b->title_format_short, FALSE);
1854 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1857 if (b->status_format) {
1858 parsed = expand_template(b->status_format, TRUE);
1859 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1862 if (b->status_background) {
1864 gdk_color_parse (b->status_background, &color);
1865 //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)
1866 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1869 if (b->title_format_long) {
1870 parsed = expand_template(b->title_format_long, FALSE);
1871 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1878 key_press_cb (GtkWidget* window, GdkEventKey* event)
1880 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1884 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1885 || 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)
1888 /* turn off insert mode (if always_insert_mode is not used) */
1889 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1890 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1895 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1898 if (event->keyval == GDK_Escape) {
1899 g_string_truncate(uzbl.state.keycmd, 0);
1901 dehilight(uzbl.gui.web_view, NULL);
1905 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1906 if (event->keyval == GDK_Insert) {
1908 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1909 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1911 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1914 g_string_append (uzbl.state.keycmd, str);
1921 if (event->keyval == GDK_BackSpace)
1922 keycmd_bs(NULL, NULL);
1924 gboolean key_ret = FALSE;
1925 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1927 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1929 run_keycmd(key_ret);
1931 if (key_ret) return (!uzbl.behave.insert_mode);
1936 run_keycmd(const gboolean key_ret) {
1937 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1939 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1940 g_string_truncate(uzbl.state.keycmd, 0);
1941 parse_command(act->name, act->param);
1945 /* try if it's an incremental keycmd or one that takes args, and run it */
1946 GString* short_keys = g_string_new ("");
1947 GString* short_keys_inc = g_string_new ("");
1949 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1950 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1951 g_string_assign(short_keys_inc, short_keys->str);
1952 g_string_append_c(short_keys, '_');
1953 g_string_append_c(short_keys_inc, '*');
1955 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1956 /* run normal cmds only if return was pressed */
1957 exec_paramcmd(act, i);
1958 g_string_truncate(uzbl.state.keycmd, 0);
1960 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1961 if (key_ret) /* just quit the incremental command on return */
1962 g_string_truncate(uzbl.state.keycmd, 0);
1963 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1967 g_string_truncate(short_keys, short_keys->len - 1);
1969 g_string_free (short_keys, TRUE);
1970 g_string_free (short_keys_inc, TRUE);
1974 exec_paramcmd(const Action *act, const guint i) {
1975 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1976 GString *actionname = g_string_new ("");
1977 GString *actionparam = g_string_new ("");
1978 g_string_erase (parampart, 0, i+1);
1980 g_string_printf (actionname, act->name, parampart->str);
1982 g_string_printf (actionparam, act->param, parampart->str);
1983 parse_command(actionname->str, actionparam->str);
1984 g_string_free(actionname, TRUE);
1985 g_string_free(actionparam, TRUE);
1986 g_string_free(parampart, TRUE);
1994 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1995 //main_window_ref = g_object_ref(scrolled_window);
1996 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
1998 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1999 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2001 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2002 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2003 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2004 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2012 return scrolled_window;
2019 g->mainbar = gtk_hbox_new (FALSE, 0);
2021 /* keep a reference to the bar so we can re-pack it at runtime*/
2022 //sbar_ref = g_object_ref(g->mainbar);
2024 g->mainbar_label = gtk_label_new ("");
2025 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2026 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2027 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2028 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2029 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2034 GtkWidget* create_window () {
2035 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2036 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2037 gtk_widget_set_name (window, "Uzbl browser");
2038 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2039 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2045 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2047 If actname is one that calls an external command, this function will inject
2048 newargs in front of the user-provided args in that command line. They will
2049 come become after the body of the script (in sh) or after the name of
2050 the command to execute (in spawn).
2051 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2052 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2054 The return value consist of two strings: the action (sh, ...) and its args.
2056 If act is not one that calls an external command, then the given action merely
2059 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2060 gchar *actdup = g_strdup(actname);
2061 g_array_append_val(rets, actdup);
2063 if ((g_strcmp0(actname, "spawn") == 0) ||
2064 (g_strcmp0(actname, "sh") == 0) ||
2065 (g_strcmp0(actname, "sync_spawn") == 0) ||
2066 (g_strcmp0(actname, "sync_sh") == 0)) {
2068 GString *a = g_string_new("");
2069 gchar **spawnparts = split_quoted(origargs, FALSE);
2070 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2071 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2073 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2074 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2076 g_array_append_val(rets, a->str);
2077 g_string_free(a, FALSE);
2078 g_strfreev(spawnparts);
2080 gchar *origdup = g_strdup(origargs);
2081 g_array_append_val(rets, origdup);
2083 return (gchar**)g_array_free(rets, FALSE);
2087 run_handler (const gchar *act, const gchar *args) {
2088 /* Consider this code a temporary hack to make the handlers usable.
2089 In practice, all this splicing, injection, and reconstruction is
2090 inefficient, annoying and hard to manage. Potential pitfalls arise
2091 when the handler specific args 1) are not quoted (the handler
2092 callbacks should take care of this) 2) are quoted but interfere
2093 with the users' own quotation. A more ideal solution is
2094 to refactor parse_command so that it doesn't just take a string
2095 and execute it; rather than that, we should have a function which
2096 returns the argument vector parsed from the string. This vector
2097 could be modified (e.g. insert additional args into it) before
2098 passing it to the next function that actually executes it. Though
2099 it still isn't perfect for chain actions.. will reconsider & re-
2100 factor when I have the time. -duc */
2102 char **parts = g_strsplit(act, " ", 2);
2104 if (g_strcmp0(parts[0], "chain") == 0) {
2105 GString *newargs = g_string_new("");
2106 gchar **chainparts = split_quoted(parts[1], FALSE);
2108 /* for every argument in the chain, inject the handler args
2109 and make sure the new parts are wrapped in quotes */
2110 gchar **cp = chainparts;
2112 gchar *quotless = NULL;
2113 gchar **spliced_quotless = NULL; // sigh -_-;
2114 gchar **inpart = NULL;
2117 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2119 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2120 } else quotless = g_strdup(*cp);
2122 spliced_quotless = g_strsplit(quotless, " ", 2);
2123 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2124 g_strfreev(spliced_quotless);
2126 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2132 parse_command(parts[0], &(newargs->str[1]));
2133 g_string_free(newargs, TRUE);
2134 g_strfreev(chainparts);
2137 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2138 parse_command(inparts[0], inparts[1]);
2146 add_binding (const gchar *key, const gchar *act) {
2147 char **parts = g_strsplit(act, " ", 2);
2154 if (uzbl.state.verbose)
2155 printf ("Binding %-10s : %s\n", key, act);
2156 action = new_action(parts[0], parts[1]);
2158 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2163 get_xdg_var (XDG_Var xdg) {
2164 const gchar* actual_value = getenv (xdg.environmental);
2165 const gchar* home = getenv ("HOME");
2167 gchar* return_value = str_replace ("~", home, actual_value);
2169 if (! actual_value || strcmp (actual_value, "") == 0) {
2170 if (xdg.default_value) {
2171 return_value = str_replace ("~", home, xdg.default_value);
2173 return_value = NULL;
2176 return return_value;
2180 find_xdg_file (int xdg_type, char* filename) {
2181 /* xdg_type = 0 => config
2182 xdg_type = 1 => data
2183 xdg_type = 2 => cache*/
2185 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2186 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2189 gchar* temporary_string;
2193 if (! file_exists (temporary_file) && xdg_type != 2) {
2194 buf = get_xdg_var (XDG[3 + xdg_type]);
2195 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2198 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2199 g_free (temporary_file);
2200 temporary_file = g_strconcat (temporary_string, filename, NULL);
2204 //g_free (temporary_string); - segfaults.
2206 if (file_exists (temporary_file)) {
2207 return temporary_file;
2214 State *s = &uzbl.state;
2215 Network *n = &uzbl.net;
2217 for (i = 0; default_config[i].command != NULL; i++) {
2218 parse_cmd_line(default_config[i].command);
2221 if (!s->config_file) {
2222 s->config_file = find_xdg_file (0, "/uzbl/config");
2225 if (s->config_file) {
2226 GArray* lines = read_file_by_line (s->config_file);
2230 while ((line = g_array_index(lines, gchar*, i))) {
2231 parse_cmd_line (line);
2235 g_array_free (lines, TRUE);
2237 if (uzbl.state.verbose)
2238 printf ("No configuration file loaded.\n");
2241 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2244 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2247 if (!uzbl.behave.cookie_handler) return;
2249 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2250 GString *s = g_string_new ("");
2251 SoupURI * soup_uri = soup_message_get_uri(msg);
2252 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2253 run_handler(uzbl.behave.cookie_handler, s->str);
2255 if(uzbl.comm.sync_stdout)
2256 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2257 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2258 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2260 g_string_free(s, TRUE);
2264 save_cookies (SoupMessage *msg, gpointer user_data){
2268 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2269 cookie = soup_cookie_to_set_cookie_header(ck->data);
2270 SoupURI * soup_uri = soup_message_get_uri(msg);
2271 GString *s = g_string_new ("");
2272 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2273 run_handler(uzbl.behave.cookie_handler, s->str);
2275 g_string_free(s, TRUE);
2280 /* --- WEBINSPECTOR --- */
2282 hide_window_cb(GtkWidget *widget, gpointer data) {
2285 gtk_widget_hide(widget);
2288 static WebKitWebView*
2289 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2292 (void) web_inspector;
2293 GtkWidget* scrolled_window;
2294 GtkWidget* new_web_view;
2297 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2298 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2299 G_CALLBACK(hide_window_cb), NULL);
2301 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2302 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2303 gtk_widget_show(g->inspector_window);
2305 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2306 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2307 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2308 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2309 gtk_widget_show(scrolled_window);
2311 new_web_view = webkit_web_view_new();
2312 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2314 return WEBKIT_WEB_VIEW(new_web_view);
2318 inspector_show_window_cb (WebKitWebInspector* inspector){
2320 gtk_widget_show(uzbl.gui.inspector_window);
2324 /* TODO: Add variables and code to make use of these functions */
2326 inspector_close_window_cb (WebKitWebInspector* inspector){
2332 inspector_attach_window_cb (WebKitWebInspector* inspector){
2338 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2344 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2350 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2356 set_up_inspector() {
2358 WebKitWebSettings *settings = view_settings();
2359 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2361 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2362 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2363 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2364 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2365 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2366 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2367 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2369 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2373 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2375 uzbl_cmdprop *c = v;
2380 if(c->type == TYPE_STR)
2381 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2382 else if(c->type == TYPE_INT)
2383 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2387 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2391 printf("bind %s = %s %s\n", (char *)k ,
2392 (char *)a->name, a->param?(char *)a->param:"");
2397 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2398 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2403 main (int argc, char* argv[]) {
2404 gtk_init (&argc, &argv);
2405 if (!g_thread_supported ())
2406 g_thread_init (NULL);
2407 uzbl.state.executable_path = g_strdup(argv[0]);
2408 uzbl.state.selected_url = NULL;
2409 uzbl.state.searchtx = NULL;
2411 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2412 g_option_context_add_main_entries (context, entries, NULL);
2413 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2414 g_option_context_parse (context, &argc, &argv, NULL);
2415 g_option_context_free(context);
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");
2450 make_var_to_name_hash();
2452 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2454 uzbl.gui.scrolled_win = create_browser();
2457 /* initial packing */
2458 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2459 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2461 uzbl.gui.main_window = create_window ();
2462 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2465 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2466 gtk_widget_show_all (uzbl.gui.main_window);
2467 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2469 if (uzbl.state.verbose) {
2470 printf("Uzbl start location: %s\n", argv[0]);
2471 printf("window_id %i\n",(int) uzbl.xwin);
2472 printf("pid %i\n", getpid ());
2473 printf("name: %s\n", uzbl.state.instance_name);
2476 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2477 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2478 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2479 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2480 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2484 if (!uzbl.behave.show_status)
2485 gtk_widget_hide(uzbl.gui.mainbar);
2494 if(uzbl.state.uri) {
2495 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2496 g_array_append_val(a, uzbl.state.uri);
2497 load_uri (uzbl.gui.web_view, a);
2498 g_array_free (a, TRUE);
2504 return EXIT_SUCCESS;
2507 /* vi: set et ts=4: */