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 enum {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR};
197 get_exp_type(gchar *s) {
201 else if(*(s+1) == '{')
202 return EXP_BRACED_VAR;
204 return EXP_SIMPLE_VAR;
209 /* setting 'recurse = 1' will prevent expand() from
210 * expanding '@(command)'
213 expand(char *s, gboolean recurse) {
220 gchar *cmd_stdout = NULL;
222 GString *buf = g_string_new("");
227 g_string_append_c(buf, *++s);
232 etype = get_exp_type(s);
247 if( (vend = strchr(s, upto)) ||
248 (vend = strchr(s, '\0')) ) {
249 strncpy(ret, s, vend-s);
253 if(etype == EXP_SIMPLE_VAR ||
254 etype == EXP_BRACED_VAR) {
255 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, ret)) ) {
256 if(c->type == TYPE_STR)
257 g_string_append(buf, (gchar *)*c->ptr);
258 else if(c->type == TYPE_INT) {
259 char *b = itos((int)*c->ptr);
260 g_string_append(buf, b);
264 if(upto == ' ') s = vend;
269 mycmd = expand(ret, 1);
270 g_spawn_command_line_sync(mycmd, &cmd_stdout, NULL, NULL, &err);
274 g_printerr("error on running command: %s\n", err->message);
277 else if (*cmd_stdout) {
278 g_string_append(buf, cmd_stdout);
286 g_string_append_c(buf, *s);
291 return g_string_free(buf, FALSE);
298 snprintf(tmp, sizeof(tmp), "%i", val);
299 return g_strdup(tmp);
303 strfree(gchar *str) { g_free(str); return NULL; } // for freeing & setting to null in one go
306 argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); }
309 str_replace (const char* search, const char* replace, const char* string) {
313 buf = g_strsplit (string, search, -1);
314 ret = g_strjoinv (replace, buf);
315 g_strfreev(buf); // somebody said this segfaults
321 read_file_by_line (gchar *path) {
322 GIOChannel *chan = NULL;
323 gchar *readbuf = NULL;
325 GArray *lines = g_array_new(TRUE, FALSE, sizeof(gchar*));
328 chan = g_io_channel_new_file(path, "r", NULL);
331 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL) == G_IO_STATUS_NORMAL) {
332 const gchar* val = g_strdup (readbuf);
333 g_array_append_val (lines, val);
338 g_io_channel_unref (chan);
340 fprintf(stderr, "File '%s' not be read.\n", path);
347 gchar* parseenv (char* string) {
348 extern char** environ;
349 gchar* tmpstr = NULL;
353 while (environ[i] != NULL) {
354 gchar** env = g_strsplit (environ[i], "=", 2);
355 gchar* envname = g_strconcat ("$", env[0], NULL);
357 if (g_strrstr (string, envname) != NULL) {
358 tmpstr = g_strdup(string);
360 string = str_replace(envname, env[1], tmpstr);
365 g_strfreev (env); // somebody said this breaks uzbl
373 setup_signal(int signr, sigfunc *shandler) {
374 struct sigaction nh, oh;
376 nh.sa_handler = shandler;
377 sigemptyset(&nh.sa_mask);
380 if(sigaction(signr, &nh, &oh) < 0)
388 if (uzbl.behave.fifo_dir)
389 unlink (uzbl.comm.fifo_path);
390 if (uzbl.behave.socket_dir)
391 unlink (uzbl.comm.socket_path);
393 g_free(uzbl.state.executable_path);
394 g_string_free(uzbl.state.keycmd, TRUE);
395 g_hash_table_destroy(uzbl.bindings);
396 g_hash_table_destroy(uzbl.behave.commands);
399 /* used for html_mode_timeout
400 * be sure to extend this function to use
401 * more timers if needed in other places
404 set_timeout(int seconds) {
406 memset(&t, 0, sizeof t);
408 t.it_value.tv_sec = seconds;
409 t.it_value.tv_usec = 0;
410 setitimer(ITIMER_REAL, &t, NULL);
413 /* --- SIGNAL HANDLER --- */
416 catch_sigterm(int s) {
422 catch_sigint(int s) {
432 set_var_value("mode", "0");
437 /* --- CALLBACKS --- */
440 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
443 (void) navigation_action;
444 (void) policy_decision;
446 const gchar* uri = webkit_network_request_get_uri (request);
447 if (uzbl.state.verbose)
448 printf("New window requested -> %s \n", uri);
449 new_window_load_uri(uri);
454 mime_policy_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, gchar *mime_type, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
459 /* If we can display it, let's display it... */
460 if (webkit_web_view_can_show_mime_type (web_view, mime_type)) {
461 webkit_web_policy_decision_use (policy_decision);
465 /* ...everything we can't displayed is downloaded */
466 webkit_web_policy_decision_download (policy_decision);
471 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
475 if (uzbl.state.selected_url != NULL) {
476 if (uzbl.state.verbose)
477 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
478 new_window_load_uri(uzbl.state.selected_url);
480 if (uzbl.state.verbose)
481 printf("New web view -> %s\n","Nothing to open, exiting");
487 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
490 if (uzbl.behave.download_handler) {
491 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
492 if (uzbl.state.verbose)
493 printf("Download -> %s\n",uri);
494 /* if urls not escaped, we may have to escape and quote uri before this call */
495 run_handler(uzbl.behave.download_handler, uri);
500 /* scroll a bar in a given direction */
502 scroll (GtkAdjustment* bar, GArray *argv) {
506 amount = g_ascii_strtod(g_array_index(argv, gchar*, 0), &end);
507 if (*end == '%') amount = gtk_adjustment_get_page_size(bar) * amount * 0.01;
508 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
512 scroll_begin(WebKitWebView* page, GArray *argv) {
513 (void) page; (void) argv;
514 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
518 scroll_end(WebKitWebView* page, GArray *argv) {
519 (void) page; (void) argv;
520 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
521 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
525 scroll_vert(WebKitWebView* page, GArray *argv) {
527 scroll(uzbl.gui.bar_v, argv);
531 scroll_horz(WebKitWebView* page, GArray *argv) {
533 scroll(uzbl.gui.bar_h, argv);
538 if (!uzbl.behave.show_status) {
539 gtk_widget_hide(uzbl.gui.mainbar);
541 gtk_widget_show(uzbl.gui.mainbar);
547 toggle_zoom_type (WebKitWebView* page, GArray *argv) {
551 webkit_web_view_set_full_content_zoom (page, !webkit_web_view_get_full_content_zoom (page));
555 toggle_status_cb (WebKitWebView* page, GArray *argv) {
559 if (uzbl.behave.show_status) {
560 gtk_widget_hide(uzbl.gui.mainbar);
562 gtk_widget_show(uzbl.gui.mainbar);
564 uzbl.behave.show_status = !uzbl.behave.show_status;
569 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
573 //Set selected_url state variable
574 g_free(uzbl.state.selected_url);
575 uzbl.state.selected_url = NULL;
577 uzbl.state.selected_url = g_strdup(link);
583 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
587 if (uzbl.gui.main_title)
588 g_free (uzbl.gui.main_title);
589 uzbl.gui.main_title = g_strdup (title);
594 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
597 uzbl.gui.sbar.load_progress = progress;
602 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
606 if (uzbl.behave.load_finish_handler)
607 run_handler(uzbl.behave.load_finish_handler, "");
611 load_start_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
615 uzbl.gui.sbar.load_progress = 0;
616 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
617 if (uzbl.behave.load_start_handler)
618 run_handler(uzbl.behave.load_start_handler, "");
622 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
625 g_free (uzbl.state.uri);
626 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
627 uzbl.state.uri = g_string_free (newuri, FALSE);
628 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
629 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
632 if (uzbl.behave.load_commit_handler)
633 run_handler(uzbl.behave.load_commit_handler, uzbl.state.uri);
637 destroy_cb (GtkWidget* widget, gpointer data) {
645 if (uzbl.behave.history_handler) {
647 struct tm * timeinfo;
650 timeinfo = localtime ( &rawtime );
651 strftime (date, 80, "\"%Y-%m-%d %H:%M:%S\"", timeinfo);
652 run_handler(uzbl.behave.history_handler, date);
657 /* VIEW funcs (little webkit wrappers) */
658 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, GArray *argv){(void)argv; webkit_web_view_##name(page);}
660 VIEWFUNC(reload_bypass_cache)
661 VIEWFUNC(stop_loading)
668 /* -- command to callback/function map for things we cannot attach to any signals */
669 static struct {char *name; Command command[2];} cmdlist[] =
670 { /* key function no_split */
671 { "back", {view_go_back, 0} },
672 { "forward", {view_go_forward, 0} },
673 { "scroll_vert", {scroll_vert, 0} },
674 { "scroll_horz", {scroll_horz, 0} },
675 { "scroll_begin", {scroll_begin, 0} },
676 { "scroll_end", {scroll_end, 0} },
677 { "reload", {view_reload, 0}, },
678 { "reload_ign_cache", {view_reload_bypass_cache, 0} },
679 { "stop", {view_stop_loading, 0}, },
680 { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?).
681 { "zoom_out", {view_zoom_out, 0}, },
682 { "toggle_zoom_type", {toggle_zoom_type, 0}, },
683 { "uri", {load_uri, NOSPLIT} },
684 { "js", {run_js, NOSPLIT} },
685 { "script", {run_external_js, 0} },
686 { "toggle_status", {toggle_status_cb, 0} },
687 { "spawn", {spawn, 0} },
688 { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler
689 { "sh", {spawn_sh, 0} },
690 { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler
691 { "exit", {close_uzbl, 0} },
692 { "search", {search_forward_text, NOSPLIT} },
693 { "search_reverse", {search_reverse_text, NOSPLIT} },
694 { "dehilight", {dehilight, 0} },
695 { "toggle_insert_mode", {toggle_insert_mode, 0} },
696 { "set", {set_var, NOSPLIT} },
697 //{ "get", {get_var, NOSPLIT} },
698 { "bind", {act_bind, NOSPLIT} },
699 { "dump_config", {act_dump_config, 0} },
700 { "keycmd", {keycmd, NOSPLIT} },
701 { "keycmd_nl", {keycmd_nl, NOSPLIT} },
702 { "keycmd_bs", {keycmd_bs, 0} },
703 { "chain", {chain, 0} },
704 { "print", {print, NOSPLIT} }
711 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
713 for (i = 0; i < LENGTH(cmdlist); i++)
714 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
717 /* -- CORE FUNCTIONS -- */
720 free_action(gpointer act) {
721 Action *action = (Action*)act;
722 g_free(action->name);
724 g_free(action->param);
729 new_action(const gchar *name, const gchar *param) {
730 Action *action = g_new(Action, 1);
732 action->name = g_strdup(name);
734 action->param = g_strdup(param);
736 action->param = NULL;
742 file_exists (const char * filename) {
743 return (access(filename, F_OK) == 0);
747 set_var(WebKitWebView *page, GArray *argv) {
749 gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2);
750 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
751 set_var_value(g_strstrip(split[0]), value);
757 print(WebKitWebView *page, GArray *argv) {
761 buf = expand(argv_idx(argv, 0), 0);
767 act_bind(WebKitWebView *page, GArray *argv) {
769 gchar **split = g_strsplit(argv_idx(argv, 0), " = ", 2);
770 gchar *value = parseenv(g_strdup(split[1] ? g_strchug(split[1]) : " "));
771 add_binding(g_strstrip(split[0]), value);
783 toggle_insert_mode(WebKitWebView *page, GArray *argv) {
786 if (argv_idx(argv, 0)) {
787 if (strcmp (argv_idx(argv, 0), "0") == 0) {
788 uzbl.behave.insert_mode = FALSE;
790 uzbl.behave.insert_mode = TRUE;
793 uzbl.behave.insert_mode = ! uzbl.behave.insert_mode;
800 load_uri (WebKitWebView *web_view, GArray *argv) {
801 if (argv_idx(argv, 0)) {
802 GString* newuri = g_string_new (argv_idx(argv, 0));
803 if (g_strstr_len (argv_idx(argv, 0), 11, "javascript:") != NULL) {
804 run_js(web_view, argv);
807 if (g_strrstr (argv_idx(argv, 0), "://") == NULL && g_strstr_len (argv_idx(argv, 0), 5, "data:") == NULL)
808 g_string_prepend (newuri, "http://");
809 /* if we do handle cookies, ask our handler for them */
810 webkit_web_view_load_uri (web_view, newuri->str);
811 g_string_free (newuri, TRUE);
816 run_js (WebKitWebView * web_view, GArray *argv) {
817 if (argv_idx(argv, 0))
818 webkit_web_view_execute_script (web_view, argv_idx(argv, 0));
822 run_external_js (WebKitWebView * web_view, GArray *argv) {
823 if (argv_idx(argv, 0)) {
824 GArray* lines = read_file_by_line (argv_idx (argv, 0));
829 while ((line = g_array_index(lines, gchar*, i))) {
831 js = g_strdup (line);
833 gchar* newjs = g_strconcat (js, line, NULL);
840 if (uzbl.state.verbose)
841 printf ("External JavaScript file %s loaded\n", argv_idx(argv, 0));
843 if (argv_idx (argv, 1)) {
844 gchar* newjs = str_replace("%s", argv_idx (argv, 1), js);
848 webkit_web_view_execute_script (web_view, js);
850 g_array_free (lines, TRUE);
855 search_text (WebKitWebView *page, GArray *argv, const gboolean forward) {
856 if (argv_idx(argv, 0) && (*argv_idx(argv, 0) != '\0')) {
857 if (g_strcmp0 (uzbl.state.searchtx, argv_idx(argv, 0)) != 0) {
858 webkit_web_view_unmark_text_matches (page);
859 webkit_web_view_mark_text_matches (page, argv_idx(argv, 0), FALSE, 0);
860 uzbl.state.searchtx = g_strdup(argv_idx(argv, 0));
864 if (uzbl.state.searchtx) {
865 if (uzbl.state.verbose)
866 printf ("Searching: %s\n", uzbl.state.searchtx);
867 webkit_web_view_set_highlight_text_matches (page, TRUE);
868 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
873 search_forward_text (WebKitWebView *page, GArray *argv) {
874 search_text(page, argv, TRUE);
878 search_reverse_text (WebKitWebView *page, GArray *argv) {
879 search_text(page, argv, FALSE);
883 dehilight (WebKitWebView *page, GArray *argv) {
885 webkit_web_view_set_highlight_text_matches (page, FALSE);
890 new_window_load_uri (const gchar * uri) {
891 GString* to_execute = g_string_new ("");
892 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
894 for (i = 0; entries[i].long_name != NULL; i++) {
895 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
896 gchar** str = (gchar**)entries[i].arg_data;
898 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
902 if (uzbl.state.verbose)
903 printf("\n%s\n", to_execute->str);
904 g_spawn_command_line_async (to_execute->str, NULL);
905 g_string_free (to_execute, TRUE);
909 chain (WebKitWebView *page, GArray *argv) {
912 gchar **parts = NULL;
914 while ((a = argv_idx(argv, i++))) {
915 parts = g_strsplit (a, " ", 2);
916 parse_command(parts[0], parts[1]);
922 keycmd (WebKitWebView *page, GArray *argv) {
925 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
931 keycmd_nl (WebKitWebView *page, GArray *argv) {
934 g_string_assign(uzbl.state.keycmd, argv_idx(argv, 0));
940 keycmd_bs (WebKitWebView *page, GArray *argv) {
944 prev = g_utf8_find_prev_char(uzbl.state.keycmd->str, uzbl.state.keycmd->str + uzbl.state.keycmd->len);
946 g_string_truncate(uzbl.state.keycmd, prev - uzbl.state.keycmd->str);
951 close_uzbl (WebKitWebView *page, GArray *argv) {
957 /* --Statusbar functions-- */
959 build_progressbar_ascii(int percent) {
960 int width=uzbl.gui.sbar.progress_w;
963 GString *bar = g_string_new("");
965 l = (double)percent*((double)width/100.);
966 l = (int)(l+.5)>=(int)l ? l+.5 : l;
968 for(i=0; i<(int)l; i++)
969 g_string_append(bar, uzbl.gui.sbar.progress_s);
972 g_string_append(bar, uzbl.gui.sbar.progress_u);
974 return g_string_free(bar, FALSE);
979 const GScannerConfig scan_config = {
982 ) /* cset_skip_characters */,
987 ) /* cset_identifier_first */,
994 ) /* cset_identifier_nth */,
995 ( "" ) /* cpair_comment_single */,
997 TRUE /* case_sensitive */,
999 FALSE /* skip_comment_multi */,
1000 FALSE /* skip_comment_single */,
1001 FALSE /* scan_comment_multi */,
1002 TRUE /* scan_identifier */,
1003 TRUE /* scan_identifier_1char */,
1004 FALSE /* scan_identifier_NULL */,
1005 TRUE /* scan_symbols */,
1006 FALSE /* scan_binary */,
1007 FALSE /* scan_octal */,
1008 FALSE /* scan_float */,
1009 FALSE /* scan_hex */,
1010 FALSE /* scan_hex_dollar */,
1011 FALSE /* scan_string_sq */,
1012 FALSE /* scan_string_dq */,
1013 TRUE /* numbers_2_int */,
1014 FALSE /* int_2_float */,
1015 FALSE /* identifier_2_string */,
1016 FALSE /* char_2_token */,
1017 FALSE /* symbol_2_token */,
1018 TRUE /* scope_0_fallback */,
1023 uzbl.scan = g_scanner_new(&scan_config);
1024 while(symp->symbol_name) {
1025 g_scanner_scope_add_symbol(uzbl.scan, 0,
1027 GINT_TO_POINTER(symp->symbol_token));
1033 expand_template(const char *template, gboolean escape_markup) {
1034 if(!template) return NULL;
1036 GTokenType token = G_TOKEN_NONE;
1037 GString *ret = g_string_new("");
1041 g_scanner_input_text(uzbl.scan, template, strlen(template));
1042 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
1043 token = g_scanner_get_next_token(uzbl.scan);
1045 if(token == G_TOKEN_SYMBOL) {
1046 sym = GPOINTER_TO_INT(g_scanner_cur_value(uzbl.scan).v_symbol);
1050 buf = uzbl.state.uri?
1051 g_markup_printf_escaped("%s", uzbl.state.uri):g_strdup("");
1052 g_string_append(ret, buf);
1056 g_string_append(ret, uzbl.state.uri?
1057 uzbl.state.uri:g_strdup(""));
1060 buf = itos(uzbl.gui.sbar.load_progress);
1061 g_string_append(ret, buf);
1064 case SYM_LOADPRGSBAR:
1065 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
1066 g_string_append(ret, buf);
1071 buf = uzbl.gui.main_title?
1072 g_markup_printf_escaped("%s", uzbl.gui.main_title):g_strdup("");
1073 g_string_append(ret, buf);
1077 g_string_append(ret, uzbl.gui.main_title?
1078 uzbl.gui.main_title:g_strdup(""));
1080 case SYM_SELECTED_URI:
1082 buf = uzbl.state.selected_url?
1083 g_markup_printf_escaped("%s", uzbl.state.selected_url):g_strdup("");
1084 g_string_append(ret, buf);
1088 g_string_append(ret, uzbl.state.selected_url?
1089 uzbl.state.selected_url:g_strdup(""));
1092 buf = itos(uzbl.xwin);
1093 g_string_append(ret,
1094 uzbl.state.instance_name?uzbl.state.instance_name:buf);
1099 buf = uzbl.state.keycmd->str?
1100 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):g_strdup("");
1101 g_string_append(ret, buf);
1105 g_string_append(ret, uzbl.state.keycmd->str?
1106 uzbl.state.keycmd->str:g_strdup(""));
1109 g_string_append(ret,
1110 uzbl.behave.insert_mode?
1111 uzbl.behave.insert_indicator:uzbl.behave.cmd_indicator);
1114 g_string_append(ret,
1115 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
1117 /* useragent syms */
1119 buf = itos(WEBKIT_MAJOR_VERSION);
1120 g_string_append(ret, buf);
1124 buf = itos(WEBKIT_MINOR_VERSION);
1125 g_string_append(ret, buf);
1129 buf = itos(WEBKIT_MICRO_VERSION);
1130 g_string_append(ret, buf);
1134 g_string_append(ret, uzbl.state.unameinfo.sysname);
1137 g_string_append(ret, uzbl.state.unameinfo.nodename);
1140 g_string_append(ret, uzbl.state.unameinfo.release);
1143 g_string_append(ret, uzbl.state.unameinfo.version);
1146 g_string_append(ret, uzbl.state.unameinfo.machine);
1149 g_string_append(ret, ARCH);
1152 case SYM_DOMAINNAME:
1153 g_string_append(ret, uzbl.state.unameinfo.domainname);
1157 g_string_append(ret, COMMIT);
1163 else if(token == G_TOKEN_INT) {
1164 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
1165 g_string_append(ret, buf);
1168 else if(token == G_TOKEN_IDENTIFIER) {
1169 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
1171 else if(token == G_TOKEN_CHAR) {
1172 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
1176 return g_string_free(ret, FALSE);
1178 /* --End Statusbar functions-- */
1181 sharg_append(GArray *a, const gchar *str) {
1182 const gchar *s = (str ? str : "");
1183 g_array_append_val(a, s);
1186 // make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
1188 run_command (const gchar *command, const guint npre, const gchar **args,
1189 const gboolean sync, char **output_stdout) {
1190 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
1193 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1194 gchar *pid = itos(getpid());
1195 gchar *xwin = itos(uzbl.xwin);
1197 sharg_append(a, command);
1198 for (i = 0; i < npre; i++) /* add n args before the default vars */
1199 sharg_append(a, args[i]);
1200 sharg_append(a, uzbl.state.config_file);
1201 sharg_append(a, pid);
1202 sharg_append(a, xwin);
1203 sharg_append(a, uzbl.comm.fifo_path);
1204 sharg_append(a, uzbl.comm.socket_path);
1205 sharg_append(a, uzbl.state.uri);
1206 sharg_append(a, uzbl.gui.main_title);
1208 for (i = npre; i < g_strv_length((gchar**)args); i++)
1209 sharg_append(a, args[i]);
1213 if (*output_stdout) *output_stdout = strfree(*output_stdout);
1215 result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1216 NULL, NULL, output_stdout, NULL, NULL, &err);
1217 } else result = g_spawn_async(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH,
1218 NULL, NULL, NULL, &err);
1220 if (uzbl.state.verbose) {
1221 GString *s = g_string_new("spawned:");
1222 for (i = 0; i < (a->len); i++) {
1223 gchar *qarg = g_shell_quote(g_array_index(a, gchar*, i));
1224 g_string_append_printf(s, " %s", qarg);
1227 g_string_append_printf(s, " -- result: %s", (result ? "true" : "false"));
1228 printf("%s\n", s->str);
1229 g_string_free(s, TRUE);
1231 printf("Stdout: %s\n", *output_stdout);
1235 g_printerr("error on run_command: %s\n", err->message);
1240 g_array_free (a, TRUE);
1245 split_quoted(const gchar* src, const gboolean unquote) {
1246 /* split on unquoted space, return array of strings;
1247 remove a layer of quotes and backslashes if unquote */
1248 if (!src) return NULL;
1250 gboolean dq = FALSE;
1251 gboolean sq = FALSE;
1252 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1253 GString *s = g_string_new ("");
1257 for (p = src; *p != '\0'; p++) {
1258 if ((*p == '\\') && unquote) g_string_append_c(s, *++p);
1259 else if (*p == '\\') { g_string_append_c(s, *p++);
1260 g_string_append_c(s, *p); }
1261 else if ((*p == '"') && unquote && !sq) dq = !dq;
1262 else if (*p == '"' && !sq) { g_string_append_c(s, *p);
1264 else if ((*p == '\'') && unquote && !dq) sq = !sq;
1265 else if (*p == '\'' && !dq) { g_string_append_c(s, *p);
1267 else if ((*p == ' ') && !dq && !sq) {
1268 dup = g_strdup(s->str);
1269 g_array_append_val(a, dup);
1270 g_string_truncate(s, 0);
1271 } else g_string_append_c(s, *p);
1273 dup = g_strdup(s->str);
1274 g_array_append_val(a, dup);
1275 ret = (gchar**)a->data;
1276 g_array_free (a, FALSE);
1277 g_string_free (s, TRUE);
1282 spawn(WebKitWebView *web_view, GArray *argv) {
1284 //TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
1285 if (argv_idx(argv, 0))
1286 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))), FALSE, NULL);
1290 spawn_sync(WebKitWebView *web_view, GArray *argv) {
1293 if (argv_idx(argv, 0))
1294 run_command(argv_idx(argv, 0), 0, ((const gchar **) (argv->data + sizeof(gchar*))),
1295 TRUE, &uzbl.comm.sync_stdout);
1299 spawn_sh(WebKitWebView *web_view, GArray *argv) {
1301 if (!uzbl.behave.shell_cmd) {
1302 g_printerr ("spawn_sh: shell_cmd is not set!\n");
1307 gchar *spacer = g_strdup("");
1308 g_array_insert_val(argv, 1, spacer);
1309 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1311 for (i = 1; i < g_strv_length(cmd); i++)
1312 g_array_prepend_val(argv, cmd[i]);
1314 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data, FALSE, NULL);
1320 spawn_sh_sync(WebKitWebView *web_view, GArray *argv) {
1322 if (!uzbl.behave.shell_cmd) {
1323 g_printerr ("spawn_sh_sync: shell_cmd is not set!\n");
1328 gchar *spacer = g_strdup("");
1329 g_array_insert_val(argv, 1, spacer);
1330 gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE);
1332 for (i = 1; i < g_strv_length(cmd); i++)
1333 g_array_prepend_val(argv, cmd[i]);
1335 if (cmd) run_command(cmd[0], g_strv_length(cmd) + 1, (const gchar **) argv->data,
1336 TRUE, &uzbl.comm.sync_stdout);
1342 parse_command(const char *cmd, const char *param) {
1345 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) {
1348 gchar **par = split_quoted(param, TRUE);
1349 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1351 if (c[1] == NOSPLIT) { /* don't split */
1352 sharg_append(a, param);
1354 for (i = 0; i < g_strv_length(par); i++)
1355 sharg_append(a, par[i]);
1357 c[0](uzbl.gui.web_view, a);
1359 g_array_free (a, TRUE);
1362 g_printerr ("command \"%s\" not understood. ignoring.\n", cmd);
1369 if(*uzbl.net.proxy_url == ' '
1370 || uzbl.net.proxy_url == NULL) {
1371 soup_session_remove_feature_by_type(uzbl.net.soup_session,
1372 (GType) SOUP_SESSION_PROXY_URI);
1375 suri = soup_uri_new(uzbl.net.proxy_url);
1376 g_object_set(G_OBJECT(uzbl.net.soup_session),
1377 SOUP_SESSION_PROXY_URI,
1379 soup_uri_free(suri);
1386 if(file_exists(uzbl.gui.icon)) {
1387 if (uzbl.gui.main_window)
1388 gtk_window_set_icon_from_file (GTK_WINDOW (uzbl.gui.main_window), uzbl.gui.icon, NULL);
1390 g_printerr ("Icon \"%s\" not found. ignoring.\n", uzbl.gui.icon);
1392 g_free (uzbl.gui.icon);
1397 GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*));
1398 g_array_append_val (a, uzbl.state.uri);
1399 load_uri(uzbl.gui.web_view, a);
1400 g_array_free (a, TRUE);
1404 cmd_always_insert_mode() {
1405 uzbl.behave.insert_mode =
1406 uzbl.behave.always_insert_mode ? TRUE : FALSE;
1412 g_object_set(G_OBJECT(uzbl.net.soup_session),
1413 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
1417 cmd_max_conns_host() {
1418 g_object_set(G_OBJECT(uzbl.net.soup_session),
1419 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
1424 soup_session_remove_feature
1425 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1426 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
1427 /*g_free(uzbl.net.soup_logger);*/
1429 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
1430 soup_session_add_feature(uzbl.net.soup_session,
1431 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
1434 static WebKitWebSettings*
1436 return webkit_web_view_get_settings(uzbl.gui.web_view);
1441 WebKitWebSettings *ws = view_settings();
1442 if (uzbl.behave.font_size > 0) {
1443 g_object_set (G_OBJECT(ws), "default-font-size", uzbl.behave.font_size, NULL);
1446 if (uzbl.behave.monospace_size > 0) {
1447 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1448 uzbl.behave.monospace_size, NULL);
1450 g_object_set (G_OBJECT(ws), "default-monospace-font-size",
1451 uzbl.behave.font_size, NULL);
1457 webkit_web_view_set_zoom_level (uzbl.gui.web_view, uzbl.behave.zoom_level);
1461 cmd_disable_plugins() {
1462 g_object_set (G_OBJECT(view_settings()), "enable-plugins",
1463 !uzbl.behave.disable_plugins, NULL);
1467 cmd_disable_scripts() {
1468 g_object_set (G_OBJECT(view_settings()), "enable-scripts",
1469 !uzbl.behave.disable_scripts, NULL);
1473 cmd_minimum_font_size() {
1474 g_object_set (G_OBJECT(view_settings()), "minimum-font-size",
1475 uzbl.behave.minimum_font_size, NULL);
1478 cmd_autoload_img() {
1479 g_object_set (G_OBJECT(view_settings()), "auto-load-images",
1480 uzbl.behave.autoload_img, NULL);
1485 cmd_autoshrink_img() {
1486 g_object_set (G_OBJECT(view_settings()), "auto-shrink-images",
1487 uzbl.behave.autoshrink_img, NULL);
1492 cmd_enable_spellcheck() {
1493 g_object_set (G_OBJECT(view_settings()), "enable-spell-checking",
1494 uzbl.behave.enable_spellcheck, NULL);
1498 cmd_enable_private() {
1499 g_object_set (G_OBJECT(view_settings()), "enable-private-browsing",
1500 uzbl.behave.enable_private, NULL);
1505 g_object_set (G_OBJECT(view_settings()), "print-backgrounds",
1506 uzbl.behave.print_bg, NULL);
1511 g_object_set (G_OBJECT(view_settings()), "user-stylesheet-uri",
1512 uzbl.behave.style_uri, NULL);
1516 cmd_resizable_txt() {
1517 g_object_set (G_OBJECT(view_settings()), "resizable-text-areas",
1518 uzbl.behave.resizable_txt, NULL);
1522 cmd_default_encoding() {
1523 g_object_set (G_OBJECT(view_settings()), "default-encoding",
1524 uzbl.behave.default_encoding, NULL);
1528 cmd_enforce_96dpi() {
1529 g_object_set (G_OBJECT(view_settings()), "enforce-96-dpi",
1530 uzbl.behave.enforce_96dpi, NULL);
1534 cmd_caret_browsing() {
1535 g_object_set (G_OBJECT(view_settings()), "enable-caret-browsing",
1536 uzbl.behave.caret_browsing, NULL);
1540 cmd_cookie_handler() {
1541 gchar **split = g_strsplit(uzbl.behave.cookie_handler, " ", 2);
1542 /* pitfall: doesn't handle chain actions; must the sync_ action manually */
1543 if ((g_strcmp0(split[0], "sh") == 0) ||
1544 (g_strcmp0(split[0], "spawn") == 0)) {
1545 g_free (uzbl.behave.cookie_handler);
1546 uzbl.behave.cookie_handler =
1547 g_strdup_printf("sync_%s %s", split[0], split[1]);
1554 uzbl.behave.fifo_dir = init_fifo(uzbl.behave.fifo_dir);
1559 uzbl.behave.socket_dir = init_socket(uzbl.behave.socket_dir);
1564 if(uzbl.behave.inject_html) {
1565 webkit_web_view_load_html_string (uzbl.gui.web_view,
1566 uzbl.behave.inject_html, NULL);
1575 buf = g_utf8_strup(uzbl.behave.modkey, -1);
1576 uzbl.behave.modmask = 0;
1578 if(uzbl.behave.modkey)
1579 g_free(uzbl.behave.modkey);
1580 uzbl.behave.modkey = buf;
1582 for (i = 0; modkeys[i].key != NULL; i++) {
1583 if (g_strrstr(buf, modkeys[i].key))
1584 uzbl.behave.modmask |= modkeys[i].mask;
1590 if (*uzbl.net.useragent == ' ') {
1591 g_free (uzbl.net.useragent);
1592 uzbl.net.useragent = NULL;
1594 gchar *ua = expand_template(uzbl.net.useragent, FALSE);
1596 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1597 g_free(uzbl.net.useragent);
1598 uzbl.net.useragent = ua;
1604 gtk_widget_ref(uzbl.gui.scrolled_win);
1605 gtk_widget_ref(uzbl.gui.mainbar);
1606 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
1607 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
1609 if(uzbl.behave.status_top) {
1610 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1611 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1614 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1615 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1617 gtk_widget_unref(uzbl.gui.scrolled_win);
1618 gtk_widget_unref(uzbl.gui.mainbar);
1619 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1624 set_var_value(gchar *name, gchar *val) {
1625 uzbl_cmdprop *c = NULL;
1629 if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
1630 /* check for the variable type */
1631 if (c->type == TYPE_STR) {
1632 buf = expand(val, 0);
1635 } else if(c->type == TYPE_INT) {
1636 int *ip = (int *)c->ptr;
1637 buf = expand(val, 0);
1638 *ip = (int)strtoul(buf, &endp, 10);
1640 } else if (c->type == TYPE_FLOAT) {
1641 float *fp = (float *)c->ptr;
1642 buf = expand(val, 0);
1643 *fp = strtod(buf, &endp);
1647 /* invoke a command specific function */
1648 if(c->func) c->func();
1655 Behaviour *b = &uzbl.behave;
1657 if(b->html_buffer->str) {
1658 webkit_web_view_load_html_string (uzbl.gui.web_view,
1659 b->html_buffer->str, b->base_url);
1660 g_string_free(b->html_buffer, TRUE);
1661 b->html_buffer = g_string_new("");
1665 enum {M_CMD, M_HTML};
1667 parse_cmd_line(const char *ctl_line) {
1668 Behaviour *b = &uzbl.behave;
1671 if(b->mode == M_HTML) {
1672 len = strlen(b->html_endmarker);
1673 /* ctl_line has trailing '\n' so we check for strlen(ctl_line)-1 */
1674 if(len == strlen(ctl_line)-1 &&
1675 !strncmp(b->html_endmarker, ctl_line, len)) {
1677 set_var_value("mode", "0");
1682 set_timeout(b->html_timeout);
1683 g_string_append(b->html_buffer, ctl_line);
1686 else if((ctl_line[0] == '#') /* Comments */
1687 || (ctl_line[0] == ' ')
1688 || (ctl_line[0] == '\n'))
1689 ; /* ignore these lines */
1690 else { /* parse a command */
1692 gchar **tokens = NULL;
1693 len = strlen(ctl_line);
1695 if (ctl_line[len - 1] == '\n') /* strip trailing newline */
1696 ctlstrip = g_strndup(ctl_line, len - 1);
1697 else ctlstrip = g_strdup(ctl_line);
1699 tokens = g_strsplit(ctlstrip, " ", 2);
1700 parse_command(tokens[0], tokens[1]);
1707 build_stream_name(int type, const gchar* dir) {
1708 char *xwin_str = NULL;
1709 State *s = &uzbl.state;
1712 xwin_str = itos((int)uzbl.xwin);
1714 str = g_strdup_printf
1715 ("%s/uzbl_fifo_%s", dir,
1716 s->instance_name ? s->instance_name : xwin_str);
1717 } else if (type == SOCKET) {
1718 str = g_strdup_printf
1719 ("%s/uzbl_socket_%s", dir,
1720 s->instance_name ? s->instance_name : xwin_str );
1727 control_fifo(GIOChannel *gio, GIOCondition condition) {
1728 if (uzbl.state.verbose)
1729 printf("triggered\n");
1734 if (condition & G_IO_HUP)
1735 g_error ("Fifo: Read end of pipe died!\n");
1738 g_error ("Fifo: GIOChannel broke\n");
1740 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1741 if (ret == G_IO_STATUS_ERROR) {
1742 g_error ("Fifo: Error reading: %s\n", err->message);
1746 parse_cmd_line(ctl_line);
1753 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1754 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1755 if (unlink(uzbl.comm.fifo_path) == -1)
1756 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1757 g_free(uzbl.comm.fifo_path);
1758 uzbl.comm.fifo_path = NULL;
1761 if (*dir == ' ') { /* space unsets the variable */
1766 GIOChannel *chan = NULL;
1767 GError *error = NULL;
1768 gchar *path = build_stream_name(FIFO, dir);
1770 if (!file_exists(path)) {
1771 if (mkfifo (path, 0666) == 0) {
1772 // 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.
1773 chan = g_io_channel_new_file(path, "r+", &error);
1775 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1776 if (uzbl.state.verbose)
1777 printf ("init_fifo: created successfully as %s\n", path);
1778 uzbl.comm.fifo_path = path;
1780 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1781 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1782 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1783 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1785 /* if we got this far, there was an error; cleanup */
1786 if (error) g_error_free (error);
1793 control_stdin(GIOChannel *gio, GIOCondition condition) {
1795 gchar *ctl_line = NULL;
1798 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
1799 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1802 parse_cmd_line(ctl_line);
1810 GIOChannel *chan = NULL;
1811 GError *error = NULL;
1813 chan = g_io_channel_unix_new(fileno(stdin));
1815 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1816 g_error ("Stdin: could not add watch\n");
1818 if (uzbl.state.verbose)
1819 printf ("Stdin: watch added successfully\n");
1822 g_error ("Stdin: Error while opening: %s\n", error->message);
1824 if (error) g_error_free (error);
1828 control_socket(GIOChannel *chan) {
1829 struct sockaddr_un remote;
1830 char buffer[512], *ctl_line;
1832 int sock, clientsock, n, done;
1835 sock = g_io_channel_unix_get_fd(chan);
1837 memset (buffer, 0, sizeof (buffer));
1839 t = sizeof (remote);
1840 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1844 memset (temp, 0, sizeof (temp));
1845 n = recv (clientsock, temp, 128, 0);
1847 buffer[strlen (buffer)] = '\0';
1851 strcat (buffer, temp);
1854 if (strcmp (buffer, "\n") < 0) {
1855 buffer[strlen (buffer) - 1] = '\0';
1857 buffer[strlen (buffer)] = '\0';
1860 ctl_line = g_strdup(buffer);
1861 parse_cmd_line (ctl_line);
1864 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1865 GError *error = NULL;
1868 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1869 if (ret == G_IO_STATUS_ERROR)
1870 g_error ("Error reading: %s\n", error->message);
1872 printf("Got line %s (%u bytes) \n",ctl_line, len);
1874 parse_line(ctl_line);
1882 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1883 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1884 if (unlink(uzbl.comm.socket_path) == -1)
1885 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1886 g_free(uzbl.comm.socket_path);
1887 uzbl.comm.socket_path = NULL;
1895 GIOChannel *chan = NULL;
1897 struct sockaddr_un local;
1898 gchar *path = build_stream_name(SOCKET, dir);
1900 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1902 local.sun_family = AF_UNIX;
1903 strcpy (local.sun_path, path);
1904 unlink (local.sun_path);
1906 len = strlen (local.sun_path) + sizeof (local.sun_family);
1907 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1908 if (uzbl.state.verbose)
1909 printf ("init_socket: opened in %s\n", path);
1912 if( (chan = g_io_channel_unix_new(sock)) ) {
1913 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1914 uzbl.comm.socket_path = path;
1917 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1919 /* if we got this far, there was an error; cleanup */
1926 NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
1927 it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
1929 // this function may be called very early when the templates are not set (yet), hence the checks
1931 update_title (void) {
1932 Behaviour *b = &uzbl.behave;
1935 if (b->show_status) {
1936 if (b->title_format_short) {
1937 parsed = expand_template(b->title_format_short, FALSE);
1938 if (uzbl.gui.main_window)
1939 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1942 if (b->status_format) {
1943 parsed = expand_template(b->status_format, TRUE);
1944 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
1947 if (b->status_background) {
1949 gdk_color_parse (b->status_background, &color);
1950 //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)
1951 if (uzbl.gui.main_window)
1952 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1955 if (b->title_format_long) {
1956 parsed = expand_template(b->title_format_long, FALSE);
1957 if (uzbl.gui.main_window)
1958 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
1965 key_press_cb (GtkWidget* window, GdkEventKey* event)
1967 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1971 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1972 || 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)
1975 /* turn off insert mode (if always_insert_mode is not used) */
1976 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1977 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1982 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1985 if (event->keyval == GDK_Escape) {
1986 g_string_truncate(uzbl.state.keycmd, 0);
1988 dehilight(uzbl.gui.web_view, NULL);
1992 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1993 if (event->keyval == GDK_Insert) {
1995 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1996 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1998 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2001 g_string_append (uzbl.state.keycmd, str);
2008 if (event->keyval == GDK_BackSpace)
2009 keycmd_bs(NULL, NULL);
2011 gboolean key_ret = FALSE;
2012 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
2014 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
2016 run_keycmd(key_ret);
2018 if (key_ret) return (!uzbl.behave.insert_mode);
2023 run_keycmd(const gboolean key_ret) {
2024 /* run the keycmd immediately if it isn't incremental and doesn't take args */
2026 if ((act = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
2027 g_string_truncate(uzbl.state.keycmd, 0);
2028 parse_command(act->name, act->param);
2032 /* try if it's an incremental keycmd or one that takes args, and run it */
2033 GString* short_keys = g_string_new ("");
2034 GString* short_keys_inc = g_string_new ("");
2036 for (i=0; i<(uzbl.state.keycmd->len); i++) {
2037 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
2038 g_string_assign(short_keys_inc, short_keys->str);
2039 g_string_append_c(short_keys, '_');
2040 g_string_append_c(short_keys_inc, '*');
2042 if (key_ret && (act = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
2043 /* run normal cmds only if return was pressed */
2044 exec_paramcmd(act, i);
2045 g_string_truncate(uzbl.state.keycmd, 0);
2047 } else if ((act = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
2048 if (key_ret) /* just quit the incremental command on return */
2049 g_string_truncate(uzbl.state.keycmd, 0);
2050 else exec_paramcmd(act, i); /* otherwise execute the incremental */
2054 g_string_truncate(short_keys, short_keys->len - 1);
2056 g_string_free (short_keys, TRUE);
2057 g_string_free (short_keys_inc, TRUE);
2061 exec_paramcmd(const Action *act, const guint i) {
2062 GString *parampart = g_string_new (uzbl.state.keycmd->str);
2063 GString *actionname = g_string_new ("");
2064 GString *actionparam = g_string_new ("");
2065 g_string_erase (parampart, 0, i+1);
2067 g_string_printf (actionname, act->name, parampart->str);
2069 g_string_printf (actionparam, act->param, parampart->str);
2070 parse_command(actionname->str, actionparam->str);
2071 g_string_free(actionname, TRUE);
2072 g_string_free(actionparam, TRUE);
2073 g_string_free(parampart, TRUE);
2081 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2082 //main_window_ref = g_object_ref(scrolled_window);
2083 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
2085 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
2086 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
2088 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
2089 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
2090 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
2091 g_signal_connect (G_OBJECT (g->web_view), "load-started", G_CALLBACK (load_start_cb), g->web_view);
2092 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
2093 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
2094 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
2095 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
2096 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
2097 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
2098 g_signal_connect (G_OBJECT (g->web_view), "mime-type-policy-decision-requested", G_CALLBACK (mime_policy_cb), g->web_view);
2100 return scrolled_window;
2107 g->mainbar = gtk_hbox_new (FALSE, 0);
2109 /* keep a reference to the bar so we can re-pack it at runtime*/
2110 //sbar_ref = g_object_ref(g->mainbar);
2112 g->mainbar_label = gtk_label_new ("");
2113 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
2114 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
2115 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
2116 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
2117 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
2118 g_signal_connect (G_OBJECT (g->mainbar), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2123 GtkWidget* create_window () {
2124 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2125 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
2126 gtk_widget_set_name (window, "Uzbl browser");
2127 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
2128 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2134 GtkPlug* create_plug () {
2135 GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id));
2136 g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL);
2137 g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL);
2144 inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) {
2146 If actname is one that calls an external command, this function will inject
2147 newargs in front of the user-provided args in that command line. They will
2148 come become after the body of the script (in sh) or after the name of
2149 the command to execute (in spawn).
2150 i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and
2151 span <command> <userargs> becomes spawn <command> <ARGS> <userargs>.
2153 The return value consist of two strings: the action (sh, ...) and its args.
2155 If act is not one that calls an external command, then the given action merely
2158 GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*));
2159 gchar *actdup = g_strdup(actname);
2160 g_array_append_val(rets, actdup);
2162 if ((g_strcmp0(actname, "spawn") == 0) ||
2163 (g_strcmp0(actname, "sh") == 0) ||
2164 (g_strcmp0(actname, "sync_spawn") == 0) ||
2165 (g_strcmp0(actname, "sync_sh") == 0)) {
2167 GString *a = g_string_new("");
2168 gchar **spawnparts = split_quoted(origargs, FALSE);
2169 g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */
2170 if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */
2172 for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */
2173 if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]);
2175 g_array_append_val(rets, a->str);
2176 g_string_free(a, FALSE);
2177 g_strfreev(spawnparts);
2179 gchar *origdup = g_strdup(origargs);
2180 g_array_append_val(rets, origdup);
2182 return (gchar**)g_array_free(rets, FALSE);
2186 run_handler (const gchar *act, const gchar *args) {
2187 /* Consider this code a temporary hack to make the handlers usable.
2188 In practice, all this splicing, injection, and reconstruction is
2189 inefficient, annoying and hard to manage. Potential pitfalls arise
2190 when the handler specific args 1) are not quoted (the handler
2191 callbacks should take care of this) 2) are quoted but interfere
2192 with the users' own quotation. A more ideal solution is
2193 to refactor parse_command so that it doesn't just take a string
2194 and execute it; rather than that, we should have a function which
2195 returns the argument vector parsed from the string. This vector
2196 could be modified (e.g. insert additional args into it) before
2197 passing it to the next function that actually executes it. Though
2198 it still isn't perfect for chain actions.. will reconsider & re-
2199 factor when I have the time. -duc */
2201 char **parts = g_strsplit(act, " ", 2);
2203 if (g_strcmp0(parts[0], "chain") == 0) {
2204 GString *newargs = g_string_new("");
2205 gchar **chainparts = split_quoted(parts[1], FALSE);
2207 /* for every argument in the chain, inject the handler args
2208 and make sure the new parts are wrapped in quotes */
2209 gchar **cp = chainparts;
2211 gchar *quotless = NULL;
2212 gchar **spliced_quotless = NULL; // sigh -_-;
2213 gchar **inpart = NULL;
2216 if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */
2218 quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2);
2219 } else quotless = g_strdup(*cp);
2221 spliced_quotless = g_strsplit(quotless, " ", 2);
2222 inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args);
2223 g_strfreev(spliced_quotless);
2225 g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot);
2231 parse_command(parts[0], &(newargs->str[1]));
2232 g_string_free(newargs, TRUE);
2233 g_strfreev(chainparts);
2236 gchar **inparts = inject_handler_args(parts[0], parts[1], args);
2237 parse_command(inparts[0], inparts[1]);
2245 add_binding (const gchar *key, const gchar *act) {
2246 char **parts = g_strsplit(act, " ", 2);
2253 if (uzbl.state.verbose)
2254 printf ("Binding %-10s : %s\n", key, act);
2255 action = new_action(parts[0], parts[1]);
2257 if (g_hash_table_remove (uzbl.bindings, key))
2258 g_warning ("Overwriting existing binding for \"%s\"", key);
2259 g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
2264 get_xdg_var (XDG_Var xdg) {
2265 const gchar* actual_value = getenv (xdg.environmental);
2266 const gchar* home = getenv ("HOME");
2267 gchar* return_value;
2269 if (! actual_value || strcmp (actual_value, "") == 0) {
2270 if (xdg.default_value) {
2271 return_value = str_replace ("~", home, xdg.default_value);
2273 return_value = NULL;
2276 return_value = str_replace("~", home, actual_value);
2279 return return_value;
2283 find_xdg_file (int xdg_type, char* filename) {
2284 /* xdg_type = 0 => config
2285 xdg_type = 1 => data
2286 xdg_type = 2 => cache*/
2288 gchar* xdgv = get_xdg_var (XDG[xdg_type]);
2289 gchar* temporary_file = g_strconcat (xdgv, filename, NULL);
2292 gchar* temporary_string;
2296 if (! file_exists (temporary_file) && xdg_type != 2) {
2297 buf = get_xdg_var (XDG[3 + xdg_type]);
2298 temporary_string = (char *) strtok_r (buf, ":", &saveptr);
2301 while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) {
2302 g_free (temporary_file);
2303 temporary_file = g_strconcat (temporary_string, filename, NULL);
2307 //g_free (temporary_string); - segfaults.
2309 if (file_exists (temporary_file)) {
2310 return temporary_file;
2317 State *s = &uzbl.state;
2318 Network *n = &uzbl.net;
2320 for (i = 0; default_config[i].command != NULL; i++) {
2321 parse_cmd_line(default_config[i].command);
2324 if (!s->config_file) {
2325 s->config_file = find_xdg_file (0, "/uzbl/config");
2328 if (s->config_file) {
2329 GArray* lines = read_file_by_line (s->config_file);
2333 while ((line = g_array_index(lines, gchar*, i))) {
2334 parse_cmd_line (line);
2338 g_array_free (lines, TRUE);
2340 if (uzbl.state.verbose)
2341 printf ("No configuration file loaded.\n");
2344 g_signal_connect_after(n->soup_session, "request-started", G_CALLBACK(handle_cookies), NULL);
2347 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
2350 if (!uzbl.behave.cookie_handler)
2353 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
2354 GString *s = g_string_new ("");
2355 SoupURI * soup_uri = soup_message_get_uri(msg);
2356 g_string_printf(s, "GET '%s' '%s'", soup_uri->host, soup_uri->path);
2357 run_handler(uzbl.behave.cookie_handler, s->str);
2359 if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) {
2360 char *p = strchr(uzbl.comm.sync_stdout, '\n' );
2361 if ( p != NULL ) *p = '\0';
2362 soup_message_headers_replace (msg->request_headers, "Cookie", (const char *) uzbl.comm.sync_stdout);
2364 if (uzbl.comm.sync_stdout)
2365 uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout);
2367 g_string_free(s, TRUE);
2371 save_cookies (SoupMessage *msg, gpointer user_data){
2375 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
2376 cookie = soup_cookie_to_set_cookie_header(ck->data);
2377 SoupURI * soup_uri = soup_message_get_uri(msg);
2378 GString *s = g_string_new ("");
2379 g_string_printf(s, "PUT '%s' '%s' '%s'", soup_uri->host, soup_uri->path, cookie);
2380 run_handler(uzbl.behave.cookie_handler, s->str);
2382 g_string_free(s, TRUE);
2387 /* --- WEBINSPECTOR --- */
2389 hide_window_cb(GtkWidget *widget, gpointer data) {
2392 gtk_widget_hide(widget);
2395 static WebKitWebView*
2396 create_inspector_cb (WebKitWebInspector* web_inspector, WebKitWebView* page, gpointer data){
2399 (void) web_inspector;
2400 GtkWidget* scrolled_window;
2401 GtkWidget* new_web_view;
2404 g->inspector_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2405 g_signal_connect(G_OBJECT(g->inspector_window), "delete-event",
2406 G_CALLBACK(hide_window_cb), NULL);
2408 gtk_window_set_title(GTK_WINDOW(g->inspector_window), "Uzbl WebInspector");
2409 gtk_window_set_default_size(GTK_WINDOW(g->inspector_window), 400, 300);
2410 gtk_widget_show(g->inspector_window);
2412 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
2413 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
2414 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2415 gtk_container_add(GTK_CONTAINER(g->inspector_window), scrolled_window);
2416 gtk_widget_show(scrolled_window);
2418 new_web_view = webkit_web_view_new();
2419 gtk_container_add(GTK_CONTAINER(scrolled_window), new_web_view);
2421 return WEBKIT_WEB_VIEW(new_web_view);
2425 inspector_show_window_cb (WebKitWebInspector* inspector){
2427 gtk_widget_show(uzbl.gui.inspector_window);
2431 /* TODO: Add variables and code to make use of these functions */
2433 inspector_close_window_cb (WebKitWebInspector* inspector){
2439 inspector_attach_window_cb (WebKitWebInspector* inspector){
2445 inspector_detach_window_cb (WebKitWebInspector* inspector){
2451 inspector_uri_changed_cb (WebKitWebInspector* inspector){
2457 inspector_inspector_destroyed_cb (WebKitWebInspector* inspector){
2463 set_up_inspector() {
2465 WebKitWebSettings *settings = view_settings();
2466 g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
2468 uzbl.gui.inspector = webkit_web_view_get_inspector(uzbl.gui.web_view);
2469 g_signal_connect (G_OBJECT (g->inspector), "inspect-web-view", G_CALLBACK (create_inspector_cb), NULL);
2470 g_signal_connect (G_OBJECT (g->inspector), "show-window", G_CALLBACK (inspector_show_window_cb), NULL);
2471 g_signal_connect (G_OBJECT (g->inspector), "close-window", G_CALLBACK (inspector_close_window_cb), NULL);
2472 g_signal_connect (G_OBJECT (g->inspector), "attach-window", G_CALLBACK (inspector_attach_window_cb), NULL);
2473 g_signal_connect (G_OBJECT (g->inspector), "detach-window", G_CALLBACK (inspector_detach_window_cb), NULL);
2474 g_signal_connect (G_OBJECT (g->inspector), "finished", G_CALLBACK (inspector_inspector_destroyed_cb), NULL);
2476 g_signal_connect (G_OBJECT (g->inspector), "notify::inspected-uri", G_CALLBACK (inspector_uri_changed_cb), NULL);
2480 dump_var_hash(gpointer k, gpointer v, gpointer ud) {
2482 uzbl_cmdprop *c = v;
2487 if(c->type == TYPE_STR)
2488 printf("set %s = %s\n", (char *)k, *c->ptr?(char *)*c->ptr:" ");
2489 else if(c->type == TYPE_INT)
2490 printf("set %s = %d\n", (char *)k, (int)*c->ptr);
2494 dump_key_hash(gpointer k, gpointer v, gpointer ud) {
2498 printf("bind %s = %s %s\n", (char *)k ,
2499 (char *)a->name, a->param?(char *)a->param:"");
2504 g_hash_table_foreach(uzbl.comm.proto_var, dump_var_hash, NULL);
2505 g_hash_table_foreach(uzbl.bindings, dump_key_hash, NULL);
2510 main (int argc, char* argv[]) {
2511 gtk_init (&argc, &argv);
2512 if (!g_thread_supported ())
2513 g_thread_init (NULL);
2514 uzbl.state.executable_path = g_strdup(argv[0]);
2515 uzbl.state.selected_url = NULL;
2516 uzbl.state.searchtx = NULL;
2518 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
2519 g_option_context_add_main_entries (context, entries, NULL);
2520 g_option_context_add_group (context, gtk_get_option_group (TRUE));
2521 g_option_context_parse (context, &argc, &argv, NULL);
2522 g_option_context_free(context);
2524 gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL);
2525 gboolean verbose_override = uzbl.state.verbose;
2527 /* initialize hash table */
2528 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
2530 uzbl.net.soup_session = webkit_get_default_session();
2531 uzbl.state.keycmd = g_string_new("");
2533 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
2534 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
2535 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
2536 fprintf(stderr, "uzbl: error hooking SIGINT\n");
2537 if(setup_signal(SIGALRM, catch_alrm) == SIG_ERR)
2538 fprintf(stderr, "uzbl: error hooking SIGALARM\n");
2541 if(uname(&uzbl.state.unameinfo) == -1)
2542 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
2544 uzbl.gui.sbar.progress_s = g_strdup("=");
2545 uzbl.gui.sbar.progress_u = g_strdup("ยท");
2546 uzbl.gui.sbar.progress_w = 10;
2548 /* HTML mode defaults*/
2549 uzbl.behave.html_buffer = g_string_new("");
2550 uzbl.behave.html_endmarker = g_strdup(".");
2551 uzbl.behave.html_timeout = 60;
2552 uzbl.behave.base_url = g_strdup("http://invalid");
2554 /* default mode indicators */
2555 uzbl.behave.insert_indicator = g_strdup("I");
2556 uzbl.behave.cmd_indicator = g_strdup("C");
2560 make_var_to_name_hash();
2562 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
2564 uzbl.gui.scrolled_win = create_browser();
2567 /* initial packing */
2568 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
2569 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
2571 if (uzbl.state.socket_id) {
2572 uzbl.gui.plug = create_plug ();
2573 gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox);
2574 gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug));
2576 uzbl.gui.main_window = create_window ();
2577 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
2578 gtk_widget_show_all (uzbl.gui.main_window);
2579 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
2582 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
2584 if (uzbl.state.verbose) {
2585 printf("Uzbl start location: %s\n", argv[0]);
2586 if (uzbl.state.socket_id)
2587 printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug));
2589 printf("window_id %i\n",(int) uzbl.xwin);
2590 printf("pid %i\n", getpid ());
2591 printf("name: %s\n", uzbl.state.instance_name);
2594 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
2595 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
2596 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
2597 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
2598 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
2602 if (!uzbl.behave.show_status)
2603 gtk_widget_hide(uzbl.gui.mainbar);
2612 if (verbose_override > uzbl.state.verbose)
2613 uzbl.state.verbose = verbose_override;
2616 set_var_value("uri", uri_override);
2617 g_free(uri_override);
2618 } else if (uzbl.state.uri)
2619 cmd_load_uri(uzbl.gui.web_view, NULL);
2624 return EXIT_SUCCESS;
2627 /* vi: set et ts=4: */