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.", NULL },
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 *);
138 /* --- UTILITY FUNCTIONS --- */
144 snprintf(tmp, sizeof(tmp), "%i", val);
145 return g_strdup(tmp);
149 str_replace (const char* search, const char* replace, const char* string) {
150 return g_strjoinv (replace, g_strsplit (string, search, -1));
154 setup_signal(int signr, sigfunc *shandler) {
155 struct sigaction nh, oh;
157 nh.sa_handler = shandler;
158 sigemptyset(&nh.sa_mask);
161 if(sigaction(signr, &nh, &oh) < 0)
169 if (uzbl.behave.fifo_dir)
170 unlink (uzbl.comm.fifo_path);
171 if (uzbl.behave.socket_dir)
172 unlink (uzbl.comm.socket_path);
174 g_string_free(uzbl.state.keycmd, TRUE);
175 g_hash_table_destroy(uzbl.bindings);
176 g_hash_table_destroy(uzbl.behave.commands);
180 /* --- SIGNAL HANDLER --- */
183 catch_sigterm(int s) {
189 catch_sigint(int s) {
195 /* --- CALLBACKS --- */
198 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
201 (void) navigation_action;
202 (void) policy_decision;
204 const gchar* uri = webkit_network_request_get_uri (request);
205 if (uzbl.state.verbose)
206 printf("New window requested -> %s \n", uri);
207 new_window_load_uri(uri);
212 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
216 if (uzbl.state.selected_url[0]!=0) {
217 if (uzbl.state.verbose)
218 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
219 new_window_load_uri(uzbl.state.selected_url);
221 if (uzbl.state.verbose)
222 printf("New web view -> %s\n","Nothing to open, exiting");
228 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
231 if (uzbl.behave.download_handler) {
232 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
233 if (uzbl.state.verbose)
234 printf("Download -> %s\n",uri);
235 run_command(uzbl.behave.download_handler, uri, FALSE, NULL);
240 /* scroll a bar in a given direction */
242 scroll (GtkAdjustment* bar, const char *param) {
246 amount = g_ascii_strtod(param, &end);
249 fprintf(stderr, "found something after double: %s\n", end);
251 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
254 static void scroll_begin(WebKitWebView* page, const char *param) {
255 (void) page; (void) param;
256 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
259 static void scroll_end(WebKitWebView* page, const char *param) {
260 (void) page; (void) param;
261 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
262 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
265 static void scroll_vert(WebKitWebView* page, const char *param) {
267 scroll(uzbl.gui.bar_v, param);
270 static void scroll_horz(WebKitWebView* page, const char *param) {
272 scroll(uzbl.gui.bar_h, param);
277 if (!uzbl.behave.show_status) {
278 gtk_widget_hide(uzbl.gui.mainbar);
280 gtk_widget_show(uzbl.gui.mainbar);
286 toggle_status_cb (WebKitWebView* page, const char *param) {
290 if (uzbl.behave.show_status) {
291 gtk_widget_hide(uzbl.gui.mainbar);
293 gtk_widget_show(uzbl.gui.mainbar);
295 uzbl.behave.show_status = !uzbl.behave.show_status;
300 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
304 //ADD HOVER URL TO WINDOW TITLE
305 uzbl.state.selected_url[0] = '\0';
307 strcpy (uzbl.state.selected_url, link);
313 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
317 if (uzbl.gui.main_title)
318 g_free (uzbl.gui.main_title);
319 uzbl.gui.main_title = g_strdup (title);
324 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
327 uzbl.gui.sbar.load_progress = progress;
332 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
336 if (uzbl.behave.load_finish_handler) {
337 run_command(uzbl.behave.load_finish_handler, NULL, FALSE, NULL);
342 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
345 free (uzbl.state.uri);
346 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
347 uzbl.state.uri = g_string_free (newuri, FALSE);
348 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
349 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
352 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
356 destroy_cb (GtkWidget* widget, gpointer data) {
364 if (uzbl.behave.history_handler) {
366 struct tm * timeinfo;
369 timeinfo = localtime ( &rawtime );
370 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
371 GString* args = g_string_new ("");
372 g_string_printf (args, "'%s'", date);
373 run_command(uzbl.behave.history_handler, args->str, FALSE, NULL);
374 g_string_free (args, TRUE);
379 /* VIEW funcs (little webkit wrappers) */
380 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
382 VIEWFUNC(reload_bypass_cache)
383 VIEWFUNC(stop_loading)
390 /* -- command to callback/function map for things we cannot attach to any signals */
393 static struct {char *name; Command command;} cmdlist[] =
395 { "back", view_go_back },
396 { "forward", view_go_forward },
397 { "scroll_vert", scroll_vert },
398 { "scroll_horz", scroll_horz },
399 { "scroll_begin", scroll_begin },
400 { "scroll_end", scroll_end },
401 { "reload", view_reload, },
402 { "reload_ign_cache", view_reload_bypass_cache},
403 { "stop", view_stop_loading, },
404 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
405 { "zoom_out", view_zoom_out, },
407 { "script", run_js },
408 { "toggle_status", toggle_status_cb },
411 { "exit", close_uzbl },
412 { "search", search_text },
413 { "insert_mode", set_insert_mode },
421 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
423 for (i = 0; i < LENGTH(cmdlist); i++)
424 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
427 /* -- CORE FUNCTIONS -- */
430 free_action(gpointer act) {
431 Action *action = (Action*)act;
432 g_free(action->name);
434 g_free(action->param);
439 new_action(const gchar *name, const gchar *param) {
440 Action *action = g_new(Action, 1);
442 action->name = g_strdup(name);
444 action->param = g_strdup(param);
446 action->param = NULL;
452 file_exists (const char * filename) {
453 return (access(filename, F_OK) == 0);
457 set_insert_mode(WebKitWebView *page, const gchar *param) {
461 uzbl.behave.insert_mode = TRUE;
466 load_uri (WebKitWebView * web_view, const gchar *param) {
468 GString* newuri = g_string_new (param);
469 if (g_strrstr (param, "://") == NULL)
470 g_string_prepend (newuri, "http://");
471 /* if we do handle cookies, ask our handler for them */
472 webkit_web_view_load_uri (web_view, newuri->str);
473 g_string_free (newuri, TRUE);
478 run_js (WebKitWebView * web_view, const gchar *param) {
480 webkit_web_view_execute_script (web_view, param);
484 search_text (WebKitWebView *page, const char *param) {
485 if ((param) && (param[0] != '\0')) {
486 strcpy(uzbl.state.searchtx, param);
488 if (uzbl.state.searchtx[0] != '\0') {
489 if (uzbl.state.verbose)
490 printf ("Searching: %s\n", uzbl.state.searchtx);
491 webkit_web_view_unmark_text_matches (page);
492 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
493 webkit_web_view_set_highlight_text_matches (page, TRUE);
494 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
499 new_window_load_uri (const gchar * uri) {
500 GString* to_execute = g_string_new ("");
501 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
503 for (i = 0; entries[i].long_name != NULL; i++) {
504 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
505 gchar** str = (gchar**)entries[i].arg_data;
507 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
511 if (uzbl.state.verbose)
512 printf("\n%s\n", to_execute->str);
513 g_spawn_command_line_async (to_execute->str, NULL);
514 g_string_free (to_execute, TRUE);
518 close_uzbl (WebKitWebView *page, const char *param) {
524 /* --Statusbar functions-- */
526 build_progressbar_ascii(int percent) {
530 GString *bar = g_string_new("");
532 l = (double)percent*((double)width/100.);
533 l = (int)(l+.5)>=(int)l ? l+.5 : l;
535 for(i=0; i<(int)l; i++)
536 g_string_append(bar, "=");
539 g_string_append(bar, "·");
541 return g_string_free(bar, FALSE);
546 const GScannerConfig scan_config = {
549 ) /* cset_skip_characters */,
554 ) /* cset_identifier_first */,
561 ) /* cset_identifier_nth */,
562 ( "" ) /* cpair_comment_single */,
564 TRUE /* case_sensitive */,
566 FALSE /* skip_comment_multi */,
567 FALSE /* skip_comment_single */,
568 FALSE /* scan_comment_multi */,
569 TRUE /* scan_identifier */,
570 TRUE /* scan_identifier_1char */,
571 FALSE /* scan_identifier_NULL */,
572 TRUE /* scan_symbols */,
573 FALSE /* scan_binary */,
574 FALSE /* scan_octal */,
575 FALSE /* scan_float */,
576 FALSE /* scan_hex */,
577 FALSE /* scan_hex_dollar */,
578 FALSE /* scan_string_sq */,
579 FALSE /* scan_string_dq */,
580 TRUE /* numbers_2_int */,
581 FALSE /* int_2_float */,
582 FALSE /* identifier_2_string */,
583 FALSE /* char_2_token */,
584 FALSE /* symbol_2_token */,
585 TRUE /* scope_0_fallback */,
590 uzbl.scan = g_scanner_new(&scan_config);
591 while(symp->symbol_name) {
592 g_scanner_scope_add_symbol(uzbl.scan, 0,
594 GINT_TO_POINTER(symp->symbol_token));
600 expand_template(const char *template) {
601 if(!template) return NULL;
603 GTokenType token = G_TOKEN_NONE;
604 GString *ret = g_string_new("");
608 g_scanner_input_text(uzbl.scan, template, strlen(template));
609 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
610 token = g_scanner_get_next_token(uzbl.scan);
612 if(token == G_TOKEN_SYMBOL) {
613 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
618 g_markup_printf_escaped("%s", uzbl.state.uri):"");
621 buf = itos(uzbl.gui.sbar.load_progress);
622 g_string_append(ret, buf);
625 case SYM_LOADPRGSBAR:
626 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
627 g_string_append(ret, buf);
633 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
636 buf = itos(uzbl.xwin);
638 uzbl.state.instance_name?uzbl.state.instance_name:buf);
643 uzbl.state.keycmd->str ?
644 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
648 uzbl.behave.insert_mode?"[I]":"[C]");
652 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
656 buf = itos(WEBKIT_MAJOR_VERSION);
657 g_string_append(ret, buf);
661 buf = itos(WEBKIT_MINOR_VERSION);
662 g_string_append(ret, buf);
666 buf = itos(WEBKIT_MICRO_VERSION);
667 g_string_append(ret, buf);
671 g_string_append(ret, uzbl.state.unameinfo.sysname);
674 g_string_append(ret, uzbl.state.unameinfo.nodename);
677 g_string_append(ret, uzbl.state.unameinfo.release);
680 g_string_append(ret, uzbl.state.unameinfo.version);
683 g_string_append(ret, uzbl.state.unameinfo.machine);
686 g_string_append(ret, ARCH);
690 g_string_append(ret, uzbl.state.unameinfo.domainname);
694 g_string_append(ret, COMMIT);
700 else if(token == G_TOKEN_INT) {
701 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
702 g_string_append(ret, buf);
705 else if(token == G_TOKEN_IDENTIFIER) {
706 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
708 else if(token == G_TOKEN_CHAR) {
709 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
713 return g_string_free(ret, FALSE);
715 /* --End Statusbar functions-- */
718 // make sure to put "" or '' around args, so that if there is whitespace we can still keep arguments together.
719 // note: if your args contain ', you must wrap them in "" (you cannot escape inside '')
720 // if your args contain ", you should wrap them in "" and escape them
722 run_command (const char *command, const char *args, const gboolean sync, char **stdout) {
723 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
724 GString* to_execute = g_string_new ("");
726 gchar* cmd = g_strstrip(g_strdup(command));
728 const char* search = "\"";
729 const char* replace = "\\\"";
730 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
731 cmd, (uzbl.state.config_file ? uzbl.state.config_file : "(null)"),
732 (int) getpid(), (int) uzbl.xwin, uzbl.comm.fifo_path,
733 uzbl.comm.socket_path);
734 g_string_append_printf (to_execute, " \"%s\" \"%s\"",
736 str_replace(search, replace, uzbl.gui.main_title));
737 if(args) g_string_append_printf (to_execute, " %s", args);
740 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, &err);
741 } else result = g_spawn_command_line_async (to_execute->str, &err);
742 if (uzbl.state.verbose)
743 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
744 g_string_free (to_execute, TRUE);
746 g_printerr("error on run_command: %s\n", err->message);
754 spawn(WebKitWebView *web_view, const char *param) {
756 run_command(param, NULL, FALSE, NULL);
760 spawn_sh(WebKitWebView *web_view, const char *param) {
762 gchar *cmd = g_strdup_printf(uzbl.behave.shell_cmd, param);
768 parse_command(const char *cmd, const char *param) {
771 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
772 c(uzbl.gui.web_view, param);
774 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
780 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
781 G_REGEX_OPTIMIZE, 0, NULL);
782 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
783 G_REGEX_OPTIMIZE, 0, NULL);
784 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
785 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
786 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
787 G_REGEX_OPTIMIZE, 0, NULL);
788 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
789 G_REGEX_OPTIMIZE, 0, NULL);
793 get_var_value(gchar *name) {
796 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
797 if(var_is("status_format", name)
798 || var_is("useragent", name)) {
799 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
800 } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
809 if(*uzbl.net.proxy_url == ' '
810 || uzbl.net.proxy_url == NULL) {
811 soup_session_remove_feature_by_type(uzbl.net.soup_session,
812 (GType) SOUP_SESSION_PROXY_URI);
815 suri = soup_uri_new(uzbl.net.proxy_url);
816 g_object_set(G_OBJECT(uzbl.net.soup_session),
817 SOUP_SESSION_PROXY_URI,
827 gtk_widget_ref(uzbl.gui.scrolled_win);
828 gtk_widget_ref(uzbl.gui.mainbar);
829 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
830 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
832 if(uzbl.behave.status_top) {
833 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
834 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
837 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
838 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
840 gtk_widget_unref(uzbl.gui.scrolled_win);
841 gtk_widget_unref(uzbl.gui.mainbar);
842 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
846 var_is(const char *x, const char *y) {
847 return (strcmp(x, y) == 0 ? TRUE : FALSE );
851 set_var_value(gchar *name, gchar *val) {
855 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
856 if(var_is("status_message", name)
857 || var_is("status_background", name)
858 || var_is("status_format", name)
859 || var_is("load_finish_handler", name)
860 || var_is("history_handler", name)
861 || var_is("download_handler", name)
862 || var_is("cookie_handler", name)) {
868 else if(var_is("uri", name)) {
871 load_uri(uzbl.gui.web_view, (const gchar*)*p);
873 else if(var_is("proxy_url", name)) {
878 else if(var_is("fifo_dir", name)) {
880 *p = init_fifo(g_strdup(val));
882 else if(var_is("socket_dir", name)) {
884 *p = init_socket(g_strdup(val));
886 else if(var_is("modkey", name)) {
889 *p = g_utf8_strup(val, -1);
890 uzbl.behave.modmask = 0;
891 for (i = 0; modkeys[i].key != NULL; i++) {
892 if (g_strrstr(*p, modkeys[i].key))
893 uzbl.behave.modmask |= modkeys[i].mask;
896 else if(var_is("useragent", name)) {
898 *p = set_useragent(g_strdup(val));
900 else if(var_is("shell_cmd", name)) {
904 /* variables that take int values */
907 *ip = (int)strtoul(val, &endp, 10);
909 if(var_is("show_status", name)) {
912 else if(var_is("always_insert_mode", name)) {
913 uzbl.behave.insert_mode =
914 uzbl.behave.always_insert_mode ? TRUE : FALSE;
917 else if (var_is("max_conns", name)) {
918 g_object_set(G_OBJECT(uzbl.net.soup_session),
919 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
921 else if (var_is("max_conns_host", name)) {
922 g_object_set(G_OBJECT(uzbl.net.soup_session),
923 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
925 else if (var_is("http_debug", name)) {
926 //soup_session_remove_feature
927 // (uzbl.net.soup_session, uzbl.net.soup_logger);
928 soup_session_remove_feature
929 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
930 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
931 /*g_free(uzbl.net.soup_logger);*/
933 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
934 soup_session_add_feature(uzbl.net.soup_session,
935 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
937 else if (var_is("status_top", name)) {
940 else if (var_is("default_font_size", name)) {
941 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
942 g_object_set (G_OBJECT(ws), "default-font-size", *ip, NULL);
944 else if (var_is("minimum_font_size", name)) {
945 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
946 g_object_set (G_OBJECT(ws), "minimum-font-size", *ip, NULL);
954 runcmd(WebKitWebView* page, const char *param) {
956 parse_cmd_line(param);
960 parse_cmd_line(const char *ctl_line) {
964 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
965 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
966 if(tokens[0][0] == 0) {
967 set_var_value(tokens[1], tokens[2]);
971 printf("Error in command: %s\n", tokens[0]);
974 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
975 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
976 if(tokens[0][0] == 0) {
977 get_var_value(tokens[1]);
981 printf("Error in command: %s\n", tokens[0]);
984 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
985 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
986 if(tokens[0][0] == 0) {
987 add_binding(tokens[1], tokens[2]);
991 printf("Error in command: %s\n", tokens[0]);
994 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
995 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
996 if(tokens[0][0] == 0) {
997 parse_command(tokens[1], tokens[2]);
1001 printf("Error in command: %s\n", tokens[0]);
1003 /* KEYCMD command */
1004 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1005 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1006 if(tokens[0][0] == 0) {
1007 /* should incremental commands want each individual "keystroke"
1008 sent in a loop or the whole string in one go like now? */
1009 g_string_assign(uzbl.state.keycmd, tokens[1]);
1016 else if( (ctl_line[0] == '#')
1017 || (ctl_line[0] == ' ')
1018 || (ctl_line[0] == '\n'))
1019 ; /* ignore these lines */
1021 printf("Command not understood (%s)\n", ctl_line);
1027 build_stream_name(int type, const gchar* dir) {
1029 State *s = &uzbl.state;
1032 xwin_str = itos((int)uzbl.xwin);
1034 str = g_strdup_printf
1035 ("%s/uzbl_fifo_%s", dir,
1036 s->instance_name ? s->instance_name : xwin_str);
1037 } else if (type == SOCKET) {
1038 str = g_strdup_printf
1039 ("%s/uzbl_socket_%s", dir,
1040 s->instance_name ? s->instance_name : xwin_str );
1047 control_fifo(GIOChannel *gio, GIOCondition condition) {
1048 if (uzbl.state.verbose)
1049 printf("triggered\n");
1054 if (condition & G_IO_HUP)
1055 g_error ("Fifo: Read end of pipe died!\n");
1058 g_error ("Fifo: GIOChannel broke\n");
1060 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1061 if (ret == G_IO_STATUS_ERROR) {
1062 g_error ("Fifo: Error reading: %s\n", err->message);
1066 parse_cmd_line(ctl_line);
1073 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1074 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1075 if (unlink(uzbl.comm.fifo_path) == -1)
1076 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1077 g_free(uzbl.comm.fifo_path);
1078 uzbl.comm.fifo_path = NULL;
1081 if (*dir == ' ') { /* space unsets the variable */
1086 GIOChannel *chan = NULL;
1087 GError *error = NULL;
1088 gchar *path = build_stream_name(FIFO, dir);
1090 if (!file_exists(path)) {
1091 if (mkfifo (path, 0666) == 0) {
1092 // 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.
1093 chan = g_io_channel_new_file(path, "r+", &error);
1095 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1096 if (uzbl.state.verbose)
1097 printf ("init_fifo: created successfully as %s\n", path);
1098 uzbl.comm.fifo_path = path;
1100 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1101 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1102 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1103 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1105 /* if we got this far, there was an error; cleanup */
1106 if (error) g_error_free (error);
1113 control_stdin(GIOChannel *gio, GIOCondition condition) {
1114 gchar *ctl_line = NULL;
1115 gsize ctl_line_len = 0;
1118 if (condition & G_IO_HUP) {
1119 ret = g_io_channel_shutdown (gio, FALSE, NULL);
1123 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, NULL);
1124 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1127 parse_cmd_line(ctl_line);
1135 GIOChannel *chan = NULL;
1136 GError *error = NULL;
1138 chan = g_io_channel_unix_new(fileno(stdin));
1140 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1141 g_error ("Stdin: could not add watch\n");
1143 if (uzbl.state.verbose)
1144 printf ("Stdin: watch added successfully\n");
1147 g_error ("Stdin: Error while opening: %s\n", error->message);
1149 if (error) g_error_free (error);
1153 control_socket(GIOChannel *chan) {
1154 struct sockaddr_un remote;
1155 char buffer[512], *ctl_line;
1157 int sock, clientsock, n, done;
1160 sock = g_io_channel_unix_get_fd(chan);
1162 memset (buffer, 0, sizeof (buffer));
1164 t = sizeof (remote);
1165 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1169 memset (temp, 0, sizeof (temp));
1170 n = recv (clientsock, temp, 128, 0);
1172 buffer[strlen (buffer)] = '\0';
1176 strcat (buffer, temp);
1179 if (strcmp (buffer, "\n") < 0) {
1180 buffer[strlen (buffer) - 1] = '\0';
1182 buffer[strlen (buffer)] = '\0';
1185 ctl_line = g_strdup(buffer);
1186 parse_cmd_line (ctl_line);
1189 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1190 GError *error = NULL;
1193 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1194 if (ret == G_IO_STATUS_ERROR)
1195 g_error ("Error reading: %s\n", error->message);
1197 printf("Got line %s (%u bytes) \n",ctl_line, len);
1199 parse_line(ctl_line);
1207 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1208 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1209 if (unlink(uzbl.comm.socket_path) == -1)
1210 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1211 g_free(uzbl.comm.socket_path);
1212 uzbl.comm.socket_path = NULL;
1220 GIOChannel *chan = NULL;
1222 struct sockaddr_un local;
1223 gchar *path = build_stream_name(SOCKET, dir);
1225 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1227 local.sun_family = AF_UNIX;
1228 strcpy (local.sun_path, path);
1229 unlink (local.sun_path);
1231 len = strlen (local.sun_path) + sizeof (local.sun_family);
1232 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1233 if (uzbl.state.verbose)
1234 printf ("init_socket: opened in %s\n", path);
1237 if( (chan = g_io_channel_unix_new(sock)) ) {
1238 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1239 uzbl.comm.socket_path = path;
1242 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1244 /* if we got this far, there was an error; cleanup */
1251 update_title (void) {
1252 GString* string_long = g_string_new ("");
1253 GString* string_short = g_string_new ("");
1257 State *s = &uzbl.state;
1258 Behaviour *b = &uzbl.behave;
1260 if(s->instance_name) {
1261 iname_len = strlen(s->instance_name)+4;
1262 iname = malloc(iname_len);
1263 snprintf(iname, iname_len, "<%s> ", s->instance_name);
1265 g_string_prepend(string_long, iname);
1266 g_string_prepend(string_short, iname);
1270 g_string_append_printf(string_long, "%s ", s->keycmd->str);
1271 if (!b->always_insert_mode)
1272 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
1273 if (uzbl.gui.main_title) {
1274 g_string_append (string_long, uzbl.gui.main_title);
1275 g_string_append (string_short, uzbl.gui.main_title);
1277 g_string_append (string_long, " - Uzbl browser");
1278 g_string_append (string_short, " - Uzbl browser");
1279 if (s->selected_url[0]!=0) {
1280 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
1283 gchar* title_long = g_string_free (string_long, FALSE);
1284 gchar* title_short = g_string_free (string_short, FALSE);
1286 if (b->show_status) {
1287 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
1288 // TODO: we should probably not do this every time we want to update the title..?
1289 statln = expand_template(uzbl.behave.status_format);
1290 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1291 if (b->status_background) {
1293 gdk_color_parse (b->status_background, &color);
1294 //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)
1295 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1299 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
1302 g_free (title_long);
1303 g_free (title_short);
1307 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1309 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1313 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1314 || 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)
1317 /* turn off insert mode (if always_insert_mode is not used) */
1318 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1319 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1324 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1327 if (event->keyval == GDK_Escape) {
1328 g_string_truncate(uzbl.state.keycmd, 0);
1333 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1334 if (event->keyval == GDK_Insert) {
1336 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1337 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1339 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1342 g_string_append (uzbl.state.keycmd, str);
1349 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1350 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1354 gboolean key_ret = FALSE;
1355 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1357 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1359 run_keycmd(key_ret);
1361 if (key_ret) return (!uzbl.behave.insert_mode);
1366 run_keycmd(const gboolean key_ret) {
1367 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1369 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1370 g_string_truncate(uzbl.state.keycmd, 0);
1371 parse_command(action->name, action->param);
1375 /* try if it's an incremental keycmd or one that takes args, and run it */
1376 GString* short_keys = g_string_new ("");
1377 GString* short_keys_inc = g_string_new ("");
1379 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1380 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1381 g_string_assign(short_keys_inc, short_keys->str);
1382 g_string_append_c(short_keys, '_');
1383 g_string_append_c(short_keys_inc, '*');
1385 gboolean exec_now = FALSE;
1386 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1387 if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
1388 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1389 if (key_ret) { /* just quit the incremental command on return */
1390 g_string_truncate(uzbl.state.keycmd, 0);
1392 } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
1396 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1397 GString* actionname = g_string_new ("");
1398 GString* actionparam = g_string_new ("");
1399 g_string_erase (parampart, 0, i+1);
1401 g_string_printf (actionname, action->name, parampart->str);
1403 g_string_printf (actionparam, action->param, parampart->str);
1404 parse_command(actionname->str, actionparam->str);
1405 g_string_free (actionname, TRUE);
1406 g_string_free (actionparam, TRUE);
1407 g_string_free (parampart, TRUE);
1409 g_string_truncate(uzbl.state.keycmd, 0);
1413 g_string_truncate(short_keys, short_keys->len - 1);
1415 g_string_free (short_keys, TRUE);
1416 g_string_free (short_keys_inc, TRUE);
1423 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1424 //main_window_ref = g_object_ref(scrolled_window);
1425 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
1427 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1428 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1430 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1431 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1432 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1433 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1434 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1435 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1436 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1437 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1438 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1439 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1441 return scrolled_window;
1448 g->mainbar = gtk_hbox_new (FALSE, 0);
1450 /* keep a reference to the bar so we can re-pack it at runtime*/
1451 //sbar_ref = g_object_ref(g->mainbar);
1453 g->mainbar_label = gtk_label_new ("");
1454 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1455 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1456 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1457 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1458 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1463 GtkWidget* create_window () {
1464 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1465 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1466 gtk_widget_set_name (window, "Uzbl browser");
1467 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1473 add_binding (const gchar *key, const gchar *act) {
1474 char **parts = g_strsplit(act, " ", 2);
1481 if (uzbl.state.verbose)
1482 printf ("Binding %-10s : %s\n", key, act);
1483 action = new_action(parts[0], parts[1]);
1485 if(g_hash_table_lookup(uzbl.bindings, key))
1486 g_hash_table_remove(uzbl.bindings, key);
1487 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1493 get_xdg_var (XDG_Var xdg) {
1494 const gchar* actual_value = getenv (xdg.environmental);
1495 const gchar* home = getenv ("HOME");
1497 gchar* return_value = str_replace ("~", home, g_strdup (actual_value));
1499 if (! actual_value || strcmp (actual_value, "") == 0) {
1500 if (xdg.default_value) {
1501 return_value = str_replace ("~", home, g_strdup (xdg.default_value));
1503 return_value = NULL;
1507 return return_value;
1511 find_xdg_file (int xdg_type, char* filename) {
1512 /* xdg_type = 0 => config
1513 xdg_type = 1 => data
1514 xdg_type = 2 => cache*/
1516 gchar* temporary_file = (char *)malloc (1024);
1517 gchar* temporary_string = NULL;
1520 strcpy (temporary_file, get_xdg_var (XDG[xdg_type]));
1522 strcat (temporary_file, filename);
1524 if (! file_exists (temporary_file) && xdg_type != 2) {
1525 temporary_string = (char *) strtok_r (get_xdg_var (XDG[3 + xdg_type]), ":", &saveptr);
1527 while (temporary_string && ! file_exists (temporary_file)) {
1528 strcpy (temporary_file, temporary_string);
1529 strcat (temporary_file, filename);
1530 temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
1534 if (file_exists (temporary_file)) {
1535 return temporary_file;
1543 State *s = &uzbl.state;
1544 Network *n = &uzbl.net;
1546 uzbl.behave.reset_command_mode = 1;
1548 if (!s->config_file) {
1549 s->config_file = g_strdup (find_xdg_file (0, "/uzbl/config"));
1552 if (s->config_file) {
1553 GIOChannel *chan = NULL;
1554 gchar *readbuf = NULL;
1557 chan = g_io_channel_new_file(s->config_file, "r", NULL);
1560 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
1561 == G_IO_STATUS_NORMAL) {
1562 parse_cmd_line(readbuf);
1566 g_io_channel_unref (chan);
1567 if (uzbl.state.verbose)
1568 printf ("Config %s loaded\n", s->config_file);
1570 fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
1573 if (uzbl.state.verbose)
1574 printf ("No configuration file loaded.\n");
1576 if (!uzbl.behave.status_format)
1577 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1579 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1583 set_useragent(gchar *val) {
1588 gchar *ua = expand_template(val);
1590 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1594 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1597 if (!uzbl.behave.cookie_handler) return;
1599 gchar * stdout = NULL;
1600 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1601 GString* args = g_string_new ("");
1602 SoupURI * soup_uri = soup_message_get_uri(msg);
1603 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1604 run_command(uzbl.behave.cookie_handler, args->str, TRUE, &stdout);
1606 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1608 g_string_free(args, TRUE);
1612 save_cookies (SoupMessage *msg, gpointer user_data){
1616 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1617 cookie = soup_cookie_to_set_cookie_header(ck->data);
1618 GString* args = g_string_new ("");
1619 SoupURI * soup_uri = soup_message_get_uri(msg);
1620 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1621 run_command(uzbl.behave.cookie_handler, args->str, FALSE, NULL);
1622 g_string_free(args, TRUE);
1630 main (int argc, char* argv[]) {
1631 gtk_init (&argc, &argv);
1632 if (!g_thread_supported ())
1633 g_thread_init (NULL);
1635 strcpy(uzbl.state.executable_path,argv[0]);
1637 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1638 g_option_context_add_main_entries (context, entries, NULL);
1639 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1640 g_option_context_parse (context, &argc, &argv, NULL);
1641 /* initialize hash table */
1642 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1644 uzbl.net.soup_session = webkit_get_default_session();
1645 uzbl.state.keycmd = g_string_new("");
1647 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1648 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1649 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
1650 fprintf(stderr, "uzbl: error hooking SIGINT\n");
1652 if(uname(&uzbl.state.unameinfo) == -1)
1653 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
1658 make_var_to_name_hash();
1661 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
1663 uzbl.gui.scrolled_win = create_browser();
1666 /* initial packing */
1667 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1668 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1670 uzbl.gui.main_window = create_window ();
1671 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
1673 load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
1675 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1676 gtk_widget_show_all (uzbl.gui.main_window);
1677 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1679 if (uzbl.state.verbose) {
1680 printf("Uzbl start location: %s\n", argv[0]);
1681 printf("window_id %i\n",(int) uzbl.xwin);
1682 printf("pid %i\n", getpid ());
1683 printf("name: %s\n", uzbl.state.instance_name);
1686 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1687 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1688 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1689 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1690 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1694 if (!uzbl.behave.show_status)
1695 gtk_widget_hide(uzbl.gui.mainbar);
1704 return EXIT_SUCCESS;
1707 /* vi: set et ts=4: */