1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
45 #include <webkit/webkit.h>
53 #include <sys/socket.h>
55 #include <libsoup/soup.h>
61 typedef void (*Command)(WebKitWebView*, GArray *argv);
65 /* commandline arguments (set initial values for the state variables) */
67 GOptionEntry entries[] =
69 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
70 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
71 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
72 "Whether to print all messages or just errors.", NULL },
73 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
74 "Name of the current instance (defaults to Xorg window id)", "NAME" },
75 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
76 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
77 { NULL, 0, 0, 0, NULL, NULL, NULL }
80 /* associate command names to their properties */
81 typedef const struct {
88 enum {TYPE_INT, TYPE_STR};
90 /* an abbreviation to help keep the table's width humane */
91 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
96 } var_name_to_ptr[] = {
97 /* variable name pointer to variable in code type dump callback function */
98 /* --------------------------------------------------------------------------------------- */
99 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
100 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
101 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
102 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
103 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
104 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
105 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
106 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
107 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
108 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
109 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
110 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
111 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
112 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
113 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
114 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
115 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
116 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
117 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
118 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
119 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
120 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
121 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
122 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
123 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
124 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
125 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
126 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
127 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
128 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
129 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
130 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
131 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
132 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
133 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
134 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
135 /* exported WebKitWebSettings properties*/
136 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
137 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
138 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
139 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
140 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
141 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
142 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
143 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
144 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
145 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
146 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
147 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
148 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
149 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
150 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
152 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
153 }, *n2v_p = var_name_to_ptr;
159 { "SHIFT", GDK_SHIFT_MASK }, // shift
160 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
161 { "CONTROL", GDK_CONTROL_MASK }, // control
162 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
163 { "MOD2", GDK_MOD2_MASK }, // 5th mod
164 { "MOD3", GDK_MOD3_MASK }, // 6th mod
165 { "MOD4", GDK_MOD4_MASK }, // 7th mod
166 { "MOD5", GDK_MOD5_MASK }, // 8th mod
167 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
168 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
169 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
170 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
171 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
172 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
173 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
174 { "META", GDK_META_MASK }, // meta (since 2.10)
179 /* construct a hash from the var_name_to_ptr array for quick access */
181 make_var_to_name_hash() {
182 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
184 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
189 /* --- UTILITY FUNCTIONS --- */
191 expand_vars(char *s) {
192 char ret[256], /* 256 chars per var name should be safe */
196 GString *buf = g_string_new("");
199 /* found quotation char */
201 g_string_append_c(buf, *++s);
210 if( (vend = strchr(s, upto)) ||
211 (vend = strchr(s, '\0')) ) {
212 strncpy(ret, s, vend-s);
214 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
215 if(c->type == TYPE_STR)
216 g_string_append(buf, (gchar *)*c->ptr);
217 else if(c->type == TYPE_INT) {
218 char *b = itos((int)*c->ptr);
219 g_string_append(buf, b);
230 /* every other char */
232 g_string_append_c(buf, *s);
236 return g_string_free(buf, FALSE);
243 snprintf(tmp, sizeof(tmp), "%i", val);
244 return g_strdup(tmp);
248 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
251 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
254 str_replace (const char* search, const char* replace, const char* string) {
258 buf = g_strsplit (string, search, -1);
259 ret = g_strjoinv (replace, buf);
260 g_strfreev(buf); // somebody said this segfaults
266 read_file_by_line (gchar *path) {
267 GIOChannel *chan = NULL;
268 gchar *readbuf = NULL;
270 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
273 chan = g_io_channel_new_file(path, "r", NULL);
276 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
277 const gchar* val = g_strdup (readbuf);
278 g_array_append_val (lines, val);
283 g_io_channel_unref (chan);
285 fprintf(stderr, "File '%s' not be read.\n", path);
292 gchar* parseenv (char* string) {
293 extern char** environ;
294 gchar* tmpstr = NULL;
298 while (environ[i] != NULL) {
299 gchar** env = g_strsplit (environ[i], "=", 2);
300 gchar* envname = g_strconcat ("$", env[0], NULL);
302 if (g_strrstr (string, envname) != NULL) {
303 tmpstr = g_strdup(string);
305 string = str_replace(envname, env[1], tmpstr);
310 g_strfreev (env); // somebody said this breaks uzbl
318 setup_signal(int signr, sigfunc *shandler) {
319 struct sigaction nh, oh;
321 nh.sa_handler = shandler;
322 sigemptyset(&nh.sa_mask);
325 if(sigaction(signr, &nh, &oh) < 0)
333 if (uzbl.behave.fifo_dir)
334 unlink (uzbl.comm.fifo_path);
335 if (uzbl.behave.socket_dir)
336 unlink (uzbl.comm.socket_path);
338 g_free(uzbl.state.executable_path);
339 g_string_free(uzbl.state.keycmd, TRUE);
340 g_hash_table_destroy(uzbl.bindings);
341 g_hash_table_destroy(uzbl.behave.commands);
344 /* used for html_mode_timeout
345 * be sure to extend this function to use
346 * more timers if needed in other places
349 set_timeout(int seconds) {
351 memset(&t, 0, sizeof t);
353 t.it_value.tv_sec = seconds;
354 t.it_value.tv_usec = 0;
355 setitimer(ITIMER_REAL, &t, NULL);
358 /* --- SIGNAL HANDLER --- */
361 catch_sigterm(int s) {
367 catch_sigint(int s) {
377 set_var_value("mode", "0");
382 /* --- CALLBACKS --- */
385 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
388 (void) navigation_action;
389 (void) policy_decision;
391 const gchar* uri = webkit_network_request_get_uri (request);
392 if (uzbl.state.verbose)
393 printf("New window requested -> %s \n", uri);
394 new_window_load_uri(uri);
399 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
403 if (uzbl.state.selected_url != NULL) {
404 if (uzbl.state.verbose)
405 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
406 new_window_load_uri(uzbl.state.selected_url);
408 if (uzbl.state.verbose)
409 printf("New web view -> %s\n","Nothing to open, exiting");
415 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
418 if (uzbl.behave.download_handler) {
419 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
420 if (uzbl.state.verbose)
421 printf("Download -> %s\n",uri);
422 /* if urls not escaped, we may have to escape and quote uri before this call */
423 run_handler(uzbl.behave.download_handler, uri);
428 /* scroll a bar in a given direction */
430 scroll (GtkAdjustment* bar, GArray *argv) {
434 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
435 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
436 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
440 scroll_begin(WebKitWebView* page, GArray *argv) {
441 (void) page; (void) argv;
442 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
446 scroll_end(WebKitWebView* page, GArray *argv) {
447 (void) page; (void) argv;
448 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
449 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
453 scroll_vert(WebKitWebView* page, GArray *argv) {
455 scroll(uzbl.gui.bar_v, argv);
459 scroll_horz(WebKitWebView* page, GArray *argv) {
461 scroll(uzbl.gui.bar_h, argv);
466 if (!uzbl.behave.show_status) {
467 gtk_widget_hide(uzbl.gui.mainbar);
469 gtk_widget_show(uzbl.gui.mainbar);
475 toggle_status_cb (WebKitWebView* page, GArray *argv) {
479 if (uzbl.behave.show_status) {
480 gtk_widget_hide(uzbl.gui.mainbar);
482 gtk_widget_show(uzbl.gui.mainbar);
484 uzbl.behave.show_status = !uzbl.behave.show_status;
489 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
493 //Set selected_url state variable
494 g_free(uzbl.state.selected_url);
495 uzbl.state.selected_url = NULL;
497 uzbl.state.selected_url = g_strdup(link);
503 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
507 if (uzbl.gui.main_title)
508 g_free (uzbl.gui.main_title);
509 uzbl.gui.main_title = g_strdup (title);
514 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
517 uzbl.gui.sbar.load_progress = progress;
522 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
526 if (uzbl.behave.load_finish_handler)
527 run_handler(uzbl.behave.load_finish_handler, "");
531 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
535 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
536 if (uzbl.behave.load_start_handler)
537 run_handler(uzbl.behave.load_start_handler, "");
541 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
544 g_free (uzbl.state.uri);
545 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
546 uzbl.state.uri = g_string_free (newuri, FALSE);
547 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
548 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
551 if (uzbl.behave.load_commit_handler)
552 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
556 destroy_cb (GtkWidget* widget, gpointer data) {
564 if (uzbl.behave.history_handler) {
566 struct tm * timeinfo;
569 timeinfo = localtime ( &rawtime );
570 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
571 run_handler(uzbl.behave.history_handler, date);
576 /* VIEW funcs (little webkit wrappers) */
577 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
579 VIEWFUNC(reload_bypass_cache)
580 VIEWFUNC(stop_loading)
587 /* -- command to callback/function map for things we cannot attach to any signals */
589 static struct {char *name; Command command[2];} cmdlist[] =
590 { /* key function no_split */
591 { "back", {view_go_back, 0} },
592 { "forward", {view_go_forward, 0} },
593 { "scroll_vert", {scroll_vert, 0} },
594 { "scroll_horz", {scroll_horz, 0} },
595 { "scroll_begin", {scroll_begin, 0} },
596 { "scroll_end", {scroll_end, 0} },
597 { "reload", {view_reload, 0}, },
598 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
599 { "stop", {view_stop_loading, 0}, },
600 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
601 { "zoom_out", {view_zoom_out, 0}, },
602 { "uri", {load_uri, NOSPLIT} },
603 { "js", {run_js, NOSPLIT} },
604 { "script", {run_external_js, 0} },
605 { "toggle_status", {toggle_status_cb, 0} },
606 { "spawn", {spawn, 0} },
607 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
608 { "sh", {spawn_sh, 0} },
609 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
610 { "exit", {close_uzbl, 0} },
611 { "search", {search_forward_text, NOSPLIT} },
612 { "search_reverse", {search_reverse_text, NOSPLIT} },
613 { "dehilight", {dehilight, 0} },
614 { "toggle_insert_mode", {toggle_insert_mode, 0} },
615 { "set", {set_var, NOSPLIT} },
616 { "get", {get_var, NOSPLIT} },
617 { "bind", {act_bind, NOSPLIT} },
618 { "dump_config", {act_dump_config, 0} },
619 { "keycmd", {keycmd, NOSPLIT} },
620 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
621 { "keycmd_bs", {keycmd_bs, 0} },
622 { "chain", {chain, 0} }
629 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
631 for (i = 0; i < LENGTH(cmdlist); i++)
632 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
635 /* -- CORE FUNCTIONS -- */
638 free_action(gpointer act) {
639 Action *action = (Action*)act;
640 g_free(action->name);
642 g_free(action->param);
647 new_action(const gchar *name, const gchar *param) {
648 Action *action = g_new(Action, 1);
650 action->name = g_strdup(name);
652 action->param = g_strdup(param);
654 action->param = NULL;
660 file_exists (const char * filename) {
661 return (access(filename, F_OK) == 0);
665 set_var(WebKitWebView *page, GArray *argv) {
667 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
668 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
669 set_var_value(g_strstrip(split[0]), value);
675 get_var(WebKitWebView *page, GArray *argv) {
677 get_var_value(argv_idx(argv, 0));
681 act_bind(WebKitWebView *page, GArray *argv) {
683 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
684 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
685 add_binding(g_strstrip(split[0]), value);
697 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
700 if (argv_idx(argv, 0)) {
701 if (strcmp (argv_idx(argv, 0), "0") == 0) {
702 uzbl.behave.insert_mode = FALSE;
704 uzbl.behave.insert_mode = TRUE;
707 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
714 load_uri (WebKitWebView *web_view, GArray *argv) {
715 if (argv_idx(argv, 0)) {
716 GString* newuri = g_string_new (argv_idx(argv, 0));
717 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
718 g_string_prepend (newuri, "http://");
719 /* if we do handle cookies, ask our handler for them */
720 webkit_web_view_load_uri (web_view, newuri->str);
721 g_string_free (newuri, TRUE);
726 run_js (WebKitWebView * web_view, GArray *argv) {
727 if (argv_idx(argv, 0))
728 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
732 run_external_js (WebKitWebView * web_view, GArray *argv) {
733 if (argv_idx(argv, 0)) {
734 GArray* lines = read_file_by_line (argv_idx (argv, 0));
739 while ((line = g_array_index(lines, gchar*, i))) {
741 js = g_strdup (line);
743 gchar* newjs = g_strconcat (js, line, NULL);
750 if (uzbl.state.verbose)
751 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
753 if (argv_idx (argv, 1)) {
754 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
758 webkit_web_view_execute_script (web_view, js);
760 g_array_free (lines, TRUE);
765 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
766 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
767 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
768 webkit_web_view_unmark_text_matches (page);
769 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
770 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
774 if (uzbl.state.searchtx) {
775 if (uzbl.state.verbose)
776 printf ("Searching: %s\n", uzbl.state.searchtx);
777 webkit_web_view_set_highlight_text_matches (page, TRUE);
778 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
783 search_forward_text (WebKitWebView *page, GArray *argv) {
784 search_text(page, argv, TRUE);
788 search_reverse_text (WebKitWebView *page, GArray *argv) {
789 search_text(page, argv, FALSE);
793 dehilight (WebKitWebView *page, GArray *argv) {
795 webkit_web_view_set_highlight_text_matches (page, FALSE);
800 new_window_load_uri (const gchar * uri) {
801 GString* to_execute = g_string_new ("");
802 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
804 for (i = 0; entries[i].long_name != NULL; i++) {
805 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
806 gchar** str = (gchar**)entries[i].arg_data;
808 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
812 if (uzbl.state.verbose)
813 printf("\n%s\n", to_execute->str);
814 g_spawn_command_line_async (to_execute->str, NULL);
815 g_string_free (to_execute, TRUE);
819 chain (WebKitWebView *page, GArray *argv) {
822 gchar **parts = NULL;
824 while ((a = argv_idx(argv, i++))) {
825 parts = g_strsplit (a, " ", 2);
826 parse_command(parts[0], parts[1]);
832 keycmd (WebKitWebView *page, GArray *argv) {
835 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
841 keycmd_nl (WebKitWebView *page, GArray *argv) {
844 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
850 keycmd_bs (WebKitWebView *page, GArray *argv) {
853 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
858 close_uzbl (WebKitWebView *page, GArray *argv) {
864 /* --Statusbar functions-- */
866 build_progressbar_ascii(int percent) {
867 int width=uzbl.gui.sbar.progress_w;
870 GString *bar = g_string_new("");
872 l = (double)percent*((double)width/100.);
873 l = (int)(l+.5)>=(int)l ? l+.5 : l;
875 for(i=0; i<(int)l; i++)
876 g_string_append(bar, uzbl.gui.sbar.progress_s);
879 g_string_append(bar, uzbl.gui.sbar.progress_u);
881 return g_string_free(bar, FALSE);
886 const GScannerConfig scan_config = {
889 ) /* cset_skip_characters */,
894 ) /* cset_identifier_first */,
901 ) /* cset_identifier_nth */,
902 ( "" ) /* cpair_comment_single */,
904 TRUE /* case_sensitive */,
906 FALSE /* skip_comment_multi */,
907 FALSE /* skip_comment_single */,
908 FALSE /* scan_comment_multi */,
909 TRUE /* scan_identifier */,
910 TRUE /* scan_identifier_1char */,
911 FALSE /* scan_identifier_NULL */,
912 TRUE /* scan_symbols */,
913 FALSE /* scan_binary */,
914 FALSE /* scan_octal */,
915 FALSE /* scan_float */,
916 FALSE /* scan_hex */,
917 FALSE /* scan_hex_dollar */,
918 FALSE /* scan_string_sq */,
919 FALSE /* scan_string_dq */,
920 TRUE /* numbers_2_int */,
921 FALSE /* int_2_float */,
922 FALSE /* identifier_2_string */,
923 FALSE /* char_2_token */,
924 FALSE /* symbol_2_token */,
925 TRUE /* scope_0_fallback */,
930 uzbl.scan = g_scanner_new(&scan_config);
931 while(symp->symbol_name) {
932 g_scanner_scope_add_symbol(uzbl.scan, 0,
934 GINT_TO_POINTER(symp->symbol_token));
940 expand_template(const char *template, gboolean escape_markup) {
941 if(!template) return NULL;
943 GTokenType token = G_TOKEN_NONE;
944 GString *ret = g_string_new("");
948 g_scanner_input_text(uzbl.scan, template, strlen(template));
949 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
950 token = g_scanner_get_next_token(uzbl.scan);
952 if(token == G_TOKEN_SYMBOL) {
953 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
957 buf = uzbl.state.uri?
958 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
959 g_string_append(ret, buf);
963 g_string_append(ret, uzbl.state.uri?
964 uzbl.state.uri:g_strdup(""));
967 buf = itos(uzbl.gui.sbar.load_progress);
968 g_string_append(ret, buf);
971 case SYM_LOADPRGSBAR:
972 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
973 g_string_append(ret, buf);
978 buf = uzbl.gui.main_title?
979 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
980 g_string_append(ret, buf);
984 g_string_append(ret, uzbl.gui.main_title?
985 uzbl.gui.main_title:g_strdup(""));
987 case SYM_SELECTED_URI:
989 buf = uzbl.state.selected_url?
990 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
991 g_string_append(ret, buf);
995 g_string_append(ret, uzbl.state.selected_url?
996 uzbl.state.selected_url:g_strdup(""));
999 buf = itos(uzbl.xwin);
1000 g_string_append(ret,
1001 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1006 buf = uzbl.state.keycmd->str?
1007 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1008 g_string_append(ret, buf);
1012 g_string_append(ret, uzbl.state.keycmd->str?
1013 uzbl.state.keycmd->str:g_strdup(""));
1016 g_string_append(ret,
1017 uzbl.behave.insert_mode?
1018 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1021 g_string_append(ret,
1022 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1024 /* useragent syms */
1026 buf = itos(WEBKIT_MAJOR_VERSION);
1027 g_string_append(ret, buf);
1031 buf = itos(WEBKIT_MINOR_VERSION);
1032 g_string_append(ret, buf);
1036 buf = itos(WEBKIT_MICRO_VERSION);
1037 g_string_append(ret, buf);
1041 g_string_append(ret, uzbl.state.unameinfo.sysname);
1044 g_string_append(ret, uzbl.state.unameinfo.nodename);
1047 g_string_append(ret, uzbl.state.unameinfo.release);
1050 g_string_append(ret, uzbl.state.unameinfo.version);
1053 g_string_append(ret, uzbl.state.unameinfo.machine);
1056 g_string_append(ret, ARCH);
1059 case SYM_DOMAINNAME:
1060 g_string_append(ret, uzbl.state.unameinfo.domainname);
1064 g_string_append(ret, COMMIT);
1070 else if(token == G_TOKEN_INT) {
1071 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1072 g_string_append(ret, buf);
1075 else if(token == G_TOKEN_IDENTIFIER) {
1076 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1078 else if(token == G_TOKEN_CHAR) {
1079 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1083 return g_string_free(ret, FALSE);
1085 /* --End Statusbar functions-- */
1088 sharg_append(GArray *a, const gchar *str) {
1089 const gchar *s = (str ? str : "");
1090 g_array_append_val(a, s);
1093 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1095 run_command (const gchar *command, const guint npre, const gchar **args,
1096 const gboolean sync, char **stdout) {
1097 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1100 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1101 gchar *pid = itos(getpid());
1102 gchar *xwin = itos(uzbl.xwin);
1104 sharg_append(a, command);
1105 for (i = 0; i < npre; i++) /* add n args before the default vars */
1106 sharg_append(a, args[i]);
1107 sharg_append(a, uzbl.state.config_file);
1108 sharg_append(a, pid);
1109 sharg_append(a, xwin);
1110 sharg_append(a, uzbl.comm.fifo_path);
1111 sharg_append(a, uzbl.comm.socket_path);
1112 sharg_append(a, uzbl.state.uri);
1113 sharg_append(a, uzbl.gui.main_title);
1115 for (i = npre; i < g_strv_length((gchar**)args); i++)
1116 sharg_append(a, args[i]);
1120 if (*stdout) *stdout = strfree(*stdout);
1122 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1123 NULL, NULL, stdout, NULL, NULL, &err);
1124 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1125 NULL, NULL, NULL, &err);
1127 if (uzbl.state.verbose) {
1128 GString *s = g_string_new("spawned:");
1129 for (i = 0; i < (a->len); i++) {
1130 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1131 g_string_append_printf(s, " %s", qarg);
1134 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1135 printf("%s\n", s->str);
1136 g_string_free(s, TRUE);
1138 printf("Stdout: %s\n", *stdout);
1142 g_printerr("error on run_command: %s\n", err->message);
1147 g_array_free (a, TRUE);
1152 split_quoted(const gchar* src, const gboolean unquote) {
1153 /* split on unquoted space, return array of strings;
1154 remove a layer of quotes and backslashes if unquote */
1155 if (!src) return NULL;
1157 gboolean dq = FALSE;
1158 gboolean sq = FALSE;
1159 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1160 GString *s = g_string_new ("");
1164 for (p = src; *p != '\0'; p++) {
1165 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1166 else if (*p == '\\') { g_string_append_c(s, *p++);
1167 g_string_append_c(s, *p); }
1168 else if ((*p == '"') && unquote && !sq) dq = !dq;
1169 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1171 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1172 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1174 else if ((*p == ' ') && !dq && !sq) {
1175 dup = g_strdup(s->str);
1176 g_array_append_val(a, dup);
1177 g_string_truncate(s, 0);
1178 } else g_string_append_c(s, *p);
1180 dup = g_strdup(s->str);
1181 g_array_append_val(a, dup);
1182 ret = (gchar**)a->data;
1183 g_array_free (a, FALSE);
1184 g_string_free (s, TRUE);
1189 spawn(WebKitWebView *web_view, GArray *argv) {
1191 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1192 if (argv_idx(argv, 0))
1193 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1197 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1200 if (argv_idx(argv, 0))
1201 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1202 TRUE, &uzbl.comm.sync_stdout);
1206 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1208 if (!uzbl.behave.shell_cmd) {
1209 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1214 gchar *spacer = g_strdup("");
1215 g_array_insert_val(argv, 1, spacer);
1216 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1218 for (i = 1; i < g_strv_length(cmd); i++)
1219 g_array_prepend_val(argv, cmd[i]);
1221 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1227 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1229 if (!uzbl.behave.shell_cmd) {
1230 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1235 gchar *spacer = g_strdup("");
1236 g_array_insert_val(argv, 1, spacer);
1237 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1239 for (i = 1; i < g_strv_length(cmd); i++)
1240 g_array_prepend_val(argv, cmd[i]);
1242 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1243 TRUE, &uzbl.comm.sync_stdout);
1249 parse_command(const char *cmd, const char *param) {
1252 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1255 gchar **par = split_quoted(param, TRUE);
1256 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1258 if (c[1] == NOSPLIT) { /* don't split */
1259 sharg_append(a, param);
1261 for (i = 0; i < g_strv_length(par); i++)
1262 sharg_append(a, par[i]);
1264 c[0](uzbl.gui.web_view, a);
1266 g_array_free (a, TRUE);
1269 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1273 get_var_value(const gchar *name) {
1276 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1277 if(c->type == TYPE_STR)
1278 printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr);
1279 else if(c->type == TYPE_INT)
1280 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1289 if(*uzbl.net.proxy_url == ' '
1290 || uzbl.net.proxy_url == NULL) {
1291 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1292 (GType) SOUP_SESSION_PROXY_URI);
1295 suri = soup_uri_new(uzbl.net.proxy_url);
1296 g_object_set(G_OBJECT(uzbl.net.soup_session),
1297 SOUP_SESSION_PROXY_URI,
1299 soup_uri_free(suri);
1306 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1307 g_array_append_val (a, uzbl.state.uri);
1308 load_uri(uzbl.gui.web_view, a);
1309 g_array_free (a, TRUE);
1313 cmd_always_insert_mode() {
1314 uzbl.behave.insert_mode =
1315 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1321 g_object_set(G_OBJECT(uzbl.net.soup_session),
1322 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1326 cmd_max_conns_host() {
1327 g_object_set(G_OBJECT(uzbl.net.soup_session),
1328 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1333 soup_session_remove_feature
1334 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1335 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1336 /*g_free(uzbl.net.soup_logger);*/
1338 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1339 soup_session_add_feature(uzbl.net.soup_session,
1340 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1343 static WebKitWebSettings*
1345 return webkit_web_view_get_settings(uzbl.gui.web_view);
1350 WebKitWebSettings *ws = view_settings();
1351 if (uzbl.behave.font_size > 0) {
1352 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1355 if (uzbl.behave.monospace_size > 0) {
1356 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1357 uzbl.behave.monospace_size, NULL);
1359 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1360 uzbl.behave.font_size, NULL);
1365 cmd_disable_plugins() {
1366 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1367 !uzbl.behave.disable_plugins, NULL);
1371 cmd_disable_scripts() {
1372 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1373 !uzbl.behave.disable_scripts, NULL);
1377 cmd_minimum_font_size() {
1378 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1379 uzbl.behave.minimum_font_size, NULL);
1382 cmd_autoload_img() {
1383 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1384 uzbl.behave.autoload_img, NULL);
1389 cmd_autoshrink_img() {
1390 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1391 uzbl.behave.autoshrink_img, NULL);
1396 cmd_enable_spellcheck() {
1397 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1398 uzbl.behave.enable_spellcheck, NULL);
1402 cmd_enable_private() {
1403 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1404 uzbl.behave.enable_private, NULL);
1409 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1410 uzbl.behave.print_bg, NULL);
1415 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1416 uzbl.behave.style_uri, NULL);
1420 cmd_resizable_txt() {
1421 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1422 uzbl.behave.resizable_txt, NULL);
1426 cmd_default_encoding() {
1427 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1428 uzbl.behave.default_encoding, NULL);
1432 cmd_enforce_96dpi() {
1433 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1434 uzbl.behave.enforce_96dpi, NULL);
1438 cmd_caret_browsing() {
1439 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1440 uzbl.behave.caret_browsing, NULL);
1444 cmd_cookie_handler() {
1445 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1446 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1447 if ((g_strcmp0(split[0], "sh") == 0) ||
1448 (g_strcmp0(split[0], "spawn") == 0)) {
1449 g_free (uzbl.behave.cookie_handler);
1450 uzbl.behave.cookie_handler =
1451 g_strdup_printf("sync_%s %s", split[0], split[1]);
1458 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1463 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1468 if(uzbl.behave.inject_html) {
1469 webkit_web_view_load_html_string (uzbl.gui.web_view,
1470 uzbl.behave.inject_html, NULL);
1479 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1480 uzbl.behave.modmask = 0;
1482 if(uzbl.behave.modkey)
1483 g_free(uzbl.behave.modkey);
1484 uzbl.behave.modkey = buf;
1486 for (i = 0; modkeys[i].key != NULL; i++) {
1487 if (g_strrstr(buf, modkeys[i].key))
1488 uzbl.behave.modmask |= modkeys[i].mask;
1494 if (*uzbl.net.useragent == ' ') {
1495 g_free (uzbl.net.useragent);
1496 uzbl.net.useragent = NULL;
1498 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1500 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1501 g_free(uzbl.net.useragent);
1502 uzbl.net.useragent = ua;
1508 gtk_widget_ref(uzbl.gui.scrolled_win);
1509 gtk_widget_ref(uzbl.gui.mainbar);
1510 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1511 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1513 if(uzbl.behave.status_top) {
1514 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1515 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1518 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1519 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1521 gtk_widget_unref(uzbl.gui.scrolled_win);
1522 gtk_widget_unref(uzbl.gui.mainbar);
1523 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1528 set_var_value(gchar *name, gchar *val) {
1529 uzbl_cmdprop *c = NULL;
1533 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1534 /* check for the variable type */
1535 if (c->type == TYPE_STR) {
1536 buf = expand_vars(val);
1539 } else if(c->type == TYPE_INT) {
1540 int *ip = (int *)c->ptr;
1541 buf = expand_vars(val);
1542 *ip = (int)strtoul(buf, &endp, 10);
1546 /* invoke a command specific function */
1547 if(c->func) c->func();
1554 Behaviour *b = &uzbl.behave;
1556 if(b->html_buffer->str) {
1557 webkit_web_view_load_html_string (uzbl.gui.web_view,
1558 b->html_buffer->str, b->base_url);
1559 g_string_free(b->html_buffer, TRUE);
1560 b->html_buffer = g_string_new("");
1564 enum {M_CMD, M_HTML};
1566 parse_cmd_line(const char *ctl_line) {
1567 Behaviour *b = &uzbl.behave;
1570 if(b->mode == M_HTML) {
1571 len = strlen(b->html_endmarker);
1572 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1573 if(len == strlen(ctl_line)-1 &&
1574 !strncmp(b->html_endmarker, ctl_line, len)) {
1576 set_var_value("mode", "0");
1581 set_timeout(b->html_timeout);
1582 g_string_append(b->html_buffer, ctl_line);
1585 else if((ctl_line[0] == '#') /* Comments */
1586 || (ctl_line[0] == ' ')
1587 || (ctl_line[0] == '\n'))
1588 ; /* ignore these lines */
1589 else { /* parse a command */
1591 gchar **tokens = NULL;
1593 if (ctl_line[strlen(ctl_line) - 1] == '\n') /* strip trailing newline */
1594 ctlstrip = g_strndup(ctl_line, strlen(ctl_line) - 1);
1595 else ctlstrip = g_strdup(ctl_line);
1597 tokens = g_strsplit(ctlstrip, " ", 2);
1598 parse_command(tokens[0], tokens[1]);
1605 build_stream_name(int type, const gchar* dir) {
1607 State *s = &uzbl.state;
1610 xwin_str = itos((int)uzbl.xwin);
1612 str = g_strdup_printf
1613 ("%s/uzbl_fifo_%s", dir,
1614 s->instance_name ? s->instance_name : xwin_str);
1615 } else if (type == SOCKET) {
1616 str = g_strdup_printf
1617 ("%s/uzbl_socket_%s", dir,
1618 s->instance_name ? s->instance_name : xwin_str );
1625 control_fifo(GIOChannel *gio, GIOCondition condition) {
1626 if (uzbl.state.verbose)
1627 printf("triggered\n");
1632 if (condition & G_IO_HUP)
1633 g_error ("Fifo: Read end of pipe died!\n");
1636 g_error ("Fifo: GIOChannel broke\n");
1638 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1639 if (ret == G_IO_STATUS_ERROR) {
1640 g_error ("Fifo: Error reading: %s\n", err->message);
1644 parse_cmd_line(ctl_line);
1651 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1652 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1653 if (unlink(uzbl.comm.fifo_path) == -1)
1654 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1655 g_free(uzbl.comm.fifo_path);
1656 uzbl.comm.fifo_path = NULL;
1659 if (*dir == ' ') { /* space unsets the variable */
1664 GIOChannel *chan = NULL;
1665 GError *error = NULL;
1666 gchar *path = build_stream_name(FIFO, dir);
1668 if (!file_exists(path)) {
1669 if (mkfifo (path, 0666) == 0) {
1670 // 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.
1671 chan = g_io_channel_new_file(path, "r+", &error);
1673 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1674 if (uzbl.state.verbose)
1675 printf ("init_fifo: created successfully as %s\n", path);
1676 uzbl.comm.fifo_path = path;
1678 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1679 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1680 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1681 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1683 /* if we got this far, there was an error; cleanup */
1684 if (error) g_error_free (error);
1691 control_stdin(GIOChannel *gio, GIOCondition condition) {
1693 gchar *ctl_line = NULL;
1696 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1697 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1700 parse_cmd_line(ctl_line);
1708 GIOChannel *chan = NULL;
1709 GError *error = NULL;
1711 chan = g_io_channel_unix_new(fileno(stdin));
1713 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1714 g_error ("Stdin: could not add watch\n");
1716 if (uzbl.state.verbose)
1717 printf ("Stdin: watch added successfully\n");
1720 g_error ("Stdin: Error while opening: %s\n", error->message);
1722 if (error) g_error_free (error);
1726 control_socket(GIOChannel *chan) {
1727 struct sockaddr_un remote;
1728 char buffer[512], *ctl_line;
1730 int sock, clientsock, n, done;
1733 sock = g_io_channel_unix_get_fd(chan);
1735 memset (buffer, 0, sizeof (buffer));
1737 t = sizeof (remote);
1738 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1742 memset (temp, 0, sizeof (temp));
1743 n = recv (clientsock, temp, 128, 0);
1745 buffer[strlen (buffer)] = '\0';
1749 strcat (buffer, temp);
1752 if (strcmp (buffer, "\n") < 0) {
1753 buffer[strlen (buffer) - 1] = '\0';
1755 buffer[strlen (buffer)] = '\0';
1758 ctl_line = g_strdup(buffer);
1759 parse_cmd_line (ctl_line);
1762 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1763 GError *error = NULL;
1766 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1767 if (ret == G_IO_STATUS_ERROR)
1768 g_error ("Error reading: %s\n", error->message);
1770 printf("Got line %s (%u bytes) \n",ctl_line, len);
1772 parse_line(ctl_line);
1780 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1781 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1782 if (unlink(uzbl.comm.socket_path) == -1)
1783 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1784 g_free(uzbl.comm.socket_path);
1785 uzbl.comm.socket_path = NULL;
1793 GIOChannel *chan = NULL;
1795 struct sockaddr_un local;
1796 gchar *path = build_stream_name(SOCKET, dir);
1798 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1800 local.sun_family = AF_UNIX;
1801 strcpy (local.sun_path, path);
1802 unlink (local.sun_path);
1804 len = strlen (local.sun_path) + sizeof (local.sun_family);
1805 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1806 if (uzbl.state.verbose)
1807 printf ("init_socket: opened in %s\n", path);
1810 if( (chan = g_io_channel_unix_new(sock)) ) {
1811 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1812 uzbl.comm.socket_path = path;
1815 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1817 /* if we got this far, there was an error; cleanup */
1824 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1825 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1827 // this function may be called very early when the templates are not set (yet), hence the checks
1829 update_title (void) {
1830 Behaviour *b = &uzbl.behave;
1833 if (b->show_status) {
1834 if (b->title_format_short) {
1835 parsed = expand_template(b->title_format_short, FALSE);
1836 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1839 if (b->status_format) {
1840 parsed = expand_template(b->status_format, TRUE);
1841 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1844 if (b->status_background) {
1846 gdk_color_parse (b->status_background, &color);
1847 //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)
1848 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1851 if (b->title_format_long) {
1852 parsed = expand_template(b->title_format_long, FALSE);
1853 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1860 key_press_cb (GtkWidget* window, GdkEventKey* event)
1862 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1866 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1867 || 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)
1870 /* turn off insert mode (if always_insert_mode is not used) */
1871 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1872 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1877 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1880 if (event->keyval == GDK_Escape) {
1881 g_string_truncate(uzbl.state.keycmd, 0);
1883 dehilight(uzbl.gui.web_view, NULL);
1887 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1888 if (event->keyval == GDK_Insert) {
1890 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1891 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1893 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1896 g_string_append (uzbl.state.keycmd, str);
1903 if (event->keyval == GDK_BackSpace)
1904 keycmd_bs(NULL, NULL);
1906 gboolean key_ret = FALSE;
1907 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1909 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1911 run_keycmd(key_ret);
1913 if (key_ret) return (!uzbl.behave.insert_mode);
1918 run_keycmd(const gboolean key_ret) {
1919 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1921 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1922 g_string_truncate(uzbl.state.keycmd, 0);
1923 parse_command(act->name, act->param);
1927 /* try if it's an incremental keycmd or one that takes args, and run it */
1928 GString* short_keys = g_string_new ("");
1929 GString* short_keys_inc = g_string_new ("");
1931 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1932 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1933 g_string_assign(short_keys_inc, short_keys->str);
1934 g_string_append_c(short_keys, '_');
1935 g_string_append_c(short_keys_inc, '*');
1937 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1938 /* run normal cmds only if return was pressed */
1939 exec_paramcmd(act, i);
1940 g_string_truncate(uzbl.state.keycmd, 0);
1942 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1943 if (key_ret) /* just quit the incremental command on return */
1944 g_string_truncate(uzbl.state.keycmd, 0);
1945 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1949 g_string_truncate(short_keys, short_keys->len - 1);
1951 g_string_free (short_keys, TRUE);
1952 g_string_free (short_keys_inc, TRUE);
1956 exec_paramcmd(const Action *act, const guint i) {
1957 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1958 GString *actionname = g_string_new ("");
1959 GString *actionparam = g_string_new ("");
1960 g_string_erase (parampart, 0, i+1);
1962 g_string_printf (actionname, act->name, parampart->str);
1964 g_string_printf (actionparam, act->param, parampart->str);
1965 parse_command(actionname->str, actionparam->str);
1966 g_string_free(actionname, TRUE);
1967 g_string_free(actionparam, TRUE);
1968 g_string_free(parampart, TRUE);
1976 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1977 //main_window_ref = g_object_ref(scrolled_window);
1978 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
1980 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1981 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1983 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1984 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1985 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1986 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1987 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1988 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1989 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1990 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1991 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1992 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1994 return scrolled_window;
2001 g->mainbar = gtk_hbox_new (FALSE, 0);
2003 /* keep a reference to the bar so we can re-pack it at runtime*/
2004 //sbar_ref = g_object_ref(g->mainbar);
2006 g->mainbar_label = gtk_label_new ("");
2007 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2008 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2009 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2010 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2011 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2016 GtkWidget* create_window () {
2017 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2018 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2019 gtk_widget_set_name (window, "Uzbl browser");
2020 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2021 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2027 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2029 If actname is one that calls an external command, this function will inject
2030 newargs in front of the user-provided args in that command line. They will
2031 come become after the body of the script (in sh) or after the name of
2032 the command to execute (in spawn).
2033 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2034 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2036 The return value consist of two strings: the action (sh, ...) and its args.
2038 If act is not one that calls an external command, then the given action merely
2041 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2042 gchar *actdup = g_strdup(actname);
2043 g_array_append_val(rets, actdup);
2045 if ((g_strcmp0(actname, "spawn") == 0) ||
2046 (g_strcmp0(actname, "sh") == 0) ||
2047 (g_strcmp0(actname, "sync_spawn") == 0) ||
2048 (g_strcmp0(actname, "sync_sh") == 0)) {
2050 GString *a = g_string_new("");
2051 gchar **spawnparts = split_quoted(origargs, FALSE);
2052 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2053 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2055 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2056 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2058 g_array_append_val(rets, a->str);
2059 g_string_free(a, FALSE);
2060 g_strfreev(spawnparts);
2062 gchar *origdup = g_strdup(origargs);
2063 g_array_append_val(rets, origdup);
2065 return (gchar**)g_array_free(rets, FALSE);
2069 run_handler (const gchar *act, const gchar *args) {
2070 /* Consider this code a temporary hack to make the handlers usable.
2071 In practice, all this splicing, injection, and reconstruction is
2072 inefficient, annoying and hard to manage. Potential pitfalls arise
2073 when the handler specific args 1) are not quoted (the handler
2074 callbacks should take care of this) 2) are quoted but interfere
2075 with the users' own quotation. A more ideal solution is
2076 to refactor parse_command so that it doesn't just take a string
2077 and execute it; rather than that, we should have a function which
2078 returns the argument vector parsed from the string. This vector
2079 could be modified (e.g. insert additional args into it) before
2080 passing it to the next function that actually executes it. Though
2081 it still isn't perfect for chain actions.. will reconsider & re-
2082 factor when I have the time. -duc */
2084 char **parts = g_strsplit(act, " ", 2);
2086 if (g_strcmp0(parts[0], "chain") == 0) {
2087 GString *newargs = g_string_new("");
2088 gchar **chainparts = split_quoted(parts[1], FALSE);
2090 /* for every argument in the chain, inject the handler args
2091 and make sure the new parts are wrapped in quotes */
2092 gchar **cp = chainparts;
2094 gchar *quotless = NULL;
2095 gchar **spliced_quotless = NULL; // sigh -_-;
2096 gchar **inpart = NULL;
2099 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2101 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2102 } else quotless = g_strdup(*cp);
2104 spliced_quotless = g_strsplit(quotless, " ", 2);
2105 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2106 g_strfreev(spliced_quotless);
2108 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2114 parse_command(parts[0], &(newargs->str[1]));
2115 g_string_free(newargs, TRUE);
2116 g_strfreev(chainparts);
2119 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2120 parse_command(inparts[0], inparts[1]);
2128 add_binding (const gchar *key, const gchar *act) {
2129 char **parts = g_strsplit(act, " ", 2);
2136 if (uzbl.state.verbose)
2137 printf ("Binding %-10s : %s\n", key, act);
2138 action = new_action(parts[0], parts[1]);
2140 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2145 get_xdg_var (XDG_Var xdg) {
2146 const gchar* actual_value = getenv (xdg.environmental);
2147 const gchar* home = getenv ("HOME");
2149 gchar* return_value = str_replace ("~", home, actual_value);
2151 if (! actual_value || strcmp (actual_value, "") == 0) {
2152 if (xdg.default_value) {
2153 return_value = str_replace ("~", home, xdg.default_value);
2155 return_value = NULL;
2158 return return_value;
2162 find_xdg_file (int xdg_type, char* filename) {
2163 /* xdg_type = 0 => config
2164 xdg_type = 1 => data
2165 xdg_type = 2 => cache*/
2167 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2168 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2171 gchar* temporary_string;
2175 if (! file_exists (temporary_file) && xdg_type != 2) {
2176 buf = get_xdg_var (XDG[3 + xdg_type]);
2177 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2180 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2181 g_free (temporary_file);
2182 temporary_file = g_strconcat (temporary_string, filename, NULL);
2186 //g_free (temporary_string); - segfaults.
2188 if (file_exists (temporary_file)) {
2189 return temporary_file;
2196 State *s = &uzbl.state;
2197 Network *n = &uzbl.net;
2199 for (i = 0; default_config[i].command != NULL; i++) {
2200 parse_cmd_line(default_config[i].command);
2203 if (!s->config_file) {
2204 s->config_file = find_xdg_file (0, "/uzbl/config");
2207 if (s->config_file) {
2208 GArray* lines = read_file_by_line (s->config_file);
2212 while ((line = g_array_index(lines, gchar*, i))) {
2213 parse_cmd_line (line);
2217 g_array_free (lines, TRUE);
2219 if (uzbl.state.verbose)
2220 printf ("No configuration file loaded.\n");
2223 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2226 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2229 if (!uzbl.behave.cookie_handler)
2232 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2233 GString *s = g_string_new ("");
2234 SoupURI * soup_uri = soup_message_get_uri(msg);
2235 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2236 run_handler(uzbl.behave.cookie_handler, s->str);
2238 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2239 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2240 if ( p != NULL ) *p = '\0';
2241 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2243 if (uzbl.comm.sync_stdout)
2244 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2246 g_string_free(s, TRUE);
2250 save_cookies (SoupMessage *msg, gpointer user_data){
2254 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2255 cookie = soup_cookie_to_set_cookie_header(ck->data);
2256 SoupURI * soup_uri = soup_message_get_uri(msg);
2257 GString *s = g_string_new ("");
2258 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2259 run_handler(uzbl.behave.cookie_handler, s->str);
2261 g_string_free(s, TRUE);
2266 /* --- WEBINSPECTOR --- */
2268 hide_window_cb(GtkWidget *widget, gpointer data) {
2271 gtk_widget_hide(widget);
2274 static WebKitWebView*
2275 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2278 (void) web_inspector;
2279 GtkWidget* scrolled_window;
2280 GtkWidget* new_web_view;
2283 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2284 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2285 G_CALLBACK(hide_window_cb), NULL);
2287 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2288 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2289 gtk_widget_show(g->inspector_window);
2291 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2292 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2293 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2294 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2295 gtk_widget_show(scrolled_window);
2297 new_web_view = webkit_web_view_new();
2298 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2300 return WEBKIT_WEB_VIEW(new_web_view);
2304 inspector_show_window_cb (WebKitWebInspector* inspector){
2306 gtk_widget_show(uzbl.gui.inspector_window);
2310 /* TODO: Add variables and code to make use of these functions */
2312 inspector_close_window_cb (WebKitWebInspector* inspector){
2318 inspector_attach_window_cb (WebKitWebInspector* inspector){
2324 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2330 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2336 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2342 set_up_inspector() {
2344 WebKitWebSettings *settings = view_settings();
2345 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2347 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2348 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2349 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2350 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2351 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2352 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2353 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2355 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2359 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2361 uzbl_cmdprop *c = v;
2366 if(c->type == TYPE_STR)
2367 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2368 else if(c->type == TYPE_INT)
2369 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2373 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2377 printf("bind %s = %s %s\n", (char *)k ,
2378 (char *)a->name, a->param?(char *)a->param:"");
2383 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2384 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2389 main (int argc, char* argv[]) {
2390 gtk_init (&argc, &argv);
2391 if (!g_thread_supported ())
2392 g_thread_init (NULL);
2393 uzbl.state.executable_path = g_strdup(argv[0]);
2394 uzbl.state.selected_url = NULL;
2395 uzbl.state.searchtx = NULL;
2397 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2398 g_option_context_add_main_entries (context, entries, NULL);
2399 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2400 g_option_context_parse (context, &argc, &argv, NULL);
2401 g_option_context_free(context);
2402 /* initialize hash table */
2403 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2405 uzbl.net.soup_session = webkit_get_default_session();
2406 uzbl.state.keycmd = g_string_new("");
2408 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2409 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2410 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2411 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2412 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2413 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2416 if(uname(&uzbl.state.unameinfo) == -1)
2417 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2419 uzbl.gui.sbar.progress_s = g_strdup("=");
2420 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2421 uzbl.gui.sbar.progress_w = 10;
2423 /* HTML mode defaults*/
2424 uzbl.behave.html_buffer = g_string_new("");
2425 uzbl.behave.html_endmarker = g_strdup(".");
2426 uzbl.behave.html_timeout = 60;
2427 uzbl.behave.base_url = g_strdup("http://invalid");
2429 /* default mode indicators */
2430 uzbl.behave.insert_indicator = g_strdup("I");
2431 uzbl.behave.cmd_indicator = g_strdup("C");
2435 make_var_to_name_hash();
2437 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2439 uzbl.gui.scrolled_win = create_browser();
2442 /* initial packing */
2443 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2444 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2446 uzbl.gui.main_window = create_window ();
2447 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2450 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2451 gtk_widget_show_all (uzbl.gui.main_window);
2452 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2454 if (uzbl.state.verbose) {
2455 printf("Uzbl start location: %s\n", argv[0]);
2456 printf("window_id %i\n",(int) uzbl.xwin);
2457 printf("pid %i\n", getpid ());
2458 printf("name: %s\n", uzbl.state.instance_name);
2461 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2462 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2463 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2464 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2465 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2469 if (!uzbl.behave.show_status)
2470 gtk_widget_hide(uzbl.gui.mainbar);
2479 if(uzbl.state.uri) {
2480 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2481 g_array_append_val(a, uzbl.state.uri);
2482 load_uri (uzbl.gui.web_view, a);
2483 g_array_free (a, TRUE);
2489 return EXIT_SUCCESS;
2492 /* vi: set et ts=4: */