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 { "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 set_var_value(g_strstrip(split[0]), (g_strchug(split[1]) ? split[1] : " "));
673 get_var(WebKitWebView *page, GArray *argv) {
675 get_var_value(argv_idx(argv, 0));
684 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
687 if (argv_idx(argv, 0)) {
688 if (strcmp (argv_idx(argv, 0), "0") == 0) {
689 uzbl.behave.insert_mode = FALSE;
691 uzbl.behave.insert_mode = TRUE;
694 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
701 load_uri (WebKitWebView *web_view, GArray *argv) {
702 if (argv_idx(argv, 0)) {
703 GString* newuri = g_string_new (argv_idx(argv, 0));
704 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
705 g_string_prepend (newuri, "http://");
706 /* if we do handle cookies, ask our handler for them */
707 webkit_web_view_load_uri (web_view, newuri->str);
708 g_string_free (newuri, TRUE);
713 run_js (WebKitWebView * web_view, GArray *argv) {
714 if (argv_idx(argv, 0))
715 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
719 run_external_js (WebKitWebView * web_view, GArray *argv) {
720 if (argv_idx(argv, 0)) {
721 GArray* lines = read_file_by_line (argv_idx (argv, 0));
726 while ((line = g_array_index(lines, gchar*, i))) {
728 js = g_strdup (line);
730 gchar* newjs = g_strconcat (js, line, NULL);
737 if (uzbl.state.verbose)
738 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
740 if (argv_idx (argv, 1)) {
741 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
745 webkit_web_view_execute_script (web_view, js);
747 g_array_free (lines, TRUE);
752 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
753 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
754 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
755 webkit_web_view_unmark_text_matches (page);
756 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
757 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
761 if (uzbl.state.searchtx) {
762 if (uzbl.state.verbose)
763 printf ("Searching: %s\n", uzbl.state.searchtx);
764 webkit_web_view_set_highlight_text_matches (page, TRUE);
765 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
770 search_forward_text (WebKitWebView *page, GArray *argv) {
771 search_text(page, argv, TRUE);
775 search_reverse_text (WebKitWebView *page, GArray *argv) {
776 search_text(page, argv, FALSE);
780 dehilight (WebKitWebView *page, GArray *argv) {
782 webkit_web_view_set_highlight_text_matches (page, FALSE);
787 new_window_load_uri (const gchar * uri) {
788 GString* to_execute = g_string_new ("");
789 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
791 for (i = 0; entries[i].long_name != NULL; i++) {
792 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
793 gchar** str = (gchar**)entries[i].arg_data;
795 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
799 if (uzbl.state.verbose)
800 printf("\n%s\n", to_execute->str);
801 g_spawn_command_line_async (to_execute->str, NULL);
802 g_string_free (to_execute, TRUE);
806 chain (WebKitWebView *page, GArray *argv) {
809 gchar **parts = NULL;
811 while ((a = argv_idx(argv, i++))) {
812 parts = g_strsplit (a, " ", 2);
813 parse_command(parts[0], parts[1]);
819 keycmd (WebKitWebView *page, GArray *argv) {
822 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
828 keycmd_nl (WebKitWebView *page, GArray *argv) {
831 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
837 keycmd_bs (WebKitWebView *page, GArray *argv) {
840 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
845 close_uzbl (WebKitWebView *page, GArray *argv) {
851 /* --Statusbar functions-- */
853 build_progressbar_ascii(int percent) {
854 int width=uzbl.gui.sbar.progress_w;
857 GString *bar = g_string_new("");
859 l = (double)percent*((double)width/100.);
860 l = (int)(l+.5)>=(int)l ? l+.5 : l;
862 for(i=0; i<(int)l; i++)
863 g_string_append(bar, uzbl.gui.sbar.progress_s);
866 g_string_append(bar, uzbl.gui.sbar.progress_u);
868 return g_string_free(bar, FALSE);
873 const GScannerConfig scan_config = {
876 ) /* cset_skip_characters */,
881 ) /* cset_identifier_first */,
888 ) /* cset_identifier_nth */,
889 ( "" ) /* cpair_comment_single */,
891 TRUE /* case_sensitive */,
893 FALSE /* skip_comment_multi */,
894 FALSE /* skip_comment_single */,
895 FALSE /* scan_comment_multi */,
896 TRUE /* scan_identifier */,
897 TRUE /* scan_identifier_1char */,
898 FALSE /* scan_identifier_NULL */,
899 TRUE /* scan_symbols */,
900 FALSE /* scan_binary */,
901 FALSE /* scan_octal */,
902 FALSE /* scan_float */,
903 FALSE /* scan_hex */,
904 FALSE /* scan_hex_dollar */,
905 FALSE /* scan_string_sq */,
906 FALSE /* scan_string_dq */,
907 TRUE /* numbers_2_int */,
908 FALSE /* int_2_float */,
909 FALSE /* identifier_2_string */,
910 FALSE /* char_2_token */,
911 FALSE /* symbol_2_token */,
912 TRUE /* scope_0_fallback */,
917 uzbl.scan = g_scanner_new(&scan_config);
918 while(symp->symbol_name) {
919 g_scanner_scope_add_symbol(uzbl.scan, 0,
921 GINT_TO_POINTER(symp->symbol_token));
927 expand_template(const char *template, gboolean escape_markup) {
928 if(!template) return NULL;
930 GTokenType token = G_TOKEN_NONE;
931 GString *ret = g_string_new("");
935 g_scanner_input_text(uzbl.scan, template, strlen(template));
936 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
937 token = g_scanner_get_next_token(uzbl.scan);
939 if(token == G_TOKEN_SYMBOL) {
940 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
944 buf = uzbl.state.uri?
945 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
946 g_string_append(ret, buf);
950 g_string_append(ret, uzbl.state.uri?
951 uzbl.state.uri:g_strdup(""));
954 buf = itos(uzbl.gui.sbar.load_progress);
955 g_string_append(ret, buf);
958 case SYM_LOADPRGSBAR:
959 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
960 g_string_append(ret, buf);
965 buf = uzbl.gui.main_title?
966 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
967 g_string_append(ret, buf);
971 g_string_append(ret, uzbl.gui.main_title?
972 uzbl.gui.main_title:g_strdup(""));
974 case SYM_SELECTED_URI:
976 buf = uzbl.state.selected_url?
977 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
978 g_string_append(ret, buf);
982 g_string_append(ret, uzbl.state.selected_url?
983 uzbl.state.selected_url:g_strdup(""));
986 buf = itos(uzbl.xwin);
988 uzbl.state.instance_name?uzbl.state.instance_name:buf);
993 buf = uzbl.state.keycmd->str?
994 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
995 g_string_append(ret, buf);
999 g_string_append(ret, uzbl.state.keycmd->str?
1000 uzbl.state.keycmd->str:g_strdup(""));
1003 g_string_append(ret,
1004 uzbl.behave.insert_mode?
1005 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1008 g_string_append(ret,
1009 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1011 /* useragent syms */
1013 buf = itos(WEBKIT_MAJOR_VERSION);
1014 g_string_append(ret, buf);
1018 buf = itos(WEBKIT_MINOR_VERSION);
1019 g_string_append(ret, buf);
1023 buf = itos(WEBKIT_MICRO_VERSION);
1024 g_string_append(ret, buf);
1028 g_string_append(ret, uzbl.state.unameinfo.sysname);
1031 g_string_append(ret, uzbl.state.unameinfo.nodename);
1034 g_string_append(ret, uzbl.state.unameinfo.release);
1037 g_string_append(ret, uzbl.state.unameinfo.version);
1040 g_string_append(ret, uzbl.state.unameinfo.machine);
1043 g_string_append(ret, ARCH);
1046 case SYM_DOMAINNAME:
1047 g_string_append(ret, uzbl.state.unameinfo.domainname);
1051 g_string_append(ret, COMMIT);
1057 else if(token == G_TOKEN_INT) {
1058 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1059 g_string_append(ret, buf);
1062 else if(token == G_TOKEN_IDENTIFIER) {
1063 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1065 else if(token == G_TOKEN_CHAR) {
1066 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1070 return g_string_free(ret, FALSE);
1072 /* --End Statusbar functions-- */
1075 sharg_append(GArray *a, const gchar *str) {
1076 const gchar *s = (str ? str : "");
1077 g_array_append_val(a, s);
1080 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1082 run_command (const gchar *command, const guint npre, const gchar **args,
1083 const gboolean sync, char **stdout) {
1084 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1087 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1088 gchar *pid = itos(getpid());
1089 gchar *xwin = itos(uzbl.xwin);
1091 sharg_append(a, command);
1092 for (i = 0; i < npre; i++) /* add n args before the default vars */
1093 sharg_append(a, args[i]);
1094 sharg_append(a, uzbl.state.config_file);
1095 sharg_append(a, pid);
1096 sharg_append(a, xwin);
1097 sharg_append(a, uzbl.comm.fifo_path);
1098 sharg_append(a, uzbl.comm.socket_path);
1099 sharg_append(a, uzbl.state.uri);
1100 sharg_append(a, uzbl.gui.main_title);
1102 for (i = npre; i < g_strv_length((gchar**)args); i++)
1103 sharg_append(a, args[i]);
1107 if (*stdout) *stdout = strfree(*stdout);
1109 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1110 NULL, NULL, stdout, NULL, NULL, &err);
1111 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1112 NULL, NULL, NULL, &err);
1114 if (uzbl.state.verbose) {
1115 GString *s = g_string_new("spawned:");
1116 for (i = 0; i < (a->len); i++) {
1117 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1118 g_string_append_printf(s, " %s", qarg);
1121 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1122 printf("%s\n", s->str);
1123 g_string_free(s, TRUE);
1126 g_printerr("error on run_command: %s\n", err->message);
1131 g_array_free (a, TRUE);
1136 split_quoted(const gchar* src, const gboolean unquote) {
1137 /* split on unquoted space, return array of strings;
1138 remove a layer of quotes and backslashes if unquote */
1139 if (!src) return NULL;
1141 gboolean dq = FALSE;
1142 gboolean sq = FALSE;
1143 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1144 GString *s = g_string_new ("");
1148 for (p = src; *p != '\0'; p++) {
1149 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1150 else if (*p == '\\') { g_string_append_c(s, *p++);
1151 g_string_append_c(s, *p); }
1152 else if ((*p == '"') && unquote && !sq) dq = !dq;
1153 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1155 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1156 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1158 else if ((*p == ' ') && !dq && !sq) {
1159 dup = g_strdup(s->str);
1160 g_array_append_val(a, dup);
1161 g_string_truncate(s, 0);
1162 } else g_string_append_c(s, *p);
1164 dup = g_strdup(s->str);
1165 g_array_append_val(a, dup);
1166 ret = (gchar**)a->data;
1167 g_array_free (a, FALSE);
1168 g_string_free (s, TRUE);
1173 spawn(WebKitWebView *web_view, GArray *argv) {
1175 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1176 if (argv_idx(argv, 0))
1177 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1181 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1184 if (argv_idx(argv, 0))
1185 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1186 TRUE, &uzbl.comm.sync_stdout);
1190 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1192 if (!uzbl.behave.shell_cmd) {
1193 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1198 gchar *spacer = g_strdup("");
1199 g_array_insert_val(argv, 1, spacer);
1200 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1202 for (i = 1; i < g_strv_length(cmd); i++)
1203 g_array_prepend_val(argv, cmd[i]);
1205 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1211 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1213 if (!uzbl.behave.shell_cmd) {
1214 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1219 gchar *spacer = g_strdup("");
1220 g_array_insert_val(argv, 1, spacer);
1221 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1223 for (i = 1; i < g_strv_length(cmd); i++)
1224 g_array_prepend_val(argv, cmd[i]);
1226 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1227 TRUE, &uzbl.comm.sync_stdout);
1233 parse_command(const char *cmd, const char *param) {
1236 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1239 gchar **par = split_quoted(param, TRUE);
1240 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1242 if (c[1] == NOSPLIT) { /* don't split */
1243 sharg_append(a, param);
1245 for (i = 0; i < g_strv_length(par); i++)
1246 sharg_append(a, par[i]);
1248 c[0](uzbl.gui.web_view, a);
1250 g_array_free (a, TRUE);
1253 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1256 /* command parser */
1259 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1260 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1261 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1262 G_REGEX_OPTIMIZE, 0, NULL);
1266 get_var_value(const gchar *name) {
1269 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1270 if(c->type == TYPE_STR)
1271 printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr);
1272 else if(c->type == TYPE_INT)
1273 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1282 if(*uzbl.net.proxy_url == ' '
1283 || uzbl.net.proxy_url == NULL) {
1284 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1285 (GType) SOUP_SESSION_PROXY_URI);
1288 suri = soup_uri_new(uzbl.net.proxy_url);
1289 g_object_set(G_OBJECT(uzbl.net.soup_session),
1290 SOUP_SESSION_PROXY_URI,
1292 soup_uri_free(suri);
1299 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1300 g_array_append_val (a, uzbl.state.uri);
1301 load_uri(uzbl.gui.web_view, a);
1302 g_array_free (a, TRUE);
1306 cmd_always_insert_mode() {
1307 uzbl.behave.insert_mode =
1308 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1314 g_object_set(G_OBJECT(uzbl.net.soup_session),
1315 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1319 cmd_max_conns_host() {
1320 g_object_set(G_OBJECT(uzbl.net.soup_session),
1321 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1326 soup_session_remove_feature
1327 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1328 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1329 /*g_free(uzbl.net.soup_logger);*/
1331 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1332 soup_session_add_feature(uzbl.net.soup_session,
1333 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1336 static WebKitWebSettings*
1338 return webkit_web_view_get_settings(uzbl.gui.web_view);
1343 WebKitWebSettings *ws = view_settings();
1344 if (uzbl.behave.font_size > 0) {
1345 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1348 if (uzbl.behave.monospace_size > 0) {
1349 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1350 uzbl.behave.monospace_size, NULL);
1352 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1353 uzbl.behave.font_size, NULL);
1358 cmd_disable_plugins() {
1359 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1360 !uzbl.behave.disable_plugins, NULL);
1364 cmd_disable_scripts() {
1365 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1366 !uzbl.behave.disable_scripts, NULL);
1370 cmd_minimum_font_size() {
1371 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1372 uzbl.behave.minimum_font_size, NULL);
1375 cmd_autoload_img() {
1376 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1377 uzbl.behave.autoload_img, NULL);
1382 cmd_autoshrink_img() {
1383 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1384 uzbl.behave.autoshrink_img, NULL);
1389 cmd_enable_spellcheck() {
1390 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1391 uzbl.behave.enable_spellcheck, NULL);
1395 cmd_enable_private() {
1396 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1397 uzbl.behave.enable_private, NULL);
1402 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1403 uzbl.behave.print_bg, NULL);
1408 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1409 uzbl.behave.style_uri, NULL);
1413 cmd_resizable_txt() {
1414 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1415 uzbl.behave.resizable_txt, NULL);
1419 cmd_default_encoding() {
1420 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1421 uzbl.behave.default_encoding, NULL);
1425 cmd_enforce_96dpi() {
1426 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1427 uzbl.behave.enforce_96dpi, NULL);
1431 cmd_caret_browsing() {
1432 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1433 uzbl.behave.caret_browsing, NULL);
1437 cmd_cookie_handler() {
1438 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1439 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1440 if ((g_strcmp0(split[0], "sh") == 0) ||
1441 (g_strcmp0(split[0], "spawn") == 0)) {
1442 g_free (uzbl.behave.cookie_handler);
1443 uzbl.behave.cookie_handler =
1444 g_strdup_printf("sync_%s %s", split[0], split[1]);
1451 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1456 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1461 if(uzbl.behave.inject_html) {
1462 webkit_web_view_load_html_string (uzbl.gui.web_view,
1463 uzbl.behave.inject_html, NULL);
1472 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1473 uzbl.behave.modmask = 0;
1475 if(uzbl.behave.modkey)
1476 g_free(uzbl.behave.modkey);
1477 uzbl.behave.modkey = buf;
1479 for (i = 0; modkeys[i].key != NULL; i++) {
1480 if (g_strrstr(buf, modkeys[i].key))
1481 uzbl.behave.modmask |= modkeys[i].mask;
1487 if (*uzbl.net.useragent == ' ') {
1488 g_free (uzbl.net.useragent);
1489 uzbl.net.useragent = NULL;
1491 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1493 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1494 g_free(uzbl.net.useragent);
1495 uzbl.net.useragent = ua;
1501 gtk_widget_ref(uzbl.gui.scrolled_win);
1502 gtk_widget_ref(uzbl.gui.mainbar);
1503 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1504 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1506 if(uzbl.behave.status_top) {
1507 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1508 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1511 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1512 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1514 gtk_widget_unref(uzbl.gui.scrolled_win);
1515 gtk_widget_unref(uzbl.gui.mainbar);
1516 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1521 set_var_value(gchar *name, gchar *val) {
1522 uzbl_cmdprop *c = NULL;
1526 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1527 /* check for the variable type */
1528 if (c->type == TYPE_STR) {
1529 buf = expand_vars(val);
1532 } else if(c->type == TYPE_INT) {
1533 int *ip = (int *)c->ptr;
1534 buf = expand_vars(val);
1535 *ip = (int)strtoul(buf, &endp, 10);
1539 /* invoke a command specific function */
1540 if(c->func) c->func();
1546 runcmd(WebKitWebView* page, GArray *argv) {
1548 parse_cmd_line(argv_idx(argv, 0));
1553 Behaviour *b = &uzbl.behave;
1555 if(b->html_buffer->str) {
1556 webkit_web_view_load_html_string (uzbl.gui.web_view,
1557 b->html_buffer->str, b->base_url);
1558 g_string_free(b->html_buffer, TRUE);
1559 b->html_buffer = g_string_new("");
1563 enum {M_CMD, M_HTML};
1565 parse_cmd_line(const char *ctl_line) {
1566 gchar **tokens = NULL;
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);
1587 if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1588 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1589 if(tokens[0][0] == 0) {
1590 gchar* value = parseenv(g_strdup(tokens[2]));
1591 add_binding(tokens[1], value);
1595 printf("Error in command: %s\n", tokens[0]);
1598 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1599 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1600 if(tokens[0][0] == 0) {
1601 parse_command(tokens[1], tokens[2]);
1604 printf("Error in command: %s\n", tokens[0]);
1607 else if( (ctl_line[0] == '#')
1608 || (ctl_line[0] == ' ')
1609 || (ctl_line[0] == '\n'))
1610 ; /* ignore these lines */
1612 printf("Command not understood (%s)\n", ctl_line);
1622 build_stream_name(int type, const gchar* dir) {
1624 State *s = &uzbl.state;
1627 xwin_str = itos((int)uzbl.xwin);
1629 str = g_strdup_printf
1630 ("%s/uzbl_fifo_%s", dir,
1631 s->instance_name ? s->instance_name : xwin_str);
1632 } else if (type == SOCKET) {
1633 str = g_strdup_printf
1634 ("%s/uzbl_socket_%s", dir,
1635 s->instance_name ? s->instance_name : xwin_str );
1642 control_fifo(GIOChannel *gio, GIOCondition condition) {
1643 if (uzbl.state.verbose)
1644 printf("triggered\n");
1649 if (condition & G_IO_HUP)
1650 g_error ("Fifo: Read end of pipe died!\n");
1653 g_error ("Fifo: GIOChannel broke\n");
1655 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1656 if (ret == G_IO_STATUS_ERROR) {
1657 g_error ("Fifo: Error reading: %s\n", err->message);
1661 parse_cmd_line(ctl_line);
1668 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1669 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1670 if (unlink(uzbl.comm.fifo_path) == -1)
1671 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1672 g_free(uzbl.comm.fifo_path);
1673 uzbl.comm.fifo_path = NULL;
1676 if (*dir == ' ') { /* space unsets the variable */
1681 GIOChannel *chan = NULL;
1682 GError *error = NULL;
1683 gchar *path = build_stream_name(FIFO, dir);
1685 if (!file_exists(path)) {
1686 if (mkfifo (path, 0666) == 0) {
1687 // 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.
1688 chan = g_io_channel_new_file(path, "r+", &error);
1690 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1691 if (uzbl.state.verbose)
1692 printf ("init_fifo: created successfully as %s\n", path);
1693 uzbl.comm.fifo_path = path;
1695 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1696 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1697 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1698 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1700 /* if we got this far, there was an error; cleanup */
1701 if (error) g_error_free (error);
1708 control_stdin(GIOChannel *gio, GIOCondition condition) {
1710 gchar *ctl_line = NULL;
1713 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1714 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1717 parse_cmd_line(ctl_line);
1725 GIOChannel *chan = NULL;
1726 GError *error = NULL;
1728 chan = g_io_channel_unix_new(fileno(stdin));
1730 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1731 g_error ("Stdin: could not add watch\n");
1733 if (uzbl.state.verbose)
1734 printf ("Stdin: watch added successfully\n");
1737 g_error ("Stdin: Error while opening: %s\n", error->message);
1739 if (error) g_error_free (error);
1743 control_socket(GIOChannel *chan) {
1744 struct sockaddr_un remote;
1745 char buffer[512], *ctl_line;
1747 int sock, clientsock, n, done;
1750 sock = g_io_channel_unix_get_fd(chan);
1752 memset (buffer, 0, sizeof (buffer));
1754 t = sizeof (remote);
1755 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1759 memset (temp, 0, sizeof (temp));
1760 n = recv (clientsock, temp, 128, 0);
1762 buffer[strlen (buffer)] = '\0';
1766 strcat (buffer, temp);
1769 if (strcmp (buffer, "\n") < 0) {
1770 buffer[strlen (buffer) - 1] = '\0';
1772 buffer[strlen (buffer)] = '\0';
1775 ctl_line = g_strdup(buffer);
1776 parse_cmd_line (ctl_line);
1779 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1780 GError *error = NULL;
1783 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1784 if (ret == G_IO_STATUS_ERROR)
1785 g_error ("Error reading: %s\n", error->message);
1787 printf("Got line %s (%u bytes) \n",ctl_line, len);
1789 parse_line(ctl_line);
1797 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1798 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1799 if (unlink(uzbl.comm.socket_path) == -1)
1800 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1801 g_free(uzbl.comm.socket_path);
1802 uzbl.comm.socket_path = NULL;
1810 GIOChannel *chan = NULL;
1812 struct sockaddr_un local;
1813 gchar *path = build_stream_name(SOCKET, dir);
1815 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1817 local.sun_family = AF_UNIX;
1818 strcpy (local.sun_path, path);
1819 unlink (local.sun_path);
1821 len = strlen (local.sun_path) + sizeof (local.sun_family);
1822 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1823 if (uzbl.state.verbose)
1824 printf ("init_socket: opened in %s\n", path);
1827 if( (chan = g_io_channel_unix_new(sock)) ) {
1828 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1829 uzbl.comm.socket_path = path;
1832 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1834 /* if we got this far, there was an error; cleanup */
1841 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1842 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1844 // this function may be called very early when the templates are not set (yet), hence the checks
1846 update_title (void) {
1847 Behaviour *b = &uzbl.behave;
1850 if (b->show_status) {
1851 if (b->title_format_short) {
1852 parsed = expand_template(b->title_format_short, FALSE);
1853 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1856 if (b->status_format) {
1857 parsed = expand_template(b->status_format, TRUE);
1858 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1861 if (b->status_background) {
1863 gdk_color_parse (b->status_background, &color);
1864 //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)
1865 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1868 if (b->title_format_long) {
1869 parsed = expand_template(b->title_format_long, FALSE);
1870 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1877 key_press_cb (GtkWidget* window, GdkEventKey* event)
1879 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1883 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1884 || 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)
1887 /* turn off insert mode (if always_insert_mode is not used) */
1888 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1889 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1894 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1897 if (event->keyval == GDK_Escape) {
1898 g_string_truncate(uzbl.state.keycmd, 0);
1900 dehilight(uzbl.gui.web_view, NULL);
1904 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1905 if (event->keyval == GDK_Insert) {
1907 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1908 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1910 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1913 g_string_append (uzbl.state.keycmd, str);
1920 if (event->keyval == GDK_BackSpace)
1921 keycmd_bs(NULL, NULL);
1923 gboolean key_ret = FALSE;
1924 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1926 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1928 run_keycmd(key_ret);
1930 if (key_ret) return (!uzbl.behave.insert_mode);
1935 run_keycmd(const gboolean key_ret) {
1936 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1938 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1939 g_string_truncate(uzbl.state.keycmd, 0);
1940 parse_command(act->name, act->param);
1944 /* try if it's an incremental keycmd or one that takes args, and run it */
1945 GString* short_keys = g_string_new ("");
1946 GString* short_keys_inc = g_string_new ("");
1948 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1949 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1950 g_string_assign(short_keys_inc, short_keys->str);
1951 g_string_append_c(short_keys, '_');
1952 g_string_append_c(short_keys_inc, '*');
1954 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1955 /* run normal cmds only if return was pressed */
1956 exec_paramcmd(act, i);
1957 g_string_truncate(uzbl.state.keycmd, 0);
1959 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1960 if (key_ret) /* just quit the incremental command on return */
1961 g_string_truncate(uzbl.state.keycmd, 0);
1962 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1966 g_string_truncate(short_keys, short_keys->len - 1);
1968 g_string_free (short_keys, TRUE);
1969 g_string_free (short_keys_inc, TRUE);
1973 exec_paramcmd(const Action *act, const guint i) {
1974 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1975 GString *actionname = g_string_new ("");
1976 GString *actionparam = g_string_new ("");
1977 g_string_erase (parampart, 0, i+1);
1979 g_string_printf (actionname, act->name, parampart->str);
1981 g_string_printf (actionparam, act->param, parampart->str);
1982 parse_command(actionname->str, actionparam->str);
1983 g_string_free(actionname, TRUE);
1984 g_string_free(actionparam, TRUE);
1985 g_string_free(parampart, TRUE);
1993 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1994 //main_window_ref = g_object_ref(scrolled_window);
1995 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
1997 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1998 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2000 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2001 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2002 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2003 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2004 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2011 return scrolled_window;
2018 g->mainbar = gtk_hbox_new (FALSE, 0);
2020 /* keep a reference to the bar so we can re-pack it at runtime*/
2021 //sbar_ref = g_object_ref(g->mainbar);
2023 g->mainbar_label = gtk_label_new ("");
2024 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2025 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2026 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2027 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2028 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2033 GtkWidget* create_window () {
2034 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2035 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2036 gtk_widget_set_name (window, "Uzbl browser");
2037 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2038 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2044 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2046 If actname is one that calls an external command, this function will inject
2047 newargs in front of the user-provided args in that command line. They will
2048 come become after the body of the script (in sh) or after the name of
2049 the command to execute (in spawn).
2050 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2051 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2053 The return value consist of two strings: the action (sh, ...) and its args.
2055 If act is not one that calls an external command, then the given action merely
2058 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2059 gchar *actdup = g_strdup(actname);
2060 g_array_append_val(rets, actdup);
2062 if ((g_strcmp0(actname, "spawn") == 0) ||
2063 (g_strcmp0(actname, "sh") == 0) ||
2064 (g_strcmp0(actname, "sync_spawn") == 0) ||
2065 (g_strcmp0(actname, "sync_sh") == 0)) {
2067 GString *a = g_string_new("");
2068 gchar **spawnparts = split_quoted(origargs, FALSE);
2069 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2070 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2072 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2073 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2075 g_array_append_val(rets, a->str);
2076 g_string_free(a, FALSE);
2077 g_strfreev(spawnparts);
2079 gchar *origdup = g_strdup(origargs);
2080 g_array_append_val(rets, origdup);
2082 return (gchar**)g_array_free(rets, FALSE);
2086 run_handler (const gchar *act, const gchar *args) {
2087 /* Consider this code a temporary hack to make the handlers usable.
2088 In practice, all this splicing, injection, and reconstruction is
2089 inefficient, annoying and hard to manage. Potential pitfalls arise
2090 when the handler specific args 1) are not quoted (the handler
2091 callbacks should take care of this) 2) are quoted but interfere
2092 with the users' own quotation. A more ideal solution is
2093 to refactor parse_command so that it doesn't just take a string
2094 and execute it; rather than that, we should have a function which
2095 returns the argument vector parsed from the string. This vector
2096 could be modified (e.g. insert additional args into it) before
2097 passing it to the next function that actually executes it. Though
2098 it still isn't perfect for chain actions.. will reconsider & re-
2099 factor when I have the time. -duc */
2101 char **parts = g_strsplit(act, " ", 2);
2103 if (g_strcmp0(parts[0], "chain") == 0) {
2104 GString *newargs = g_string_new("");
2105 gchar **chainparts = split_quoted(parts[1], FALSE);
2107 /* for every argument in the chain, inject the handler args
2108 and make sure the new parts are wrapped in quotes */
2109 gchar **cp = chainparts;
2111 gchar *quotless = NULL;
2112 gchar **spliced_quotless = NULL; // sigh -_-;
2113 gchar **inpart = NULL;
2116 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2118 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2119 } else quotless = g_strdup(*cp);
2121 spliced_quotless = g_strsplit(quotless, " ", 2);
2122 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2123 g_strfreev(spliced_quotless);
2125 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2131 parse_command(parts[0], &(newargs->str[1]));
2132 g_string_free(newargs, TRUE);
2133 g_strfreev(chainparts);
2136 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2137 parse_command(inparts[0], inparts[1]);
2145 add_binding (const gchar *key, const gchar *act) {
2146 char **parts = g_strsplit(act, " ", 2);
2153 if (uzbl.state.verbose)
2154 printf ("Binding %-10s : %s\n", key, act);
2155 action = new_action(parts[0], parts[1]);
2157 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2162 get_xdg_var (XDG_Var xdg) {
2163 const gchar* actual_value = getenv (xdg.environmental);
2164 const gchar* home = getenv ("HOME");
2166 gchar* return_value = str_replace ("~", home, actual_value);
2168 if (! actual_value || strcmp (actual_value, "") == 0) {
2169 if (xdg.default_value) {
2170 return_value = str_replace ("~", home, xdg.default_value);
2172 return_value = NULL;
2175 return return_value;
2179 find_xdg_file (int xdg_type, char* filename) {
2180 /* xdg_type = 0 => config
2181 xdg_type = 1 => data
2182 xdg_type = 2 => cache*/
2184 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2185 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2188 gchar* temporary_string;
2192 if (! file_exists (temporary_file) && xdg_type != 2) {
2193 buf = get_xdg_var (XDG[3 + xdg_type]);
2194 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2197 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2198 g_free (temporary_file);
2199 temporary_file = g_strconcat (temporary_string, filename, NULL);
2203 //g_free (temporary_string); - segfaults.
2205 if (file_exists (temporary_file)) {
2206 return temporary_file;
2213 State *s = &uzbl.state;
2214 Network *n = &uzbl.net;
2216 for (i = 0; default_config[i].command != NULL; i++) {
2217 parse_cmd_line(default_config[i].command);
2220 if (!s->config_file) {
2221 s->config_file = find_xdg_file (0, "/uzbl/config");
2224 if (s->config_file) {
2225 GArray* lines = read_file_by_line (s->config_file);
2229 while ((line = g_array_index(lines, gchar*, i))) {
2230 parse_cmd_line (line);
2234 g_array_free (lines, TRUE);
2236 if (uzbl.state.verbose)
2237 printf ("No configuration file loaded.\n");
2240 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2243 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2246 if (!uzbl.behave.cookie_handler) return;
2248 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2249 GString *s = g_string_new ("");
2250 SoupURI * soup_uri = soup_message_get_uri(msg);
2251 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2252 run_handler(uzbl.behave.cookie_handler, s->str);
2254 if(uzbl.comm.sync_stdout)
2255 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2256 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2257 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2259 g_string_free(s, TRUE);
2263 save_cookies (SoupMessage *msg, gpointer user_data){
2267 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2268 cookie = soup_cookie_to_set_cookie_header(ck->data);
2269 SoupURI * soup_uri = soup_message_get_uri(msg);
2270 GString *s = g_string_new ("");
2271 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2272 run_handler(uzbl.behave.cookie_handler, s->str);
2274 g_string_free(s, TRUE);
2279 /* --- WEBINSPECTOR --- */
2281 hide_window_cb(GtkWidget *widget, gpointer data) {
2284 gtk_widget_hide(widget);
2287 static WebKitWebView*
2288 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2291 (void) web_inspector;
2292 GtkWidget* scrolled_window;
2293 GtkWidget* new_web_view;
2296 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2297 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2298 G_CALLBACK(hide_window_cb), NULL);
2300 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2301 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2302 gtk_widget_show(g->inspector_window);
2304 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2305 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2306 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2307 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2308 gtk_widget_show(scrolled_window);
2310 new_web_view = webkit_web_view_new();
2311 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2313 return WEBKIT_WEB_VIEW(new_web_view);
2317 inspector_show_window_cb (WebKitWebInspector* inspector){
2319 gtk_widget_show(uzbl.gui.inspector_window);
2323 /* TODO: Add variables and code to make use of these functions */
2325 inspector_close_window_cb (WebKitWebInspector* inspector){
2331 inspector_attach_window_cb (WebKitWebInspector* inspector){
2337 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2343 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2349 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2355 set_up_inspector() {
2357 WebKitWebSettings *settings = view_settings();
2358 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2360 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2361 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2362 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2363 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2364 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2365 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2366 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2368 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2372 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2374 uzbl_cmdprop *c = v;
2379 if(c->type == TYPE_STR)
2380 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2381 else if(c->type == TYPE_INT)
2382 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2386 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2390 printf("bind %s = %s %s\n", (char *)k ,
2391 (char *)a->name, a->param?(char *)a->param:"");
2396 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2397 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2402 main (int argc, char* argv[]) {
2403 gtk_init (&argc, &argv);
2404 if (!g_thread_supported ())
2405 g_thread_init (NULL);
2406 uzbl.state.executable_path = g_strdup(argv[0]);
2407 uzbl.state.selected_url = NULL;
2408 uzbl.state.searchtx = NULL;
2410 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2411 g_option_context_add_main_entries (context, entries, NULL);
2412 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2413 g_option_context_parse (context, &argc, &argv, NULL);
2414 g_option_context_free(context);
2415 /* initialize hash table */
2416 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2418 uzbl.net.soup_session = webkit_get_default_session();
2419 uzbl.state.keycmd = g_string_new("");
2421 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2422 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2423 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2424 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2425 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2426 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2429 if(uname(&uzbl.state.unameinfo) == -1)
2430 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2432 uzbl.gui.sbar.progress_s = g_strdup("=");
2433 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2434 uzbl.gui.sbar.progress_w = 10;
2436 /* HTML mode defaults*/
2437 uzbl.behave.html_buffer = g_string_new("");
2438 uzbl.behave.html_endmarker = g_strdup(".");
2439 uzbl.behave.html_timeout = 60;
2440 uzbl.behave.base_url = g_strdup("http://invalid");
2442 /* default mode indicators */
2443 uzbl.behave.insert_indicator = g_strdup("I");
2444 uzbl.behave.cmd_indicator = g_strdup("C");
2449 make_var_to_name_hash();
2451 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2453 uzbl.gui.scrolled_win = create_browser();
2456 /* initial packing */
2457 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2458 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2460 uzbl.gui.main_window = create_window ();
2461 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2464 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2465 gtk_widget_show_all (uzbl.gui.main_window);
2466 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2468 if (uzbl.state.verbose) {
2469 printf("Uzbl start location: %s\n", argv[0]);
2470 printf("window_id %i\n",(int) uzbl.xwin);
2471 printf("pid %i\n", getpid ());
2472 printf("name: %s\n", uzbl.state.instance_name);
2475 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2476 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2477 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2478 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2479 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2483 if (!uzbl.behave.show_status)
2484 gtk_widget_hide(uzbl.gui.mainbar);
2493 if(uzbl.state.uri) {
2494 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2495 g_array_append_val(a, uzbl.state.uri);
2496 load_uri (uzbl.gui.web_view, a);
2497 g_array_free (a, TRUE);
2503 return EXIT_SUCCESS;
2506 /* vi: set et ts=4: */