1 /* -*- c-basic-offset: 4; -*- */
2 // Original code taken from the example webkit-gtk+ application. see notice below.
3 // Modified code is licensed under the GPL 3. See LICENSE file.
7 * Copyright (C) 2006, 2007 Apple Inc.
8 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
27 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #define LENGTH(x) (sizeof x / sizeof x[0])
34 #define MAX_BINDINGS 256
38 #include <gdk/gdkkeysyms.h>
39 #include <sys/socket.h>
41 #include <sys/types.h>
43 #include <sys/utsname.h>
44 #include <webkit/webkit.h>
52 #include <sys/socket.h>
54 #include <libsoup/soup.h>
61 /* define names and pointers to all config specific variables */
65 } var_name_to_ptr[] = {
66 { "uri", (void *)&uzbl.state.uri },
67 { "status_message", (void *)&uzbl.gui.sbar.msg },
68 { "show_status", (void *)&uzbl.behave.show_status },
69 { "status_top", (void *)&uzbl.behave.status_top },
70 { "status_format", (void *)&uzbl.behave.status_format },
71 { "status_background", (void *)&uzbl.behave.status_background },
72 { "insert_mode", (void *)&uzbl.behave.insert_mode },
73 { "always_insert_mode", (void *)&uzbl.behave.always_insert_mode },
74 { "reset_command_mode", (void *)&uzbl.behave.reset_command_mode },
75 { "modkey" , (void *)&uzbl.behave.modkey },
76 { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler},
77 { "history_handler", (void *)&uzbl.behave.history_handler },
78 { "download_handler", (void *)&uzbl.behave.download_handler },
79 { "cookie_handler", (void *)&uzbl.behave.cookie_handler },
80 { "fifo_dir", (void *)&uzbl.behave.fifo_dir },
81 { "socket_dir", (void *)&uzbl.behave.socket_dir },
82 { "http_debug", (void *)&uzbl.behave.http_debug },
83 { "default_font_size", (void *)&uzbl.behave.default_font_size },
84 { "minimum_font_size", (void *)&uzbl.behave.minimum_font_size },
85 { "shell_cmd", (void *)&uzbl.behave.shell_cmd },
86 { "proxy_url", (void *)&uzbl.net.proxy_url },
87 { "max_conns", (void *)&uzbl.net.max_conns },
88 { "max_conns_host", (void *)&uzbl.net.max_conns_host },
89 { "useragent", (void *)&uzbl.net.useragent },
91 }, *n2v_p = var_name_to_ptr;
97 { "SHIFT", GDK_SHIFT_MASK }, // shift
98 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
99 { "CONTROL", GDK_CONTROL_MASK }, // control
100 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
101 { "MOD2", GDK_MOD2_MASK }, // 5th mod
102 { "MOD3", GDK_MOD3_MASK }, // 6th mod
103 { "MOD4", GDK_MOD4_MASK }, // 7th mod
104 { "MOD5", GDK_MOD5_MASK }, // 8th mod
105 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
106 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
107 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
108 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
109 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
110 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
111 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
112 { "META", GDK_META_MASK }, // meta (since 2.10)
116 /* construct a hash from the var_name_to_ptr array for quick access */
118 make_var_to_name_hash() {
119 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
121 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
126 /* commandline arguments (set initial values for the state variables) */
127 static GOptionEntry entries[] =
129 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
130 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", "VERBOSE" },
131 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" },
132 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
133 { NULL, 0, 0, 0, NULL, NULL, NULL }
136 typedef void (*Command)(WebKitWebView*, const char *);
139 static char *XDG_CONFIG_HOME_default[256];
140 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
143 /* --- UTILITY FUNCTIONS --- */
149 snprintf(tmp, sizeof(tmp), "%i", val);
150 return g_strdup(tmp);
154 str_replace (const char* search, const char* replace, const char* string) {
155 return g_strjoinv (replace, g_strsplit (string, search, -1));
159 setup_signal(int signr, sigfunc *shandler) {
160 struct sigaction nh, oh;
162 nh.sa_handler = shandler;
163 sigemptyset(&nh.sa_mask);
166 if(sigaction(signr, &nh, &oh) < 0)
174 if (uzbl.behave.fifo_dir)
175 unlink (uzbl.comm.fifo_path);
176 if (uzbl.behave.socket_dir)
177 unlink (uzbl.comm.socket_path);
179 g_string_free(uzbl.state.keycmd, TRUE);
180 g_hash_table_destroy(uzbl.bindings);
181 g_hash_table_destroy(uzbl.behave.commands);
185 /* --- SIGNAL HANDLER --- */
188 catch_sigterm(int s) {
194 catch_sigint(int s) {
200 /* --- CALLBACKS --- */
203 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
206 (void) navigation_action;
207 (void) policy_decision;
209 const gchar* uri = webkit_network_request_get_uri (request);
210 if (uzbl.state.verbose)
211 printf("New window requested -> %s \n", uri);
212 new_window_load_uri(uri);
217 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
221 if (uzbl.state.selected_url[0]!=0) {
222 if (uzbl.state.verbose)
223 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
224 new_window_load_uri(uzbl.state.selected_url);
226 if (uzbl.state.verbose)
227 printf("New web view -> %s\n","Nothing to open, exiting");
233 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
236 if (uzbl.behave.download_handler) {
237 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
238 if (uzbl.state.verbose)
239 printf("Download -> %s\n",uri);
240 run_command(uzbl.behave.download_handler, uri, FALSE, NULL);
245 /* scroll a bar in a given direction */
247 scroll (GtkAdjustment* bar, const char *param) {
251 amount = g_ascii_strtod(param, &end);
254 fprintf(stderr, "found something after double: %s\n", end);
256 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
259 static void scroll_begin(WebKitWebView* page, const char *param) {
260 (void) page; (void) param;
261 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
264 static void scroll_end(WebKitWebView* page, const char *param) {
265 (void) page; (void) param;
266 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
267 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
270 static void scroll_vert(WebKitWebView* page, const char *param) {
272 scroll(uzbl.gui.bar_v, param);
275 static void scroll_horz(WebKitWebView* page, const char *param) {
277 scroll(uzbl.gui.bar_h, param);
282 if (!uzbl.behave.show_status) {
283 gtk_widget_hide(uzbl.gui.mainbar);
285 gtk_widget_show(uzbl.gui.mainbar);
291 toggle_status_cb (WebKitWebView* page, const char *param) {
295 if (uzbl.behave.show_status) {
296 gtk_widget_hide(uzbl.gui.mainbar);
298 gtk_widget_show(uzbl.gui.mainbar);
300 uzbl.behave.show_status = !uzbl.behave.show_status;
305 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
309 //ADD HOVER URL TO WINDOW TITLE
310 uzbl.state.selected_url[0] = '\0';
312 strcpy (uzbl.state.selected_url, link);
318 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
322 if (uzbl.gui.main_title)
323 g_free (uzbl.gui.main_title);
324 uzbl.gui.main_title = g_strdup (title);
329 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
332 uzbl.gui.sbar.load_progress = progress;
337 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
341 if (uzbl.behave.load_finish_handler) {
342 run_command(uzbl.behave.load_finish_handler, NULL, FALSE, NULL);
347 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
350 free (uzbl.state.uri);
351 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
352 uzbl.state.uri = g_string_free (newuri, FALSE);
353 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
354 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
357 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
361 destroy_cb (GtkWidget* widget, gpointer data) {
369 if (uzbl.behave.history_handler) {
371 struct tm * timeinfo;
374 timeinfo = localtime ( &rawtime );
375 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
376 GString* args = g_string_new ("");
377 g_string_printf (args, "'%s'", date);
378 run_command(uzbl.behave.history_handler, args->str, FALSE, NULL);
379 g_string_free (args, TRUE);
384 /* VIEW funcs (little webkit wrappers) */
385 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
387 VIEWFUNC(reload_bypass_cache)
388 VIEWFUNC(stop_loading)
395 /* -- command to callback/function map for things we cannot attach to any signals */
398 static struct {char *name; Command command;} cmdlist[] =
400 { "back", view_go_back },
401 { "forward", view_go_forward },
402 { "scroll_vert", scroll_vert },
403 { "scroll_horz", scroll_horz },
404 { "scroll_begin", scroll_begin },
405 { "scroll_end", scroll_end },
406 { "reload", view_reload, },
407 { "reload_ign_cache", view_reload_bypass_cache},
408 { "stop", view_stop_loading, },
409 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
410 { "zoom_out", view_zoom_out, },
412 { "script", run_js },
413 { "toggle_status", toggle_status_cb },
416 { "exit", close_uzbl },
417 { "search", search_text },
418 { "insert_mode", set_insert_mode },
426 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
428 for (i = 0; i < LENGTH(cmdlist); i++)
429 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
432 /* -- CORE FUNCTIONS -- */
435 free_action(gpointer act) {
436 Action *action = (Action*)act;
437 g_free(action->name);
439 g_free(action->param);
444 new_action(const gchar *name, const gchar *param) {
445 Action *action = g_new(Action, 1);
447 action->name = g_strdup(name);
449 action->param = g_strdup(param);
451 action->param = NULL;
457 file_exists (const char * filename) {
458 return (access(filename, F_OK) == 0);
462 set_insert_mode(WebKitWebView *page, const gchar *param) {
466 uzbl.behave.insert_mode = TRUE;
471 load_uri (WebKitWebView * web_view, const gchar *param) {
473 GString* newuri = g_string_new (param);
474 if (g_strrstr (param, "://") == NULL)
475 g_string_prepend (newuri, "http://");
476 /* if we do handle cookies, ask our handler for them */
477 webkit_web_view_load_uri (web_view, newuri->str);
478 g_string_free (newuri, TRUE);
483 run_js (WebKitWebView * web_view, const gchar *param) {
485 webkit_web_view_execute_script (web_view, param);
489 search_text (WebKitWebView *page, const char *param) {
490 if ((param) && (param[0] != '\0')) {
491 strcpy(uzbl.state.searchtx, param);
493 if (uzbl.state.searchtx[0] != '\0') {
494 if (uzbl.state.verbose)
495 printf ("Searching: %s\n", uzbl.state.searchtx);
496 webkit_web_view_unmark_text_matches (page);
497 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
498 webkit_web_view_set_highlight_text_matches (page, TRUE);
499 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
504 new_window_load_uri (const gchar * uri) {
505 GString* to_execute = g_string_new ("");
506 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
508 for (i = 0; entries[i].long_name != NULL; i++) {
509 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
510 gchar** str = (gchar**)entries[i].arg_data;
512 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
516 if (uzbl.state.verbose)
517 printf("\n%s\n", to_execute->str);
518 g_spawn_command_line_async (to_execute->str, NULL);
519 g_string_free (to_execute, TRUE);
523 close_uzbl (WebKitWebView *page, const char *param) {
529 /* --Statusbar functions-- */
531 build_progressbar_ascii(int percent) {
535 GString *bar = g_string_new("");
537 l = (double)percent*((double)width/100.);
538 l = (int)(l+.5)>=(int)l ? l+.5 : l;
540 for(i=0; i<(int)l; i++)
541 g_string_append(bar, "=");
544 g_string_append(bar, "·");
546 return g_string_free(bar, FALSE);
551 const GScannerConfig scan_config = {
554 ) /* cset_skip_characters */,
559 ) /* cset_identifier_first */,
566 ) /* cset_identifier_nth */,
567 ( "" ) /* cpair_comment_single */,
569 TRUE /* case_sensitive */,
571 FALSE /* skip_comment_multi */,
572 FALSE /* skip_comment_single */,
573 FALSE /* scan_comment_multi */,
574 TRUE /* scan_identifier */,
575 TRUE /* scan_identifier_1char */,
576 FALSE /* scan_identifier_NULL */,
577 TRUE /* scan_symbols */,
578 FALSE /* scan_binary */,
579 FALSE /* scan_octal */,
580 FALSE /* scan_float */,
581 FALSE /* scan_hex */,
582 FALSE /* scan_hex_dollar */,
583 FALSE /* scan_string_sq */,
584 FALSE /* scan_string_dq */,
585 TRUE /* numbers_2_int */,
586 FALSE /* int_2_float */,
587 FALSE /* identifier_2_string */,
588 FALSE /* char_2_token */,
589 FALSE /* symbol_2_token */,
590 TRUE /* scope_0_fallback */,
595 uzbl.scan = g_scanner_new(&scan_config);
596 while(symp->symbol_name) {
597 g_scanner_scope_add_symbol(uzbl.scan, 0,
599 GINT_TO_POINTER(symp->symbol_token));
605 expand_template(const char *template) {
606 if(!template) return NULL;
608 GTokenType token = G_TOKEN_NONE;
609 GString *ret = g_string_new("");
613 g_scanner_input_text(uzbl.scan, template, strlen(template));
614 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
615 token = g_scanner_get_next_token(uzbl.scan);
617 if(token == G_TOKEN_SYMBOL) {
618 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
623 g_markup_printf_escaped("%s", uzbl.state.uri):"");
626 buf = itos(uzbl.gui.sbar.load_progress);
627 g_string_append(ret, buf);
630 case SYM_LOADPRGSBAR:
631 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
632 g_string_append(ret, buf);
638 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
641 buf = itos(uzbl.xwin);
643 uzbl.state.instance_name?uzbl.state.instance_name:buf);
648 uzbl.state.keycmd->str ?
649 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
653 uzbl.behave.insert_mode?"[I]":"[C]");
657 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
661 buf = itos(WEBKIT_MAJOR_VERSION);
662 g_string_append(ret, buf);
666 buf = itos(WEBKIT_MINOR_VERSION);
667 g_string_append(ret, buf);
671 buf = itos(WEBKIT_MICRO_VERSION);
672 g_string_append(ret, buf);
676 g_string_append(ret, uzbl.state.unameinfo.sysname);
679 g_string_append(ret, uzbl.state.unameinfo.nodename);
682 g_string_append(ret, uzbl.state.unameinfo.release);
685 g_string_append(ret, uzbl.state.unameinfo.version);
688 g_string_append(ret, uzbl.state.unameinfo.machine);
691 g_string_append(ret, ARCH);
695 g_string_append(ret, uzbl.state.unameinfo.domainname);
699 g_string_append(ret, COMMIT);
705 else if(token == G_TOKEN_INT) {
706 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
707 g_string_append(ret, buf);
710 else if(token == G_TOKEN_IDENTIFIER) {
711 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
713 else if(token == G_TOKEN_CHAR) {
714 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
718 return g_string_free(ret, FALSE);
720 /* --End Statusbar functions-- */
723 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
725 run_command (const char *command, const char *args, const gboolean sync, char **stdout) {
726 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
727 GString *to_execute = g_string_new ("");
729 gchar *cmd = g_strstrip(g_strdup(command));
730 gchar *qcfg = (uzbl.state.config_file ? g_shell_quote(uzbl.state.config_file) : g_strdup("''"));
731 gchar *qfifo = (uzbl.comm.fifo_path ? g_shell_quote(uzbl.comm.fifo_path) : g_strdup("''"));
732 gchar *qsock = (uzbl.comm.socket_path ? g_shell_quote(uzbl.comm.socket_path) : g_strdup("''"));
733 gchar *quri = (uzbl.state.uri ? g_shell_quote(uzbl.state.uri) : g_strdup("''"));
734 gchar *qtitle = (uzbl.gui.main_title ? g_shell_quote(uzbl.gui.main_title) : g_strdup("''"));
737 g_string_printf (to_execute, "%s %s '%i' '%i' %s %s",
738 cmd, qcfg, (int) getpid(), (int) uzbl.xwin, qfifo, qsock);
739 g_string_append_printf (to_execute, " %s %s", quri, qtitle);
740 if(args) g_string_append_printf (to_execute, " %s", args);
743 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, &err);
744 } else result = g_spawn_command_line_async (to_execute->str, &err);
745 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
746 g_string_free (to_execute, TRUE);
748 g_printerr("error on run_command: %s\n", err->message);
762 spawn(WebKitWebView *web_view, const char *param) {
764 run_command(param, NULL, FALSE, NULL);
768 spawn_sh(WebKitWebView *web_view, const char *param) {
770 gchar *cmd = g_strdup_printf(uzbl.behave.shell_cmd, param);
776 parse_command(const char *cmd, const char *param) {
779 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
780 c(uzbl.gui.web_view, param);
782 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
788 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
789 G_REGEX_OPTIMIZE, 0, NULL);
790 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
791 G_REGEX_OPTIMIZE, 0, NULL);
792 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
793 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
794 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
795 G_REGEX_OPTIMIZE, 0, NULL);
796 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
797 G_REGEX_OPTIMIZE, 0, NULL);
801 get_var_value(gchar *name) {
804 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
805 if(var_is("status_format", name)
806 || var_is("useragent", name)) {
807 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
808 } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
817 if(*uzbl.net.proxy_url == ' '
818 || uzbl.net.proxy_url == NULL) {
819 soup_session_remove_feature_by_type(uzbl.net.soup_session,
820 (GType) SOUP_SESSION_PROXY_URI);
823 suri = soup_uri_new(uzbl.net.proxy_url);
824 g_object_set(G_OBJECT(uzbl.net.soup_session),
825 SOUP_SESSION_PROXY_URI,
835 gtk_widget_ref(uzbl.gui.scrolled_win);
836 gtk_widget_ref(uzbl.gui.mainbar);
837 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
838 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
840 if(uzbl.behave.status_top) {
841 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
842 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
845 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
846 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
848 gtk_widget_unref(uzbl.gui.scrolled_win);
849 gtk_widget_unref(uzbl.gui.mainbar);
850 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
854 var_is(const char *x, const char *y) {
855 return (strcmp(x, y) == 0 ? TRUE : FALSE );
859 set_var_value(gchar *name, gchar *val) {
863 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
864 if(var_is("status_message", name)
865 || var_is("status_background", name)
866 || var_is("status_format", name)
867 || var_is("load_finish_handler", name)
868 || var_is("history_handler", name)
869 || var_is("download_handler", name)
870 || var_is("cookie_handler", name)) {
876 else if(var_is("uri", name)) {
879 load_uri(uzbl.gui.web_view, (const gchar*)*p);
881 else if(var_is("proxy_url", name)) {
886 else if(var_is("fifo_dir", name)) {
888 *p = init_fifo(g_strdup(val));
890 else if(var_is("socket_dir", name)) {
892 *p = init_socket(g_strdup(val));
894 else if(var_is("modkey", name)) {
897 *p = g_utf8_strup(val, -1);
898 uzbl.behave.modmask = 0;
899 for (i = 0; modkeys[i].key != NULL; i++) {
900 if (g_strrstr(*p, modkeys[i].key))
901 uzbl.behave.modmask |= modkeys[i].mask;
904 else if(var_is("useragent", name)) {
906 *p = set_useragent(g_strdup(val));
908 else if(var_is("shell_cmd", name)) {
912 /* variables that take int values */
915 *ip = (int)strtoul(val, &endp, 10);
917 if(var_is("show_status", name)) {
920 else if(var_is("always_insert_mode", name)) {
921 uzbl.behave.insert_mode =
922 uzbl.behave.always_insert_mode ? TRUE : FALSE;
925 else if (var_is("max_conns", name)) {
926 g_object_set(G_OBJECT(uzbl.net.soup_session),
927 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
929 else if (var_is("max_conns_host", name)) {
930 g_object_set(G_OBJECT(uzbl.net.soup_session),
931 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
933 else if (var_is("http_debug", name)) {
934 //soup_session_remove_feature
935 // (uzbl.net.soup_session, uzbl.net.soup_logger);
936 soup_session_remove_feature
937 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
938 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
939 /*g_free(uzbl.net.soup_logger);*/
941 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
942 soup_session_add_feature(uzbl.net.soup_session,
943 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
945 else if (var_is("status_top", name)) {
948 else if (var_is("default_font_size", name)) {
949 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
950 g_object_set (G_OBJECT(ws), "default-font-size", *ip, NULL);
952 else if (var_is("minimum_font_size", name)) {
953 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
954 g_object_set (G_OBJECT(ws), "minimum-font-size", *ip, NULL);
962 runcmd(WebKitWebView* page, const char *param) {
964 parse_cmd_line(param);
968 parse_cmd_line(const char *ctl_line) {
972 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
973 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
974 if(tokens[0][0] == 0) {
975 set_var_value(tokens[1], tokens[2]);
979 printf("Error in command: %s\n", tokens[0]);
982 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
983 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
984 if(tokens[0][0] == 0) {
985 get_var_value(tokens[1]);
989 printf("Error in command: %s\n", tokens[0]);
992 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
993 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
994 if(tokens[0][0] == 0) {
995 add_binding(tokens[1], tokens[2]);
999 printf("Error in command: %s\n", tokens[0]);
1002 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1003 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1004 if(tokens[0][0] == 0) {
1005 parse_command(tokens[1], tokens[2]);
1009 printf("Error in command: %s\n", tokens[0]);
1011 /* KEYCMD command */
1012 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1013 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1014 if(tokens[0][0] == 0) {
1015 /* should incremental commands want each individual "keystroke"
1016 sent in a loop or the whole string in one go like now? */
1017 g_string_assign(uzbl.state.keycmd, tokens[1]);
1024 else if( (ctl_line[0] == '#')
1025 || (ctl_line[0] == ' ')
1026 || (ctl_line[0] == '\n'))
1027 ; /* ignore these lines */
1029 printf("Command not understood (%s)\n", ctl_line);
1035 build_stream_name(int type, const gchar* dir) {
1037 State *s = &uzbl.state;
1040 xwin_str = itos((int)uzbl.xwin);
1042 str = g_strdup_printf
1043 ("%s/uzbl_fifo_%s", dir,
1044 s->instance_name ? s->instance_name : xwin_str);
1045 } else if (type == SOCKET) {
1046 str = g_strdup_printf
1047 ("%s/uzbl_socket_%s", dir,
1048 s->instance_name ? s->instance_name : xwin_str );
1055 control_fifo(GIOChannel *gio, GIOCondition condition) {
1056 if (uzbl.state.verbose)
1057 printf("triggered\n");
1062 if (condition & G_IO_HUP)
1063 g_error ("Fifo: Read end of pipe died!\n");
1066 g_error ("Fifo: GIOChannel broke\n");
1068 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1069 if (ret == G_IO_STATUS_ERROR) {
1070 g_error ("Fifo: Error reading: %s\n", err->message);
1074 parse_cmd_line(ctl_line);
1081 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1082 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1083 if (unlink(uzbl.comm.fifo_path) == -1)
1084 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1085 g_free(uzbl.comm.fifo_path);
1086 uzbl.comm.fifo_path = NULL;
1089 if (*dir == ' ') { /* space unsets the variable */
1094 GIOChannel *chan = NULL;
1095 GError *error = NULL;
1096 gchar *path = build_stream_name(FIFO, dir);
1098 if (!file_exists(path)) {
1099 if (mkfifo (path, 0666) == 0) {
1100 // 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.
1101 chan = g_io_channel_new_file(path, "r+", &error);
1103 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1104 if (uzbl.state.verbose)
1105 printf ("init_fifo: created successfully as %s\n", path);
1106 uzbl.comm.fifo_path = path;
1108 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1109 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1110 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1111 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1113 /* if we got this far, there was an error; cleanup */
1114 if (error) g_error_free (error);
1121 control_stdin(GIOChannel *gio, GIOCondition condition) {
1122 gchar *ctl_line = NULL;
1123 gsize ctl_line_len = 0;
1126 if (condition & G_IO_HUP) {
1127 ret = g_io_channel_shutdown (gio, FALSE, NULL);
1131 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, NULL);
1132 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1135 parse_cmd_line(ctl_line);
1143 GIOChannel *chan = NULL;
1144 GError *error = NULL;
1146 chan = g_io_channel_unix_new(fileno(stdin));
1148 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1149 g_error ("Stdin: could not add watch\n");
1151 printf ("Stdin: watch added successfully\n");
1154 g_error ("Stdin: Error while opening: %s\n", error->message);
1156 if (error) g_error_free (error);
1160 control_socket(GIOChannel *chan) {
1161 struct sockaddr_un remote;
1162 char buffer[512], *ctl_line;
1164 int sock, clientsock, n, done;
1167 sock = g_io_channel_unix_get_fd(chan);
1169 memset (buffer, 0, sizeof (buffer));
1171 t = sizeof (remote);
1172 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1176 memset (temp, 0, sizeof (temp));
1177 n = recv (clientsock, temp, 128, 0);
1179 buffer[strlen (buffer)] = '\0';
1183 strcat (buffer, temp);
1186 if (strcmp (buffer, "\n") < 0) {
1187 buffer[strlen (buffer) - 1] = '\0';
1189 buffer[strlen (buffer)] = '\0';
1192 ctl_line = g_strdup(buffer);
1193 parse_cmd_line (ctl_line);
1196 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1197 GError *error = NULL;
1200 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1201 if (ret == G_IO_STATUS_ERROR)
1202 g_error ("Error reading: %s\n", error->message);
1204 printf("Got line %s (%u bytes) \n",ctl_line, len);
1206 parse_line(ctl_line);
1214 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1215 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1216 if (unlink(uzbl.comm.socket_path) == -1)
1217 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1218 g_free(uzbl.comm.socket_path);
1219 uzbl.comm.socket_path = NULL;
1227 GIOChannel *chan = NULL;
1229 struct sockaddr_un local;
1230 gchar *path = build_stream_name(SOCKET, dir);
1232 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1234 local.sun_family = AF_UNIX;
1235 strcpy (local.sun_path, path);
1236 unlink (local.sun_path);
1238 len = strlen (local.sun_path) + sizeof (local.sun_family);
1239 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1240 printf ("init_socket: opened in %s\n", path);
1243 if( (chan = g_io_channel_unix_new(sock)) ) {
1244 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1245 uzbl.comm.socket_path = path;
1248 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1250 /* if we got this far, there was an error; cleanup */
1257 update_title (void) {
1258 GString* string_long = g_string_new ("");
1259 GString* string_short = g_string_new ("");
1263 State *s = &uzbl.state;
1264 Behaviour *b = &uzbl.behave;
1266 if(s->instance_name) {
1267 iname_len = strlen(s->instance_name)+4;
1268 iname = malloc(iname_len);
1269 snprintf(iname, iname_len, "<%s> ", s->instance_name);
1271 g_string_prepend(string_long, iname);
1272 g_string_prepend(string_short, iname);
1276 g_string_append_printf(string_long, "%s ", s->keycmd->str);
1277 if (!b->always_insert_mode)
1278 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
1279 if (uzbl.gui.main_title) {
1280 g_string_append (string_long, uzbl.gui.main_title);
1281 g_string_append (string_short, uzbl.gui.main_title);
1283 g_string_append (string_long, " - Uzbl browser");
1284 g_string_append (string_short, " - Uzbl browser");
1285 if (s->selected_url[0]!=0) {
1286 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
1289 gchar* title_long = g_string_free (string_long, FALSE);
1290 gchar* title_short = g_string_free (string_short, FALSE);
1292 if (b->show_status) {
1293 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
1294 // TODO: we should probably not do this every time we want to update the title..?
1295 statln = expand_template(uzbl.behave.status_format);
1296 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1297 if (b->status_background) {
1299 gdk_color_parse (b->status_background, &color);
1300 //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)
1301 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1305 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
1308 g_free (title_long);
1309 g_free (title_short);
1313 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1315 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1319 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1320 || 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)
1323 /* turn off insert mode (if always_insert_mode is not used) */
1324 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1325 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1330 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1333 if (event->keyval == GDK_Escape) {
1334 g_string_truncate(uzbl.state.keycmd, 0);
1339 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1340 if (event->keyval == GDK_Insert) {
1342 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1343 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1345 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1348 g_string_append (uzbl.state.keycmd, str);
1355 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1356 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1360 gboolean key_ret = FALSE;
1361 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1363 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1365 run_keycmd(key_ret);
1367 if (key_ret) return (!uzbl.behave.insert_mode);
1372 run_keycmd(const gboolean key_ret) {
1373 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1375 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1376 g_string_truncate(uzbl.state.keycmd, 0);
1377 parse_command(action->name, action->param);
1381 /* try if it's an incremental keycmd or one that takes args, and run it */
1382 GString* short_keys = g_string_new ("");
1383 GString* short_keys_inc = g_string_new ("");
1385 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1386 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1387 g_string_assign(short_keys_inc, short_keys->str);
1388 g_string_append_c(short_keys, '_');
1389 g_string_append_c(short_keys_inc, '*');
1391 gboolean exec_now = FALSE;
1392 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1393 if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
1394 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1395 if (key_ret) { /* just quit the incremental command on return */
1396 g_string_truncate(uzbl.state.keycmd, 0);
1398 } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
1402 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1403 GString* actionname = g_string_new ("");
1404 GString* actionparam = g_string_new ("");
1405 g_string_erase (parampart, 0, i+1);
1407 g_string_printf (actionname, action->name, parampart->str);
1409 g_string_printf (actionparam, action->param, parampart->str);
1410 parse_command(actionname->str, actionparam->str);
1411 g_string_free (actionname, TRUE);
1412 g_string_free (actionparam, TRUE);
1413 g_string_free (parampart, TRUE);
1415 g_string_truncate(uzbl.state.keycmd, 0);
1419 g_string_truncate(short_keys, short_keys->len - 1);
1421 g_string_free (short_keys, TRUE);
1422 g_string_free (short_keys_inc, TRUE);
1429 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1430 //main_window_ref = g_object_ref(scrolled_window);
1431 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
1433 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1434 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1436 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1437 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1438 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1439 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1440 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1441 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1442 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1443 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1444 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1445 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1447 return scrolled_window;
1454 g->mainbar = gtk_hbox_new (FALSE, 0);
1456 /* keep a reference to the bar so we can re-pack it at runtime*/
1457 //sbar_ref = g_object_ref(g->mainbar);
1459 g->mainbar_label = gtk_label_new ("");
1460 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1461 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1462 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1463 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1464 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1469 GtkWidget* create_window () {
1470 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1471 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1472 gtk_widget_set_name (window, "Uzbl browser");
1473 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1479 add_binding (const gchar *key, const gchar *act) {
1480 char **parts = g_strsplit(act, " ", 2);
1487 if (uzbl.state.verbose)
1488 printf ("Binding %-10s : %s\n", key, act);
1489 action = new_action(parts[0], parts[1]);
1491 if(g_hash_table_lookup(uzbl.bindings, key))
1492 g_hash_table_remove(uzbl.bindings, key);
1493 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1499 get_xdg_var (XDG_Var xdg) {
1500 const gchar* actual_value = getenv (xdg.environmental);
1501 const gchar* home = getenv ("HOME");
1503 gchar* return_value = str_replace ("~", home, g_strdup (actual_value));
1505 if (! actual_value || strcmp (actual_value, "") == 0) {
1506 if (xdg.default_value) {
1507 return_value = str_replace ("~", home, g_strdup (xdg.default_value));
1509 return_value = NULL;
1513 return return_value;
1517 find_xdg_file (int xdg_type, char* filename) {
1518 /* xdg_type = 0 => config
1519 xdg_type = 1 => data
1520 xdg_type = 2 => cache*/
1522 gchar* xdg_config_home = get_xdg_var (XDG[0]);
1523 gchar* xdg_data_home = get_xdg_var (XDG[1]);
1524 gchar* xdg_cache_home = get_xdg_var (XDG[2]);
1525 gchar* xdg_config_dirs = get_xdg_var (XDG[3]);
1526 gchar* xdg_data_dirs = get_xdg_var (XDG[4]);
1527 gchar* temporary_file = (char *)malloc (1024);
1528 gchar* temporary_string = NULL;
1532 strcpy (temporary_file, xdg_config_home);
1535 strcpy (temporary_file, xdg_data_home);
1538 strcpy (temporary_file, xdg_cache_home);
1540 strcat (temporary_file, filename);
1542 if (! file_exists (temporary_file) && xdg_type != 2) {
1544 temporary_string = (char *) strtok_r (xdg_config_dirs, ":", &saveptr);
1547 temporary_string = (char *) strtok_r (xdg_data_dirs, ":", &saveptr);
1549 while (temporary_string && ! file_exists (temporary_file)) {
1550 strcpy (temporary_file, temporary_string);
1551 strcat (temporary_file, filename);
1552 temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
1556 if (file_exists (temporary_file)) {
1557 return temporary_file;
1566 State *s = &uzbl.state;
1567 Network *n = &uzbl.net;
1569 uzbl.behave.reset_command_mode = 1;
1571 if (!s->config_file) {
1572 s->config_file = g_strdup (find_xdg_file (0, "/uzbl/config"));
1575 if (s->config_file) {
1576 GIOChannel *chan = NULL;
1577 gchar *readbuf = NULL;
1580 chan = g_io_channel_new_file(s->config_file, "r", NULL);
1583 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
1584 == G_IO_STATUS_NORMAL) {
1585 parse_cmd_line(readbuf);
1589 g_io_channel_unref (chan);
1590 printf ("Config %s loaded\n", s->config_file);
1592 fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
1595 printf ("No configuration file loaded.\n");
1597 if (!uzbl.behave.status_format)
1598 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1600 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1604 set_useragent(gchar *val) {
1609 gchar *ua = expand_template(val);
1611 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1615 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1618 if (!uzbl.behave.cookie_handler) return;
1620 gchar * stdout = NULL;
1621 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1622 GString* args = g_string_new ("");
1623 SoupURI * soup_uri = soup_message_get_uri(msg);
1624 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1625 run_command(uzbl.behave.cookie_handler, args->str, TRUE, &stdout);
1627 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1629 g_string_free(args, TRUE);
1633 save_cookies (SoupMessage *msg, gpointer user_data){
1637 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1638 cookie = soup_cookie_to_set_cookie_header(ck->data);
1639 GString* args = g_string_new ("");
1640 SoupURI * soup_uri = soup_message_get_uri(msg);
1641 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1642 run_command(uzbl.behave.cookie_handler, args->str, FALSE, NULL);
1643 g_string_free(args, TRUE);
1651 main (int argc, char* argv[]) {
1652 gtk_init (&argc, &argv);
1653 if (!g_thread_supported ())
1654 g_thread_init (NULL);
1656 strcpy(uzbl.state.executable_path,argv[0]);
1658 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1659 g_option_context_add_main_entries (context, entries, NULL);
1660 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1661 g_option_context_parse (context, &argc, &argv, NULL);
1662 /* initialize hash table */
1663 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1665 uzbl.net.soup_session = webkit_get_default_session();
1666 uzbl.state.keycmd = g_string_new("");
1668 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1669 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1670 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
1671 fprintf(stderr, "uzbl: error hooking SIGINT\n");
1673 if(uname(&uzbl.state.unameinfo) == -1)
1674 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
1679 make_var_to_name_hash();
1682 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
1684 uzbl.gui.scrolled_win = create_browser();
1687 /* initial packing */
1688 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1689 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1691 uzbl.gui.main_window = create_window ();
1692 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
1694 load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
1696 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1697 gtk_widget_show_all (uzbl.gui.main_window);
1698 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1700 if (uzbl.state.verbose) {
1701 printf("Uzbl start location: %s\n", argv[0]);
1702 printf("window_id %i\n",(int) uzbl.xwin);
1703 printf("pid %i\n", getpid ());
1704 printf("name: %s\n", uzbl.state.instance_name);
1707 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1708 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1709 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1710 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1711 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1715 if (!uzbl.behave.show_status)
1716 gtk_widget_hide(uzbl.gui.mainbar);
1725 return EXIT_SUCCESS;
1728 /* vi: set et ts=4: */