684d4a5db4c03f11e264465390ff1c64ca332181
[surf.git] / libsurf-webext.c
1 #include <sys/stat.h>
2 #include <fcntl.h>
3 #include <limits.h>
4 #include <stdlib.h>
5
6 #include <gio/gio.h>
7 #include <webkit2/webkit-web-extension.h>
8 #include <webkitdom/webkitdom.h>
9 #include <webkitdom/WebKitDOMDOMWindowUnstable.h>
10
11 #include "common.h"
12
13 #define LENGTH(x)   (sizeof(x) / sizeof(x[0]))
14
15 typedef struct Page {
16         guint64 id;
17         WebKitWebPage *webpage;
18         struct Page *next;
19 } Page;
20
21 static int pipein, pipeout;
22 static Page *pages;
23
24 Page *
25 newpage(WebKitWebPage *page)
26 {
27         Page *p;
28
29         if (!(p = calloc(1, sizeof(Page))))
30                 die("Cannot malloc!\n");
31
32         p->next = pages;
33         pages = p;
34
35         p->id = webkit_web_page_get_id(page);
36         p->webpage = page;
37
38         return p;
39 }
40
41 static void
42 msgsurf(Page *p, const char *s)
43 {
44         char msg[MSGBUFSZ];
45         int ret;
46
47         msg[0] = p ? p->id : 0;
48         ret = snprintf(&msg[1], sizeof(msg) - 1, "%s", s);
49         if (ret >= sizeof(msg)) {
50                 fprintf(stderr, "webext: message too long: %d\n", ret);
51                 return;
52         }
53
54         if (pipeout) {
55                 if (write(pipeout, msg, sizeof(msg)) < 0)
56                         fprintf(stderr, "webext: error sending: %s\n", msg);
57         }
58 }
59
60 static gboolean
61 readpipe(GIOChannel *s, GIOCondition c, gpointer unused)
62 {
63         char msg[MSGBUFSZ];
64         gsize msgsz;
65         WebKitDOMDOMWindow *view;
66         GError *gerr = NULL;
67         glong wh, ww;
68         Page *p;
69
70         if (g_io_channel_read_chars(s, msg, LENGTH(msg), &msgsz, &gerr) !=
71             G_IO_STATUS_NORMAL) {
72                 fprintf(stderr, "webext: error reading pipe: %s\n",
73                         gerr->message);
74                 g_error_free(gerr);
75                 return TRUE;
76         }
77         msg[msgsz] = '\0';
78
79         for (p = pages; p; p = p->next) {
80                 if (p->id == msg[0])
81                         break;
82         }
83         if (!p || !(view = webkit_dom_document_get_default_view(
84                     webkit_web_page_get_dom_document(p->webpage))))
85                 return TRUE;
86
87         switch (msg[1]) {
88         case 'h':
89                 ww = webkit_dom_dom_window_get_inner_width(view);
90                 webkit_dom_dom_window_scroll_by(view,
91                                                 (ww / 100) * msg[2], 0);
92                 break;
93         case 'v':
94                 wh = webkit_dom_dom_window_get_inner_height(view);
95                 webkit_dom_dom_window_scroll_by(view,
96                                                 0, (wh / 100) * msg[2]);
97                 break;
98         }
99
100         return TRUE;
101 }
102
103 static void
104 webpagecreated(WebKitWebExtension *e, WebKitWebPage *wp, gpointer unused)
105 {
106         Page *p = newpage(wp);
107 }
108
109 G_MODULE_EXPORT void
110 webkit_web_extension_initialize_with_user_data(WebKitWebExtension *e, GVariant *gv)
111 {
112         GIOChannel *gchanpipe;
113
114         g_signal_connect(e, "page-created", G_CALLBACK(webpagecreated), NULL);
115
116         g_variant_get(gv, "(ii)", &pipein, &pipeout);
117         msgsurf(NULL, "i");
118
119         gchanpipe = g_io_channel_unix_new(pipein);
120         g_io_channel_set_encoding(gchanpipe, NULL, NULL);
121         g_io_channel_set_close_on_unref(gchanpipe, TRUE);
122         g_io_add_watch(gchanpipe, G_IO_IN, readpipe, NULL);
123 }