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 { "proxy_url", (void *)&uzbl.net.proxy_url },
84 { "max_conns", (void *)&uzbl.net.max_conns },
85 { "max_conns_host", (void *)&uzbl.net.max_conns_host },
86 { "useragent", (void *)&uzbl.net.useragent },
88 }, *n2v_p = var_name_to_ptr;
94 { "SHIFT", GDK_SHIFT_MASK }, // shift
95 { "LOCK", GDK_LOCK_MASK }, // capslock or shiftlock, depending on xserver's modmappings
96 { "CONTROL", GDK_CONTROL_MASK }, // control
97 { "MOD1", GDK_MOD1_MASK }, // 4th mod - normally alt but depends on modmappings
98 { "MOD2", GDK_MOD2_MASK }, // 5th mod
99 { "MOD3", GDK_MOD3_MASK }, // 6th mod
100 { "MOD4", GDK_MOD4_MASK }, // 7th mod
101 { "MOD5", GDK_MOD5_MASK }, // 8th mod
102 { "BUTTON1", GDK_BUTTON1_MASK }, // 1st mouse button
103 { "BUTTON2", GDK_BUTTON2_MASK }, // 2nd mouse button
104 { "BUTTON3", GDK_BUTTON3_MASK }, // 3rd mouse button
105 { "BUTTON4", GDK_BUTTON4_MASK }, // 4th mouse button
106 { "BUTTON5", GDK_BUTTON5_MASK }, // 5th mouse button
107 { "SUPER", GDK_SUPER_MASK }, // super (since 2.10)
108 { "HYPER", GDK_HYPER_MASK }, // hyper (since 2.10)
109 { "META", GDK_META_MASK }, // meta (since 2.10)
113 /* construct a hash from the var_name_to_ptr array for quick access */
115 make_var_to_name_hash() {
116 uzbl.comm.proto_var = g_hash_table_new(g_str_hash, g_str_equal);
118 g_hash_table_insert(uzbl.comm.proto_var, n2v_p->name, n2v_p->ptr);
123 /* commandline arguments (set initial values for the state variables) */
124 static GOptionEntry entries[] =
126 { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" },
127 { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" },
128 { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" },
129 { NULL, 0, 0, 0, NULL, NULL, NULL }
132 typedef void (*Command)(WebKitWebView*, const char *);
135 static char *XDG_CONFIG_HOME_default[256];
136 static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
139 /* --- UTILITY FUNCTIONS --- */
145 snprintf(tmp, sizeof(tmp), "%i", val);
146 return g_strdup(tmp);
150 setup_signal(int signr, sigfunc *shandler) {
151 struct sigaction nh, oh;
153 nh.sa_handler = shandler;
154 sigemptyset(&nh.sa_mask);
157 if(sigaction(signr, &nh, &oh) < 0)
165 if (uzbl.behave.fifo_dir)
166 unlink (uzbl.comm.fifo_path);
167 if (uzbl.behave.socket_dir)
168 unlink (uzbl.comm.socket_path);
170 g_string_free(uzbl.state.keycmd, TRUE);
171 g_hash_table_destroy(uzbl.bindings);
172 g_hash_table_destroy(uzbl.behave.commands);
176 /* --- SIGNAL HANDLER --- */
179 catch_sigterm(int s) {
184 /* --- CALLBACKS --- */
187 new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *navigation_action, WebKitWebPolicyDecision *policy_decision, gpointer user_data) {
190 (void) navigation_action;
191 (void) policy_decision;
193 const gchar* uri = webkit_network_request_get_uri (request);
194 printf("New window requested -> %s \n", uri);
195 new_window_load_uri(uri);
200 create_web_view_cb (WebKitWebView *web_view, WebKitWebFrame *frame, gpointer user_data) {
204 if (uzbl.state.selected_url[0]!=0) {
205 printf("\nNew web view -> %s\n",uzbl.state.selected_url);
206 new_window_load_uri(uzbl.state.selected_url);
208 printf("New web view -> %s\n","Nothing to open, exiting");
214 download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
217 if (uzbl.behave.download_handler) {
218 const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
219 printf("Download -> %s\n",uri);
220 run_command_async(uzbl.behave.download_handler, uri);
225 /* scroll a bar in a given direction */
227 scroll (GtkAdjustment* bar, const char *param) {
231 amount = g_ascii_strtod(param, &end);
234 fprintf(stderr, "found something after double: %s\n", end);
236 gtk_adjustment_set_value (bar, gtk_adjustment_get_value(bar)+amount);
239 static void scroll_begin(WebKitWebView* page, const char *param) {
240 (void) page; (void) param;
241 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_lower(uzbl.gui.bar_v));
244 static void scroll_end(WebKitWebView* page, const char *param) {
245 (void) page; (void) param;
246 gtk_adjustment_set_value (uzbl.gui.bar_v, gtk_adjustment_get_upper(uzbl.gui.bar_v) -
247 gtk_adjustment_get_page_size(uzbl.gui.bar_v));
250 static void scroll_vert(WebKitWebView* page, const char *param) {
252 scroll(uzbl.gui.bar_v, param);
255 static void scroll_horz(WebKitWebView* page, const char *param) {
257 scroll(uzbl.gui.bar_h, param);
262 if (!uzbl.behave.show_status) {
263 gtk_widget_hide(uzbl.gui.mainbar);
265 gtk_widget_show(uzbl.gui.mainbar);
271 toggle_status_cb (WebKitWebView* page, const char *param) {
275 if (uzbl.behave.show_status) {
276 gtk_widget_hide(uzbl.gui.mainbar);
278 gtk_widget_show(uzbl.gui.mainbar);
280 uzbl.behave.show_status = !uzbl.behave.show_status;
285 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data) {
289 //ADD HOVER URL TO WINDOW TITLE
290 uzbl.state.selected_url[0] = '\0';
292 strcpy (uzbl.state.selected_url, link);
298 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data) {
302 if (uzbl.gui.main_title)
303 g_free (uzbl.gui.main_title);
304 uzbl.gui.main_title = g_strdup (title);
309 progress_change_cb (WebKitWebView* page, gint progress, gpointer data) {
312 uzbl.gui.sbar.load_progress = progress;
317 load_finish_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
321 if (uzbl.behave.load_finish_handler) {
322 run_command_async(uzbl.behave.load_finish_handler, NULL);
327 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) {
330 free (uzbl.state.uri);
331 GString* newuri = g_string_new (webkit_web_frame_get_uri (frame));
332 uzbl.state.uri = g_string_free (newuri, FALSE);
333 if (uzbl.behave.reset_command_mode && uzbl.behave.insert_mode) {
334 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
337 g_string_truncate(uzbl.state.keycmd, 0); // don't need old commands to remain on new page?
341 destroy_cb (GtkWidget* widget, gpointer data) {
349 if (uzbl.behave.history_handler) {
351 struct tm * timeinfo;
354 timeinfo = localtime ( &rawtime );
355 strftime (date, 80, "%Y-%m-%d %H:%M:%S", timeinfo);
356 GString* args = g_string_new ("");
357 g_string_printf (args, "'%s'", date);
358 run_command_async(uzbl.behave.history_handler, args->str);
359 g_string_free (args, TRUE);
364 /* VIEW funcs (little webkit wrappers) */
365 #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);}
367 VIEWFUNC(reload_bypass_cache)
368 VIEWFUNC(stop_loading)
375 /* -- command to callback/function map for things we cannot attach to any signals */
378 static struct {char *name; Command command;} cmdlist[] =
380 { "back", view_go_back },
381 { "forward", view_go_forward },
382 { "scroll_vert", scroll_vert },
383 { "scroll_horz", scroll_horz },
384 { "scroll_begin", scroll_begin },
385 { "scroll_end", scroll_end },
386 { "reload", view_reload, },
387 { "reload_ign_cache", view_reload_bypass_cache},
388 { "stop", view_stop_loading, },
389 { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?).
390 { "zoom_out", view_zoom_out, },
392 { "script", run_js },
393 { "toggle_status", toggle_status_cb },
395 { "exit", close_uzbl },
396 { "search", search_text },
397 { "insert_mode", set_insert_mode },
405 uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal);
407 for (i = 0; i < LENGTH(cmdlist); i++)
408 g_hash_table_insert(uzbl.behave.commands, cmdlist[i].name, cmdlist[i].command);
411 /* -- CORE FUNCTIONS -- */
414 free_action(gpointer act) {
415 Action *action = (Action*)act;
416 g_free(action->name);
418 g_free(action->param);
423 new_action(const gchar *name, const gchar *param) {
424 Action *action = g_new(Action, 1);
426 action->name = g_strdup(name);
428 action->param = g_strdup(param);
430 action->param = NULL;
436 file_exists (const char * filename) {
437 FILE *file = fopen (filename, "r");
446 set_insert_mode(WebKitWebView *page, const gchar *param) {
450 uzbl.behave.insert_mode = TRUE;
455 load_uri (WebKitWebView * web_view, const gchar *param) {
457 GString* newuri = g_string_new (param);
458 if (g_strrstr (param, "://") == NULL)
459 g_string_prepend (newuri, "http://");
460 /* if we do handle cookies, ask our handler for them */
461 webkit_web_view_load_uri (web_view, newuri->str);
462 g_string_free (newuri, TRUE);
467 run_js (WebKitWebView * web_view, const gchar *param) {
469 webkit_web_view_execute_script (web_view, param);
473 search_text (WebKitWebView *page, const char *param) {
474 if ((param) && (param[0] != '\0')) {
475 strcpy(uzbl.state.searchtx, param);
477 if (uzbl.state.searchtx[0] != '\0') {
478 printf ("Searching: %s\n", uzbl.state.searchtx);
479 webkit_web_view_unmark_text_matches (page);
480 webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
481 webkit_web_view_set_highlight_text_matches (page, TRUE);
482 webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
487 new_window_load_uri (const gchar * uri) {
488 GString* to_execute = g_string_new ("");
489 g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
491 for (i = 0; entries[i].long_name != NULL; i++) {
492 if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
493 gchar** str = (gchar**)entries[i].arg_data;
495 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
499 printf("\n%s\n", to_execute->str);
500 g_spawn_command_line_async (to_execute->str, NULL);
501 g_string_free (to_execute, TRUE);
505 close_uzbl (WebKitWebView *page, const char *param) {
511 /* --Statusbar functions-- */
513 build_progressbar_ascii(int percent) {
517 GString *bar = g_string_new("");
519 l = (double)percent*((double)width/100.);
520 l = (int)(l+.5)>=(int)l ? l+.5 : l;
522 for(i=0; i<(int)l; i++)
523 g_string_append(bar, "=");
526 g_string_append(bar, "·");
528 return g_string_free(bar, FALSE);
533 const GScannerConfig scan_config = {
536 ) /* cset_skip_characters */,
541 ) /* cset_identifier_first */,
548 ) /* cset_identifier_nth */,
549 ( "" ) /* cpair_comment_single */,
551 TRUE /* case_sensitive */,
553 FALSE /* skip_comment_multi */,
554 FALSE /* skip_comment_single */,
555 FALSE /* scan_comment_multi */,
556 TRUE /* scan_identifier */,
557 TRUE /* scan_identifier_1char */,
558 FALSE /* scan_identifier_NULL */,
559 TRUE /* scan_symbols */,
560 FALSE /* scan_binary */,
561 FALSE /* scan_octal */,
562 FALSE /* scan_float */,
563 FALSE /* scan_hex */,
564 FALSE /* scan_hex_dollar */,
565 FALSE /* scan_string_sq */,
566 FALSE /* scan_string_dq */,
567 TRUE /* numbers_2_int */,
568 FALSE /* int_2_float */,
569 FALSE /* identifier_2_string */,
570 FALSE /* char_2_token */,
571 FALSE /* symbol_2_token */,
572 TRUE /* scope_0_fallback */,
577 uzbl.scan = g_scanner_new(&scan_config);
578 while(symp->symbol_name) {
579 g_scanner_scope_add_symbol(uzbl.scan, 0,
581 GINT_TO_POINTER(symp->symbol_token));
587 expand_template(const char *template) {
588 if(!template) return NULL;
590 GTokenType token = G_TOKEN_NONE;
591 GString *ret = g_string_new("");
595 g_scanner_input_text(uzbl.scan, template, strlen(template));
596 while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) {
597 token = g_scanner_get_next_token(uzbl.scan);
599 if(token == G_TOKEN_SYMBOL) {
600 sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
605 g_markup_printf_escaped("%s", uzbl.state.uri):"");
608 buf = itos(uzbl.gui.sbar.load_progress);
609 g_string_append(ret, buf);
612 case SYM_LOADPRGSBAR:
613 buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress);
614 g_string_append(ret, buf);
620 g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
623 buf = itos(uzbl.xwin);
625 uzbl.state.instance_name?uzbl.state.instance_name:buf);
630 uzbl.state.keycmd->str ?
631 g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
635 uzbl.behave.insert_mode?"[I]":"[C]");
639 uzbl.gui.sbar.msg?uzbl.gui.sbar.msg:"");
643 buf = itos(WEBKIT_MAJOR_VERSION);
644 g_string_append(ret, buf);
648 buf = itos(WEBKIT_MINOR_VERSION);
649 g_string_append(ret, buf);
653 buf = itos(WEBKIT_MICRO_VERSION);
654 g_string_append(ret, buf);
658 g_string_append(ret, uzbl.state.unameinfo.sysname);
661 g_string_append(ret, uzbl.state.unameinfo.nodename);
664 g_string_append(ret, uzbl.state.unameinfo.release);
667 g_string_append(ret, uzbl.state.unameinfo.version);
670 g_string_append(ret, uzbl.state.unameinfo.machine);
673 g_string_append(ret, ARCH);
677 g_string_append(ret, uzbl.state.unameinfo.domainname);
681 g_string_append(ret, COMMIT);
687 else if(token == G_TOKEN_INT) {
688 buf = itos(g_scanner_cur_value(uzbl.scan).v_int);
689 g_string_append(ret, buf);
692 else if(token == G_TOKEN_IDENTIFIER) {
693 g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier);
695 else if(token == G_TOKEN_CHAR) {
696 g_string_append_c(ret, (gchar)g_scanner_cur_value(uzbl.scan).v_char);
700 return g_string_free(ret, FALSE);
702 /* --End Statusbar functions-- */
705 // make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
707 run_command_async(const char *command, const char *args) {
708 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
709 GString* to_execute = g_string_new ("");
711 g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
712 command, uzbl.state.config_file, (int) getpid() ,
713 (int) uzbl.xwin, uzbl.comm.fifo_path, uzbl.comm.socket_path);
714 g_string_append_printf (to_execute, " '%s' '%s'",
715 uzbl.state.uri, "TODO title here");
717 g_string_append_printf (to_execute, " %s", args);
719 result = g_spawn_command_line_async (to_execute->str, NULL);
720 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
721 g_string_free (to_execute, TRUE);
726 run_command_sync(const char *command, const char *args, char **stdout) {
727 //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
728 GString* to_execute = g_string_new ("");
730 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);
731 g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here");
733 g_string_append_printf (to_execute, " %s", args);
735 result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, NULL);
736 printf("Called %s. Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
737 g_string_free (to_execute, TRUE);
742 spawn(WebKitWebView *web_view, const char *param) {
744 run_command_async(param, NULL);
748 parse_command(const char *cmd, const char *param) {
751 if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd)))
752 c(uzbl.gui.web_view, param);
754 fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd);
762 uzbl.comm.get_regex = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
763 G_REGEX_OPTIMIZE, 0, &err);
764 uzbl.comm.set_regex = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
765 G_REGEX_OPTIMIZE, 0, &err);
766 uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
767 G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err);
768 uzbl.comm.cmd_regex = g_regex_new("^[Cc][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
769 G_REGEX_OPTIMIZE, 0, &err);
773 get_var_value(gchar *name) {
776 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
777 if(var_is("status_format", name)
778 || var_is("useragent", name)) {
779 printf("VAR: %s VALUE: %s\n", name, (char *)*p);
780 } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
789 if(*uzbl.net.proxy_url == ' '
790 || uzbl.net.proxy_url == NULL) {
791 soup_session_remove_feature_by_type(uzbl.net.soup_session,
792 (GType) SOUP_SESSION_PROXY_URI);
795 suri = soup_uri_new(uzbl.net.proxy_url);
796 g_object_set(G_OBJECT(uzbl.net.soup_session),
797 SOUP_SESSION_PROXY_URI,
807 gtk_widget_ref(uzbl.gui.scrolled_win);
808 gtk_widget_ref(uzbl.gui.mainbar);
809 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.scrolled_win);
810 gtk_container_remove(GTK_CONTAINER(uzbl.gui.vbox), uzbl.gui.mainbar);
812 if(uzbl.behave.status_top) {
813 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
814 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
817 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
818 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
820 gtk_widget_unref(uzbl.gui.scrolled_win);
821 gtk_widget_unref(uzbl.gui.mainbar);
822 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
826 var_is(const char *x, const char *y) {
827 return (strcmp(x, y) == 0 ? TRUE : FALSE );
831 set_var_value(gchar *name, gchar *val) {
835 if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
836 if(var_is("status_message", name)
837 || var_is("status_background", name)
838 || var_is("status_format", name)
839 || var_is("load_finish_handler", name)
840 || var_is("history_handler", name)
841 || var_is("download_handler", name)
842 || var_is("cookie_handler", name)) {
848 else if(var_is("uri", name)) {
851 load_uri(uzbl.gui.web_view, (const gchar*)*p);
853 else if(var_is("proxy_url", name)) {
858 else if(var_is("fifo_dir", name)) {
860 *p = init_fifo(g_strdup(val));
862 else if(var_is("socket_dir", name)) {
864 *p = init_socket(g_strdup(val));
866 else if(var_is("modkey", name)) {
869 *p = g_utf8_strup(val, -1);
870 uzbl.behave.modmask = 0;
871 for (i = 0; modkeys[i].key != NULL; i++) {
872 if (g_strrstr(*p, modkeys[i].key))
873 uzbl.behave.modmask |= modkeys[i].mask;
876 else if(var_is("useragent", name)) {
878 *p = set_useragent(g_strdup(val));
880 /* variables that take int values */
883 *ip = (int)strtoul(val, &endp, 10);
885 if(var_is("show_status", name)) {
888 else if(var_is("always_insert_mode", name)) {
889 uzbl.behave.insert_mode =
890 uzbl.behave.always_insert_mode ? TRUE : FALSE;
893 else if (var_is("max_conns", name)) {
894 g_object_set(G_OBJECT(uzbl.net.soup_session),
895 SOUP_SESSION_MAX_CONNS, uzbl.net.max_conns, NULL);
897 else if (var_is("max_conns_host", name)) {
898 g_object_set(G_OBJECT(uzbl.net.soup_session),
899 SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
901 else if (var_is("http_debug", name)) {
902 //soup_session_remove_feature
903 // (uzbl.net.soup_session, uzbl.net.soup_logger);
904 soup_session_remove_feature
905 (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
906 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
907 /*g_free(uzbl.net.soup_logger);*/
909 uzbl.net.soup_logger = soup_logger_new(uzbl.behave.http_debug, -1);
910 soup_session_add_feature(uzbl.net.soup_session,
911 SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
913 else if (var_is("status_top", name)) {
922 runcmd(WebKitWebView* page, const char *param) {
924 parse_cmd_line(param);
928 parse_cmd_line(const char *ctl_line) {
932 if(ctl_line[0] == 's' || ctl_line[0] == 'S') {
933 tokens = g_regex_split(uzbl.comm.set_regex, ctl_line, 0);
934 if(tokens[0][0] == 0) {
935 set_var_value(tokens[1], tokens[2]);
939 printf("Error in command: %s\n", tokens[0]);
942 else if(ctl_line[0] == 'g' || ctl_line[0] == 'G') {
943 tokens = g_regex_split(uzbl.comm.get_regex, ctl_line, 0);
944 if(tokens[0][0] == 0) {
945 get_var_value(tokens[1]);
949 printf("Error in command: %s\n", tokens[0]);
952 else if(ctl_line[0] == 'b' || ctl_line[0] == 'B') {
953 tokens = g_regex_split(uzbl.comm.bind_regex, ctl_line, 0);
954 if(tokens[0][0] == 0) {
955 add_binding(tokens[1], tokens[2]);
959 printf("Error in command: %s\n", tokens[0]);
962 else if(ctl_line[0] == 'C' || ctl_line[0] == 'c') {
963 tokens = g_regex_split(uzbl.comm.cmd_regex, ctl_line, 0);
964 if(tokens[0][0] == 0) {
965 parse_command(tokens[1], tokens[2]);
969 printf("Error in command: %s\n", tokens[0]);
972 else if( (ctl_line[0] == '#')
973 || (ctl_line[0] == ' ')
974 || (ctl_line[0] == '\n'))
975 ; /* ignore these lines */
977 printf("Command not understood (%s)\n", ctl_line);
983 build_stream_name(int type, const gchar* dir) {
985 State *s = &uzbl.state;
988 xwin_str = itos((int)uzbl.xwin);
990 str = g_strdup_printf
991 ("%s/uzbl_fifo_%s", dir,
992 s->instance_name ? s->instance_name : xwin_str);
993 } else if (type == SOCKET) {
994 str = g_strdup_printf
995 ("%s/uzbl_socket_%s", dir,
996 s->instance_name ? s->instance_name : xwin_str );
1003 control_fifo(GIOChannel *gio, GIOCondition condition) {
1004 printf("triggered\n");
1009 if (condition & G_IO_HUP)
1010 g_error ("Fifo: Read end of pipe died!\n");
1013 g_error ("Fifo: GIOChannel broke\n");
1015 ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err);
1016 if (ret == G_IO_STATUS_ERROR)
1017 g_error ("Fifo: Error reading: %s\n", err->message);
1019 parse_cmd_line(ctl_line);
1026 init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1027 if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */
1028 if (unlink(uzbl.comm.fifo_path) == -1)
1029 g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path);
1030 g_free(uzbl.comm.fifo_path);
1031 uzbl.comm.fifo_path = NULL;
1034 if (*dir == ' ') { /* space unsets the variable */
1039 GIOChannel *chan = NULL;
1040 GError *error = NULL;
1041 gchar *path = build_stream_name(FIFO, dir);
1043 if (!file_exists(path)) {
1044 if (mkfifo (path, 0666) == 0) {
1045 // 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.
1046 chan = g_io_channel_new_file(path, "r+", &error);
1048 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
1049 printf ("init_fifo: created successfully as %s\n", path);
1050 uzbl.comm.fifo_path = path;
1052 } else g_warning ("init_fifo: could not add watch on %s\n", path);
1053 } else g_warning ("init_fifo: can't open: %s\n", error->message);
1054 } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno));
1055 } else g_warning ("init_fifo: can't create %s: file exists\n", path);
1057 /* if we got this far, there was an error; cleanup */
1064 control_stdin(GIOChannel *gio, GIOCondition condition) {
1065 gchar *ctl_line = NULL;
1066 gsize ctl_line_len = 0;
1070 if (condition & G_IO_HUP) {
1071 ret = g_io_channel_shutdown (gio, FALSE, &err);
1075 ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
1076 if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
1079 parse_cmd_line(ctl_line);
1087 GIOChannel *chan = NULL;
1088 GError *error = NULL;
1090 chan = g_io_channel_unix_new(fileno(stdin));
1092 if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
1093 g_error ("Stdin: could not add watch\n");
1095 printf ("Stdin: watch added successfully\n");
1098 g_error ("Stdin: Error while opening: %s\n", error->message);
1103 control_socket(GIOChannel *chan) {
1104 struct sockaddr_un remote;
1105 char buffer[512], *ctl_line;
1107 int sock, clientsock, n, done;
1110 sock = g_io_channel_unix_get_fd(chan);
1112 memset (buffer, 0, sizeof (buffer));
1114 t = sizeof (remote);
1115 clientsock = accept (sock, (struct sockaddr *) &remote, &t);
1119 memset (temp, 0, sizeof (temp));
1120 n = recv (clientsock, temp, 128, 0);
1122 buffer[strlen (buffer)] = '\0';
1126 strcat (buffer, temp);
1129 if (strcmp (buffer, "\n") < 0) {
1130 buffer[strlen (buffer) - 1] = '\0';
1132 buffer[strlen (buffer)] = '\0';
1135 ctl_line = g_strdup(buffer);
1136 parse_cmd_line (ctl_line);
1139 TODO: we should be able to do it with this. but glib errors out with "Invalid argument"
1140 GError *error = NULL;
1143 ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error);
1144 if (ret == G_IO_STATUS_ERROR)
1145 g_error ("Error reading: %s\n", error->message);
1147 printf("Got line %s (%u bytes) \n",ctl_line, len);
1149 parse_line(ctl_line);
1157 init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */
1158 if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */
1159 if (unlink(uzbl.comm.socket_path) == -1)
1160 g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path);
1161 g_free(uzbl.comm.socket_path);
1162 uzbl.comm.socket_path = NULL;
1170 GIOChannel *chan = NULL;
1172 struct sockaddr_un local;
1173 gchar *path = build_stream_name(SOCKET, dir);
1175 sock = socket (AF_UNIX, SOCK_STREAM, 0);
1177 local.sun_family = AF_UNIX;
1178 strcpy (local.sun_path, path);
1179 unlink (local.sun_path);
1181 len = strlen (local.sun_path) + sizeof (local.sun_family);
1182 if (bind (sock, (struct sockaddr *) &local, len) != -1) {
1183 printf ("init_socket: opened in %s\n", path);
1186 if( (chan = g_io_channel_unix_new(sock)) ) {
1187 g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan);
1188 uzbl.comm.socket_path = path;
1191 } else g_warning ("init_socket: could not open in %s: %s\n", path, strerror(errno));
1193 /* if we got this far, there was an error; cleanup */
1200 update_title (void) {
1201 GString* string_long = g_string_new ("");
1202 GString* string_short = g_string_new ("");
1206 State *s = &uzbl.state;
1207 Behaviour *b = &uzbl.behave;
1209 if(s->instance_name) {
1210 iname_len = strlen(s->instance_name)+4;
1211 iname = malloc(iname_len);
1212 snprintf(iname, iname_len, "<%s> ", s->instance_name);
1214 g_string_prepend(string_long, iname);
1215 g_string_prepend(string_short, iname);
1219 g_string_append_printf(string_long, "%s ", s->keycmd->str);
1220 if (!b->always_insert_mode)
1221 g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
1222 if (uzbl.gui.main_title) {
1223 g_string_append (string_long, uzbl.gui.main_title);
1224 g_string_append (string_short, uzbl.gui.main_title);
1226 g_string_append (string_long, " - Uzbl browser");
1227 g_string_append (string_short, " - Uzbl browser");
1228 if (s->selected_url[0]!=0) {
1229 g_string_append_printf (string_long, " -> (%s)", s->selected_url);
1232 gchar* title_long = g_string_free (string_long, FALSE);
1233 gchar* title_short = g_string_free (string_short, FALSE);
1235 if (b->show_status) {
1236 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
1237 // TODO: we should probably not do this every time we want to update the title..?
1238 statln = expand_template(uzbl.behave.status_format);
1239 gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
1240 if (b->status_background) {
1242 gdk_color_parse (b->status_background, &color);
1243 //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)
1244 gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
1248 gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
1251 g_free (title_long);
1252 g_free (title_short);
1256 key_press_cb (WebKitWebView* page, GdkEventKey* event)
1258 //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1263 if (event->type != GDK_KEY_PRESS || event->keyval == GDK_Page_Up || event->keyval == GDK_Page_Down
1264 || 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)
1267 /* turn off insert mode (if always_insert_mode is not used) */
1268 if (uzbl.behave.insert_mode && (event->keyval == GDK_Escape)) {
1269 uzbl.behave.insert_mode = uzbl.behave.always_insert_mode;
1274 if (uzbl.behave.insert_mode && (((event->state & uzbl.behave.modmask) != uzbl.behave.modmask) || (!uzbl.behave.modmask)))
1277 if (event->keyval == GDK_Escape) {
1278 g_string_truncate(uzbl.state.keycmd, 0);
1283 //Insert without shift - insert from clipboard; Insert with shift - insert from primary
1284 if (event->keyval == GDK_Insert) {
1286 if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) {
1287 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
1289 str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
1292 g_string_append_printf (uzbl.state.keycmd, "%s", str);
1299 if ((event->keyval == GDK_BackSpace) && (uzbl.state.keycmd->len > 0)) {
1300 g_string_truncate(uzbl.state.keycmd, uzbl.state.keycmd->len - 1);
1304 gboolean key_ret = FALSE;
1305 if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter))
1308 if (!key_ret) g_string_append(uzbl.state.keycmd, event->string);
1309 if ((action = g_hash_table_lookup(uzbl.bindings, uzbl.state.keycmd->str))) {
1310 g_string_truncate(uzbl.state.keycmd, 0);
1311 parse_command(action->name, action->param);
1314 GString* short_keys = g_string_new ("");
1315 GString* short_keys_inc = g_string_new ("");
1317 for (i=0; i<(uzbl.state.keycmd->len); i++) {
1318 g_string_append_c(short_keys, uzbl.state.keycmd->str[i]);
1319 g_string_assign(short_keys_inc, short_keys->str);
1320 g_string_append_c(short_keys, '_');
1321 g_string_append_c(short_keys_inc, '*');
1323 gboolean exec_now = FALSE;
1324 if ((action = g_hash_table_lookup(uzbl.bindings, short_keys->str))) {
1325 if (key_ret) exec_now = TRUE; // run normal cmds only if return was pressed
1326 } else if ((action = g_hash_table_lookup(uzbl.bindings, short_keys_inc->str))) {
1327 if (key_ret) { // just quit the incremental command on return
1328 g_string_truncate(uzbl.state.keycmd, 0);
1330 } else exec_now = TRUE; // always exec inc. commands on keys other than return
1334 GString* parampart = g_string_new (uzbl.state.keycmd->str);
1335 GString* actionname = g_string_new ("");
1336 GString* actionparam = g_string_new ("");
1337 g_string_erase (parampart, 0, i+1);
1339 g_string_printf (actionname, action->name, parampart->str);
1341 g_string_printf (actionparam, action->param, parampart->str);
1342 parse_command(actionname->str, actionparam->str);
1343 g_string_free (actionname, TRUE);
1344 g_string_free (actionparam, TRUE);
1345 g_string_free (parampart, TRUE);
1347 g_string_truncate(uzbl.state.keycmd, 0);
1351 g_string_truncate(short_keys, short_keys->len - 1);
1353 g_string_free (short_keys, TRUE);
1354 g_string_free (short_keys_inc, TRUE);
1356 if (key_ret) return (!uzbl.behave.insert_mode);
1364 GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1365 //main_window_ref = g_object_ref(scrolled_window);
1366 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
1368 g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
1369 gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view));
1371 g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view);
1372 g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view);
1373 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view);
1374 g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view);
1375 g_signal_connect (G_OBJECT (g->web_view), "load-finished", G_CALLBACK (load_finish_cb), g->web_view);
1376 g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view);
1377 g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view);
1378 g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view);
1379 g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view);
1380 g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view);
1382 return scrolled_window;
1389 g->mainbar = gtk_hbox_new (FALSE, 0);
1391 /* keep a reference to the bar so we can re-pack it at runtime*/
1392 //sbar_ref = g_object_ref(g->mainbar);
1394 g->mainbar_label = gtk_label_new ("");
1395 gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
1396 gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
1397 gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0);
1398 gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2);
1399 gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0);
1404 GtkWidget* create_window () {
1405 GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1406 gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
1407 gtk_widget_set_name (window, "Uzbl browser");
1408 g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
1414 add_binding (const gchar *key, const gchar *act) {
1415 char **parts = g_strsplit(act, " ", 2);
1422 printf ("Binding %-10s : %s\n", key, act);
1423 action = new_action(parts[0], parts[1]);
1425 if(g_hash_table_lookup(uzbl.bindings, key))
1426 g_hash_table_remove(uzbl.bindings, key);
1427 g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
1435 State *s = &uzbl.state;
1436 Network *n = &uzbl.net;
1438 uzbl.behave.reset_command_mode = 1;
1440 if (!s->config_file) {
1441 const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
1442 if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
1443 XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
1445 printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
1447 strcpy (s->config_file_path, XDG_CONFIG_HOME);
1448 strcat (s->config_file_path, "/uzbl/config");
1449 if (file_exists (s->config_file_path)) {
1450 printf ("Config file %s found.\n", s->config_file_path);
1451 s->config_file = &s->config_file_path[0];
1453 // Now we check $XDG_CONFIG_DIRS
1454 char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
1455 if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
1456 XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
1458 printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
1461 strcpy (buffer, XDG_CONFIG_DIRS);
1462 const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
1463 while (dir && ! file_exists (s->config_file_path)) {
1464 strcpy (s->config_file_path, dir);
1465 strcat (s->config_file_path, "/uzbl/config_file_pathig");
1466 if (file_exists (s->config_file_path)) {
1467 printf ("Config file %s found.\n", s->config_file_path);
1468 s->config_file = &s->config_file_path[0];
1470 dir = (char * ) strtok_r (NULL, ":", &saveptr);
1475 if (s->config_file) {
1476 GIOChannel *chan = NULL;
1477 GError *error = NULL;
1478 gchar *readbuf = NULL;
1481 chan = g_io_channel_new_file(s->config_file, "r", &error);
1484 while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
1485 == G_IO_STATUS_NORMAL) {
1486 parse_cmd_line(readbuf);
1490 g_io_channel_unref (chan);
1491 printf ("Config %s loaded\n", s->config_file);
1493 fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
1496 printf ("No configuration file loaded.\n");
1498 if (!uzbl.behave.status_format)
1499 uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
1501 g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
1505 set_useragent(gchar *val) {
1510 gchar *ua = expand_template(val);
1512 g_object_set(G_OBJECT(uzbl.net.soup_session), SOUP_SESSION_USER_AGENT, ua, NULL);
1516 static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){
1519 if (!uzbl.behave.cookie_handler) return;
1521 gchar * stdout = NULL;
1522 soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL);
1523 GString* args = g_string_new ("");
1524 SoupURI * soup_uri = soup_message_get_uri(msg);
1525 g_string_printf (args, "GET %s %s", soup_uri->host, soup_uri->path);
1526 run_command_sync(uzbl.behave.cookie_handler, args->str, &stdout);
1528 soup_message_headers_replace (msg->request_headers, "Cookie", stdout);
1530 g_string_free(args, TRUE);
1534 save_cookies (SoupMessage *msg, gpointer user_data){
1538 for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){
1539 cookie = soup_cookie_to_set_cookie_header(ck->data);
1540 GString* args = g_string_new ("");
1541 SoupURI * soup_uri = soup_message_get_uri(msg);
1542 g_string_printf (args, "PUT %s %s \"%s\"", soup_uri->host, soup_uri->path, cookie);
1543 run_command_async(uzbl.behave.cookie_handler, args->str);
1544 g_string_free(args, TRUE);
1552 main (int argc, char* argv[]) {
1553 gtk_init (&argc, &argv);
1554 if (!g_thread_supported ())
1555 g_thread_init (NULL);
1557 printf("Uzbl start location: %s\n", argv[0]);
1558 strcpy(uzbl.state.executable_path,argv[0]);
1560 strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
1561 strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
1563 GError *error = NULL;
1564 GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
1565 g_option_context_add_main_entries (context, entries, NULL);
1566 g_option_context_add_group (context, gtk_get_option_group (TRUE));
1567 g_option_context_parse (context, &argc, &argv, &error);
1568 /* initialize hash table */
1569 uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
1571 uzbl.net.soup_session = webkit_get_default_session();
1572 uzbl.state.keycmd = g_string_new("");
1574 if(setup_signal(SIGTERM, catch_sigterm) == SIG_ERR)
1575 fprintf(stderr, "uzbl: error hooking SIGTERM\n");
1577 if(uname(&uzbl.state.unameinfo) == -1)
1578 g_printerr("Can't retrieve unameinfo. Your useragent might appear wrong.\n");
1583 make_var_to_name_hash();
1586 uzbl.gui.vbox = gtk_vbox_new (FALSE, 0);
1588 uzbl.gui.scrolled_win = create_browser();
1591 /* initial packing */
1592 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0);
1593 gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0);
1595 uzbl.gui.main_window = create_window ();
1596 gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
1598 load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
1600 gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
1601 gtk_widget_show_all (uzbl.gui.main_window);
1602 uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
1603 printf("window_id %i\n",(int) uzbl.xwin);
1604 printf("pid %i\n", getpid ());
1605 printf("name: %s\n", uzbl.state.instance_name);
1607 uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
1608 uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
1609 uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL);
1610 uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h);
1611 gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v);
1615 if (!uzbl.behave.show_status)
1616 gtk_widget_hide(uzbl.gui.mainbar);
1625 return EXIT_SUCCESS;
1628 /* vi: set et ts=4: */