6c3deb72c6224174a958c1f86583f4c6b86568a2
[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 #define LENGTH(x)   (sizeof(x) / sizeof(x[0]))
12
13 #define MSGBUFSZ 32
14
15 typedef struct Page {
16         guint64 id;
17         WebKitWebPage *webpage;
18         WebKitDOMDOMWindow *view;
19         struct Page *next;
20 } Page;
21
22 static int pipein, pipeout;
23 static Page *pages;
24
25 Page *
26 newpage(WebKitWebPage *page)
27 {
28         Page *p;
29
30         if (!(p = calloc(1, sizeof(Page))))
31                 die("Cannot malloc!\n");
32
33         p->next = pages;
34         pages = p;
35
36         p->id = webkit_web_page_get_id(page);
37         p->webpage = page;
38
39         return p;
40 }
41
42 static void
43 msgsurf(Page *p, const char *s)
44 {
45         char msg[MSGBUFSZ];
46         int ret;
47
48         msg[0] = p ? p->id : 0;
49         ret = snprintf(&msg[1], sizeof(msg) - 1, "%s", s);
50         if (ret >= sizeof(msg)) {
51                 fprintf(stderr, "webext: message too long: %d\n", ret);
52                 return;
53         }
54
55         if (pipeout) {
56                 if (write(pipeout, msg, sizeof(msg)) < 0)
57                         fprintf(stderr, "webext: error sending: %s\n", msg);
58         }
59 }
60
61 static gboolean
62 readpipe(GIOChannel *s, GIOCondition c, gpointer unused)
63 {
64         char msg[MSGBUFSZ];
65         gsize msgsz;
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 || !p->view)
84                 return TRUE;
85
86         switch (msg[1]) {
87         case 'h':
88                 ww = webkit_dom_dom_window_get_inner_width(p->view);
89                 webkit_dom_dom_window_scroll_by(p->view,
90                                                 (ww / 100) * msg[2], 0);
91                 break;
92         case 'v':
93                 wh = webkit_dom_dom_window_get_inner_height(p->view);
94                 webkit_dom_dom_window_scroll_by(p->view,
95                                                 0, (wh / 100) * msg[2]);
96                 break;
97         }
98
99         return TRUE;
100 }
101
102 static void
103 documentloaded(WebKitWebPage *wp, Page *p)
104 {
105         p->view = webkit_dom_document_get_default_view(
106                   webkit_web_page_get_dom_document(wp));
107 }
108
109 static void
110 webpagecreated(WebKitWebExtension *e, WebKitWebPage *wp, gpointer unused)
111 {
112         Page *p = newpage(wp);
113
114         g_signal_connect(wp, "document-loaded", G_CALLBACK(documentloaded), p);
115 }
116
117 G_MODULE_EXPORT void
118 webkit_web_extension_initialize_with_user_data(WebKitWebExtension *e, GVariant *gv)
119 {
120         GIOChannel *gchanpipe;
121
122         g_signal_connect(e, "page-created", G_CALLBACK(webpagecreated), NULL);
123
124         g_variant_get(gv, "(ii)", &pipein, &pipeout);
125         msgsurf(NULL, "i");
126
127         gchanpipe = g_io_channel_unix_new(pipein);
128         g_io_channel_set_encoding(gchanpipe, NULL, NULL);
129         g_io_channel_set_close_on_unref(gchanpipe, TRUE);
130         g_io_add_watch(gchanpipe, G_IO_IN, readpipe, NULL);
131 }