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>
46 #include <libsoup/soup.h>
59 typedef void (*Command)(WebKitWebView*, GArray *argv);
63 /* commandline arguments (set initial values for the state variables) */
65 GOptionEntry entries[] =
67 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
68 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
69 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
70 "Whether to print all messages or just errors.", NULL },
71 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
72 "Name of the current instance (defaults to Xorg window id)", "NAME" },
73 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
74 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
75 { NULL, 0, 0, 0, NULL, NULL, NULL }
78 /* associate command names to their properties */
79 typedef const struct {
86 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
88 /* an abbreviation to help keep the table's width humane */
89 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
94 } var_name_to_ptr[] = {
95 /* variable name pointer to variable in code type dump callback function */
96 /* --------------------------------------------------------------------------------------- */
97 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
98 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
99 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
100 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
101 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
102 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
103 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
104 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
105 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
106 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
107 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
108 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
109 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
110 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
111 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
112 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
113 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
114 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
115 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
116 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
117 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
118 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
119 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
120 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
121 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
122 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
123 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
124 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
125 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
126 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
127 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
128 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
129 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
130 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
131 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
132 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
133 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
134 /* exported WebKitWebSettings properties */
135 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
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 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
400 /* If we can display it, let's display it... */
401 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
402 webkit_web_policy_decision_use (policy_decision);
406 /* ...everything we can't displayed is downloaded */
407 webkit_web_policy_decision_download (policy_decision);
412 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
416 if (uzbl.state.selected_url != NULL) {
417 if (uzbl.state.verbose)
418 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
419 new_window_load_uri(uzbl.state.selected_url);
421 if (uzbl.state.verbose)
422 printf("New web view -> %s\n","Nothing to open, exiting");
428 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
431 if (uzbl.behave.download_handler) {
432 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
433 if (uzbl.state.verbose)
434 printf("Download -> %s\n",uri);
435 /* if urls not escaped, we may have to escape and quote uri before this call */
436 run_handler(uzbl.behave.download_handler, uri);
441 /* scroll a bar in a given direction */
443 scroll (GtkAdjustment* bar, GArray *argv) {
447 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
448 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
449 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
453 scroll_begin(WebKitWebView* page, GArray *argv) {
454 (void) page; (void) argv;
455 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
459 scroll_end(WebKitWebView* page, GArray *argv) {
460 (void) page; (void) argv;
461 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
462 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
466 scroll_vert(WebKitWebView* page, GArray *argv) {
468 scroll(uzbl.gui.bar_v, argv);
472 scroll_horz(WebKitWebView* page, GArray *argv) {
474 scroll(uzbl.gui.bar_h, argv);
479 if (!uzbl.behave.show_status) {
480 gtk_widget_hide(uzbl.gui.mainbar);
482 gtk_widget_show(uzbl.gui.mainbar);
488 toggle_status_cb (WebKitWebView* page, GArray *argv) {
492 if (uzbl.behave.show_status) {
493 gtk_widget_hide(uzbl.gui.mainbar);
495 gtk_widget_show(uzbl.gui.mainbar);
497 uzbl.behave.show_status = !uzbl.behave.show_status;
502 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
506 //Set selected_url state variable
507 g_free(uzbl.state.selected_url);
508 uzbl.state.selected_url = NULL;
510 uzbl.state.selected_url = g_strdup(link);
516 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
520 if (uzbl.gui.main_title)
521 g_free (uzbl.gui.main_title);
522 uzbl.gui.main_title = g_strdup (title);
527 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
530 uzbl.gui.sbar.load_progress = progress;
535 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
539 if (uzbl.behave.load_finish_handler)
540 run_handler(uzbl.behave.load_finish_handler, "");
544 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
548 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
549 if (uzbl.behave.load_start_handler)
550 run_handler(uzbl.behave.load_start_handler, "");
554 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
557 g_free (uzbl.state.uri);
558 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
559 uzbl.state.uri = g_string_free (newuri, FALSE);
560 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
561 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
564 if (uzbl.behave.load_commit_handler)
565 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
569 destroy_cb (GtkWidget* widget, gpointer data) {
577 if (uzbl.behave.history_handler) {
579 struct tm * timeinfo;
582 timeinfo = localtime ( &rawtime );
583 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
584 run_handler(uzbl.behave.history_handler, date);
589 /* VIEW funcs (little webkit wrappers) */
590 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
592 VIEWFUNC(reload_bypass_cache)
593 VIEWFUNC(stop_loading)
600 /* -- command to callback/function map for things we cannot attach to any signals */
601 static struct {char *name; Command command[2];} cmdlist[] =
602 { /* key function no_split */
603 { "back", {view_go_back, 0} },
604 { "forward", {view_go_forward, 0} },
605 { "scroll_vert", {scroll_vert, 0} },
606 { "scroll_horz", {scroll_horz, 0} },
607 { "scroll_begin", {scroll_begin, 0} },
608 { "scroll_end", {scroll_end, 0} },
609 { "reload", {view_reload, 0}, },
610 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
611 { "stop", {view_stop_loading, 0}, },
612 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
613 { "zoom_out", {view_zoom_out, 0}, },
614 { "uri", {load_uri, NOSPLIT} },
615 { "js", {run_js, NOSPLIT} },
616 { "script", {run_external_js, 0} },
617 { "toggle_status", {toggle_status_cb, 0} },
618 { "spawn", {spawn, 0} },
619 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
620 { "sh", {spawn_sh, 0} },
621 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
622 { "exit", {close_uzbl, 0} },
623 { "search", {search_forward_text, NOSPLIT} },
624 { "search_reverse", {search_reverse_text, NOSPLIT} },
625 { "dehilight", {dehilight, 0} },
626 { "toggle_insert_mode", {toggle_insert_mode, 0} },
627 { "set", {set_var, NOSPLIT} },
628 //{ "get", {get_var, NOSPLIT} },
629 { "bind", {act_bind, NOSPLIT} },
630 { "dump_config", {act_dump_config, 0} },
631 { "keycmd", {keycmd, NOSPLIT} },
632 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
633 { "keycmd_bs", {keycmd_bs, 0} },
634 { "chain", {chain, 0} },
635 { "print", {print, NOSPLIT} }
642 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
644 for (i = 0; i < LENGTH(cmdlist); i++)
645 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
648 /* -- CORE FUNCTIONS -- */
651 free_action(gpointer act) {
652 Action *action = (Action*)act;
653 g_free(action->name);
655 g_free(action->param);
660 new_action(const gchar *name, const gchar *param) {
661 Action *action = g_new(Action, 1);
663 action->name = g_strdup(name);
665 action->param = g_strdup(param);
667 action->param = NULL;
673 file_exists (const char * filename) {
674 return (access(filename, F_OK) == 0);
678 set_var(WebKitWebView *page, GArray *argv) {
680 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
681 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
682 set_var_value(g_strstrip(split[0]), value);
688 print(WebKitWebView *page, GArray *argv) {
692 buf = expand_vars(argv_idx(argv, 0));
698 act_bind(WebKitWebView *page, GArray *argv) {
700 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
701 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
702 add_binding(g_strstrip(split[0]), value);
714 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
717 if (argv_idx(argv, 0)) {
718 if (strcmp (argv_idx(argv, 0), "0") == 0) {
719 uzbl.behave.insert_mode = FALSE;
721 uzbl.behave.insert_mode = TRUE;
724 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
731 load_uri (WebKitWebView *web_view, GArray *argv) {
732 if (argv_idx(argv, 0)) {
733 GString* newuri = g_string_new (argv_idx(argv, 0));
734 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
735 run_js(web_view, argv);
738 if (g_strrstr (argv_idx(argv, 0), "://") == NULL)
739 g_string_prepend (newuri, "http://");
740 /* if we do handle cookies, ask our handler for them */
741 webkit_web_view_load_uri (web_view, newuri->str);
742 g_string_free (newuri, TRUE);
747 run_js (WebKitWebView * web_view, GArray *argv) {
748 if (argv_idx(argv, 0))
749 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
753 run_external_js (WebKitWebView * web_view, GArray *argv) {
754 if (argv_idx(argv, 0)) {
755 GArray* lines = read_file_by_line (argv_idx (argv, 0));
760 while ((line = g_array_index(lines, gchar*, i))) {
762 js = g_strdup (line);
764 gchar* newjs = g_strconcat (js, line, NULL);
771 if (uzbl.state.verbose)
772 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
774 if (argv_idx (argv, 1)) {
775 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
779 webkit_web_view_execute_script (web_view, js);
781 g_array_free (lines, TRUE);
786 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
787 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
788 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
789 webkit_web_view_unmark_text_matches (page);
790 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
791 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
795 if (uzbl.state.searchtx) {
796 if (uzbl.state.verbose)
797 printf ("Searching: %s\n", uzbl.state.searchtx);
798 webkit_web_view_set_highlight_text_matches (page, TRUE);
799 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
804 search_forward_text (WebKitWebView *page, GArray *argv) {
805 search_text(page, argv, TRUE);
809 search_reverse_text (WebKitWebView *page, GArray *argv) {
810 search_text(page, argv, FALSE);
814 dehilight (WebKitWebView *page, GArray *argv) {
816 webkit_web_view_set_highlight_text_matches (page, FALSE);
821 new_window_load_uri (const gchar * uri) {
822 GString* to_execute = g_string_new ("");
823 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
825 for (i = 0; entries[i].long_name != NULL; i++) {
826 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
827 gchar** str = (gchar**)entries[i].arg_data;
829 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
833 if (uzbl.state.verbose)
834 printf("\n%s\n", to_execute->str);
835 g_spawn_command_line_async (to_execute->str, NULL);
836 g_string_free (to_execute, TRUE);
840 chain (WebKitWebView *page, GArray *argv) {
843 gchar **parts = NULL;
845 while ((a = argv_idx(argv, i++))) {
846 parts = g_strsplit (a, " ", 2);
847 parse_command(parts[0], parts[1]);
853 keycmd (WebKitWebView *page, GArray *argv) {
856 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
862 keycmd_nl (WebKitWebView *page, GArray *argv) {
865 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
871 keycmd_bs (WebKitWebView *page, GArray *argv) {
874 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
879 close_uzbl (WebKitWebView *page, GArray *argv) {
885 /* --Statusbar functions-- */
887 build_progressbar_ascii(int percent) {
888 int width=uzbl.gui.sbar.progress_w;
891 GString *bar = g_string_new("");
893 l = (double)percent*((double)width/100.);
894 l = (int)(l+.5)>=(int)l ? l+.5 : l;
896 for(i=0; i<(int)l; i++)
897 g_string_append(bar, uzbl.gui.sbar.progress_s);
900 g_string_append(bar, uzbl.gui.sbar.progress_u);
902 return g_string_free(bar, FALSE);
907 const GScannerConfig scan_config = {
910 ) /* cset_skip_characters */,
915 ) /* cset_identifier_first */,
922 ) /* cset_identifier_nth */,
923 ( "" ) /* cpair_comment_single */,
925 TRUE /* case_sensitive */,
927 FALSE /* skip_comment_multi */,
928 FALSE /* skip_comment_single */,
929 FALSE /* scan_comment_multi */,
930 TRUE /* scan_identifier */,
931 TRUE /* scan_identifier_1char */,
932 FALSE /* scan_identifier_NULL */,
933 TRUE /* scan_symbols */,
934 FALSE /* scan_binary */,
935 FALSE /* scan_octal */,
936 FALSE /* scan_float */,
937 FALSE /* scan_hex */,
938 FALSE /* scan_hex_dollar */,
939 FALSE /* scan_string_sq */,
940 FALSE /* scan_string_dq */,
941 TRUE /* numbers_2_int */,
942 FALSE /* int_2_float */,
943 FALSE /* identifier_2_string */,
944 FALSE /* char_2_token */,
945 FALSE /* symbol_2_token */,
946 TRUE /* scope_0_fallback */,
951 uzbl.scan = g_scanner_new(&scan_config);
952 while(symp->symbol_name) {
953 g_scanner_scope_add_symbol(uzbl.scan, 0,
955 GINT_TO_POINTER(symp->symbol_token));
961 expand_template(const char *template, gboolean escape_markup) {
962 if(!template) return NULL;
964 GTokenType token = G_TOKEN_NONE;
965 GString *ret = g_string_new("");
969 g_scanner_input_text(uzbl.scan, template, strlen(template));
970 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
971 token = g_scanner_get_next_token(uzbl.scan);
973 if(token == G_TOKEN_SYMBOL) {
974 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
978 buf = uzbl.state.uri?
979 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
980 g_string_append(ret, buf);
984 g_string_append(ret, uzbl.state.uri?
985 uzbl.state.uri:g_strdup(""));
988 buf = itos(uzbl.gui.sbar.load_progress);
989 g_string_append(ret, buf);
992 case SYM_LOADPRGSBAR:
993 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
994 g_string_append(ret, buf);
999 buf = uzbl.gui.main_title?
1000 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1001 g_string_append(ret, buf);
1005 g_string_append(ret, uzbl.gui.main_title?
1006 uzbl.gui.main_title:g_strdup(""));
1008 case SYM_SELECTED_URI:
1010 buf = uzbl.state.selected_url?
1011 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1012 g_string_append(ret, buf);
1016 g_string_append(ret, uzbl.state.selected_url?
1017 uzbl.state.selected_url:g_strdup(""));
1020 buf = itos(uzbl.xwin);
1021 g_string_append(ret,
1022 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1027 buf = uzbl.state.keycmd->str?
1028 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1029 g_string_append(ret, buf);
1033 g_string_append(ret, uzbl.state.keycmd->str?
1034 uzbl.state.keycmd->str:g_strdup(""));
1037 g_string_append(ret,
1038 uzbl.behave.insert_mode?
1039 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1042 g_string_append(ret,
1043 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1045 /* useragent syms */
1047 buf = itos(WEBKIT_MAJOR_VERSION);
1048 g_string_append(ret, buf);
1052 buf = itos(WEBKIT_MINOR_VERSION);
1053 g_string_append(ret, buf);
1057 buf = itos(WEBKIT_MICRO_VERSION);
1058 g_string_append(ret, buf);
1062 g_string_append(ret, uzbl.state.unameinfo.sysname);
1065 g_string_append(ret, uzbl.state.unameinfo.nodename);
1068 g_string_append(ret, uzbl.state.unameinfo.release);
1071 g_string_append(ret, uzbl.state.unameinfo.version);
1074 g_string_append(ret, uzbl.state.unameinfo.machine);
1077 g_string_append(ret, ARCH);
1080 case SYM_DOMAINNAME:
1081 g_string_append(ret, uzbl.state.unameinfo.domainname);
1085 g_string_append(ret, COMMIT);
1091 else if(token == G_TOKEN_INT) {
1092 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1093 g_string_append(ret, buf);
1096 else if(token == G_TOKEN_IDENTIFIER) {
1097 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1099 else if(token == G_TOKEN_CHAR) {
1100 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1104 return g_string_free(ret, FALSE);
1106 /* --End Statusbar functions-- */
1109 sharg_append(GArray *a, const gchar *str) {
1110 const gchar *s = (str ? str : "");
1111 g_array_append_val(a, s);
1114 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1116 run_command (const gchar *command, const guint npre, const gchar **args,
1117 const gboolean sync, char **stdout) {
1118 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1121 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1122 gchar *pid = itos(getpid());
1123 gchar *xwin = itos(uzbl.xwin);
1125 sharg_append(a, command);
1126 for (i = 0; i < npre; i++) /* add n args before the default vars */
1127 sharg_append(a, args[i]);
1128 sharg_append(a, uzbl.state.config_file);
1129 sharg_append(a, pid);
1130 sharg_append(a, xwin);
1131 sharg_append(a, uzbl.comm.fifo_path);
1132 sharg_append(a, uzbl.comm.socket_path);
1133 sharg_append(a, uzbl.state.uri);
1134 sharg_append(a, uzbl.gui.main_title);
1136 for (i = npre; i < g_strv_length((gchar**)args); i++)
1137 sharg_append(a, args[i]);
1141 if (*stdout) *stdout = strfree(*stdout);
1143 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1144 NULL, NULL, stdout, NULL, NULL, &err);
1145 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1146 NULL, NULL, NULL, &err);
1148 if (uzbl.state.verbose) {
1149 GString *s = g_string_new("spawned:");
1150 for (i = 0; i < (a->len); i++) {
1151 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1152 g_string_append_printf(s, " %s", qarg);
1155 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1156 printf("%s\n", s->str);
1157 g_string_free(s, TRUE);
1159 printf("Stdout: %s\n", *stdout);
1163 g_printerr("error on run_command: %s\n", err->message);
1168 g_array_free (a, TRUE);
1173 split_quoted(const gchar* src, const gboolean unquote) {
1174 /* split on unquoted space, return array of strings;
1175 remove a layer of quotes and backslashes if unquote */
1176 if (!src) return NULL;
1178 gboolean dq = FALSE;
1179 gboolean sq = FALSE;
1180 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1181 GString *s = g_string_new ("");
1185 for (p = src; *p != '\0'; p++) {
1186 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1187 else if (*p == '\\') { g_string_append_c(s, *p++);
1188 g_string_append_c(s, *p); }
1189 else if ((*p == '"') && unquote && !sq) dq = !dq;
1190 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1192 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1193 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1195 else if ((*p == ' ') && !dq && !sq) {
1196 dup = g_strdup(s->str);
1197 g_array_append_val(a, dup);
1198 g_string_truncate(s, 0);
1199 } else g_string_append_c(s, *p);
1201 dup = g_strdup(s->str);
1202 g_array_append_val(a, dup);
1203 ret = (gchar**)a->data;
1204 g_array_free (a, FALSE);
1205 g_string_free (s, TRUE);
1210 spawn(WebKitWebView *web_view, GArray *argv) {
1212 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1213 if (argv_idx(argv, 0))
1214 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1218 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1221 if (argv_idx(argv, 0))
1222 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1223 TRUE, &uzbl.comm.sync_stdout);
1227 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1229 if (!uzbl.behave.shell_cmd) {
1230 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1235 gchar *spacer = g_strdup("");
1236 g_array_insert_val(argv, 1, spacer);
1237 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1239 for (i = 1; i < g_strv_length(cmd); i++)
1240 g_array_prepend_val(argv, cmd[i]);
1242 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1248 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1250 if (!uzbl.behave.shell_cmd) {
1251 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1256 gchar *spacer = g_strdup("");
1257 g_array_insert_val(argv, 1, spacer);
1258 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1260 for (i = 1; i < g_strv_length(cmd); i++)
1261 g_array_prepend_val(argv, cmd[i]);
1263 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1264 TRUE, &uzbl.comm.sync_stdout);
1270 parse_command(const char *cmd, const char *param) {
1273 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1276 gchar **par = split_quoted(param, TRUE);
1277 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1279 if (c[1] == NOSPLIT) { /* don't split */
1280 sharg_append(a, param);
1282 for (i = 0; i < g_strv_length(par); i++)
1283 sharg_append(a, par[i]);
1285 c[0](uzbl.gui.web_view, a);
1287 g_array_free (a, TRUE);
1290 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1297 if(*uzbl.net.proxy_url == ' '
1298 || uzbl.net.proxy_url == NULL) {
1299 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1300 (GType) SOUP_SESSION_PROXY_URI);
1303 suri = soup_uri_new(uzbl.net.proxy_url);
1304 g_object_set(G_OBJECT(uzbl.net.soup_session),
1305 SOUP_SESSION_PROXY_URI,
1307 soup_uri_free(suri);
1314 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1315 g_array_append_val (a, uzbl.state.uri);
1316 load_uri(uzbl.gui.web_view, a);
1317 g_array_free (a, TRUE);
1321 cmd_always_insert_mode() {
1322 uzbl.behave.insert_mode =
1323 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1329 g_object_set(G_OBJECT(uzbl.net.soup_session),
1330 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1334 cmd_max_conns_host() {
1335 g_object_set(G_OBJECT(uzbl.net.soup_session),
1336 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1341 soup_session_remove_feature
1342 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1343 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1344 /*g_free(uzbl.net.soup_logger);*/
1346 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1347 soup_session_add_feature(uzbl.net.soup_session,
1348 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1351 static WebKitWebSettings*
1353 return webkit_web_view_get_settings(uzbl.gui.web_view);
1358 WebKitWebSettings *ws = view_settings();
1359 if (uzbl.behave.font_size > 0) {
1360 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1363 if (uzbl.behave.monospace_size > 0) {
1364 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1365 uzbl.behave.monospace_size, NULL);
1367 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1368 uzbl.behave.font_size, NULL);
1374 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1378 cmd_disable_plugins() {
1379 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1380 !uzbl.behave.disable_plugins, NULL);
1384 cmd_disable_scripts() {
1385 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1386 !uzbl.behave.disable_scripts, NULL);
1390 cmd_minimum_font_size() {
1391 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1392 uzbl.behave.minimum_font_size, NULL);
1395 cmd_autoload_img() {
1396 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1397 uzbl.behave.autoload_img, NULL);
1402 cmd_autoshrink_img() {
1403 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1404 uzbl.behave.autoshrink_img, NULL);
1409 cmd_enable_spellcheck() {
1410 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1411 uzbl.behave.enable_spellcheck, NULL);
1415 cmd_enable_private() {
1416 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1417 uzbl.behave.enable_private, NULL);
1422 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1423 uzbl.behave.print_bg, NULL);
1428 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1429 uzbl.behave.style_uri, NULL);
1433 cmd_resizable_txt() {
1434 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1435 uzbl.behave.resizable_txt, NULL);
1439 cmd_default_encoding() {
1440 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1441 uzbl.behave.default_encoding, NULL);
1445 cmd_enforce_96dpi() {
1446 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1447 uzbl.behave.enforce_96dpi, NULL);
1451 cmd_caret_browsing() {
1452 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1453 uzbl.behave.caret_browsing, NULL);
1457 cmd_cookie_handler() {
1458 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1459 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1460 if ((g_strcmp0(split[0], "sh") == 0) ||
1461 (g_strcmp0(split[0], "spawn") == 0)) {
1462 g_free (uzbl.behave.cookie_handler);
1463 uzbl.behave.cookie_handler =
1464 g_strdup_printf("sync_%s %s", split[0], split[1]);
1471 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1476 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1481 if(uzbl.behave.inject_html) {
1482 webkit_web_view_load_html_string (uzbl.gui.web_view,
1483 uzbl.behave.inject_html, NULL);
1492 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1493 uzbl.behave.modmask = 0;
1495 if(uzbl.behave.modkey)
1496 g_free(uzbl.behave.modkey);
1497 uzbl.behave.modkey = buf;
1499 for (i = 0; modkeys[i].key != NULL; i++) {
1500 if (g_strrstr(buf, modkeys[i].key))
1501 uzbl.behave.modmask |= modkeys[i].mask;
1507 if (*uzbl.net.useragent == ' ') {
1508 g_free (uzbl.net.useragent);
1509 uzbl.net.useragent = NULL;
1511 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1513 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1514 g_free(uzbl.net.useragent);
1515 uzbl.net.useragent = ua;
1521 gtk_widget_ref(uzbl.gui.scrolled_win);
1522 gtk_widget_ref(uzbl.gui.mainbar);
1523 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1524 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1526 if(uzbl.behave.status_top) {
1527 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1528 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1531 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1532 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1534 gtk_widget_unref(uzbl.gui.scrolled_win);
1535 gtk_widget_unref(uzbl.gui.mainbar);
1536 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1541 set_var_value(gchar *name, gchar *val) {
1542 uzbl_cmdprop *c = NULL;
1546 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1547 /* check for the variable type */
1548 if (c->type == TYPE_STR) {
1549 buf = expand_vars(val);
1552 } else if(c->type == TYPE_INT) {
1553 int *ip = (int *)c->ptr;
1554 buf = expand_vars(val);
1555 *ip = (int)strtoul(buf, &endp, 10);
1557 } else if (c->type == TYPE_FLOAT) {
1558 float *fp = (float *)c->ptr;
1559 buf = expand_vars(val);
1560 *fp = strtof(buf, &endp);
1564 /* invoke a command specific function */
1565 if(c->func) c->func();
1572 Behaviour *b = &uzbl.behave;
1574 if(b->html_buffer->str) {
1575 webkit_web_view_load_html_string (uzbl.gui.web_view,
1576 b->html_buffer->str, b->base_url);
1577 g_string_free(b->html_buffer, TRUE);
1578 b->html_buffer = g_string_new("");
1582 enum {M_CMD, M_HTML};
1584 parse_cmd_line(const char *ctl_line) {
1585 Behaviour *b = &uzbl.behave;
1588 if(b->mode == M_HTML) {
1589 len = strlen(b->html_endmarker);
1590 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1591 if(len == strlen(ctl_line)-1 &&
1592 !strncmp(b->html_endmarker, ctl_line, len)) {
1594 set_var_value("mode", "0");
1599 set_timeout(b->html_timeout);
1600 g_string_append(b->html_buffer, ctl_line);
1603 else if((ctl_line[0] == '#') /* Comments */
1604 || (ctl_line[0] == ' ')
1605 || (ctl_line[0] == '\n'))
1606 ; /* ignore these lines */
1607 else { /* parse a command */
1609 gchar **tokens = NULL;
1610 len = strlen(ctl_line);
1612 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1613 ctlstrip = g_strndup(ctl_line, len - 1);
1614 else ctlstrip = g_strdup(ctl_line);
1616 tokens = g_strsplit(ctlstrip, " ", 2);
1617 parse_command(tokens[0], tokens[1]);
1624 build_stream_name(int type, const gchar* dir) {
1626 State *s = &uzbl.state;
1629 xwin_str = itos((int)uzbl.xwin);
1631 str = g_strdup_printf
1632 ("%s/uzbl_fifo_%s", dir,
1633 s->instance_name ? s->instance_name : xwin_str);
1634 } else if (type == SOCKET) {
1635 str = g_strdup_printf
1636 ("%s/uzbl_socket_%s", dir,
1637 s->instance_name ? s->instance_name : xwin_str );
1644 control_fifo(GIOChannel *gio, GIOCondition condition) {
1645 if (uzbl.state.verbose)
1646 printf("triggered\n");
1651 if (condition & G_IO_HUP)
1652 g_error ("Fifo: Read end of pipe died!\n");
1655 g_error ("Fifo: GIOChannel broke\n");
1657 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1658 if (ret == G_IO_STATUS_ERROR) {
1659 g_error ("Fifo: Error reading: %s\n", err->message);
1663 parse_cmd_line(ctl_line);
1670 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1671 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1672 if (unlink(uzbl.comm.fifo_path) == -1)
1673 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1674 g_free(uzbl.comm.fifo_path);
1675 uzbl.comm.fifo_path = NULL;
1678 if (*dir == ' ') { /* space unsets the variable */
1683 GIOChannel *chan = NULL;
1684 GError *error = NULL;
1685 gchar *path = build_stream_name(FIFO, dir);
1687 if (!file_exists(path)) {
1688 if (mkfifo (path, 0666) == 0) {
1689 // 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.
1690 chan = g_io_channel_new_file(path, "r+", &error);
1692 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1693 if (uzbl.state.verbose)
1694 printf ("init_fifo: created successfully as %s\n", path);
1695 uzbl.comm.fifo_path = path;
1697 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1698 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1699 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1700 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1702 /* if we got this far, there was an error; cleanup */
1703 if (error) g_error_free (error);
1710 control_stdin(GIOChannel *gio, GIOCondition condition) {
1712 gchar *ctl_line = NULL;
1715 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1716 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1719 parse_cmd_line(ctl_line);
1727 GIOChannel *chan = NULL;
1728 GError *error = NULL;
1730 chan = g_io_channel_unix_new(fileno(stdin));
1732 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1733 g_error ("Stdin: could not add watch\n");
1735 if (uzbl.state.verbose)
1736 printf ("Stdin: watch added successfully\n");
1739 g_error ("Stdin: Error while opening: %s\n", error->message);
1741 if (error) g_error_free (error);
1745 control_socket(GIOChannel *chan) {
1746 struct sockaddr_un remote;
1747 char buffer[512], *ctl_line;
1749 int sock, clientsock, n, done;
1752 sock = g_io_channel_unix_get_fd(chan);
1754 memset (buffer, 0, sizeof (buffer));
1756 t = sizeof (remote);
1757 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1761 memset (temp, 0, sizeof (temp));
1762 n = recv (clientsock, temp, 128, 0);
1764 buffer[strlen (buffer)] = '\0';
1768 strcat (buffer, temp);
1771 if (strcmp (buffer, "\n") < 0) {
1772 buffer[strlen (buffer) - 1] = '\0';
1774 buffer[strlen (buffer)] = '\0';
1777 ctl_line = g_strdup(buffer);
1778 parse_cmd_line (ctl_line);
1781 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1782 GError *error = NULL;
1785 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1786 if (ret == G_IO_STATUS_ERROR)
1787 g_error ("Error reading: %s\n", error->message);
1789 printf("Got line %s (%u bytes) \n",ctl_line, len);
1791 parse_line(ctl_line);
1799 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1800 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1801 if (unlink(uzbl.comm.socket_path) == -1)
1802 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1803 g_free(uzbl.comm.socket_path);
1804 uzbl.comm.socket_path = NULL;
1812 GIOChannel *chan = NULL;
1814 struct sockaddr_un local;
1815 gchar *path = build_stream_name(SOCKET, dir);
1817 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1819 local.sun_family = AF_UNIX;
1820 strcpy (local.sun_path, path);
1821 unlink (local.sun_path);
1823 len = strlen (local.sun_path) + sizeof (local.sun_family);
1824 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1825 if (uzbl.state.verbose)
1826 printf ("init_socket: opened in %s\n", path);
1829 if( (chan = g_io_channel_unix_new(sock)) ) {
1830 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1831 uzbl.comm.socket_path = path;
1834 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1836 /* if we got this far, there was an error; cleanup */
1843 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1844 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1846 // this function may be called very early when the templates are not set (yet), hence the checks
1848 update_title (void) {
1849 Behaviour *b = &uzbl.behave;
1852 if (b->show_status) {
1853 if (b->title_format_short) {
1854 parsed = expand_template(b->title_format_short, FALSE);
1855 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1858 if (b->status_format) {
1859 parsed = expand_template(b->status_format, TRUE);
1860 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1863 if (b->status_background) {
1865 gdk_color_parse (b->status_background, &color);
1866 //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)
1867 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1870 if (b->title_format_long) {
1871 parsed = expand_template(b->title_format_long, FALSE);
1872 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1879 key_press_cb (GtkWidget* window, GdkEventKey* event)
1881 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1885 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1886 || 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)
1889 /* turn off insert mode (if always_insert_mode is not used) */
1890 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1891 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1896 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1899 if (event->keyval == GDK_Escape) {
1900 g_string_truncate(uzbl.state.keycmd, 0);
1902 dehilight(uzbl.gui.web_view, NULL);
1906 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1907 if (event->keyval == GDK_Insert) {
1909 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1910 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1912 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1915 g_string_append (uzbl.state.keycmd, str);
1922 if (event->keyval == GDK_BackSpace)
1923 keycmd_bs(NULL, NULL);
1925 gboolean key_ret = FALSE;
1926 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1928 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1930 run_keycmd(key_ret);
1932 if (key_ret) return (!uzbl.behave.insert_mode);
1937 run_keycmd(const gboolean key_ret) {
1938 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1940 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1941 g_string_truncate(uzbl.state.keycmd, 0);
1942 parse_command(act->name, act->param);
1946 /* try if it's an incremental keycmd or one that takes args, and run it */
1947 GString* short_keys = g_string_new ("");
1948 GString* short_keys_inc = g_string_new ("");
1950 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1951 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1952 g_string_assign(short_keys_inc, short_keys->str);
1953 g_string_append_c(short_keys, '_');
1954 g_string_append_c(short_keys_inc, '*');
1956 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1957 /* run normal cmds only if return was pressed */
1958 exec_paramcmd(act, i);
1959 g_string_truncate(uzbl.state.keycmd, 0);
1961 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1962 if (key_ret) /* just quit the incremental command on return */
1963 g_string_truncate(uzbl.state.keycmd, 0);
1964 else exec_paramcmd(act, i); /* otherwise execute the incremental */
1968 g_string_truncate(short_keys, short_keys->len - 1);
1970 g_string_free (short_keys, TRUE);
1971 g_string_free (short_keys_inc, TRUE);
1975 exec_paramcmd(const Action *act, const guint i) {
1976 GString *parampart = g_string_new (uzbl.state.keycmd->str);
1977 GString *actionname = g_string_new ("");
1978 GString *actionparam = g_string_new ("");
1979 g_string_erase (parampart, 0, i+1);
1981 g_string_printf (actionname, act->name, parampart->str);
1983 g_string_printf (actionparam, act->param, parampart->str);
1984 parse_command(actionname->str, actionparam->str);
1985 g_string_free(actionname, TRUE);
1986 g_string_free(actionparam, TRUE);
1987 g_string_free(parampart, TRUE);
1995 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1996 //main_window_ref = g_object_ref(scrolled_window);
1997 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
1999 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2000 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2002 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2003 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2004 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2005 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2006 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2007 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2008 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2009 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2010 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2011 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2012 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2014 return scrolled_window;
2021 g->mainbar = gtk_hbox_new (FALSE, 0);
2023 /* keep a reference to the bar so we can re-pack it at runtime*/
2024 //sbar_ref = g_object_ref(g->mainbar);
2026 g->mainbar_label = gtk_label_new ("");
2027 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2028 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2029 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2030 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2031 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2036 GtkWidget* create_window () {
2037 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2038 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2039 gtk_widget_set_name (window, "Uzbl browser");
2040 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2041 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2047 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2049 If actname is one that calls an external command, this function will inject
2050 newargs in front of the user-provided args in that command line. They will
2051 come become after the body of the script (in sh) or after the name of
2052 the command to execute (in spawn).
2053 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2054 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2056 The return value consist of two strings: the action (sh, ...) and its args.
2058 If act is not one that calls an external command, then the given action merely
2061 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2062 gchar *actdup = g_strdup(actname);
2063 g_array_append_val(rets, actdup);
2065 if ((g_strcmp0(actname, "spawn") == 0) ||
2066 (g_strcmp0(actname, "sh") == 0) ||
2067 (g_strcmp0(actname, "sync_spawn") == 0) ||
2068 (g_strcmp0(actname, "sync_sh") == 0)) {
2070 GString *a = g_string_new("");
2071 gchar **spawnparts = split_quoted(origargs, FALSE);
2072 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2073 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2075 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2076 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2078 g_array_append_val(rets, a->str);
2079 g_string_free(a, FALSE);
2080 g_strfreev(spawnparts);
2082 gchar *origdup = g_strdup(origargs);
2083 g_array_append_val(rets, origdup);
2085 return (gchar**)g_array_free(rets, FALSE);
2089 run_handler (const gchar *act, const gchar *args) {
2090 /* Consider this code a temporary hack to make the handlers usable.
2091 In practice, all this splicing, injection, and reconstruction is
2092 inefficient, annoying and hard to manage. Potential pitfalls arise
2093 when the handler specific args 1) are not quoted (the handler
2094 callbacks should take care of this) 2) are quoted but interfere
2095 with the users' own quotation. A more ideal solution is
2096 to refactor parse_command so that it doesn't just take a string
2097 and execute it; rather than that, we should have a function which
2098 returns the argument vector parsed from the string. This vector
2099 could be modified (e.g. insert additional args into it) before
2100 passing it to the next function that actually executes it. Though
2101 it still isn't perfect for chain actions.. will reconsider & re-
2102 factor when I have the time. -duc */
2104 char **parts = g_strsplit(act, " ", 2);
2106 if (g_strcmp0(parts[0], "chain") == 0) {
2107 GString *newargs = g_string_new("");
2108 gchar **chainparts = split_quoted(parts[1], FALSE);
2110 /* for every argument in the chain, inject the handler args
2111 and make sure the new parts are wrapped in quotes */
2112 gchar **cp = chainparts;
2114 gchar *quotless = NULL;
2115 gchar **spliced_quotless = NULL; // sigh -_-;
2116 gchar **inpart = NULL;
2119 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2121 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2122 } else quotless = g_strdup(*cp);
2124 spliced_quotless = g_strsplit(quotless, " ", 2);
2125 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2126 g_strfreev(spliced_quotless);
2128 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2134 parse_command(parts[0], &(newargs->str[1]));
2135 g_string_free(newargs, TRUE);
2136 g_strfreev(chainparts);
2139 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2140 parse_command(inparts[0], inparts[1]);
2148 add_binding (const gchar *key, const gchar *act) {
2149 char **parts = g_strsplit(act, " ", 2);
2156 if (uzbl.state.verbose)
2157 printf ("Binding %-10s : %s\n", key, act);
2158 action = new_action(parts[0], parts[1]);
2160 if (g_hash_table_remove (uzbl.bindings, key))
2161 g_warning ("Overwriting existing binding for \"%s\"", key);
2162 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2167 get_xdg_var (XDG_Var xdg) {
2168 const gchar* actual_value = getenv (xdg.environmental);
2169 const gchar* home = getenv ("HOME");
2171 gchar* return_value = str_replace ("~", home, actual_value);
2173 if (! actual_value || strcmp (actual_value, "") == 0) {
2174 if (xdg.default_value) {
2175 return_value = str_replace ("~", home, xdg.default_value);
2177 return_value = NULL;
2180 return return_value;
2184 find_xdg_file (int xdg_type, char* filename) {
2185 /* xdg_type = 0 => config
2186 xdg_type = 1 => data
2187 xdg_type = 2 => cache*/
2189 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2190 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2193 gchar* temporary_string;
2197 if (! file_exists (temporary_file) && xdg_type != 2) {
2198 buf = get_xdg_var (XDG[3 + xdg_type]);
2199 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2202 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2203 g_free (temporary_file);
2204 temporary_file = g_strconcat (temporary_string, filename, NULL);
2208 //g_free (temporary_string); - segfaults.
2210 if (file_exists (temporary_file)) {
2211 return temporary_file;
2218 State *s = &uzbl.state;
2219 Network *n = &uzbl.net;
2221 for (i = 0; default_config[i].command != NULL; i++) {
2222 parse_cmd_line(default_config[i].command);
2225 if (!s->config_file) {
2226 s->config_file = find_xdg_file (0, "/uzbl/config");
2229 if (s->config_file) {
2230 GArray* lines = read_file_by_line (s->config_file);
2234 while ((line = g_array_index(lines, gchar*, i))) {
2235 parse_cmd_line (line);
2239 g_array_free (lines, TRUE);
2241 if (uzbl.state.verbose)
2242 printf ("No configuration file loaded.\n");
2245 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2248 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2251 if (!uzbl.behave.cookie_handler)
2254 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2255 GString *s = g_string_new ("");
2256 SoupURI * soup_uri = soup_message_get_uri(msg);
2257 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2258 run_handler(uzbl.behave.cookie_handler, s->str);
2260 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2261 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2262 if ( p != NULL ) *p = '\0';
2263 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2265 if (uzbl.comm.sync_stdout)
2266 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2268 g_string_free(s, TRUE);
2272 save_cookies (SoupMessage *msg, gpointer user_data){
2276 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2277 cookie = soup_cookie_to_set_cookie_header(ck->data);
2278 SoupURI * soup_uri = soup_message_get_uri(msg);
2279 GString *s = g_string_new ("");
2280 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2281 run_handler(uzbl.behave.cookie_handler, s->str);
2283 g_string_free(s, TRUE);
2288 /* --- WEBINSPECTOR --- */
2290 hide_window_cb(GtkWidget *widget, gpointer data) {
2293 gtk_widget_hide(widget);
2296 static WebKitWebView*
2297 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2300 (void) web_inspector;
2301 GtkWidget* scrolled_window;
2302 GtkWidget* new_web_view;
2305 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2306 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2307 G_CALLBACK(hide_window_cb), NULL);
2309 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2310 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2311 gtk_widget_show(g->inspector_window);
2313 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2314 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2315 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2316 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2317 gtk_widget_show(scrolled_window);
2319 new_web_view = webkit_web_view_new();
2320 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2322 return WEBKIT_WEB_VIEW(new_web_view);
2326 inspector_show_window_cb (WebKitWebInspector* inspector){
2328 gtk_widget_show(uzbl.gui.inspector_window);
2332 /* TODO: Add variables and code to make use of these functions */
2334 inspector_close_window_cb (WebKitWebInspector* inspector){
2340 inspector_attach_window_cb (WebKitWebInspector* inspector){
2346 inspector_dettach_window_cb (WebKitWebInspector* inspector){
2352 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2358 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2364 set_up_inspector() {
2366 WebKitWebSettings *settings = view_settings();
2367 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2369 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2370 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2371 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2372 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2373 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2374 g_signal_connect (G_OBJECT (g->inspector), "dettach-window", G_CALLBACK (inspector_dettach_window_cb), NULL);
2375 g_signal_connect (G_OBJECT (g->inspector), "destroy", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2377 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2381 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2383 uzbl_cmdprop *c = v;
2388 if(c->type == TYPE_STR)
2389 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2390 else if(c->type == TYPE_INT)
2391 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2395 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2399 printf("bind %s = %s %s\n", (char *)k ,
2400 (char *)a->name, a->param?(char *)a->param:"");
2405 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2406 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2411 main (int argc, char* argv[]) {
2412 gtk_init (&argc, &argv);
2413 if (!g_thread_supported ())
2414 g_thread_init (NULL);
2415 uzbl.state.executable_path = g_strdup(argv[0]);
2416 uzbl.state.selected_url = NULL;
2417 uzbl.state.searchtx = NULL;
2419 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2420 g_option_context_add_main_entries (context, entries, NULL);
2421 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2422 g_option_context_parse (context, &argc, &argv, NULL);
2423 g_option_context_free(context);
2425 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2426 gboolean verbose_override = uzbl.state.verbose;
2428 /* initialize hash table */
2429 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2431 uzbl.net.soup_session = webkit_get_default_session();
2432 uzbl.state.keycmd = g_string_new("");
2434 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2435 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2436 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2437 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2438 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2439 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2442 if(uname(&uzbl.state.unameinfo) == -1)
2443 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2445 uzbl.gui.sbar.progress_s = g_strdup("=");
2446 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2447 uzbl.gui.sbar.progress_w = 10;
2449 /* HTML mode defaults*/
2450 uzbl.behave.html_buffer = g_string_new("");
2451 uzbl.behave.html_endmarker = g_strdup(".");
2452 uzbl.behave.html_timeout = 60;
2453 uzbl.behave.base_url = g_strdup("http://invalid");
2455 /* default mode indicators */
2456 uzbl.behave.insert_indicator = g_strdup("I");
2457 uzbl.behave.cmd_indicator = g_strdup("C");
2461 make_var_to_name_hash();
2463 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2465 uzbl.gui.scrolled_win = create_browser();
2468 /* initial packing */
2469 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2470 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2472 uzbl.gui.main_window = create_window ();
2473 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2476 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2477 gtk_widget_show_all (uzbl.gui.main_window);
2478 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2480 if (uzbl.state.verbose) {
2481 printf("Uzbl start location: %s\n", argv[0]);
2482 printf("window_id %i\n",(int) uzbl.xwin);
2483 printf("pid %i\n", getpid ());
2484 printf("name: %s\n", uzbl.state.instance_name);
2487 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2488 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2489 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2490 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2491 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2495 if (!uzbl.behave.show_status)
2496 gtk_widget_hide(uzbl.gui.mainbar);
2505 if (verbose_override > uzbl.state.verbose)
2506 uzbl.state.verbose = verbose_override;
2509 set_var_value("uri", uri_override);
2510 g_free(uri_override);
2511 } else if (uzbl.state.uri)
2512 cmd_load_uri(uzbl.gui.web_view, NULL);
2517 return EXIT_SUCCESS;
2520 /* vi: set et ts=4: */