diff options
Diffstat (limited to 'uzbl.c')
-rw-r--r-- | uzbl.c | 816 |
1 files changed, 572 insertions, 244 deletions
@@ -40,8 +40,8 @@ #include <sys/stat.h> #include <sys/types.h> #include <sys/un.h> +#include <sys/utsname.h> #include <webkit/webkit.h> -#include <pthread.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -54,35 +54,26 @@ #include <libsoup/soup.h> #include "uzbl.h" + +/* status bar format + TODO: integrate with the config file +*/ +char *status_format = "<span background=\"darkgreen\" foreground=\"khaki\"> MODE </span> | Cmd: <span background=\"red\" foreground=\"white\">KEYCMD</span> | <span background=\"darkblue\" foreground=\"white\"> <b>TITLE</b> </span> | LOAD_PROGRESS% <span font_family=\"monospace\">LOAD_PROGRESSBAR</span> | <span foreground=\"darkgreen\">URI</span> | NAME | <span foreground=\"black\" background=\"khaki\"> Uzbl browser </span>"; + /* housekeeping / internal variables */ -static GtkWidget* main_window; -static GtkWidget* mainbar; -static GtkWidget* mainbar_label; -static GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar -static GtkScrollbar* scbar_h; // (These are still hidden) -static GtkAdjustment* bar_v; // Information about document length -static GtkAdjustment* bar_h; // and scrolling position -static WebKitWebView* web_view; -static gchar* main_title; static gchar selected_url[500] = "\0"; -static gint load_progress; -static Window xwin = 0; -static char fifo_path[64]; -static char socket_path[108]; static char executable_path[500]; static GString* keycmd; +static gchar searchtx[500] = "\0"; -/* state variables (initial values coming from command line arguments but may be changed later) */ -static gchar* uri = NULL; -static gchar* config_file = NULL; -static gchar config_file_path[500]; -static gboolean verbose = FALSE; +static Uzbl uzbl; /* settings from config: group behaviour */ static gchar* history_handler = NULL; static gchar* fifo_dir = NULL; static gchar* socket_dir = NULL; static gchar* download_handler = NULL; +static gchar* cookie_handler = NULL; static gboolean always_insert_mode = FALSE; static gboolean show_status = FALSE; static gboolean insert_mode = FALSE; @@ -90,7 +81,10 @@ static gboolean status_top = FALSE; static gchar* modkey = NULL; static guint modmask = 0; static guint http_debug = 0; -static gchar* cookie_handler = NULL; + +/* System info */ +static struct utsname unameinfo; + /* settings from config: group bindings, key -> action */ static GHashTable* bindings; @@ -100,9 +94,9 @@ static GHashTable* commands; /* commandline arguments (set initial values for the state variables) */ static GOptionEntry entries[] = { - { "uri", 'u', 0, G_OPTION_ARG_STRING, &uri, "Uri to load", NULL }, - { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, - { "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Config file", NULL }, + { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load", "URI" }, + { "name", 'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance", "NAME" }, + { "config", 'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file, "Config file", "FILE" }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; @@ -112,15 +106,21 @@ typedef void (*Command)(WebKitWebView*, const char *); static char *XDG_CONFIG_HOME_default[256]; static char *XDG_CONFIG_DIRS_default = "/etc/xdg"; -/* libsoup stuff - proxy and friends; networking aptions actually */ -static SoupSession *soup_session; -static SoupLogger *soup_logger; -static char *proxy_url = NULL; -static char *useragent = NULL; -static gint max_conns; -static gint max_conns_host; -static SoupCookieJar *ck; -static char* current_req = NULL; + +/* --- UTILITY FUNCTIONS --- */ + +char * +itos(int val) { + char tmp[20]; + + snprintf(tmp, sizeof(tmp), "%i", val); + return g_strdup(tmp); +} + +static char * +str_replace (const char* search, const char* replace, const char* string) { + return g_strjoinv (replace, g_strsplit(string, search, -1)); +} /* --- CALLBACKS --- */ @@ -180,13 +180,13 @@ scroll (GtkAdjustment* bar, const char *param) { static void scroll_vert(WebKitWebView* page, const char *param) { (void) page; - scroll(bar_v, param); + scroll(uzbl.gui.bar_v, param); } static void scroll_horz(WebKitWebView* page, const char *param) { (void) page; - scroll(bar_h, param); + scroll(uzbl.gui.bar_h, param); } static void @@ -195,9 +195,9 @@ toggle_status_cb (WebKitWebView* page, const char *param) { (void)param; if (show_status) { - gtk_widget_hide(mainbar); + gtk_widget_hide(uzbl.gui.mainbar); } else { - gtk_widget_show(mainbar); + gtk_widget_show(uzbl.gui.mainbar); } show_status = !show_status; update_title(); @@ -221,9 +221,9 @@ title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar (void) web_view; (void) web_frame; (void) data; - if (main_title) - g_free (main_title); - main_title = g_strdup (title); + if (uzbl.gui.main_title) + g_free (uzbl.gui.main_title); + uzbl.gui.main_title = g_strdup (title); update_title(); } @@ -231,7 +231,7 @@ static void progress_change_cb (WebKitWebView* page, gint progress, gpointer data) { (void) page; (void) data; - load_progress = progress; + uzbl.gui.sbar.load_progress = progress; update_title(); } @@ -239,9 +239,9 @@ static void load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data) { (void) page; (void) data; - free (uri); + free (uzbl.state.uri); GString* newuri = g_string_new (webkit_web_frame_get_uri (frame)); - uri = g_string_free (newuri, FALSE); + uzbl.state.uri = g_string_free (newuri, FALSE); } static void @@ -267,10 +267,11 @@ log_history_cb () { } } -/* VIEW funcs (little webkit wrappers) */ +/* VIEW funcs (little webkit wrappers) */ #define VIEWFUNC(name) static void view_##name(WebKitWebView *page, const char *param){(void)param; webkit_web_view_##name(page);} VIEWFUNC(reload) +VIEWFUNC(reload_bypass_cache) VIEWFUNC(stop_loading) VIEWFUNC(zoom_in) VIEWFUNC(zoom_out) @@ -283,20 +284,22 @@ VIEWFUNC(go_forward) static struct {char *name; Command command;} cmdlist[] = { - { "back", view_go_back }, - { "forward", view_go_forward }, - { "scroll_vert", scroll_vert }, - { "scroll_horz", scroll_horz }, - { "reload", view_reload, }, //Buggy - { "refresh", view_reload, }, /* for convenience, will change */ - { "stop", view_stop_loading, }, - { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). - { "zoom_out", view_zoom_out, }, - { "uri", load_uri }, - { "toggle_status", toggle_status_cb }, - { "spawn", spawn }, - { "exit", close_uzbl }, - { "insert_mode", set_insert_mode } + { "back", view_go_back }, + { "forward", view_go_forward }, + { "scroll_vert", scroll_vert }, + { "scroll_horz", scroll_horz }, + { "reload", view_reload, }, + { "reload_ign_cache", view_reload_bypass_cache}, + { "stop", view_stop_loading, }, + { "zoom_in", view_zoom_in, }, //Can crash (when max zoom reached?). + { "zoom_out", view_zoom_out, }, + { "uri", load_uri }, + { "script", run_js }, + { "toggle_status", toggle_status_cb }, + { "spawn", spawn }, + { "exit", close_uzbl }, + { "search", search_text }, + { "insert_mode", set_insert_mode } }; static void @@ -365,6 +368,26 @@ load_uri (WebKitWebView * web_view, const gchar *param) { } static void +run_js (WebKitWebView * web_view, const gchar *param) { + if (param) + webkit_web_view_execute_script (web_view, param); +} + +static void +search_text (WebKitWebView *page, const char *param) { + if ((param) && (param[0] != '\0')) { + strcpy(searchtx, param); + } + if (searchtx[0] != '\0') { + printf ("Searching: %s\n", searchtx); + webkit_web_view_unmark_text_matches (page); + webkit_web_view_mark_text_matches (page, searchtx, FALSE, 0); + webkit_web_view_set_highlight_text_matches (page, TRUE); + webkit_web_view_search_text (page, searchtx, FALSE, TRUE, TRUE); + } +} + +static void new_window_load_uri (const gchar * uri) { GString* to_execute = g_string_new (""); g_string_append_printf (to_execute, "%s --uri '%s'", executable_path, uri); @@ -389,14 +412,158 @@ close_uzbl (WebKitWebView *page, const char *param) { gtk_main_quit (); } +/* --Statusbar functions-- */ +static char* +build_progressbar_ascii(int percent) { + int width=10; + int i; + double l; + GString *bar = g_string_new(""); + + l = (double)percent*((double)width/100.); + l = (int)(l+.5)>=(int)l ? l+.5 : l; + + g_string_append(bar, "["); + for(i=0; i<(int)l; i++) + g_string_append(bar, "="); + + for(; i<width; i++) + g_string_append(bar, "ยท"); + g_string_append(bar, "]"); + + return g_string_free(bar, FALSE); +} + +static void +setup_scanner() { + const GScannerConfig scan_config = { + ( + "\t\r\n" + ) /* cset_skip_characters */, + ( + G_CSET_a_2_z + "_" + G_CSET_A_2_Z + ) /* cset_identifier_first */, + ( + G_CSET_a_2_z + "_0123456789" + G_CSET_A_2_Z + G_CSET_LATINS + G_CSET_LATINC + ) /* cset_identifier_nth */, + ( "#\n" ) /* cpair_comment_single */, + + TRUE /* case_sensitive */, + + FALSE /* skip_comment_multi */, + FALSE /* skip_comment_single */, + FALSE /* scan_comment_multi */, + TRUE /* scan_identifier */, + TRUE /* scan_identifier_1char */, + FALSE /* scan_identifier_NULL */, + TRUE /* scan_symbols */, + FALSE /* scan_binary */, + FALSE /* scan_octal */, + FALSE /* scan_float */, + FALSE /* scan_hex */, + FALSE /* scan_hex_dollar */, + FALSE /* scan_string_sq */, + FALSE /* scan_string_dq */, + TRUE /* numbers_2_int */, + FALSE /* int_2_float */, + FALSE /* identifier_2_string */, + FALSE /* char_2_token */, + FALSE /* symbol_2_token */, + TRUE /* scope_0_fallback */, + FALSE, + TRUE + }; + + uzbl.scan = g_scanner_new(&scan_config); + while(symp->symbol_name) { + g_scanner_scope_add_symbol(uzbl.scan, 0, + symp->symbol_name, + GINT_TO_POINTER(symp->symbol_token)); + symp++; + } +} + +static gchar * +parse_status_template(const char *template) { + GTokenType token = G_TOKEN_NONE; + GString *ret = g_string_new(""); + gchar *buf=NULL; + int sym; + + if(!template) + return NULL; + + g_scanner_input_text(uzbl.scan, template, strlen(template)); + while(!g_scanner_eof(uzbl.scan) && token != G_TOKEN_LAST) { + token = g_scanner_get_next_token(uzbl.scan); + + if(token == G_TOKEN_SYMBOL) { + sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol; + switch(sym) { + case SYM_URI: + g_string_append(ret, uzbl.state.uri); + break; + case SYM_LOADPRGS: + g_string_append(ret, itos(uzbl.gui.sbar.load_progress)); + break; + case SYM_LOADPRGSBAR: + buf = build_progressbar_ascii(uzbl.gui.sbar.load_progress); + g_string_append(ret, buf); + g_free(buf); + break; + case SYM_TITLE: + g_string_append(ret, + uzbl.gui.main_title?uzbl.gui.main_title:""); + break; + case SYM_NAME: + g_string_append(ret, + uzbl.state.instance_name?uzbl.state.instance_name:"" ); + break; + case SYM_KEYCMD: + g_string_append(ret, + keycmd->str?keycmd->str:"" ); + break; + case SYM_MODE: + g_string_append(ret, + insert_mode?"[I]":"[C]" ); + break; + default: + break; + } + } + else if(token == G_TOKEN_INT) { + g_string_append(ret, itos(g_scanner_cur_value(uzbl.scan).v_int)); + } + else if(token == G_TOKEN_IDENTIFIER) { + g_string_append(ret, (gchar *)g_scanner_cur_value(uzbl.scan).v_identifier); + } + else if(token == G_TOKEN_CHAR) { + g_string_append_printf(ret, "%c", g_scanner_cur_value(uzbl.scan).v_char); + } + } + + return g_string_free(ret, FALSE); +} +/* --End Statusbar functions-- */ + + // make sure to put '' around args, so that if there is whitespace we can still keep arguments together. static gboolean run_command_async(const char *command, const char *args) { //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args] GString* to_execute = g_string_new (""); gboolean result; - g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path); - g_string_append_printf (to_execute, " '%s' '%s'", uri, "TODO title here"); + 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); + g_string_append_printf (to_execute, " '%s' '%s'", + uzbl.state.uri, "TODO title here"); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -411,8 +578,8 @@ run_command_sync(const char *command, const char *args, char **stdout) { //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args] GString* to_execute = g_string_new (""); gboolean result; - g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'", command, config_file, (int) getpid() , (int) xwin, fifo_path, socket_path); - g_string_append_printf (to_execute, " '%s' '%s'", uri, "TODO title here"); + 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); + g_string_append_printf (to_execute, " '%s' '%s'", uzbl.state.uri, "TODO title here"); if(args) { g_string_append_printf (to_execute, " %s", args); } @@ -433,7 +600,7 @@ parse_command(const char *cmd, const char *param) { Command c; if ((c = g_hash_table_lookup(commands, cmd))) - c(web_view, param); + c(uzbl.gui.web_view, param); else fprintf (stderr, "command \"%s\" not understood. ignoring.\n", cmd); } @@ -454,132 +621,199 @@ parse_line(char *line) { g_strfreev(parts); } +enum { FIFO, SOCKET}; +void +build_stream_name(int type) { + char *xwin_str; + State *s = &uzbl.state; + + xwin_str = itos((int)uzbl.xwin); + switch(type) { + case FIFO: + if (fifo_dir) { + sprintf (uzbl.comm.fifo_path, "%s/uzbl_fifo_%s", + fifo_dir, s->instance_name ? s->instance_name : xwin_str); + } else { + sprintf (uzbl.comm.fifo_path, "/tmp/uzbl_fifo_%s", + s->instance_name ? s->instance_name : xwin_str); + } + break; + + case SOCKET: + if (socket_dir) { + sprintf (uzbl.comm.socket_path, "%s/uzbl_socket_%s", + socket_dir, s->instance_name ? s->instance_name : xwin_str); + } else { + sprintf (uzbl.comm.socket_path, "/tmp/uzbl_socket_%s", + s->instance_name ? s->instance_name : xwin_str); + } + break; + default: + break; + } + g_free(xwin_str); +} + static void -control_fifo(GIOChannel *fd) { +control_fifo(GIOChannel *gio, GIOCondition condition) { + printf("triggered\n"); gchar *ctl_line; - gsize term_pos; + GIOStatus ret; + GError *err = NULL; - if(!fd) - return; + if (condition & G_IO_HUP) + g_error ("Fifo: Read end of pipe died!\n"); - g_io_channel_read_line(fd, &ctl_line, NULL, &term_pos, NULL); - ctl_line[term_pos] ='\0'; + if(!gio) + g_error ("Fifo: GIOChannel broke\n"); - parse_line(ctl_line); + ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, &err); + if (ret == G_IO_STATUS_ERROR) + g_error ("Fifo: Error reading: %s\n", err->message); + parse_line(ctl_line); g_free(ctl_line); - + printf("...done\n"); return; } static void create_fifo() { GIOChannel *chan = NULL; + GError *error = NULL; - if (fifo_dir) { - sprintf (fifo_path, "%s/uzbl_fifo_%d", fifo_dir, (int) xwin); - } else { - sprintf (fifo_path, "/tmp/uzbl_fifo_%d", (int) xwin); + build_stream_name(FIFO); + if (file_exists(uzbl.comm.fifo_path)) { + g_error ("Fifo: Error when creating %s: File exists\n", uzbl.comm.fifo_path); + return; } - printf ("Control fifo opened in %s\n", fifo_path); - if (mkfifo (fifo_path, 0666) == -1) { - printf ("Possible error creating fifo\n"); + if (mkfifo (uzbl.comm.fifo_path, 0666) == -1) { + g_error ("Fifo: Error when creating %s: %s\n", uzbl.comm.fifo_path, strerror(errno)); + } else { + // 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. + chan = g_io_channel_new_file((gchar *) uzbl.comm.fifo_path, "r+", &error); + if (chan) { + if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { + g_error ("Fifo: could not add watch on %s\n", uzbl.comm.fifo_path); + } else { + printf ("Fifo: created successfully as %s\n", uzbl.comm.fifo_path); + } + } else { + g_error ("Fifo: Error while opening: %s\n", error->message); + } } - - if( (chan = g_io_channel_new_file((gchar *) fifo_path, "r+", NULL)) ) - g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, chan); return; } static void -*control_socket() { - if (socket_dir) { - sprintf (socket_path, "%s/uzbl_socket_%d", socket_dir, (int) xwin); +control_socket(GIOChannel *chan) { + struct sockaddr_un remote; + char buffer[512], *ctl_line; + char temp[128]; + int sock, clientsock, n, done; + unsigned int t; + + sock = g_io_channel_unix_get_fd(chan); + + memset (buffer, 0, sizeof (buffer)); + + t = sizeof (remote); + clientsock = accept (sock, (struct sockaddr *) &remote, &t); + + done = 0; + do { + memset (temp, 0, sizeof (temp)); + n = recv (clientsock, temp, 128, 0); + if (n == 0) { + buffer[strlen (buffer)] = '\0'; + done = 1; + } + if (!done) + strcat (buffer, temp); + } while (!done); + + if (strcmp (buffer, "\n") < 0) { + buffer[strlen (buffer) - 1] = '\0'; } else { - sprintf (socket_path, "/tmp/uzbl_socket_%d", (int) xwin); + buffer[strlen (buffer)] = '\0'; } - - int sock, clientsock, len; - unsigned int t; - struct sockaddr_un local, remote; + close (clientsock); + ctl_line = g_strdup(buffer); + parse_line (ctl_line); + +/* + TODO: we should be able to do it with this. but glib errors out with "Invalid argument" + GError *error = NULL; + gsize len; + GIOStatus ret; + ret = g_io_channel_read_line(chan, &ctl_line, &len, NULL, &error); + if (ret == G_IO_STATUS_ERROR) + g_error ("Error reading: %s\n", error->message); + + printf("Got line %s (%u bytes) \n",ctl_line, len); + if(ctl_line) { + parse_line(ctl_line); +*/ + + g_free(ctl_line); + return; +} +static void +create_socket() { + GIOChannel *chan = NULL; + int sock, len; + struct sockaddr_un local; + + build_stream_name(SOCKET); sock = socket (AF_UNIX, SOCK_STREAM, 0); local.sun_family = AF_UNIX; - strcpy (local.sun_path, socket_path); + strcpy (local.sun_path, uzbl.comm.socket_path); unlink (local.sun_path); len = strlen (local.sun_path) + sizeof (local.sun_family); bind (sock, (struct sockaddr *) &local, len); if (errno == -1) { - printf ("A problem occurred when opening a socket in %s\n", socket_path); + printf ("Socket: Could not open in %s: %s\n", uzbl.comm.socket_path, strerror(errno)); } else { - printf ("Control socket opened in %s\n", socket_path); - } - - listen (sock, 5); - - char buffer[512]; - char temp[128]; - int done, n; - for(;;) { - memset (buffer, 0, sizeof (buffer)); - - t = sizeof (remote); - clientsock = accept (sock, (struct sockaddr *) &remote, &t); - printf ("Connected to client\n"); - - done = 0; - do { - memset (temp, 0, sizeof (temp)); - n = recv (clientsock, temp, 128, 0); - if (n == 0) { - buffer[strlen (buffer)] = '\0'; - done = 1; - } - - if (!done) - strcat (buffer, temp); - } while (!done); + printf ("Socket: Opened in %s\n", uzbl.comm.socket_path); + listen (sock, 5); - if (strcmp (buffer, "\n") < 0) { - buffer[strlen (buffer) - 1] = '\0'; - } else { - buffer[strlen (buffer)] = '\0'; - } - - parse_line (buffer); - close (clientsock); + if( (chan = g_io_channel_unix_new(sock)) ) + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); } - - return NULL; -} - -static void -setup_threading () { - pthread_t control_thread; - pthread_create(&control_thread, NULL, control_socket, NULL); - pthread_detach(control_thread); } static void update_title (void) { GString* string_long = g_string_new (""); GString* string_short = g_string_new (""); + char* iname = NULL; + gchar *statln; + int iname_len; + State *s = &uzbl.state; + + if(s->instance_name) { + iname_len = strlen(s->instance_name)+4; + iname = malloc(iname_len); + snprintf(iname, iname_len, "<%s> ", s->instance_name); + + g_string_prepend(string_long, iname); + g_string_prepend(string_short, iname); + free(iname); + } g_string_append_printf(string_long, "%s ", keycmd->str); if (!always_insert_mode) g_string_append (string_long, (insert_mode ? "[I] " : "[C] ")); - if (main_title) { - g_string_append (string_long, main_title); - g_string_append (string_short, main_title); + if (uzbl.gui.main_title) { + g_string_append (string_long, uzbl.gui.main_title); + g_string_append (string_short, uzbl.gui.main_title); } g_string_append (string_long, " - Uzbl browser"); g_string_append (string_short, " - Uzbl browser"); - if (load_progress < 100) - g_string_append_printf (string_long, " (%d%%)", load_progress); - if (selected_url[0]!=0) { g_string_append_printf (string_long, " -> (%s)", selected_url); } @@ -588,16 +822,18 @@ update_title (void) { gchar* title_short = g_string_free (string_short, FALSE); if (show_status) { - gtk_window_set_title (GTK_WINDOW(main_window), title_short); - gtk_label_set_text(GTK_LABEL(mainbar_label), title_long); + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short); + statln = parse_status_template(status_format); + gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln); + g_free(statln); } else { - gtk_window_set_title (GTK_WINDOW(main_window), title_long); + gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long); } g_free (title_long); g_free (title_short); } - + static gboolean key_press_cb (WebKitWebView* page, GdkEventKey* event) { @@ -617,23 +853,72 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) return TRUE; } - if (insert_mode && event->state != modmask) + if (insert_mode && ((event->state & modmask) != modmask)) return FALSE; - if (event->keyval == GDK_Escape) { g_string_truncate(keycmd, 0); - update_title(); + return TRUE; + } + //Insert without shift - insert from clipboard; Insert with shift - insert from primary + if (event->keyval == GDK_Insert) { + gchar * str; + if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK) { + str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY)); + } else { + str = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); + } + if (str) { + g_string_append_printf (keycmd, "%s", str); + update_title (); + free (str); + } return TRUE; } - g_string_append(keycmd, event->string); + if ((event->keyval == GDK_BackSpace) && (keycmd->len > 0)) { + g_string_truncate(keycmd, keycmd->len - 1); + update_title(); + return TRUE; + } + if ((event->keyval == GDK_Return) || (event->keyval == GDK_KP_Enter)) { + GString* short_keys = g_string_new (""); + unsigned int i; + for (i=0; i<(keycmd->len); i++) { + g_string_append_c(short_keys, keycmd->str[i]); + g_string_append_c(short_keys, '_'); + + //printf("\nTesting string: @%s@\n", short_keys->str); + if ((action = g_hash_table_lookup(bindings, short_keys->str))) { + GString* parampart = g_string_new (keycmd->str); + g_string_erase (parampart, 0, i+1); + //printf("\nParameter: @%s@\n", parampart->str); + GString* actionname = g_string_new (""); + if (action->name) + g_string_printf (actionname, action->name, parampart->str); + GString* actionparam = g_string_new (""); + if (action->param) + g_string_printf (actionparam, action->param, parampart->str); + parse_command(actionname->str, actionparam->str); + g_string_free (actionname, TRUE); + g_string_free (actionparam, TRUE); + g_string_free (parampart, TRUE); + g_string_truncate(keycmd, 0); + update_title(); + } + + g_string_truncate(short_keys, short_keys->len - 1); + } + g_string_free (short_keys, TRUE); + return (!insert_mode); + } + + g_string_append(keycmd, event->string); if ((action = g_hash_table_lookup(bindings, keycmd->str))) { g_string_truncate(keycmd, 0); - parse_command(action->name, action->param); } @@ -644,33 +929,38 @@ key_press_cb (WebKitWebView* page, GdkEventKey* event) static GtkWidget* create_browser () { + GUI *g = &uzbl.gui; + GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL); 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 - web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); - gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view)); + g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); + gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (g->web_view)); - g_signal_connect (G_OBJECT (web_view), "title-changed", G_CALLBACK (title_change_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (load_commit_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "key-press-event", G_CALLBACK (key_press_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "download-requested", G_CALLBACK (download_cb), web_view); - g_signal_connect (G_OBJECT (web_view), "create-web-view", G_CALLBACK (create_web_view_cb), web_view); + g_signal_connect (G_OBJECT (g->web_view), "title-changed", G_CALLBACK (title_change_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (load_commit_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "load-committed", G_CALLBACK (log_history_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "key-press-event", G_CALLBACK (key_press_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "new-window-policy-decision-requested", G_CALLBACK (new_window_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "download-requested", G_CALLBACK (download_cb), g->web_view); + g_signal_connect (G_OBJECT (g->web_view), "create-web-view", G_CALLBACK (create_web_view_cb), g->web_view); return scrolled_window; } static GtkWidget* create_mainbar () { - mainbar = gtk_hbox_new (FALSE, 0); - mainbar_label = gtk_label_new (""); - gtk_misc_set_alignment (GTK_MISC(mainbar_label), 0, 0); - gtk_misc_set_padding (GTK_MISC(mainbar_label), 2, 2); - gtk_box_pack_start (GTK_BOX (mainbar), mainbar_label, TRUE, TRUE, 0); - return mainbar; + GUI *g = &uzbl.gui; + + g->mainbar = gtk_hbox_new (FALSE, 0); + g->mainbar_label = gtk_label_new (""); + gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC(g->mainbar_label), 0, 0); + gtk_misc_set_padding (GTK_MISC(g->mainbar_label), 2, 2); + gtk_box_pack_start (GTK_BOX (g->mainbar), g->mainbar_label, TRUE, TRUE, 0); + return g->mainbar; } static @@ -691,6 +981,8 @@ add_binding (const gchar *key, const gchar *act) { if (!parts) return; + //Debug: + printf ("Binding %-10s : %s\n", key, act); action = new_action(parts[0], parts[1]); g_hash_table_insert(bindings, g_strdup(key), action); @@ -703,19 +995,21 @@ settings_init () { gboolean res = FALSE; char *saveptr; gchar** keys = NULL; + State *s = &uzbl.state; + Network *n = &uzbl.net; - if (!config_file) { + if (!s->config_file) { const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME"); if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) { XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default; } printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME); - strcpy (config_file_path, XDG_CONFIG_HOME); - strcat (config_file_path, "/uzbl/config"); - if (file_exists (config_file_path)) { - printf ("Config file %s found.\n", config_file_path); - config_file = &config_file_path[0]; + strcpy (s->config_file_path, XDG_CONFIG_HOME); + strcat (s->config_file_path, "/uzbl/config"); + if (file_exists (s->config_file_path)) { + printf ("Config file %s found.\n", s->config_file_path); + s->config_file = &s->config_file_path[0]; } else { // Now we check $XDG_CONFIG_DIRS char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS"); @@ -727,25 +1021,25 @@ settings_init () { char buffer[512]; strcpy (buffer, XDG_CONFIG_DIRS); const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr); - while (dir && ! file_exists (config_file_path)) { - strcpy (config_file_path, dir); - strcat (config_file_path, "/uzbl/config_file_pathig"); - if (file_exists (config_file_path)) { - printf ("Config file %s found.\n", config_file_path); - config_file = &config_file_path[0]; + while (dir && ! file_exists (s->config_file_path)) { + strcpy (s->config_file_path, dir); + strcat (s->config_file_path, "/uzbl/config_file_pathig"); + if (file_exists (s->config_file_path)) { + printf ("Config file %s found.\n", s->config_file_path); + s->config_file = &s->config_file_path[0]; } dir = (char * ) strtok_r (NULL, ":", &saveptr); } } } - if (config_file) { + if (s->config_file) { config = g_key_file_new (); - res = g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, NULL); - if(res) { - printf ("Config %s loaded\n", config_file); + res = g_key_file_load_from_file (config, s->config_file, G_KEY_FILE_NONE, NULL); + if (res) { + printf ("Config %s loaded\n", s->config_file); } else { - fprintf (stderr, "Config %s loading failed\n", config_file); + fprintf (stderr, "Config %s loading failed\n", s->config_file); } } else { printf ("No configuration.\n"); @@ -754,6 +1048,7 @@ settings_init () { if (res) { history_handler = g_key_file_get_value (config, "behavior", "history_handler", NULL); download_handler = g_key_file_get_value (config, "behavior", "download_handler", NULL); + cookie_handler = g_key_file_get_string (config, "behavior", "cookie_handler", NULL); always_insert_mode = g_key_file_get_boolean (config, "behavior", "always_insert_mode", NULL); show_status = g_key_file_get_boolean (config, "behavior", "show_status", NULL); modkey = g_key_file_get_value (config, "behavior", "modkey", NULL); @@ -764,11 +1059,12 @@ settings_init () { socket_dir = g_key_file_get_value (config, "behavior", "socket_dir", NULL); keys = g_key_file_get_keys (config, "bindings", NULL, NULL); } - + printf ("History handler: %s\n", (history_handler ? history_handler : "disabled")); printf ("Download manager: %s\n", (download_handler ? download_handler : "disabled")); - printf ("Fifo directory: %s\n", (fifo_dir ? fifo_dir : "/tmp")); - printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "/tmp")); + printf ("Cookie handler: %s\n", (cookie_handler ? cookie_handler : "disabled")); + printf ("Fifo directory: %s\n", (fifo_dir ? fifo_dir : "disabled")); + printf ("Socket directory: %s\n", (socket_dir ? socket_dir : "disabled")); printf ("Always insert mode: %s\n", (always_insert_mode ? "TRUE" : "FALSE")); printf ("Show status: %s\n", (show_status ? "TRUE" : "FALSE")); printf ("Status top: %s\n", (status_top ? "TRUE" : "FALSE")); @@ -810,59 +1106,84 @@ settings_init () { } /* networking options */ - proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL); - http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL); - useragent = g_key_file_get_value (config, "network", "user-agent", NULL); - max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL); - max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL); + if (res) { + n->proxy_url = g_key_file_get_value (config, "network", "proxy_server", NULL); + http_debug = g_key_file_get_integer (config, "network", "http_debug", NULL); + n->useragent = g_key_file_get_value (config, "network", "user-agent", NULL); + n->max_conns = g_key_file_get_integer (config, "network", "max_conns", NULL); + n->max_conns_host = g_key_file_get_integer (config, "network", "max_conns_per_host", NULL); + } - if(proxy_url){ - g_object_set(G_OBJECT(soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(proxy_url), NULL); + if(n->proxy_url){ + g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_PROXY_URI, soup_uri_new(n->proxy_url), NULL); } if(!(http_debug <= 3)){ http_debug = 0; fprintf(stderr, "Wrong http_debug level, ignoring.\n"); } else if (http_debug > 0) { - soup_logger = soup_logger_new(http_debug, -1); - soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(soup_logger)); + n->soup_logger = soup_logger_new(http_debug, -1); + soup_session_add_feature(n->soup_session, SOUP_SESSION_FEATURE(n->soup_logger)); } - if(useragent){ - g_object_set(G_OBJECT(soup_session), SOUP_SESSION_USER_AGENT, useragent, NULL); + if(n->useragent){ + char* newagent = malloc(1024); + + strcpy(newagent, str_replace("%webkit-major%", itos(WEBKIT_MAJOR_VERSION), n->useragent)); + strcpy(newagent, str_replace("%webkit-minor%", itos(WEBKIT_MINOR_VERSION), newagent)); + strcpy(newagent, str_replace("%webkit-micro%", itos(WEBKIT_MICRO_VERSION), newagent)); + + if (uname (&unameinfo) == -1) { + printf("Error getting uname info. Not replacing system-related user agent variables.\n"); + } else { + strcpy(newagent, str_replace("%sysname%", unameinfo.sysname, newagent)); + strcpy(newagent, str_replace("%nodename%", unameinfo.nodename, newagent)); + strcpy(newagent, str_replace("%kernrel%", unameinfo.release, newagent)); + strcpy(newagent, str_replace("%kernver%", unameinfo.version, newagent)); + strcpy(newagent, str_replace("%arch-system%", unameinfo.machine, newagent)); + + #ifdef _GNU_SOURCE + strcpy(newagent, str_replace("%domainname%", unameinfo.domainname, newagent)); + #endif + } + + strcpy(newagent, str_replace("%arch-uzbl%", ARCH, newagent)); + strcpy(newagent, str_replace("%commit%", COMMIT, newagent)); + + n->useragent = malloc(1024); + strcpy(n->useragent, newagent); + g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_USER_AGENT, n->useragent, NULL); } - if(max_conns >= 1){ - g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS, max_conns, NULL); + if(n->max_conns >= 1){ + g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS, n->max_conns, NULL); } - if(max_conns_host >= 1){ - g_object_set(G_OBJECT(soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, max_conns_host, NULL); + if(n->max_conns_host >= 1){ + g_object_set(G_OBJECT(n->soup_session), SOUP_SESSION_MAX_CONNS_PER_HOST, n->max_conns_host, NULL); } - printf("Proxy configured: %s\n", proxy_url ? proxy_url : "none"); + printf("Proxy configured: %s\n", n->proxy_url ? n->proxy_url : "none"); printf("HTTP logging level: %d\n", http_debug); - printf("User-agent: %s\n", useragent? useragent : "default"); - printf("Maximum connections: %d\n", max_conns ? max_conns : 0); - printf("Maximum connections per host: %d\n", max_conns_host ? max_conns_host: 0); + printf("User-agent: %s\n", n->useragent? n->useragent : "default"); + printf("Maximum connections: %d\n", n->max_conns ? n->max_conns : 0); + printf("Maximum connections per host: %d\n", n->max_conns_host ? n->max_conns_host: 0); + - /* om nom nom nom */ - cookie_handler = g_key_file_get_string(config, "behavior", "cookie_handler", NULL); if(cookie_handler){ /* ck = soup_cookie_jar_new(); */ /* soup_session_add_feature(soup_session, SOUP_SESSION_FEATURE(ck)); */ /* g_signal_connect(ck, "changed", G_CALLBACK(cookie_recieved_action), NULL); */ - g_signal_connect(soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL); - printf("Cookie handler: %s\n", cookie_handler); + g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL); } } -static void handle_cookies (SoupSession *session, - SoupMessage *msg, - gpointer user_data){ - soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); +static void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data){ + (void) session; + (void) user_data; + soup_message_add_header_handler(msg, "got-headers", "Set-Cookie", G_CALLBACK(save_cookies), NULL); /* ask handler for cookies, if there are any, use soup_message_headers_replace (msg->request_headers, @@ -872,19 +1193,19 @@ static void handle_cookies (SoupSession *session, } static void -save_cookies (SoupMessage *msg, - gpointer user_data){ - GSList *ck; - char *req, *cookie; - for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ - cookie = soup_cookie_to_set_cookie_header(ck->data); - req = malloc(strlen(cookie) + 10); - sprintf(req, "PUT \"%s\"", cookie); - run_command_async(cookie_handler, req); - free(req); - free(cookie); - } - g_slist_free(ck); +save_cookies (SoupMessage *msg, gpointer user_data){ + (void) user_data; + GSList *ck; + char *req, *cookie; + for (ck = soup_cookies_from_response(msg); ck; ck = ck->next){ + cookie = soup_cookie_to_set_cookie_header(ck->data); + req = malloc(strlen(cookie) + 10); + sprintf(req, "PUT \"%s\"", cookie); + run_command_async(cookie_handler, req); + free(req); + free(cookie); + } + g_slist_free(ck); } int @@ -907,7 +1228,7 @@ main (int argc, char* argv[]) { /* initialize hash table */ bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action); - soup_session = webkit_get_default_session(); + uzbl.net.soup_session = webkit_get_default_session(); keycmd = g_string_new(""); settings_init (); @@ -923,35 +1244,42 @@ main (int argc, char* argv[]) { if (!status_top) gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0); - main_window = create_window (); - gtk_container_add (GTK_CONTAINER (main_window), vbox); + uzbl.gui.main_window = create_window (); + gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), vbox); - load_uri (web_view, uri); + load_uri (uzbl.gui.web_view, uzbl.state.uri); - gtk_widget_grab_focus (GTK_WIDGET (web_view)); - gtk_widget_show_all (main_window); - xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window); - printf("window_id %i\n",(int) xwin); + gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); + gtk_widget_show_all (uzbl.gui.main_window); + uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window); + printf("window_id %i\n",(int) uzbl.xwin); printf("pid %i\n", getpid ()); + printf("name: %s\n", uzbl.state.instance_name); + + uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); + uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v); + uzbl.gui.scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); + uzbl.gui.bar_h = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_h); + gtk_widget_set_scroll_adjustments ((GtkWidget*) uzbl.gui.web_view, uzbl.gui.bar_h, uzbl.gui.bar_v); - scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL); - bar_v = gtk_range_get_adjustment((GtkRange*) scbar_v); - scbar_h = (GtkScrollbar*) gtk_hscrollbar_new (NULL); - bar_h = gtk_range_get_adjustment((GtkRange*) scbar_h); - gtk_widget_set_scroll_adjustments ((GtkWidget*) web_view, bar_h, bar_v); if (!show_status) - gtk_widget_hide(mainbar); + gtk_widget_hide(uzbl.gui.mainbar); + setup_scanner(); - setup_threading (); - create_fifo (); + if (fifo_dir) + create_fifo (); + if (socket_dir) + create_socket(); gtk_main (); g_string_free(keycmd, TRUE); - unlink (socket_path); - unlink (fifo_path); + if (fifo_dir) + unlink (uzbl.comm.fifo_path); + if (socket_dir) + unlink (uzbl.comm.socket_path); g_hash_table_destroy(bindings); g_hash_table_destroy(commands); |