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) {
193 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);
202 g_string_append_c(buf, *(s+1));
208 if( (vend = strchr(s, ' ')) ||
209 (vend = strchr(s, '\0')) ) {
210 strncpy(ret, s, vend-s);
212 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
213 if(c->type == TYPE_STR)
214 g_string_append(buf, (gchar *)*c->ptr);
215 else if(c->type == TYPE_INT) {
216 char *b = itos((int)*c->ptr);
217 g_string_append(buf, b);
224 /* every other char */
226 g_string_append_c(buf, *s);
230 return g_string_free(buf, FALSE);
237 snprintf(tmp, sizeof(tmp), "%i", val);
238 return g_strdup(tmp);
242 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
245 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
248 str_replace (const char* search, const char* replace, const char* string) {
252 buf = g_strsplit (string, search, -1);
253 ret = g_strjoinv (replace, buf);
254 g_strfreev(buf); // somebody said this segfaults
260 read_file_by_line (gchar *path) {
261 GIOChannel *chan = NULL;
262 gchar *readbuf = NULL;
264 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
267 chan = g_io_channel_new_file(path, "r", NULL);
270 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
271 const gchar* val = g_strdup (readbuf);
272 g_array_append_val (lines, val);
277 g_io_channel_unref (chan);
279 fprintf(stderr, "File '%s' not be read.\n", path);
286 gchar* parseenv (char* string) {
287 extern char** environ;
288 gchar* tmpstr = NULL;
292 while (environ[i] != NULL) {
293 gchar** env = g_strsplit (environ[i], "=", 2);
294 gchar* envname = g_strconcat ("$", env[0], NULL);
296 if (g_strrstr (string, envname) != NULL) {
297 tmpstr = g_strdup(string);
299 string = str_replace(envname, env[1], tmpstr);
304 g_strfreev (env); // somebody said this breaks uzbl
312 setup_signal(int signr, sigfunc *shandler) {
313 struct sigaction nh, oh;
315 nh.sa_handler = shandler;
316 sigemptyset(&nh.sa_mask);
319 if(sigaction(signr, &nh, &oh) < 0)
327 if (uzbl.behave.fifo_dir)
328 unlink (uzbl.comm.fifo_path);
329 if (uzbl.behave.socket_dir)
330 unlink (uzbl.comm.socket_path);
332 g_free(uzbl.state.executable_path);
333 g_string_free(uzbl.state.keycmd, TRUE);
334 g_hash_table_destroy(uzbl.bindings);
335 g_hash_table_destroy(uzbl.behave.commands);
338 /* used for html_mode_timeout
339 * be sure to extend this function to use
340 * more timers if needed in other places
343 set_timeout(int seconds) {
345 memset(&t, 0, sizeof t);
347 t.it_value.tv_sec = seconds;
348 t.it_value.tv_usec = 0;
349 setitimer(ITIMER_REAL, &t, NULL);
352 /* --- SIGNAL HANDLER --- */
355 catch_sigterm(int s) {
361 catch_sigint(int s) {
371 set_var_value("mode", "0");
376 /* --- CALLBACKS --- */
379 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
382 (void) navigation_action;
383 (void) policy_decision;
385 const gchar* uri = webkit_network_request_get_uri (request);
386 if (uzbl.state.verbose)
387 printf("New window requested -> %s \n", uri);
388 new_window_load_uri(uri);
393 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
397 if (uzbl.state.selected_url != NULL) {
398 if (uzbl.state.verbose)
399 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
400 new_window_load_uri(uzbl.state.selected_url);
402 if (uzbl.state.verbose)
403 printf("New web view -> %s\n","Nothing to open, exiting");
409 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
412 if (uzbl.behave.download_handler) {
413 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
414 if (uzbl.state.verbose)
415 printf("Download -> %s\n",uri);
416 /* if urls not escaped, we may have to escape and quote uri before this call */
417 run_handler(uzbl.behave.download_handler, uri);
422 /* scroll a bar in a given direction */
424 scroll (GtkAdjustment* bar, GArray *argv) {
428 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
429 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
430 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
434 scroll_begin(WebKitWebView* page, GArray *argv) {
435 (void) page; (void) argv;
436 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
440 scroll_end(WebKitWebView* page, GArray *argv) {
441 (void) page; (void) argv;
442 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
443 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
447 scroll_vert(WebKitWebView* page, GArray *argv) {
449 scroll(uzbl.gui.bar_v, argv);
453 scroll_horz(WebKitWebView* page, GArray *argv) {
455 scroll(uzbl.gui.bar_h, argv);
460 if (!uzbl.behave.show_status) {
461 gtk_widget_hide(uzbl.gui.mainbar);
463 gtk_widget_show(uzbl.gui.mainbar);
469 toggle_status_cb (WebKitWebView* page, GArray *argv) {
473 if (uzbl.behave.show_status) {
474 gtk_widget_hide(uzbl.gui.mainbar);
476 gtk_widget_show(uzbl.gui.mainbar);
478 uzbl.behave.show_status = !uzbl.behave.show_status;
483 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
487 //Set selected_url state variable
488 g_free(uzbl.state.selected_url);
489 uzbl.state.selected_url = NULL;
491 uzbl.state.selected_url = g_strdup(link);
497 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
501 if (uzbl.gui.main_title)
502 g_free (uzbl.gui.main_title);
503 uzbl.gui.main_title = g_strdup (title);
508 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
511 uzbl.gui.sbar.load_progress = progress;
516 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
520 if (uzbl.behave.load_finish_handler)
521 run_handler(uzbl.behave.load_finish_handler, "");
525 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
529 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
530 if (uzbl.behave.load_start_handler)
531 run_handler(uzbl.behave.load_start_handler, "");
535 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
538 g_free (uzbl.state.uri);
539 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
540 uzbl.state.uri = g_string_free (newuri, FALSE);
541 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
542 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
545 if (uzbl.behave.load_commit_handler)
546 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
550 destroy_cb (GtkWidget* widget, gpointer data) {
558 if (uzbl.behave.history_handler) {
560 struct tm * timeinfo;
563 timeinfo = localtime ( &rawtime );
564 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
565 run_handler(uzbl.behave.history_handler, date);
570 /* VIEW funcs (little webkit wrappers) */
571 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
573 VIEWFUNC(reload_bypass_cache)
574 VIEWFUNC(stop_loading)
581 /* -- command to callback/function map for things we cannot attach to any signals */
583 static struct {char *name; Command command[2];} cmdlist[] =
584 { /* key function no_split */
585 { "back", {view_go_back, 0} },
586 { "forward", {view_go_forward, 0} },
587 { "scroll_vert", {scroll_vert, 0} },
588 { "scroll_horz", {scroll_horz, 0} },
589 { "scroll_begin", {scroll_begin, 0} },
590 { "scroll_end", {scroll_end, 0} },
591 { "reload", {view_reload, 0}, },
592 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
593 { "stop", {view_stop_loading, 0}, },
594 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
595 { "zoom_out", {view_zoom_out, 0}, },
596 { "uri", {load_uri, NOSPLIT} },
597 { "js", {run_js, NOSPLIT} },
598 { "script", {run_external_js, 0} },
599 { "toggle_status", {toggle_status_cb, 0} },
600 { "spawn", {spawn, 0} },
601 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
602 { "sh", {spawn_sh, 0} },
603 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
604 { "exit", {close_uzbl, 0} },
605 { "search", {search_forward_text, NOSPLIT} },
606 { "search_reverse", {search_reverse_text, NOSPLIT} },
607 { "dehilight", {dehilight, 0} },
608 { "toggle_insert_mode", {toggle_insert_mode, 0} },
609 { "runcmd", {runcmd, NOSPLIT} },
610 { "set", {set_var, NOSPLIT} },
611 { "dump_config", {act_dump_config, 0} },
612 { "keycmd", {keycmd, NOSPLIT} },
613 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
614 { "keycmd_bs", {keycmd_bs, 0} },
615 { "chain", {chain, 0} }
622 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
624 for (i = 0; i < LENGTH(cmdlist); i++)
625 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
628 /* -- CORE FUNCTIONS -- */
631 free_action(gpointer act) {
632 Action *action = (Action*)act;
633 g_free(action->name);
635 g_free(action->param);
640 new_action(const gchar *name, const gchar *param) {
641 Action *action = g_new(Action, 1);
643 action->name = g_strdup(name);
645 action->param = g_strdup(param);
647 action->param = NULL;
653 file_exists (const char * filename) {
654 return (access(filename, F_OK) == 0);
658 set_var(WebKitWebView *page, GArray *argv) {
662 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
663 parse_cmd_line(ctl_line);
673 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
676 if (argv_idx(argv, 0)) {
677 if (strcmp (argv_idx(argv, 0), "0") == 0) {
678 uzbl.behave.insert_mode = FALSE;
680 uzbl.behave.insert_mode = TRUE;
683 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
690 load_uri (WebKitWebView *web_view, GArray *argv) {
691 if (argv_idx(argv, 0)) {
692 GString* newuri = g_string_new (argv_idx(argv, 0));
693 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
694 g_string_prepend (newuri, "http://");
695 /* if we do handle cookies, ask our handler for them */
696 webkit_web_view_load_uri (web_view, newuri->str);
697 g_string_free (newuri, TRUE);
702 run_js (WebKitWebView * web_view, GArray *argv) {
703 if (argv_idx(argv, 0))
704 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
708 run_external_js (WebKitWebView * web_view, GArray *argv) {
709 if (argv_idx(argv, 0)) {
710 GArray* lines = read_file_by_line (argv_idx (argv, 0));
715 while ((line = g_array_index(lines, gchar*, i))) {
717 js = g_strdup (line);
719 gchar* newjs = g_strconcat (js, line, NULL);
726 if (uzbl.state.verbose)
727 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
729 if (argv_idx (argv, 1)) {
730 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
734 webkit_web_view_execute_script (web_view, js);
736 g_array_free (lines, TRUE);
741 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
742 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
743 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
744 webkit_web_view_unmark_text_matches (page);
745 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
746 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
750 if (uzbl.state.searchtx) {
751 if (uzbl.state.verbose)
752 printf ("Searching: %s\n", uzbl.state.searchtx);
753 webkit_web_view_set_highlight_text_matches (page, TRUE);
754 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
759 search_forward_text (WebKitWebView *page, GArray *argv) {
760 search_text(page, argv, TRUE);
764 search_reverse_text (WebKitWebView *page, GArray *argv) {
765 search_text(page, argv, FALSE);
769 dehilight (WebKitWebView *page, GArray *argv) {
771 webkit_web_view_set_highlight_text_matches (page, FALSE);
776 new_window_load_uri (const gchar * uri) {
777 GString* to_execute = g_string_new ("");
778 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
780 for (i = 0; entries[i].long_name != NULL; i++) {
781 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
782 gchar** str = (gchar**)entries[i].arg_data;
784 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
788 if (uzbl.state.verbose)
789 printf("\n%s\n", to_execute->str);
790 g_spawn_command_line_async (to_execute->str, NULL);
791 g_string_free (to_execute, TRUE);
795 chain (WebKitWebView *page, GArray *argv) {
798 gchar **parts = NULL;
800 while ((a = argv_idx(argv, i++))) {
801 parts = g_strsplit (a, " ", 2);
802 parse_command(parts[0], parts[1]);
808 keycmd (WebKitWebView *page, GArray *argv) {
811 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
817 keycmd_nl (WebKitWebView *page, GArray *argv) {
820 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
826 keycmd_bs (WebKitWebView *page, GArray *argv) {
829 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
834 close_uzbl (WebKitWebView *page, GArray *argv) {
840 /* --Statusbar functions-- */
842 build_progressbar_ascii(int percent) {
843 int width=uzbl.gui.sbar.progress_w;
846 GString *bar = g_string_new("");
848 l = (double)percent*((double)width/100.);
849 l = (int)(l+.5)>=(int)l ? l+.5 : l;
851 for(i=0; i<(int)l; i++)
852 g_string_append(bar, uzbl.gui.sbar.progress_s);
855 g_string_append(bar, uzbl.gui.sbar.progress_u);
857 return g_string_free(bar, FALSE);
862 const GScannerConfig scan_config = {
865 ) /* cset_skip_characters */,
870 ) /* cset_identifier_first */,
877 ) /* cset_identifier_nth */,
878 ( "" ) /* cpair_comment_single */,
880 TRUE /* case_sensitive */,
882 FALSE /* skip_comment_multi */,
883 FALSE /* skip_comment_single */,
884 FALSE /* scan_comment_multi */,
885 TRUE /* scan_identifier */,
886 TRUE /* scan_identifier_1char */,
887 FALSE /* scan_identifier_NULL */,
888 TRUE /* scan_symbols */,
889 FALSE /* scan_binary */,
890 FALSE /* scan_octal */,
891 FALSE /* scan_float */,
892 FALSE /* scan_hex */,
893 FALSE /* scan_hex_dollar */,
894 FALSE /* scan_string_sq */,
895 FALSE /* scan_string_dq */,
896 TRUE /* numbers_2_int */,
897 FALSE /* int_2_float */,
898 FALSE /* identifier_2_string */,
899 FALSE /* char_2_token */,
900 FALSE /* symbol_2_token */,
901 TRUE /* scope_0_fallback */,
906 uzbl.scan = g_scanner_new(&scan_config);
907 while(symp->symbol_name) {
908 g_scanner_scope_add_symbol(uzbl.scan, 0,
910 GINT_TO_POINTER(symp->symbol_token));
916 expand_template(const char *template, gboolean escape_markup) {
917 if(!template) return NULL;
919 GTokenType token = G_TOKEN_NONE;
920 GString *ret = g_string_new("");
924 g_scanner_input_text(uzbl.scan, template, strlen(template));
925 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
926 token = g_scanner_get_next_token(uzbl.scan);
928 if(token == G_TOKEN_SYMBOL) {
929 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
933 buf = uzbl.state.uri?
934 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
935 g_string_append(ret, buf);
939 g_string_append(ret, uzbl.state.uri?
940 uzbl.state.uri:g_strdup(""));
943 buf = itos(uzbl.gui.sbar.load_progress);
944 g_string_append(ret, buf);
947 case SYM_LOADPRGSBAR:
948 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
949 g_string_append(ret, buf);
954 buf = uzbl.gui.main_title?
955 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
956 g_string_append(ret, buf);
960 g_string_append(ret, uzbl.gui.main_title?
961 uzbl.gui.main_title:g_strdup(""));
963 case SYM_SELECTED_URI:
965 buf = uzbl.state.selected_url?
966 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
967 g_string_append(ret, buf);
971 g_string_append(ret, uzbl.state.selected_url?
972 uzbl.state.selected_url:g_strdup(""));
975 buf = itos(uzbl.xwin);
977 uzbl.state.instance_name?uzbl.state.instance_name:buf);
982 buf = uzbl.state.keycmd->str?
983 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
984 g_string_append(ret, buf);
988 g_string_append(ret, uzbl.state.keycmd->str?
989 uzbl.state.keycmd->str:g_strdup(""));
993 uzbl.behave.insert_mode?
994 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
998 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1000 /* useragent syms */
1002 buf = itos(WEBKIT_MAJOR_VERSION);
1003 g_string_append(ret, buf);
1007 buf = itos(WEBKIT_MINOR_VERSION);
1008 g_string_append(ret, buf);
1012 buf = itos(WEBKIT_MICRO_VERSION);
1013 g_string_append(ret, buf);
1017 g_string_append(ret, uzbl.state.unameinfo.sysname);
1020 g_string_append(ret, uzbl.state.unameinfo.nodename);
1023 g_string_append(ret, uzbl.state.unameinfo.release);
1026 g_string_append(ret, uzbl.state.unameinfo.version);
1029 g_string_append(ret, uzbl.state.unameinfo.machine);
1032 g_string_append(ret, ARCH);
1035 case SYM_DOMAINNAME:
1036 g_string_append(ret, uzbl.state.unameinfo.domainname);
1040 g_string_append(ret, COMMIT);
1046 else if(token == G_TOKEN_INT) {
1047 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1048 g_string_append(ret, buf);
1051 else if(token == G_TOKEN_IDENTIFIER) {
1052 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1054 else if(token == G_TOKEN_CHAR) {
1055 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1059 return g_string_free(ret, FALSE);
1061 /* --End Statusbar functions-- */
1064 sharg_append(GArray *a, const gchar *str) {
1065 const gchar *s = (str ? str : "");
1066 g_array_append_val(a, s);
1069 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1071 run_command (const gchar *command, const guint npre, const gchar **args,
1072 const gboolean sync, char **stdout) {
1073 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1076 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1077 gchar *pid = itos(getpid());
1078 gchar *xwin = itos(uzbl.xwin);
1080 sharg_append(a, command);
1081 for (i = 0; i < npre; i++) /* add n args before the default vars */
1082 sharg_append(a, args[i]);
1083 sharg_append(a, uzbl.state.config_file);
1084 sharg_append(a, pid);
1085 sharg_append(a, xwin);
1086 sharg_append(a, uzbl.comm.fifo_path);
1087 sharg_append(a, uzbl.comm.socket_path);
1088 sharg_append(a, uzbl.state.uri);
1089 sharg_append(a, uzbl.gui.main_title);
1091 for (i = npre; i < g_strv_length((gchar**)args); i++)
1092 sharg_append(a, args[i]);
1096 if (*stdout) *stdout = strfree(*stdout);
1098 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1099 NULL, NULL, stdout, NULL, NULL, &err);
1100 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1101 NULL, NULL, NULL, &err);
1103 if (uzbl.state.verbose) {
1104 GString *s = g_string_new("spawned:");
1105 for (i = 0; i < (a->len); i++) {
1106 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1107 g_string_append_printf(s, " %s", qarg);
1110 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1111 printf("%s\n", s->str);
1112 g_string_free(s, TRUE);
1115 g_printerr("error on run_command: %s\n", err->message);
1120 g_array_free (a, TRUE);
1125 split_quoted(const gchar* src, const gboolean unquote) {
1126 /* split on unquoted space, return array of strings;
1127 remove a layer of quotes and backslashes if unquote */
1128 if (!src) return NULL;
1130 gboolean dq = FALSE;
1131 gboolean sq = FALSE;
1132 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1133 GString *s = g_string_new ("");
1137 for (p = src; *p != '\0'; p++) {
1138 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1139 else if (*p == '\\') { g_string_append_c(s, *p++);
1140 g_string_append_c(s, *p); }
1141 else if ((*p == '"') && unquote && !sq) dq = !dq;
1142 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1144 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1145 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1147 else if ((*p == ' ') && !dq && !sq) {
1148 dup = g_strdup(s->str);
1149 g_array_append_val(a, dup);
1150 g_string_truncate(s, 0);
1151 } else g_string_append_c(s, *p);
1153 dup = g_strdup(s->str);
1154 g_array_append_val(a, dup);
1155 ret = (gchar**)a->data;
1156 g_array_free (a, FALSE);
1157 g_string_free (s, TRUE);
1162 spawn(WebKitWebView *web_view, GArray *argv) {
1164 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1165 if (argv_idx(argv, 0))
1166 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1170 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1173 if (argv_idx(argv, 0))
1174 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1175 TRUE, &uzbl.comm.sync_stdout);
1179 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1181 if (!uzbl.behave.shell_cmd) {
1182 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1187 gchar *spacer = g_strdup("");
1188 g_array_insert_val(argv, 1, spacer);
1189 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1191 for (i = 1; i < g_strv_length(cmd); i++)
1192 g_array_prepend_val(argv, cmd[i]);
1194 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1200 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1202 if (!uzbl.behave.shell_cmd) {
1203 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1208 gchar *spacer = g_strdup("");
1209 g_array_insert_val(argv, 1, spacer);
1210 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1212 for (i = 1; i < g_strv_length(cmd); i++)
1213 g_array_prepend_val(argv, cmd[i]);
1215 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1216 TRUE, &uzbl.comm.sync_stdout);
1222 parse_command(const char *cmd, const char *param) {
1225 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1228 gchar **par = split_quoted(param, TRUE);
1229 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1231 if (c[1] == NOSPLIT) { /* don't split */
1232 sharg_append(a, param);
1234 for (i = 0; i < g_strv_length(par); i++)
1235 sharg_append(a, par[i]);
1237 c[0](uzbl.gui.web_view, a);
1239 g_array_free (a, TRUE);
1242 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1245 /* command parser */
1248 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1249 G_REGEX_OPTIMIZE, 0, NULL);
1250 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1251 G_REGEX_OPTIMIZE, 0, NULL);
1252 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1253 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1254 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1255 G_REGEX_OPTIMIZE, 0, NULL);
1259 get_var_value(gchar *name) {
1262 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1263 if(c->type == TYPE_STR)
1264 printf("VAR: %s VALUE: %s\n", name, (char *)*c->ptr);
1265 else if(c->type == TYPE_INT)
1266 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1275 if(*uzbl.net.proxy_url == ' '
1276 || uzbl.net.proxy_url == NULL) {
1277 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1278 (GType) SOUP_SESSION_PROXY_URI);
1281 suri = soup_uri_new(uzbl.net.proxy_url);
1282 g_object_set(G_OBJECT(uzbl.net.soup_session),
1283 SOUP_SESSION_PROXY_URI,
1285 soup_uri_free(suri);
1292 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1293 g_array_append_val (a, uzbl.state.uri);
1294 load_uri(uzbl.gui.web_view, a);
1295 g_array_free (a, TRUE);
1299 cmd_always_insert_mode() {
1300 uzbl.behave.insert_mode =
1301 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1307 g_object_set(G_OBJECT(uzbl.net.soup_session),
1308 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1312 cmd_max_conns_host() {
1313 g_object_set(G_OBJECT(uzbl.net.soup_session),
1314 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1319 soup_session_remove_feature
1320 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1321 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1322 /*g_free(uzbl.net.soup_logger);*/
1324 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1325 soup_session_add_feature(uzbl.net.soup_session,
1326 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1329 static WebKitWebSettings*
1331 return webkit_web_view_get_settings(uzbl.gui.web_view);
1336 WebKitWebSettings *ws = view_settings();
1337 if (uzbl.behave.font_size > 0) {
1338 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1341 if (uzbl.behave.monospace_size > 0) {
1342 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1343 uzbl.behave.monospace_size, NULL);
1345 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1346 uzbl.behave.font_size, NULL);
1351 cmd_disable_plugins() {
1352 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1353 !uzbl.behave.disable_plugins, NULL);
1357 cmd_disable_scripts() {
1358 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1359 !uzbl.behave.disable_scripts, NULL);
1363 cmd_minimum_font_size() {
1364 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1365 uzbl.behave.minimum_font_size, NULL);
1368 cmd_autoload_img() {
1369 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1370 uzbl.behave.autoload_img, NULL);
1375 cmd_autoshrink_img() {
1376 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1377 uzbl.behave.autoshrink_img, NULL);
1382 cmd_enable_spellcheck() {
1383 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1384 uzbl.behave.enable_spellcheck, NULL);
1388 cmd_enable_private() {
1389 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1390 uzbl.behave.enable_private, NULL);
1395 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1396 uzbl.behave.print_bg, NULL);
1401 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1402 uzbl.behave.style_uri, NULL);
1406 cmd_resizable_txt() {
1407 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1408 uzbl.behave.resizable_txt, NULL);
1412 cmd_default_encoding() {
1413 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1414 uzbl.behave.default_encoding, NULL);
1418 cmd_enforce_96dpi() {
1419 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1420 uzbl.behave.enforce_96dpi, NULL);
1424 cmd_caret_browsing() {
1425 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1426 uzbl.behave.caret_browsing, NULL);
1430 cmd_cookie_handler() {
1431 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1432 if ((g_strcmp0(split[0], "sh") == 0) ||
1433 (g_strcmp0(split[0], "spawn") == 0)) {
1434 g_free (uzbl.behave.cookie_handler);
1435 uzbl.behave.cookie_handler =
1436 g_strdup_printf("sync_%s %s", split[0], split[1]);
1443 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1448 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1453 if(uzbl.behave.inject_html) {
1454 webkit_web_view_load_html_string (uzbl.gui.web_view,
1455 uzbl.behave.inject_html, NULL);
1464 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1465 uzbl.behave.modmask = 0;
1467 if(uzbl.behave.modkey)
1468 g_free(uzbl.behave.modkey);
1469 uzbl.behave.modkey = buf;
1471 for (i = 0; modkeys[i].key != NULL; i++) {
1472 if (g_strrstr(buf, modkeys[i].key))
1473 uzbl.behave.modmask |= modkeys[i].mask;
1479 if (*uzbl.net.useragent == ' ') {
1480 g_free (uzbl.net.useragent);
1481 uzbl.net.useragent = NULL;
1483 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1485 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1486 g_free(uzbl.net.useragent);
1487 uzbl.net.useragent = ua;
1493 gtk_widget_ref(uzbl.gui.scrolled_win);
1494 gtk_widget_ref(uzbl.gui.mainbar);
1495 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1496 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1498 if(uzbl.behave.status_top) {
1499 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1500 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1503 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1504 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1506 gtk_widget_unref(uzbl.gui.scrolled_win);
1507 gtk_widget_unref(uzbl.gui.mainbar);
1508 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1513 set_var_value(gchar *name, gchar *val) {
1514 uzbl_cmdprop *c = NULL;
1518 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1519 /* check for the variable type */
1520 if (c->type == TYPE_STR) {
1521 buf = expand_vars(val);
1524 } else if(c->type == TYPE_INT) {
1525 int *ip = (int *)c->ptr;
1526 buf = expand_vars(val);
1527 *ip = (int)strtoul(buf, &endp, 10);
1531 /* invoke a command specific function */
1532 if(c->func) c->func();
1538 runcmd(WebKitWebView* page, GArray *argv) {
1540 parse_cmd_line(argv_idx(argv, 0));
1545 Behaviour *b = &uzbl.behave;
1547 if(b->html_buffer->str) {
1548 webkit_web_view_load_html_string (uzbl.gui.web_view,
1549 b->html_buffer->str, b->base_url);
1550 g_string_free(b->html_buffer, TRUE);
1551 b->html_buffer = g_string_new("");
1555 enum {M_CMD, M_HTML};
1557 parse_cmd_line(const char *ctl_line) {
1558 gchar **tokens = NULL;
1559 Behaviour *b = &uzbl.behave;
1562 if(b->mode == M_HTML) {
1563 len = strlen(b->html_endmarker);
1564 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1565 if(len == strlen(ctl_line)-1 &&
1566 !strncmp(b->html_endmarker, ctl_line, len)) {
1568 set_var_value("mode", "0");
1573 set_timeout(b->html_timeout);
1574 g_string_append(b->html_buffer, ctl_line);
1579 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1580 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1581 if(tokens[0][0] == 0) {
1582 gchar* value = parseenv(g_strdup(tokens[2]));
1583 set_var_value(tokens[1], value);
1587 printf("Error in command: %s\n", tokens[0]);
1590 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1591 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1592 if(tokens[0][0] == 0) {
1593 get_var_value(tokens[1]);
1596 printf("Error in command: %s\n", tokens[0]);
1599 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1600 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1601 if(tokens[0][0] == 0) {
1602 gchar* value = parseenv(g_strdup(tokens[2]));
1603 add_binding(tokens[1], value);
1607 printf("Error in command: %s\n", tokens[0]);
1610 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1611 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1612 if(tokens[0][0] == 0) {
1613 parse_command(tokens[1], tokens[2]);
1616 printf("Error in command: %s\n", tokens[0]);
1619 else if( (ctl_line[0] == '#')
1620 || (ctl_line[0] == ' ')
1621 || (ctl_line[0] == '\n'))
1622 ; /* ignore these lines */
1624 printf("Command not understood (%s)\n", ctl_line);
1634 build_stream_name(int type, const gchar* dir) {
1636 State *s = &uzbl.state;
1639 xwin_str = itos((int)uzbl.xwin);
1641 str = g_strdup_printf
1642 ("%s/uzbl_fifo_%s", dir,
1643 s->instance_name ? s->instance_name : xwin_str);
1644 } else if (type == SOCKET) {
1645 str = g_strdup_printf
1646 ("%s/uzbl_socket_%s", dir,
1647 s->instance_name ? s->instance_name : xwin_str );
1654 control_fifo(GIOChannel *gio, GIOCondition condition) {
1655 if (uzbl.state.verbose)
1656 printf("triggered\n");
1661 if (condition & G_IO_HUP)
1662 g_error ("Fifo: Read end of pipe died!\n");
1665 g_error ("Fifo: GIOChannel broke\n");
1667 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1668 if (ret == G_IO_STATUS_ERROR) {
1669 g_error ("Fifo: Error reading: %s\n", err->message);
1673 parse_cmd_line(ctl_line);
1680 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1681 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1682 if (unlink(uzbl.comm.fifo_path) == -1)
1683 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1684 g_free(uzbl.comm.fifo_path);
1685 uzbl.comm.fifo_path = NULL;
1688 if (*dir == ' ') { /* space unsets the variable */
1693 GIOChannel *chan = NULL;
1694 GError *error = NULL;
1695 gchar *path = build_stream_name(FIFO, dir);
1697 if (!file_exists(path)) {
1698 if (mkfifo (path, 0666) == 0) {
1699 // 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.
1700 chan = g_io_channel_new_file(path, "r+", &error);
1702 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1703 if (uzbl.state.verbose)
1704 printf ("init_fifo: created successfully as %s\n", path);
1705 uzbl.comm.fifo_path = path;
1707 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1708 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1709 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1710 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1712 /* if we got this far, there was an error; cleanup */
1713 if (error) g_error_free (error);
1720 control_stdin(GIOChannel *gio, GIOCondition condition) {
1722 gchar *ctl_line = NULL;
1725 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1726 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1729 parse_cmd_line(ctl_line);
1737 GIOChannel *chan = NULL;
1738 GError *error = NULL;
1740 chan = g_io_channel_unix_new(fileno(stdin));
1742 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1743 g_error ("Stdin: could not add watch\n");
1745 if (uzbl.state.verbose)
1746 printf ("Stdin: watch added successfully\n");
1749 g_error ("Stdin: Error while opening: %s\n", error->message);
1751 if (error) g_error_free (error);
1755 control_socket(GIOChannel *chan) {
1756 struct sockaddr_un remote;
1757 char buffer[512], *ctl_line;
1759 int sock, clientsock, n, done;
1762 sock = g_io_channel_unix_get_fd(chan);
1764 memset (buffer, 0, sizeof (buffer));
1766 t = sizeof (remote);
1767 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1771 memset (temp, 0, sizeof (temp));
1772 n = recv (clientsock, temp, 128, 0);
1774 buffer[strlen (buffer)] = '\0';
1778 strcat (buffer, temp);
1781 if (strcmp (buffer, "\n") < 0) {
1782 buffer[strlen (buffer) - 1] = '\0';
1784 buffer[strlen (buffer)] = '\0';
1787 ctl_line = g_strdup(buffer);
1788 parse_cmd_line (ctl_line);
1791 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1792 GError *error = NULL;
1795 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1796 if (ret == G_IO_STATUS_ERROR)
1797 g_error ("Error reading: %s\n", error->message);
1799 printf("Got line %s (%u bytes) \n",ctl_line, len);
1801 parse_line(ctl_line);
1809 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1810 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1811 if (unlink(uzbl.comm.socket_path) == -1)
1812 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1813 g_free(uzbl.comm.socket_path);
1814 uzbl.comm.socket_path = NULL;
1822 GIOChannel *chan = NULL;
1824 struct sockaddr_un local;
1825 gchar *path = build_stream_name(SOCKET, dir);
1827 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1829 local.sun_family = AF_UNIX;
1830 strcpy (local.sun_path, path);
1831 unlink (local.sun_path);
1833 len = strlen (local.sun_path) + sizeof (local.sun_family);
1834 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1835 if (uzbl.state.verbose)
1836 printf ("init_socket: opened in %s\n", path);
1839 if( (chan = g_io_channel_unix_new(sock)) ) {
1840 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1841 uzbl.comm.socket_path = path;
1844 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1846 /* if we got this far, there was an error; cleanup */
1853 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1854 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1856 // this function may be called very early when the templates are not set (yet), hence the checks
1858 update_title (void) {
1859 Behaviour *b = &uzbl.behave;
1862 if (b->show_status) {
1863 if (b->title_format_short) {
1864 parsed = expand_template(b->title_format_short, FALSE);
1865 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1868 if (b->status_format) {
1869 parsed = expand_template(b->status_format, TRUE);
1870 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1873 if (b->status_background) {
1875 gdk_color_parse (b->status_background, &color);
1876 //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)
1877 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1880 if (b->title_format_long) {
1881 parsed = expand_template(b->title_format_long, FALSE);
1882 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1889 key_press_cb (GtkWidget* window, GdkEventKey* event)
1891 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1895 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1896 || 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)
1899 /* turn off insert mode (if always_insert_mode is not used) */
1900 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1901 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1906 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1909 if (event->keyval == GDK_Escape) {
1910 g_string_truncate(uzbl.state.keycmd, 0);
1912 dehilight(uzbl.gui.web_view, NULL);
1916 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1917 if (event->keyval == GDK_Insert) {
1919 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1920 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1922 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1925 g_string_append (uzbl.state.keycmd, str);
1932 if (event->keyval == GDK_BackSpace)
1933 keycmd_bs(NULL, NULL);
1935 gboolean key_ret = FALSE;
1936 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1938 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1940 run_keycmd(key_ret);
1942 if (key_ret) return (!uzbl.behave.insert_mode);
1947 run_keycmd(const gboolean key_ret) {
1948 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1950 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1951 g_string_truncate(uzbl.state.keycmd, 0);
1952 parse_command(act->name, act->param);
1956 /* try if it's an incremental keycmd or one that takes args, and run it */
1957 GString* short_keys = g_string_new ("");
1958 GString* short_keys_inc = g_string_new ("");
1960 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1961 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1962 g_string_assign(short_keys_inc, short_keys->str);
1963 g_string_append_c(short_keys, '_');
1964 g_string_append_c(short_keys_inc, '*');
1966 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1967 /* run normal cmds only if return was pressed */
1968 exec_paramcmd(act, i);
1969 g_string_truncate(uzbl.state.keycmd, 0);
1971 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1972 if (key_ret) /* just quit the incremental command on return */
1973 g_string_truncate(uzbl.state.keycmd, 0);
1974 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1978 g_string_truncate(short_keys, short_keys->len - 1);
1980 g_string_free (short_keys, TRUE);
1981 g_string_free (short_keys_inc, TRUE);
1985 exec_paramcmd(const Action *act, const guint i) {
1986 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1987 GString *actionname = g_string_new ("");
1988 GString *actionparam = g_string_new ("");
1989 g_string_erase (parampart, 0, i+1);
1991 g_string_printf (actionname, act->name, parampart->str);
1993 g_string_printf (actionparam, act->param, parampart->str);
1994 parse_command(actionname->str, actionparam->str);
1995 g_string_free(actionname, TRUE);
1996 g_string_free(actionparam, TRUE);
1997 g_string_free(parampart, TRUE);
2005 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2006 //main_window_ref = g_object_ref(scrolled_window);
2007 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
2009 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2010 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2012 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2013 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2014 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2015 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2016 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2017 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2018 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2020 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2021 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2023 return scrolled_window;
2030 g->mainbar = gtk_hbox_new (FALSE, 0);
2032 /* keep a reference to the bar so we can re-pack it at runtime*/
2033 //sbar_ref = g_object_ref(g->mainbar);
2035 g->mainbar_label = gtk_label_new ("");
2036 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2037 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2038 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2039 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2040 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2045 GtkWidget* create_window () {
2046 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2047 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2048 gtk_widget_set_name (window, "Uzbl browser");
2049 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2050 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2056 run_handler (const gchar *act, const gchar *args) {
2057 char **parts = g_strsplit(act, " ", 2);
2059 else if ((g_strcmp0(parts[0], "spawn") == 0)
2060 || (g_strcmp0(parts[0], "sh") == 0)
2061 || (g_strcmp0(parts[0], "sync_spawn") == 0)
2062 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
2064 GString *a = g_string_new ("");
2066 spawnparts = split_quoted(parts[1], FALSE);
2067 g_string_append_printf(a, "%s", spawnparts[0]);
2068 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
2070 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2071 g_string_append_printf(a, " %s", spawnparts[i]);
2072 parse_command(parts[0], a->str);
2073 g_string_free (a, TRUE);
2074 g_strfreev (spawnparts);
2076 parse_command(parts[0], parts[1]);
2081 add_binding (const gchar *key, const gchar *act) {
2082 char **parts = g_strsplit(act, " ", 2);
2089 if (uzbl.state.verbose)
2090 printf ("Binding %-10s : %s\n", key, act);
2091 action = new_action(parts[0], parts[1]);
2093 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2098 get_xdg_var (XDG_Var xdg) {
2099 const gchar* actual_value = getenv (xdg.environmental);
2100 const gchar* home = getenv ("HOME");
2102 gchar* return_value = str_replace ("~", home, actual_value);
2104 if (! actual_value || strcmp (actual_value, "") == 0) {
2105 if (xdg.default_value) {
2106 return_value = str_replace ("~", home, xdg.default_value);
2108 return_value = NULL;
2111 return return_value;
2115 find_xdg_file (int xdg_type, char* filename) {
2116 /* xdg_type = 0 => config
2117 xdg_type = 1 => data
2118 xdg_type = 2 => cache*/
2120 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2121 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2124 gchar* temporary_string;
2128 if (! file_exists (temporary_file) && xdg_type != 2) {
2129 buf = get_xdg_var (XDG[3 + xdg_type]);
2130 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2133 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2134 g_free (temporary_file);
2135 temporary_file = g_strconcat (temporary_string, filename, NULL);
2139 //g_free (temporary_string); - segfaults.
2141 if (file_exists (temporary_file)) {
2142 return temporary_file;
2149 State *s = &uzbl.state;
2150 Network *n = &uzbl.net;
2152 for (i = 0; default_config[i].command != NULL; i++) {
2153 parse_cmd_line(default_config[i].command);
2156 if (!s->config_file) {
2157 s->config_file = find_xdg_file (0, "/uzbl/config");
2160 if (s->config_file) {
2161 GArray* lines = read_file_by_line (s->config_file);
2165 while ((line = g_array_index(lines, gchar*, i))) {
2166 parse_cmd_line (line);
2170 g_array_free (lines, TRUE);
2172 if (uzbl.state.verbose)
2173 printf ("No configuration file loaded.\n");
2176 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2179 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2182 if (!uzbl.behave.cookie_handler) return;
2184 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2185 GString *s = g_string_new ("");
2186 SoupURI * soup_uri = soup_message_get_uri(msg);
2187 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2188 run_handler(uzbl.behave.cookie_handler, s->str);
2190 if(uzbl.comm.sync_stdout)
2191 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2192 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2193 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2195 g_string_free(s, TRUE);
2199 save_cookies (SoupMessage *msg, gpointer user_data){
2203 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2204 cookie = soup_cookie_to_set_cookie_header(ck->data);
2205 SoupURI * soup_uri = soup_message_get_uri(msg);
2206 GString *s = g_string_new ("");
2207 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2208 run_handler(uzbl.behave.cookie_handler, s->str);
2210 g_string_free(s, TRUE);
2215 /* --- WEBINSPECTOR --- */
2217 hide_window_cb(GtkWidget *widget, gpointer data) {
2220 gtk_widget_hide(widget);
2223 static WebKitWebView*
2224 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2227 (void) web_inspector;
2228 GtkWidget* scrolled_window;
2229 GtkWidget* new_web_view;
2232 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2233 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2234 G_CALLBACK(hide_window_cb), NULL);
2236 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2237 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2238 gtk_widget_show(g->inspector_window);
2240 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2241 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2242 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2243 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2244 gtk_widget_show(scrolled_window);
2246 new_web_view = webkit_web_view_new();
2247 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2249 return WEBKIT_WEB_VIEW(new_web_view);
2253 inspector_show_window_cb (WebKitWebInspector* inspector){
2255 gtk_widget_show(uzbl.gui.inspector_window);
2259 /* TODO: Add variables and code to make use of these functions */
2261 inspector_close_window_cb (WebKitWebInspector* inspector){
2267 inspector_attach_window_cb (WebKitWebInspector* inspector){
2273 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2279 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2285 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2291 set_up_inspector() {
2293 WebKitWebSettings *settings = view_settings();
2294 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2296 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2297 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2298 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2299 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2300 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2301 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2302 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2304 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2308 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2310 uzbl_cmdprop *c = v;
2315 if(c->type == TYPE_STR)
2316 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2317 else if(c->type == TYPE_INT)
2318 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2322 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2326 printf("bind %s = %s %s\n", (char *)k ,
2327 (char *)a->name, a->param?(char *)a->param:"");
2332 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2333 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2338 main (int argc, char* argv[]) {
2339 gtk_init (&argc, &argv);
2340 if (!g_thread_supported ())
2341 g_thread_init (NULL);
2342 uzbl.state.executable_path = g_strdup(argv[0]);
2343 uzbl.state.selected_url = NULL;
2344 uzbl.state.searchtx = NULL;
2346 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2347 g_option_context_add_main_entries (context, entries, NULL);
2348 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2349 g_option_context_parse (context, &argc, &argv, NULL);
2350 g_option_context_free(context);
2351 /* initialize hash table */
2352 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2354 uzbl.net.soup_session = webkit_get_default_session();
2355 uzbl.state.keycmd = g_string_new("");
2357 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2358 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2359 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2360 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2361 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2362 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2365 if(uname(&uzbl.state.unameinfo) == -1)
2366 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2368 uzbl.gui.sbar.progress_s = g_strdup("=");
2369 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2370 uzbl.gui.sbar.progress_w = 10;
2372 /* HTML mode defaults*/
2373 uzbl.behave.html_buffer = g_string_new("");
2374 uzbl.behave.html_endmarker = g_strdup(".");
2375 uzbl.behave.html_timeout = 60;
2376 uzbl.behave.base_url = g_strdup("http://invalid");
2378 /* default mode indicators */
2379 uzbl.behave.insert_indicator = g_strdup("I");
2380 uzbl.behave.cmd_indicator = g_strdup("C");
2385 make_var_to_name_hash();
2387 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2389 uzbl.gui.scrolled_win = create_browser();
2392 /* initial packing */
2393 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2394 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2396 uzbl.gui.main_window = create_window ();
2397 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2400 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2401 gtk_widget_show_all (uzbl.gui.main_window);
2402 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2404 if (uzbl.state.verbose) {
2405 printf("Uzbl start location: %s\n", argv[0]);
2406 printf("window_id %i\n",(int) uzbl.xwin);
2407 printf("pid %i\n", getpid ());
2408 printf("name: %s\n", uzbl.state.instance_name);
2411 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2412 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2413 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2414 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2415 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2419 if (!uzbl.behave.show_status)
2420 gtk_widget_hide(uzbl.gui.mainbar);
2429 if(uzbl.state.uri) {
2430 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2431 g_array_append_val(a, uzbl.state.uri);
2432 load_uri (uzbl.gui.web_view, a);
2433 g_array_free (a, TRUE);
2436 //char *tstr = "Proxy is @proxy_url and now quoted \\@proxy_url status_top=@status_top \\\\\\";
2437 //expand_vars(tstr);
2441 return EXIT_SUCCESS;
2444 /* vi: set et ts=4: */