added searx
[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         static char msg[MSGBUFSZ];
45         size_t sln = strlen(s);
46         int ret;
47
48         if ((ret = snprintf(msg, sizeof(msg), "%c%c%s",
49                             2 + sln, p ? p->id : 0, s))
50             >= sizeof(msg)) {
51                 fprintf(stderr, "webext: message too long: %d\n", ret);
52                 return;
53         }
54
55         if (pipeout && write(pipeout, msg, sizeof(msg)) < 0)
56                 fprintf(stderr, "webext: error sending: %.*s\n", ret-2, msg+2);
57 }
58
59 static gboolean
60 readpipe(GIOChannel *s, GIOCondition c, gpointer unused)
61 {
62         static char msg[MSGBUFSZ], msgsz;
63         WebKitDOMDOMWindow *view;
64         GError *gerr = NULL;
65         glong wh, ww;
66         Page *p;
67
68         if (g_io_channel_read_chars(s, msg, LENGTH(msg), NULL, &gerr) !=
69             G_IO_STATUS_NORMAL) {
70                 fprintf(stderr, "webext: error reading pipe: %s\n",
71                         gerr->message);
72                 g_error_free(gerr);
73                 return TRUE;
74         }
75         if ((msgsz = msg[0]) < 3) {
76                 fprintf(stderr, "webext: message too short: %d\n", msgsz);
77                 return TRUE;
78         }
79
80         for (p = pages; p; p = p->next) {
81                 if (p->id == msg[1])
82                         break;
83         }
84         if (!p || !(view = webkit_dom_document_get_default_view(
85                     webkit_web_page_get_dom_document(p->webpage))))
86                 return TRUE;
87
88         switch (msg[2]) {
89         case 'h':
90                 if (msgsz != 4)
91                         return TRUE;
92                 ww = webkit_dom_dom_window_get_inner_width(view);
93                 webkit_dom_dom_window_scroll_by(view,
94                                                 (ww / 100) * msg[3], 0);
95                 break;
96         case 'v':
97                 if (msgsz != 4)
98                         return TRUE;
99                 wh = webkit_dom_dom_window_get_inner_height(view);
100                 webkit_dom_dom_window_scroll_by(view,
101                                                 0, (wh / 100) * msg[3]);
102                 break;
103         }
104
105         return TRUE;
106 }
107
108 static void
109 webpagecreated(WebKitWebExtension *e, WebKitWebPage *wp, gpointer unused)
110 {
111         Page *p = newpage(wp);
112 }
113
114 G_MODULE_EXPORT void
115 webkit_web_extension_initialize_with_user_data(WebKitWebExtension *e, GVariant *gv)
116 {
117         GIOChannel *gchanpipe;
118
119         g_signal_connect(e, "page-created", G_CALLBACK(webpagecreated), NULL);
120
121         g_variant_get(gv, "(ii)", &pipein, &pipeout);
122         msgsurf(NULL, "i");
123
124         gchanpipe = g_io_channel_unix_new(pipein);
125         g_io_channel_set_encoding(gchanpipe, NULL, NULL);
126         g_io_channel_set_close_on_unref(gchanpipe, TRUE);
127         g_io_add_watch(gchanpipe, G_IO_IN, readpipe, NULL);
128 }