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 // Already working commands
67 { "uri", (void *)&uzbl.state.uri },
68 { "status_format", (void *)&uzbl.behave.status_format },
69 { "status_background", (void *)&uzbl.behave.status_background },
70 { "status_message", (void *)&uzbl.gui.sbar.msg },
71 { "show_status", (void *)&uzbl.behave.show_status },
72 { "insert_mode", (void *)&uzbl.behave.insert_mode },
73 { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler},
74 { "history_handler", (void *)&uzbl.behave.history_handler },
75 { "download_handler", (void *)&uzbl.behave.download_handler },
76 { "cookie_handler", (void *)&uzbl.behave.cookie_handler },
77 { "fifo_dir", (void *)&uzbl.behave.fifo_dir },
78 { "socket_dir", (void *)&uzbl.behave.socket_dir },
79 { "proxy_url", (void *)&uzbl.net.proxy_url },
80 { "max_conns", (void *)&uzbl.net.max_conns },
81 { "max_conns_host", (void *)&uzbl.net.max_conns_host },
82 { "http_debug", (void *)&uzbl.behave.http_debug },
83 // TODO: write cmd handlers for the following
84 { "useragent", (void *)&uzbl.net.useragent },
86 }, *n2v_p = var_name_to_ptr;
88 /* construct a hash from the var_name_to_ptr array for quick access */
90 make_var_to_name_hash() {
91 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
93 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
98 /* commandline arguments (set initial values for the state variables) */
99 static GOptionEntry entries[] =
101 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
102 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
103 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
104 { NULL, 0, 0, 0, NULL, NULL, NULL }
107 typedef void (*Command)(WebKitWebView*, const char *);
110 static char *XDG_CONFIG_HOME_default[256];
111 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
114 /* --- UTILITY FUNCTIONS --- */
120 snprintf(tmp, sizeof(tmp), "%i", val);
121 return g_strdup(tmp);
125 str_replace (const char* search, const char* replace, const char* string) {
126 return g_strjoinv (replace, g_strsplit(string, search, -1));
130 setup_signal(int signr, sigfunc *shandler) {
131 struct sigaction nh, oh;
133 nh.sa_handler = shandler;
134 sigemptyset(&nh.sa_mask);
137 if(sigaction(signr, &nh, &oh) < 0)
145 if (uzbl.behave.fifo_dir)
146 unlink (uzbl.comm.fifo_path);
147 if (uzbl.behave.socket_dir)
148 unlink (uzbl.comm.socket_path);
150 g_string_free(uzbl.state.keycmd, TRUE);
151 g_hash_table_destroy(uzbl.bindings);
152 g_hash_table_destroy(uzbl.behave.commands);
156 /* --- SIGNAL HANDLER --- */
159 catch_sigterm(int s) {
164 /* --- CALLBACKS --- */
167 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
170 (void) navigation_action;
171 (void) policy_decision;
173 const gchar* uri = webkit_network_request_get_uri (request);
174 printf("New window requested -> %s \n", uri);
175 new_window_load_uri(uri);
180 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
184 if (uzbl.state.selected_url[0]!=0) {
185 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
186 new_window_load_uri(uzbl.state.selected_url);
188 printf("New web view -> %s\n","Nothing to open, exiting");
194 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
197 if (uzbl.behave.download_handler) {
198 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
199 printf("Download -> %s\n",uri);
200 run_command_async(uzbl.behave.download_handler, uri);
205 /* scroll a bar in a given direction */
207 scroll (GtkAdjustment* bar, const char *param) {
211 amount = g_ascii_strtod(param, &end);
214 fprintf(stderr, "found something after double: %s\n", end);
216 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
219 static void scroll_vert(WebKitWebView* page, const char *param) {
222 scroll(uzbl.gui.bar_v, param);
225 static void scroll_horz(WebKitWebView* page, const char *param) {
228 scroll(uzbl.gui.bar_h, param);
233 if (!uzbl.behave.show_status) {
234 gtk_widget_hide(uzbl.gui.mainbar);
236 gtk_widget_show(uzbl.gui.mainbar);
242 toggle_status_cb (WebKitWebView* page, const char *param) {
246 if (uzbl.behave.show_status) {
247 gtk_widget_hide(uzbl.gui.mainbar);
249 gtk_widget_show(uzbl.gui.mainbar);
251 uzbl.behave.show_status = !uzbl.behave.show_status;
256 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
260 //ADD HOVER URL TO WINDOW TITLE
261 uzbl.state.selected_url[0] = '\0';
263 strcpy (uzbl.state.selected_url, link);
269 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
273 if (uzbl.gui.main_title)
274 g_free (uzbl.gui.main_title);
275 uzbl.gui.main_title = g_strdup (title);
280 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
283 uzbl.gui.sbar.load_progress = progress;
288 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
292 if (uzbl.behave.load_finish_handler) {
293 run_command_async(uzbl.behave.load_finish_handler, NULL);
298 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
301 free (uzbl.state.uri);
302 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
303 uzbl.state.uri = g_string_free (newuri, FALSE);
304 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
305 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
308 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
312 destroy_cb (GtkWidget* widget, gpointer data) {
320 if (uzbl.behave.history_handler) {
322 struct tm * timeinfo;
325 timeinfo = localtime ( &rawtime );
326 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
327 GString* args = g_string_new ("");
328 g_string_printf (args, "'%s'", date);
329 run_command_async(uzbl.behave.history_handler, args->str);
330 g_string_free (args, TRUE);
335 /* VIEW funcs (little webkit wrappers) */
336 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
338 VIEWFUNC(reload_bypass_cache)
339 VIEWFUNC(stop_loading)
346 /* -- command to callback/function map for things we cannot attach to any signals */
349 static struct {char *name; Command command;} cmdlist[] =
351 { "back", view_go_back },
352 { "forward", view_go_forward },
353 { "scroll_vert", scroll_vert },
354 { "scroll_horz", scroll_horz },
355 { "reload", view_reload, },
356 { "reload_ign_cache", view_reload_bypass_cache},
357 { "stop", view_stop_loading, },
358 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
359 { "zoom_out", view_zoom_out, },
361 { "script", run_js },
362 { "toggle_status", toggle_status_cb },
364 { "exit", close_uzbl },
365 { "search", search_text },
366 { "insert_mode", set_insert_mode }
373 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
375 for (i = 0; i < LENGTH(cmdlist); i++)
376 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
379 /* -- CORE FUNCTIONS -- */
382 free_action(gpointer act) {
383 Action *action = (Action*)act;
384 g_free(action->name);
386 g_free(action->param);
391 new_action(const gchar *name, const gchar *param) {
392 Action *action = g_new(Action, 1);
394 action->name = g_strdup(name);
396 action->param = g_strdup(param);
398 action->param = NULL;
404 file_exists (const char * filename) {
405 FILE *file = fopen (filename, "r");
414 set_insert_mode(WebKitWebView *page, const gchar *param) {
418 uzbl.behave.insert_mode = TRUE;
423 load_uri (WebKitWebView * web_view, const gchar *param) {
425 GString* newuri = g_string_new (param);
426 if (g_strrstr (param, "://") == NULL)
427 g_string_prepend (newuri, "http://");
428 /* if we do handle cookies, ask our handler for them */
429 webkit_web_view_load_uri (web_view, newuri->str);
430 g_string_free (newuri, TRUE);
435 run_js (WebKitWebView * web_view, const gchar *param) {
437 webkit_web_view_execute_script (web_view, param);
441 search_text (WebKitWebView *page, const char *param) {
442 if ((param) && (param[0] != '\0')) {
443 strcpy(uzbl.state.searchtx, param);
445 if (uzbl.state.searchtx[0] != '\0') {
446 printf ("Searching: %s\n", uzbl.state.searchtx);
447 webkit_web_view_unmark_text_matches (page);
448 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
449 webkit_web_view_set_highlight_text_matches (page, TRUE);
450 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
455 new_window_load_uri (const gchar * uri) {
456 GString* to_execute = g_string_new ("");
457 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
459 for (i = 0; entries[i].long_name != NULL; i++) {
460 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
461 gchar** str = (gchar**)entries[i].arg_data;
463 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
467 printf("\n%s\n", to_execute->str);
468 g_spawn_command_line_async (to_execute->str, NULL);
469 g_string_free (to_execute, TRUE);
473 close_uzbl (WebKitWebView *page, const char *param) {
479 /* --Statusbar functions-- */
481 build_progressbar_ascii(int percent) {
485 GString *bar = g_string_new("");
487 l = (double)percent*((double)width/100.);
488 l = (int)(l+.5)>=(int)l ? l+.5 : l;
490 g_string_append(bar, "[");
491 for(i=0; i<(int)l; i++)
492 g_string_append(bar, "=");
495 g_string_append(bar, "·");
496 g_string_append(bar, "]");
498 return g_string_free(bar, FALSE);
503 const GScannerConfig scan_config = {
506 ) /* cset_skip_characters */,
511 ) /* cset_identifier_first */,
518 ) /* cset_identifier_nth */,
519 ( "" ) /* cpair_comment_single */,
521 TRUE /* case_sensitive */,
523 FALSE /* skip_comment_multi */,
524 FALSE /* skip_comment_single */,
525 FALSE /* scan_comment_multi */,
526 TRUE /* scan_identifier */,
527 TRUE /* scan_identifier_1char */,
528 FALSE /* scan_identifier_NULL */,
529 TRUE /* scan_symbols */,
530 FALSE /* scan_binary */,
531 FALSE /* scan_octal */,
532 FALSE /* scan_float */,
533 FALSE /* scan_hex */,
534 FALSE /* scan_hex_dollar */,
535 FALSE /* scan_string_sq */,
536 FALSE /* scan_string_dq */,
537 TRUE /* numbers_2_int */,
538 FALSE /* int_2_float */,
539 FALSE /* identifier_2_string */,
540 FALSE /* char_2_token */,
541 FALSE /* symbol_2_token */,
542 TRUE /* scope_0_fallback */,
547 uzbl.scan = g_scanner_new(&scan_config);
548 while(symp->symbol_name) {
549 g_scanner_scope_add_symbol(uzbl.scan, 0,
551 GINT_TO_POINTER(symp->symbol_token));
557 parse_status_template(const char *template) {
558 GTokenType token = G_TOKEN_NONE;
559 GString *ret = g_string_new("");
566 g_scanner_input_text(uzbl.scan, template, strlen(template));
567 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
568 token = g_scanner_get_next_token(uzbl.scan);
570 if(token == G_TOKEN_SYMBOL) {
571 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
576 g_markup_printf_escaped("%s", uzbl.state.uri):"");
579 g_string_append(ret, itos(uzbl.gui.sbar.load_progress));
581 case SYM_LOADPRGSBAR:
582 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
583 g_string_append(ret, buf);
589 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
593 uzbl.state.instance_name?uzbl.state.instance_name:itos(uzbl.xwin));
597 uzbl.state.keycmd->str ?
598 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
602 uzbl.behave.insert_mode?"[I]":"[C]");
606 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
612 else if(token == G_TOKEN_INT) {
613 g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int));
615 else if(token == G_TOKEN_IDENTIFIER) {
616 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
618 else if(token == G_TOKEN_CHAR) {
619 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
623 return g_string_free(ret, FALSE);
625 /* --End Statusbar functions-- */
628 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
630 run_command_async(const char *command, const char *args) {
631 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
632 GString* to_execute = g_string_new ("");
634 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
635 command, uzbl.state.config_file, (int) getpid() ,
636 (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
637 g_string_append_printf (to_execute, " '%s' '%s'",
638 uzbl.state.uri, "TODO title here");
640 g_string_append_printf (to_execute, " %s", args);
642 result = g_spawn_command_line_async (to_execute->str, NULL);
643 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
644 g_string_free (to_execute, TRUE);
649 run_command_sync(const char *command, const char *args, char **stdout) {
650 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
651 GString* to_execute = g_string_new ("");
653 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, uzbl.state.config_file, (int) getpid() , (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
654 g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
656 g_string_append_printf (to_execute, " %s", args);
658 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
659 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
660 g_string_free (to_execute, TRUE);
665 spawn(WebKitWebView *web_view, const char *param) {
667 run_command_async(param, NULL);
671 parse_command(const char *cmd, const char *param) {
674 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
675 c(uzbl.gui.web_view, param);
677 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
685 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
686 G_REGEX_OPTIMIZE, 0, &err);
687 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
688 G_REGEX_OPTIMIZE, 0, &err);
689 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
690 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err);
691 uzbl.comm.cmd_regex = g_regex_new("^[Cc][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
692 G_REGEX_OPTIMIZE, 0, &err);
696 get_var_value(gchar *name) {
699 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
700 if(!strcmp(name, "status_format")) {
701 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
703 printf("VAR: %s VALUE: %d\n", name, (int)*p);
713 if(*uzbl.net.proxy_url == ' '
714 || uzbl.net.proxy_url == NULL) {
715 soup_session_remove_feature_by_type(uzbl.net.soup_session,
716 (GType) SOUP_SESSION_PROXY_URI);
719 suri = soup_uri_new(uzbl.net.proxy_url);
720 g_object_set(G_OBJECT(uzbl.net.soup_session),
721 SOUP_SESSION_PROXY_URI,
729 var_is(const char *x, const char *y) {
730 return (strcmp(x, y) == 0 ? TRUE : FALSE );
734 set_var_value(gchar *name, gchar *val) {
738 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
739 if(var_is("status_message", name)
740 || var_is("status_background", name)
741 || var_is("status_format", name)
742 || var_is("load_finish_handler", name)
743 || var_is("history_handler", name)
744 || var_is("download_handler", name)
745 || var_is("cookie_handler", name)) {
751 else if(var_is("uri", name)) {
755 load_uri(uzbl.gui.web_view, (const gchar*)*p);
757 else if(var_is("proxy_url", name)) {
763 else if(var_is("fifo_dir", name)) {
765 *p = init_fifo(g_strdup(val));
767 else if(var_is("socket_dir", name)) {
769 *p = init_socket(g_strdup(val));
771 /* variables that take int values */
774 *ip = (int)strtoul(val, &endp, 10);
776 if(var_is("show_status", name)) {
779 else if (var_is("max_conns", name)) {
780 g_object_set(G_OBJECT(uzbl.net.soup_session),
781 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
783 else if (var_is("max_conns_host", name)) {
784 g_object_set(G_OBJECT(uzbl.net.soup_session),
785 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
787 else if (var_is("http_debug", name)) {
788 soup_session_remove_feature
789 (uzbl.net.soup_session, uzbl.net.soup_logger);
790 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
791 /*g_free(uzbl.net.soup_logger);*/
793 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
794 soup_session_add_feature(uzbl.net.soup_session,
795 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
803 parse_cmd_line(char *ctl_line) {
807 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
808 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
809 if(tokens[0][0] == 0) {
810 set_var_value(tokens[1], tokens[2]);
814 printf("Error in command: %s\n", tokens[0]);
817 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
818 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
819 if(tokens[0][0] == 0) {
820 get_var_value(tokens[1]);
824 printf("Error in command: %s\n", tokens[0]);
827 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
828 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
829 if(tokens[0][0] == 0) {
830 add_binding(tokens[1], tokens[2]);
834 printf("Error in command: %s\n", tokens[0]);
837 else if(ctl_line[0] == 'C' || ctl_line[0] == 'c') {
838 tokens = g_regex_split(uzbl.comm.cmd_regex, ctl_line, 0);
839 if(tokens[0][0] == 0) {
840 parse_command(tokens[1], tokens[2]);
844 printf("Error in command: %s\n", tokens[0]);
847 else if( (ctl_line[0] == '#')
848 || (ctl_line[0] == ' ')
849 || (ctl_line[0] == '\n'))
850 ; /* ignore these lines */
852 printf("Command not understood (%s)\n", ctl_line);
858 build_stream_name(int type, const gchar* dir) {
860 State *s = &uzbl.state;
863 xwin_str = itos((int)uzbl.xwin);
865 str = g_strdup_printf
866 ("%s/uzbl_fifo_%s", dir,
867 s->instance_name ? s->instance_name : xwin_str);
868 } else if (type == SOCKET) {
869 str = g_strdup_printf
870 ("%s/uzbl_socket_%s", dir,
871 s->instance_name ? s->instance_name : xwin_str );
878 control_fifo(GIOChannel *gio, GIOCondition condition) {
879 printf("triggered\n");
884 if (condition & G_IO_HUP)
885 g_error ("Fifo: Read end of pipe died!\n");
888 g_error ("Fifo: GIOChannel broke\n");
890 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
891 if (ret == G_IO_STATUS_ERROR)
892 g_error ("Fifo: Error reading: %s\n", err->message);
894 parse_cmd_line(ctl_line);
901 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
902 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
903 if (unlink(uzbl.comm.fifo_path) == -1)
904 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
905 g_free(uzbl.comm.fifo_path);
906 uzbl.comm.fifo_path = NULL;
909 if (*dir == ' ') { /* space unsets the variable */
914 GIOChannel *chan = NULL;
915 GError *error = NULL;
916 gchar *path = build_stream_name(FIFO, dir);
918 if (!file_exists(path)) {
919 if (mkfifo (path, 0666) == 0) {
920 // 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.
921 chan = g_io_channel_new_file(path, "r+", &error);
923 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
924 printf ("init_fifo: created successfully as %s\n", path);
925 uzbl.comm.fifo_path = path;
927 } else g_warning ("init_fifo: could not add watch on %s\n", path);
928 } else g_warning ("init_fifo: can't open: %s\n", error->message);
929 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
930 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
932 /* if we got this far, there was an error; cleanup */
939 control_stdin(GIOChannel *gio, GIOCondition condition) {
940 gchar *ctl_line = NULL;
941 gsize ctl_line_len = 0;
945 if (condition & G_IO_HUP) {
946 ret = g_io_channel_shutdown (gio, FALSE, &err);
950 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
951 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
954 parse_cmd_line(ctl_line);
962 GIOChannel *chan = NULL;
963 GError *error = NULL;
965 chan = g_io_channel_unix_new(fileno(stdin));
967 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
968 g_error ("Stdin: could not add watch\n");
970 printf ("Stdin: watch added successfully\n");
973 g_error ("Stdin: Error while opening: %s\n", error->message);
978 control_socket(GIOChannel *chan) {
979 struct sockaddr_un remote;
980 char buffer[512], *ctl_line;
982 int sock, clientsock, n, done;
985 sock = g_io_channel_unix_get_fd(chan);
987 memset (buffer, 0, sizeof (buffer));
990 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
994 memset (temp, 0, sizeof (temp));
995 n = recv (clientsock, temp, 128, 0);
997 buffer[strlen (buffer)] = '\0';
1001 strcat (buffer, temp);
1004 if (strcmp (buffer, "\n") < 0) {
1005 buffer[strlen (buffer) - 1] = '\0';
1007 buffer[strlen (buffer)] = '\0';
1010 ctl_line = g_strdup(buffer);
1011 parse_cmd_line (ctl_line);
1014 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1015 GError *error = NULL;
1018 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1019 if (ret == G_IO_STATUS_ERROR)
1020 g_error ("Error reading: %s\n", error->message);
1022 printf("Got line %s (%u bytes) \n",ctl_line, len);
1024 parse_line(ctl_line);
1032 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1033 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1034 if (unlink(uzbl.comm.socket_path) == -1)
1035 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1036 g_free(uzbl.comm.socket_path);
1037 uzbl.comm.socket_path = NULL;
1045 GIOChannel *chan = NULL;
1047 struct sockaddr_un local;
1048 gchar *path = build_stream_name(SOCKET, dir);
1050 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1052 local.sun_family = AF_UNIX;
1053 strcpy (local.sun_path, path);
1054 unlink (local.sun_path);
1056 len = strlen (local.sun_path) + sizeof (local.sun_family);
1057 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1058 printf ("init_socket: opened in %s\n", path);
1061 if( (chan = g_io_channel_unix_new(sock)) ) {
1062 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1063 uzbl.comm.socket_path = path;
1066 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1068 /* if we got this far, there was an error; cleanup */
1075 update_title (void) {
1076 GString* string_long = g_string_new ("");
1077 GString* string_short = g_string_new ("");
1081 State *s = &uzbl.state;
1082 Behaviour *b = &uzbl.behave;
1084 if(s->instance_name) {
1085 iname_len = strlen(s->instance_name)+4;
1086 iname = malloc(iname_len);
1087 snprintf(iname, iname_len, "<%s> ", s->instance_name);
1089 g_string_prepend(string_long, iname);
1090 g_string_prepend(string_short, iname);
1094 g_string_append_printf(string_long, "%s ", s->keycmd->str);
1095 if (!b->always_insert_mode)
1096 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
1097 if (uzbl.gui.main_title) {
1098 g_string_append (string_long, uzbl.gui.main_title);
1099 g_string_append (string_short, uzbl.gui.main_title);
1101 g_string_append (string_long, " - Uzbl browser");
1102 g_string_append (string_short, " - Uzbl browser");
1103 if (s->selected_url[0]!=0) {
1104 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
1107 gchar* title_long = g_string_free (string_long, FALSE);
1108 gchar* title_short = g_string_free (string_short, FALSE);
1110 if (b->show_status) {
1111 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
1112 // TODO: we should probably not do this every time we want to update the title..?
1113 statln = parse_status_template(uzbl.behave.status_format);
1114 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1115 if (b->status_background) {
1117 gdk_color_parse (b->status_background, &color);
1118 //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)
1119 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1123 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
1126 g_free (title_long);
1127 g_free (title_short);
1131 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1133 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1138 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1139 || 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)
1142 /* turn off insert mode (if always_insert_mode is not used) */
1143 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1144 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1149 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1152 if (event->keyval == GDK_Escape) {
1153 g_string_truncate(uzbl.state.keycmd, 0);
1158 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1159 if (event->keyval == GDK_Insert) {
1161 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1162 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1164 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1167 g_string_append_printf (uzbl.state.keycmd, "%s", str);
1174 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1175 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1179 gboolean key_ret = FALSE;
1180 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1183 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1184 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1185 g_string_truncate(uzbl.state.keycmd, 0);
1186 parse_command(action->name, action->param);
1189 GString* short_keys = g_string_new ("");
1190 GString* short_keys_inc = g_string_new ("");
1192 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1193 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1194 g_string_assign(short_keys_inc, short_keys->str);
1195 g_string_append_c(short_keys, '_');
1196 g_string_append_c(short_keys_inc, '*');
1198 gboolean exec_now = FALSE;
1199 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1200 if (key_ret) exec_now = TRUE; // run normal cmds only if return was pressed
1201 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1202 if (key_ret) { // just quit the incremental command on return
1203 g_string_truncate(uzbl.state.keycmd, 0);
1205 } else exec_now = TRUE; // always exec inc. commands on keys other than return
1209 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1210 GString* actionname = g_string_new ("");
1211 GString* actionparam = g_string_new ("");
1212 g_string_erase (parampart, 0, i+1);
1214 g_string_printf (actionname, action->name, parampart->str);
1216 g_string_printf (actionparam, action->param, parampart->str);
1217 parse_command(actionname->str, actionparam->str);
1218 g_string_free (actionname, TRUE);
1219 g_string_free (actionparam, TRUE);
1220 g_string_free (parampart, TRUE);
1222 g_string_truncate(uzbl.state.keycmd, 0);
1226 g_string_truncate(short_keys, short_keys->len - 1);
1228 g_string_free (short_keys, TRUE);
1229 g_string_free (short_keys_inc, TRUE);
1231 if (key_ret) return (!uzbl.behave.insert_mode);
1239 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1240 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
1242 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1243 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1245 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1246 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1247 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1248 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
1249 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1250 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1251 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1252 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1253 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1254 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1256 return scrolled_window;
1263 g->mainbar = gtk_hbox_new (FALSE, 0);
1264 g->mainbar_label = gtk_label_new ("");
1265 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1266 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1267 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1268 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1269 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1274 GtkWidget* create_window () {
1275 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1276 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1277 gtk_widget_set_name (window, "Uzbl browser");
1278 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1284 add_binding (const gchar *key, const gchar *act) {
1285 char **parts = g_strsplit(act, " ", 2);
1292 printf ("Binding %-10s : %s\n", key, act);
1293 action = new_action(parts[0], parts[1]);
1295 if(g_hash_table_lookup(uzbl.bindings, key))
1296 g_hash_table_remove(uzbl.bindings, key);
1297 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1304 GKeyFile* config = NULL;
1305 gboolean res = FALSE;
1307 gchar** keys = NULL;
1308 State *s = &uzbl.state;
1309 Network *n = &uzbl.net;
1310 Behaviour *b = &uzbl.behave;
1312 if (!s->config_file) {
1313 const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
1314 if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
1315 XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
1317 printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
1319 strcpy (s->config_file_path, XDG_CONFIG_HOME);
1320 strcat (s->config_file_path, "/uzbl/config");
1321 if (file_exists (s->config_file_path)) {
1322 printf ("Config file %s found.\n", s->config_file_path);
1323 s->config_file = &s->config_file_path[0];
1325 // Now we check $XDG_CONFIG_DIRS
1326 char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
1327 if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
1328 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1330 printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1333 strcpy (buffer, XDG_CONFIG_DIRS);
1334 const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1335 while (dir && ! file_exists (s->config_file_path)) {
1336 strcpy (s->config_file_path, dir);
1337 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1338 if (file_exists (s->config_file_path)) {
1339 printf ("Config file %s found.\n", s->config_file_path);
1340 s->config_file = &s->config_file_path[0];
1342 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1347 if (s->config_file) {
1348 config = g_key_file_new ();
1349 res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL);
1351 printf ("Config %s loaded\n", s->config_file);
1353 fprintf (stderr, "Config %s loading failed\n", s->config_file);
1356 printf ("No configuration.\n");
1360 b->load_finish_handler= g_key_file_get_value (config, "behavior", "load_finish_handler",NULL);
1361 b->history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL);
1362 b->download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL);
1363 b->cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL);
1364 b->always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL);
1365 b->show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL);
1366 b->modkey = g_key_file_get_value (config, "behavior", "modkey", NULL);
1367 b->status_top = g_key_file_get_boolean (config, "behavior", "status_top", NULL);
1368 b->reset_command_mode = g_key_file_get_boolean (config, "behavior", "reset_command_mode", NULL);
1369 b->status_format = g_key_file_get_string (config, "behavior", "status_format", NULL);
1370 b->status_background = g_key_file_get_string (config, "behavior", "status_background", NULL);
1372 b->fifo_dir = g_key_file_get_value (config, "behavior", "fifo_dir", NULL);
1373 if (! b->socket_dir)
1374 b->socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL);
1375 keys = g_key_file_get_keys (config, "bindings", NULL, NULL);
1378 printf ("History handler: %s\n", (b->history_handler ? b->history_handler : "disabled"));
1379 printf ("Download manager: %s\n", (b->download_handler ? b->download_handler : "disabled"));
1380 printf ("Cookie handler: %s\n", (b->cookie_handler ? b->cookie_handler : "disabled"));
1381 printf ("Fifo directory: %s\n", (b->fifo_dir ? b->fifo_dir : "disabled"));
1382 printf ("Socket directory: %s\n", (b->socket_dir ? b->socket_dir : "disabled"));
1383 printf ("Always insert mode: %s\n", (b->always_insert_mode ? "TRUE" : "FALSE"));
1384 printf ("Reset mode: %s\n" , (b->reset_command_mode ? "TRUE" : "FALSE"));
1385 printf ("Show status: %s\n", (b->show_status ? "TRUE" : "FALSE"));
1386 printf ("Status top: %s\n", (b->status_top ? "TRUE" : "FALSE"));
1387 printf ("Modkey: %s\n", (b->modkey ? b->modkey : "disabled"));
1388 printf ("Status format: %s\n", (b->status_format ? b->status_format : "none"));
1393 //POSSIBLE MODKEY VALUES (COMBINATIONS CAN BE USED)
1394 gchar* modkeyup = g_utf8_strup (b->modkey, -1);
1395 if (g_strrstr (modkeyup,"SHIFT") != NULL) b->modmask |= GDK_SHIFT_MASK; //the Shift key.
1396 if (g_strrstr (modkeyup,"LOCK") != NULL) b->modmask |= GDK_LOCK_MASK; //a Lock key (depending on the modifier mapping of the X server this may either be CapsLock or ShiftLock).
1397 if (g_strrstr (modkeyup,"CONTROL") != NULL) b->modmask |= GDK_CONTROL_MASK; //the Control key.
1398 if (g_strrstr (modkeyup,"MOD1") != NULL) b->modmask |= GDK_MOD1_MASK; //the fourth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier, but normally it is the Alt key).
1399 if (g_strrstr (modkeyup,"MOD2") != NULL) b->modmask |= GDK_MOD2_MASK; //the fifth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1400 if (g_strrstr (modkeyup,"MOD3") != NULL) b->modmask |= GDK_MOD3_MASK; //the sixth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1401 if (g_strrstr (modkeyup,"MOD4") != NULL) b->modmask |= GDK_MOD4_MASK; //the seventh modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1402 if (g_strrstr (modkeyup,"MOD5") != NULL) b->modmask |= GDK_MOD5_MASK; //the eighth modifier key (it depends on the modifier mapping of the X server which key is interpreted as this modifier).
1403 if (g_strrstr (modkeyup,"BUTTON1") != NULL) b->modmask |= GDK_BUTTON1_MASK; //the first mouse button.
1404 if (g_strrstr (modkeyup,"BUTTON2") != NULL) b->modmask |= GDK_BUTTON2_MASK; //the second mouse button.
1405 if (g_strrstr (modkeyup,"BUTTON3") != NULL) b->modmask |= GDK_BUTTON3_MASK; //the third mouse button.
1406 if (g_strrstr (modkeyup,"BUTTON4") != NULL) b->modmask |= GDK_BUTTON4_MASK; //the fourth mouse button.
1407 if (g_strrstr (modkeyup,"BUTTON5") != NULL) b->modmask |= GDK_BUTTON5_MASK; //the fifth mouse button.
1408 if (g_strrstr (modkeyup,"SUPER") != NULL) b->modmask |= GDK_SUPER_MASK; //the Super modifier. Since 2.10
1409 if (g_strrstr (modkeyup,"HYPER") != NULL) b->modmask |= GDK_HYPER_MASK; //the Hyper modifier. Since 2.10
1410 if (g_strrstr (modkeyup,"META") != NULL) b->modmask |= GDK_META_MASK; //the Meta modifier. Since 2.10 */
1415 for (i = 0; keys[i]; i++) {
1416 gchar *value = g_key_file_get_string (config, "bindings", keys[i], NULL);
1418 add_binding(g_strstrip(keys[i]), value);
1425 /* networking options */
1427 b->http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL);
1428 n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL);
1429 n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL);
1430 n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL);
1434 if(!(b->http_debug <= 3)){
1436 fprintf(stderr, "Wrong http_debug level, ignoring.\n");
1437 } else if (b->http_debug > 0) {
1438 n->soup_logger = soup_logger_new(b->http_debug, -1);
1439 soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger));
1443 char* newagent = malloc(1024);
1445 strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent));
1446 strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent));
1447 strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent));
1449 if (uname (&s->unameinfo) == -1) {
1450 printf("Error getting uname info. Not replacing system-related user agent variables.\n");
1452 strcpy(newagent, str_replace("%sysname%", s->unameinfo.sysname, newagent));
1453 strcpy(newagent, str_replace("%nodename%", s->unameinfo.nodename, newagent));
1454 strcpy(newagent, str_replace("%kernrel%", s->unameinfo.release, newagent));
1455 strcpy(newagent, str_replace("%kernver%", s->unameinfo.version, newagent));
1456 strcpy(newagent, str_replace("%arch-system%", s->unameinfo.machine, newagent));
1459 strcpy(newagent, str_replace("%domainname%", s->unameinfo.domainname, newagent));
1463 strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent));
1464 strcpy(newagent, str_replace("%commit%", COMMIT, newagent));
1466 n->useragent = malloc(1024);
1467 strcpy(n->useragent, newagent);
1468 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL);
1471 if(n->max_conns >= 1){
1472 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL);
1475 if(n->max_conns_host >= 1){
1476 g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL);
1479 printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none");
1480 printf("HTTP logging level: %d\n", b->http_debug);
1481 printf("User-agent: %s\n", n->useragent? n->useragent : "default");
1482 printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0);
1483 printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0);
1485 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1488 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1491 if (!uzbl.behave.cookie_handler) return;
1493 gchar * stdout = NULL;
1494 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1495 GString* args = g_string_new ("");
1496 SoupURI * soup_uri = soup_message_get_uri(msg);
1497 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1498 run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout);
1500 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1502 g_string_free(args, TRUE);
1506 save_cookies (SoupMessage *msg, gpointer user_data){
1510 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1511 cookie = soup_cookie_to_set_cookie_header(ck->data);
1512 GString* args = g_string_new ("");
1513 SoupURI * soup_uri = soup_message_get_uri(msg);
1514 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1515 run_command_async(uzbl.behave.cookie_handler, args->str);
1516 g_string_free(args, TRUE);
1523 main (int argc, char* argv[]) {
1524 gtk_init (&argc, &argv);
1525 if (!g_thread_supported ())
1526 g_thread_init (NULL);
1528 printf("Uzbl start location: %s\n", argv[0]);
1529 strcpy(uzbl.state.executable_path,argv[0]);
1531 strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1532 strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1534 GError *error = NULL;
1535 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1536 g_option_context_add_main_entries (context, entries, NULL);
1537 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1538 g_option_context_parse (context, &argc, &argv, &error);
1539 /* initialize hash table */
1540 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1542 uzbl.net.soup_session = webkit_get_default_session();
1543 uzbl.state.keycmd = g_string_new("");
1548 if (uzbl.behave.always_insert_mode)
1549 uzbl.behave.insert_mode = TRUE;
1551 GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
1552 if (uzbl.behave.status_top)
1553 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1554 gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
1555 if (!uzbl.behave.status_top)
1556 gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
1558 uzbl.gui.main_window = create_window ();
1559 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox);
1561 load_uri (uzbl.gui.web_view, uzbl.state.uri);
1563 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1564 gtk_widget_show_all (uzbl.gui.main_window);
1565 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1566 printf("window_id %i\n",(int) uzbl.xwin);
1567 printf("pid %i\n", getpid ());
1568 printf("name: %s\n", uzbl.state.instance_name);
1570 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1571 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1572 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1573 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1574 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1577 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1578 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1584 if (!uzbl.behave.status_format)
1585 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1586 if (!uzbl.behave.show_status)
1587 gtk_widget_hide(uzbl.gui.mainbar);
1592 make_var_to_name_hash();
1594 /*if (uzbl.behave.fifo_dir)
1596 /*if (uzbl.behave.socket_dir)
1602 return EXIT_SUCCESS;
1605 /* vi: set et ts=4: */