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) {
194 char ret[256], *vend;
195 GString *buf = g_string_new("");
200 g_string_append_c(buf, *++s);
208 if( (vend = strchr(s, upto)) ||
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);
221 if(upto == ' ') s = vend;
227 g_string_append_c(buf, *s);
232 return g_string_free(buf, FALSE);
239 snprintf(tmp, sizeof(tmp), "%i", val);
240 return g_strdup(tmp);
244 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
247 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
250 str_replace (const char* search, const char* replace, const char* string) {
254 buf = g_strsplit (string, search, -1);
255 ret = g_strjoinv (replace, buf);
256 g_strfreev(buf); // somebody said this segfaults
262 read_file_by_line (gchar *path) {
263 GIOChannel *chan = NULL;
264 gchar *readbuf = NULL;
266 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
269 chan = g_io_channel_new_file(path, "r", NULL);
272 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
273 const gchar* val = g_strdup (readbuf);
274 g_array_append_val (lines, val);
279 g_io_channel_unref (chan);
281 fprintf(stderr, "File '%s' not be read.\n", path);
288 gchar* parseenv (char* string) {
289 extern char** environ;
290 gchar* tmpstr = NULL;
294 while (environ[i] != NULL) {
295 gchar** env = g_strsplit (environ[i], "=", 2);
296 gchar* envname = g_strconcat ("$", env[0], NULL);
298 if (g_strrstr (string, envname) != NULL) {
299 tmpstr = g_strdup(string);
301 string = str_replace(envname, env[1], tmpstr);
306 g_strfreev (env); // somebody said this breaks uzbl
314 setup_signal(int signr, sigfunc *shandler) {
315 struct sigaction nh, oh;
317 nh.sa_handler = shandler;
318 sigemptyset(&nh.sa_mask);
321 if(sigaction(signr, &nh, &oh) < 0)
329 if (uzbl.behave.fifo_dir)
330 unlink (uzbl.comm.fifo_path);
331 if (uzbl.behave.socket_dir)
332 unlink (uzbl.comm.socket_path);
334 g_free(uzbl.state.executable_path);
335 g_string_free(uzbl.state.keycmd, TRUE);
336 g_hash_table_destroy(uzbl.bindings);
337 g_hash_table_destroy(uzbl.behave.commands);
340 /* used for html_mode_timeout
341 * be sure to extend this function to use
342 * more timers if needed in other places
345 set_timeout(int seconds) {
347 memset(&t, 0, sizeof t);
349 t.it_value.tv_sec = seconds;
350 t.it_value.tv_usec = 0;
351 setitimer(ITIMER_REAL, &t, NULL);
354 /* --- SIGNAL HANDLER --- */
357 catch_sigterm(int s) {
363 catch_sigint(int s) {
373 set_var_value("mode", "0");
378 /* --- CALLBACKS --- */
381 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
384 (void) navigation_action;
385 (void) policy_decision;
387 const gchar* uri = webkit_network_request_get_uri (request);
388 if (uzbl.state.verbose)
389 printf("New window requested -> %s \n", uri);
390 new_window_load_uri(uri);
395 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
399 if (uzbl.state.selected_url != NULL) {
400 if (uzbl.state.verbose)
401 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
402 new_window_load_uri(uzbl.state.selected_url);
404 if (uzbl.state.verbose)
405 printf("New web view -> %s\n","Nothing to open, exiting");
411 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
414 if (uzbl.behave.download_handler) {
415 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
416 if (uzbl.state.verbose)
417 printf("Download -> %s\n",uri);
418 /* if urls not escaped, we may have to escape and quote uri before this call */
419 run_handler(uzbl.behave.download_handler, uri);
424 /* scroll a bar in a given direction */
426 scroll (GtkAdjustment* bar, GArray *argv) {
430 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
431 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
432 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
436 scroll_begin(WebKitWebView* page, GArray *argv) {
437 (void) page; (void) argv;
438 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
442 scroll_end(WebKitWebView* page, GArray *argv) {
443 (void) page; (void) argv;
444 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
445 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
449 scroll_vert(WebKitWebView* page, GArray *argv) {
451 scroll(uzbl.gui.bar_v, argv);
455 scroll_horz(WebKitWebView* page, GArray *argv) {
457 scroll(uzbl.gui.bar_h, argv);
462 if (!uzbl.behave.show_status) {
463 gtk_widget_hide(uzbl.gui.mainbar);
465 gtk_widget_show(uzbl.gui.mainbar);
471 toggle_status_cb (WebKitWebView* page, GArray *argv) {
475 if (uzbl.behave.show_status) {
476 gtk_widget_hide(uzbl.gui.mainbar);
478 gtk_widget_show(uzbl.gui.mainbar);
480 uzbl.behave.show_status = !uzbl.behave.show_status;
485 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
489 //Set selected_url state variable
490 g_free(uzbl.state.selected_url);
491 uzbl.state.selected_url = NULL;
493 uzbl.state.selected_url = g_strdup(link);
499 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
503 if (uzbl.gui.main_title)
504 g_free (uzbl.gui.main_title);
505 uzbl.gui.main_title = g_strdup (title);
510 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
513 uzbl.gui.sbar.load_progress = progress;
518 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
522 if (uzbl.behave.load_finish_handler)
523 run_handler(uzbl.behave.load_finish_handler, "");
527 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
531 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
532 if (uzbl.behave.load_start_handler)
533 run_handler(uzbl.behave.load_start_handler, "");
537 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
540 g_free (uzbl.state.uri);
541 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
542 uzbl.state.uri = g_string_free (newuri, FALSE);
543 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
544 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
547 if (uzbl.behave.load_commit_handler)
548 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
552 destroy_cb (GtkWidget* widget, gpointer data) {
560 if (uzbl.behave.history_handler) {
562 struct tm * timeinfo;
565 timeinfo = localtime ( &rawtime );
566 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
567 run_handler(uzbl.behave.history_handler, date);
572 /* VIEW funcs (little webkit wrappers) */
573 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
575 VIEWFUNC(reload_bypass_cache)
576 VIEWFUNC(stop_loading)
583 /* -- command to callback/function map for things we cannot attach to any signals */
585 static struct {char *name; Command command[2];} cmdlist[] =
586 { /* key function no_split */
587 { "back", {view_go_back, 0} },
588 { "forward", {view_go_forward, 0} },
589 { "scroll_vert", {scroll_vert, 0} },
590 { "scroll_horz", {scroll_horz, 0} },
591 { "scroll_begin", {scroll_begin, 0} },
592 { "scroll_end", {scroll_end, 0} },
593 { "reload", {view_reload, 0}, },
594 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
595 { "stop", {view_stop_loading, 0}, },
596 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
597 { "zoom_out", {view_zoom_out, 0}, },
598 { "uri", {load_uri, NOSPLIT} },
599 { "js", {run_js, NOSPLIT} },
600 { "script", {run_external_js, 0} },
601 { "toggle_status", {toggle_status_cb, 0} },
602 { "spawn", {spawn, 0} },
603 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
604 { "sh", {spawn_sh, 0} },
605 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
606 { "exit", {close_uzbl, 0} },
607 { "search", {search_forward_text, NOSPLIT} },
608 { "search_reverse", {search_reverse_text, NOSPLIT} },
609 { "dehilight", {dehilight, 0} },
610 { "toggle_insert_mode", {toggle_insert_mode, 0} },
611 { "runcmd", {runcmd, NOSPLIT} },
612 { "set", {set_var, NOSPLIT} },
613 { "dump_config", {act_dump_config, 0} },
614 { "keycmd", {keycmd, NOSPLIT} },
615 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
616 { "keycmd_bs", {keycmd_bs, 0} },
617 { "chain", {chain, 0} }
624 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
626 for (i = 0; i < LENGTH(cmdlist); i++)
627 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
630 /* -- CORE FUNCTIONS -- */
633 free_action(gpointer act) {
634 Action *action = (Action*)act;
635 g_free(action->name);
637 g_free(action->param);
642 new_action(const gchar *name, const gchar *param) {
643 Action *action = g_new(Action, 1);
645 action->name = g_strdup(name);
647 action->param = g_strdup(param);
649 action->param = NULL;
655 file_exists (const char * filename) {
656 return (access(filename, F_OK) == 0);
660 set_var(WebKitWebView *page, GArray *argv) {
664 ctl_line = g_strdup_printf("%s %s", "set", argv_idx(argv, 0));
665 parse_cmd_line(ctl_line);
675 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
678 if (argv_idx(argv, 0)) {
679 if (strcmp (argv_idx(argv, 0), "0") == 0) {
680 uzbl.behave.insert_mode = FALSE;
682 uzbl.behave.insert_mode = TRUE;
685 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
692 load_uri (WebKitWebView *web_view, GArray *argv) {
693 if (argv_idx(argv, 0)) {
694 GString* newuri = g_string_new (argv_idx(argv, 0));
695 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
696 g_string_prepend (newuri, "http://");
697 /* if we do handle cookies, ask our handler for them */
698 webkit_web_view_load_uri (web_view, newuri->str);
699 g_string_free (newuri, TRUE);
704 run_js (WebKitWebView * web_view, GArray *argv) {
705 if (argv_idx(argv, 0))
706 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
710 run_external_js (WebKitWebView * web_view, GArray *argv) {
711 if (argv_idx(argv, 0)) {
712 GArray* lines = read_file_by_line (argv_idx (argv, 0));
717 while ((line = g_array_index(lines, gchar*, i))) {
719 js = g_strdup (line);
721 gchar* newjs = g_strconcat (js, line, NULL);
728 if (uzbl.state.verbose)
729 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
731 if (argv_idx (argv, 1)) {
732 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
736 webkit_web_view_execute_script (web_view, js);
738 g_array_free (lines, TRUE);
743 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
744 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
745 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
746 webkit_web_view_unmark_text_matches (page);
747 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
748 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
752 if (uzbl.state.searchtx) {
753 if (uzbl.state.verbose)
754 printf ("Searching: %s\n", uzbl.state.searchtx);
755 webkit_web_view_set_highlight_text_matches (page, TRUE);
756 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
761 search_forward_text (WebKitWebView *page, GArray *argv) {
762 search_text(page, argv, TRUE);
766 search_reverse_text (WebKitWebView *page, GArray *argv) {
767 search_text(page, argv, FALSE);
771 dehilight (WebKitWebView *page, GArray *argv) {
773 webkit_web_view_set_highlight_text_matches (page, FALSE);
778 new_window_load_uri (const gchar * uri) {
779 GString* to_execute = g_string_new ("");
780 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
782 for (i = 0; entries[i].long_name != NULL; i++) {
783 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
784 gchar** str = (gchar**)entries[i].arg_data;
786 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
790 if (uzbl.state.verbose)
791 printf("\n%s\n", to_execute->str);
792 g_spawn_command_line_async (to_execute->str, NULL);
793 g_string_free (to_execute, TRUE);
797 chain (WebKitWebView *page, GArray *argv) {
800 gchar **parts = NULL;
802 while ((a = argv_idx(argv, i++))) {
803 parts = g_strsplit (a, " ", 2);
804 parse_command(parts[0], parts[1]);
810 keycmd (WebKitWebView *page, GArray *argv) {
813 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
819 keycmd_nl (WebKitWebView *page, GArray *argv) {
822 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
828 keycmd_bs (WebKitWebView *page, GArray *argv) {
831 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
836 close_uzbl (WebKitWebView *page, GArray *argv) {
842 /* --Statusbar functions-- */
844 build_progressbar_ascii(int percent) {
845 int width=uzbl.gui.sbar.progress_w;
848 GString *bar = g_string_new("");
850 l = (double)percent*((double)width/100.);
851 l = (int)(l+.5)>=(int)l ? l+.5 : l;
853 for(i=0; i<(int)l; i++)
854 g_string_append(bar, uzbl.gui.sbar.progress_s);
857 g_string_append(bar, uzbl.gui.sbar.progress_u);
859 return g_string_free(bar, FALSE);
864 const GScannerConfig scan_config = {
867 ) /* cset_skip_characters */,
872 ) /* cset_identifier_first */,
879 ) /* cset_identifier_nth */,
880 ( "" ) /* cpair_comment_single */,
882 TRUE /* case_sensitive */,
884 FALSE /* skip_comment_multi */,
885 FALSE /* skip_comment_single */,
886 FALSE /* scan_comment_multi */,
887 TRUE /* scan_identifier */,
888 TRUE /* scan_identifier_1char */,
889 FALSE /* scan_identifier_NULL */,
890 TRUE /* scan_symbols */,
891 FALSE /* scan_binary */,
892 FALSE /* scan_octal */,
893 FALSE /* scan_float */,
894 FALSE /* scan_hex */,
895 FALSE /* scan_hex_dollar */,
896 FALSE /* scan_string_sq */,
897 FALSE /* scan_string_dq */,
898 TRUE /* numbers_2_int */,
899 FALSE /* int_2_float */,
900 FALSE /* identifier_2_string */,
901 FALSE /* char_2_token */,
902 FALSE /* symbol_2_token */,
903 TRUE /* scope_0_fallback */,
908 uzbl.scan = g_scanner_new(&scan_config);
909 while(symp->symbol_name) {
910 g_scanner_scope_add_symbol(uzbl.scan, 0,
912 GINT_TO_POINTER(symp->symbol_token));
918 expand_template(const char *template, gboolean escape_markup) {
919 if(!template) return NULL;
921 GTokenType token = G_TOKEN_NONE;
922 GString *ret = g_string_new("");
926 g_scanner_input_text(uzbl.scan, template, strlen(template));
927 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
928 token = g_scanner_get_next_token(uzbl.scan);
930 if(token == G_TOKEN_SYMBOL) {
931 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
935 buf = uzbl.state.uri?
936 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
937 g_string_append(ret, buf);
941 g_string_append(ret, uzbl.state.uri?
942 uzbl.state.uri:g_strdup(""));
945 buf = itos(uzbl.gui.sbar.load_progress);
946 g_string_append(ret, buf);
949 case SYM_LOADPRGSBAR:
950 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
951 g_string_append(ret, buf);
956 buf = uzbl.gui.main_title?
957 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
958 g_string_append(ret, buf);
962 g_string_append(ret, uzbl.gui.main_title?
963 uzbl.gui.main_title:g_strdup(""));
965 case SYM_SELECTED_URI:
967 buf = uzbl.state.selected_url?
968 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
969 g_string_append(ret, buf);
973 g_string_append(ret, uzbl.state.selected_url?
974 uzbl.state.selected_url:g_strdup(""));
977 buf = itos(uzbl.xwin);
979 uzbl.state.instance_name?uzbl.state.instance_name:buf);
984 buf = uzbl.state.keycmd->str?
985 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
986 g_string_append(ret, buf);
990 g_string_append(ret, uzbl.state.keycmd->str?
991 uzbl.state.keycmd->str:g_strdup(""));
995 uzbl.behave.insert_mode?
996 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1000 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1002 /* useragent syms */
1004 buf = itos(WEBKIT_MAJOR_VERSION);
1005 g_string_append(ret, buf);
1009 buf = itos(WEBKIT_MINOR_VERSION);
1010 g_string_append(ret, buf);
1014 buf = itos(WEBKIT_MICRO_VERSION);
1015 g_string_append(ret, buf);
1019 g_string_append(ret, uzbl.state.unameinfo.sysname);
1022 g_string_append(ret, uzbl.state.unameinfo.nodename);
1025 g_string_append(ret, uzbl.state.unameinfo.release);
1028 g_string_append(ret, uzbl.state.unameinfo.version);
1031 g_string_append(ret, uzbl.state.unameinfo.machine);
1034 g_string_append(ret, ARCH);
1037 case SYM_DOMAINNAME:
1038 g_string_append(ret, uzbl.state.unameinfo.domainname);
1042 g_string_append(ret, COMMIT);
1048 else if(token == G_TOKEN_INT) {
1049 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1050 g_string_append(ret, buf);
1053 else if(token == G_TOKEN_IDENTIFIER) {
1054 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1056 else if(token == G_TOKEN_CHAR) {
1057 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1061 return g_string_free(ret, FALSE);
1063 /* --End Statusbar functions-- */
1066 sharg_append(GArray *a, const gchar *str) {
1067 const gchar *s = (str ? str : "");
1068 g_array_append_val(a, s);
1071 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1073 run_command (const gchar *command, const guint npre, const gchar **args,
1074 const gboolean sync, char **stdout) {
1075 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1078 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1079 gchar *pid = itos(getpid());
1080 gchar *xwin = itos(uzbl.xwin);
1082 sharg_append(a, command);
1083 for (i = 0; i < npre; i++) /* add n args before the default vars */
1084 sharg_append(a, args[i]);
1085 sharg_append(a, uzbl.state.config_file);
1086 sharg_append(a, pid);
1087 sharg_append(a, xwin);
1088 sharg_append(a, uzbl.comm.fifo_path);
1089 sharg_append(a, uzbl.comm.socket_path);
1090 sharg_append(a, uzbl.state.uri);
1091 sharg_append(a, uzbl.gui.main_title);
1093 for (i = npre; i < g_strv_length((gchar**)args); i++)
1094 sharg_append(a, args[i]);
1098 if (*stdout) *stdout = strfree(*stdout);
1100 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1101 NULL, NULL, stdout, NULL, NULL, &err);
1102 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1103 NULL, NULL, NULL, &err);
1105 if (uzbl.state.verbose) {
1106 GString *s = g_string_new("spawned:");
1107 for (i = 0; i < (a->len); i++) {
1108 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1109 g_string_append_printf(s, " %s", qarg);
1112 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1113 printf("%s\n", s->str);
1114 g_string_free(s, TRUE);
1117 g_printerr("error on run_command: %s\n", err->message);
1122 g_array_free (a, TRUE);
1127 split_quoted(const gchar* src, const gboolean unquote) {
1128 /* split on unquoted space, return array of strings;
1129 remove a layer of quotes and backslashes if unquote */
1130 if (!src) return NULL;
1132 gboolean dq = FALSE;
1133 gboolean sq = FALSE;
1134 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1135 GString *s = g_string_new ("");
1139 for (p = src; *p != '\0'; p++) {
1140 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1141 else if (*p == '\\') { g_string_append_c(s, *p++);
1142 g_string_append_c(s, *p); }
1143 else if ((*p == '"') && unquote && !sq) dq = !dq;
1144 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1146 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1147 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1149 else if ((*p == ' ') && !dq && !sq) {
1150 dup = g_strdup(s->str);
1151 g_array_append_val(a, dup);
1152 g_string_truncate(s, 0);
1153 } else g_string_append_c(s, *p);
1155 dup = g_strdup(s->str);
1156 g_array_append_val(a, dup);
1157 ret = (gchar**)a->data;
1158 g_array_free (a, FALSE);
1159 g_string_free (s, TRUE);
1164 spawn(WebKitWebView *web_view, GArray *argv) {
1166 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1167 if (argv_idx(argv, 0))
1168 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1172 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1175 if (argv_idx(argv, 0))
1176 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1177 TRUE, &uzbl.comm.sync_stdout);
1181 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1183 if (!uzbl.behave.shell_cmd) {
1184 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1189 gchar *spacer = g_strdup("");
1190 g_array_insert_val(argv, 1, spacer);
1191 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1193 for (i = 1; i < g_strv_length(cmd); i++)
1194 g_array_prepend_val(argv, cmd[i]);
1196 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1202 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1204 if (!uzbl.behave.shell_cmd) {
1205 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1210 gchar *spacer = g_strdup("");
1211 g_array_insert_val(argv, 1, spacer);
1212 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1214 for (i = 1; i < g_strv_length(cmd); i++)
1215 g_array_prepend_val(argv, cmd[i]);
1217 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1218 TRUE, &uzbl.comm.sync_stdout);
1224 parse_command(const char *cmd, const char *param) {
1227 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1230 gchar **par = split_quoted(param, TRUE);
1231 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1233 if (c[1] == NOSPLIT) { /* don't split */
1234 sharg_append(a, param);
1236 for (i = 0; i < g_strv_length(par); i++)
1237 sharg_append(a, par[i]);
1239 c[0](uzbl.gui.web_view, a);
1241 g_array_free (a, TRUE);
1244 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1247 /* command parser */
1250 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
1251 G_REGEX_OPTIMIZE, 0, NULL);
1252 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
1253 G_REGEX_OPTIMIZE, 0, NULL);
1254 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
1255 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
1256 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
1257 G_REGEX_OPTIMIZE, 0, NULL);
1261 get_var_value(gchar *name) {
1264 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1265 if(c->type == TYPE_STR)
1266 printf("VAR: %s VALUE: (%s)\n", name, (char *)*c->ptr);
1267 else if(c->type == TYPE_INT)
1268 printf("VAR: %s VALUE: %d\n", name, (int)*c->ptr);
1277 if(*uzbl.net.proxy_url == ' '
1278 || uzbl.net.proxy_url == NULL) {
1279 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1280 (GType) SOUP_SESSION_PROXY_URI);
1283 suri = soup_uri_new(uzbl.net.proxy_url);
1284 g_object_set(G_OBJECT(uzbl.net.soup_session),
1285 SOUP_SESSION_PROXY_URI,
1287 soup_uri_free(suri);
1294 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1295 g_array_append_val (a, uzbl.state.uri);
1296 load_uri(uzbl.gui.web_view, a);
1297 g_array_free (a, TRUE);
1301 cmd_always_insert_mode() {
1302 uzbl.behave.insert_mode =
1303 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1309 g_object_set(G_OBJECT(uzbl.net.soup_session),
1310 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1314 cmd_max_conns_host() {
1315 g_object_set(G_OBJECT(uzbl.net.soup_session),
1316 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1321 soup_session_remove_feature
1322 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1323 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1324 /*g_free(uzbl.net.soup_logger);*/
1326 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1327 soup_session_add_feature(uzbl.net.soup_session,
1328 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1331 static WebKitWebSettings*
1333 return webkit_web_view_get_settings(uzbl.gui.web_view);
1338 WebKitWebSettings *ws = view_settings();
1339 if (uzbl.behave.font_size > 0) {
1340 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1343 if (uzbl.behave.monospace_size > 0) {
1344 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1345 uzbl.behave.monospace_size, NULL);
1347 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1348 uzbl.behave.font_size, NULL);
1353 cmd_disable_plugins() {
1354 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1355 !uzbl.behave.disable_plugins, NULL);
1359 cmd_disable_scripts() {
1360 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1361 !uzbl.behave.disable_scripts, NULL);
1365 cmd_minimum_font_size() {
1366 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1367 uzbl.behave.minimum_font_size, NULL);
1370 cmd_autoload_img() {
1371 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1372 uzbl.behave.autoload_img, NULL);
1377 cmd_autoshrink_img() {
1378 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1379 uzbl.behave.autoshrink_img, NULL);
1384 cmd_enable_spellcheck() {
1385 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1386 uzbl.behave.enable_spellcheck, NULL);
1390 cmd_enable_private() {
1391 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1392 uzbl.behave.enable_private, NULL);
1397 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1398 uzbl.behave.print_bg, NULL);
1403 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1404 uzbl.behave.style_uri, NULL);
1408 cmd_resizable_txt() {
1409 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1410 uzbl.behave.resizable_txt, NULL);
1414 cmd_default_encoding() {
1415 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1416 uzbl.behave.default_encoding, NULL);
1420 cmd_enforce_96dpi() {
1421 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1422 uzbl.behave.enforce_96dpi, NULL);
1426 cmd_caret_browsing() {
1427 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1428 uzbl.behave.caret_browsing, NULL);
1432 cmd_cookie_handler() {
1433 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1434 if ((g_strcmp0(split[0], "sh") == 0) ||
1435 (g_strcmp0(split[0], "spawn") == 0)) {
1436 g_free (uzbl.behave.cookie_handler);
1437 uzbl.behave.cookie_handler =
1438 g_strdup_printf("sync_%s %s", split[0], split[1]);
1445 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1450 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1455 if(uzbl.behave.inject_html) {
1456 webkit_web_view_load_html_string (uzbl.gui.web_view,
1457 uzbl.behave.inject_html, NULL);
1466 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1467 uzbl.behave.modmask = 0;
1469 if(uzbl.behave.modkey)
1470 g_free(uzbl.behave.modkey);
1471 uzbl.behave.modkey = buf;
1473 for (i = 0; modkeys[i].key != NULL; i++) {
1474 if (g_strrstr(buf, modkeys[i].key))
1475 uzbl.behave.modmask |= modkeys[i].mask;
1481 if (*uzbl.net.useragent == ' ') {
1482 g_free (uzbl.net.useragent);
1483 uzbl.net.useragent = NULL;
1485 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1487 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1488 g_free(uzbl.net.useragent);
1489 uzbl.net.useragent = ua;
1495 gtk_widget_ref(uzbl.gui.scrolled_win);
1496 gtk_widget_ref(uzbl.gui.mainbar);
1497 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1498 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1500 if(uzbl.behave.status_top) {
1501 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1502 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1505 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1506 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1508 gtk_widget_unref(uzbl.gui.scrolled_win);
1509 gtk_widget_unref(uzbl.gui.mainbar);
1510 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1515 set_var_value(gchar *name, gchar *val) {
1516 uzbl_cmdprop *c = NULL;
1520 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1521 /* check for the variable type */
1522 if (c->type == TYPE_STR) {
1523 buf = expand_vars(val);
1526 } else if(c->type == TYPE_INT) {
1527 int *ip = (int *)c->ptr;
1528 buf = expand_vars(val);
1529 *ip = (int)strtoul(buf, &endp, 10);
1533 /* invoke a command specific function */
1534 if(c->func) c->func();
1540 runcmd(WebKitWebView* page, GArray *argv) {
1542 parse_cmd_line(argv_idx(argv, 0));
1547 Behaviour *b = &uzbl.behave;
1549 if(b->html_buffer->str) {
1550 webkit_web_view_load_html_string (uzbl.gui.web_view,
1551 b->html_buffer->str, b->base_url);
1552 g_string_free(b->html_buffer, TRUE);
1553 b->html_buffer = g_string_new("");
1557 enum {M_CMD, M_HTML};
1559 parse_cmd_line(const char *ctl_line) {
1560 gchar **tokens = NULL;
1561 Behaviour *b = &uzbl.behave;
1564 if(b->mode == M_HTML) {
1565 len = strlen(b->html_endmarker);
1566 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1567 if(len == strlen(ctl_line)-1 &&
1568 !strncmp(b->html_endmarker, ctl_line, len)) {
1570 set_var_value("mode", "0");
1575 set_timeout(b->html_timeout);
1576 g_string_append(b->html_buffer, ctl_line);
1581 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
1582 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
1583 if(tokens[0][0] == 0) {
1584 gchar* value = parseenv(g_strdup(tokens[2]));
1585 set_var_value(tokens[1], value);
1589 printf("Error in command: %s\n", tokens[0]);
1592 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
1593 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
1594 if(tokens[0][0] == 0) {
1595 get_var_value(tokens[1]);
1598 printf("Error in command: %s\n", tokens[0]);
1601 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
1602 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
1603 if(tokens[0][0] == 0) {
1604 gchar* value = parseenv(g_strdup(tokens[2]));
1605 add_binding(tokens[1], value);
1609 printf("Error in command: %s\n", tokens[0]);
1612 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1613 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1614 if(tokens[0][0] == 0) {
1615 parse_command(tokens[1], tokens[2]);
1618 printf("Error in command: %s\n", tokens[0]);
1621 else if( (ctl_line[0] == '#')
1622 || (ctl_line[0] == ' ')
1623 || (ctl_line[0] == '\n'))
1624 ; /* ignore these lines */
1626 printf("Command not understood (%s)\n", ctl_line);
1636 build_stream_name(int type, const gchar* dir) {
1638 State *s = &uzbl.state;
1641 xwin_str = itos((int)uzbl.xwin);
1643 str = g_strdup_printf
1644 ("%s/uzbl_fifo_%s", dir,
1645 s->instance_name ? s->instance_name : xwin_str);
1646 } else if (type == SOCKET) {
1647 str = g_strdup_printf
1648 ("%s/uzbl_socket_%s", dir,
1649 s->instance_name ? s->instance_name : xwin_str );
1656 control_fifo(GIOChannel *gio, GIOCondition condition) {
1657 if (uzbl.state.verbose)
1658 printf("triggered\n");
1663 if (condition & G_IO_HUP)
1664 g_error ("Fifo: Read end of pipe died!\n");
1667 g_error ("Fifo: GIOChannel broke\n");
1669 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1670 if (ret == G_IO_STATUS_ERROR) {
1671 g_error ("Fifo: Error reading: %s\n", err->message);
1675 parse_cmd_line(ctl_line);
1682 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1683 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1684 if (unlink(uzbl.comm.fifo_path) == -1)
1685 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1686 g_free(uzbl.comm.fifo_path);
1687 uzbl.comm.fifo_path = NULL;
1690 if (*dir == ' ') { /* space unsets the variable */
1695 GIOChannel *chan = NULL;
1696 GError *error = NULL;
1697 gchar *path = build_stream_name(FIFO, dir);
1699 if (!file_exists(path)) {
1700 if (mkfifo (path, 0666) == 0) {
1701 // 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.
1702 chan = g_io_channel_new_file(path, "r+", &error);
1704 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1705 if (uzbl.state.verbose)
1706 printf ("init_fifo: created successfully as %s\n", path);
1707 uzbl.comm.fifo_path = path;
1709 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1710 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1711 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1712 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1714 /* if we got this far, there was an error; cleanup */
1715 if (error) g_error_free (error);
1722 control_stdin(GIOChannel *gio, GIOCondition condition) {
1724 gchar *ctl_line = NULL;
1727 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1728 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1731 parse_cmd_line(ctl_line);
1739 GIOChannel *chan = NULL;
1740 GError *error = NULL;
1742 chan = g_io_channel_unix_new(fileno(stdin));
1744 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1745 g_error ("Stdin: could not add watch\n");
1747 if (uzbl.state.verbose)
1748 printf ("Stdin: watch added successfully\n");
1751 g_error ("Stdin: Error while opening: %s\n", error->message);
1753 if (error) g_error_free (error);
1757 control_socket(GIOChannel *chan) {
1758 struct sockaddr_un remote;
1759 char buffer[512], *ctl_line;
1761 int sock, clientsock, n, done;
1764 sock = g_io_channel_unix_get_fd(chan);
1766 memset (buffer, 0, sizeof (buffer));
1768 t = sizeof (remote);
1769 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1773 memset (temp, 0, sizeof (temp));
1774 n = recv (clientsock, temp, 128, 0);
1776 buffer[strlen (buffer)] = '\0';
1780 strcat (buffer, temp);
1783 if (strcmp (buffer, "\n") < 0) {
1784 buffer[strlen (buffer) - 1] = '\0';
1786 buffer[strlen (buffer)] = '\0';
1789 ctl_line = g_strdup(buffer);
1790 parse_cmd_line (ctl_line);
1793 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1794 GError *error = NULL;
1797 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1798 if (ret == G_IO_STATUS_ERROR)
1799 g_error ("Error reading: %s\n", error->message);
1801 printf("Got line %s (%u bytes) \n",ctl_line, len);
1803 parse_line(ctl_line);
1811 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1812 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1813 if (unlink(uzbl.comm.socket_path) == -1)
1814 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1815 g_free(uzbl.comm.socket_path);
1816 uzbl.comm.socket_path = NULL;
1824 GIOChannel *chan = NULL;
1826 struct sockaddr_un local;
1827 gchar *path = build_stream_name(SOCKET, dir);
1829 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1831 local.sun_family = AF_UNIX;
1832 strcpy (local.sun_path, path);
1833 unlink (local.sun_path);
1835 len = strlen (local.sun_path) + sizeof (local.sun_family);
1836 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1837 if (uzbl.state.verbose)
1838 printf ("init_socket: opened in %s\n", path);
1841 if( (chan = g_io_channel_unix_new(sock)) ) {
1842 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1843 uzbl.comm.socket_path = path;
1846 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1848 /* if we got this far, there was an error; cleanup */
1855 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1856 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1858 // this function may be called very early when the templates are not set (yet), hence the checks
1860 update_title (void) {
1861 Behaviour *b = &uzbl.behave;
1864 if (b->show_status) {
1865 if (b->title_format_short) {
1866 parsed = expand_template(b->title_format_short, FALSE);
1867 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1870 if (b->status_format) {
1871 parsed = expand_template(b->status_format, TRUE);
1872 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1875 if (b->status_background) {
1877 gdk_color_parse (b->status_background, &color);
1878 //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)
1879 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1882 if (b->title_format_long) {
1883 parsed = expand_template(b->title_format_long, FALSE);
1884 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1891 key_press_cb (GtkWidget* window, GdkEventKey* event)
1893 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1897 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1898 || 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)
1901 /* turn off insert mode (if always_insert_mode is not used) */
1902 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1903 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1908 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1911 if (event->keyval == GDK_Escape) {
1912 g_string_truncate(uzbl.state.keycmd, 0);
1914 dehilight(uzbl.gui.web_view, NULL);
1918 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1919 if (event->keyval == GDK_Insert) {
1921 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1922 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1924 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1927 g_string_append (uzbl.state.keycmd, str);
1934 if (event->keyval == GDK_BackSpace)
1935 keycmd_bs(NULL, NULL);
1937 gboolean key_ret = FALSE;
1938 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1940 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1942 run_keycmd(key_ret);
1944 if (key_ret) return (!uzbl.behave.insert_mode);
1949 run_keycmd(const gboolean key_ret) {
1950 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1952 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1953 g_string_truncate(uzbl.state.keycmd, 0);
1954 parse_command(act->name, act->param);
1958 /* try if it's an incremental keycmd or one that takes args, and run it */
1959 GString* short_keys = g_string_new ("");
1960 GString* short_keys_inc = g_string_new ("");
1962 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1963 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1964 g_string_assign(short_keys_inc, short_keys->str);
1965 g_string_append_c(short_keys, '_');
1966 g_string_append_c(short_keys_inc, '*');
1968 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1969 /* run normal cmds only if return was pressed */
1970 exec_paramcmd(act, i);
1971 g_string_truncate(uzbl.state.keycmd, 0);
1973 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1974 if (key_ret) /* just quit the incremental command on return */
1975 g_string_truncate(uzbl.state.keycmd, 0);
1976 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1980 g_string_truncate(short_keys, short_keys->len - 1);
1982 g_string_free (short_keys, TRUE);
1983 g_string_free (short_keys_inc, TRUE);
1987 exec_paramcmd(const Action *act, const guint i) {
1988 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1989 GString *actionname = g_string_new ("");
1990 GString *actionparam = g_string_new ("");
1991 g_string_erase (parampart, 0, i+1);
1993 g_string_printf (actionname, act->name, parampart->str);
1995 g_string_printf (actionparam, act->param, parampart->str);
1996 parse_command(actionname->str, actionparam->str);
1997 g_string_free(actionname, TRUE);
1998 g_string_free(actionparam, TRUE);
1999 g_string_free(parampart, TRUE);
2007 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2008 //main_window_ref = g_object_ref(scrolled_window);
2009 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
2011 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2012 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2014 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2015 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2016 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2017 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2018 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2019 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2020 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2021 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2022 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2023 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2025 return scrolled_window;
2032 g->mainbar = gtk_hbox_new (FALSE, 0);
2034 /* keep a reference to the bar so we can re-pack it at runtime*/
2035 //sbar_ref = g_object_ref(g->mainbar);
2037 g->mainbar_label = gtk_label_new ("");
2038 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2039 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2040 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2041 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2042 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2047 GtkWidget* create_window () {
2048 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2049 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2050 gtk_widget_set_name (window, "Uzbl browser");
2051 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2052 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2058 run_handler (const gchar *act, const gchar *args) {
2059 char **parts = g_strsplit(act, " ", 2);
2061 else if ((g_strcmp0(parts[0], "spawn") == 0)
2062 || (g_strcmp0(parts[0], "sh") == 0)
2063 || (g_strcmp0(parts[0], "sync_spawn") == 0)
2064 || (g_strcmp0(parts[0], "sync_sh") == 0)) {
2066 GString *a = g_string_new ("");
2068 spawnparts = split_quoted(parts[1], FALSE);
2069 g_string_append_printf(a, "%s", spawnparts[0]);
2070 if (args) g_string_append_printf(a, " %s", args); /* append handler args before user args */
2072 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2073 g_string_append_printf(a, " %s", spawnparts[i]);
2074 parse_command(parts[0], a->str);
2075 g_string_free (a, TRUE);
2076 g_strfreev (spawnparts);
2078 parse_command(parts[0], parts[1]);
2083 add_binding (const gchar *key, const gchar *act) {
2084 char **parts = g_strsplit(act, " ", 2);
2091 if (uzbl.state.verbose)
2092 printf ("Binding %-10s : %s\n", key, act);
2093 action = new_action(parts[0], parts[1]);
2095 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2100 get_xdg_var (XDG_Var xdg) {
2101 const gchar* actual_value = getenv (xdg.environmental);
2102 const gchar* home = getenv ("HOME");
2104 gchar* return_value = str_replace ("~", home, actual_value);
2106 if (! actual_value || strcmp (actual_value, "") == 0) {
2107 if (xdg.default_value) {
2108 return_value = str_replace ("~", home, xdg.default_value);
2110 return_value = NULL;
2113 return return_value;
2117 find_xdg_file (int xdg_type, char* filename) {
2118 /* xdg_type = 0 => config
2119 xdg_type = 1 => data
2120 xdg_type = 2 => cache*/
2122 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2123 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2126 gchar* temporary_string;
2130 if (! file_exists (temporary_file) && xdg_type != 2) {
2131 buf = get_xdg_var (XDG[3 + xdg_type]);
2132 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2135 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2136 g_free (temporary_file);
2137 temporary_file = g_strconcat (temporary_string, filename, NULL);
2141 //g_free (temporary_string); - segfaults.
2143 if (file_exists (temporary_file)) {
2144 return temporary_file;
2151 State *s = &uzbl.state;
2152 Network *n = &uzbl.net;
2154 for (i = 0; default_config[i].command != NULL; i++) {
2155 parse_cmd_line(default_config[i].command);
2158 if (!s->config_file) {
2159 s->config_file = find_xdg_file (0, "/uzbl/config");
2162 if (s->config_file) {
2163 GArray* lines = read_file_by_line (s->config_file);
2167 while ((line = g_array_index(lines, gchar*, i))) {
2168 parse_cmd_line (line);
2172 g_array_free (lines, TRUE);
2174 if (uzbl.state.verbose)
2175 printf ("No configuration file loaded.\n");
2178 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2181 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2184 if (!uzbl.behave.cookie_handler) return;
2186 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2187 GString *s = g_string_new ("");
2188 SoupURI * soup_uri = soup_message_get_uri(msg);
2189 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2190 run_handler(uzbl.behave.cookie_handler, s->str);
2192 if(uzbl.comm.sync_stdout)
2193 soup_message_headers_replace (msg->request_headers, "Cookie", uzbl.comm.sync_stdout);
2194 //printf("stdout: %s\n", uzbl.comm.sync_stdout); // debugging
2195 if (uzbl.comm.sync_stdout) uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2197 g_string_free(s, TRUE);
2201 save_cookies (SoupMessage *msg, gpointer user_data){
2205 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2206 cookie = soup_cookie_to_set_cookie_header(ck->data);
2207 SoupURI * soup_uri = soup_message_get_uri(msg);
2208 GString *s = g_string_new ("");
2209 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2210 run_handler(uzbl.behave.cookie_handler, s->str);
2212 g_string_free(s, TRUE);
2217 /* --- WEBINSPECTOR --- */
2219 hide_window_cb(GtkWidget *widget, gpointer data) {
2222 gtk_widget_hide(widget);
2225 static WebKitWebView*
2226 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2229 (void) web_inspector;
2230 GtkWidget* scrolled_window;
2231 GtkWidget* new_web_view;
2234 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2235 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2236 G_CALLBACK(hide_window_cb), NULL);
2238 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2239 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2240 gtk_widget_show(g->inspector_window);
2242 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2243 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2244 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2245 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2246 gtk_widget_show(scrolled_window);
2248 new_web_view = webkit_web_view_new();
2249 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2251 return WEBKIT_WEB_VIEW(new_web_view);
2255 inspector_show_window_cb (WebKitWebInspector* inspector){
2257 gtk_widget_show(uzbl.gui.inspector_window);
2261 /* TODO: Add variables and code to make use of these functions */
2263 inspector_close_window_cb (WebKitWebInspector* inspector){
2269 inspector_attach_window_cb (WebKitWebInspector* inspector){
2275 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2281 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2287 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2293 set_up_inspector() {
2295 WebKitWebSettings *settings = view_settings();
2296 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2298 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2299 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2300 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2301 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2302 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2303 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2304 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2306 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2310 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2312 uzbl_cmdprop *c = v;
2317 if(c->type == TYPE_STR)
2318 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2319 else if(c->type == TYPE_INT)
2320 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2324 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2328 printf("bind %s = %s %s\n", (char *)k ,
2329 (char *)a->name, a->param?(char *)a->param:"");
2334 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2335 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2340 main (int argc, char* argv[]) {
2341 gtk_init (&argc, &argv);
2342 if (!g_thread_supported ())
2343 g_thread_init (NULL);
2344 uzbl.state.executable_path = g_strdup(argv[0]);
2345 uzbl.state.selected_url = NULL;
2346 uzbl.state.searchtx = NULL;
2348 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2349 g_option_context_add_main_entries (context, entries, NULL);
2350 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2351 g_option_context_parse (context, &argc, &argv, NULL);
2352 g_option_context_free(context);
2353 /* initialize hash table */
2354 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2356 uzbl.net.soup_session = webkit_get_default_session();
2357 uzbl.state.keycmd = g_string_new("");
2359 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2360 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2361 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2362 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2363 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2364 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2367 if(uname(&uzbl.state.unameinfo) == -1)
2368 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2370 uzbl.gui.sbar.progress_s = g_strdup("=");
2371 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2372 uzbl.gui.sbar.progress_w = 10;
2374 /* HTML mode defaults*/
2375 uzbl.behave.html_buffer = g_string_new("");
2376 uzbl.behave.html_endmarker = g_strdup(".");
2377 uzbl.behave.html_timeout = 60;
2378 uzbl.behave.base_url = g_strdup("http://invalid");
2380 /* default mode indicators */
2381 uzbl.behave.insert_indicator = g_strdup("I");
2382 uzbl.behave.cmd_indicator = g_strdup("C");
2387 make_var_to_name_hash();
2389 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2391 uzbl.gui.scrolled_win = create_browser();
2394 /* initial packing */
2395 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2396 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2398 uzbl.gui.main_window = create_window ();
2399 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2402 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2403 gtk_widget_show_all (uzbl.gui.main_window);
2404 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2406 if (uzbl.state.verbose) {
2407 printf("Uzbl start location: %s\n", argv[0]);
2408 printf("window_id %i\n",(int) uzbl.xwin);
2409 printf("pid %i\n", getpid ());
2410 printf("name: %s\n", uzbl.state.instance_name);
2413 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2414 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2415 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2416 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2417 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2421 if (!uzbl.behave.show_status)
2422 gtk_widget_hide(uzbl.gui.mainbar);
2431 if(uzbl.state.uri) {
2432 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
2433 g_array_append_val(a, uzbl.state.uri);
2434 load_uri (uzbl.gui.web_view, a);
2435 g_array_free (a, TRUE);
2441 return EXIT_SUCCESS;
2444 /* vi: set et ts=4: */