diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/callbacks.c | 187 | ||||
-rw-r--r-- | src/callbacks.h | 3 | ||||
-rw-r--r-- | src/cookie-jar.c | 300 | ||||
-rw-r--r-- | src/cookie-jar.h | 12 | ||||
-rw-r--r-- | src/events.c | 83 | ||||
-rw-r--r-- | src/events.h | 13 | ||||
-rw-r--r-- | src/io.c | 346 | ||||
-rw-r--r-- | src/io.h | 23 | ||||
-rw-r--r-- | src/menu.c | 192 | ||||
-rw-r--r-- | src/menu.h | 18 | ||||
-rw-r--r-- | src/util.c | 166 | ||||
-rw-r--r-- | src/util.h | 23 | ||||
-rwxr-xr-x | src/uzbl-browser | 7 | ||||
-rw-r--r-- | src/uzbl-core.c | 1471 | ||||
-rw-r--r-- | src/uzbl-core.h | 468 |
15 files changed, 1511 insertions, 1801 deletions
diff --git a/src/callbacks.c b/src/callbacks.c index 37c22a6..d315a9e 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -7,12 +7,14 @@ #include "callbacks.h" #include "events.h" #include "util.h" +#include "io.h" + void set_proxy_url() { SoupURI *suri; - if(uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') { + if (uzbl.net.proxy_url == NULL || *uzbl.net.proxy_url == ' ') { soup_session_remove_feature_by_type(uzbl.net.soup_session, (GType) SOUP_SESSION_PROXY_URI); } @@ -23,9 +25,11 @@ set_proxy_url() { suri, NULL); soup_uri_free(suri); } + return; } + void set_authentication_handler() { /* Check if WEBKIT_TYPE_SOUP_AUTH_DIALOG feature is set */ @@ -45,19 +49,26 @@ set_authentication_handler() { return; } + void set_status_background() { - GdkColor color; - gdk_color_parse (uzbl.behave.status_background, &color); /* labels and hboxes do not draw their own background. applying this * on the vbox/main_window is ok as the statusbar is the only affected * widget. (if not, we could also use GtkEventBox) */ - if (uzbl.gui.main_window) - gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color); - else if (uzbl.gui.plug) - gtk_widget_modify_bg (GTK_WIDGET(uzbl.gui.plug), GTK_STATE_NORMAL, &color); + GtkWidget* widget = uzbl.gui.main_window ? uzbl.gui.main_window : GTK_WIDGET (uzbl.gui.plug); + +#if GTK_CHECK_VERSION(2,91,0) + GdkRGBA color; + gdk_rgba_parse (&color, uzbl.behave.status_background); + gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &color); +#else + GdkColor color; + gdk_color_parse (uzbl.behave.status_background, &color); + gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &color); +#endif } + void set_icon() { if(file_exists(uzbl.gui.icon)) { @@ -105,7 +116,7 @@ cmd_set_status() { void cmd_load_uri() { - load_uri_imp (uzbl.state.uri); + load_uri_imp (uzbl.state.uri); } void @@ -402,12 +413,12 @@ link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpoin if(s->last_selected_url && g_strcmp0(s->selected_url, s->last_selected_url)) - send_event(LINK_UNHOVER, s->last_selected_url, NULL); + send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL); - send_event(LINK_HOVER, s->selected_url, NULL); + send_event(LINK_HOVER, NULL, TYPE_STR, s->selected_url, NULL); } else if(s->last_selected_url) { - send_event(LINK_UNHOVER, s->last_selected_url, NULL); + send_event(LINK_UNHOVER, NULL, TYPE_STR, s->last_selected_url, NULL); } update_title(); @@ -422,7 +433,7 @@ title_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { g_free (uzbl.gui.main_title); uzbl.gui.main_title = title ? g_strdup (title) : g_strdup ("(no title)"); update_title(); - send_event(TITLE_CHANGED, uzbl.gui.main_title, NULL); + send_event(TITLE_CHANGED, NULL, TYPE_STR, uzbl.gui.main_title, NULL); g_setenv("UZBL_TITLE", uzbl.gui.main_title, TRUE); } @@ -430,9 +441,7 @@ void progress_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { (void) param_spec; int progress = webkit_web_view_get_progress(web_view) * 100; - gchar *prg_str = itos(progress); - send_event(LOAD_PROGRESS, prg_str, NULL); - g_free(prg_str); + send_event(LOAD_PROGRESS, NULL, TYPE_INT, progress, NULL); } void @@ -443,7 +452,7 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { WebKitLoadStatus status = webkit_web_view_get_load_status(web_view); switch(status) { case WEBKIT_LOAD_PROVISIONAL: - send_event(LOAD_START, uzbl.state.uri, NULL); + send_event(LOAD_START, NULL, TYPE_STR, uzbl.state.uri ? uzbl.state.uri : "", NULL); break; case WEBKIT_LOAD_COMMITTED: g_free (uzbl.state.uri); @@ -451,10 +460,10 @@ load_status_change_cb (WebKitWebView* web_view, GParamSpec param_spec) { uzbl.state.uri = g_string_free (newuri, FALSE); g_setenv("UZBL_URI", uzbl.state.uri, TRUE); - send_event(LOAD_COMMIT, webkit_web_frame_get_uri (frame), NULL); + send_event(LOAD_COMMIT, NULL, TYPE_STR, webkit_web_frame_get_uri (frame), NULL); break; case WEBKIT_LOAD_FINISHED: - send_event(LOAD_FINISH, webkit_web_frame_get_uri(frame), NULL); + send_event(LOAD_FINISH, NULL, TYPE_STR, webkit_web_frame_get_uri(frame), NULL); break; case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT: break; /* we don't do anything with this (yet) */ @@ -471,7 +480,7 @@ selection_changed_cb(WebKitWebView *webkitwebview, gpointer ud) { webkit_web_view_copy_clipboard(webkitwebview); tmp = gtk_clipboard_wait_for_text(gtk_clipboard_get (GDK_SELECTION_CLIPBOARD)); - send_event(SELECTION_CHANGED, tmp, NULL); + send_event(SELECTION_CHANGED, NULL, TYPE_STR, tmp ? tmp : "", NULL); g_free(tmp); } @@ -481,11 +490,12 @@ load_error_cb (WebKitWebView* page, WebKitWebFrame* frame, gchar *uri, gpointer (void) frame; (void) ud; GError *err = web_err; - gchar *details; - details = g_strdup_printf("%s %d:%s", uri, err->code, err->message); - send_event(LOAD_ERROR, details, NULL); - g_free(details); + send_event (LOAD_ERROR, NULL, + TYPE_STR, uri, + TYPE_INT, err->code, + TYPE_STR, err->message, + NULL); } void @@ -505,7 +515,7 @@ configure_event_cb(GtkWidget* window, GdkEventConfigure* event) { retrieve_geometry(); if(strcmp(lastgeo, uzbl.gui.geometry)) - send_event(GEOMETRY_CHANGED, uzbl.gui.geometry, NULL); + send_event(GEOMETRY_CHANGED, NULL, TYPE_STR, uzbl.gui.geometry, NULL); g_free(lastgeo); return FALSE; @@ -517,10 +527,7 @@ focus_cb(GtkWidget* window, GdkEventFocus* event, void *ud) { (void) event; (void) ud; - if(event->in) - send_event(FOCUS_GAINED, "", NULL); - else - send_event(FOCUS_LOST, "", NULL); + send_event (event->in?FOCUS_GAINED:FOCUS_LOST, NULL, NULL); return FALSE; } @@ -562,9 +569,9 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) { /* left click */ if(event->button == 1) { if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) - send_event(FORM_ACTIVE, "button1", NULL); + send_event(FORM_ACTIVE, NULL, TYPE_NAME, "button1", NULL); else if((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)) - send_event(ROOT_ACTIVE, "button1", NULL); + send_event(ROOT_ACTIVE, NULL, TYPE_NAME, "button1", NULL); } else if(event->button == 2 && !(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) { sendev = TRUE; @@ -577,8 +584,8 @@ button_press_cb (GtkWidget* window, GdkEventButton* event) { if(sendev) { details = g_strdup_printf("Button%d", event->button); - send_event(KEY_PRESS, details, NULL); - g_free(details); + send_event(KEY_PRESS, NULL, TYPE_NAME, details, NULL); + g_free (details); } } @@ -606,8 +613,8 @@ button_release_cb (GtkWidget* window, GdkEventButton* event) { if(sendev) { details = g_strdup_printf("Button%d", event->button); - send_event(KEY_RELEASE, details, NULL); - g_free(details); + send_event(KEY_RELEASE, NULL, TYPE_NAME, details, NULL); + g_free (details); } } @@ -620,9 +627,11 @@ motion_notify_cb(GtkWidget* window, GdkEventMotion* event, gpointer user_data) { (void) event; (void) user_data; - gchar *details = g_strdup_printf("%.0lf %.0lf %u", event->x, event->y, event->state); - send_event(PTR_MOVE, details, NULL); - g_free(details); + send_event (PTR_MOVE, NULL, + TYPE_FLOAT, event->x, + TYPE_FLOAT, event->y, + TYPE_INT, event->state, + NULL); return FALSE; } @@ -641,23 +650,26 @@ navigation_decision_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNe printf("Navigation requested -> %s\n", uri); if (uzbl.behave.scheme_handler) { - GString *s = g_string_new (""); - g_string_printf(s, "'%s'", uri); + GString *result = g_string_new (""); + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + const CommandInfo *c = parse_command_parts(uzbl.behave.scheme_handler, a); - run_handler(uzbl.behave.scheme_handler, s->str); + if(c) { + g_array_append_val(a, uri); + run_parsed_command(c, a, result); + } + g_array_free(a, TRUE); - if(uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { - char *p = strchr(uzbl.comm.sync_stdout, '\n' ); + if(result->len > 0) { + char *p = strchr(result->str, '\n' ); if ( p != NULL ) *p = '\0'; - if (!strcmp(uzbl.comm.sync_stdout, "USED")) { + if (!strcmp(result->str, "USED")) { webkit_web_policy_decision_ignore(policy_decision); decision_made = TRUE; } } - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - g_string_free(s, TRUE); + g_string_free(result, TRUE); } if (!decision_made) webkit_web_policy_decision_use(policy_decision); @@ -676,7 +688,7 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, (void) user_data; if (uzbl.state.verbose) - printf("New window requested -> %s \n", webkit_network_request_get_uri (request)); + printf ("New window requested -> %s \n", webkit_network_request_get_uri (request)); /* This event function causes troubles with `target="_blank"` anchors. * Either we: @@ -690,9 +702,9 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, * We are leaving this uncommented as we would rather links open twice * than not at all. */ - send_event(NEW_WINDOW, webkit_network_request_get_uri (request), NULL); + send_event (NEW_WINDOW, NULL, TYPE_STR, webkit_network_request_get_uri (request), NULL); - webkit_web_policy_decision_ignore(policy_decision); + webkit_web_policy_decision_ignore (policy_decision); return TRUE; } @@ -722,7 +734,7 @@ request_starting_cb(WebKitWebView *web_view, WebKitWebFrame *frame, WebKitWebRes (void) response; (void) user_data; - send_event(REQUEST_STARTING, webkit_network_request_get_uri(request), NULL); + send_event (REQUEST_STARTING, NULL, TYPE_STR, webkit_network_request_get_uri(request), NULL); } void @@ -737,7 +749,7 @@ create_web_view_js2_cb (WebKitWebView* web_view, GParamSpec param_spec) { gtk_widget_destroy(GTK_WIDGET(web_view)); } else - send_event(NEW_WINDOW, uri, NULL); + send_event(NEW_WINDOW, NULL, TYPE_STR, uri, NULL); } @@ -778,9 +790,10 @@ download_progress_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_ const gchar *dest_uri = webkit_download_get_destination_uri(download); const gchar *dest_path = dest_uri + strlen("file://"); - gchar *details = g_strdup_printf("%s %.2lf", dest_path, progress); - send_event(DOWNLOAD_PROGRESS, details, NULL); - g_free(details); + send_event(DOWNLOAD_PROGRESS, NULL, + TYPE_STR, dest_path, + TYPE_FLOAT, progress, + NULL); } void @@ -800,7 +813,7 @@ download_status_cb(WebKitDownload *download, GParamSpec *pspec, gpointer user_da { const gchar *dest_uri = webkit_download_get_destination_uri(download); const gchar *dest_path = dest_uri + strlen("file://"); - send_event(DOWNLOAD_COMPLETE, dest_path, NULL); + send_event(DOWNLOAD_COMPLETE, NULL, TYPE_STR, dest_path, NULL); } } } @@ -844,27 +857,35 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat (this may be inaccurate, there's nothing we can do about that.) */ unsigned int total_size = webkit_download_get_total_size(download); - gchar *ev = g_strdup_printf("'%s' '%s' '%s' %d", uri, suggested_filename, - content_type, total_size); - run_handler(uzbl.behave.download_handler, ev); - g_free(ev); - - /* no response, cancel the download */ - if(!uzbl.comm.sync_stdout) { + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + const CommandInfo *c = parse_command_parts(uzbl.behave.download_handler, a); + if(!c) { webkit_download_cancel(download); + g_array_free(a, TRUE); return FALSE; } + g_array_append_val(a, uri); + g_array_append_val(a, suggested_filename); + g_array_append_val(a, content_type); + gchar *total_size_s = g_strdup_printf("%d", total_size); + g_array_append_val(a, total_size_s); + + GString *result = g_string_new (""); + run_parsed_command(c, a, result); + + g_free(total_size_s); + g_array_free(a, TRUE); + /* no response, cancel the download */ - if(uzbl.comm.sync_stdout[0] == 0) { + if(result->len == 0) { webkit_download_cancel(download); - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); return FALSE; } /* we got a response, it's the path we should download the file to */ - gchar *destination_path = uzbl.comm.sync_stdout; - uzbl.comm.sync_stdout = NULL; + gchar *destination_path = result->str; + g_string_free(result, FALSE); /* presumably people don't need newlines in their filenames. */ char *p = strchr(destination_path, '\n'); @@ -883,7 +904,7 @@ download_cb(WebKitWebView *web_view, WebKitDownload *download, gpointer user_dat g_free(rel_path); } - send_event(DOWNLOAD_STARTED, destination_path, NULL); + send_event(DOWNLOAD_STARTED, NULL, TYPE_STR, destination_path, NULL); /* convert absolute path to file:// URI */ gchar *destination_uri = g_strconcat("file://", destination_path, NULL); @@ -904,12 +925,13 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w) gdouble min = gtk_adjustment_get_lower(adjust); gdouble max = gtk_adjustment_get_upper(adjust); gdouble page = gtk_adjustment_get_page_size(adjust); - gchar* details; - details = g_strdup_printf("%g %g %g %g", value, min, max, page); - send_event(SCROLL_VERT, details, NULL); - - g_free(details); + send_event (SCROLL_VERT, NULL, + TYPE_FLOAT, value, + TYPE_FLOAT, min, + TYPE_FLOAT, max, + TYPE_FLOAT, page, + NULL); return (FALSE); } @@ -923,12 +945,13 @@ scroll_horiz_cb(GtkAdjustment *adjust, void *w) gdouble min = gtk_adjustment_get_lower(adjust); gdouble max = gtk_adjustment_get_upper(adjust); gdouble page = gtk_adjustment_get_page_size(adjust); - gchar* details; - details = g_strdup_printf("%g %g %g %g", value, min, max, page); - - send_event(SCROLL_HORIZ, details, NULL); - g_free(details); + send_event (SCROLL_HORIZ, NULL, + TYPE_FLOAT, value, + TYPE_FLOAT, min, + TYPE_FLOAT, max, + TYPE_FLOAT, page, + NULL); return (FALSE); } @@ -1019,12 +1042,4 @@ populate_popup_cb(WebKitWebView *v, GtkMenu *m, void *c) { } } -void -cmd_set_cookie_handler() { - if(uzbl.behave.cookie_handler[0] == 0) { - g_free(uzbl.behave.cookie_handler); - uzbl.behave.cookie_handler = NULL; - } - - uzbl_cookie_jar_set_handler(uzbl.net.soup_cookie_jar, uzbl.behave.cookie_handler); -} +/* vi: set et ts=4: */ diff --git a/src/callbacks.h b/src/callbacks.h index 899e959..13cb83d 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -216,6 +216,3 @@ scroll_vert_cb(GtkAdjustment *adjust, void *w); gboolean scroll_horiz_cb(GtkAdjustment *adjust, void *w); - -void -cmd_set_cookie_handler(); diff --git a/src/cookie-jar.c b/src/cookie-jar.c index 626e454..bc7d022 100644 --- a/src/cookie-jar.c +++ b/src/cookie-jar.c @@ -1,51 +1,20 @@ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <poll.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <string.h> -#include <errno.h> - -#include <libsoup/soup-uri.h> #include <libsoup/soup-cookie.h> #include "cookie-jar.h" #include "uzbl-core.h" #include "events.h" -static void -uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data); - -G_DEFINE_TYPE_WITH_CODE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR, - G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, uzbl_cookie_jar_session_feature_init)) +G_DEFINE_TYPE (UzblCookieJar, soup_cookie_jar_socket, SOUP_TYPE_COOKIE_JAR) -static void request_started (SoupSessionFeature *feature, SoupSession *session, SoupMessage *msg, SoupSocket *socket); static void changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie); -static void setup_handler(UzblCookieJar *jar); - -static void connect_cookie_socket(UzblCookieJar *jar); -static void disconnect_cookie_socket(UzblCookieJar *jar); - -static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_len); - -static bool has_socket_handler(UzblCookieJar *jar) { - return jar->socket_path != NULL; -} - static void soup_cookie_jar_socket_init(UzblCookieJar *jar) { - jar->handler = NULL; - jar->socket_path = NULL; - jar->connection_fd = -1; - jar->in_get_callback = 0; jar->in_manual_add = 0; } static void finalize(GObject *object) { - disconnect_cookie_socket(UZBL_COOKIE_JAR(object)); G_OBJECT_CLASS(soup_cookie_jar_socket_parent_class)->finalize(object); } @@ -55,272 +24,37 @@ soup_cookie_jar_socket_class_init(UzblCookieJarClass *socket_class) { SOUP_COOKIE_JAR_CLASS(socket_class)->changed = changed; } -/* override SoupCookieJar's request_started handler */ -static void -uzbl_cookie_jar_session_feature_init(SoupSessionFeatureInterface *iface, gpointer user_data) { - (void) user_data; - iface->request_started = request_started; -} - UzblCookieJar *uzbl_cookie_jar_new() { return g_object_new(UZBL_TYPE_COOKIE_JAR, NULL); } -void -uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar* handler) { - jar->handler = handler; - setup_handler(jar); -} - -char *get_cookies(UzblCookieJar *jar, SoupURI *uri) { - gchar *result, *path; - GString *s = g_string_new ("GET"); - - path = uri->path[0] ? uri->path : "/"; - - if(has_socket_handler(jar)) { - g_string_append_c(s, 0); /* null-terminate the GET */ - g_string_append_len(s, uri->scheme, strlen(uri->scheme)+1); - g_string_append_len(s, uri->host, strlen(uri->host)+1 ); - g_string_append_len(s, path, strlen(path)+1 ); - - result = do_socket_request(jar, s->str, s->len); - /* try it again; older cookie daemons closed the connection after each request */ - if(result == NULL) - result = do_socket_request(jar, s->str, s->len); - } else { - g_string_append_printf(s, " '%s' '%s' '%s'", uri->scheme, uri->host, uri->path); - - run_handler(jar->handler, s->str); - result = g_strdup(uzbl.comm.sync_stdout); - } - g_string_free(s, TRUE); - return result; -} - -/* this is a duplicate of SoupCookieJar's request_started that uses our get_cookies instead */ -static void -request_started(SoupSessionFeature *feature, SoupSession *session, - SoupMessage *msg, SoupSocket *socket) { - (void) session; (void) socket; - gchar *cookies; - - UzblCookieJar *jar = UZBL_COOKIE_JAR (feature); - SoupURI *uri = soup_message_get_uri(msg); - gboolean add_to_internal_jar = false; - - if(jar->handler) { - cookies = get_cookies(jar, uri); - } else { - /* no handler is set, fall back to the internal soup cookie jar */ - cookies = soup_cookie_jar_get_cookies(SOUP_COOKIE_JAR(jar), soup_message_get_uri (msg), TRUE); - } - - if (cookies && cookies[0] != 0) { - const gchar *next_cookie_start = cookies; - - if (add_to_internal_jar) { - /* add the cookie data that we just obtained from the cookie handler - to the cookie jar so that javascript has access to them. - we set this flag so that we don't trigger the PUT handler. */ - jar->in_get_callback = true; - do { - SoupCookie *soup_cookie = soup_cookie_parse(next_cookie_start, uri); - if(soup_cookie) - soup_cookie_jar_add_cookie(SOUP_COOKIE_JAR(uzbl.net.soup_cookie_jar), soup_cookie); - next_cookie_start = strchr(next_cookie_start, ';'); - } while(next_cookie_start++ != NULL); - jar->in_get_callback = false; - } - - soup_message_headers_replace (msg->request_headers, "Cookie", cookies); - } else { - soup_message_headers_remove (msg->request_headers, "Cookie"); - } - - if(cookies) - g_free (cookies); -} - static void changed(SoupCookieJar *jar, SoupCookie *old_cookie, SoupCookie *new_cookie) { - SoupCookie * cookie = new_cookie ? new_cookie : old_cookie; + SoupCookie *cookie = new_cookie ? new_cookie : old_cookie; UzblCookieJar *uzbl_jar = UZBL_COOKIE_JAR(jar); - /* when Uzbl begins an HTTP request, it GETs cookies from the handler - and then adds them to the cookie jar so that javascript can access - these cookies. this causes a 'changed' callback, which we don't want - to do anything, so we just return. - - (if SoupCookieJar let us override soup_cookie_jar_get_cookies we - wouldn't have to do this.) */ - if(uzbl_jar->in_get_callback) - return; - - gchar *scheme = cookie->secure ? "https" : "http"; - - /* send a ADD or DELETE -_COOKIE event depending on what have changed */ + /* send a ADD or DELETE -_COOKIE event depending on what has changed. these + * events aren't sent when a cookie changes due to an add/delete_cookie + * command because otherwise a loop would occur when a cookie change is + * propagated to other uzbl instances using add/delete_cookie. */ if(!uzbl_jar->in_manual_add) { + gchar *scheme = cookie->secure ? "https" : "http"; + gchar *expires = NULL; if(cookie->expires) expires = g_strdup_printf ("%d", soup_date_to_time_t (cookie->expires)); - gchar * eventstr = g_strdup_printf ("'%s' '%s' '%s' '%s' '%s' '%s'", - cookie->domain, cookie->path, cookie->name, cookie->value, scheme, expires?expires:""); - if(new_cookie) - send_event(ADD_COOKIE, eventstr, NULL); - else - send_event(DELETE_COOKIE, eventstr, NULL); - g_free(eventstr); + send_event (new_cookie ? ADD_COOKIE : DELETE_COOKIE, NULL, + TYPE_STR, cookie->domain, + TYPE_STR, cookie->path, + TYPE_STR, cookie->name, + TYPE_STR, cookie->value, + TYPE_STR, scheme, + TYPE_STR, expires ? expires : "", + NULL); + if(expires) g_free(expires); } - - /* the cookie daemon is only interested in new cookies and changed - ones, it can take care of deleting expired cookies on its own. */ - if(!new_cookie) - return; - - GString *s = g_string_new ("PUT"); - - if(has_socket_handler(uzbl_jar)) { - g_string_append_c(s, 0); /* null-terminate the PUT */ - g_string_append_len(s, scheme, strlen(scheme)+1); - g_string_append_len(s, new_cookie->domain, strlen(new_cookie->domain)+1 ); - g_string_append_len(s, new_cookie->path, strlen(new_cookie->path)+1 ); - g_string_append_printf(s, "%s=%s", new_cookie->name, new_cookie->value); - - gchar *result = do_socket_request(uzbl_jar, s->str, s->len+1); - /* try it again; older cookie daemons closed the connection after each request */ - if(!result) - result = do_socket_request(uzbl_jar, s->str, s->len+1); - - g_free(result); - } else { - g_string_append_printf(s, " '%s' '%s' '%s' '%s=%s'", scheme, new_cookie->domain, new_cookie->path, new_cookie->name, new_cookie->value); - - run_handler(uzbl_jar->handler, s->str); - } - - g_string_free(s, TRUE); -} - -static void -setup_handler(UzblCookieJar *jar) { - if(jar->handler && strncmp(jar->handler, "talk_to_socket", strlen("talk_to_socket")) == 0) { - /* extract the socket path from the handler. */ - jar->socket_path = jar->handler + strlen("talk_to_socket"); - while(isspace(*jar->socket_path)) - jar->socket_path++; - if(*jar->socket_path == 0) - return; /* there was no path specified. */ - disconnect_cookie_socket(jar); - connect_cookie_socket(jar); - } else { - jar->socket_path = NULL; - } -} - -static void -connect_cookie_socket(UzblCookieJar *jar) { - struct sockaddr_un sa; - int fd; - - g_strlcpy(sa.sun_path, jar->socket_path, sizeof(sa.sun_path)); - sa.sun_family = AF_UNIX; - - /* create socket file descriptor and connect it to path */ - fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if(fd == -1) { - g_printerr("connect_cookie_socket: creating socket failed (%s)\n", strerror(errno)); - return; - } - - if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))) { - g_printerr("connect_cookie_socket: connect failed (%s)\n", strerror(errno)); - close(fd); - return; - } - - /* successful connection! */ - jar->connection_fd = fd; -} - -static void -disconnect_cookie_socket(UzblCookieJar *jar) { - if(jar->connection_fd > 0) { - close(jar->connection_fd); - jar->connection_fd = -1; - } -} - -static gchar *do_socket_request(UzblCookieJar *jar, gchar *request, int request_length) { - int len; - ssize_t ret; - struct pollfd pfd; - gchar *result = NULL; - - if(jar->connection_fd < 0) - connect_cookie_socket(jar); /* connection was lost, reconnect */ - - /* write request */ - ret = write(jar->connection_fd, request, request_length); - if(ret == -1) { - g_printerr("talk_to_socket: write failed (%s)\n", strerror(errno)); - disconnect_cookie_socket(jar); - return NULL; - } - - /* wait for a response, with a 500ms timeout */ - pfd.fd = jar->connection_fd; - pfd.events = POLLIN; - while(1) { - ret = poll(&pfd, 1, 500); - if(ret == 1) break; - if(ret == 0) errno = ETIMEDOUT; - if(errno == EINTR) continue; - g_printerr("talk_to_socket: poll failed while waiting for input (%s)\n", - strerror(errno)); - if(errno != ETIMEDOUT) - disconnect_cookie_socket(jar); - return NULL; - } - - /* get length of response */ - if(ioctl(jar->connection_fd, FIONREAD, &len) == -1) { - g_printerr("talk_to_socket: cannot find daemon response length, " - "ioctl failed (%s)\n", strerror(errno)); - disconnect_cookie_socket(jar); - return NULL; - } - - /* there was an empty response. */ - if(len == 0) - return g_strdup(""); - - /* there is a response, read it */ - result = g_malloc(len + 1); - if(!result) { - g_printerr("talk_to_socket: failed to allocate %d bytes\n", len); - return NULL; - } - result[len] = 0; /* ensure result is null terminated */ - - gchar *p = result; - while(len > 0) { - ret = read(jar->connection_fd, p, len); - if(ret == -1) { - g_printerr("talk_to_socket: failed to read from socket (%s)\n", - strerror(errno)); - disconnect_cookie_socket(jar); - g_free(result); - return NULL; - } else { - len -= ret; - p += ret; - } - } - - return result; } diff --git a/src/cookie-jar.h b/src/cookie-jar.h index f3e3733..05f4a6f 100644 --- a/src/cookie-jar.h +++ b/src/cookie-jar.h @@ -10,12 +10,6 @@ typedef struct { SoupCookieJar parent; - const gchar *handler; - - const gchar *socket_path; - int connection_fd; - - gboolean in_get_callback; gboolean in_manual_add; } UzblCookieJar; @@ -25,10 +19,4 @@ typedef struct { UzblCookieJar *uzbl_cookie_jar_new(); -void -uzbl_cookie_jar_set_handler(UzblCookieJar *jar, const gchar *handler); - -char -*get_cookies(UzblCookieJar *jar, SoupURI *uri); - #endif diff --git a/src/events.c b/src/events.c index 31a95d5..174ff75 100644 --- a/src/events.c +++ b/src/events.c @@ -5,6 +5,7 @@ #include "uzbl-core.h" #include "events.h" +#include "util.h" UzblCore uzbl; @@ -137,32 +138,66 @@ send_event_stdout(GString *msg) { fflush(stdout); } +void +vsend_event(int type, const gchar *custom_event, va_list vargs) { + GString *event_message = g_string_sized_new (512); + + if (type >= LAST_EVENT) + return; + const gchar *event = custom_event ? custom_event : event_table[type]; + char* str; + + int next; + g_string_printf (event_message, "EVENT [%s] %s", + uzbl.state.instance_name, event); + + while ((next = va_arg (vargs, int)) != 0) { + g_string_append_c(event_message, ' '); + switch(next) { + case TYPE_INT: + g_string_append_printf (event_message, "%d", va_arg (vargs, int)); + break; + case TYPE_STR: + g_string_append_c (event_message, '\''); + append_escaped (event_message, va_arg (vargs, char*)); + g_string_append_c (event_message, '\''); + break; + case TYPE_FORMATTEDSTR: + g_string_append (event_message, va_arg (vargs, char*)); + break; + case TYPE_NAME: + str = va_arg (vargs, char*); + g_assert (valid_name (str)); + g_string_append (event_message, str); + break; + case TYPE_FLOAT: + // ‘float’ is promoted to ‘double’ when passed through ‘...’ + g_string_append_printf (event_message, "%.2f", va_arg (vargs, double)); + break; + } + } + + g_string_append_c(event_message, '\n'); + + if (uzbl.state.events_stdout) + send_event_stdout (event_message); + send_event_socket (event_message); + + g_string_free (event_message, TRUE); +} + /* * build event string and send over the supported interfaces * custom_event == NULL indicates an internal event */ void -send_event(int type, const gchar *details, const gchar *custom_event) { - GString *event_message = g_string_new(""); - - /* check for custom events */ - if(custom_event) { - g_string_printf(event_message, "EVENT [%s] %s %s\n", - uzbl.state.instance_name, custom_event, details); - } - /* check wether we support the internal event */ - else if(type < LAST_EVENT) { - g_string_printf(event_message, "EVENT [%s] %s %s\n", - uzbl.state.instance_name, event_table[type], details); - } - - if(event_message->str) { - if(uzbl.state.events_stdout) - send_event_stdout(event_message); - send_event_socket(event_message); - - g_string_free(event_message, TRUE); - } +send_event(int type, const gchar *custom_event, ...) { + va_list vargs, vacopy; + va_start (vargs, custom_event); + va_copy (vacopy, vargs); + vsend_event (type, custom_event, vacopy); + va_end (vacopy); + va_end (vargs); } /* Transform gdk key events to our own events */ @@ -181,12 +216,14 @@ key_to_event(guint keyval, gint mode) { ucs[ulen] = 0; send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE, - ucs, NULL); + NULL, TYPE_FORMATTEDSTR, ucs, NULL); } /* send keysym for non-printable chars */ else { send_event(mode == GDK_KEY_PRESS ? KEY_PRESS : KEY_RELEASE, - gdk_keyval_name(keyval), NULL); + NULL, TYPE_NAME, gdk_keyval_name(keyval), NULL); } } + +/* vi: set et ts=4: */ diff --git a/src/events.h b/src/events.h index 3c7b933..8e75097 100644 --- a/src/events.h +++ b/src/events.h @@ -3,6 +3,12 @@ ** (c) 2009 by Robert Manea */ +#ifndef __EVENTS__ +#define __EVENTS__ + +#include <glib.h> +#include <stdarg.h> + /* Event system */ enum event_type { LOAD_START, LOAD_COMMIT, LOAD_FINISH, LOAD_ERROR, @@ -33,7 +39,12 @@ void send_event_stdout(GString *msg); void -send_event(int type, const gchar *details, const gchar *custom_event); +vsend_event(int type, const gchar *custom_event, va_list vargs); + +void +send_event(int type, const gchar *custom_event, ...) G_GNUC_NULL_TERMINATED; void key_to_event(guint keyval, gint mode); + +#endif diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..b84780e --- /dev/null +++ b/src/io.c @@ -0,0 +1,346 @@ +#define _POSIX_SOURCE + +#include <stdio.h> + +#include "events.h" +#include "io.h" +#include "util.h" +#include "uzbl-core.h" + +/*@null@*/ gchar* +build_stream_name(int type, const gchar* dir) { + State *s = &uzbl.state; + gchar *str = NULL; + + if (type == FIFO) { + str = g_strdup_printf + ("%s/uzbl_fifo_%s", dir, s->instance_name); + } else if (type == SOCKET) { + str = g_strdup_printf + ("%s/uzbl_socket_%s", dir, s->instance_name); + } + return str; +} + + +gboolean +control_fifo(GIOChannel *gio, GIOCondition condition) { + if (uzbl.state.verbose) + printf("triggered\n"); + gchar *ctl_line; + GIOStatus ret; + GError *err = NULL; + + if (condition & G_IO_HUP) + g_error ("Fifo: Read end of pipe died!\n"); + + if(!gio) + g_error ("Fifo: GIOChannel broke\n"); + + 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); + g_error_free (err); + } + + parse_cmd_line(ctl_line, NULL); + g_free(ctl_line); + + return TRUE; +} + + +gboolean +attach_fifo(gchar *path) { + GError *error = NULL; + /* 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. */ + GIOChannel *chan = g_io_channel_new_file(path, "r+", &error); + if (chan) { + if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { + if (uzbl.state.verbose) + printf ("attach_fifo: created successfully as %s\n", path); + send_event(FIFO_SET, path, NULL); + uzbl.comm.fifo_path = path; + g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE); + return TRUE; + } else g_warning ("attach_fifo: could not add watch on %s\n", path); + } else g_warning ("attach_fifo: can't open: %s\n", error->message); + + if (error) g_error_free (error); + return FALSE; +} + + +/*@null@*/ gchar* +init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ + if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */ + if (unlink(uzbl.comm.fifo_path) == -1) + g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path); + g_free(uzbl.comm.fifo_path); + uzbl.comm.fifo_path = NULL; + } + + gchar *path = build_stream_name(FIFO, dir); + + if (!file_exists(path)) { + if (mkfifo (path, 0666) == 0 && attach_fifo(path)) { + return dir; + } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno)); + } else { + /* the fifo exists. but is anybody home? */ + int fd = open(path, O_WRONLY|O_NONBLOCK); + if(fd < 0) { + /* some error occurred, presumably nobody's on the read end. + * we can attach ourselves to it. */ + if(attach_fifo(path)) + return dir; + else + g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno)); + } else { + /* somebody's there, we can't use that fifo. */ + close(fd); + /* whatever, this instance can live without a fifo. */ + g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path); + } + } + + /* if we got this far, there was an error; cleanup */ + g_free(dir); + g_free(path); + return NULL; +} + + +gboolean +control_stdin(GIOChannel *gio, GIOCondition condition) { + (void) condition; + gchar *ctl_line = NULL; + GIOStatus ret; + + ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL); + if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) + return FALSE; + + GString *result = g_string_new(""); + + parse_cmd_line(ctl_line, result); + g_free(ctl_line); + + puts(result->str); + g_string_free(result, TRUE); + + return TRUE; +} + +void +create_stdin() { + GIOChannel *chan = g_io_channel_unix_new(fileno(stdin)); + if (chan) { + if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) { + g_error ("create_stdin: could not add watch\n"); + } else if (uzbl.state.verbose) { + printf ("create_stdin: watch added successfully\n"); + } + } else { + g_error ("create_stdin: error while opening stdin\n"); + } +} + +gboolean +remove_socket_from_array(GIOChannel *chan) { + gboolean ret = 0; + + ret = g_ptr_array_remove_fast(uzbl.comm.connect_chan, chan); + if(!ret) + ret = g_ptr_array_remove_fast(uzbl.comm.client_chan, chan); + + if(ret) + g_io_channel_unref (chan); + return ret; +} + +gboolean +control_socket(GIOChannel *chan) { + struct sockaddr_un remote; + unsigned int t = sizeof(remote); + GIOChannel *iochan; + int clientsock; + + clientsock = accept (g_io_channel_unix_get_fd(chan), + (struct sockaddr *) &remote, &t); + + if(!uzbl.comm.client_chan) + uzbl.comm.client_chan = g_ptr_array_new(); + + if ((iochan = g_io_channel_unix_new(clientsock))) { + g_io_channel_set_encoding(iochan, NULL, NULL); + g_io_add_watch(iochan, G_IO_IN|G_IO_HUP, + (GIOFunc) control_client_socket, iochan); + g_ptr_array_add(uzbl.comm.client_chan, (gpointer)iochan); + } + return TRUE; +} + + +void +init_connect_socket() { + int sockfd, replay = 0; + struct sockaddr_un local; + GIOChannel *chan; + gchar **name = NULL; + + if(!uzbl.comm.connect_chan) + uzbl.comm.connect_chan = g_ptr_array_new(); + + name = uzbl.state.connect_socket_names; + + while(name && *name) { + sockfd = socket (AF_UNIX, SOCK_STREAM, 0); + local.sun_family = AF_UNIX; + strcpy (local.sun_path, *name); + + if(!connect(sockfd, (struct sockaddr *) &local, sizeof(local))) { + if ((chan = g_io_channel_unix_new(sockfd))) { + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, + (GIOFunc) control_client_socket, chan); + g_ptr_array_add(uzbl.comm.connect_chan, (gpointer)chan); + replay++; + } + } + else + g_warning("Error connecting to socket: %s\n", *name); + name++; + } + + /* replay buffered events */ + if(replay) + send_event_socket(NULL); +} + + +gboolean +control_client_socket(GIOChannel *clientchan) { + char *ctl_line; + GString *result = g_string_new(""); + GError *error = NULL; + GIOStatus ret; + gsize len; + + ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error reading: %s", error->message); + g_clear_error (&error); + ret = g_io_channel_shutdown (clientchan, TRUE, &error); + remove_socket_from_array (clientchan); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error closing: %s", error->message); + g_clear_error (&error); + } + return FALSE; + } else if (ret == G_IO_STATUS_EOF) { + /* shutdown and remove channel watch from main loop */ + ret = g_io_channel_shutdown (clientchan, TRUE, &error); + remove_socket_from_array (clientchan); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error closing: %s", error->message); + g_clear_error (&error); + } + return FALSE; + } + + if (ctl_line) { + parse_cmd_line (ctl_line, result); + g_string_append_c(result, '\n'); + ret = g_io_channel_write_chars (clientchan, result->str, result->len, + &len, &error); + if (ret == G_IO_STATUS_ERROR) { + g_warning ("Error writing: %s", error->message); + g_clear_error (&error); + } + if (g_io_channel_flush(clientchan, &error) == G_IO_STATUS_ERROR) { + g_warning ("Error flushing: %s", error->message); + g_clear_error (&error); + } + } + + g_string_free(result, TRUE); + g_free(ctl_line); + return TRUE; +} + + +gboolean +attach_socket(gchar *path, struct sockaddr_un *local) { + GIOChannel *chan = NULL; + int sock = socket (AF_UNIX, SOCK_STREAM, 0); + + if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) { + if (uzbl.state.verbose) + printf ("init_socket: opened in %s\n", path); + + if(listen (sock, 5) < 0) + g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno)); + + if( (chan = g_io_channel_unix_new(sock)) ) { + g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); + uzbl.comm.socket_path = path; + send_event(SOCKET_SET, path, NULL); + g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE); + return TRUE; + } + } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno)); + + return FALSE; +} + + +/*@null@*/ gchar* +init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */ + if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */ + if (unlink(uzbl.comm.socket_path) == -1) + g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path); + g_free(uzbl.comm.socket_path); + uzbl.comm.socket_path = NULL; + } + + if (*dir == ' ') { + g_free(dir); + return NULL; + } + + struct sockaddr_un local; + gchar *path = build_stream_name(SOCKET, dir); + + local.sun_family = AF_UNIX; + strcpy (local.sun_path, path); + + if(!file_exists(path) && attach_socket(path, &local)) { + /* it's free for the taking. */ + return dir; + } else { + /* see if anybody's listening on the socket path we want. */ + int sock = socket (AF_UNIX, SOCK_STREAM, 0); + if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) { + /* some error occurred, presumably nobody's listening. + * we can attach ourselves to it. */ + unlink(path); + if(attach_socket(path, &local)) + return dir; + else + g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno)); + } else { + /* somebody's there, we can't use that socket path. */ + close(sock); + /* whatever, this instance can live without a socket. */ + g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path); + } + } + + /* if we got this far, there was an error; cleanup */ + g_free(path); + g_free(dir); + return NULL; +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..a6ea0a1 --- /dev/null +++ b/src/io.h @@ -0,0 +1,23 @@ +#ifndef __IO__ +#define __IO__ + +#include <glib/gstdio.h> + +/*@null@*/ gchar* +build_stream_name(int type, const gchar *dir); + +gboolean control_fifo(GIOChannel *gio, GIOCondition condition); + +/*@null@*/ gchar* +init_fifo(gchar *dir); + +gboolean control_stdin(GIOChannel *gio, GIOCondition condition); +void create_stdin(); + +/*@null@*/ gchar* +init_socket(gchar *dir); + +gboolean control_socket(GIOChannel *chan); +gboolean control_client_socket(GIOChannel *chan); + +#endif diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..451b35a --- /dev/null +++ b/src/menu.c @@ -0,0 +1,192 @@ +#include "menu.h" +#include "util.h" +#include "uzbl-core.h" + +void +add_to_menu(GArray *argv, guint context) { + GUI *g = &uzbl.gui; + MenuItem *m; + gchar *item_cmd = NULL; + + if(!argv_idx(argv, 0)) + return; + + gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); + if(!g->menu_items) + g->menu_items = g_ptr_array_new(); + + if(split[1]) + item_cmd = split[1]; + + if(split[0]) { + m = malloc(sizeof(MenuItem)); + m->name = g_strdup(split[0]); + m->cmd = g_strdup(item_cmd?item_cmd:""); + m->context = context; + m->issep = FALSE; + g_ptr_array_add(g->menu_items, m); + } + + g_strfreev(split); +} + + +void +menu_add(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); + +} + + +void +menu_add_link(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); +} + + +void +menu_add_image(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); +} + + +void +menu_add_edit(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); +} + + +void +add_separator_to_menu(GArray *argv, guint context) { + GUI *g = &uzbl.gui; + MenuItem *m; + gchar *sep_name; + + if(!g->menu_items) + g->menu_items = g_ptr_array_new(); + + if(!argv_idx(argv, 0)) + return; + else + sep_name = argv_idx(argv, 0); + + m = malloc(sizeof(MenuItem)); + m->name = g_strdup(sep_name); + m->cmd = NULL; + m->context = context; + m->issep = TRUE; + g_ptr_array_add(g->menu_items, m); +} + + +void +menu_add_separator(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); +} + + +void +menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); +} + + +void +menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); +} + + +void +menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); +} + + +void +remove_from_menu(GArray *argv, guint context) { + GUI *g = &uzbl.gui; + MenuItem *mi; + gchar *name = NULL; + guint i=0; + + if(!g->menu_items) + return; + + if(!argv_idx(argv, 0)) + return; + else + name = argv_idx(argv, 0); + + for(i=0; i < g->menu_items->len; i++) { + mi = g_ptr_array_index(g->menu_items, i); + + if((context == mi->context) && !strcmp(name, mi->name)) { + g_free(mi->name); + g_free(mi->cmd); + g_free(mi); + g_ptr_array_remove_index(g->menu_items, i); + } + } +} + + +void +menu_remove(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); +} + + +void +menu_remove_link(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); +} + + +void +menu_remove_image(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); +} + + +void +menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; + (void) result; + + remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); +} + diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..8b89f2f --- /dev/null +++ b/src/menu.h @@ -0,0 +1,18 @@ +#ifndef __MENU__ +#define __MENU__ + +#include <webkit/webkit.h> + +void menu_add(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_link(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_image(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_edit(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_separator(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result); +void menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result); +void menu_remove(WebKitWebView *page, GArray *argv, GString *result); +void menu_remove_link(WebKitWebView *page, GArray *argv, GString *result); +void menu_remove_image(WebKitWebView *page, GArray *argv, GString *result); +void menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result); +#endif @@ -6,8 +6,9 @@ #include "util.h" -const XDG_Var XDG[] = -{ +gchar* find_existing_file2(gchar *, const gchar *); + +const XDG_Var XDG[] = { { "XDG_CONFIG_HOME", "~/.config" }, { "XDG_DATA_HOME", "~/.local/share" }, { "XDG_CACHE_HOME", "~/.cache" }, @@ -17,56 +18,41 @@ const XDG_Var XDG[] = /*@null@*/ gchar* get_xdg_var (XDG_Var xdg) { - const gchar* actual_value = getenv (xdg.environmental); - const gchar* home = getenv ("HOME"); - gchar* return_value; - - if (! actual_value || strcmp (actual_value, "") == 0) { - if (xdg.default_value) { - return_value = str_replace ("~", home, xdg.default_value); - } else { - return_value = NULL; - } - } else { - return_value = str_replace("~", home, actual_value); - } + const gchar *actual_value = getenv(xdg.environmental); + const gchar *home = getenv("HOME"); - return return_value; + if (!actual_value || !actual_value[0]) + actual_value = xdg.default_value; + + if (!actual_value) + return NULL; + + return str_replace("~", home, actual_value); } /*@null@*/ gchar* -find_xdg_file (int xdg_type, const char* filename) { +find_xdg_file (int xdg_type, const char* basename) { /* xdg_type = 0 => config xdg_type = 1 => data - xdg_type = 2 => cache*/ + xdg_type = 2 => cache */ - gchar* xdgv = get_xdg_var (XDG[xdg_type]); - gchar* temporary_file = g_strconcat (xdgv, filename, NULL); + gchar *xdgv = get_xdg_var(XDG[xdg_type]); + gchar *path = g_strconcat (xdgv, basename, NULL); g_free (xdgv); - gchar* temporary_string; - char* saveptr; - char* buf; - - if (! file_exists (temporary_file) && xdg_type != 2) { - buf = get_xdg_var (XDG[3 + xdg_type]); - temporary_string = (char *) strtok_r (buf, ":", &saveptr); - g_free(buf); + if (file_exists(path)) + return path; - while ((temporary_string = (char * ) strtok_r (NULL, ":", &saveptr)) && ! file_exists (temporary_file)) { - g_free (temporary_file); - temporary_file = g_strconcat (temporary_string, filename, NULL); - } - } + if (xdg_type == 2) + return NULL; - //g_free (temporary_string); - segfaults. + /* the file doesn't exist in the expected directory. + * check if it exists in one of the system-wide directories. */ + char *system_dirs = get_xdg_var(XDG[3 + xdg_type]); + path = find_existing_file2(system_dirs, basename); + g_free(system_dirs); - if (file_exists (temporary_file)) { - return temporary_file; - } else { - g_free(temporary_file); - return NULL; - } + return path; } gboolean @@ -96,15 +82,99 @@ for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void * GIOChannel *chan = g_io_channel_new_file(path, "r", NULL); - if (chan) { - while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) { - callback(line, user_data); - g_free(line); - } - g_io_channel_unref (chan); + if (!chan) + return FALSE; - return TRUE; + while (g_io_channel_read_line(chan, &line, &len, NULL, NULL) == G_IO_STATUS_NORMAL) { + callback(line, user_data); + g_free(line); } - return FALSE; + g_io_channel_unref (chan); + + return TRUE; +} + +/* This function searches the directories in the : separated ($PATH style) + * string 'dirs' for a file named 'basename'. It returns the path of the first + * file found, or NULL if none could be found. + * NOTE: this function modifies the 'dirs' argument. */ +gchar* +find_existing_file2(gchar *dirs, const gchar *basename) { + char *saveptr = NULL; + + /* iterate through the : separated elements until we find our file. */ + char *tok = strtok_r(dirs, ":", &saveptr); + char *path = g_strconcat (tok, "/", basename, NULL); + + while (!file_exists(path)) { + g_free(path); + + tok = strtok_r(NULL, ":", &saveptr); + if (!tok) + return NULL; /* we've hit the end of the string */ + + path = g_strconcat (tok, "/", basename, NULL); + } + + return path; +} + +/* search a PATH style string for an existing file+path combination. + * everything after the last ':' is assumed to be the name of the file. + * e.g. "/tmp:/home:a/file" will look for /tmp/a/file and /home/a/file. + * + * if there are no :s then the entire thing is taken to be the path. */ +gchar* +find_existing_file(const gchar* path_list) { + if(!path_list) + return NULL; + + char *path_list_dup = g_strdup(path_list); + + char *basename = strrchr(path_list_dup, ':'); + if(!basename) + return path_list_dup; + + basename[0] = '\0'; + basename++; + + char *result = find_existing_file2(path_list_dup, basename); + g_free(path_list_dup); + return result; +} + +gchar* +argv_idx(const GArray *a, const guint idx) { + return g_array_index(a, gchar*, idx); +} + +GString * +append_escaped (GString *dest, const gchar *src) { + g_assert(dest); + g_assert(src); + + // Hint that we are going to append another string. + int oldlen = dest->len; + g_string_set_size (dest, dest->len + strlen(src) * 2); + g_string_truncate (dest, oldlen); + + // Append src char by char with baddies escaped + for (const gchar *p = src; *p; p++) { + switch (*p) { + case '\\': + g_string_append (dest, "\\\\"); + break; + case '\'': + g_string_append (dest, "\\'"); + break; + case '\n': + g_string_append (dest, "\\n"); + break; + default: + g_string_append_c (dest, *p); + break; + } + } + return dest; } @@ -1,18 +1,19 @@ #include <glib.h> +#include <stdio.h> typedef struct { gchar* environmental; gchar* default_value; } XDG_Var; -gchar* get_xdg_var (XDG_Var xdg); - -gchar* find_xdg_file (int xdg_type, const char* filename); - -gboolean file_exists(const char* filename); - -char * -str_replace (const char* search, const char* replace, const char* string); - -gboolean -for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data); +gchar* get_xdg_var(XDG_Var xdg); +gchar* find_xdg_file(int xdg_type, const char* filename); +gboolean file_exists(const char* filename); +char* str_replace(const char* search, const char* replace, const char* string); +gboolean for_each_line_in_file(const gchar *path, void (*callback)(const gchar *l, void *c), void *user_data); +gchar* find_existing_file(const gchar*); +gchar* argv_idx(const GArray*, const guint); +/** + * appends `src' to `dest' with backslash, single-quotes and newlines in + * `src' escaped */ +GString * append_escaped (GString *dest, const gchar *src); diff --git a/src/uzbl-browser b/src/uzbl-browser index faa2829..81645ca 100755 --- a/src/uzbl-browser +++ b/src/uzbl-browser @@ -64,13 +64,6 @@ then export UZBL_UTIL_DIR fi -# uzbl-cookie-manager will exit if another instance is already running. -# we could also check if its pid file exists to avoid having to spawn it. -#if [ ! -f "$XDG_CACHE_HOME"/uzbl/cookie_daemon_socket.pid ] -#then -# ${UZBL_COOKIE_DAEMON:-uzbl-cookie-manager} -#fi - # uzbl-event-manager will exit if one is already running. # we could also check if its pid file exists to avoid having to spawn it. DAEMON_SOCKET="$XDG_CACHE_HOME"/uzbl/event_daemon diff --git a/src/uzbl-core.c b/src/uzbl-core.c index 5953a11..638dd1f 100644 --- a/src/uzbl-core.c +++ b/src/uzbl-core.c @@ -35,13 +35,14 @@ #include "inspector.h" #include "config.h" #include "util.h" +#include "menu.h" +#include "io.h" UzblCore uzbl; /* commandline arguments (set initial values for the state variables) */ const -GOptionEntry entries[] = -{ +GOptionEntry entries[] = { { "uri", 'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri, "Uri to load at startup (equivalent to 'uzbl <uri>' or 'set uri = URI' after uzbl has launched)", "URI" }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &uzbl.state.verbose, @@ -91,7 +92,6 @@ const struct var_name_to_ptr_t { { "title_format_short", PTR_V_STR(uzbl.behave.title_format_short, 1, NULL)}, { "icon", PTR_V_STR(uzbl.gui.icon, 1, set_icon)}, { "forward_keys", PTR_V_INT(uzbl.behave.forward_keys, 1, NULL)}, - { "cookie_handler", PTR_V_STR(uzbl.behave.cookie_handler, 1, cmd_set_cookie_handler)}, { "authentication_handler", PTR_V_STR(uzbl.behave.authentication_handler, 1, set_authentication_handler)}, { "scheme_handler", PTR_V_STR(uzbl.behave.scheme_handler, 1, NULL)}, { "download_handler", PTR_V_STR(uzbl.behave.download_handler, 1, NULL)}, @@ -145,6 +145,7 @@ const struct var_name_to_ptr_t { { "SELECTED_URI", PTR_C_STR(uzbl.state.selected_url, NULL)}, { "NAME", PTR_C_STR(uzbl.state.instance_name, NULL)}, { "PID", PTR_C_STR(uzbl.info.pid_str, NULL)}, + { "_", PTR_C_STR(uzbl.state.last_result, NULL)}, { NULL, {.ptr.s = NULL, .type = TYPE_INT, .dump = 0, .writeable = 0, .func = NULL}} }; @@ -164,43 +165,39 @@ create_var_to_name_hash() { /* --- UTILITY FUNCTIONS --- */ -enum exp_type {EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE}; +enum exp_type { + EXP_ERR, EXP_SIMPLE_VAR, EXP_BRACED_VAR, EXP_EXPR, EXP_JS, EXP_ESCAPE +}; + enum exp_type get_exp_type(const gchar *s) { - /* variables */ - if(*(s+1) == '(') - return EXP_EXPR; - else if(*(s+1) == '{') - return EXP_BRACED_VAR; - else if(*(s+1) == '<') - return EXP_JS; - else if(*(s+1) == '[') - return EXP_ESCAPE; - else - return EXP_SIMPLE_VAR; - - /*@notreached@*/ -return EXP_ERR; + switch(*(s+1)) { + case '(': return EXP_EXPR; + case '{': return EXP_BRACED_VAR; + case '<': return EXP_JS; + case '[': return EXP_ESCAPE; + default: return EXP_SIMPLE_VAR; + } } /* * recurse == 1: don't expand '@(command)@' * recurse == 2: don't expand '@<java script>@' */ -gchar * -expand(const char *s, guint recurse) { - uzbl_cmdprop *c; +gchar* +expand(const char* s, guint recurse) { + uzbl_cmdprop* c; enum exp_type etype; - char *end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½"; - char *ret = NULL; - char *vend = NULL; - GError *err = NULL; - gchar *cmd_stdout = NULL; - gchar *mycmd = NULL; - GString *buf = g_string_new(""); - GString *js_ret = g_string_new(""); - - while(s && *s) { + char* end_simple_var = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½"; + char* ret = NULL; + char* vend = NULL; + GError* err = NULL; + gchar* cmd_stdout = NULL; + gchar* mycmd = NULL; + GString* buf = g_string_new(""); + GString* js_ret = g_string_new(""); + + while (s && *s) { switch(*s) { case '\\': g_string_append_c(buf, *++s); @@ -351,81 +348,15 @@ expand(const char *s, guint recurse) { return g_string_free(buf, FALSE); } -char * -itos(int val) { - char tmp[20]; - - snprintf(tmp, sizeof(tmp), "%i", val); - return g_strdup(tmp); -} - -gchar* -strfree(gchar *str) { - g_free(str); - return NULL; -} - -gchar* -argv_idx(const GArray *a, const guint idx) { return g_array_index(a, gchar*, idx); } - -/* search a PATH style string for an existing file+path combination */ -gchar* -find_existing_file(gchar* path_list) { - int i=0; - int cnt; - gchar **split; - gchar *tmp = NULL; - gchar *executable; - - if(!path_list) - return NULL; - - split = g_strsplit(path_list, ":", 0); - while(split[i]) - i++; - - if(i<=1) { - tmp = g_strdup(split[0]); - g_strfreev(split); - return tmp; - } - else - cnt = i-1; - - i=0; - tmp = g_strdup(split[cnt]); - g_strstrip(tmp); - if(tmp[0] == '/') - executable = g_strdup_printf("%s", tmp+1); - else - executable = g_strdup(tmp); - g_free(tmp); - - while(i<cnt) { - tmp = g_strconcat(g_strstrip(split[i]), "/", executable, NULL); - if(g_file_test(tmp, G_FILE_TEST_EXISTS)) { - g_strfreev(split); - return tmp; - } - else - g_free(tmp); - i++; - } - - g_free(executable); - g_strfreev(split); - return NULL; -} - void clean_up(void) { - if(uzbl.info.pid_str) { - send_event(INSTANCE_EXIT, uzbl.info.pid_str, NULL); + if (uzbl.info.pid_str) { + send_event (INSTANCE_EXIT, NULL, TYPE_INT, getpid(), NULL); g_free(uzbl.info.pid_str); uzbl.info.pid_str = NULL; } - if(uzbl.state.executable_path) { + if (uzbl.state.executable_path) { g_free(uzbl.state.executable_path); uzbl.state.executable_path = NULL; } @@ -435,7 +366,7 @@ clean_up(void) { uzbl.behave.commands = NULL; } - if(uzbl.state.event_buffer) { + if (uzbl.state.event_buffer) { g_ptr_array_free(uzbl.state.event_buffer, TRUE); uzbl.state.event_buffer = NULL; } @@ -495,7 +426,7 @@ empty_event_buffer(int s) { /* scroll a bar in a given direction */ void -scroll (GtkAdjustment* bar, gchar *amount_str) { +scroll(GtkAdjustment* bar, gchar *amount_str) { gchar *end; gdouble max_value; @@ -571,79 +502,79 @@ VIEWFUNC(go_forward) #undef VIEWFUNC /* -- command to callback/function map for things we cannot attach to any signals */ -struct {const char *key; CommandInfo value;} cmdlist[] = +CommandInfo cmdlist[] = { /* key function no_split */ - { "back", {view_go_back, 0} }, - { "forward", {view_go_forward, 0} }, - { "scroll", {scroll_cmd, 0} }, - { "reload", {view_reload, 0}, }, - { "reload_ign_cache", {view_reload_bypass_cache, 0} }, - { "stop", {view_stop_loading, 0}, }, - { "zoom_in", {view_zoom_in, 0}, }, //Can crash (when max zoom reached?). - { "zoom_out", {view_zoom_out, 0}, }, - { "toggle_zoom_type", {toggle_zoom_type, 0}, }, - { "uri", {load_uri, TRUE} }, - { "js", {run_js, TRUE} }, - { "script", {run_external_js, 0} }, - { "toggle_status", {toggle_status_cb, 0} }, - { "spawn", {spawn_async, 0} }, - { "sync_spawn", {spawn_sync, 0} }, // needed for cookie handler - { "sync_spawn_exec", {spawn_sync_exec, 0} }, // needed for load_cookies.sh :( - { "sh", {spawn_sh_async, 0} }, - { "sync_sh", {spawn_sh_sync, 0} }, // needed for cookie handler - { "exit", {close_uzbl, 0} }, - { "search", {search_forward_text, TRUE} }, - { "search_reverse", {search_reverse_text, TRUE} }, - { "search_clear", {search_clear, TRUE} }, - { "dehilight", {dehilight, 0} }, - { "set", {set_var, TRUE} }, - { "dump_config", {act_dump_config, 0} }, - { "dump_config_as_events", {act_dump_config_as_events, 0} }, - { "chain", {chain, 0} }, - { "print", {print, TRUE} }, - { "event", {event, TRUE} }, - { "request", {event, TRUE} }, - { "menu_add", {menu_add, TRUE} }, - { "menu_link_add", {menu_add_link, TRUE} }, - { "menu_image_add", {menu_add_image, TRUE} }, - { "menu_editable_add", {menu_add_edit, TRUE} }, - { "menu_separator", {menu_add_separator, TRUE} }, - { "menu_link_separator", {menu_add_separator_link, TRUE} }, - { "menu_image_separator", {menu_add_separator_image, TRUE}}, - { "menu_editable_separator", {menu_add_separator_edit, TRUE} }, - { "menu_remove", {menu_remove, TRUE} }, - { "menu_link_remove", {menu_remove_link, TRUE} }, - { "menu_image_remove", {menu_remove_image, TRUE} }, - { "menu_editable_remove", {menu_remove_edit, TRUE} }, - { "hardcopy", {hardcopy, TRUE} }, - { "include", {include, TRUE} }, - { "show_inspector", {show_inspector, 0} }, - { "add_cookie", {add_cookie, 0} }, - { "delete_cookie", {delete_cookie, 0} } + { "back", view_go_back, 0 }, + { "forward", view_go_forward, 0 }, + { "scroll", scroll_cmd, 0 }, + { "reload", view_reload, 0 }, + { "reload_ign_cache", view_reload_bypass_cache, 0 }, + { "stop", view_stop_loading, 0 }, + { "zoom_in", view_zoom_in, 0 }, //Can crash (when max zoom reached?). + { "zoom_out", view_zoom_out, 0 }, + { "toggle_zoom_type", toggle_zoom_type, 0 }, + { "uri", load_uri, TRUE }, + { "js", run_js, TRUE }, + { "script", run_external_js, 0 }, + { "toggle_status", toggle_status_cb, 0 }, + { "spawn", spawn_async, 0 }, + { "sync_spawn", spawn_sync, 0 }, + { "sync_spawn_exec", spawn_sync_exec, 0 }, // needed for load_cookies.sh :( + { "sh", spawn_sh_async, 0 }, + { "sync_sh", spawn_sh_sync, 0 }, + { "exit", close_uzbl, 0 }, + { "search", search_forward_text, TRUE }, + { "search_reverse", search_reverse_text, TRUE }, + { "search_clear", search_clear, TRUE }, + { "dehilight", dehilight, 0 }, + { "set", set_var, TRUE }, + { "dump_config", act_dump_config, 0 }, + { "dump_config_as_events", act_dump_config_as_events, 0 }, + { "chain", chain, 0 }, + { "print", print, TRUE }, + { "event", event, TRUE }, + { "request", event, TRUE }, + { "menu_add", menu_add, TRUE }, + { "menu_link_add", menu_add_link, TRUE }, + { "menu_image_add", menu_add_image, TRUE }, + { "menu_editable_add", menu_add_edit, TRUE }, + { "menu_separator", menu_add_separator, TRUE }, + { "menu_link_separator", menu_add_separator_link, TRUE }, + { "menu_image_separator", menu_add_separator_image, TRUE }, + { "menu_editable_separator", menu_add_separator_edit, TRUE }, + { "menu_remove", menu_remove, TRUE }, + { "menu_link_remove", menu_remove_link, TRUE }, + { "menu_image_remove", menu_remove_image, TRUE }, + { "menu_editable_remove", menu_remove_edit, TRUE }, + { "hardcopy", hardcopy, TRUE }, + { "include", include, TRUE }, + { "show_inspector", show_inspector, 0 }, + { "add_cookie", add_cookie, 0 }, + { "delete_cookie", delete_cookie, 0 } }; void -commands_hash(void) -{ +commands_hash(void) { unsigned int i; uzbl.behave.commands = g_hash_table_new(g_str_hash, g_str_equal); for (i = 0; i < LENGTH(cmdlist); i++) - g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i].value); + g_hash_table_insert(uzbl.behave.commands, (gpointer) cmdlist[i].key, &cmdlist[i]); } + void builtins() { - unsigned int i, - len = LENGTH(cmdlist); - GString *command_list = g_string_new(""); + unsigned int i; + unsigned int len = LENGTH(cmdlist); + GString* command_list = g_string_new(""); for (i = 0; i < len; i++) { g_string_append(command_list, cmdlist[i].key); g_string_append_c(command_list, ' '); } - send_event(BUILTINS, command_list->str, NULL); + send_event(BUILTINS, NULL, TYPE_STR, command_list->str, NULL); g_string_free(command_list, TRUE); } @@ -664,178 +595,6 @@ set_var(WebKitWebView *page, GArray *argv, GString *result) { g_strfreev(split); } -void -add_to_menu(GArray *argv, guint context) { - GUI *g = &uzbl.gui; - MenuItem *m; - gchar *item_cmd = NULL; - - if(!argv_idx(argv, 0)) - return; - - gchar **split = g_strsplit(argv_idx(argv, 0), "=", 2); - if(!g->menu_items) - g->menu_items = g_ptr_array_new(); - - if(split[1]) - item_cmd = split[1]; - - if(split[0]) { - m = malloc(sizeof(MenuItem)); - m->name = g_strdup(split[0]); - m->cmd = g_strdup(item_cmd?item_cmd:""); - m->context = context; - m->issep = FALSE; - g_ptr_array_add(g->menu_items, m); - } - - g_strfreev(split); -} - -void -menu_add(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); - -} - -void -menu_add_link(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); -} - -void -menu_add_image(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); -} - -void -menu_add_edit(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); -} - -void -add_separator_to_menu(GArray *argv, guint context) { - GUI *g = &uzbl.gui; - MenuItem *m; - gchar *sep_name; - - if(!g->menu_items) - g->menu_items = g_ptr_array_new(); - - if(!argv_idx(argv, 0)) - return; - else - sep_name = argv_idx(argv, 0); - - m = malloc(sizeof(MenuItem)); - m->name = g_strdup(sep_name); - m->cmd = NULL; - m->context = context; - m->issep = TRUE; - g_ptr_array_add(g->menu_items, m); -} - -void -menu_add_separator(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); -} - -void -menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); -} -void -menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); -} - -void -menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - add_separator_to_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); -} - -void -remove_from_menu(GArray *argv, guint context) { - GUI *g = &uzbl.gui; - MenuItem *mi; - gchar *name = NULL; - guint i=0; - - if(!g->menu_items) - return; - - if(!argv_idx(argv, 0)) - return; - else - name = argv_idx(argv, 0); - - for(i=0; i < g->menu_items->len; i++) { - mi = g_ptr_array_index(g->menu_items, i); - - if((context == mi->context) && !strcmp(name, mi->name)) { - g_free(mi->name); - g_free(mi->cmd); - g_free(mi); - g_ptr_array_remove_index(g->menu_items, i); - } - } -} - -void -menu_remove(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT); -} - -void -menu_remove_link(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK); -} - -void -menu_remove_image(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE); -} - -void -menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result) { - (void) page; - (void) result; - - remove_from_menu(argv, WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE); -} void event(WebKitWebView *page, GArray *argv, GString *result) { @@ -852,7 +611,7 @@ event(WebKitWebView *page, GArray *argv, GString *result) { else return; - send_event(0, split[1]?split[1]:"", event_name->str); + send_event(0, event_name->str, TYPE_FORMATTEDSTR, split[1] ? split[1] : "", NULL); g_string_free(event_name, TRUE); g_strfreev(split); @@ -863,6 +622,9 @@ print(WebKitWebView *page, GArray *argv, GString *result) { (void) page; (void) result; gchar* buf; + if(!result) + return; + buf = expand(argv_idx(argv, 0), 0); g_string_assign(result, buf); g_free(buf); @@ -895,11 +657,11 @@ include(WebKitWebView *page, GArray *argv, GString *result) { if((path = find_existing_file(path))) { if(!for_each_line_in_file(path, parse_cmd_line_cb, NULL)) { gchar *tmp = g_strdup_printf("File %s can not be read.", path); - send_event(COMMAND_ERROR, tmp, NULL); + send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL); g_free(tmp); } - send_event(FILE_INCLUDED, path, NULL); + send_event(FILE_INCLUDED, NULL, TYPE_STR, path, NULL); g_free(path); } } @@ -973,9 +735,10 @@ act_dump_config_as_events() { } void -load_uri (WebKitWebView *web_view, GArray *argv, GString *result) { +load_uri(WebKitWebView *web_view, GArray *argv, GString *result) { (void) web_view; (void) result; - set_var_value("uri", argv_idx(argv, 0)); + gchar * uri = argv_idx(argv, 0); + set_var_value("uri", uri ? uri : ""); } /* Javascript*/ @@ -1118,7 +881,8 @@ search_clear(WebKitWebView *page, GArray *argv, GString *result) { (void) result; webkit_web_view_unmark_text_matches (page); - uzbl.state.searchtx = strfree (uzbl.state.searchtx); + g_free(uzbl.state.searchtx); + uzbl.state.searchtx = NULL; } void @@ -1128,29 +892,34 @@ search_forward_text (WebKitWebView *page, GArray *argv, GString *result) { } void -search_reverse_text (WebKitWebView *page, GArray *argv, GString *result) { +search_reverse_text(WebKitWebView *page, GArray *argv, GString *result) { (void) result; search_text(page, argv, FALSE); } void -dehilight (WebKitWebView *page, GArray *argv, GString *result) { +dehilight(WebKitWebView *page, GArray *argv, GString *result) { (void) argv; (void) result; webkit_web_view_set_highlight_text_matches (page, FALSE); } void -chain (WebKitWebView *page, GArray *argv, GString *result) { - (void) page; (void) result; - gchar *a = NULL; - gchar **parts = NULL; +chain(WebKitWebView *page, GArray *argv, GString *result) { + (void) page; guint i = 0; - while ((a = argv_idx(argv, i++))) { - parts = g_strsplit (a, " ", 2); - if (parts[0]) - parse_command(parts[0], parts[1], result); - g_strfreev (parts); + const gchar *cmd; + GString *r = g_string_new (""); + while ((cmd = argv_idx(argv, i++))) { + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + const CommandInfo *c = parse_command_parts(cmd, a); + if (c) + run_parsed_command(c, a, r); + g_array_free (a, TRUE); } + if(result) + g_string_assign (result, r->str); + + g_string_free(r, TRUE); } void @@ -1184,7 +953,8 @@ run_command (const gchar *command, const gchar **args, const gboolean sync, gboolean result; if (sync) { - if (*output_stdout) *output_stdout = strfree(*output_stdout); + if (*output_stdout) + g_free(*output_stdout); result = g_spawn_sync(NULL, (gchar **)a->data, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, output_stdout, NULL, NULL, &err); @@ -1252,25 +1022,28 @@ split_quoted(const gchar* src, const gboolean unquote) { } void -spawn(GArray *argv, gboolean sync, gboolean exec) { +spawn(GArray *argv, GString *result, gboolean exec) { gchar *path = NULL; gchar *arg_car = argv_idx(argv, 0); const gchar **arg_cdr = &g_array_index(argv, const gchar *, 1); if (arg_car && (path = find_existing_file(arg_car))) { - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - run_command(path, arg_cdr, sync, sync?&uzbl.comm.sync_stdout:NULL); - // run each line of output from the program as a command - if (sync && exec && uzbl.comm.sync_stdout) { - gchar *head = uzbl.comm.sync_stdout; - gchar *tail; - while ((tail = strchr (head, '\n'))) { - *tail = '\0'; - parse_cmd_line(head, NULL); - head = tail + 1; + gchar *r = NULL; + run_command(path, arg_cdr, result != NULL, result ? &r : NULL); + if(result) { + g_string_assign(result, r); + // run each line of output from the program as a command + if (exec && r) { + gchar *head = r; + gchar *tail; + while ((tail = strchr (head, '\n'))) { + *tail = '\0'; + parse_cmd_line(head, NULL); + head = tail + 1; + } } } + g_free(r); g_free(path); } } @@ -1278,23 +1051,28 @@ spawn(GArray *argv, gboolean sync, gboolean exec) { void spawn_async(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - spawn(argv, FALSE, FALSE); + spawn(argv, NULL, FALSE); } void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - spawn(argv, TRUE, FALSE); + (void)web_view; + spawn(argv, result, FALSE); } void spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result) { - (void)web_view; (void)result; - spawn(argv, TRUE, TRUE); + (void)web_view; + if(!result) { + GString *force_result = g_string_new(""); + spawn(argv, force_result, TRUE); + g_string_free (force_result, TRUE); + } else + spawn(argv, result, TRUE); } void -spawn_sh(GArray *argv, gboolean sync) { +spawn_sh(GArray *argv, GString *result) { if (!uzbl.behave.shell_cmd) { g_printerr ("spawn_sh: shell_cmd is not set!\n"); return; @@ -1302,19 +1080,23 @@ spawn_sh(GArray *argv, gboolean sync) { guint i; gchar **cmd = split_quoted(uzbl.behave.shell_cmd, TRUE); + if(!cmd) + return; + gchar *cmdname = g_strdup(cmd[0]); g_array_insert_val(argv, 1, cmdname); for (i = 1; i < g_strv_length(cmd); i++) g_array_prepend_val(argv, cmd[i]); - if (cmd) { - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); + if (result) { + gchar *r = NULL; + run_command(cmd[0], (const gchar **) argv->data, TRUE, &r); + g_string_assign(result, r); + g_free(r); + } else + run_command(cmd[0], (const gchar **) argv->data, FALSE, NULL); - run_command(cmd[0], (const gchar **) argv->data, - sync, sync?&uzbl.comm.sync_stdout:NULL); - } g_free (cmdname); g_strfreev (cmd); } @@ -1322,58 +1104,108 @@ spawn_sh(GArray *argv, gboolean sync) { void spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - spawn_sh(argv, FALSE); + spawn_sh(argv, NULL); } void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result) { (void)web_view; (void)result; - spawn_sh(argv, TRUE); + spawn_sh(argv, result); } void -parse_command(const char *cmd, const char *param, GString *result) { - CommandInfo *c; - GString *tmp = g_string_new(""); +run_parsed_command(const CommandInfo *c, GArray *a, GString *result) { + c->function(uzbl.gui.web_view, a, result); - if ((c = g_hash_table_lookup(uzbl.behave.commands, cmd))) { - guint i; - gchar **par = split_quoted(param, TRUE); - GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + /* send the COMMAND_EXECUTED event, except for set and event/request commands */ + if(strcmp("set", c->key) && + strcmp("event", c->key) && + strcmp("request", c->key)) { + // FIXME, build string inside send_event + GString *param = g_string_new(""); + const gchar *p; + guint i = 0; + while ((p = argv_idx(a, i++))) + g_string_append_printf(param, " '%s'", p); + send_event(COMMAND_EXECUTED, NULL, + TYPE_NAME, c->key, + TYPE_FORMATTEDSTR, param->str, + NULL); + g_string_free(param, TRUE); + } - if (c->no_split) { /* don't split */ - sharg_append(a, param); - } else if (par) { - for (i = 0; i < g_strv_length(par); i++) - sharg_append(a, par[i]); - } + if(result) { + g_free(uzbl.state.last_result); + uzbl.state.last_result = g_strdup(result->str); + } +} + +void +parse_command_arguments(const gchar *p, GArray *a, gboolean no_split) { + if (no_split && p) { /* pass the parameters through in one chunk */ + sharg_append(a, g_strdup(p)); + return; + } + + gchar **par = split_quoted(p, TRUE); + if (par) { + guint i; + for (i = 0; i < g_strv_length(par); i++) + sharg_append(a, g_strdup(par[i])); + g_strfreev (par); + } +} - if (result == NULL) { - GString *result_print = g_string_new(""); +const CommandInfo * +parse_command_parts(const gchar *line, GArray *a) { + CommandInfo *c = NULL; - c->function(uzbl.gui.web_view, a, result_print); - if (result_print->len) - printf("%*s\n", (int)result_print->len, result_print->str); + gchar *exp_line = expand(line, 0); + if(exp_line[0] == '\0') + return NULL; - g_string_free(result_print, TRUE); - } else { - c->function(uzbl.gui.web_view, a, result); - } - g_strfreev (par); - g_array_free (a, TRUE); + /* separate the line into the command and its parameters */ + gchar **tokens = g_strsplit(exp_line, " ", 2); - if(strcmp("set", cmd) && - strcmp("event", cmd) && - strcmp("request", cmd)) { - g_string_printf(tmp, "%s %s", cmd, param?param:""); - send_event(COMMAND_EXECUTED, tmp->str, NULL); - } + /* look up the command */ + c = g_hash_table_lookup(uzbl.behave.commands, tokens[0]); + + if(!c) { + send_event(COMMAND_ERROR, NULL, + TYPE_STR, exp_line, + NULL); + g_free(exp_line); + g_strfreev(tokens); + return NULL; } - else { - g_string_printf (tmp, "%s %s", cmd, param?param:""); - send_event(COMMAND_ERROR, tmp->str, NULL); + + gchar *p = g_strdup(tokens[1]); + g_free(exp_line); + g_strfreev(tokens); + + /* parse the arguments */ + parse_command_arguments(p, a, c->no_split); + g_free(p); + + return c; +} + +void +parse_command(const char *cmd, const char *params, GString *result) { + CommandInfo *c = g_hash_table_lookup(uzbl.behave.commands, cmd); + if(c) { + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + + parse_command_arguments(params, a, c->no_split); + run_parsed_command(c, a, result); + + g_array_free (a, TRUE); + } else { + send_event(COMMAND_ERROR, NULL, + TYPE_NAME, cmd, + TYPE_STR, params ? params : "", + NULL); } - g_string_free(tmp, TRUE); } @@ -1404,42 +1236,75 @@ move_statusbar() { } gboolean +valid_name(const gchar* name) { + char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½"; + return strpbrk(name, invalid_chars) == NULL; +} + +void +send_set_var_event(const char *name, const uzbl_cmdprop *c) { + /* check for the variable type */ + switch(c->type) { + case TYPE_STR: + send_event (VARIABLE_SET, NULL, + TYPE_NAME, name, + TYPE_NAME, "str", + TYPE_STR, *c->ptr.s ? *c->ptr.s : " ", + NULL); + break; + case TYPE_INT: + send_event (VARIABLE_SET, NULL, + TYPE_NAME, name, + TYPE_NAME, "int", + TYPE_INT, *c->ptr.i, + NULL); + break; + case TYPE_FLOAT: + send_event (VARIABLE_SET, NULL, + TYPE_NAME, name, + TYPE_NAME, "float", + TYPE_FLOAT, *c->ptr.f, + NULL); + break; + default: + g_assert_not_reached(); + } +} + +gboolean set_var_value(const gchar *name, gchar *val) { uzbl_cmdprop *c = NULL; char *endp = NULL; char *buf = NULL; - char *invalid_chars = "\t^°!\"§$%&/()=?'`'+~*'#-:,;@<>| \\{}[]¹²³¼½"; - GString *msg; + + g_assert(val != NULL); if( (c = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) { if(!c->writeable) return FALSE; - msg = g_string_new(name); - - /* check for the variable type */ - if (c->type == TYPE_STR) { + switch(c->type) { + case TYPE_STR: buf = g_strdup(val); g_free(*c->ptr.s); *c->ptr.s = buf; - g_string_append_printf(msg, " str %s", buf); - - } else if(c->type == TYPE_INT) { + break; + case TYPE_INT: *c->ptr.i = (int)strtoul(val, &endp, 10); - g_string_append_printf(msg, " int %d", *c->ptr.i); - - } else if (c->type == TYPE_FLOAT) { + break; + case TYPE_FLOAT: *c->ptr.f = strtod(val, &endp); - g_string_append_printf(msg, " float %f", *c->ptr.f); + break; + default: + g_assert_not_reached(); } - send_event(VARIABLE_SET, msg->str, NULL); - g_string_free(msg,TRUE); + send_set_var_event(name, c); /* invoke a command specific function */ if(c->func) c->func(); } else { /* check wether name violates our naming scheme */ - if(strpbrk(name, invalid_chars)) { + if(!valid_name(name)) { if (uzbl.state.verbose) printf("Invalid variable name: %s\n", name); return FALSE; @@ -1457,10 +1322,11 @@ set_var_value(const gchar *name, gchar *val) { g_hash_table_insert(uzbl.comm.proto_var, g_strdup(name), (gpointer) c); - msg = g_string_new(name); - g_string_append_printf(msg, " str %s", buf); - send_event(VARIABLE_SET, msg->str, NULL); - g_string_free(msg,TRUE); + send_event (VARIABLE_SET, NULL, + TYPE_NAME, name, + TYPE_NAME, "str", + TYPE_STR, buf, + NULL); } update_title(); return TRUE; @@ -1468,376 +1334,26 @@ set_var_value(const gchar *name, gchar *val) { void parse_cmd_line(const char *ctl_line, GString *result) { - size_t len=0; - gchar *ctlstrip = NULL; - gchar *exp_line = NULL; - gchar *work_string = NULL; + gchar *work_string = g_strdup(ctl_line); - work_string = g_strdup(ctl_line); + /* strip trailing newline, and any other whitespace in front */ + g_strstrip(work_string); - /* strip trailing newline */ - len = strlen(ctl_line); - if (work_string[len - 1] == '\n') - ctlstrip = g_strndup(work_string, len - 1); - else - ctlstrip = g_strdup(work_string); - g_free(work_string); - - if( strcmp(g_strchug(ctlstrip), "") && - strcmp(exp_line = expand(ctlstrip, 0), "") - ) { - /* ignore comments */ - if((exp_line[0] == '#')) - ; - - /* parse a command */ - else { - gchar **tokens = NULL; - - tokens = g_strsplit(exp_line, " ", 2); - parse_command(tokens[0], tokens[1], result); - g_strfreev(tokens); - } - g_free(exp_line); - } - - g_free(ctlstrip); -} - -/*@null@*/ gchar* -build_stream_name(int type, const gchar* dir) { - State *s = &uzbl.state; - gchar *str = NULL; - - if (type == FIFO) { - str = g_strdup_printf - ("%s/uzbl_fifo_%s", dir, s->instance_name); - } else if (type == SOCKET) { - str = g_strdup_printf - ("%s/uzbl_socket_%s", dir, s->instance_name); - } - return str; -} - -gboolean -control_fifo(GIOChannel *gio, GIOCondition condition) { - if (uzbl.state.verbose) - printf("triggered\n"); - gchar *ctl_line; - GIOStatus ret; - GError *err = NULL; - - if (condition & G_IO_HUP) - g_error ("Fifo: Read end of pipe died!\n"); - - if(!gio) - g_error ("Fifo: GIOChannel broke\n"); - - 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); - g_error_free (err); - } - - parse_cmd_line(ctl_line, NULL); - g_free(ctl_line); - - return TRUE; -} - -gboolean -attach_fifo(gchar *path) { - GError *error = NULL; - /* 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. */ - GIOChannel *chan = g_io_channel_new_file(path, "r+", &error); - if (chan) { - if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) { - if (uzbl.state.verbose) - printf ("attach_fifo: created successfully as %s\n", path); - send_event(FIFO_SET, path, NULL); - uzbl.comm.fifo_path = path; - g_setenv("UZBL_FIFO", uzbl.comm.fifo_path, TRUE); - return TRUE; - } else g_warning ("attach_fifo: could not add watch on %s\n", path); - } else g_warning ("attach_fifo: can't open: %s\n", error->message); - - if (error) g_error_free (error); - return FALSE; -} - -/*@null@*/ gchar* -init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */ - if (uzbl.comm.fifo_path) { /* get rid of the old fifo if one exists */ - if (unlink(uzbl.comm.fifo_path) == -1) - g_warning ("Fifo: Can't unlink old fifo at %s\n", uzbl.comm.fifo_path); - g_free(uzbl.comm.fifo_path); - uzbl.comm.fifo_path = NULL; - } - - gchar *path = build_stream_name(FIFO, dir); - - if (!file_exists(path)) { - if (mkfifo (path, 0666) == 0 && attach_fifo(path)) { - return dir; - } else g_warning ("init_fifo: can't create %s: %s\n", path, strerror(errno)); - } else { - /* the fifo exists. but is anybody home? */ - int fd = open(path, O_WRONLY|O_NONBLOCK); - if(fd < 0) { - /* some error occurred, presumably nobody's on the read end. - * we can attach ourselves to it. */ - if(attach_fifo(path)) - return dir; - else - g_warning("init_fifo: can't attach to %s: %s\n", path, strerror(errno)); - } else { - /* somebody's there, we can't use that fifo. */ - close(fd); - /* whatever, this instance can live without a fifo. */ - g_warning ("init_fifo: can't create %s: file exists and is occupied\n", path); - } - } - - /* if we got this far, there was an error; cleanup */ - g_free(dir); - g_free(path); - return NULL; -} - -gboolean -control_stdin(GIOChannel *gio, GIOCondition condition) { - (void) condition; - gchar *ctl_line = NULL; - GIOStatus ret; - - ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL); - if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) ) - return FALSE; - - parse_cmd_line(ctl_line, NULL); - g_free(ctl_line); - - return TRUE; -} - -void -create_stdin () { - GIOChannel *chan = NULL; - GError *error = NULL; - - chan = g_io_channel_unix_new(fileno(stdin)); - if (chan) { - if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) { - g_error ("Stdin: could not add watch\n"); - } else { - if (uzbl.state.verbose) - printf ("Stdin: watch added successfully\n"); - } - } else { - g_error ("Stdin: Error while opening: %s\n", error->message); - } - if (error) g_error_free (error); -} - -gboolean -remove_socket_from_array(GIOChannel *chan) { - gboolean ret = 0; - - ret = g_ptr_array_remove_fast(uzbl.comm.connect_chan, chan); - if(!ret) - ret = g_ptr_array_remove_fast(uzbl.comm.client_chan, chan); - - if(ret) - g_io_channel_unref (chan); - return ret; -} - -gboolean -control_socket(GIOChannel *chan) { - struct sockaddr_un remote; - unsigned int t = sizeof(remote); - GIOChannel *iochan; - int clientsock; - - clientsock = accept (g_io_channel_unix_get_fd(chan), - (struct sockaddr *) &remote, &t); - - if(!uzbl.comm.client_chan) - uzbl.comm.client_chan = g_ptr_array_new(); - - if ((iochan = g_io_channel_unix_new(clientsock))) { - g_io_channel_set_encoding(iochan, NULL, NULL); - g_io_add_watch(iochan, G_IO_IN|G_IO_HUP, - (GIOFunc) control_client_socket, iochan); - g_ptr_array_add(uzbl.comm.client_chan, (gpointer)iochan); - } - return TRUE; -} - -void -init_connect_socket() { - int sockfd, replay = 0; - struct sockaddr_un local; - GIOChannel *chan; - gchar **name = NULL; - - if(!uzbl.comm.connect_chan) - uzbl.comm.connect_chan = g_ptr_array_new(); - - name = uzbl.state.connect_socket_names; - - while(name && *name) { - sockfd = socket (AF_UNIX, SOCK_STREAM, 0); - local.sun_family = AF_UNIX; - strcpy (local.sun_path, *name); - - if(!connect(sockfd, (struct sockaddr *) &local, sizeof(local))) { - if ((chan = g_io_channel_unix_new(sockfd))) { - g_io_channel_set_encoding(chan, NULL, NULL); - g_io_add_watch(chan, G_IO_IN|G_IO_HUP, - (GIOFunc) control_client_socket, chan); - g_ptr_array_add(uzbl.comm.connect_chan, (gpointer)chan); - replay++; - } - } - else - g_warning("Error connecting to socket: %s\n", *name); - name++; - } - - /* replay buffered events */ - if(replay) - send_event_socket(NULL); -} - -gboolean -control_client_socket(GIOChannel *clientchan) { - char *ctl_line; - GString *result = g_string_new(""); - GError *error = NULL; - GIOStatus ret; - gsize len; - - ret = g_io_channel_read_line(clientchan, &ctl_line, &len, NULL, &error); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error reading: %s", error->message); - g_clear_error (&error); - ret = g_io_channel_shutdown (clientchan, TRUE, &error); - remove_socket_from_array (clientchan); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error closing: %s", error->message); - g_clear_error (&error); - } - return FALSE; - } else if (ret == G_IO_STATUS_EOF) { - /* shutdown and remove channel watch from main loop */ - ret = g_io_channel_shutdown (clientchan, TRUE, &error); - remove_socket_from_array (clientchan); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error closing: %s", error->message); - g_clear_error (&error); - } - return FALSE; - } - - if (ctl_line) { - parse_cmd_line (ctl_line, result); - g_string_append_c(result, '\n'); - ret = g_io_channel_write_chars (clientchan, result->str, result->len, - &len, &error); - if (ret == G_IO_STATUS_ERROR) { - g_warning ("Error writing: %s", error->message); - g_clear_error (&error); - } - if (g_io_channel_flush(clientchan, &error) == G_IO_STATUS_ERROR) { - g_warning ("Error flushing: %s", error->message); - g_clear_error (&error); - } - } - - g_string_free(result, TRUE); - g_free(ctl_line); - return TRUE; -} - - -gboolean -attach_socket(gchar *path, struct sockaddr_un *local) { - GIOChannel *chan = NULL; - int sock = socket (AF_UNIX, SOCK_STREAM, 0); - - if (bind (sock, (struct sockaddr *) local, sizeof(*local)) != -1) { - if (uzbl.state.verbose) - printf ("init_socket: opened in %s\n", path); - - if(listen (sock, 5) < 0) - g_warning ("attach_socket: could not listen on %s: %s\n", path, strerror(errno)); - - if( (chan = g_io_channel_unix_new(sock)) ) { - g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_socket, chan); - uzbl.comm.socket_path = path; - send_event(SOCKET_SET, path, NULL); - g_setenv("UZBL_SOCKET", uzbl.comm.socket_path, TRUE); - return TRUE; - } - } else g_warning ("attach_socket: could not bind to %s: %s\n", path, strerror(errno)); - - return FALSE; -} - - -/*@null@*/ gchar* -init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL */ - if (uzbl.comm.socket_path) { /* remove an existing socket should one exist */ - if (unlink(uzbl.comm.socket_path) == -1) - g_warning ("init_socket: couldn't unlink socket at %s\n", uzbl.comm.socket_path); - g_free(uzbl.comm.socket_path); - uzbl.comm.socket_path = NULL; - } - - if (*dir == ' ') { - g_free(dir); - return NULL; - } - - struct sockaddr_un local; - gchar *path = build_stream_name(SOCKET, dir); - - local.sun_family = AF_UNIX; - strcpy (local.sun_path, path); - - if(!file_exists(path) && attach_socket(path, &local)) { - /* it's free for the taking. */ - return dir; - } else { - /* see if anybody's listening on the socket path we want. */ - int sock = socket (AF_UNIX, SOCK_STREAM, 0); - if(connect(sock, (struct sockaddr *) &local, sizeof(local)) < 0) { - /* some error occurred, presumably nobody's listening. - * we can attach ourselves to it. */ - unlink(path); - if(attach_socket(path, &local)) - return dir; - else - g_warning("init_socket: can't attach to existing socket %s: %s\n", path, strerror(errno)); - } else { - /* somebody's there, we can't use that socket path. */ - close(sock); - /* whatever, this instance can live without a socket. */ - g_warning ("init_socket: can't create %s: socket exists and is occupied\n", path); + if( strcmp(work_string, "") ) { + if((work_string[0] != '#')) { /* ignore comments */ + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + const CommandInfo *c = parse_command_parts(work_string, a); + if(c) + run_parsed_command(c, a, result); + g_array_free (a, TRUE); } } - /* if we got this far, there was an error; cleanup */ - g_free(path); - g_free(dir); - return NULL; + g_free(work_string); } void -update_title (void) { +update_title(void) { Behaviour *b = &uzbl.behave; const gchar *title_format = b->title_format_long; @@ -1875,11 +1391,24 @@ update_title (void) { } } + void -create_browser () { - GUI *g = &uzbl.gui; +create_scrolled_win() { + GUI* g = &uzbl.gui; + + g->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new()); + g->scrolled_win = gtk_scrolled_window_new(NULL, NULL); - g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); + gtk_scrolled_window_set_policy( + GTK_SCROLLED_WINDOW(g->scrolled_win), + GTK_POLICY_NEVER, + GTK_POLICY_NEVER + ); + + gtk_container_add( + GTK_CONTAINER(g->scrolled_win), + GTK_WIDGET(g->web_view) + ); g_object_connect((GObject*)g->web_view, "signal::key-press-event", (GCallback)key_press_cb, NULL, @@ -1905,8 +1434,9 @@ create_browser () { NULL); } + GtkWidget* -create_mainbar () { +create_mainbar() { GUI *g = &uzbl.gui; g->mainbar = gtk_hbox_new (FALSE, 0); @@ -1938,11 +1468,12 @@ create_mainbar () { GtkWidget* -create_window () { +create_window() { GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); gtk_widget_set_name (window, "Uzbl browser"); + gtk_window_set_title(GTK_WINDOW(window), "Uzbl browser"); /* if the window has been made small, it shouldn't try to resize itself due * to a long statusbar. */ @@ -1957,8 +1488,9 @@ create_window () { return window; } + GtkPlug* -create_plug () { +create_plug() { GtkPlug* plug = GTK_PLUG (gtk_plug_new (uzbl.state.socket_id)); g_signal_connect (G_OBJECT (plug), "destroy", G_CALLBACK (destroy_cb), NULL); g_signal_connect (G_OBJECT (plug), "key-press-event", G_CALLBACK (key_press_cb), NULL); @@ -1967,132 +1499,13 @@ create_plug () { return plug; } - -gchar** -inject_handler_args(const gchar *actname, const gchar *origargs, const gchar *newargs) { - /* - If actname is one that calls an external command, this function will inject - newargs in front of the user-provided args in that command line. They will - come become after the body of the script (in sh) or after the name of - the command to execute (in spawn). - i.e. sh <body> <userargs> becomes sh <body> <ARGS> <userargs> and - spawn <command> <userargs> becomes spawn <command> <ARGS> <userargs>. - - The return value consist of two strings: the action (sh, ...) and its args. - - If act is not one that calls an external command, then the given action merely - gets duplicated. - */ - GArray *rets = g_array_new(TRUE, FALSE, sizeof(gchar*)); - /* Arrr! Here be memory leaks */ - gchar *actdup = g_strdup(actname); - g_array_append_val(rets, actdup); - - if ((g_strcmp0(actname, "spawn") == 0) || - (g_strcmp0(actname, "sh") == 0) || - (g_strcmp0(actname, "sync_spawn") == 0) || - (g_strcmp0(actname, "sync_sh") == 0)) { - guint i; - GString *a = g_string_new(""); - gchar **spawnparts = split_quoted(origargs, FALSE); - g_string_append_printf(a, "%s", spawnparts[0]); /* sh body or script name */ - if (newargs) g_string_append_printf(a, " %s", newargs); /* handler args */ - - for (i = 1; i < g_strv_length(spawnparts); i++) /* user args */ - if (spawnparts[i]) g_string_append_printf(a, " %s", spawnparts[i]); - - g_array_append_val(rets, a->str); - g_string_free(a, FALSE); - g_strfreev(spawnparts); - } else { - gchar *origdup = g_strdup(origargs); - g_array_append_val(rets, origdup); - } - return (gchar**)g_array_free(rets, FALSE); -} - -void -run_handler (const gchar *act, const gchar *args) { - /* Consider this code a temporary hack to make the handlers usable. - In practice, all this splicing, injection, and reconstruction is - inefficient, annoying and hard to manage. Potential pitfalls arise - when the handler specific args 1) are not quoted (the handler - callbacks should take care of this) 2) are quoted but interfere - with the users' own quotation. A more ideal solution is - to refactor parse_command so that it doesn't just take a string - and execute it; rather than that, we should have a function which - returns the argument vector parsed from the string. This vector - could be modified (e.g. insert additional args into it) before - passing it to the next function that actually executes it. Though - it still isn't perfect for chain actions.. will reconsider & re- - factor when I have the time. -duc */ - - if (!act) return; - char **parts = g_strsplit(act, " ", 2); - if (!parts || !parts[0]) return; - if (g_strcmp0(parts[0], "chain") == 0) { - GString *newargs = g_string_new(""); - gchar **chainparts = split_quoted(parts[1], FALSE); - - /* for every argument in the chain, inject the handler args - and make sure the new parts are wrapped in quotes */ - gchar **cp = chainparts; - gchar quot = '\''; - gchar *quotless = NULL; - gchar **spliced_quotless = NULL; // sigh -_-; - gchar **inpart = NULL; - - while (*cp) { - if ((**cp == '\'') || (**cp == '\"')) { /* strip old quotes */ - quot = **cp; - quotless = g_strndup(&(*cp)[1], strlen(*cp) - 2); - } else quotless = g_strdup(*cp); - - spliced_quotless = g_strsplit(quotless, " ", 2); - inpart = inject_handler_args(spliced_quotless[0], spliced_quotless[1], args); - g_strfreev(spliced_quotless); - - g_string_append_printf(newargs, " %c%s %s%c", quot, inpart[0], inpart[1], quot); - g_free(quotless); - g_strfreev(inpart); - cp++; - } - - parse_command(parts[0], &(newargs->str[1]), NULL); - g_string_free(newargs, TRUE); - g_strfreev(chainparts); - - } else { - gchar **inparts; - gchar *inparts_[2]; - if (parts[1]) { - /* expand the user-specified arguments */ - gchar* expanded = expand(parts[1], 0); - inparts = inject_handler_args(parts[0], expanded, args); - g_free(expanded); - } else { - inparts_[0] = parts[0]; - inparts_[1] = g_strdup(args); - inparts = inparts_; - } - - parse_command(inparts[0], inparts[1], NULL); - - if (inparts != inparts_) { - g_free(inparts[0]); - g_free(inparts[1]); - } else - g_free(inparts[1]); - } - g_strfreev(parts); -} - void settings_init () { - State *s = &uzbl.state; - Network *n = &uzbl.net; - - int i; + State* s = &uzbl.state; + Network* n = &uzbl.net; + int i; + + /* Load default config */ for (i = 0; default_config[i].command != NULL; i++) { parse_cmd_line(default_config[i].command, NULL); } @@ -2103,56 +1516,59 @@ settings_init () { } else if (!s->config_file) { - s->config_file = find_xdg_file (0, "/uzbl/config"); + s->config_file = find_xdg_file(0, "/uzbl/config"); } + /* Load config file, if any */ if (s->config_file) { - if(!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) { + if (!for_each_line_in_file(s->config_file, parse_cmd_line_cb, NULL)) { gchar *tmp = g_strdup_printf("File %s can not be read.", s->config_file); - send_event(COMMAND_ERROR, tmp, NULL); + send_event(COMMAND_ERROR, NULL, TYPE_STR, tmp, NULL); g_free(tmp); } g_setenv("UZBL_CONFIG", s->config_file, TRUE); } else if (uzbl.state.verbose) printf ("No configuration file loaded.\n"); - if(s->connect_socket_names) + if (s->connect_socket_names) init_connect_socket(); g_signal_connect(n->soup_session, "authenticate", G_CALLBACK(handle_authentication), NULL); } -void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data) { +void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data) { (void) user_data; - if(uzbl.behave.authentication_handler && *uzbl.behave.authentication_handler != 0) { - gchar *info, *host, *realm; - gchar *p; - + if (uzbl.behave.authentication_handler && *uzbl.behave.authentication_handler != 0) { soup_session_pause_message(session, msg); - /* Sanitize strings */ - info = g_strdup(soup_auth_get_info(auth)); - host = g_strdup(soup_auth_get_host(auth)); - realm = g_strdup(soup_auth_get_realm(auth)); - for (p = info; *p; p++) if (*p == '\'') *p = '\"'; - for (p = host; *p; p++) if (*p == '\'') *p = '\"'; - for (p = realm; *p; p++) if (*p == '\'') *p = '\"'; + GString *result = g_string_new (""); - GString *s = g_string_new (""); - g_string_printf(s, "'%s' '%s' '%s' '%s'", - info, host, realm, retrying?"TRUE":"FALSE"); + gchar *info = g_strdup(soup_auth_get_info(auth)); + gchar *host = g_strdup(soup_auth_get_host(auth)); + gchar *realm = g_strdup(soup_auth_get_realm(auth)); - run_handler(uzbl.behave.authentication_handler, s->str); + GArray *a = g_array_new (TRUE, FALSE, sizeof(gchar*)); + const CommandInfo *c = parse_command_parts(uzbl.behave.authentication_handler, a); + if(c) { + sharg_append(a, info); + sharg_append(a, host); + sharg_append(a, realm); + sharg_append(a, retrying ? "TRUE" : "FALSE"); - if (uzbl.comm.sync_stdout && strcmp (uzbl.comm.sync_stdout, "") != 0) { + run_parsed_command(c, a, result); + } + g_array_free(a, TRUE); + + if (result->len > 0) { char *username, *password; int number_of_endls=0; - username = uzbl.comm.sync_stdout; + username = result->str; - for (p = uzbl.comm.sync_stdout; *p; p++) { + gchar *p; + for (p = result->str; *p; p++) { if (*p == '\n') { *p = '\0'; if (++number_of_endls == 1) @@ -2166,12 +1582,9 @@ void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *au soup_auth_authenticate(auth, username, password); } - if (uzbl.comm.sync_stdout) - uzbl.comm.sync_stdout = strfree(uzbl.comm.sync_stdout); - soup_session_unpause_message(session, msg); - g_string_free(s, TRUE); + g_string_free(result, TRUE); g_free(info); g_free(host); g_free(realm); @@ -2203,23 +1616,9 @@ void dump_var_hash_as_event(gpointer k, gpointer v, gpointer ud) { (void) ud; uzbl_cmdprop *c = v; - GString *msg; - - if(!c->dump) - return; - - /* check for the variable type */ - msg = g_string_new((char *)k); - if (c->type == TYPE_STR) { - g_string_append_printf(msg, " str %s", *c->ptr.s ? *c->ptr.s : " "); - } else if(c->type == TYPE_INT) { - g_string_append_printf(msg, " int %d", *c->ptr.i); - } else if (c->type == TYPE_FLOAT) { - g_string_append_printf(msg, " float %f", *c->ptr.f); - } - send_event(VARIABLE_SET, msg->str, NULL); - g_string_free(msg, TRUE); + if(c->dump) + send_set_var_event(k, c); } void @@ -2263,62 +1662,76 @@ set_webview_scroll_adjustments() { NULL); } -/* set up gtk, gobject, variable defaults and other things that tests and other + +/* Set up gtk, gobject, variable defaults and other things that tests and other * external applications need to do anyhow */ void -initialize(int argc, char *argv[]) { - int i; +initialize(int argc, char** argv) { + /* Initialize variables */ + uzbl.state.socket_id = 0; + uzbl.state.plug_mode = FALSE; - for(i=0; i<argc; ++i) { - if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--socket")) { - uzbl.state.plug_mode = TRUE; - break; - } - } + uzbl.state.executable_path = g_strdup(argv[0]); + uzbl.state.selected_url = NULL; + uzbl.state.searchtx = NULL; - if (!g_thread_supported ()) - g_thread_init (NULL); - gtk_init (&argc, &argv); + uzbl.info.webkit_major = webkit_major_version(); + uzbl.info.webkit_minor = webkit_minor_version(); + uzbl.info.webkit_micro = webkit_micro_version(); + uzbl.info.arch = ARCH; + uzbl.info.commit = COMMIT; - uzbl.state.executable_path = g_strdup(argv[0]); - uzbl.state.selected_url = NULL; - uzbl.state.searchtx = NULL; + uzbl.state.last_result = NULL; + /* Parse commandline arguments */ GOptionContext* context = g_option_context_new ("[ uri ] - load a uri by default"); - g_option_context_add_main_entries (context, entries, NULL); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - g_option_context_parse (context, &argc, &argv, NULL); + g_option_context_add_main_entries(context, entries, NULL); + g_option_context_add_group(context, gtk_get_option_group (TRUE)); + g_option_context_parse(context, &argc, &argv, NULL); g_option_context_free(context); + /* Only print version */ if (uzbl.behave.print_version) { printf("Commit: %s\n", COMMIT); exit(EXIT_SUCCESS); } - uzbl.net.soup_session = webkit_get_default_session(); + /* Embedded mode */ + if (uzbl.state.socket_id) + uzbl.state.plug_mode = TRUE; + + if (!g_thread_supported()) + g_thread_init(NULL); - uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new(); - soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar)); /* TODO: move the handler setup to event_buffer_timeout and disarm the * handler in empty_event_buffer? */ - if(setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR) + if (setup_signal(SIGALRM, empty_event_buffer) == SIG_ERR) fprintf(stderr, "uzbl: error hooking %d: %s\n", SIGALRM, strerror(errno)); event_buffer_timeout(10); - uzbl.info.webkit_major = webkit_major_version(); - uzbl.info.webkit_minor = webkit_minor_version(); - uzbl.info.webkit_micro = webkit_micro_version(); - uzbl.info.arch = ARCH; - uzbl.info.commit = COMMIT; + + /* HTTP client */ + uzbl.net.soup_session = webkit_get_default_session(); + uzbl.net.soup_cookie_jar = uzbl_cookie_jar_new(); - commands_hash (); + soup_session_add_feature(uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_cookie_jar)); + + + commands_hash(); create_var_to_name_hash(); + /* GUI */ + gtk_init(&argc, &argv); create_mainbar(); - create_browser(); + create_scrolled_win(); + + uzbl.gui.vbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); } + void load_uri_imp(gchar *uri) { GString* newuri; @@ -2368,21 +1781,9 @@ int main (int argc, char* argv[]) { initialize(argc, argv); - uzbl.gui.scrolled_win = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (uzbl.gui.scrolled_win), - GTK_POLICY_NEVER, GTK_POLICY_NEVER); - - gtk_container_add (GTK_CONTAINER (uzbl.gui.scrolled_win), - GTK_WIDGET (uzbl.gui.web_view)); - - uzbl.gui.vbox = gtk_vbox_new (FALSE, 0); - - /* initial packing */ - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.scrolled_win, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (uzbl.gui.vbox), uzbl.gui.mainbar, FALSE, TRUE, 0); - + /* Embedded mode */ if (uzbl.state.plug_mode) { - uzbl.gui.plug = create_plug (); + uzbl.gui.plug = create_plug(); gtk_container_add (GTK_CONTAINER (uzbl.gui.plug), uzbl.gui.vbox); gtk_widget_show_all (GTK_WIDGET (uzbl.gui.plug)); /* in xembed mode the window has no unique id and thus @@ -2393,13 +1794,20 @@ main (int argc, char* argv[]) { gettimeofday(&tv, NULL); srand((unsigned int)tv.tv_sec*tv.tv_usec); uzbl.xwin = rand(); - } else { - uzbl.gui.main_window = create_window (); + } + + /* Windowed mode */ + else { + uzbl.gui.main_window = create_window(); gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox); gtk_widget_show_all (uzbl.gui.main_window); + uzbl.xwin = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (uzbl.gui.main_window))); + + gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); } + /* Scrolling */ 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); @@ -2417,34 +1825,18 @@ main (int argc, char* argv[]) { uzbl.info.pid_str = g_strdup_printf("%d", getpid()); g_setenv("UZBL_PID", uzbl.info.pid_str, TRUE); - send_event(INSTANCE_START, uzbl.info.pid_str, NULL); + send_event(INSTANCE_START, NULL, TYPE_INT, getpid(), NULL); - if(uzbl.state.plug_mode) { - char *t = itos(gtk_plug_get_id(uzbl.gui.plug)); - send_event(PLUG_CREATED, t, NULL); - g_free(t); + if (uzbl.state.plug_mode) { + send_event(PLUG_CREATED, NULL, TYPE_INT, gtk_plug_get_id (uzbl.gui.plug), NULL); } - /* generate an event with a list of built in commands */ + /* Generate an event with a list of built in commands */ builtins(); - if (!uzbl.state.plug_mode) - gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view)); - - if (uzbl.state.verbose) { - printf("Uzbl start location: %s\n", argv[0]); - if (uzbl.state.socket_id) - printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug)); - else - printf("window_id %i\n",(int) uzbl.xwin); - printf("pid %i\n", getpid ()); - printf("name: %s\n", uzbl.state.instance_name); - printf("commit: %s\n", uzbl.info.commit); - } - /* Check uzbl is in window mode before getting/setting geometry */ if (uzbl.gui.main_window) { - if(uzbl.gui.geometry) + if (uzbl.gui.geometry) cmd_set_geometry(); else retrieve_geometry(); @@ -2453,10 +1845,13 @@ main (int argc, char* argv[]) { gchar *uri_override = (uzbl.state.uri ? g_strdup(uzbl.state.uri) : NULL); if (argc > 1 && !uzbl.state.uri) uri_override = g_strdup(argv[1]); + gboolean verbose_override = uzbl.state.verbose; - settings_init (); + /* Read configuration file */ + settings_init(); + /* Update status bar */ if (!uzbl.behave.show_status) gtk_widget_hide(uzbl.gui.mainbar); else @@ -2465,6 +1860,7 @@ main (int argc, char* argv[]) { /* WebInspector */ set_up_inspector(); + /* Options overriding */ if (verbose_override > uzbl.state.verbose) uzbl.state.verbose = verbose_override; @@ -2473,7 +1869,22 @@ main (int argc, char* argv[]) { g_free(uri_override); } - gtk_main (); + /* Verbose feedback */ + if (uzbl.state.verbose) { + printf("Uzbl start location: %s\n", argv[0]); + if (uzbl.state.socket_id) + printf("plug_id %i\n", gtk_plug_get_id(uzbl.gui.plug)); + else + printf("window_id %i\n",(int) uzbl.xwin); + printf("pid %i\n", getpid ()); + printf("name: %s\n", uzbl.state.instance_name); + printf("commit: %s\n", uzbl.info.commit); + } + + + gtk_main(); + + /* Cleanup and exit*/ clean_up(); return EXIT_SUCCESS; diff --git a/src/uzbl-core.h b/src/uzbl-core.h index 429b892..1285e3a 100644 --- a/src/uzbl-core.h +++ b/src/uzbl-core.h @@ -10,6 +10,9 @@ * */ +#ifndef __UZBL_CORE__ +#define __UZBL_CORE__ + #define _POSIX_SOURCE #include <glib/gstdio.h> @@ -40,12 +43,18 @@ #include <sys/ioctl.h> #include <assert.h> +#if GTK_CHECK_VERSION(2,91,0) + #include <gtk/gtkx.h> +#endif + #include "cookie-jar.h" #define LENGTH(x) (sizeof x / sizeof x[0]) -/* gui elements */ + +/* GUI elements */ typedef struct { + /* Window */ GtkWidget* main_window; gchar* geometry; GtkPlug* plug; @@ -57,100 +66,110 @@ typedef struct { GtkWidget* mainbar_label_left; GtkWidget* mainbar_label_right; - GtkScrollbar* scbar_v; // Horizontal and Vertical Scrollbar - GtkScrollbar* scbar_h; // (These are still hidden) - GtkAdjustment* bar_v; // Information about document length - GtkAdjustment* bar_h; // and scrolling position + /* Scrolling */ + GtkScrollbar* scbar_v; /* Horizontal and Vertical Scrollbar */ + GtkScrollbar* scbar_h; /* (These are still hidden) */ + GtkAdjustment* bar_v; /* Information about document length */ + GtkAdjustment* bar_h; /* and scrolling position */ int scrollbars_visible; + + /* Web page */ WebKitWebView* web_view; gchar* main_title; gchar* icon; /* WebInspector */ - GtkWidget *inspector_window; - WebKitWebInspector *inspector; + GtkWidget* inspector_window; + WebKitWebInspector* inspector; - /* custom context menu item */ - GPtrArray *menu_items; + /* Custom context menu item */ + GPtrArray* menu_items; } GUI; -/* external communication*/ +/* External communication */ enum { FIFO, SOCKET}; typedef struct { gchar *fifo_path; gchar *socket_path; - /* stores (key)"variable name" -> (value)"pointer to var*/ - GHashTable *proto_var; + GHashTable *proto_var; /* stores (key)"variable name" -> (value)"pointer to var */ - gchar *sync_stdout; GPtrArray *connect_chan; GPtrArray *client_chan; } Communication; -/* internal state */ +/* Internal state */ typedef struct { - gchar *uri; - gchar *config_file; - int socket_id; - char *instance_name; - gchar *selected_url; - gchar *last_selected_url; - gchar *executable_path; - gchar* searchtx; - gboolean verbose; - gboolean events_stdout; - GPtrArray *event_buffer; - gchar** connect_socket_names; - GdkEventButton *last_button; - gboolean plug_mode; + gchar* uri; + gchar* config_file; + char* instance_name; + gchar* selected_url; + gchar* last_selected_url; + gchar* executable_path; + gchar* searchtx; + gboolean verbose; + GdkEventButton* last_button; + gchar* last_result; + gboolean plug_mode; + + /* Events */ + int socket_id; + gboolean events_stdout; + GPtrArray* event_buffer; + gchar** connect_socket_names; } State; -/* networking */ +/* Networking */ typedef struct { - SoupSession *soup_session; - UzblCookieJar *soup_cookie_jar; - SoupLogger *soup_logger; - char *proxy_url; - char *useragent; - char *accept_languages; - gint max_conns; - gint max_conns_host; + SoupSession* soup_session; + UzblCookieJar* soup_cookie_jar; + SoupLogger* soup_logger; + char* proxy_url; + char* useragent; + char* accept_languages; + gint max_conns; + gint max_conns_host; } Network; -/* behaviour */ +/* Behaviour */ typedef struct { /* Status bar */ gchar* status_format; gchar* status_format_right; gchar* status_background; + gboolean show_status; + gboolean status_top; /* Window title */ gchar* title_format_short; gchar* title_format_long; + /* Communication */ gchar* fifo_dir; gchar* socket_dir; - gchar* cookie_handler; + + /* Handlers */ gchar* authentication_handler; + gchar* scheme_handler; + gchar* download_handler; + + /* Fonts */ gchar* default_font_family; gchar* monospace_font_family; gchar* sans_serif_font_family; gchar* serif_font_family; gchar* fantasy_font_family; gchar* cursive_font_family; - gchar* scheme_handler; - gchar* download_handler; - gboolean show_status; + gboolean forward_keys; - gboolean status_top; guint modmask; guint http_debug; gchar* shell_cmd; guint view_source; + /* WebKitWebSettings exports */ guint font_size; guint monospace_size; @@ -177,30 +196,33 @@ typedef struct { gboolean print_version; /* command list: (key)name -> (value)Command */ - /* command list: (key)name -> (value)Command */ GHashTable* commands; + /* event lookup: (key)event_id -> (value)event_name */ GHashTable *event_lookup; } Behaviour; -/* javascript */ + +/* Javascript */ typedef struct { gboolean initialized; JSClassDefinition classdef; JSClassRef classref; } Javascript; -/* static information */ + +/* Static information */ typedef struct { - int webkit_major; - int webkit_minor; - int webkit_micro; - gchar *arch; - gchar *commit; - gchar *pid_str; + int webkit_major; + int webkit_minor; + int webkit_micro; + gchar* arch; + gchar* commit; + gchar* pid_str; } Info; -/* main uzbl data structure */ + +/* Main uzbl data structure */ typedef struct { GUI gui; State state; @@ -213,13 +235,15 @@ typedef struct { Window xwin; } UzblCore; -/* Main Uzbl object */ -extern UzblCore uzbl; +extern UzblCore uzbl; /* Main Uzbl object */ + typedef void sigfunc(int); -/* uzbl variables */ -enum ptr_type {TYPE_INT, TYPE_STR, TYPE_FLOAT}; +/* Uzbl variables */ +enum ptr_type {TYPE_INT = 1, TYPE_STR, TYPE_FLOAT, + TYPE_NAME, TYPE_FORMATTEDSTR // used by send_event +}; typedef struct { enum ptr_type type; union { @@ -233,263 +257,113 @@ typedef struct { } uzbl_cmdprop; /* Functions */ -char * -itos(int val); - -gchar* -strfree(gchar *str); - -void -clean_up(void); - -void -catch_sigterm(int s); - -sigfunc * -setup_signal(int signe, sigfunc *shandler); - -gboolean -set_var_value(const gchar *name, gchar *val); - -void -load_uri_imp(gchar *uri); - -void -print(WebKitWebView *page, GArray *argv, GString *result); - -void -commands_hash(void); - -void -load_uri (WebKitWebView * web_view, GArray *argv, GString *result); - -void -chain (WebKitWebView *page, GArray *argv, GString *result); - -void -close_uzbl (WebKitWebView *page, GArray *argv, GString *result); - -gboolean -run_command(const gchar *command, const gchar **args, const gboolean sync, - char **output_stdout); - -void -spawn_async(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result); - -void -spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result); - -void -parse_command(const char *cmd, const char *param, GString *result); - -void -parse_cmd_line(const char *ctl_line, GString *result); - -/*@null@*/ gchar* -build_stream_name(int type, const gchar *dir); - -gboolean -control_fifo(GIOChannel *gio, GIOCondition condition); - -/*@null@*/ gchar* -init_fifo(gchar *dir); - -gboolean -control_stdin(GIOChannel *gio, GIOCondition condition); - -void -create_stdin(); - -/*@null@*/ gchar* -init_socket(gchar *dir); - -gboolean -control_socket(GIOChannel *chan); - -gboolean -control_client_socket(GIOChannel *chan); - -void -update_title (void); - -gboolean -key_press_cb (GtkWidget* window, GdkEventKey* event); - -gboolean -key_release_cb (GtkWidget* window, GdkEventKey* event); - -void -initialize (int argc, char *argv[]); - -void -create_browser (); - -GtkWidget* -create_mainbar (); - -GtkWidget* -create_window (); - -GtkPlug* -create_plug (); - -void -run_handler (const gchar *act, const gchar *args); - -void -settings_init (); - -void -search_text (WebKitWebView *page, GArray *argv, const gboolean forward); - -void -search_forward_text (WebKitWebView *page, GArray *argv, GString *result); - -void -search_reverse_text (WebKitWebView *page, GArray *argv, GString *result); - -void -search_clear(WebKitWebView *page, GArray *argv, GString *result); - -void -dehilight (WebKitWebView *page, GArray *argv, GString *result); - -void -run_js (WebKitWebView * web_view, GArray *argv, GString *result); - -void -run_external_js (WebKitWebView * web_view, GArray *argv, GString *result); - -void -eval_js(WebKitWebView * web_view, gchar *script, GString *result, const gchar *script_file); - -void -handle_authentication (SoupSession *session, +void clean_up(void); +void update_title(void); + +/* Signal management functions */ +void catch_sigterm(int s); +sigfunc* setup_signal(int signe, sigfunc *shandler); + +gboolean set_var_value(const gchar *name, gchar *val); +void load_uri_imp(gchar *uri); +void print(WebKitWebView *page, GArray *argv, GString *result); +void commands_hash(void); +void load_uri(WebKitWebView * web_view, GArray *argv, GString *result); +void chain(WebKitWebView *page, GArray *argv, GString *result); +void close_uzbl(WebKitWebView *page, GArray *argv, GString *result); + +/* Running commands */ +gboolean run_command(const gchar *command, const gchar **args, const gboolean sync, + char **output_stdout); +void spawn_async(WebKitWebView *web_view, GArray *argv, GString *result); +void spawn_sh_async(WebKitWebView *web_view, GArray *argv, GString *result); +void spawn_sync(WebKitWebView *web_view, GArray *argv, GString *result); +void spawn_sh_sync(WebKitWebView *web_view, GArray *argv, GString *result); +void spawn_sync_exec(WebKitWebView *web_view, GArray *argv, GString *result); +void parse_command(const char *cmd, const char *param, GString *result); +void parse_cmd_line(const char *ctl_line, GString *result); + +/* Keyboard events functions */ +gboolean key_press_cb(GtkWidget* window, GdkEventKey* event); +gboolean key_release_cb(GtkWidget* window, GdkEventKey* event); + +/* Initialization functions */ +void initialize(int argc, char *argv[]); +void create_scrolled_win(); +GtkWidget* create_mainbar(); +GtkWidget* create_window(); +GtkPlug* create_plug(); +void run_handler(const gchar *act, const gchar *args); +void settings_init(); + +/* Search functions */ +void search_text (WebKitWebView *page, GArray *argv, const gboolean forward); +void search_forward_text (WebKitWebView *page, GArray *argv, GString *result); +void search_reverse_text (WebKitWebView *page, GArray *argv, GString *result); +void search_clear(WebKitWebView *page, GArray *argv, GString *result); +void dehilight (WebKitWebView *page, GArray *argv, GString *result); + +/* Javascript functions */ +void run_js (WebKitWebView * web_view, GArray *argv, GString *result); +void run_external_js (WebKitWebView * web_view, GArray *argv, GString *result); +void eval_js(WebKitWebView * web_view, gchar *script, GString *result, const gchar *script_file); + +/* Network functions */ +void handle_authentication (SoupSession *session, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer user_data); - -void handle_cookies (SoupSession *session, +void handle_cookies (SoupSession *session, SoupMessage *msg, gpointer user_data); +gboolean valid_name(const gchar* name); +void set_var(WebKitWebView *page, GArray *argv, GString *result); +void act_dump_config(); +void act_dump_config_as_events(); +void dump_var_hash(gpointer k, gpointer v, gpointer ud); +void dump_key_hash(gpointer k, gpointer v, gpointer ud); +void dump_config(); +void dump_config_as_events(); + +void retrieve_geometry(); +void set_webview_scroll_adjustments(); +void event(WebKitWebView *page, GArray *argv, GString *result); +void init_connect_socket(); +gboolean remove_socket_from_array(GIOChannel *chan); + +gint get_click_context(); +void hardcopy(WebKitWebView *page, GArray *argv, GString *result); +void include(WebKitWebView *page, GArray *argv, GString *result); +void show_inspector(WebKitWebView *page, GArray *argv, GString *result); +void add_cookie(WebKitWebView *page, GArray *argv, GString *result); +void delete_cookie(WebKitWebView *page, GArray *argv, GString *result); +void builtins(); -void -set_var(WebKitWebView *page, GArray *argv, GString *result); - -void -act_dump_config(); - -void -act_dump_config_as_events(); - -void -dump_var_hash(gpointer k, gpointer v, gpointer ud); - -void -dump_key_hash(gpointer k, gpointer v, gpointer ud); - -void -dump_config(); - -void -dump_config_as_events(); - -void -retrieve_geometry(); - -void -set_webview_scroll_adjustments(); - -void -event(WebKitWebView *page, GArray *argv, GString *result); - -void -init_connect_socket(); - -gboolean -remove_socket_from_array(GIOChannel *chan); - -void -menu_add(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_link(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_image(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_edit(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_separator(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_separator_link(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_separator_image(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_add_separator_edit(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_remove(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_remove_link(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_remove_image(WebKitWebView *page, GArray *argv, GString *result); - -void -menu_remove_edit(WebKitWebView *page, GArray *argv, GString *result); - -gint -get_click_context(); - -void -hardcopy(WebKitWebView *page, GArray *argv, GString *result); - -void -include(WebKitWebView *page, GArray *argv, GString *result); +typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result); -void -show_inspector(WebKitWebView *page, GArray *argv, GString *result); +typedef struct { + const gchar *key; + Command function; + gboolean no_split; +} CommandInfo; -void -add_cookie(WebKitWebView *page, GArray *argv, GString *result); +const CommandInfo * +parse_command_parts(const gchar *line, GArray *a); void -delete_cookie(WebKitWebView *page, GArray *argv, GString *result); +parse_command_arguments(const gchar *p, GArray *a, gboolean no_split); void -builtins(); - -typedef void (*Command)(WebKitWebView*, GArray *argv, GString *result); +run_parsed_command(const CommandInfo *c, GArray *a, GString *result); typedef struct { - Command function; - gboolean no_split; -} CommandInfo; - -typedef struct { - gchar *name; - gchar *cmd; + gchar* name; + gchar* cmd; gboolean issep; - guint context; + guint context; WebKitHitTestResult* hittest; } MenuItem; - +#endif /* vi: set et ts=4: */ |