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 { "title_format_long", (void *)&uzbl.behave.title_format_long },
73 { "title_format_short", (void *)&uzbl.behave.title_format_short },
74 { "insert_mode", (void *)&uzbl.behave.insert_mode },
75 { "always_insert_mode", (void *)&uzbl.behave.always_insert_mode },
76 { "reset_command_mode", (void *)&uzbl.behave.reset_command_mode },
77 { "modkey" , (void *)&uzbl.behave.modkey },
78 { "load_finish_handler",(void *)&uzbl.behave.load_finish_handler},
79 { "history_handler", (void *)&uzbl.behave.history_handler },
80 { "download_handler", (void *)&uzbl.behave.download_handler },
81 { "cookie_handler", (void *)&uzbl.behave.cookie_handler },
82 { "fifo_dir", (void *)&uzbl.behave.fifo_dir },
83 { "socket_dir", (void *)&uzbl.behave.socket_dir },
84 { "http_debug", (void *)&uzbl.behave.http_debug },
85 { "default_font_size", (void *)&uzbl.behave.default_font_size },
86 { "minimum_font_size", (void *)&uzbl.behave.minimum_font_size },
87 { "shell_cmd", (void *)&uzbl.behave.shell_cmd },
88 { "proxy_url", (void *)&uzbl.net.proxy_url },
89 { "max_conns", (void *)&uzbl.net.max_conns },
90 { "max_conns_host", (void *)&uzbl.net.max_conns_host },
91 { "useragent", (void *)&uzbl.net.useragent },
93 }, *n2v_p = var_name_to_ptr;
99 { "SHIFT", GDK_SHIFT_MASK }, // shift
100 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
101 { "CONTROL", GDK_CONTROL_MASK }, // control
102 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
103 { "MOD2", GDK_MOD2_MASK }, // 5th mod
104 { "MOD3", GDK_MOD3_MASK }, // 6th mod
105 { "MOD4", GDK_MOD4_MASK }, // 7th mod
106 { "MOD5", GDK_MOD5_MASK }, // 8th mod
107 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
108 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
109 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
110 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
111 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
112 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
113 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
114 { "META", GDK_META_MASK }, // meta (since 2.10)
118 /* construct a hash from the var_name_to_ptr array for quick access */
120 make_var_to_name_hash() {
121 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
123 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
128 /* commandline arguments (set initial values for the state variables) */
129 static GOptionEntry entries[] =
131 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
132 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, "Whether to print all messages or just errors.", "VERBOSE" },
133 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" },
134 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
135 { NULL, 0, 0, 0, NULL, NULL, NULL }
138 typedef void (*Command)(WebKitWebView*, const char *);
140 /* --- UTILITY FUNCTIONS --- */
146 snprintf(tmp, sizeof(tmp), "%i", val);
147 return g_strdup(tmp);
151 str_replace (const char* search, const char* replace, const char* string) {
152 return g_strjoinv (replace, g_strsplit (string, search, -1));
156 setup_signal(int signr, sigfunc *shandler) {
157 struct sigaction nh, oh;
159 nh.sa_handler = shandler;
160 sigemptyset(&nh.sa_mask);
163 if(sigaction(signr, &nh, &oh) < 0)
171 if (uzbl.behave.fifo_dir)
172 unlink (uzbl.comm.fifo_path);
173 if (uzbl.behave.socket_dir)
174 unlink (uzbl.comm.socket_path);
176 g_string_free(uzbl.state.keycmd, TRUE);
177 g_hash_table_destroy(uzbl.bindings);
178 g_hash_table_destroy(uzbl.behave.commands);
182 /* --- SIGNAL HANDLER --- */
185 catch_sigterm(int s) {
191 catch_sigint(int s) {
197 /* --- CALLBACKS --- */
200 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
203 (void) navigation_action;
204 (void) policy_decision;
206 const gchar* uri = webkit_network_request_get_uri (request);
207 if (uzbl.state.verbose)
208 printf("New window requested -> %s \n", uri);
209 new_window_load_uri(uri);
214 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
218 if (uzbl.state.selected_url[0]!=0) {
219 if (uzbl.state.verbose)
220 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
221 new_window_load_uri(uzbl.state.selected_url);
223 if (uzbl.state.verbose)
224 printf("New web view -> %s\n","Nothing to open, exiting");
230 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
233 if (uzbl.behave.download_handler) {
234 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
235 if (uzbl.state.verbose)
236 printf("Download -> %s\n",uri);
237 run_command(uzbl.behave.download_handler, uri, FALSE, NULL);
242 /* scroll a bar in a given direction */
244 scroll (GtkAdjustment* bar, const char *param) {
248 amount = g_ascii_strtod(param, &end);
251 fprintf(stderr, "found something after double: %s\n", end);
253 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
256 static void scroll_begin(WebKitWebView* page, const char *param) {
257 (void) page; (void) param;
258 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
261 static void scroll_end(WebKitWebView* page, const char *param) {
262 (void) page; (void) param;
263 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
264 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
267 static void scroll_vert(WebKitWebView* page, const char *param) {
269 scroll(uzbl.gui.bar_v, param);
272 static void scroll_horz(WebKitWebView* page, const char *param) {
274 scroll(uzbl.gui.bar_h, param);
279 if (!uzbl.behave.show_status) {
280 gtk_widget_hide(uzbl.gui.mainbar);
282 gtk_widget_show(uzbl.gui.mainbar);
288 toggle_status_cb (WebKitWebView* page, const char *param) {
292 if (uzbl.behave.show_status) {
293 gtk_widget_hide(uzbl.gui.mainbar);
295 gtk_widget_show(uzbl.gui.mainbar);
297 uzbl.behave.show_status = !uzbl.behave.show_status;
302 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
306 //Set selected_url state variable
307 uzbl.state.selected_url[0] = '\0';
309 strcpy (uzbl.state.selected_url, link);
315 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
319 if (uzbl.gui.main_title)
320 g_free (uzbl.gui.main_title);
321 uzbl.gui.main_title = g_strdup (title);
326 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
329 uzbl.gui.sbar.load_progress = progress;
334 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
338 if (uzbl.behave.load_finish_handler) {
339 run_command(uzbl.behave.load_finish_handler, NULL, FALSE, NULL);
344 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
347 free (uzbl.state.uri);
348 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
349 uzbl.state.uri = g_string_free (newuri, FALSE);
350 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
351 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
354 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
358 destroy_cb (GtkWidget* widget, gpointer data) {
366 if (uzbl.behave.history_handler) {
368 struct tm * timeinfo;
371 timeinfo = localtime ( &rawtime );
372 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
373 GString* args = g_string_new ("");
374 g_string_printf (args, "'%s'", date);
375 run_command(uzbl.behave.history_handler, args->str, FALSE, NULL);
376 g_string_free (args, TRUE);
381 /* VIEW funcs (little webkit wrappers) */
382 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
384 VIEWFUNC(reload_bypass_cache)
385 VIEWFUNC(stop_loading)
392 /* -- command to callback/function map for things we cannot attach to any signals */
395 static struct {char *name; Command command;} cmdlist[] =
397 { "back", view_go_back },
398 { "forward", view_go_forward },
399 { "scroll_vert", scroll_vert },
400 { "scroll_horz", scroll_horz },
401 { "scroll_begin", scroll_begin },
402 { "scroll_end", scroll_end },
403 { "reload", view_reload, },
404 { "reload_ign_cache", view_reload_bypass_cache},
405 { "stop", view_stop_loading, },
406 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
407 { "zoom_out", view_zoom_out, },
409 { "script", run_js },
410 { "toggle_status", toggle_status_cb },
413 { "exit", close_uzbl },
414 { "search", search_text },
415 { "insert_mode", set_insert_mode },
423 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
425 for (i = 0; i < LENGTH(cmdlist); i++)
426 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
429 /* -- CORE FUNCTIONS -- */
432 free_action(gpointer act) {
433 Action *action = (Action*)act;
434 g_free(action->name);
436 g_free(action->param);
441 new_action(const gchar *name, const gchar *param) {
442 Action *action = g_new(Action, 1);
444 action->name = g_strdup(name);
446 action->param = g_strdup(param);
448 action->param = NULL;
454 file_exists (const char * filename) {
455 return (access(filename, F_OK) == 0);
459 set_insert_mode(WebKitWebView *page, const gchar *param) {
463 uzbl.behave.insert_mode = TRUE;
468 load_uri (WebKitWebView * web_view, const gchar *param) {
470 GString* newuri = g_string_new (param);
471 if (g_strrstr (param, "://") == NULL)
472 g_string_prepend (newuri, "http://");
473 /* if we do handle cookies, ask our handler for them */
474 webkit_web_view_load_uri (web_view, newuri->str);
475 g_string_free (newuri, TRUE);
480 run_js (WebKitWebView * web_view, const gchar *param) {
482 webkit_web_view_execute_script (web_view, param);
486 search_text (WebKitWebView *page, const char *param) {
487 if ((param) && (param[0] != '\0')) {
488 strcpy(uzbl.state.searchtx, param);
490 if (uzbl.state.searchtx[0] != '\0') {
491 if (uzbl.state.verbose)
492 printf ("Searching: %s\n", uzbl.state.searchtx);
493 webkit_web_view_unmark_text_matches (page);
494 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
495 webkit_web_view_set_highlight_text_matches (page, TRUE);
496 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
501 new_window_load_uri (const gchar * uri) {
502 GString* to_execute = g_string_new ("");
503 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
505 for (i = 0; entries[i].long_name != NULL; i++) {
506 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
507 gchar** str = (gchar**)entries[i].arg_data;
509 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
513 if (uzbl.state.verbose)
514 printf("\n%s\n", to_execute->str);
515 g_spawn_command_line_async (to_execute->str, NULL);
516 g_string_free (to_execute, TRUE);
520 close_uzbl (WebKitWebView *page, const char *param) {
526 /* --Statusbar functions-- */
528 build_progressbar_ascii(int percent) {
532 GString *bar = g_string_new("");
534 l = (double)percent*((double)width/100.);
535 l = (int)(l+.5)>=(int)l ? l+.5 : l;
537 for(i=0; i<(int)l; i++)
538 g_string_append(bar, "=");
541 g_string_append(bar, "·");
543 return g_string_free(bar, FALSE);
548 const GScannerConfig scan_config = {
551 ) /* cset_skip_characters */,
556 ) /* cset_identifier_first */,
563 ) /* cset_identifier_nth */,
564 ( "" ) /* cpair_comment_single */,
566 TRUE /* case_sensitive */,
568 FALSE /* skip_comment_multi */,
569 FALSE /* skip_comment_single */,
570 FALSE /* scan_comment_multi */,
571 TRUE /* scan_identifier */,
572 TRUE /* scan_identifier_1char */,
573 FALSE /* scan_identifier_NULL */,
574 TRUE /* scan_symbols */,
575 FALSE /* scan_binary */,
576 FALSE /* scan_octal */,
577 FALSE /* scan_float */,
578 FALSE /* scan_hex */,
579 FALSE /* scan_hex_dollar */,
580 FALSE /* scan_string_sq */,
581 FALSE /* scan_string_dq */,
582 TRUE /* numbers_2_int */,
583 FALSE /* int_2_float */,
584 FALSE /* identifier_2_string */,
585 FALSE /* char_2_token */,
586 FALSE /* symbol_2_token */,
587 TRUE /* scope_0_fallback */,
592 uzbl.scan = g_scanner_new(&scan_config);
593 while(symp->symbol_name) {
594 g_scanner_scope_add_symbol(uzbl.scan, 0,
596 GINT_TO_POINTER(symp->symbol_token));
602 expand_template(const char *template) {
603 if(!template) return NULL;
605 GTokenType token = G_TOKEN_NONE;
606 GString *ret = g_string_new("");
610 g_scanner_input_text(uzbl.scan, template, strlen(template));
611 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
612 token = g_scanner_get_next_token(uzbl.scan);
614 if(token == G_TOKEN_SYMBOL) {
615 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
620 g_markup_printf_escaped("%s", uzbl.state.uri):"");
623 buf = itos(uzbl.gui.sbar.load_progress);
624 g_string_append(ret, buf);
627 case SYM_LOADPRGSBAR:
628 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
629 g_string_append(ret, buf);
635 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
637 case SYM_SELECTED_URI:
639 uzbl.state.selected_url?
640 g_markup_printf_escaped("%s", uzbl.state.selected_url):"");
643 buf = itos(uzbl.xwin);
645 uzbl.state.instance_name?uzbl.state.instance_name:buf);
650 uzbl.state.keycmd->str ?
651 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
655 uzbl.behave.insert_mode?"[I]":"[C]");
659 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
663 buf = itos(WEBKIT_MAJOR_VERSION);
664 g_string_append(ret, buf);
668 buf = itos(WEBKIT_MINOR_VERSION);
669 g_string_append(ret, buf);
673 buf = itos(WEBKIT_MICRO_VERSION);
674 g_string_append(ret, buf);
678 g_string_append(ret, uzbl.state.unameinfo.sysname);
681 g_string_append(ret, uzbl.state.unameinfo.nodename);
684 g_string_append(ret, uzbl.state.unameinfo.release);
687 g_string_append(ret, uzbl.state.unameinfo.version);
690 g_string_append(ret, uzbl.state.unameinfo.machine);
693 g_string_append(ret, ARCH);
697 g_string_append(ret, uzbl.state.unameinfo.domainname);
701 g_string_append(ret, COMMIT);
707 else if(token == G_TOKEN_INT) {
708 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
709 g_string_append(ret, buf);
712 else if(token == G_TOKEN_IDENTIFIER) {
713 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
715 else if(token == G_TOKEN_CHAR) {
716 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
720 return g_string_free(ret, FALSE);
722 /* --End Statusbar functions-- */
725 // make sure to put "" or '' around args, so that if there is whitespace we can still keep arguments together.
726 // note: if your args contain ', you must wrap them in "" (you cannot escape inside '')
727 // if your args contain ", you should wrap them in "" and escape them
729 run_command (const char *command, const char *args, const gboolean sync, char **stdout) {
730 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
731 GString* to_execute = g_string_new ("");
733 gchar* cmd = g_strstrip(g_strdup(command));
735 const char* search = "\"";
736 const char* replace = "\\\"";
737 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
738 cmd, (uzbl.state.config_file ? uzbl.state.config_file : "(null)"),
739 (int) getpid(), (int) uzbl.xwin, uzbl.comm.fifo_path,
740 uzbl.comm.socket_path);
741 g_string_append_printf (to_execute, " \"%s\" \"%s\"",
743 str_replace(search, replace, uzbl.gui.main_title));
744 if(args) g_string_append_printf (to_execute, " %s", args);
747 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, &err);
748 } else result = g_spawn_command_line_async (to_execute->str, &err);
749 if (uzbl.state.verbose)
750 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
751 g_string_free (to_execute, TRUE);
753 g_printerr("error on run_command: %s\n", err->message);
761 spawn(WebKitWebView *web_view, const char *param) {
763 run_command(param, NULL, FALSE, NULL);
767 spawn_sh(WebKitWebView *web_view, const char *param) {
769 gchar *cmd = g_strdup_printf(uzbl.behave.shell_cmd, param);
775 parse_command(const char *cmd, const char *param) {
778 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
779 c(uzbl.gui.web_view, param);
781 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
787 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
788 G_REGEX_OPTIMIZE, 0, NULL);
789 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
790 G_REGEX_OPTIMIZE, 0, NULL);
791 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
792 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
793 uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
794 G_REGEX_OPTIMIZE, 0, NULL);
795 uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
796 G_REGEX_OPTIMIZE, 0, NULL);
800 get_var_value(gchar *name) {
803 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
804 if(var_is("status_format", name)
805 || var_is("useragent", name)
806 || var_is("title_format_short", name)
807 || var_is("title_format_long", name)) {
808 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
809 } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
818 if(*uzbl.net.proxy_url == ' '
819 || uzbl.net.proxy_url == NULL) {
820 soup_session_remove_feature_by_type(uzbl.net.soup_session,
821 (GType) SOUP_SESSION_PROXY_URI);
824 suri = soup_uri_new(uzbl.net.proxy_url);
825 g_object_set(G_OBJECT(uzbl.net.soup_session),
826 SOUP_SESSION_PROXY_URI,
836 gtk_widget_ref(uzbl.gui.scrolled_win);
837 gtk_widget_ref(uzbl.gui.mainbar);
838 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
839 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
841 if(uzbl.behave.status_top) {
842 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
843 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.scrolled_win, TRUE, TRUE, 0);
847 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
849 gtk_widget_unref(uzbl.gui.scrolled_win);
850 gtk_widget_unref(uzbl.gui.mainbar);
851 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
855 var_is(const char *x, const char *y) {
856 return (strcmp(x, y) == 0 ? TRUE : FALSE );
860 set_var_value(gchar *name, gchar *val) {
864 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
865 if(var_is("status_message", name)
866 || var_is("status_background", name)
867 || var_is("status_format", name)
868 || var_is("title_format_long", name)
869 || var_is("title_format_short", name)
870 || var_is("load_finish_handler", name)
871 || var_is("history_handler", name)
872 || var_is("download_handler", name)
873 || var_is("cookie_handler", name)) {
879 else if(var_is("uri", name)) {
882 load_uri(uzbl.gui.web_view, (const gchar*)*p);
884 else if(var_is("proxy_url", name)) {
889 else if(var_is("fifo_dir", name)) {
891 *p = init_fifo(g_strdup(val));
893 else if(var_is("socket_dir", name)) {
895 *p = init_socket(g_strdup(val));
897 else if(var_is("modkey", name)) {
900 *p = g_utf8_strup(val, -1);
901 uzbl.behave.modmask = 0;
902 for (i = 0; modkeys[i].key != NULL; i++) {
903 if (g_strrstr(*p, modkeys[i].key))
904 uzbl.behave.modmask |= modkeys[i].mask;
907 else if(var_is("useragent", name)) {
909 *p = set_useragent(g_strdup(val));
911 else if(var_is("shell_cmd", name)) {
915 /* variables that take int values */
918 *ip = (int)strtoul(val, &endp, 10);
920 if(var_is("show_status", name)) {
923 else if(var_is("always_insert_mode", name)) {
924 uzbl.behave.insert_mode =
925 uzbl.behave.always_insert_mode ? TRUE : FALSE;
928 else if (var_is("max_conns", name)) {
929 g_object_set(G_OBJECT(uzbl.net.soup_session),
930 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
932 else if (var_is("max_conns_host", name)) {
933 g_object_set(G_OBJECT(uzbl.net.soup_session),
934 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
936 else if (var_is("http_debug", name)) {
937 //soup_session_remove_feature
938 // (uzbl.net.soup_session, uzbl.net.soup_logger);
939 soup_session_remove_feature
940 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
941 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
942 /*g_free(uzbl.net.soup_logger);*/
944 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
945 soup_session_add_feature(uzbl.net.soup_session,
946 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
948 else if (var_is("status_top", name)) {
951 else if (var_is("default_font_size", name)) {
952 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
953 g_object_set (G_OBJECT(ws), "default-font-size", *ip, NULL);
955 else if (var_is("minimum_font_size", name)) {
956 WebKitWebSettings *ws = webkit_web_view_get_settings(uzbl.gui.web_view);
957 g_object_set (G_OBJECT(ws), "minimum-font-size", *ip, NULL);
965 runcmd(WebKitWebView* page, const char *param) {
967 parse_cmd_line(param);
971 parse_cmd_line(const char *ctl_line) {
975 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
976 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
977 if(tokens[0][0] == 0) {
978 set_var_value(tokens[1], tokens[2]);
982 printf("Error in command: %s\n", tokens[0]);
985 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
986 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
987 if(tokens[0][0] == 0) {
988 get_var_value(tokens[1]);
992 printf("Error in command: %s\n", tokens[0]);
995 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
996 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
997 if(tokens[0][0] == 0) {
998 add_binding(tokens[1], tokens[2]);
1002 printf("Error in command: %s\n", tokens[0]);
1005 else if(ctl_line[0] == 'A' || ctl_line[0] == 'a') {
1006 tokens = g_regex_split(uzbl.comm.act_regex, ctl_line, 0);
1007 if(tokens[0][0] == 0) {
1008 parse_command(tokens[1], tokens[2]);
1012 printf("Error in command: %s\n", tokens[0]);
1014 /* KEYCMD command */
1015 else if(ctl_line[0] == 'K' || ctl_line[0] == 'k') {
1016 tokens = g_regex_split(uzbl.comm.keycmd_regex, ctl_line, 0);
1017 if(tokens[0][0] == 0) {
1018 /* should incremental commands want each individual "keystroke"
1019 sent in a loop or the whole string in one go like now? */
1020 g_string_assign(uzbl.state.keycmd, tokens[1]);
1027 else if( (ctl_line[0] == '#')
1028 || (ctl_line[0] == ' ')
1029 || (ctl_line[0] == '\n'))
1030 ; /* ignore these lines */
1032 printf("Command not understood (%s)\n", ctl_line);
1038 build_stream_name(int type, const gchar* dir) {
1040 State *s = &uzbl.state;
1043 xwin_str = itos((int)uzbl.xwin);
1045 str = g_strdup_printf
1046 ("%s/uzbl_fifo_%s", dir,
1047 s->instance_name ? s->instance_name : xwin_str);
1048 } else if (type == SOCKET) {
1049 str = g_strdup_printf
1050 ("%s/uzbl_socket_%s", dir,
1051 s->instance_name ? s->instance_name : xwin_str );
1058 control_fifo(GIOChannel *gio, GIOCondition condition) {
1059 if (uzbl.state.verbose)
1060 printf("triggered\n");
1065 if (condition & G_IO_HUP)
1066 g_error ("Fifo: Read end of pipe died!\n");
1069 g_error ("Fifo: GIOChannel broke\n");
1071 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1072 if (ret == G_IO_STATUS_ERROR) {
1073 g_error ("Fifo: Error reading: %s\n", err->message);
1077 parse_cmd_line(ctl_line);
1084 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1085 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1086 if (unlink(uzbl.comm.fifo_path) == -1)
1087 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1088 g_free(uzbl.comm.fifo_path);
1089 uzbl.comm.fifo_path = NULL;
1092 if (*dir == ' ') { /* space unsets the variable */
1097 GIOChannel *chan = NULL;
1098 GError *error = NULL;
1099 gchar *path = build_stream_name(FIFO, dir);
1101 if (!file_exists(path)) {
1102 if (mkfifo (path, 0666) == 0) {
1103 // 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.
1104 chan = g_io_channel_new_file(path, "r+", &error);
1106 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1107 if (uzbl.state.verbose)
1108 printf ("init_fifo: created successfully as %s\n", path);
1109 uzbl.comm.fifo_path = path;
1111 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1112 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1113 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1114 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1116 /* if we got this far, there was an error; cleanup */
1117 if (error) g_error_free (error);
1124 control_stdin(GIOChannel *gio, GIOCondition condition) {
1125 gchar *ctl_line = NULL;
1126 gsize ctl_line_len = 0;
1129 if (condition & G_IO_HUP) {
1130 ret = g_io_channel_shutdown (gio, FALSE, NULL);
1134 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, NULL);
1135 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1138 parse_cmd_line(ctl_line);
1146 GIOChannel *chan = NULL;
1147 GError *error = NULL;
1149 chan = g_io_channel_unix_new(fileno(stdin));
1151 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1152 g_error ("Stdin: could not add watch\n");
1154 if (uzbl.state.verbose)
1155 printf ("Stdin: watch added successfully\n");
1158 g_error ("Stdin: Error while opening: %s\n", error->message);
1160 if (error) g_error_free (error);
1164 control_socket(GIOChannel *chan) {
1165 struct sockaddr_un remote;
1166 char buffer[512], *ctl_line;
1168 int sock, clientsock, n, done;
1171 sock = g_io_channel_unix_get_fd(chan);
1173 memset (buffer, 0, sizeof (buffer));
1175 t = sizeof (remote);
1176 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1180 memset (temp, 0, sizeof (temp));
1181 n = recv (clientsock, temp, 128, 0);
1183 buffer[strlen (buffer)] = '\0';
1187 strcat (buffer, temp);
1190 if (strcmp (buffer, "\n") < 0) {
1191 buffer[strlen (buffer) - 1] = '\0';
1193 buffer[strlen (buffer)] = '\0';
1196 ctl_line = g_strdup(buffer);
1197 parse_cmd_line (ctl_line);
1200 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1201 GError *error = NULL;
1204 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1205 if (ret == G_IO_STATUS_ERROR)
1206 g_error ("Error reading: %s\n", error->message);
1208 printf("Got line %s (%u bytes) \n",ctl_line, len);
1210 parse_line(ctl_line);
1218 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1219 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1220 if (unlink(uzbl.comm.socket_path) == -1)
1221 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1222 g_free(uzbl.comm.socket_path);
1223 uzbl.comm.socket_path = NULL;
1231 GIOChannel *chan = NULL;
1233 struct sockaddr_un local;
1234 gchar *path = build_stream_name(SOCKET, dir);
1236 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1238 local.sun_family = AF_UNIX;
1239 strcpy (local.sun_path, path);
1240 unlink (local.sun_path);
1242 len = strlen (local.sun_path) + sizeof (local.sun_family);
1243 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1244 if (uzbl.state.verbose)
1245 printf ("init_socket: opened in %s\n", path);
1248 if( (chan = g_io_channel_unix_new(sock)) ) {
1249 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1250 uzbl.comm.socket_path = path;
1253 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1255 /* if we got this far, there was an error; cleanup */
1262 update_title (void) {
1263 Behaviour *b = &uzbl.behave;
1265 if (b->show_status) {
1267 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), expand_template(b->title_format_short));
1268 // TODO: we should probably not do this every time we want to update the title..?
1269 statln = expand_template(uzbl.behave.status_format);
1270 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1271 if (b->status_background) {
1273 gdk_color_parse (b->status_background, &color);
1274 //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)
1275 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1279 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), expand_template(b->title_format_long));
1284 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1286 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1290 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1291 || 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)
1294 /* turn off insert mode (if always_insert_mode is not used) */
1295 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1296 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1301 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1304 if (event->keyval == GDK_Escape) {
1305 g_string_truncate(uzbl.state.keycmd, 0);
1310 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1311 if (event->keyval == GDK_Insert) {
1313 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1314 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1316 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1319 g_string_append (uzbl.state.keycmd, str);
1326 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1327 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1331 gboolean key_ret = FALSE;
1332 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1334 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1336 run_keycmd(key_ret);
1338 if (key_ret) return (!uzbl.behave.insert_mode);
1343 run_keycmd(const gboolean key_ret) {
1344 /* run the keycmd immediately if it isn't incremental and doesn't take args */
1346 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1347 g_string_truncate(uzbl.state.keycmd, 0);
1348 parse_command(action->name, action->param);
1352 /* try if it's an incremental keycmd or one that takes args, and run it */
1353 GString* short_keys = g_string_new ("");
1354 GString* short_keys_inc = g_string_new ("");
1356 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1357 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1358 g_string_assign(short_keys_inc, short_keys->str);
1359 g_string_append_c(short_keys, '_');
1360 g_string_append_c(short_keys_inc, '*');
1362 gboolean exec_now = FALSE;
1363 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1364 if (key_ret) exec_now = TRUE; /* run normal cmds only if return was pressed */
1365 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1366 if (key_ret) { /* just quit the incremental command on return */
1367 g_string_truncate(uzbl.state.keycmd, 0);
1369 } else exec_now = TRUE; /* always exec incr. commands on keys other than return */
1373 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1374 GString* actionname = g_string_new ("");
1375 GString* actionparam = g_string_new ("");
1376 g_string_erase (parampart, 0, i+1);
1378 g_string_printf (actionname, action->name, parampart->str);
1380 g_string_printf (actionparam, action->param, parampart->str);
1381 parse_command(actionname->str, actionparam->str);
1382 g_string_free (actionname, TRUE);
1383 g_string_free (actionparam, TRUE);
1384 g_string_free (parampart, TRUE);
1386 g_string_truncate(uzbl.state.keycmd, 0);
1390 g_string_truncate(short_keys, short_keys->len - 1);
1392 g_string_free (short_keys, TRUE);
1393 g_string_free (short_keys_inc, TRUE);
1400 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1401 //main_window_ref = g_object_ref(scrolled_window);
1402 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
1404 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1405 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1407 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1408 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1409 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1410 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (log_history_cb), g->web_view);
1411 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1412 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1413 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1414 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1415 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1416 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1418 return scrolled_window;
1425 g->mainbar = gtk_hbox_new (FALSE, 0);
1427 /* keep a reference to the bar so we can re-pack it at runtime*/
1428 //sbar_ref = g_object_ref(g->mainbar);
1430 g->mainbar_label = gtk_label_new ("");
1431 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1432 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1433 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1434 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1435 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1440 GtkWidget* create_window () {
1441 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1442 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1443 gtk_widget_set_name (window, "Uzbl browser");
1444 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1450 add_binding (const gchar *key, const gchar *act) {
1451 char **parts = g_strsplit(act, " ", 2);
1458 if (uzbl.state.verbose)
1459 printf ("Binding %-10s : %s\n", key, act);
1460 action = new_action(parts[0], parts[1]);
1462 if(g_hash_table_lookup(uzbl.bindings, key))
1463 g_hash_table_remove(uzbl.bindings, key);
1464 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1470 get_xdg_var (XDG_Var xdg) {
1471 const gchar* actual_value = getenv (xdg.environmental);
1472 const gchar* home = getenv ("HOME");
1474 gchar* return_value = str_replace ("~", home, g_strdup (actual_value));
1476 if (! actual_value || strcmp (actual_value, "") == 0) {
1477 if (xdg.default_value) {
1478 return_value = str_replace ("~", home, g_strdup (xdg.default_value));
1480 return_value = NULL;
1484 return return_value;
1488 find_xdg_file (int xdg_type, char* filename) {
1489 /* xdg_type = 0 => config
1490 xdg_type = 1 => data
1491 xdg_type = 2 => cache*/
1493 gchar* xdg_config_home = get_xdg_var (XDG[0]);
1494 gchar* xdg_data_home = get_xdg_var (XDG[1]);
1495 gchar* xdg_cache_home = get_xdg_var (XDG[2]);
1496 gchar* xdg_config_dirs = get_xdg_var (XDG[3]);
1497 gchar* xdg_data_dirs = get_xdg_var (XDG[4]);
1498 gchar* temporary_file = (char *)malloc (1024);
1499 gchar* temporary_string = NULL;
1503 strcpy (temporary_file, xdg_config_home);
1506 strcpy (temporary_file, xdg_data_home);
1509 strcpy (temporary_file, xdg_cache_home);
1511 strcat (temporary_file, filename);
1513 if (! file_exists (temporary_file) && xdg_type != 2) {
1515 temporary_string = (char *) strtok_r (xdg_config_dirs, ":", &saveptr);
1518 temporary_string = (char *) strtok_r (xdg_data_dirs, ":", &saveptr);
1520 while (temporary_string && ! file_exists (temporary_file)) {
1521 strcpy (temporary_file, temporary_string);
1522 strcat (temporary_file, filename);
1523 temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
1527 if (file_exists (temporary_file)) {
1528 return temporary_file;
1536 State *s = &uzbl.state;
1537 Network *n = &uzbl.net;
1539 uzbl.behave.reset_command_mode = 1;
1541 if (!s->config_file) {
1542 s->config_file = g_strdup (find_xdg_file (0, "/uzbl/config"));
1545 if (s->config_file) {
1546 GIOChannel *chan = NULL;
1547 gchar *readbuf = NULL;
1550 chan = g_io_channel_new_file(s->config_file, "r", NULL);
1553 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
1554 == G_IO_STATUS_NORMAL) {
1555 parse_cmd_line(readbuf);
1559 g_io_channel_unref (chan);
1560 if (uzbl.state.verbose)
1561 printf ("Config %s loaded\n", s->config_file);
1563 fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
1566 if (uzbl.state.verbose)
1567 printf ("No configuration file loaded.\n");
1569 if (!uzbl.behave.status_format)
1570 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1571 if (!uzbl.behave.title_format_long)
1572 uzbl.behave.title_format_long = g_strdup(TITLE_LONG_DEFAULT);
1573 if (!uzbl.behave.title_format_short)
1574 uzbl.behave.title_format_short = g_strdup(TITLE_SHORT_DEFAULT);
1577 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1581 set_useragent(gchar *val) {
1586 gchar *ua = expand_template(val);
1588 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1592 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1595 if (!uzbl.behave.cookie_handler) return;
1597 gchar * stdout = NULL;
1598 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1599 GString* args = g_string_new ("");
1600 SoupURI * soup_uri = soup_message_get_uri(msg);
1601 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1602 run_command(uzbl.behave.cookie_handler, args->str, TRUE, &stdout);
1604 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1606 g_string_free(args, TRUE);
1610 save_cookies (SoupMessage *msg, gpointer user_data){
1614 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1615 cookie = soup_cookie_to_set_cookie_header(ck->data);
1616 GString* args = g_string_new ("");
1617 SoupURI * soup_uri = soup_message_get_uri(msg);
1618 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1619 run_command(uzbl.behave.cookie_handler, args->str, FALSE, NULL);
1620 g_string_free(args, TRUE);
1628 main (int argc, char* argv[]) {
1629 gtk_init (&argc, &argv);
1630 if (!g_thread_supported ())
1631 g_thread_init (NULL);
1633 strcpy(uzbl.state.executable_path,argv[0]);
1635 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1636 g_option_context_add_main_entries (context, entries, NULL);
1637 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1638 g_option_context_parse (context, &argc, &argv, NULL);
1639 /* initialize hash table */
1640 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1642 uzbl.net.soup_session = webkit_get_default_session();
1643 uzbl.state.keycmd = g_string_new("");
1645 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1646 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1647 if(setup_signal(SIGINT, catch_sigint) == SIG_ERR)
1648 fprintf(stderr, "uzbl: error hooking SIGINT\n");
1650 if(uname(&uzbl.state.unameinfo) == -1)
1651 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
1656 make_var_to_name_hash();
1659 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
1661 uzbl.gui.scrolled_win = create_browser();
1664 /* initial packing */
1665 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1666 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1668 uzbl.gui.main_window = create_window ();
1669 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
1671 load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
1673 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1674 gtk_widget_show_all (uzbl.gui.main_window);
1675 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1677 if (uzbl.state.verbose) {
1678 printf("Uzbl start location: %s\n", argv[0]);
1679 printf("window_id %i\n",(int) uzbl.xwin);
1680 printf("pid %i\n", getpid ());
1681 printf("name: %s\n", uzbl.state.instance_name);
1684 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1685 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1686 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1687 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1688 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1692 if (!uzbl.behave.show_status)
1693 gtk_widget_hide(uzbl.gui.mainbar);
1702 return EXIT_SUCCESS;
1705 /* vi: set et ts=4: */