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
39 #include <gdk/gdkkeysyms.h>
40 #include <sys/socket.h>
42 #include <sys/types.h>
44 #include <sys/utsname.h>
46 #include <webkit/webkit.h>
47 #include <libsoup/soup.h>
60 typedef void (*Command)(WebKitWebView*, GArray *argv);
64 /* commandline arguments (set initial values for the state variables) */
66 GOptionEntry entries[] =
68 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,
69 "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
70 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose,
71 "Whether to print all messages or just errors.", NULL },
72 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name,
73 "Name of the current instance (defaults to Xorg window id)", "NAME" },
74 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,
75 "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
76 { "socket", 's', 0, G_OPTION_ARG_INT, &uzbl.state.socket_id,
77 "Socket ID", "SOCKET" },
78 { NULL, 0, 0, 0, NULL, NULL, NULL }
81 /* associate command names to their properties */
82 typedef const struct {
89 enum {TYPE_INT, TYPE_STR, TYPE_FLOAT};
91 /* an abbreviation to help keep the table's width humane */
92 #define PTR(var, t, d, fun) { .ptr = (void*)&(var), .type = TYPE_##t, .dump = d, .func = fun }
97 } var_name_to_ptr[] = {
98 /* variable name pointer to variable in code type dump callback function */
99 /* --------------------------------------------------------------------------------------- */
100 { "uri", PTR(uzbl.state.uri, STR, 1, cmd_load_uri)},
101 { "verbose", PTR(uzbl.state.verbose, INT, 1, NULL)},
102 { "mode", PTR(uzbl.behave.mode, INT, 0, NULL)},
103 { "inject_html", PTR(uzbl.behave.inject_html, STR, 0, cmd_inject_html)},
104 { "base_url", PTR(uzbl.behave.base_url, STR, 1, NULL)},
105 { "html_endmarker", PTR(uzbl.behave.html_endmarker, STR, 1, NULL)},
106 { "html_mode_timeout", PTR(uzbl.behave.html_timeout, INT, 1, NULL)},
107 { "status_message", PTR(uzbl.gui.sbar.msg, STR, 1, update_title)},
108 { "show_status", PTR(uzbl.behave.show_status, INT, 1, cmd_set_status)},
109 { "status_top", PTR(uzbl.behave.status_top, INT, 1, move_statusbar)},
110 { "status_format", PTR(uzbl.behave.status_format, STR, 1, update_title)},
111 { "status_pbar_done", PTR(uzbl.gui.sbar.progress_s, STR, 1, update_title)},
112 { "status_pbar_pending", PTR(uzbl.gui.sbar.progress_u, STR, 1, update_title)},
113 { "status_pbar_width", PTR(uzbl.gui.sbar.progress_w, INT, 1, update_title)},
114 { "status_background", PTR(uzbl.behave.status_background, STR, 1, update_title)},
115 { "insert_indicator", PTR(uzbl.behave.insert_indicator, STR, 1, update_title)},
116 { "command_indicator", PTR(uzbl.behave.cmd_indicator, STR, 1, update_title)},
117 { "title_format_long", PTR(uzbl.behave.title_format_long, STR, 1, update_title)},
118 { "title_format_short", PTR(uzbl.behave.title_format_short, STR, 1, update_title)},
119 { "icon", PTR(uzbl.gui.icon, STR, 1, set_icon)},
120 { "insert_mode", PTR(uzbl.behave.insert_mode, INT, 1, NULL)},
121 { "always_insert_mode", PTR(uzbl.behave.always_insert_mode, INT, 1, cmd_always_insert_mode)},
122 { "reset_command_mode", PTR(uzbl.behave.reset_command_mode, INT, 1, NULL)},
123 { "modkey", PTR(uzbl.behave.modkey, STR, 1, cmd_modkey)},
124 { "load_finish_handler", PTR(uzbl.behave.load_finish_handler, STR, 1, NULL)},
125 { "load_start_handler", PTR(uzbl.behave.load_start_handler, STR, 1, NULL)},
126 { "load_commit_handler", PTR(uzbl.behave.load_commit_handler, STR, 1, NULL)},
127 { "history_handler", PTR(uzbl.behave.history_handler, STR, 1, NULL)},
128 { "download_handler", PTR(uzbl.behave.download_handler, STR, 1, NULL)},
129 { "cookie_handler", PTR(uzbl.behave.cookie_handler, STR, 1, cmd_cookie_handler)},
130 { "fifo_dir", PTR(uzbl.behave.fifo_dir, STR, 1, cmd_fifo_dir)},
131 { "socket_dir", PTR(uzbl.behave.socket_dir, STR, 1, cmd_socket_dir)},
132 { "http_debug", PTR(uzbl.behave.http_debug, INT, 1, cmd_http_debug)},
133 { "shell_cmd", PTR(uzbl.behave.shell_cmd, STR, 1, NULL)},
134 { "proxy_url", PTR(uzbl.net.proxy_url, STR, 1, set_proxy_url)},
135 { "max_conns", PTR(uzbl.net.max_conns, INT, 1, cmd_max_conns)},
136 { "max_conns_host", PTR(uzbl.net.max_conns_host, INT, 1, cmd_max_conns_host)},
137 { "useragent", PTR(uzbl.net.useragent, STR, 1, cmd_useragent)},
138 /* exported WebKitWebSettings properties */
139 { "zoom_level", PTR(uzbl.behave.zoom_level, FLOAT,1, cmd_zoom_level)},
140 { "font_size", PTR(uzbl.behave.font_size, INT, 1, cmd_font_size)},
141 { "monospace_size", PTR(uzbl.behave.monospace_size, INT, 1, cmd_font_size)},
142 { "minimum_font_size", PTR(uzbl.behave.minimum_font_size, INT, 1, cmd_minimum_font_size)},
143 { "disable_plugins", PTR(uzbl.behave.disable_plugins, INT, 1, cmd_disable_plugins)},
144 { "disable_scripts", PTR(uzbl.behave.disable_scripts, INT, 1, cmd_disable_scripts)},
145 { "autoload_images", PTR(uzbl.behave.autoload_img, INT, 1, cmd_autoload_img)},
146 { "autoshrink_images", PTR(uzbl.behave.autoshrink_img, INT, 1, cmd_autoshrink_img)},
147 { "enable_spellcheck", PTR(uzbl.behave.enable_spellcheck, INT, 1, cmd_enable_spellcheck)},
148 { "enable_private", PTR(uzbl.behave.enable_private, INT, 1, cmd_enable_private)},
149 { "print_backgrounds", PTR(uzbl.behave.print_bg, INT, 1, cmd_print_bg)},
150 { "stylesheet_uri", PTR(uzbl.behave.style_uri, STR, 1, cmd_style_uri)},
151 { "resizable_text_areas",PTR(uzbl.behave.resizable_txt, INT, 1, cmd_resizable_txt)},
152 { "default_encoding", PTR(uzbl.behave.default_encoding, STR, 1, cmd_default_encoding)},
153 { "enforce_96_dpi", PTR(uzbl.behave.enforce_96dpi, INT, 1, cmd_enforce_96dpi)},
154 { "caret_browsing", PTR(uzbl.behave.caret_browsing, INT, 1, cmd_caret_browsing)},
156 { NULL, {.ptr = NULL, .type = TYPE_INT, .dump = 0, .func = NULL}}
157 }, *n2v_p = var_name_to_ptr;
163 { "SHIFT", GDK_SHIFT_MASK }, // shift
164 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
165 { "CONTROL", GDK_CONTROL_MASK }, // control
166 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
167 { "MOD2", GDK_MOD2_MASK }, // 5th mod
168 { "MOD3", GDK_MOD3_MASK }, // 6th mod
169 { "MOD4", GDK_MOD4_MASK }, // 7th mod
170 { "MOD5", GDK_MOD5_MASK }, // 8th mod
171 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
172 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
173 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
174 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
175 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
176 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
177 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
178 { "META", GDK_META_MASK }, // meta (since 2.10)
183 /* construct a hash from the var_name_to_ptr array for quick access */
185 make_var_to_name_hash() {
186 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
188 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, (gpointer) &n2v_p->cp);
193 /* --- UTILITY FUNCTIONS --- */
195 expand_vars(char *s) {
198 char ret[256], *vend;
199 GString *buf = g_string_new("");
204 g_string_append_c(buf, *++s);
212 if( (vend = strchr(s, upto)) ||
213 (vend = strchr(s, '\0')) ) {
214 strncpy(ret, s, vend-s);
216 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
217 if(c->type == TYPE_STR)
218 g_string_append(buf, (gchar *)*c->ptr);
219 else if(c->type == TYPE_INT) {
220 char *b = itos((int)*c->ptr);
221 g_string_append(buf, b);
225 if(upto == ' ') s = vend;
231 g_string_append_c(buf, *s);
236 return g_string_free(buf, FALSE);
243 snprintf(tmp, sizeof(tmp), "%i", val);
244 return g_strdup(tmp);
248 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
251 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
254 str_replace (const char* search, const char* replace, const char* string) {
258 buf = g_strsplit (string, search, -1);
259 ret = g_strjoinv (replace, buf);
260 g_strfreev(buf); // somebody said this segfaults
266 read_file_by_line (gchar *path) {
267 GIOChannel *chan = NULL;
268 gchar *readbuf = NULL;
270 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
273 chan = g_io_channel_new_file(path, "r", NULL);
276 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
277 const gchar* val = g_strdup (readbuf);
278 g_array_append_val (lines, val);
283 g_io_channel_unref (chan);
285 fprintf(stderr, "File '%s' not be read.\n", path);
292 gchar* parseenv (char* string) {
293 extern char** environ;
294 gchar* tmpstr = NULL;
298 while (environ[i] != NULL) {
299 gchar** env = g_strsplit (environ[i], "=", 2);
300 gchar* envname = g_strconcat ("$", env[0], NULL);
302 if (g_strrstr (string, envname) != NULL) {
303 tmpstr = g_strdup(string);
305 string = str_replace(envname, env[1], tmpstr);
310 g_strfreev (env); // somebody said this breaks uzbl
318 setup_signal(int signr, sigfunc *shandler) {
319 struct sigaction nh, oh;
321 nh.sa_handler = shandler;
322 sigemptyset(&nh.sa_mask);
325 if(sigaction(signr, &nh, &oh) < 0)
333 if (uzbl.behave.fifo_dir)
334 unlink (uzbl.comm.fifo_path);
335 if (uzbl.behave.socket_dir)
336 unlink (uzbl.comm.socket_path);
338 g_free(uzbl.state.executable_path);
339 g_string_free(uzbl.state.keycmd, TRUE);
340 g_hash_table_destroy(uzbl.bindings);
341 g_hash_table_destroy(uzbl.behave.commands);
344 /* used for html_mode_timeout
345 * be sure to extend this function to use
346 * more timers if needed in other places
349 set_timeout(int seconds) {
351 memset(&t, 0, sizeof t);
353 t.it_value.tv_sec = seconds;
354 t.it_value.tv_usec = 0;
355 setitimer(ITIMER_REAL, &t, NULL);
358 /* --- SIGNAL HANDLER --- */
361 catch_sigterm(int s) {
367 catch_sigint(int s) {
377 set_var_value("mode", "0");
382 /* --- CALLBACKS --- */
385 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
388 (void) navigation_action;
389 (void) policy_decision;
391 const gchar* uri = webkit_network_request_get_uri (request);
392 if (uzbl.state.verbose)
393 printf("New window requested -> %s \n", uri);
394 new_window_load_uri(uri);
399 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
404 /* If we can display it, let's display it... */
405 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
406 webkit_web_policy_decision_use (policy_decision);
410 /* ...everything we can't displayed is downloaded */
411 webkit_web_policy_decision_download (policy_decision);
416 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
420 if (uzbl.state.selected_url != NULL) {
421 if (uzbl.state.verbose)
422 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
423 new_window_load_uri(uzbl.state.selected_url);
425 if (uzbl.state.verbose)
426 printf("New web view -> %s\n","Nothing to open, exiting");
432 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
435 if (uzbl.behave.download_handler) {
436 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
437 if (uzbl.state.verbose)
438 printf("Download -> %s\n",uri);
439 /* if urls not escaped, we may have to escape and quote uri before this call */
440 run_handler(uzbl.behave.download_handler, uri);
445 /* scroll a bar in a given direction */
447 scroll (GtkAdjustment* bar, GArray *argv) {
451 gdouble page_size = gtk_adjustment_get_page_size(bar);
452 gdouble value = gtk_adjustment_get_value(bar);
453 gdouble amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
456 value += page_size * amount * 0.01;
460 max_value = gtk_adjustment_get_upper(bar) - page_size;
462 if (value > max_value)
463 value = max_value; /* don't scroll past the end of the page */
465 gtk_adjustment_set_value (bar, value);
469 scroll_begin(WebKitWebView* page, GArray *argv) {
470 (void) page; (void) argv;
471 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
475 scroll_end(WebKitWebView* page, GArray *argv) {
476 (void) page; (void) argv;
477 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
478 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
482 scroll_vert(WebKitWebView* page, GArray *argv) {
484 scroll(uzbl.gui.bar_v, argv);
488 scroll_horz(WebKitWebView* page, GArray *argv) {
490 scroll(uzbl.gui.bar_h, argv);
495 if (!uzbl.behave.show_status) {
496 gtk_widget_hide(uzbl.gui.mainbar);
498 gtk_widget_show(uzbl.gui.mainbar);
504 toggle_zoom_type (WebKitWebView* page, GArray *argv) {
508 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
512 toggle_status_cb (WebKitWebView* page, GArray *argv) {
516 if (uzbl.behave.show_status) {
517 gtk_widget_hide(uzbl.gui.mainbar);
519 gtk_widget_show(uzbl.gui.mainbar);
521 uzbl.behave.show_status = !uzbl.behave.show_status;
526 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
530 //Set selected_url state variable
531 g_free(uzbl.state.selected_url);
532 uzbl.state.selected_url = NULL;
534 uzbl.state.selected_url = g_strdup(link);
540 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
544 if (uzbl.gui.main_title)
545 g_free (uzbl.gui.main_title);
546 uzbl.gui.main_title = g_strdup (title);
551 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
554 uzbl.gui.sbar.load_progress = progress;
559 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
563 if (uzbl.behave.load_finish_handler)
564 run_handler(uzbl.behave.load_finish_handler, "");
568 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
572 uzbl.gui.sbar.load_progress = 0;
573 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
574 if (uzbl.behave.load_start_handler)
575 run_handler(uzbl.behave.load_start_handler, "");
579 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
582 g_free (uzbl.state.uri);
583 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
584 uzbl.state.uri = g_string_free (newuri, FALSE);
585 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
586 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
589 if (uzbl.behave.load_commit_handler)
590 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
594 destroy_cb (GtkWidget* widget, gpointer data) {
602 if (uzbl.behave.history_handler) {
604 struct tm * timeinfo;
607 timeinfo = localtime ( &rawtime );
608 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
609 run_handler(uzbl.behave.history_handler, date);
614 /* VIEW funcs (little webkit wrappers) */
615 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
617 VIEWFUNC(reload_bypass_cache)
618 VIEWFUNC(stop_loading)
625 /* -- command to callback/function map for things we cannot attach to any signals */
626 static struct {char *name; Command command[2];} cmdlist[] =
627 { /* key function no_split */
628 { "back", {view_go_back, 0} },
629 { "forward", {view_go_forward, 0} },
630 { "scroll_vert", {scroll_vert, 0} },
631 { "scroll_horz", {scroll_horz, 0} },
632 { "scroll_begin", {scroll_begin, 0} },
633 { "scroll_end", {scroll_end, 0} },
634 { "reload", {view_reload, 0}, },
635 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
636 { "stop", {view_stop_loading, 0}, },
637 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
638 { "zoom_out", {view_zoom_out, 0}, },
639 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
640 { "uri", {load_uri, NOSPLIT} },
641 { "js", {run_js, NOSPLIT} },
642 { "script", {run_external_js, 0} },
643 { "toggle_status", {toggle_status_cb, 0} },
644 { "spawn", {spawn, 0} },
645 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
646 { "sh", {spawn_sh, 0} },
647 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
648 { "exit", {close_uzbl, 0} },
649 { "search", {search_forward_text, NOSPLIT} },
650 { "search_reverse", {search_reverse_text, NOSPLIT} },
651 { "dehilight", {dehilight, 0} },
652 { "toggle_insert_mode", {toggle_insert_mode, 0} },
653 { "set", {set_var, NOSPLIT} },
654 //{ "get", {get_var, NOSPLIT} },
655 { "bind", {act_bind, NOSPLIT} },
656 { "dump_config", {act_dump_config, 0} },
657 { "keycmd", {keycmd, NOSPLIT} },
658 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
659 { "keycmd_bs", {keycmd_bs, 0} },
660 { "chain", {chain, 0} },
661 { "print", {print, NOSPLIT} }
668 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
670 for (i = 0; i < LENGTH(cmdlist); i++)
671 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
674 /* -- CORE FUNCTIONS -- */
677 free_action(gpointer act) {
678 Action *action = (Action*)act;
679 g_free(action->name);
681 g_free(action->param);
686 new_action(const gchar *name, const gchar *param) {
687 Action *action = g_new(Action, 1);
689 action->name = g_strdup(name);
691 action->param = g_strdup(param);
693 action->param = NULL;
699 file_exists (const char * filename) {
700 return (access(filename, F_OK) == 0);
704 set_var(WebKitWebView *page, GArray *argv) {
706 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
707 if (split[0] != NULL) {
708 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
709 set_var_value(g_strstrip(split[0]), value);
716 print(WebKitWebView *page, GArray *argv) {
720 buf = expand_vars(argv_idx(argv, 0));
726 act_bind(WebKitWebView *page, GArray *argv) {
728 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
729 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
730 add_binding(g_strstrip(split[0]), value);
742 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
745 if (argv_idx(argv, 0)) {
746 if (strcmp (argv_idx(argv, 0), "0") == 0) {
747 uzbl.behave.insert_mode = FALSE;
749 uzbl.behave.insert_mode = TRUE;
752 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
759 load_uri (WebKitWebView *web_view, GArray *argv) {
760 if (argv_idx(argv, 0)) {
761 GString* newuri = g_string_new (argv_idx(argv, 0));
762 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
763 run_js(web_view, argv);
766 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
767 g_string_prepend (newuri, "http://");
768 /* if we do handle cookies, ask our handler for them */
769 webkit_web_view_load_uri (web_view, newuri->str);
770 g_string_free (newuri, TRUE);
775 run_js (WebKitWebView * web_view, GArray *argv) {
776 if (argv_idx(argv, 0))
777 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
781 run_external_js (WebKitWebView * web_view, GArray *argv) {
782 if (argv_idx(argv, 0)) {
783 GArray* lines = read_file_by_line (argv_idx (argv, 0));
788 while ((line = g_array_index(lines, gchar*, i))) {
790 js = g_strdup (line);
792 gchar* newjs = g_strconcat (js, line, NULL);
799 if (uzbl.state.verbose)
800 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
802 if (argv_idx (argv, 1)) {
803 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
807 webkit_web_view_execute_script (web_view, js);
809 g_array_free (lines, TRUE);
814 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
815 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
816 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
817 webkit_web_view_unmark_text_matches (page);
818 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
819 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
823 if (uzbl.state.searchtx) {
824 if (uzbl.state.verbose)
825 printf ("Searching: %s\n", uzbl.state.searchtx);
826 webkit_web_view_set_highlight_text_matches (page, TRUE);
827 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
832 search_forward_text (WebKitWebView *page, GArray *argv) {
833 search_text(page, argv, TRUE);
837 search_reverse_text (WebKitWebView *page, GArray *argv) {
838 search_text(page, argv, FALSE);
842 dehilight (WebKitWebView *page, GArray *argv) {
844 webkit_web_view_set_highlight_text_matches (page, FALSE);
849 new_window_load_uri (const gchar * uri) {
850 GString* to_execute = g_string_new ("");
851 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
853 for (i = 0; entries[i].long_name != NULL; i++) {
854 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
855 gchar** str = (gchar**)entries[i].arg_data;
857 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
861 if (uzbl.state.verbose)
862 printf("\n%s\n", to_execute->str);
863 g_spawn_command_line_async (to_execute->str, NULL);
864 g_string_free (to_execute, TRUE);
868 chain (WebKitWebView *page, GArray *argv) {
871 gchar **parts = NULL;
873 while ((a = argv_idx(argv, i++))) {
874 parts = g_strsplit (a, " ", 2);
875 parse_command(parts[0], parts[1]);
881 keycmd (WebKitWebView *page, GArray *argv) {
884 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
890 keycmd_nl (WebKitWebView *page, GArray *argv) {
893 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
899 keycmd_bs (WebKitWebView *page, GArray *argv) {
903 prev = g_utf8_find_prev_char(uzbl.state.keycmd->str, uzbl.state.keycmd->str + uzbl.state.keycmd->len);
905 g_string_truncate(uzbl.state.keycmd, prev - uzbl.state.keycmd->str);
910 close_uzbl (WebKitWebView *page, GArray *argv) {
916 /* --Statusbar functions-- */
918 build_progressbar_ascii(int percent) {
919 int width=uzbl.gui.sbar.progress_w;
922 GString *bar = g_string_new("");
924 l = (double)percent*((double)width/100.);
925 l = (int)(l+.5)>=(int)l ? l+.5 : l;
927 for(i=0; i<(int)l; i++)
928 g_string_append(bar, uzbl.gui.sbar.progress_s);
931 g_string_append(bar, uzbl.gui.sbar.progress_u);
933 return g_string_free(bar, FALSE);
938 const GScannerConfig scan_config = {
941 ) /* cset_skip_characters */,
946 ) /* cset_identifier_first */,
953 ) /* cset_identifier_nth */,
954 ( "" ) /* cpair_comment_single */,
956 TRUE /* case_sensitive */,
958 FALSE /* skip_comment_multi */,
959 FALSE /* skip_comment_single */,
960 FALSE /* scan_comment_multi */,
961 TRUE /* scan_identifier */,
962 TRUE /* scan_identifier_1char */,
963 FALSE /* scan_identifier_NULL */,
964 TRUE /* scan_symbols */,
965 FALSE /* scan_binary */,
966 FALSE /* scan_octal */,
967 FALSE /* scan_float */,
968 FALSE /* scan_hex */,
969 FALSE /* scan_hex_dollar */,
970 FALSE /* scan_string_sq */,
971 FALSE /* scan_string_dq */,
972 TRUE /* numbers_2_int */,
973 FALSE /* int_2_float */,
974 FALSE /* identifier_2_string */,
975 FALSE /* char_2_token */,
976 FALSE /* symbol_2_token */,
977 TRUE /* scope_0_fallback */,
982 uzbl.scan = g_scanner_new(&scan_config);
983 while(symp->symbol_name) {
984 g_scanner_scope_add_symbol(uzbl.scan, 0,
986 GINT_TO_POINTER(symp->symbol_token));
992 expand_template(const char *template, gboolean escape_markup) {
993 if(!template) return NULL;
995 GTokenType token = G_TOKEN_NONE;
996 GString *ret = g_string_new("");
1000 g_scanner_input_text(uzbl.scan, template, strlen(template));
1001 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
1002 token = g_scanner_get_next_token(uzbl.scan);
1004 if(token == G_TOKEN_SYMBOL) {
1005 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
1009 buf = uzbl.state.uri?
1010 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
1011 g_string_append(ret, buf);
1015 g_string_append(ret, uzbl.state.uri?
1016 uzbl.state.uri:g_strdup(""));
1019 buf = itos(uzbl.gui.sbar.load_progress);
1020 g_string_append(ret, buf);
1023 case SYM_LOADPRGSBAR:
1024 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1025 g_string_append(ret, buf);
1030 buf = uzbl.gui.main_title?
1031 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1032 g_string_append(ret, buf);
1036 g_string_append(ret, uzbl.gui.main_title?
1037 uzbl.gui.main_title:g_strdup(""));
1039 case SYM_SELECTED_URI:
1041 buf = uzbl.state.selected_url?
1042 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1043 g_string_append(ret, buf);
1047 g_string_append(ret, uzbl.state.selected_url?
1048 uzbl.state.selected_url:g_strdup(""));
1051 buf = itos(uzbl.xwin);
1052 g_string_append(ret,
1053 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1058 buf = uzbl.state.keycmd->str?
1059 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1060 g_string_append(ret, buf);
1064 g_string_append(ret, uzbl.state.keycmd->str?
1065 uzbl.state.keycmd->str:g_strdup(""));
1068 g_string_append(ret,
1069 uzbl.behave.insert_mode?
1070 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1073 g_string_append(ret,
1074 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1076 /* useragent syms */
1078 buf = itos(WEBKIT_MAJOR_VERSION);
1079 g_string_append(ret, buf);
1083 buf = itos(WEBKIT_MINOR_VERSION);
1084 g_string_append(ret, buf);
1088 buf = itos(WEBKIT_MICRO_VERSION);
1089 g_string_append(ret, buf);
1093 g_string_append(ret, uzbl.state.unameinfo.sysname);
1096 g_string_append(ret, uzbl.state.unameinfo.nodename);
1099 g_string_append(ret, uzbl.state.unameinfo.release);
1102 g_string_append(ret, uzbl.state.unameinfo.version);
1105 g_string_append(ret, uzbl.state.unameinfo.machine);
1108 g_string_append(ret, ARCH);
1111 case SYM_DOMAINNAME:
1112 g_string_append(ret, uzbl.state.unameinfo.domainname);
1116 g_string_append(ret, COMMIT);
1122 else if(token == G_TOKEN_INT) {
1123 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1124 g_string_append(ret, buf);
1127 else if(token == G_TOKEN_IDENTIFIER) {
1128 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1130 else if(token == G_TOKEN_CHAR) {
1131 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1135 return g_string_free(ret, FALSE);
1137 /* --End Statusbar functions-- */
1140 sharg_append(GArray *a, const gchar *str) {
1141 const gchar *s = (str ? str : "");
1142 g_array_append_val(a, s);
1145 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1147 run_command (const gchar *command, const guint npre, const gchar **args,
1148 const gboolean sync, char **output_stdout) {
1149 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1152 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1153 gchar *pid = itos(getpid());
1154 gchar *xwin = itos(uzbl.xwin);
1156 sharg_append(a, command);
1157 for (i = 0; i < npre; i++) /* add n args before the default vars */
1158 sharg_append(a, args[i]);
1159 sharg_append(a, uzbl.state.config_file);
1160 sharg_append(a, pid);
1161 sharg_append(a, xwin);
1162 sharg_append(a, uzbl.comm.fifo_path);
1163 sharg_append(a, uzbl.comm.socket_path);
1164 sharg_append(a, uzbl.state.uri);
1165 sharg_append(a, uzbl.gui.main_title);
1167 for (i = npre; i < g_strv_length((gchar**)args); i++)
1168 sharg_append(a, args[i]);
1172 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1174 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1175 NULL, NULL, output_stdout, NULL, NULL, &err);
1176 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1177 NULL, NULL, NULL, &err);
1179 if (uzbl.state.verbose) {
1180 GString *s = g_string_new("spawned:");
1181 for (i = 0; i < (a->len); i++) {
1182 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1183 g_string_append_printf(s, " %s", qarg);
1186 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1187 printf("%s\n", s->str);
1188 g_string_free(s, TRUE);
1190 printf("Stdout: %s\n", *output_stdout);
1194 g_printerr("error on run_command: %s\n", err->message);
1199 g_array_free (a, TRUE);
1204 split_quoted(const gchar* src, const gboolean unquote) {
1205 /* split on unquoted space, return array of strings;
1206 remove a layer of quotes and backslashes if unquote */
1207 if (!src) return NULL;
1209 gboolean dq = FALSE;
1210 gboolean sq = FALSE;
1211 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1212 GString *s = g_string_new ("");
1216 for (p = src; *p != '\0'; p++) {
1217 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1218 else if (*p == '\\') { g_string_append_c(s, *p++);
1219 g_string_append_c(s, *p); }
1220 else if ((*p == '"') && unquote && !sq) dq = !dq;
1221 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1223 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1224 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1226 else if ((*p == ' ') && !dq && !sq) {
1227 dup = g_strdup(s->str);
1228 g_array_append_val(a, dup);
1229 g_string_truncate(s, 0);
1230 } else g_string_append_c(s, *p);
1232 dup = g_strdup(s->str);
1233 g_array_append_val(a, dup);
1234 ret = (gchar**)a->data;
1235 g_array_free (a, FALSE);
1236 g_string_free (s, TRUE);
1241 spawn(WebKitWebView *web_view, GArray *argv) {
1243 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1244 if (argv_idx(argv, 0))
1245 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1249 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1252 if (argv_idx(argv, 0))
1253 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1254 TRUE, &uzbl.comm.sync_stdout);
1258 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1260 if (!uzbl.behave.shell_cmd) {
1261 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1266 gchar *spacer = g_strdup("");
1267 g_array_insert_val(argv, 1, spacer);
1268 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1270 for (i = 1; i < g_strv_length(cmd); i++)
1271 g_array_prepend_val(argv, cmd[i]);
1273 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1279 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1281 if (!uzbl.behave.shell_cmd) {
1282 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1287 gchar *spacer = g_strdup("");
1288 g_array_insert_val(argv, 1, spacer);
1289 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1291 for (i = 1; i < g_strv_length(cmd); i++)
1292 g_array_prepend_val(argv, cmd[i]);
1294 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1295 TRUE, &uzbl.comm.sync_stdout);
1301 parse_command(const char *cmd, const char *param) {
1304 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1307 gchar **par = split_quoted(param, TRUE);
1308 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1310 if (c[1] == NOSPLIT) { /* don't split */
1311 sharg_append(a, param);
1313 for (i = 0; i < g_strv_length(par); i++)
1314 sharg_append(a, par[i]);
1316 c[0](uzbl.gui.web_view, a);
1318 g_array_free (a, TRUE);
1321 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1328 if(*uzbl.net.proxy_url == ' '
1329 || uzbl.net.proxy_url == NULL) {
1330 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1331 (GType) SOUP_SESSION_PROXY_URI);
1334 suri = soup_uri_new(uzbl.net.proxy_url);
1335 g_object_set(G_OBJECT(uzbl.net.soup_session),
1336 SOUP_SESSION_PROXY_URI,
1338 soup_uri_free(suri);
1345 if(file_exists(uzbl.gui.icon)) {
1346 if (uzbl.gui.main_window)
1347 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1349 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1351 g_free (uzbl.gui.icon);
1356 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1357 g_array_append_val (a, uzbl.state.uri);
1358 load_uri(uzbl.gui.web_view, a);
1359 g_array_free (a, TRUE);
1363 cmd_always_insert_mode() {
1364 uzbl.behave.insert_mode =
1365 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1371 g_object_set(G_OBJECT(uzbl.net.soup_session),
1372 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1376 cmd_max_conns_host() {
1377 g_object_set(G_OBJECT(uzbl.net.soup_session),
1378 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1383 soup_session_remove_feature
1384 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1385 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1386 /*g_free(uzbl.net.soup_logger);*/
1388 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1389 soup_session_add_feature(uzbl.net.soup_session,
1390 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1393 static WebKitWebSettings*
1395 return webkit_web_view_get_settings(uzbl.gui.web_view);
1400 WebKitWebSettings *ws = view_settings();
1401 if (uzbl.behave.font_size > 0) {
1402 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1405 if (uzbl.behave.monospace_size > 0) {
1406 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1407 uzbl.behave.monospace_size, NULL);
1409 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1410 uzbl.behave.font_size, NULL);
1416 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1420 cmd_disable_plugins() {
1421 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1422 !uzbl.behave.disable_plugins, NULL);
1426 cmd_disable_scripts() {
1427 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1428 !uzbl.behave.disable_scripts, NULL);
1432 cmd_minimum_font_size() {
1433 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1434 uzbl.behave.minimum_font_size, NULL);
1437 cmd_autoload_img() {
1438 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1439 uzbl.behave.autoload_img, NULL);
1444 cmd_autoshrink_img() {
1445 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1446 uzbl.behave.autoshrink_img, NULL);
1451 cmd_enable_spellcheck() {
1452 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1453 uzbl.behave.enable_spellcheck, NULL);
1457 cmd_enable_private() {
1458 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1459 uzbl.behave.enable_private, NULL);
1464 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1465 uzbl.behave.print_bg, NULL);
1470 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1471 uzbl.behave.style_uri, NULL);
1475 cmd_resizable_txt() {
1476 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1477 uzbl.behave.resizable_txt, NULL);
1481 cmd_default_encoding() {
1482 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1483 uzbl.behave.default_encoding, NULL);
1487 cmd_enforce_96dpi() {
1488 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1489 uzbl.behave.enforce_96dpi, NULL);
1493 cmd_caret_browsing() {
1494 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1495 uzbl.behave.caret_browsing, NULL);
1499 cmd_cookie_handler() {
1500 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1501 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1502 if ((g_strcmp0(split[0], "sh") == 0) ||
1503 (g_strcmp0(split[0], "spawn") == 0)) {
1504 g_free (uzbl.behave.cookie_handler);
1505 uzbl.behave.cookie_handler =
1506 g_strdup_printf("sync_%s %s", split[0], split[1]);
1513 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1518 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1523 if(uzbl.behave.inject_html) {
1524 webkit_web_view_load_html_string (uzbl.gui.web_view,
1525 uzbl.behave.inject_html, NULL);
1534 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1535 uzbl.behave.modmask = 0;
1537 if(uzbl.behave.modkey)
1538 g_free(uzbl.behave.modkey);
1539 uzbl.behave.modkey = buf;
1541 for (i = 0; modkeys[i].key != NULL; i++) {
1542 if (g_strrstr(buf, modkeys[i].key))
1543 uzbl.behave.modmask |= modkeys[i].mask;
1549 if (*uzbl.net.useragent == ' ') {
1550 g_free (uzbl.net.useragent);
1551 uzbl.net.useragent = NULL;
1553 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1555 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1556 g_free(uzbl.net.useragent);
1557 uzbl.net.useragent = ua;
1563 gtk_widget_ref(uzbl.gui.scrolled_win);
1564 gtk_widget_ref(uzbl.gui.mainbar);
1565 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1566 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1568 if(uzbl.behave.status_top) {
1569 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1570 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1573 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1574 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1576 gtk_widget_unref(uzbl.gui.scrolled_win);
1577 gtk_widget_unref(uzbl.gui.mainbar);
1578 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1583 set_var_value(gchar *name, gchar *val) {
1584 uzbl_cmdprop *c = NULL;
1588 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1589 /* check for the variable type */
1590 if (c->type == TYPE_STR) {
1591 buf = expand_vars(val);
1594 } else if(c->type == TYPE_INT) {
1595 int *ip = (int *)c->ptr;
1596 buf = expand_vars(val);
1597 *ip = (int)strtoul(buf, &endp, 10);
1599 } else if (c->type == TYPE_FLOAT) {
1600 float *fp = (float *)c->ptr;
1601 buf = expand_vars(val);
1602 *fp = strtod(buf, &endp);
1606 /* invoke a command specific function */
1607 if(c->func) c->func();
1614 Behaviour *b = &uzbl.behave;
1616 if(b->html_buffer->str) {
1617 webkit_web_view_load_html_string (uzbl.gui.web_view,
1618 b->html_buffer->str, b->base_url);
1619 g_string_free(b->html_buffer, TRUE);
1620 b->html_buffer = g_string_new("");
1624 enum {M_CMD, M_HTML};
1626 parse_cmd_line(const char *ctl_line) {
1627 Behaviour *b = &uzbl.behave;
1630 if(b->mode == M_HTML) {
1631 len = strlen(b->html_endmarker);
1632 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1633 if(len == strlen(ctl_line)-1 &&
1634 !strncmp(b->html_endmarker, ctl_line, len)) {
1636 set_var_value("mode", "0");
1641 set_timeout(b->html_timeout);
1642 g_string_append(b->html_buffer, ctl_line);
1645 else if((ctl_line[0] == '#') /* Comments */
1646 || (ctl_line[0] == ' ')
1647 || (ctl_line[0] == '\n'))
1648 ; /* ignore these lines */
1649 else { /* parse a command */
1651 gchar **tokens = NULL;
1652 len = strlen(ctl_line);
1654 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1655 ctlstrip = g_strndup(ctl_line, len - 1);
1656 else ctlstrip = g_strdup(ctl_line);
1658 tokens = g_strsplit(ctlstrip, " ", 2);
1659 parse_command(tokens[0], tokens[1]);
1666 build_stream_name(int type, const gchar* dir) {
1667 char *xwin_str = NULL;
1668 State *s = &uzbl.state;
1671 xwin_str = itos((int)uzbl.xwin);
1673 str = g_strdup_printf
1674 ("%s/uzbl_fifo_%s", dir,
1675 s->instance_name ? s->instance_name : xwin_str);
1676 } else if (type == SOCKET) {
1677 str = g_strdup_printf
1678 ("%s/uzbl_socket_%s", dir,
1679 s->instance_name ? s->instance_name : xwin_str );
1686 control_fifo(GIOChannel *gio, GIOCondition condition) {
1687 if (uzbl.state.verbose)
1688 printf("triggered\n");
1693 if (condition & G_IO_HUP)
1694 g_error ("Fifo: Read end of pipe died!\n");
1697 g_error ("Fifo: GIOChannel broke\n");
1699 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1700 if (ret == G_IO_STATUS_ERROR) {
1701 g_error ("Fifo: Error reading: %s\n", err->message);
1705 parse_cmd_line(ctl_line);
1712 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1713 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1714 if (unlink(uzbl.comm.fifo_path) == -1)
1715 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1716 g_free(uzbl.comm.fifo_path);
1717 uzbl.comm.fifo_path = NULL;
1720 if (*dir == ' ') { /* space unsets the variable */
1725 GIOChannel *chan = NULL;
1726 GError *error = NULL;
1727 gchar *path = build_stream_name(FIFO, dir);
1729 if (!file_exists(path)) {
1730 if (mkfifo (path, 0666) == 0) {
1731 // 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.
1732 chan = g_io_channel_new_file(path, "r+", &error);
1734 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1735 if (uzbl.state.verbose)
1736 printf ("init_fifo: created successfully as %s\n", path);
1737 uzbl.comm.fifo_path = path;
1739 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1740 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1741 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1742 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1744 /* if we got this far, there was an error; cleanup */
1745 if (error) g_error_free (error);
1752 control_stdin(GIOChannel *gio, GIOCondition condition) {
1754 gchar *ctl_line = NULL;
1757 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1758 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1761 parse_cmd_line(ctl_line);
1769 GIOChannel *chan = NULL;
1770 GError *error = NULL;
1772 chan = g_io_channel_unix_new(fileno(stdin));
1774 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1775 g_error ("Stdin: could not add watch\n");
1777 if (uzbl.state.verbose)
1778 printf ("Stdin: watch added successfully\n");
1781 g_error ("Stdin: Error while opening: %s\n", error->message);
1783 if (error) g_error_free (error);
1787 control_socket(GIOChannel *chan) {
1788 struct sockaddr_un remote;
1789 char buffer[512], *ctl_line;
1791 int sock, clientsock, n, done;
1794 sock = g_io_channel_unix_get_fd(chan);
1796 memset (buffer, 0, sizeof (buffer));
1798 t = sizeof (remote);
1799 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1803 memset (temp, 0, sizeof (temp));
1804 n = recv (clientsock, temp, 128, 0);
1806 buffer[strlen (buffer)] = '\0';
1810 strcat (buffer, temp);
1813 if (strcmp (buffer, "\n") < 0) {
1814 buffer[strlen (buffer) - 1] = '\0';
1816 buffer[strlen (buffer)] = '\0';
1819 ctl_line = g_strdup(buffer);
1820 parse_cmd_line (ctl_line);
1823 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1824 GError *error = NULL;
1827 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1828 if (ret == G_IO_STATUS_ERROR)
1829 g_error ("Error reading: %s\n", error->message);
1831 printf("Got line %s (%u bytes) \n",ctl_line, len);
1833 parse_line(ctl_line);
1841 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1842 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1843 if (unlink(uzbl.comm.socket_path) == -1)
1844 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1845 g_free(uzbl.comm.socket_path);
1846 uzbl.comm.socket_path = NULL;
1854 GIOChannel *chan = NULL;
1856 struct sockaddr_un local;
1857 gchar *path = build_stream_name(SOCKET, dir);
1859 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1861 local.sun_family = AF_UNIX;
1862 strcpy (local.sun_path, path);
1863 unlink (local.sun_path);
1865 len = strlen (local.sun_path) + sizeof (local.sun_family);
1866 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1867 if (uzbl.state.verbose)
1868 printf ("init_socket: opened in %s\n", path);
1871 if( (chan = g_io_channel_unix_new(sock)) ) {
1872 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1873 uzbl.comm.socket_path = path;
1876 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1878 /* if we got this far, there was an error; cleanup */
1885 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1886 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1888 // this function may be called very early when the templates are not set (yet), hence the checks
1890 update_title (void) {
1891 Behaviour *b = &uzbl.behave;
1894 if (b->show_status) {
1895 if (b->title_format_short) {
1896 parsed = expand_template(b->title_format_short, FALSE);
1897 if (uzbl.gui.main_window)
1898 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1901 if (b->status_format) {
1902 parsed = expand_template(b->status_format, TRUE);
1903 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1906 if (b->status_background) {
1908 gdk_color_parse (b->status_background, &color);
1909 //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)
1910 if (uzbl.gui.main_window)
1911 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1914 if (b->title_format_long) {
1915 parsed = expand_template(b->title_format_long, FALSE);
1916 if (uzbl.gui.main_window)
1917 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1924 key_press_cb (GtkWidget* window, GdkEventKey* event)
1926 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1930 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1931 || 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)
1934 /* turn off insert mode (if always_insert_mode is not used) */
1935 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1936 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1941 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1944 if (event->keyval == GDK_Escape) {
1945 g_string_truncate(uzbl.state.keycmd, 0);
1947 dehilight(uzbl.gui.web_view, NULL);
1951 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1952 if (event->keyval == GDK_Insert) {
1954 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1955 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1957 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1960 g_string_append (uzbl.state.keycmd, str);
1967 if (event->keyval == GDK_BackSpace)
1968 keycmd_bs(NULL, NULL);
1970 gboolean key_ret = FALSE;
1971 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1973 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1975 run_keycmd(key_ret);
1977 if (key_ret) return (!uzbl.behave.insert_mode);
1982 run_keycmd(const gboolean key_ret) {
1983 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1985 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1986 g_string_truncate(uzbl.state.keycmd, 0);
1987 parse_command(act->name, act->param);
1991 /* try if it's an incremental keycmd or one that takes args, and run it */
1992 GString* short_keys = g_string_new ("");
1993 GString* short_keys_inc = g_string_new ("");
1995 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1996 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1997 g_string_assign(short_keys_inc, short_keys->str);
1998 g_string_append_c(short_keys, '_');
1999 g_string_append_c(short_keys_inc, '*');
2001 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2002 /* run normal cmds only if return was pressed */
2003 exec_paramcmd(act, i);
2004 g_string_truncate(uzbl.state.keycmd, 0);
2006 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2007 if (key_ret) /* just quit the incremental command on return */
2008 g_string_truncate(uzbl.state.keycmd, 0);
2009 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2013 g_string_truncate(short_keys, short_keys->len - 1);
2015 g_string_free (short_keys, TRUE);
2016 g_string_free (short_keys_inc, TRUE);
2020 exec_paramcmd(const Action *act, const guint i) {
2021 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2022 GString *actionname = g_string_new ("");
2023 GString *actionparam = g_string_new ("");
2024 g_string_erase (parampart, 0, i+1);
2026 g_string_printf (actionname, act->name, parampart->str);
2028 g_string_printf (actionparam, act->param, parampart->str);
2029 parse_command(actionname->str, actionparam->str);
2030 g_string_free(actionname, TRUE);
2031 g_string_free(actionparam, TRUE);
2032 g_string_free(parampart, TRUE);
2040 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2041 //main_window_ref = g_object_ref(scrolled_window);
2042 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
2044 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2045 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2047 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2048 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2049 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2050 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2051 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2052 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2053 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2054 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2055 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2056 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2057 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2059 return scrolled_window;
2066 g->mainbar = gtk_hbox_new (FALSE, 0);
2068 /* keep a reference to the bar so we can re-pack it at runtime*/
2069 //sbar_ref = g_object_ref(g->mainbar);
2071 g->mainbar_label = gtk_label_new ("");
2072 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2073 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2074 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2075 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2076 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2077 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2082 GtkWidget* create_window () {
2083 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2084 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2085 gtk_widget_set_name (window, "Uzbl browser");
2086 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2087 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2093 GtkPlug* create_plug () {
2094 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2095 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2096 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2103 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2105 If actname is one that calls an external command, this function will inject
2106 newargs in front of the user-provided args in that command line. They will
2107 come become after the body of the script (in sh) or after the name of
2108 the command to execute (in spawn).
2109 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2110 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2112 The return value consist of two strings: the action (sh, ...) and its args.
2114 If act is not one that calls an external command, then the given action merely
2117 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2118 gchar *actdup = g_strdup(actname);
2119 g_array_append_val(rets, actdup);
2121 if ((g_strcmp0(actname, "spawn") == 0) ||
2122 (g_strcmp0(actname, "sh") == 0) ||
2123 (g_strcmp0(actname, "sync_spawn") == 0) ||
2124 (g_strcmp0(actname, "sync_sh") == 0)) {
2126 GString *a = g_string_new("");
2127 gchar **spawnparts = split_quoted(origargs, FALSE);
2128 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2129 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2131 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2132 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2134 g_array_append_val(rets, a->str);
2135 g_string_free(a, FALSE);
2136 g_strfreev(spawnparts);
2138 gchar *origdup = g_strdup(origargs);
2139 g_array_append_val(rets, origdup);
2141 return (gchar**)g_array_free(rets, FALSE);
2145 run_handler (const gchar *act, const gchar *args) {
2146 /* Consider this code a temporary hack to make the handlers usable.
2147 In practice, all this splicing, injection, and reconstruction is
2148 inefficient, annoying and hard to manage. Potential pitfalls arise
2149 when the handler specific args 1) are not quoted (the handler
2150 callbacks should take care of this) 2) are quoted but interfere
2151 with the users' own quotation. A more ideal solution is
2152 to refactor parse_command so that it doesn't just take a string
2153 and execute it; rather than that, we should have a function which
2154 returns the argument vector parsed from the string. This vector
2155 could be modified (e.g. insert additional args into it) before
2156 passing it to the next function that actually executes it. Though
2157 it still isn't perfect for chain actions.. will reconsider & re-
2158 factor when I have the time. -duc */
2160 char **parts = g_strsplit(act, " ", 2);
2162 if (g_strcmp0(parts[0], "chain") == 0) {
2163 GString *newargs = g_string_new("");
2164 gchar **chainparts = split_quoted(parts[1], FALSE);
2166 /* for every argument in the chain, inject the handler args
2167 and make sure the new parts are wrapped in quotes */
2168 gchar **cp = chainparts;
2170 gchar *quotless = NULL;
2171 gchar **spliced_quotless = NULL; // sigh -_-;
2172 gchar **inpart = NULL;
2175 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2177 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2178 } else quotless = g_strdup(*cp);
2180 spliced_quotless = g_strsplit(quotless, " ", 2);
2181 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2182 g_strfreev(spliced_quotless);
2184 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2190 parse_command(parts[0], &(newargs->str[1]));
2191 g_string_free(newargs, TRUE);
2192 g_strfreev(chainparts);
2195 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2196 parse_command(inparts[0], inparts[1]);
2204 add_binding (const gchar *key, const gchar *act) {
2205 char **parts = g_strsplit(act, " ", 2);
2212 if (uzbl.state.verbose)
2213 printf ("Binding %-10s : %s\n", key, act);
2214 action = new_action(parts[0], parts[1]);
2216 if (g_hash_table_remove (uzbl.bindings, key))
2217 g_warning ("Overwriting existing binding for \"%s\"", key);
2218 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2223 get_xdg_var (XDG_Var xdg) {
2224 const gchar* actual_value = getenv (xdg.environmental);
2225 const gchar* home = getenv ("HOME");
2226 gchar* return_value;
2228 if (! actual_value || strcmp (actual_value, "") == 0) {
2229 if (xdg.default_value) {
2230 return_value = str_replace ("~", home, xdg.default_value);
2232 return_value = NULL;
2235 return_value = str_replace("~", home, actual_value);
2238 return return_value;
2242 find_xdg_file (int xdg_type, char* filename) {
2243 /* xdg_type = 0 => config
2244 xdg_type = 1 => data
2245 xdg_type = 2 => cache*/
2247 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2248 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2251 gchar* temporary_string;
2255 if (! file_exists (temporary_file) && xdg_type != 2) {
2256 buf = get_xdg_var (XDG[3 + xdg_type]);
2257 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2260 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2261 g_free (temporary_file);
2262 temporary_file = g_strconcat (temporary_string, filename, NULL);
2266 //g_free (temporary_string); - segfaults.
2268 if (file_exists (temporary_file)) {
2269 return temporary_file;
2276 State *s = &uzbl.state;
2277 Network *n = &uzbl.net;
2279 for (i = 0; default_config[i].command != NULL; i++) {
2280 parse_cmd_line(default_config[i].command);
2283 if (!s->config_file) {
2284 s->config_file = find_xdg_file (0, "/uzbl/config");
2287 if (s->config_file) {
2288 GArray* lines = read_file_by_line (s->config_file);
2292 while ((line = g_array_index(lines, gchar*, i))) {
2293 parse_cmd_line (line);
2297 g_array_free (lines, TRUE);
2299 if (uzbl.state.verbose)
2300 printf ("No configuration file loaded.\n");
2303 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2306 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2309 if (!uzbl.behave.cookie_handler)
2312 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2313 GString *s = g_string_new ("");
2314 SoupURI * soup_uri = soup_message_get_uri(msg);
2315 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2316 run_handler(uzbl.behave.cookie_handler, s->str);
2318 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2319 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2320 if ( p != NULL ) *p = '\0';
2321 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2323 if (uzbl.comm.sync_stdout)
2324 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2326 g_string_free(s, TRUE);
2330 save_cookies (SoupMessage *msg, gpointer user_data){
2334 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2335 cookie = soup_cookie_to_set_cookie_header(ck->data);
2336 SoupURI * soup_uri = soup_message_get_uri(msg);
2337 GString *s = g_string_new ("");
2338 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2339 run_handler(uzbl.behave.cookie_handler, s->str);
2341 g_string_free(s, TRUE);
2346 /* --- WEBINSPECTOR --- */
2348 hide_window_cb(GtkWidget *widget, gpointer data) {
2351 gtk_widget_hide(widget);
2354 static WebKitWebView*
2355 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2358 (void) web_inspector;
2359 GtkWidget* scrolled_window;
2360 GtkWidget* new_web_view;
2363 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2364 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2365 G_CALLBACK(hide_window_cb), NULL);
2367 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2368 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2369 gtk_widget_show(g->inspector_window);
2371 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2372 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2373 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2374 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2375 gtk_widget_show(scrolled_window);
2377 new_web_view = webkit_web_view_new();
2378 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2380 return WEBKIT_WEB_VIEW(new_web_view);
2384 inspector_show_window_cb (WebKitWebInspector* inspector){
2386 gtk_widget_show(uzbl.gui.inspector_window);
2390 /* TODO: Add variables and code to make use of these functions */
2392 inspector_close_window_cb (WebKitWebInspector* inspector){
2398 inspector_attach_window_cb (WebKitWebInspector* inspector){
2404 inspector_detach_window_cb (WebKitWebInspector* inspector){
2410 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2416 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2422 set_up_inspector() {
2424 WebKitWebSettings *settings = view_settings();
2425 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2427 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2428 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2429 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2430 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2431 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2432 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2433 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2435 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2439 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2441 uzbl_cmdprop *c = v;
2446 if(c->type == TYPE_STR)
2447 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2448 else if(c->type == TYPE_INT)
2449 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2453 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2457 printf("bind %s = %s %s\n", (char *)k ,
2458 (char *)a->name, a->param?(char *)a->param:"");
2463 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2464 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2469 main (int argc, char* argv[]) {
2470 gtk_init (&argc, &argv);
2471 if (!g_thread_supported ())
2472 g_thread_init (NULL);
2473 uzbl.state.executable_path = g_strdup(argv[0]);
2474 uzbl.state.selected_url = NULL;
2475 uzbl.state.searchtx = NULL;
2477 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2478 g_option_context_add_main_entries (context, entries, NULL);
2479 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2480 g_option_context_parse (context, &argc, &argv, NULL);
2481 g_option_context_free(context);
2483 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2484 gboolean verbose_override = uzbl.state.verbose;
2486 /* initialize hash table */
2487 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2489 uzbl.net.soup_session = webkit_get_default_session();
2490 uzbl.state.keycmd = g_string_new("");
2492 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2493 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2494 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2495 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2496 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2497 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2500 if(uname(&uzbl.state.unameinfo) == -1)
2501 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2503 uzbl.gui.sbar.progress_s = g_strdup("=");
2504 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2505 uzbl.gui.sbar.progress_w = 10;
2507 /* HTML mode defaults*/
2508 uzbl.behave.html_buffer = g_string_new("");
2509 uzbl.behave.html_endmarker = g_strdup(".");
2510 uzbl.behave.html_timeout = 60;
2511 uzbl.behave.base_url = g_strdup("http://invalid");
2513 /* default mode indicators */
2514 uzbl.behave.insert_indicator = g_strdup("I");
2515 uzbl.behave.cmd_indicator = g_strdup("C");
2519 make_var_to_name_hash();
2521 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2523 uzbl.gui.scrolled_win = create_browser();
2526 /* initial packing */
2527 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2528 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2530 if (uzbl.state.socket_id) {
2531 uzbl.gui.plug = create_plug ();
2532 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2533 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2535 uzbl.gui.main_window = create_window ();
2536 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2537 gtk_widget_show_all (uzbl.gui.main_window);
2538 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2541 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2543 if (uzbl.state.verbose) {
2544 printf("Uzbl start location: %s\n", argv[0]);
2545 if (uzbl.state.socket_id)
2546 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2548 printf("window_id %i\n",(int) uzbl.xwin);
2549 printf("pid %i\n", getpid ());
2550 printf("name: %s\n", uzbl.state.instance_name);
2553 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2554 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2555 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2556 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2557 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2561 if (!uzbl.behave.show_status)
2562 gtk_widget_hide(uzbl.gui.mainbar);
2571 if (verbose_override > uzbl.state.verbose)
2572 uzbl.state.verbose = verbose_override;
2575 set_var_value("uri", uri_override);
2576 g_free(uri_override);
2577 } else if (uzbl.state.uri)
2578 cmd_load_uri(uzbl.gui.web_view, NULL);
2583 return EXIT_SUCCESS;
2586 /* vi: set et ts=4: */