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 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
101 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
102 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
103 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
104 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
105 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
106 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
107 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
108 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
109 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
110 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
111 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
112 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
113 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
114 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
115 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
116 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
117 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
118 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
119 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
120 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
121 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
122 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
123 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
124 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
125 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
126 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
127 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
128 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
129 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
130 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
131 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
132 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
133 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
134 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
135 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
136 /* exported WebKitWebSettings properties*/
137 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
138 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
139 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
140 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
141 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
142 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
143 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
144 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
145 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
146 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
147 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
148 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
149 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
150 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
151 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
153 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
154 }, *n2v_p = var_name_to_ptr;
160 { "SHIFT", GDK_SHIFT_MASK }, // shift
161 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
162 { "CONTROL", GDK_CONTROL_MASK }, // control
163 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
164 { "MOD2", GDK_MOD2_MASK }, // 5th mod
165 { "MOD3", GDK_MOD3_MASK }, // 6th mod
166 { "MOD4", GDK_MOD4_MASK }, // 7th mod
167 { "MOD5", GDK_MOD5_MASK }, // 8th mod
168 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
169 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
170 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
171 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
172 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
173 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
174 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
175 { "META", GDK_META_MASK }, // meta (since 2.10)
180 /* construct a hash from the var_name_to_ptr array for quick access */
182 make_var_to_name_hash() {
183 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
185 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
190 /* --- UTILITY FUNCTIONS --- */
192 expand_vars(char *s) {
195 char ret[256], *vend;
196 GString *buf = g_string_new("");
201 g_string_append_c(buf, *++s);
209 if( (vend = strchr(s, upto)) ||
210 (vend = strchr(s, '\0')) ) {
211 strncpy(ret, s, vend-s);
213 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
214 if(c->type == TYPE_STR)
215 g_string_append(buf, (gchar *)*c->ptr);
216 else if(c->type == TYPE_INT) {
217 char *b = itos((int)*c->ptr);
218 g_string_append(buf, b);
222 if(upto == ' ') s = vend;
228 g_string_append_c(buf, *s);
233 return g_string_free(buf, FALSE);
240 snprintf(tmp, sizeof(tmp), "%i", val);
241 return g_strdup(tmp);
245 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
248 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
251 str_replace (const char* search, const char* replace, const char* string) {
255 buf = g_strsplit (string, search, -1);
256 ret = g_strjoinv (replace, buf);
257 g_strfreev(buf); // somebody said this segfaults
263 read_file_by_line (gchar *path) {
264 GIOChannel *chan = NULL;
265 gchar *readbuf = NULL;
267 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
270 chan = g_io_channel_new_file(path, "r", NULL);
273 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
274 const gchar* val = g_strdup (readbuf);
275 g_array_append_val (lines, val);
280 g_io_channel_unref (chan);
282 fprintf(stderr, "File '%s' not be read.\n", path);
289 gchar* parseenv (char* string) {
290 extern char** environ;
291 gchar* tmpstr = NULL;
295 while (environ[i] != NULL) {
296 gchar** env = g_strsplit (environ[i], "=", 2);
297 gchar* envname = g_strconcat ("$", env[0], NULL);
299 if (g_strrstr (string, envname) != NULL) {
300 tmpstr = g_strdup(string);
302 string = str_replace(envname, env[1], tmpstr);
307 g_strfreev (env); // somebody said this breaks uzbl
315 setup_signal(int signr, sigfunc *shandler) {
316 struct sigaction nh, oh;
318 nh.sa_handler = shandler;
319 sigemptyset(&nh.sa_mask);
322 if(sigaction(signr, &nh, &oh) < 0)
330 if (uzbl.behave.fifo_dir)
331 unlink (uzbl.comm.fifo_path);
332 if (uzbl.behave.socket_dir)
333 unlink (uzbl.comm.socket_path);
335 g_free(uzbl.state.executable_path);
336 g_string_free(uzbl.state.keycmd, TRUE);
337 g_hash_table_destroy(uzbl.bindings);
338 g_hash_table_destroy(uzbl.behave.commands);
341 /* used for html_mode_timeout
342 * be sure to extend this function to use
343 * more timers if needed in other places
346 set_timeout(int seconds) {
348 memset(&t, 0, sizeof t);
350 t.it_value.tv_sec = seconds;
351 t.it_value.tv_usec = 0;
352 setitimer(ITIMER_REAL, &t, NULL);
355 /* --- SIGNAL HANDLER --- */
358 catch_sigterm(int s) {
364 catch_sigint(int s) {
374 set_var_value("mode", "0");
379 /* --- CALLBACKS --- */
382 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
385 (void) navigation_action;
386 (void) policy_decision;
388 const gchar* uri = webkit_network_request_get_uri (request);
389 if (uzbl.state.verbose)
390 printf("New window requested -> %s \n", uri);
391 new_window_load_uri(uri);
396 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
400 if (uzbl.state.selected_url != NULL) {
401 if (uzbl.state.verbose)
402 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
403 new_window_load_uri(uzbl.state.selected_url);
405 if (uzbl.state.verbose)
406 printf("New web view -> %s\n","Nothing to open, exiting");
412 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
415 if (uzbl.behave.download_handler) {
416 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
417 if (uzbl.state.verbose)
418 printf("Download -> %s\n",uri);
419 /* if urls not escaped, we may have to escape and quote uri before this call */
420 run_handler(uzbl.behave.download_handler, uri);
425 /* scroll a bar in a given direction */
427 scroll (GtkAdjustment* bar, GArray *argv) {
431 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
432 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
433 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
437 scroll_begin(WebKitWebView* page, GArray *argv) {
438 (void) page; (void) argv;
439 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
443 scroll_end(WebKitWebView* page, GArray *argv) {
444 (void) page; (void) argv;
445 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
446 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
450 scroll_vert(WebKitWebView* page, GArray *argv) {
452 scroll(uzbl.gui.bar_v, argv);
456 scroll_horz(WebKitWebView* page, GArray *argv) {
458 scroll(uzbl.gui.bar_h, argv);
463 if (!uzbl.behave.show_status) {
464 gtk_widget_hide(uzbl.gui.mainbar);
466 gtk_widget_show(uzbl.gui.mainbar);
472 toggle_status_cb (WebKitWebView* page, GArray *argv) {
476 if (uzbl.behave.show_status) {
477 gtk_widget_hide(uzbl.gui.mainbar);
479 gtk_widget_show(uzbl.gui.mainbar);
481 uzbl.behave.show_status = !uzbl.behave.show_status;
486 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
490 //Set selected_url state variable
491 g_free(uzbl.state.selected_url);
492 uzbl.state.selected_url = NULL;
494 uzbl.state.selected_url = g_strdup(link);
500 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
504 if (uzbl.gui.main_title)
505 g_free (uzbl.gui.main_title);
506 uzbl.gui.main_title = g_strdup (title);
511 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
514 uzbl.gui.sbar.load_progress = progress;
519 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
523 if (uzbl.behave.load_finish_handler)
524 run_handler(uzbl.behave.load_finish_handler, "");
528 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
532 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
533 if (uzbl.behave.load_start_handler)
534 run_handler(uzbl.behave.load_start_handler, "");
538 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
541 g_free (uzbl.state.uri);
542 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
543 uzbl.state.uri = g_string_free (newuri, FALSE);
544 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
545 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
548 if (uzbl.behave.load_commit_handler)
549 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
553 destroy_cb (GtkWidget* widget, gpointer data) {
561 if (uzbl.behave.history_handler) {
563 struct tm * timeinfo;
566 timeinfo = localtime ( &rawtime );
567 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
568 run_handler(uzbl.behave.history_handler, date);
573 /* VIEW funcs (little webkit wrappers) */
574 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
576 VIEWFUNC(reload_bypass_cache)
577 VIEWFUNC(stop_loading)
584 /* -- command to callback/function map for things we cannot attach to any signals */
586 static struct {char *name; Command command[2];} cmdlist[] =
587 { /* key function no_split */
588 { "back", {view_go_back, 0} },
589 { "forward", {view_go_forward, 0} },
590 { "scroll_vert", {scroll_vert, 0} },
591 { "scroll_horz", {scroll_horz, 0} },
592 { "scroll_begin", {scroll_begin, 0} },
593 { "scroll_end", {scroll_end, 0} },
594 { "reload", {view_reload, 0}, },
595 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
596 { "stop", {view_stop_loading, 0}, },
597 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
598 { "zoom_out", {view_zoom_out, 0}, },
599 { "uri", {load_uri, NOSPLIT} },
600 { "js", {run_js, NOSPLIT} },
601 { "script", {run_external_js, 0} },
602 { "toggle_status", {toggle_status_cb, 0} },
603 { "spawn", {spawn, 0} },
604 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
605 { "sh", {spawn_sh, 0} },
606 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
607 { "exit", {close_uzbl, 0} },
608 { "search", {search_forward_text, NOSPLIT} },
609 { "search_reverse", {search_reverse_text, NOSPLIT} },
610 { "dehilight", {dehilight, 0} },
611 { "toggle_insert_mode", {toggle_insert_mode, 0} },
612 { "set", {set_var, NOSPLIT} },
613 //{ "get", {get_var, NOSPLIT} },
614 { "bind", {act_bind, NOSPLIT} },
615 { "dump_config", {act_dump_config, 0} },
616 { "keycmd", {keycmd, NOSPLIT} },
617 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
618 { "keycmd_bs", {keycmd_bs, 0} },
619 { "chain", {chain, 0} },
620 { "print", {print, NOSPLIT} }
627 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
629 for (i = 0; i < LENGTH(cmdlist); i++)
630 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
633 /* -- CORE FUNCTIONS -- */
636 free_action(gpointer act) {
637 Action *action = (Action*)act;
638 g_free(action->name);
640 g_free(action->param);
645 new_action(const gchar *name, const gchar *param) {
646 Action *action = g_new(Action, 1);
648 action->name = g_strdup(name);
650 action->param = g_strdup(param);
652 action->param = NULL;
658 file_exists (const char * filename) {
659 return (access(filename, F_OK) == 0);
663 set_var(WebKitWebView *page, GArray *argv) {
665 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
666 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
667 set_var_value(g_strstrip(split[0]), value);
673 print(WebKitWebView *page, GArray *argv) {
677 buf = expand_vars(argv_idx(argv, 0));
683 act_bind(WebKitWebView *page, GArray *argv) {
685 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
686 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
687 add_binding(g_strstrip(split[0]), value);
699 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
702 if (argv_idx(argv, 0)) {
703 if (strcmp (argv_idx(argv, 0), "0") == 0) {
704 uzbl.behave.insert_mode = FALSE;
706 uzbl.behave.insert_mode = TRUE;
709 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
716 load_uri (WebKitWebView *web_view, GArray *argv) {
717 if (argv_idx(argv, 0)) {
718 GString* newuri = g_string_new (argv_idx(argv, 0));
719 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
720 g_string_prepend (newuri, "http://");
721 /* if we do handle cookies, ask our handler for them */
722 webkit_web_view_load_uri (web_view, newuri->str);
723 g_string_free (newuri, TRUE);
728 run_js (WebKitWebView * web_view, GArray *argv) {
729 if (argv_idx(argv, 0))
730 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
734 run_external_js (WebKitWebView * web_view, GArray *argv) {
735 if (argv_idx(argv, 0)) {
736 GArray* lines = read_file_by_line (argv_idx (argv, 0));
741 while ((line = g_array_index(lines, gchar*, i))) {
743 js = g_strdup (line);
745 gchar* newjs = g_strconcat (js, line, NULL);
752 if (uzbl.state.verbose)
753 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
755 if (argv_idx (argv, 1)) {
756 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
760 webkit_web_view_execute_script (web_view, js);
762 g_array_free (lines, TRUE);
767 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
768 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
769 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
770 webkit_web_view_unmark_text_matches (page);
771 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
772 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
776 if (uzbl.state.searchtx) {
777 if (uzbl.state.verbose)
778 printf ("Searching: %s\n", uzbl.state.searchtx);
779 webkit_web_view_set_highlight_text_matches (page, TRUE);
780 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
785 search_forward_text (WebKitWebView *page, GArray *argv) {
786 search_text(page, argv, TRUE);
790 search_reverse_text (WebKitWebView *page, GArray *argv) {
791 search_text(page, argv, FALSE);
795 dehilight (WebKitWebView *page, GArray *argv) {
797 webkit_web_view_set_highlight_text_matches (page, FALSE);
802 new_window_load_uri (const gchar * uri) {
803 GString* to_execute = g_string_new ("");
804 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
806 for (i = 0; entries[i].long_name != NULL; i++) {
807 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
808 gchar** str = (gchar**)entries[i].arg_data;
810 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
814 if (uzbl.state.verbose)
815 printf("\n%s\n", to_execute->str);
816 g_spawn_command_line_async (to_execute->str, NULL);
817 g_string_free (to_execute, TRUE);
821 chain (WebKitWebView *page, GArray *argv) {
824 gchar **parts = NULL;
826 while ((a = argv_idx(argv, i++))) {
827 parts = g_strsplit (a, " ", 2);
828 parse_command(parts[0], parts[1]);
834 keycmd (WebKitWebView *page, GArray *argv) {
837 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
843 keycmd_nl (WebKitWebView *page, GArray *argv) {
846 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
852 keycmd_bs (WebKitWebView *page, GArray *argv) {
855 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
860 close_uzbl (WebKitWebView *page, GArray *argv) {
866 /* --Statusbar functions-- */
868 build_progressbar_ascii(int percent) {
869 int width=uzbl.gui.sbar.progress_w;
872 GString *bar = g_string_new("");
874 l = (double)percent*((double)width/100.);
875 l = (int)(l+.5)>=(int)l ? l+.5 : l;
877 for(i=0; i<(int)l; i++)
878 g_string_append(bar, uzbl.gui.sbar.progress_s);
881 g_string_append(bar, uzbl.gui.sbar.progress_u);
883 return g_string_free(bar, FALSE);
888 const GScannerConfig scan_config = {
891 ) /* cset_skip_characters */,
896 ) /* cset_identifier_first */,
903 ) /* cset_identifier_nth */,
904 ( "" ) /* cpair_comment_single */,
906 TRUE /* case_sensitive */,
908 FALSE /* skip_comment_multi */,
909 FALSE /* skip_comment_single */,
910 FALSE /* scan_comment_multi */,
911 TRUE /* scan_identifier */,
912 TRUE /* scan_identifier_1char */,
913 FALSE /* scan_identifier_NULL */,
914 TRUE /* scan_symbols */,
915 FALSE /* scan_binary */,
916 FALSE /* scan_octal */,
917 FALSE /* scan_float */,
918 FALSE /* scan_hex */,
919 FALSE /* scan_hex_dollar */,
920 FALSE /* scan_string_sq */,
921 FALSE /* scan_string_dq */,
922 TRUE /* numbers_2_int */,
923 FALSE /* int_2_float */,
924 FALSE /* identifier_2_string */,
925 FALSE /* char_2_token */,
926 FALSE /* symbol_2_token */,
927 TRUE /* scope_0_fallback */,
932 uzbl.scan = g_scanner_new(&scan_config);
933 while(symp->symbol_name) {
934 g_scanner_scope_add_symbol(uzbl.scan, 0,
936 GINT_TO_POINTER(symp->symbol_token));
942 expand_template(const char *template, gboolean escape_markup) {
943 if(!template) return NULL;
945 GTokenType token = G_TOKEN_NONE;
946 GString *ret = g_string_new("");
950 g_scanner_input_text(uzbl.scan, template, strlen(template));
951 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
952 token = g_scanner_get_next_token(uzbl.scan);
954 if(token == G_TOKEN_SYMBOL) {
955 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
959 buf = uzbl.state.uri?
960 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
961 g_string_append(ret, buf);
965 g_string_append(ret, uzbl.state.uri?
966 uzbl.state.uri:g_strdup(""));
969 buf = itos(uzbl.gui.sbar.load_progress);
970 g_string_append(ret, buf);
973 case SYM_LOADPRGSBAR:
974 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
975 g_string_append(ret, buf);
980 buf = uzbl.gui.main_title?
981 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
982 g_string_append(ret, buf);
986 g_string_append(ret, uzbl.gui.main_title?
987 uzbl.gui.main_title:g_strdup(""));
989 case SYM_SELECTED_URI:
991 buf = uzbl.state.selected_url?
992 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
993 g_string_append(ret, buf);
997 g_string_append(ret, uzbl.state.selected_url?
998 uzbl.state.selected_url:g_strdup(""));
1001 buf = itos(uzbl.xwin);
1002 g_string_append(ret,
1003 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1008 buf = uzbl.state.keycmd->str?
1009 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1010 g_string_append(ret, buf);
1014 g_string_append(ret, uzbl.state.keycmd->str?
1015 uzbl.state.keycmd->str:g_strdup(""));
1018 g_string_append(ret,
1019 uzbl.behave.insert_mode?
1020 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1023 g_string_append(ret,
1024 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1026 /* useragent syms */
1028 buf = itos(WEBKIT_MAJOR_VERSION);
1029 g_string_append(ret, buf);
1033 buf = itos(WEBKIT_MINOR_VERSION);
1034 g_string_append(ret, buf);
1038 buf = itos(WEBKIT_MICRO_VERSION);
1039 g_string_append(ret, buf);
1043 g_string_append(ret, uzbl.state.unameinfo.sysname);
1046 g_string_append(ret, uzbl.state.unameinfo.nodename);
1049 g_string_append(ret, uzbl.state.unameinfo.release);
1052 g_string_append(ret, uzbl.state.unameinfo.version);
1055 g_string_append(ret, uzbl.state.unameinfo.machine);
1058 g_string_append(ret, ARCH);
1061 case SYM_DOMAINNAME:
1062 g_string_append(ret, uzbl.state.unameinfo.domainname);
1066 g_string_append(ret, COMMIT);
1072 else if(token == G_TOKEN_INT) {
1073 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1074 g_string_append(ret, buf);
1077 else if(token == G_TOKEN_IDENTIFIER) {
1078 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1080 else if(token == G_TOKEN_CHAR) {
1081 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1085 return g_string_free(ret, FALSE);
1087 /* --End Statusbar functions-- */
1090 sharg_append(GArray *a, const gchar *str) {
1091 const gchar *s = (str ? str : "");
1092 g_array_append_val(a, s);
1095 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1097 run_command (const gchar *command, const guint npre, const gchar **args,
1098 const gboolean sync, char **stdout) {
1099 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1102 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1103 gchar *pid = itos(getpid());
1104 gchar *xwin = itos(uzbl.xwin);
1106 sharg_append(a, command);
1107 for (i = 0; i < npre; i++) /* add n args before the default vars */
1108 sharg_append(a, args[i]);
1109 sharg_append(a, uzbl.state.config_file);
1110 sharg_append(a, pid);
1111 sharg_append(a, xwin);
1112 sharg_append(a, uzbl.comm.fifo_path);
1113 sharg_append(a, uzbl.comm.socket_path);
1114 sharg_append(a, uzbl.state.uri);
1115 sharg_append(a, uzbl.gui.main_title);
1117 for (i = npre; i < g_strv_length((gchar**)args); i++)
1118 sharg_append(a, args[i]);
1122 if (*stdout) *stdout = strfree(*stdout);
1124 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1125 NULL, NULL, stdout, NULL, NULL, &err);
1126 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1127 NULL, NULL, NULL, &err);
1129 if (uzbl.state.verbose) {
1130 GString *s = g_string_new("spawned:");
1131 for (i = 0; i < (a->len); i++) {
1132 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1133 g_string_append_printf(s, " %s", qarg);
1136 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1137 printf("%s\n", s->str);
1138 g_string_free(s, TRUE);
1140 printf("Stdout: %s\n", *stdout);
1144 g_printerr("error on run_command: %s\n", err->message);
1149 g_array_free (a, TRUE);
1154 split_quoted(const gchar* src, const gboolean unquote) {
1155 /* split on unquoted space, return array of strings;
1156 remove a layer of quotes and backslashes if unquote */
1157 if (!src) return NULL;
1159 gboolean dq = FALSE;
1160 gboolean sq = FALSE;
1161 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1162 GString *s = g_string_new ("");
1166 for (p = src; *p != '\0'; p++) {
1167 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1168 else if (*p == '\\') { g_string_append_c(s, *p++);
1169 g_string_append_c(s, *p); }
1170 else if ((*p == '"') && unquote && !sq) dq = !dq;
1171 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1173 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1174 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1176 else if ((*p == ' ') && !dq && !sq) {
1177 dup = g_strdup(s->str);
1178 g_array_append_val(a, dup);
1179 g_string_truncate(s, 0);
1180 } else g_string_append_c(s, *p);
1182 dup = g_strdup(s->str);
1183 g_array_append_val(a, dup);
1184 ret = (gchar**)a->data;
1185 g_array_free (a, FALSE);
1186 g_string_free (s, TRUE);
1191 spawn(WebKitWebView *web_view, GArray *argv) {
1193 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1194 if (argv_idx(argv, 0))
1195 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1199 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1202 if (argv_idx(argv, 0))
1203 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1204 TRUE, &uzbl.comm.sync_stdout);
1208 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1210 if (!uzbl.behave.shell_cmd) {
1211 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1216 gchar *spacer = g_strdup("");
1217 g_array_insert_val(argv, 1, spacer);
1218 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1220 for (i = 1; i < g_strv_length(cmd); i++)
1221 g_array_prepend_val(argv, cmd[i]);
1223 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1229 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1231 if (!uzbl.behave.shell_cmd) {
1232 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1237 gchar *spacer = g_strdup("");
1238 g_array_insert_val(argv, 1, spacer);
1239 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1241 for (i = 1; i < g_strv_length(cmd); i++)
1242 g_array_prepend_val(argv, cmd[i]);
1244 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1245 TRUE, &uzbl.comm.sync_stdout);
1251 parse_command(const char *cmd, const char *param) {
1254 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1257 gchar **par = split_quoted(param, TRUE);
1258 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1260 if (c[1] == NOSPLIT) { /* don't split */
1261 sharg_append(a, param);
1263 for (i = 0; i < g_strv_length(par); i++)
1264 sharg_append(a, par[i]);
1266 c[0](uzbl.gui.web_view, a);
1268 g_array_free (a, TRUE);
1271 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1278 if(*uzbl.net.proxy_url == ' '
1279 || uzbl.net.proxy_url == NULL) {
1280 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1281 (GType) SOUP_SESSION_PROXY_URI);
1284 suri = soup_uri_new(uzbl.net.proxy_url);
1285 g_object_set(G_OBJECT(uzbl.net.soup_session),
1286 SOUP_SESSION_PROXY_URI,
1288 soup_uri_free(suri);
1295 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1296 g_array_append_val (a, uzbl.state.uri);
1297 load_uri(uzbl.gui.web_view, a);
1298 g_array_free (a, TRUE);
1302 cmd_always_insert_mode() {
1303 uzbl.behave.insert_mode =
1304 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1310 g_object_set(G_OBJECT(uzbl.net.soup_session),
1311 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1315 cmd_max_conns_host() {
1316 g_object_set(G_OBJECT(uzbl.net.soup_session),
1317 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1322 soup_session_remove_feature
1323 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1324 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1325 /*g_free(uzbl.net.soup_logger);*/
1327 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1328 soup_session_add_feature(uzbl.net.soup_session,
1329 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1332 static WebKitWebSettings*
1334 return webkit_web_view_get_settings(uzbl.gui.web_view);
1339 WebKitWebSettings *ws = view_settings();
1340 if (uzbl.behave.font_size > 0) {
1341 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1344 if (uzbl.behave.monospace_size > 0) {
1345 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1346 uzbl.behave.monospace_size, NULL);
1348 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1349 uzbl.behave.font_size, NULL);
1354 cmd_disable_plugins() {
1355 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1356 !uzbl.behave.disable_plugins, NULL);
1360 cmd_disable_scripts() {
1361 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1362 !uzbl.behave.disable_scripts, NULL);
1366 cmd_minimum_font_size() {
1367 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1368 uzbl.behave.minimum_font_size, NULL);
1371 cmd_autoload_img() {
1372 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1373 uzbl.behave.autoload_img, NULL);
1378 cmd_autoshrink_img() {
1379 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1380 uzbl.behave.autoshrink_img, NULL);
1385 cmd_enable_spellcheck() {
1386 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1387 uzbl.behave.enable_spellcheck, NULL);
1391 cmd_enable_private() {
1392 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1393 uzbl.behave.enable_private, NULL);
1398 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1399 uzbl.behave.print_bg, NULL);
1404 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1405 uzbl.behave.style_uri, NULL);
1409 cmd_resizable_txt() {
1410 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1411 uzbl.behave.resizable_txt, NULL);
1415 cmd_default_encoding() {
1416 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1417 uzbl.behave.default_encoding, NULL);
1421 cmd_enforce_96dpi() {
1422 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1423 uzbl.behave.enforce_96dpi, NULL);
1427 cmd_caret_browsing() {
1428 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1429 uzbl.behave.caret_browsing, NULL);
1433 cmd_cookie_handler() {
1434 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1435 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1436 if ((g_strcmp0(split[0], "sh") == 0) ||
1437 (g_strcmp0(split[0], "spawn") == 0)) {
1438 g_free (uzbl.behave.cookie_handler);
1439 uzbl.behave.cookie_handler =
1440 g_strdup_printf("sync_%s %s", split[0], split[1]);
1447 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1452 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1457 if(uzbl.behave.inject_html) {
1458 webkit_web_view_load_html_string (uzbl.gui.web_view,
1459 uzbl.behave.inject_html, NULL);
1468 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1469 uzbl.behave.modmask = 0;
1471 if(uzbl.behave.modkey)
1472 g_free(uzbl.behave.modkey);
1473 uzbl.behave.modkey = buf;
1475 for (i = 0; modkeys[i].key != NULL; i++) {
1476 if (g_strrstr(buf, modkeys[i].key))
1477 uzbl.behave.modmask |= modkeys[i].mask;
1483 if (*uzbl.net.useragent == ' ') {
1484 g_free (uzbl.net.useragent);
1485 uzbl.net.useragent = NULL;
1487 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1489 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1490 g_free(uzbl.net.useragent);
1491 uzbl.net.useragent = ua;
1497 gtk_widget_ref(uzbl.gui.scrolled_win);
1498 gtk_widget_ref(uzbl.gui.mainbar);
1499 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1500 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1502 if(uzbl.behave.status_top) {
1503 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1504 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1507 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1508 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1510 gtk_widget_unref(uzbl.gui.scrolled_win);
1511 gtk_widget_unref(uzbl.gui.mainbar);
1512 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1517 set_var_value(gchar *name, gchar *val) {
1518 uzbl_cmdprop *c = NULL;
1522 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1523 /* check for the variable type */
1524 if (c->type == TYPE_STR) {
1525 buf = expand_vars(val);
1528 } else if(c->type == TYPE_INT) {
1529 int *ip = (int *)c->ptr;
1530 buf = expand_vars(val);
1531 *ip = (int)strtoul(buf, &endp, 10);
1535 /* invoke a command specific function */
1536 if(c->func) c->func();
1543 Behaviour *b = &uzbl.behave;
1545 if(b->html_buffer->str) {
1546 webkit_web_view_load_html_string (uzbl.gui.web_view,
1547 b->html_buffer->str, b->base_url);
1548 g_string_free(b->html_buffer, TRUE);
1549 b->html_buffer = g_string_new("");
1553 enum {M_CMD, M_HTML};
1555 parse_cmd_line(const char *ctl_line) {
1556 Behaviour *b = &uzbl.behave;
1559 if(b->mode == M_HTML) {
1560 len = strlen(b->html_endmarker);
1561 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1562 if(len == strlen(ctl_line)-1 &&
1563 !strncmp(b->html_endmarker, ctl_line, len)) {
1565 set_var_value("mode", "0");
1570 set_timeout(b->html_timeout);
1571 g_string_append(b->html_buffer, ctl_line);
1574 else if((ctl_line[0] == '#') /* Comments */
1575 || (ctl_line[0] == ' ')
1576 || (ctl_line[0] == '\n'))
1577 ; /* ignore these lines */
1578 else { /* parse a command */
1580 gchar **tokens = NULL;
1581 len = strlen(ctl_line);
1583 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1584 ctlstrip = g_strndup(ctl_line, len - 1);
1585 else ctlstrip = g_strdup(ctl_line);
1587 tokens = g_strsplit(ctlstrip, " ", 2);
1588 parse_command(tokens[0], tokens[1]);
1595 build_stream_name(int type, const gchar* dir) {
1597 State *s = &uzbl.state;
1600 xwin_str = itos((int)uzbl.xwin);
1602 str = g_strdup_printf
1603 ("%s/uzbl_fifo_%s", dir,
1604 s->instance_name ? s->instance_name : xwin_str);
1605 } else if (type == SOCKET) {
1606 str = g_strdup_printf
1607 ("%s/uzbl_socket_%s", dir,
1608 s->instance_name ? s->instance_name : xwin_str );
1615 control_fifo(GIOChannel *gio, GIOCondition condition) {
1616 if (uzbl.state.verbose)
1617 printf("triggered\n");
1622 if (condition & G_IO_HUP)
1623 g_error ("Fifo: Read end of pipe died!\n");
1626 g_error ("Fifo: GIOChannel broke\n");
1628 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1629 if (ret == G_IO_STATUS_ERROR) {
1630 g_error ("Fifo: Error reading: %s\n", err->message);
1634 parse_cmd_line(ctl_line);
1641 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1642 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1643 if (unlink(uzbl.comm.fifo_path) == -1)
1644 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1645 g_free(uzbl.comm.fifo_path);
1646 uzbl.comm.fifo_path = NULL;
1649 if (*dir == ' ') { /* space unsets the variable */
1654 GIOChannel *chan = NULL;
1655 GError *error = NULL;
1656 gchar *path = build_stream_name(FIFO, dir);
1658 if (!file_exists(path)) {
1659 if (mkfifo (path, 0666) == 0) {
1660 // 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.
1661 chan = g_io_channel_new_file(path, "r+", &error);
1663 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1664 if (uzbl.state.verbose)
1665 printf ("init_fifo: created successfully as %s\n", path);
1666 uzbl.comm.fifo_path = path;
1668 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1669 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1670 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1671 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1673 /* if we got this far, there was an error; cleanup */
1674 if (error) g_error_free (error);
1681 control_stdin(GIOChannel *gio, GIOCondition condition) {
1683 gchar *ctl_line = NULL;
1686 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1687 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1690 parse_cmd_line(ctl_line);
1698 GIOChannel *chan = NULL;
1699 GError *error = NULL;
1701 chan = g_io_channel_unix_new(fileno(stdin));
1703 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1704 g_error ("Stdin: could not add watch\n");
1706 if (uzbl.state.verbose)
1707 printf ("Stdin: watch added successfully\n");
1710 g_error ("Stdin: Error while opening: %s\n", error->message);
1712 if (error) g_error_free (error);
1716 control_socket(GIOChannel *chan) {
1717 struct sockaddr_un remote;
1718 char buffer[512], *ctl_line;
1720 int sock, clientsock, n, done;
1723 sock = g_io_channel_unix_get_fd(chan);
1725 memset (buffer, 0, sizeof (buffer));
1727 t = sizeof (remote);
1728 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1732 memset (temp, 0, sizeof (temp));
1733 n = recv (clientsock, temp, 128, 0);
1735 buffer[strlen (buffer)] = '\0';
1739 strcat (buffer, temp);
1742 if (strcmp (buffer, "\n") < 0) {
1743 buffer[strlen (buffer) - 1] = '\0';
1745 buffer[strlen (buffer)] = '\0';
1748 ctl_line = g_strdup(buffer);
1749 parse_cmd_line (ctl_line);
1752 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1753 GError *error = NULL;
1756 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1757 if (ret == G_IO_STATUS_ERROR)
1758 g_error ("Error reading: %s\n", error->message);
1760 printf("Got line %s (%u bytes) \n",ctl_line, len);
1762 parse_line(ctl_line);
1770 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1771 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1772 if (unlink(uzbl.comm.socket_path) == -1)
1773 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1774 g_free(uzbl.comm.socket_path);
1775 uzbl.comm.socket_path = NULL;
1783 GIOChannel *chan = NULL;
1785 struct sockaddr_un local;
1786 gchar *path = build_stream_name(SOCKET, dir);
1788 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1790 local.sun_family = AF_UNIX;
1791 strcpy (local.sun_path, path);
1792 unlink (local.sun_path);
1794 len = strlen (local.sun_path) + sizeof (local.sun_family);
1795 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1796 if (uzbl.state.verbose)
1797 printf ("init_socket: opened in %s\n", path);
1800 if( (chan = g_io_channel_unix_new(sock)) ) {
1801 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1802 uzbl.comm.socket_path = path;
1805 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1807 /* if we got this far, there was an error; cleanup */
1814 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1815 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1817 // this function may be called very early when the templates are not set (yet), hence the checks
1819 update_title (void) {
1820 Behaviour *b = &uzbl.behave;
1823 if (b->show_status) {
1824 if (b->title_format_short) {
1825 parsed = expand_template(b->title_format_short, FALSE);
1826 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1829 if (b->status_format) {
1830 parsed = expand_template(b->status_format, TRUE);
1831 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1834 if (b->status_background) {
1836 gdk_color_parse (b->status_background, &color);
1837 //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)
1838 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1841 if (b->title_format_long) {
1842 parsed = expand_template(b->title_format_long, FALSE);
1843 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1850 key_press_cb (GtkWidget* window, GdkEventKey* event)
1852 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1856 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1857 || 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)
1860 /* turn off insert mode (if always_insert_mode is not used) */
1861 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1862 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1867 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1870 if (event->keyval == GDK_Escape) {
1871 g_string_truncate(uzbl.state.keycmd, 0);
1873 dehilight(uzbl.gui.web_view, NULL);
1877 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1878 if (event->keyval == GDK_Insert) {
1880 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1881 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1883 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1886 g_string_append (uzbl.state.keycmd, str);
1893 if (event->keyval == GDK_BackSpace)
1894 keycmd_bs(NULL, NULL);
1896 gboolean key_ret = FALSE;
1897 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1899 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1901 run_keycmd(key_ret);
1903 if (key_ret) return (!uzbl.behave.insert_mode);
1908 run_keycmd(const gboolean key_ret) {
1909 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1911 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1912 g_string_truncate(uzbl.state.keycmd, 0);
1913 parse_command(act->name, act->param);
1917 /* try if it's an incremental keycmd or one that takes args, and run it */
1918 GString* short_keys = g_string_new ("");
1919 GString* short_keys_inc = g_string_new ("");
1921 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1922 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1923 g_string_assign(short_keys_inc, short_keys->str);
1924 g_string_append_c(short_keys, '_');
1925 g_string_append_c(short_keys_inc, '*');
1927 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1928 /* run normal cmds only if return was pressed */
1929 exec_paramcmd(act, i);
1930 g_string_truncate(uzbl.state.keycmd, 0);
1932 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1933 if (key_ret) /* just quit the incremental command on return */
1934 g_string_truncate(uzbl.state.keycmd, 0);
1935 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1939 g_string_truncate(short_keys, short_keys->len - 1);
1941 g_string_free (short_keys, TRUE);
1942 g_string_free (short_keys_inc, TRUE);
1946 exec_paramcmd(const Action *act, const guint i) {
1947 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1948 GString *actionname = g_string_new ("");
1949 GString *actionparam = g_string_new ("");
1950 g_string_erase (parampart, 0, i+1);
1952 g_string_printf (actionname, act->name, parampart->str);
1954 g_string_printf (actionparam, act->param, parampart->str);
1955 parse_command(actionname->str, actionparam->str);
1956 g_string_free(actionname, TRUE);
1957 g_string_free(actionparam, TRUE);
1958 g_string_free(parampart, TRUE);
1966 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1967 //main_window_ref = g_object_ref(scrolled_window);
1968 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
1970 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1971 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1973 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1974 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1975 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1976 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
1977 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1978 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1979 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1980 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1981 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1982 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1984 return scrolled_window;
1991 g->mainbar = gtk_hbox_new (FALSE, 0);
1993 /* keep a reference to the bar so we can re-pack it at runtime*/
1994 //sbar_ref = g_object_ref(g->mainbar);
1996 g->mainbar_label = gtk_label_new ("");
1997 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1998 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1999 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2000 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2001 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2006 GtkWidget* create_window () {
2007 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2008 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2009 gtk_widget_set_name (window, "Uzbl browser");
2010 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2011 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2017 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2019 If actname is one that calls an external command, this function will inject
2020 newargs in front of the user-provided args in that command line. They will
2021 come become after the body of the script (in sh) or after the name of
2022 the command to execute (in spawn).
2023 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2024 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2026 The return value consist of two strings: the action (sh, ...) and its args.
2028 If act is not one that calls an external command, then the given action merely
2031 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2032 gchar *actdup = g_strdup(actname);
2033 g_array_append_val(rets, actdup);
2035 if ((g_strcmp0(actname, "spawn") == 0) ||
2036 (g_strcmp0(actname, "sh") == 0) ||
2037 (g_strcmp0(actname, "sync_spawn") == 0) ||
2038 (g_strcmp0(actname, "sync_sh") == 0)) {
2040 GString *a = g_string_new("");
2041 gchar **spawnparts = split_quoted(origargs, FALSE);
2042 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2043 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2045 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2046 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2048 g_array_append_val(rets, a->str);
2049 g_string_free(a, FALSE);
2050 g_strfreev(spawnparts);
2052 gchar *origdup = g_strdup(origargs);
2053 g_array_append_val(rets, origdup);
2055 return (gchar**)g_array_free(rets, FALSE);
2059 run_handler (const gchar *act, const gchar *args) {
2060 /* Consider this code a temporary hack to make the handlers usable.
2061 In practice, all this splicing, injection, and reconstruction is
2062 inefficient, annoying and hard to manage. Potential pitfalls arise
2063 when the handler specific args 1) are not quoted (the handler
2064 callbacks should take care of this) 2) are quoted but interfere
2065 with the users' own quotation. A more ideal solution is
2066 to refactor parse_command so that it doesn't just take a string
2067 and execute it; rather than that, we should have a function which
2068 returns the argument vector parsed from the string. This vector
2069 could be modified (e.g. insert additional args into it) before
2070 passing it to the next function that actually executes it. Though
2071 it still isn't perfect for chain actions.. will reconsider & re-
2072 factor when I have the time. -duc */
2074 char **parts = g_strsplit(act, " ", 2);
2076 if (g_strcmp0(parts[0], "chain") == 0) {
2077 GString *newargs = g_string_new("");
2078 gchar **chainparts = split_quoted(parts[1], FALSE);
2080 /* for every argument in the chain, inject the handler args
2081 and make sure the new parts are wrapped in quotes */
2082 gchar **cp = chainparts;
2084 gchar *quotless = NULL;
2085 gchar **spliced_quotless = NULL; // sigh -_-;
2086 gchar **inpart = NULL;
2089 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2091 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2092 } else quotless = g_strdup(*cp);
2094 spliced_quotless = g_strsplit(quotless, " ", 2);
2095 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2096 g_strfreev(spliced_quotless);
2098 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2104 parse_command(parts[0], &(newargs->str[1]));
2105 g_string_free(newargs, TRUE);
2106 g_strfreev(chainparts);
2109 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2110 parse_command(inparts[0], inparts[1]);
2118 add_binding (const gchar *key, const gchar *act) {
2119 char **parts = g_strsplit(act, " ", 2);
2126 if (uzbl.state.verbose)
2127 printf ("Binding %-10s : %s\n", key, act);
2128 action = new_action(parts[0], parts[1]);
2130 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2135 get_xdg_var (XDG_Var xdg) {
2136 const gchar* actual_value = getenv (xdg.environmental);
2137 const gchar* home = getenv ("HOME");
2139 gchar* return_value = str_replace ("~", home, actual_value);
2141 if (! actual_value || strcmp (actual_value, "") == 0) {
2142 if (xdg.default_value) {
2143 return_value = str_replace ("~", home, xdg.default_value);
2145 return_value = NULL;
2148 return return_value;
2152 find_xdg_file (int xdg_type, char* filename) {
2153 /* xdg_type = 0 => config
2154 xdg_type = 1 => data
2155 xdg_type = 2 => cache*/
2157 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2158 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2161 gchar* temporary_string;
2165 if (! file_exists (temporary_file) && xdg_type != 2) {
2166 buf = get_xdg_var (XDG[3 + xdg_type]);
2167 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2170 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2171 g_free (temporary_file);
2172 temporary_file = g_strconcat (temporary_string, filename, NULL);
2176 //g_free (temporary_string); - segfaults.
2178 if (file_exists (temporary_file)) {
2179 return temporary_file;
2186 State *s = &uzbl.state;
2187 Network *n = &uzbl.net;
2189 for (i = 0; default_config[i].command != NULL; i++) {
2190 parse_cmd_line(default_config[i].command);
2193 if (!s->config_file) {
2194 s->config_file = find_xdg_file (0, "/uzbl/config");
2197 if (s->config_file) {
2198 GArray* lines = read_file_by_line (s->config_file);
2202 while ((line = g_array_index(lines, gchar*, i))) {
2203 parse_cmd_line (line);
2207 g_array_free (lines, TRUE);
2209 if (uzbl.state.verbose)
2210 printf ("No configuration file loaded.\n");
2213 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
2216 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2219 if (!uzbl.behave.cookie_handler)
2222 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2223 GString *s = g_string_new ("");
2224 SoupURI * soup_uri = soup_message_get_uri(msg);
2225 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2226 run_handler(uzbl.behave.cookie_handler, s->str);
2228 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2229 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2230 if ( p != NULL ) *p = '\0';
2231 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2233 if (uzbl.comm.sync_stdout)
2234 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2236 g_string_free(s, TRUE);
2240 save_cookies (SoupMessage *msg, gpointer user_data){
2244 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2245 cookie = soup_cookie_to_set_cookie_header(ck->data);
2246 SoupURI * soup_uri = soup_message_get_uri(msg);
2247 GString *s = g_string_new ("");
2248 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2249 run_handler(uzbl.behave.cookie_handler, s->str);
2251 g_string_free(s, TRUE);
2256 /* --- WEBINSPECTOR --- */
2258 hide_window_cb(GtkWidget *widget, gpointer data) {
2261 gtk_widget_hide(widget);
2264 static WebKitWebView*
2265 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2268 (void) web_inspector;
2269 GtkWidget* scrolled_window;
2270 GtkWidget* new_web_view;
2273 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2274 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2275 G_CALLBACK(hide_window_cb), NULL);
2277 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2278 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2279 gtk_widget_show(g->inspector_window);
2281 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2282 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2283 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2284 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2285 gtk_widget_show(scrolled_window);
2287 new_web_view = webkit_web_view_new();
2288 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2290 return WEBKIT_WEB_VIEW(new_web_view);
2294 inspector_show_window_cb (WebKitWebInspector* inspector){
2296 gtk_widget_show(uzbl.gui.inspector_window);
2300 /* TODO: Add variables and code to make use of these functions */
2302 inspector_close_window_cb (WebKitWebInspector* inspector){
2308 inspector_attach_window_cb (WebKitWebInspector* inspector){
2314 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2320 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2326 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2332 set_up_inspector() {
2334 WebKitWebSettings *settings = view_settings();
2335 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2337 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2338 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2339 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2340 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2341 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2342 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2343 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2345 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2349 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2351 uzbl_cmdprop *c = v;
2356 if(c->type == TYPE_STR)
2357 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2358 else if(c->type == TYPE_INT)
2359 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2363 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2367 printf("bind %s = %s %s\n", (char *)k ,
2368 (char *)a->name, a->param?(char *)a->param:"");
2373 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2374 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2379 main (int argc, char* argv[]) {
2380 gtk_init (&argc, &argv);
2381 if (!g_thread_supported ())
2382 g_thread_init (NULL);
2383 uzbl.state.executable_path = g_strdup(argv[0]);
2384 uzbl.state.selected_url = NULL;
2385 uzbl.state.searchtx = NULL;
2387 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2388 g_option_context_add_main_entries (context, entries, NULL);
2389 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2390 g_option_context_parse (context, &argc, &argv, NULL);
2391 g_option_context_free(context);
2393 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2394 gboolean verbose_override = uzbl.state.verbose;
2396 /* initialize hash table */
2397 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2399 uzbl.net.soup_session = webkit_get_default_session();
2400 uzbl.state.keycmd = g_string_new("");
2402 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2403 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2404 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2405 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2406 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2407 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2410 if(uname(&uzbl.state.unameinfo) == -1)
2411 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2413 uzbl.gui.sbar.progress_s = g_strdup("=");
2414 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2415 uzbl.gui.sbar.progress_w = 10;
2417 /* HTML mode defaults*/
2418 uzbl.behave.html_buffer = g_string_new("");
2419 uzbl.behave.html_endmarker = g_strdup(".");
2420 uzbl.behave.html_timeout = 60;
2421 uzbl.behave.base_url = g_strdup("http://invalid");
2423 /* default mode indicators */
2424 uzbl.behave.insert_indicator = g_strdup("I");
2425 uzbl.behave.cmd_indicator = g_strdup("C");
2429 make_var_to_name_hash();
2431 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2433 uzbl.gui.scrolled_win = create_browser();
2436 /* initial packing */
2437 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2438 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2440 uzbl.gui.main_window = create_window ();
2441 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2444 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2445 gtk_widget_show_all (uzbl.gui.main_window);
2446 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2448 if (uzbl.state.verbose) {
2449 printf("Uzbl start location: %s\n", argv[0]);
2450 printf("window_id %i\n",(int) uzbl.xwin);
2451 printf("pid %i\n", getpid ());
2452 printf("name: %s\n", uzbl.state.instance_name);
2455 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2456 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2457 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2458 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2459 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2463 if (!uzbl.behave.show_status)
2464 gtk_widget_hide(uzbl.gui.mainbar);
2473 if (verbose_override > uzbl.state.verbose)
2474 uzbl.state.verbose = verbose_override;
2477 set_var_value("uri", uri_override);
2478 g_free(uri_override);
2479 } else if (uzbl.state.uri)
2480 cmd_load_uri(uzbl.gui.web_view, NULL);
2485 return EXIT_SUCCESS;
2488 /* vi: set et ts=4: */