surf

surf browser, a WebKit2GTK based browser
Log | Files | Refs | README | LICENSE

commit 35cd70737bb6bc77591b3ac66afd8c7ad12dd529
parent 315af78589c1eb00b45dd0ece32087dba5eb93e3
Author: Quentin Rameau <quinq@fifth.space>
Date:   Mon,  7 Dec 2015 15:50:00 +0100

Communicate with webextension via a pipe

Diffstat:
Makefile | 2+-
config.def.h | 12++++++------
libsurf-webext.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
surf.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
4 files changed, 201 insertions(+), 44 deletions(-)

diff --git a/Makefile b/Makefile @@ -31,7 +31,7 @@ options: @$(LIBTOOL) --mode compile --tag CC $(CC) $(LIBCFLAGS) -c $< $(OBJ): config.h config.mk -$(LIBOBJ): config.mk +$(LIBOBJ): config.h config.mk config.h: @echo creating $@ from config.def.h diff --git a/config.def.h b/config.def.h @@ -145,12 +145,12 @@ static Key keys[] = { /* Currently we have to use scrolling steps that WebKit2GTK+ gives us * d: step down, u: step up, r: step right, l:step left * D: page down, U: page up */ - { MODKEY, GDK_KEY_j, scroll, { .i = 'd' } }, - { MODKEY, GDK_KEY_k, scroll, { .i = 'u' } }, - { MODKEY, GDK_KEY_b, scroll, { .i = 'U' } }, - { MODKEY, GDK_KEY_space, scroll, { .i = 'D' } }, - { MODKEY, GDK_KEY_i, scroll, { .i = 'r' } }, - { MODKEY, GDK_KEY_u, scroll, { .i = 'l' } }, + { MODKEY, GDK_KEY_j, scrollv, { .i = +10 } }, + { MODKEY, GDK_KEY_k, scrollv, { .i = -10 } }, + { MODKEY, GDK_KEY_b, scrollv, { .i = +50 } }, + { MODKEY, GDK_KEY_space, scrollv, { .i = -50 } }, + { MODKEY, GDK_KEY_i, scrollh, { .i = +10 } }, + { MODKEY, GDK_KEY_u, scrollh, { .i = -10 } }, { MODKEY|GDK_SHIFT_MASK, GDK_KEY_j, zoom, { .i = -1 } }, diff --git a/libsurf-webext.c b/libsurf-webext.c @@ -1,7 +1,123 @@ +#include <sys/stat.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> + +#include <gio/gio.h> #include <webkit2/webkit-web-extension.h> +#include <webkitdom/webkitdom.h> +#include <webkitdom/WebKitDOMDOMWindowUnstable.h> + +#define LENGTH(x) (sizeof(x) / sizeof(x[0])) + +typedef struct Page { + guint64 id; + WebKitWebPage *webpage; + WebKitDOMDOMWindow *view; + struct Page *next; +} Page; + +static int pipein, pipeout; +static Page *pages; + +Page * +newpage(WebKitWebPage *page) +{ + Page *p; + + if (!(p = calloc(1, sizeof(Page)))) + die("Cannot malloc!\n"); + + p->next = pages; + pages = p; + + p->id = webkit_web_page_get_id(page); + p->webpage = page; + + return p; +} + +static void +msgsurf(Page *p, const char *s) +{ + char msg[BUFSIZ]; + + msg[0] = p ? p->id : 0; + snprintf(&msg[1], sizeof(msg) - 1, "%s", s); + + if (pipeout) + write(pipeout, msg, sizeof(msg)); +} + +static gboolean +readpipe(GIOChannel *s, GIOCondition c, gpointer unused) +{ + char msg[BUFSIZ]; + gsize msgsz; + GError *gerr = NULL; + glong wh, ww; + Page *p; + + if (g_io_channel_read_chars(s, msg, LENGTH(msg), &msgsz, &gerr) != + G_IO_STATUS_NORMAL) { + fprintf(stderr, "Unable to read pipe: %s\n", gerr->message); + g_error_free(gerr); + return TRUE; + } + msg[msgsz] = '\0'; + + for (p = pages; p; p = p->next) { + if (p->id == msg[0]) + break; + } + if (!p || !p->view) + return TRUE; + + switch (msg[1]) { + case 'h': + ww = webkit_dom_dom_window_get_inner_width(p->view); + webkit_dom_dom_window_scroll_by(p->view, + (ww / 100) * msg[2], 0); + break; + case 'v': + wh = webkit_dom_dom_window_get_inner_height(p->view); + webkit_dom_dom_window_scroll_by(p->view, + 0, (wh / 100) * msg[2]); + break; + } + + return TRUE; +} + +static void +documentloaded(WebKitWebPage *wp, Page *p) +{ + p->view = webkit_dom_document_get_default_view( + webkit_web_page_get_dom_document(wp)); +} + +static void +webpagecreated(WebKitWebExtension *e, WebKitWebPage *p, gpointer unused) +{ + Page *np = newpage(p); + + g_signal_connect(p, "document-loaded", + G_CALLBACK(documentloaded), np); +} G_MODULE_EXPORT void -webkit_web_extension_initialize(WebKitWebExtension *e) +webkit_web_extension_initialize_with_user_data(WebKitWebExtension *e, GVariant *gv) { - return; + GIOChannel *gchanpipe; + + g_signal_connect(e, "page-created", + G_CALLBACK(webpagecreated), NULL); + + g_variant_get(gv, "(ii)", &pipein, &pipeout); + msgsurf(NULL, "i"); + + gchanpipe = g_io_channel_unix_new(pipein); + g_io_channel_set_encoding(gchanpipe, NULL, NULL); + g_io_channel_set_close_on_unref(gchanpipe, TRUE); + g_io_add_watch(gchanpipe, G_IO_IN, readpipe, NULL); } diff --git a/surf.c b/surf.c @@ -11,7 +11,6 @@ #include <pwd.h> #include <regex.h> #include <signal.h> -#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -28,6 +27,7 @@ #include <webkit2/webkit2.h> #include <X11/X.h> #include <X11/Xatom.h> +#include <glib.h> #include "arg.h" @@ -103,6 +103,7 @@ typedef struct Client { GTlsCertificate *cert, *failedcert; GTlsCertificateFlags tlserr; Window xid; + unsigned long pageid; int progress, fullscreen, https, insecure, errorpage; const char *title, *overtitle, *targeturi; const char *needle; @@ -169,6 +170,7 @@ static void updatewinid(Client *c); static void handleplumb(Client *c, const char *uri); static void newwindow(Client *c, const Arg *a, int noembed); static void spawn(Client *c, const Arg *a); +static void msgext(Client *c, char type, const Arg *a); static void destroyclient(Client *c); static void cleanup(void); @@ -214,7 +216,8 @@ static void print(Client *c, const Arg *a); static void showcert(Client *c, const Arg *a); static void clipboard(Client *c, const Arg *a); static void zoom(Client *c, const Arg *a); -static void scroll(Client *c, const Arg *a); +static void scrollv(Client *c, const Arg *a); +static void scrollh(Client *c, const Arg *a); static void navigate(Client *c, const Arg *a); static void stop(Client *c, const Arg *a); static void toggle(Client *c, const Arg *a); @@ -242,6 +245,7 @@ static char *stylefile; static const char *useragent; static Parameter *curconfig; static int modparams[ParameterLast]; +static int pipein[2], pipeout[2]; char *argv0; static ParamName loadtransient[] = { @@ -313,6 +317,7 @@ die(const char *errstr, ...) void setup(void) { + GIOChannel *gchanin; GdkDisplay *gdpy; int i, j; @@ -343,6 +348,16 @@ setup(void) gdkkb = gdk_seat_get_keyboard(gdk_display_get_default_seat(gdpy)); + if (pipe(pipeout) < 0 || pipe(pipein) < 0) { + fputs("Unable to create pipes\n", stderr); + } else { + gchanin = g_io_channel_unix_new(pipein[0]); + g_io_channel_set_encoding(gchanin, NULL, NULL); + g_io_channel_set_close_on_unref(gchanin, TRUE); + g_io_add_watch(gchanin, G_IO_IN, readpipe, NULL); + } + + for (i = 0; i < LENGTH(certs); ++i) { if (!regcomp(&(certs[i].re), certs[i].regex, REG_EXTENDED)) { certs[i].file = g_strconcat(certdir, "/", certs[i].file, @@ -1009,6 +1024,8 @@ spawn(Client *c, const Arg *a) if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); + close(pipein[0]); + close(pipeout[1]); setsid(); execvp(((char **)a->v)[0], (char **)a->v); fprintf(stderr, "%s: execvp %s", argv0, ((char **)a->v)[0]); @@ -1041,6 +1058,9 @@ cleanup(void) { while (clients) destroyclient(clients); + + close(pipein[0]); + close(pipeout[1]); g_free(cookiefile); g_free(scriptfile); g_free(stylefile); @@ -1053,13 +1073,12 @@ newview(Client *c, WebKitWebView *rv) { WebKitWebView *v; WebKitSettings *settings; - WebKitUserContentManager *contentmanager; WebKitWebContext *context; + WebKitUserContentManager *contentmanager; /* Webview */ if (rv) { - v = WEBKIT_WEB_VIEW( - webkit_web_view_new_with_related_view(rv)); + v = WEBKIT_WEB_VIEW(webkit_web_view_new_with_related_view(rv)); } else { settings = webkit_settings_new_with_settings( "allow-file-access-from-file-urls", curconfig[FileURLsCrossAccess].val.i, @@ -1169,10 +1188,45 @@ newview(Client *c, WebKitWebView *rv) return v; } +static gboolean +readpipe(GIOChannel *s, GIOCondition ioc, gpointer unused) +{ + char msg[BUFSIZ]; + gsize msgsz; + GError *gerr = NULL; + + if (g_io_channel_read_chars(s, msg, sizeof(msg), &msgsz, &gerr) != + G_IO_STATUS_NORMAL) { + fprintf(stderr, "Unable to read pipe: %s\n", gerr->message); + g_error_free(gerr); + return TRUE; + } + msg[msgsz] = '\0'; + + switch (msg[1]) { + case 'i': + close(pipein[1]); + close(pipeout[0]); + break; + default: + fprintf(stderr, "surf: message in: \"%s\"\n", &msg[1]); + break; + } + + return TRUE; +} + void initwebextensions(WebKitWebContext *wc, Client *c) { + GVariant *gv; + + if (!pipeout[0] || !pipein[1]) + return; + + gv = g_variant_new("(ii)", pipeout[0], pipein[1]); webkit_web_context_set_web_extensions_directory(wc, WEBEXTDIR); + webkit_web_context_set_web_extensions_initialization_user_data(wc, gv); } GtkWidget * @@ -1298,6 +1352,7 @@ showview(WebKitWebView *v, Client *c) c->finder = webkit_web_view_get_find_controller(c->view); c->inspector = webkit_web_view_get_inspector(c->view); + c->pageid = webkit_web_view_get_page_id(c->view); c->win = createwindow(c); gtk_container_add(GTK_CONTAINER(c->win), GTK_WIDGET(c->view)); @@ -1346,8 +1401,7 @@ createwindow(Client *c) gtk_window_set_wmclass(GTK_WINDOW(w), wmstr, "Surf"); g_free(wmstr); - wmstr = g_strdup_printf("%s[%lu]", "Surf", - webkit_web_view_get_page_id(c->view)); + wmstr = g_strdup_printf("%s[%lu]", "Surf", c->pageid); gtk_window_set_role(GTK_WINDOW(w), wmstr); g_free(wmstr); @@ -1759,38 +1813,25 @@ zoom(Client *c, const Arg *a) curconfig[ZoomLevel].val.f = webkit_web_view_get_zoom_level(c->view); } -void -scroll(Client *c, const Arg *a) +static void +msgext(Client *c, char type, const Arg *a) { - GdkEvent *ev = gdk_event_new(GDK_KEY_PRESS); + char msg[BUFSIZ] = { c->pageid, type, a->i, '\0' }; - gdk_event_set_device(ev, gdkkb); - ev->key.window = gtk_widget_get_window(GTK_WIDGET(c->win)); - ev->key.state = GDK_CONTROL_MASK; - ev->key.time = GDK_CURRENT_TIME; + if (pipeout[1]) + write(pipeout[1], msg, sizeof(msg)); +} - switch (a->i) { - case 'd': - ev->key.keyval = GDK_KEY_Down; - break; - case 'D': - ev->key.keyval = GDK_KEY_Page_Down; - break; - case 'l': - ev->key.keyval = GDK_KEY_Left; - break; - case 'r': - ev->key.keyval = GDK_KEY_Right; - break; - case 'U': - ev->key.keyval = GDK_KEY_Page_Up; - break; - case 'u': - ev->key.keyval = GDK_KEY_Up; - break; - } +void +scrollv(Client *c, const Arg *a) +{ + msgext(c, 'v', a); +} - gdk_event_put(ev); +void +scrollh(Client *c, const Arg *a) +{ + msgext(c, 'h', a); } void