Use `get_settings_object(..)` to get correct settings GObject
[luakit.git] / widgets / webview.c
blobd6dadad4f616095db5a36a23872afb5cf9b73582
1 /*
2 * webview.c - webkit webview widget
4 * Copyright (C) 2010 Mason Larobina <mason.larobina@gmail.com>
5 * Copyright (C) 2007-2009 Julien Danjou <julien@danjou.info>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "luah.h"
23 #include "widgets/common.h"
24 #include <JavaScriptCore/JavaScript.h>
25 #include <webkit/webkit.h>
26 #include <libsoup/soup.h>
27 #include "math.h"
29 static struct {
30 SoupSession *session;
31 SoupCookieJar *cookiejar;
32 } Soup = { NULL, NULL };
34 typedef enum { BOOL, CHAR, INT, FLOAT, DOUBLE, URI } property_value_type;
35 typedef enum { SETTINGS, WEBKITVIEW, SOUPSESSION } property_value_scope;
37 typedef union {
38 gchar *c;
39 gboolean b;
40 gdouble d;
41 gfloat f;
42 gint i;
43 } property_tmp_values;
45 const struct property_t {
46 const gchar *name;
47 property_value_type type;
48 property_value_scope scope;
49 gboolean writable;
50 } properties[] = {
51 { "accept-language", CHAR, SOUPSESSION, TRUE },
52 { "accept-language-auto", BOOL, SOUPSESSION, TRUE },
53 { "auto-load-images", BOOL, SETTINGS, TRUE },
54 { "auto-resize-window", BOOL, SETTINGS, TRUE },
55 { "auto-shrink-images", BOOL, SETTINGS, TRUE },
56 { "cursive-font-family", CHAR, SETTINGS, TRUE },
57 { "custom-encoding", CHAR, WEBKITVIEW, TRUE },
58 { "default-encoding", CHAR, SETTINGS, TRUE },
59 { "default-font-family", CHAR, SETTINGS, TRUE },
60 { "default-font-size", INT, SETTINGS, TRUE },
61 { "default-monospace-font-size", INT, SETTINGS, TRUE },
62 { "editable", BOOL, WEBKITVIEW, TRUE },
63 { "enable-caret-browsing", BOOL, SETTINGS, TRUE },
64 { "enable-default-context-menu", BOOL, SETTINGS, TRUE },
65 { "enable-developer-extras", BOOL, SETTINGS, TRUE },
66 { "enable-dom-paste", BOOL, SETTINGS, TRUE },
67 { "enable-file-access-from-file-uris", BOOL, SETTINGS, TRUE },
68 { "enable-html5-database", BOOL, SETTINGS, TRUE },
69 { "enable-html5-local-storage", BOOL, SETTINGS, TRUE },
70 { "enable-java-applet", BOOL, SETTINGS, TRUE },
71 { "enable-offline-web-application-cache", BOOL, SETTINGS, TRUE },
72 { "enable-page-cache", BOOL, SETTINGS, TRUE },
73 { "enable-plugins", BOOL, SETTINGS, TRUE },
74 { "enable-private-browsing", BOOL, SETTINGS, TRUE },
75 { "enable-scripts", BOOL, SETTINGS, TRUE },
76 { "enable-site-specific-quirks", BOOL, SETTINGS, TRUE },
77 { "enable-spatial-navigation", BOOL, SETTINGS, TRUE },
78 { "enable-spell-checking", BOOL, SETTINGS, TRUE },
79 { "enable-universal-access-from-file-uris", BOOL, SETTINGS, TRUE },
80 { "enable-xss-auditor", BOOL, SETTINGS, TRUE },
81 { "encoding", CHAR, WEBKITVIEW, FALSE },
82 { "enforce-96-dpi", BOOL, SETTINGS, TRUE },
83 { "fantasy-font-family", CHAR, SETTINGS, TRUE },
84 { "full-content-zoom", BOOL, WEBKITVIEW, TRUE },
85 { "idle-timeout", INT, SOUPSESSION, TRUE },
86 { "icon-uri", CHAR, WEBKITVIEW, FALSE },
87 { "javascript-can-access-clipboard", BOOL, SETTINGS, TRUE },
88 { "javascript-can-open-windows-automatically", BOOL, SETTINGS, TRUE },
89 { "max-conns", INT, SOUPSESSION, TRUE },
90 { "max-conns-per-host", INT, SOUPSESSION, TRUE },
91 { "minimum-font-size", INT, SETTINGS, TRUE },
92 { "minimum-logical-font-size", INT, SETTINGS, TRUE },
93 { "monospace-font-family", CHAR, SETTINGS, TRUE },
94 { "print-backgrounds", BOOL, SETTINGS, TRUE },
95 { "progress", DOUBLE, WEBKITVIEW, FALSE },
96 { "proxy-uri", URI, SOUPSESSION, TRUE },
97 { "resizable-text-areas", BOOL, SETTINGS, TRUE },
98 { "sans-serif-font-family", CHAR, SETTINGS, TRUE },
99 { "serif-font-family", CHAR, SETTINGS, TRUE },
100 { "spell-checking-languages", CHAR, SETTINGS, TRUE },
101 { "ssl-ca-file", CHAR, SOUPSESSION, TRUE },
102 { "ssl-strict", BOOL, SOUPSESSION, TRUE },
103 { "tab-key-cycles-through-elements", BOOL, SETTINGS, TRUE },
104 { "timeout", INT, SOUPSESSION, TRUE },
105 { "title", CHAR, WEBKITVIEW, FALSE },
106 { "transparent", BOOL, WEBKITVIEW, TRUE },
107 { "use-ntlm", BOOL, SOUPSESSION, TRUE },
108 { "user-agent", CHAR, SETTINGS, TRUE },
109 { "user-stylesheet-uri", CHAR, SETTINGS, TRUE },
110 { "zoom-level", FLOAT, WEBKITVIEW, TRUE },
111 { "zoom-step", FLOAT, SETTINGS, TRUE },
112 { NULL, 0, 0, 0 },
115 static void
116 progress_cb(WebKitWebView *v, gint p, widget_t *w)
118 (void) v;
119 (void) p;
121 lua_State *L = globalconf.L;
122 luaH_object_push(L, w->ref);
123 luaH_object_emit_signal(L, -1, "progress-update", 0, 0);
124 lua_pop(L, 1);
127 static void
128 title_changed_cb(WebKitWebView *v, WebKitWebFrame *f, const gchar *title, widget_t *w)
130 (void) f;
131 (void) v;
132 (void) title;
134 lua_State *L = globalconf.L;
135 luaH_object_push(L, w->ref);
136 luaH_object_emit_signal(L, -1, "title-changed", 0, 0);
137 lua_pop(L, 1);
140 static void
141 load_start_cb(WebKitWebView *v, WebKitWebFrame *f, widget_t *w)
143 (void) v;
144 (void) f;
146 lua_State *L = globalconf.L;
147 luaH_object_push(L, w->ref);
148 luaH_object_emit_signal(L, -1, "load-start", 0, 0);
149 lua_pop(L, 1);
152 inline static void
153 update_uri(GtkWidget *view, const gchar *uri, widget_t *w)
155 /* return if uri has not changed */
156 if (!g_strcmp0(uri, g_object_get_data(G_OBJECT(view), "uri")))
157 return;
159 g_object_set_data_full(G_OBJECT(view), "uri", g_strdup(uri), g_free);
160 lua_State *L = globalconf.L;
161 luaH_object_push(L, w->ref);
162 luaH_object_emit_signal(L, -1, "property::uri", 0, 0);
163 lua_pop(L, 1);
166 static void
167 load_commit_cb(WebKitWebView *v, WebKitWebFrame *f, widget_t *w)
169 update_uri(GTK_WIDGET(v), webkit_web_frame_get_uri(f), w);
170 lua_State *L = globalconf.L;
171 luaH_object_push(L, w->ref);
172 luaH_object_emit_signal(L, -1, "load-commit", 0, 0);
173 lua_pop(L, 1);
176 static void
177 load_finish_cb(WebKitWebView *v, WebKitWebFrame *f, widget_t *w)
179 update_uri(GTK_WIDGET(v), webkit_web_frame_get_uri(f), w);
180 lua_State *L = globalconf.L;
181 luaH_object_push(L, w->ref);
182 luaH_object_emit_signal(L, -1, "load-finish", 0, 0);
183 lua_pop(L, 1);
186 static void
187 link_hover_cb(WebKitWebView *view, const char *t, const gchar *link, widget_t *w)
189 (void) t;
190 lua_State *L = globalconf.L;
191 GObject *ws = G_OBJECT(view);
192 gchar *last_hover = g_object_get_data(ws, "hovered-uri");
194 /* links are identical, do nothing */
195 if (last_hover && !g_strcmp0(last_hover, link))
196 return;
198 luaH_object_push(L, w->ref);
200 if (last_hover) {
201 lua_pushstring(L, last_hover);
202 g_object_set_data(ws, "hovered-uri", NULL);
203 luaH_object_emit_signal(L, -2, "link-unhover", 1, 0);
206 if (link) {
207 lua_pushstring(L, link);
208 g_object_set_data_full(ws, "hovered-uri", g_strdup(link), g_free);
209 luaH_object_emit_signal(L, -2, "link-hover", 1, 0);
212 luaH_object_emit_signal(L, -1, "property::hovered_uri", 0, 0);
213 lua_pop(L, 1);
216 /* Raises the "navigation-request" signal on a webkit navigation policy
217 * decision request. The default action is to load the requested uri.
219 * The signal handler is able to:
220 * - return true for the handler execution to stop and the request to continue
221 * - return false for the handler execution to stop and the request to hault
222 * - do nothing and give the navigation decision to the next signal handler
224 * This signal is also where you would attach custom scheme handlers to take
225 * over the navigation request by launching an external application.
227 static gboolean
228 navigation_decision_cb(WebKitWebView *v, WebKitWebFrame *f,
229 WebKitNetworkRequest *r, WebKitWebNavigationAction *a,
230 WebKitWebPolicyDecision *p, widget_t *w)
232 (void) v;
233 (void) f;
234 (void) a;
236 lua_State *L = globalconf.L;
237 const gchar *uri = webkit_network_request_get_uri(r);
238 gint ret;
240 debug("Navigation requested: %s", uri);
242 luaH_object_push(L, w->ref);
243 lua_pushstring(L, uri);
244 ret = luaH_object_emit_signal(L, -2, "navigation-request", 1, 1);
246 if (ret && !luaH_checkboolean(L, -1))
247 /* User responded with false, do not continue navigation request */
248 webkit_web_policy_decision_ignore(p);
249 else
250 webkit_web_policy_decision_use(p);
252 lua_pop(L, ret);
253 return TRUE;
256 inline static gint
257 push_adjustment_values(lua_State *L, GtkAdjustment *adjustment)
259 gdouble view_size = gtk_adjustment_get_page_size(adjustment);
260 gdouble value = gtk_adjustment_get_value(adjustment);
261 gdouble max = gtk_adjustment_get_upper(adjustment) - view_size;
262 lua_pushnumber(L, value);
263 lua_pushnumber(L, (max < 0 ? 0 : max));
264 lua_pushnumber(L, view_size);
265 return 3;
268 static gint
269 luaH_webview_get_vscroll(lua_State *L)
271 widget_t *w = luaH_checkudata(L, 1, &widget_class);
272 GtkAdjustment *adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(w->widget));
273 return push_adjustment_values(L, adjustment);
276 static gint
277 luaH_webview_get_hscroll(lua_State *L)
279 widget_t *w = luaH_checkudata(L, 1, &widget_class);
280 GtkAdjustment *adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(w->widget));
281 return push_adjustment_values(L, adjustment);
284 inline static void
285 set_adjustment(GtkAdjustment *adjustment, gdouble new)
287 gdouble view_size = gtk_adjustment_get_page_size(adjustment);
288 gdouble max = gtk_adjustment_get_upper(adjustment) - view_size;
289 gtk_adjustment_set_value(adjustment, ((new < 0 ? 0 : new) > max ? max : new));
292 static gint
293 luaH_webview_set_scroll_vert(lua_State *L)
295 widget_t *w = luaH_checkudata(L, 1, &widget_class);
296 gdouble value = (gdouble) luaL_checknumber(L, 2);
297 GtkAdjustment *adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(w->widget));
298 set_adjustment(adjustment, value);
299 return 0;
302 static gint
303 luaH_webview_set_scroll_horiz(lua_State *L)
305 widget_t *w = luaH_checkudata(L, 1, &widget_class);
306 gdouble value = (gdouble) luaL_checknumber(L, 2);
307 GtkAdjustment *adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(w->widget));
308 set_adjustment(adjustment, value);
309 return 0;
312 static gint
313 luaH_webview_go_back(lua_State *L)
315 widget_t *w = luaH_checkudata(L, 1, &widget_class);
316 gint steps = (gint) luaL_checknumber(L, 2);
317 GtkWidget *view = GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview"));
318 webkit_web_view_go_back_or_forward(WEBKIT_WEB_VIEW(view), steps * -1);
319 return 0;
322 static gint
323 luaH_webview_go_forward(lua_State *L)
325 widget_t *w = luaH_checkudata(L, 1, &widget_class);
326 gint steps = (gint) luaL_checknumber(L, 2);
327 GtkWidget *view = GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview"));
328 webkit_web_view_go_back_or_forward(WEBKIT_WEB_VIEW(view), steps);
329 return 0;
332 static gint
333 luaH_webview_search(lua_State *L)
335 widget_t *w = luaH_checkudata(L, 1, &widget_class);
336 WebKitWebView *view = WEBKIT_WEB_VIEW(GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview")));
337 const gchar *text = luaL_checkstring(L, 2);
338 gboolean case_sensitive = luaH_checkboolean(L, 3);
339 gboolean forward = luaH_checkboolean(L, 4);
340 gboolean wrap = luaH_checkboolean(L, 5);
342 webkit_web_view_unmark_text_matches(view);
343 webkit_web_view_search_text(view, text, case_sensitive, forward, wrap);
344 webkit_web_view_mark_text_matches(view, text, case_sensitive, 0);
345 webkit_web_view_set_highlight_text_matches(view, TRUE);
346 return 0;
349 static gint
350 luaH_webview_clear_search(lua_State *L)
352 widget_t *w = luaH_checkudata(L, 1, &widget_class);
353 WebKitWebView *view = WEBKIT_WEB_VIEW(GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview")));
354 webkit_web_view_unmark_text_matches(view);
355 return 0;
358 inline static GObject*
359 get_settings_object(GtkWidget *view, property_value_scope scope)
361 switch (scope) {
362 case SETTINGS:
363 return G_OBJECT(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(view)));
364 case WEBKITVIEW:
365 return G_OBJECT(view);
366 case SOUPSESSION:
367 return G_OBJECT(Soup.session);
368 default:
369 break;
371 return NULL;
374 static gint
375 luaH_webview_get_prop(lua_State *L)
377 widget_t *w = luaH_checkudata(L, 1, &widget_class);
378 const gchar *prop = luaL_checkstring(L, 2);
379 GtkWidget *view = GTK_WIDGET(g_object_get_data(G_OBJECT(w->widget), "webview"));
380 GObject *ws;
381 property_tmp_values tmp;
382 SoupURI *u;
384 for (guint i = 0; i < LENGTH(properties); i++) {
385 if (g_strcmp0(properties[i].name, prop))
386 continue;
388 ws = get_settings_object(view, properties[i].scope);
390 switch(properties[i].type) {
391 case BOOL:
392 g_object_get(ws, prop, &tmp.b, NULL);
393 lua_pushboolean(L, tmp.b);
394 return 1;
396 case CHAR:
397 g_object_get(ws, prop, &tmp.c, NULL);
398 lua_pushstring(L, tmp.c);
399 g_free(tmp.c);
400 return 1;
402 case INT:
403 g_object_get(ws, prop, &tmp.i, NULL);
404 lua_pushnumber(L, tmp.i);
405 return 1;
407 case FLOAT:
408 g_object_get(ws, prop, &tmp.f, NULL);
409 lua_pushnumber(L, tmp.f);
410 return 1;
412 case DOUBLE:
413 g_object_get(ws, prop, &tmp.d, NULL);
414 lua_pushnumber(L, tmp.d);
415 return 1;
417 case URI:
418 g_object_get(ws, prop, &u, NULL);
419 tmp.c = soup_uri_to_string(u, 0);
420 lua_pushstring(L, tmp.c);
421 soup_uri_free(u);
422 g_free(tmp.c);
423 return 1;
425 default:
426 warn("unknown property type for: %s", properties[i].name);
427 break;
430 warn("unknown property: %s", prop);
431 return 0;
434 static gint
435 luaH_webview_set_prop(lua_State *L)
437 size_t len;
438 widget_t *w = luaH_checkudata(L, 1, &widget_class);
439 const gchar *prop = luaL_checklstring(L, 2, &len);
440 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
441 GObject *ws;
442 property_tmp_values tmp;
443 SoupURI *u;
445 for (guint i = 0; i < LENGTH(properties); i++) {
446 if (g_strcmp0(properties[i].name, prop))
447 continue;
449 if (!properties[i].writable) {
450 warn("attempt to set read-only property: %s", prop);
451 return 0;
454 ws = get_settings_object(view, properties[i].scope);
456 switch(properties[i].type) {
457 case BOOL:
458 tmp.b = luaH_checkboolean(L, 3);
459 g_object_set(ws, prop, tmp.b, NULL);
460 return 0;
462 case CHAR:
463 tmp.c = (gchar*) luaL_checklstring(L, 3, &len);
464 g_object_set(ws, prop, tmp.c, NULL);
465 return 0;
467 case INT:
468 tmp.i = (gint) luaL_checknumber(L, 3);
469 g_object_set(ws, prop, tmp.i, NULL);
470 return 0;
472 case FLOAT:
473 tmp.f = (gfloat) luaL_checknumber(L, 3);
474 g_object_set(ws, prop, tmp.f, NULL);
475 return 0;
477 case DOUBLE:
478 tmp.d = (gdouble) luaL_checknumber(L, 3);
479 g_object_set(ws, prop, tmp.d, NULL);
480 return 0;
482 case URI:
483 tmp.c = (gchar*) luaL_checkstring(L, 3);
484 u = soup_uri_new(tmp.c);
485 if (SOUP_URI_VALID_FOR_HTTP(u))
486 g_object_set(ws, prop, u, NULL);
487 else
488 luaL_error(L, "cannot parse uri: %s", tmp.c);
489 soup_uri_free(u);
490 return 0;
492 default:
493 warn("unknown property type for: %s", properties[i].name);
494 break;
497 warn("unknown property: %s", prop);
498 return 0;
501 static gint
502 luaH_webview_loading(lua_State *L)
504 widget_t *w = luaH_checkudata(L, 1, &widget_class);
505 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
506 WebKitLoadStatus s;
507 g_object_get(G_OBJECT(view), "load-status", &s, NULL);
508 switch (s) {
509 case WEBKIT_LOAD_PROVISIONAL:
510 case WEBKIT_LOAD_COMMITTED:
511 case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT:
512 lua_pushboolean(L, TRUE);
513 break;
515 default:
516 lua_pushboolean(L, FALSE);
517 break;
519 return 1;
522 void
523 show_scrollbars(widget_t *w, gboolean show)
525 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
526 WebKitWebFrame *mf = webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(view));
527 gulong id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(view), "hide_handler_id"));
529 if (show) {
530 if (id)
531 g_signal_handler_disconnect((gpointer) mf, id);
532 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
533 id = 0;
534 } else if (!id) {
535 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w->widget), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
536 id = g_signal_connect(G_OBJECT(mf), "scrollbars-policy-changed", G_CALLBACK(true_cb), NULL);
538 g_object_set_data(G_OBJECT(view), "hide_handler_id", GINT_TO_POINTER(id));
541 static gint
542 luaH_webview_index(lua_State *L, luakit_token_t token)
544 widget_t *w = luaH_checkudata(L, 1, &widget_class);
545 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
547 switch(token)
549 case L_TK_DESTROY:
550 lua_pushcfunction(L, luaH_widget_destroy);
551 return 1;
553 case L_TK_GET_SCROLL_VERT:
554 lua_pushcfunction(L, luaH_webview_get_vscroll);
555 return 1;
557 case L_TK_GET_SCROLL_HORIZ:
558 lua_pushcfunction(L, luaH_webview_get_hscroll);
559 return 1;
561 case L_TK_SET_SCROLL_VERT:
562 lua_pushcfunction(L, luaH_webview_set_scroll_vert);
563 return 1;
565 case L_TK_SET_SCROLL_HORIZ:
566 lua_pushcfunction(L, luaH_webview_set_scroll_horiz);
567 return 1;
569 case L_TK_SEARCH:
570 lua_pushcfunction(L, luaH_webview_search);
571 return 1;
573 case L_TK_CLEAR_SEARCH:
574 lua_pushcfunction(L, luaH_webview_clear_search);
575 return 1;
577 case L_TK_SET_PROP:
578 lua_pushcfunction(L, luaH_webview_set_prop);
579 return 1;
581 case L_TK_GET_PROP:
582 lua_pushcfunction(L, luaH_webview_get_prop);
583 return 1;
585 case L_TK_HOVERED_URI:
586 lua_pushstring(L, g_object_get_data(G_OBJECT(view), "hovered-uri"));
587 return 1;
589 case L_TK_URI:
590 lua_pushstring(L, g_object_get_data(G_OBJECT(view), "uri"));
591 return 1;
593 case L_TK_SHOW:
594 lua_pushcfunction(L, luaH_widget_show);
595 return 1;
597 case L_TK_HIDE:
598 lua_pushcfunction(L, luaH_widget_hide);
599 return 1;
601 case L_TK_FOCUS:
602 lua_pushcfunction(L, luaH_widget_focus);
603 return 1;
605 case L_TK_LOADING:
606 lua_pushcfunction(L, luaH_webview_loading);
607 return 1;
609 case L_TK_GO_BACK:
610 lua_pushcfunction(L, luaH_webview_go_back);
611 return 1;
613 case L_TK_GO_FORWARD:
614 lua_pushcfunction(L, luaH_webview_go_forward);
615 return 1;
617 default:
618 warn("unknown property: %s", luaL_checkstring(L, 2));
619 break;
622 return 0;
625 /* The __newindex method for the webview object */
626 static gint
627 luaH_webview_newindex(lua_State *L, luakit_token_t token)
629 size_t len;
630 widget_t *w = luaH_checkudata(L, 1, &widget_class);
631 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
632 gchar *uri;
634 switch(token)
636 case L_TK_URI:
637 uri = (gchar*) luaL_checklstring(L, 3, &len);
638 uri = g_strrstr(uri, "://") ? g_strdup(uri) :
639 g_strdup_printf("http://%s", uri);
640 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view), uri);
641 g_object_set_data_full(G_OBJECT(view), "uri", uri, g_free);
642 break;
644 case L_TK_SHOW_SCROLLBARS:
645 show_scrollbars(w, luaH_checkboolean(L, 3));
646 return 0;
648 default:
649 warn("unknown property: %s", luaL_checkstring(L, 2));
650 return 0;
653 return luaH_object_emit_property_signal(L, 1);
656 static gboolean
657 expose_cb(GtkWidget *widget, GdkEventExpose *e, widget_t *w)
659 (void) e;
660 (void) widget;
661 lua_State *L = globalconf.L;
662 luaH_object_push(L, w->ref);
663 luaH_object_emit_signal(L, -1, "expose", 0, 0);
664 lua_pop(L, 1);
665 return FALSE;
668 static gboolean
669 wv_button_press_cb(GtkWidget *view, GdkEventButton *event, widget_t *w)
671 if((event->type != GDK_BUTTON_PRESS) || (event->button != 1))
672 return FALSE;
674 /* get webview hit context */
675 WebKitHitTestResult *ht = webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(view), event);
676 guint c;
677 g_object_get(ht, "context", &c, NULL);
678 gint context = (gint) c;
680 lua_State *L = globalconf.L;
681 luaH_object_push(L, w->ref);
682 /* raise "form-active" when a user clicks on a form field and raise
683 * "root-active" when a user clicks elsewhere */
684 if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
685 luaH_object_emit_signal(L, -1, "form-active", 0, 0);
686 else if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)
687 luaH_object_emit_signal(L, -1, "root-active", 0, 0);
688 lua_pop(L, 1);
689 return FALSE;
692 static void
693 webview_destructor(widget_t *w)
695 GtkWidget *view = g_object_get_data(G_OBJECT(w->widget), "webview");
696 gtk_widget_destroy(GTK_WIDGET(view));
697 gtk_widget_destroy(GTK_WIDGET(w->widget));
700 widget_t *
701 widget_webview(widget_t *w)
703 w->index = luaH_webview_index;
704 w->newindex = luaH_webview_newindex;
705 w->destructor = webview_destructor;
707 /* init soup session & cookies handling */
708 if (!Soup.session) {
709 Soup.session = webkit_get_default_session();
710 gchar *cookie_file = g_build_filename(globalconf.base_data_directory, "cookies.txt", NULL);
711 Soup.cookiejar = soup_cookie_jar_text_new(cookie_file, FALSE);
712 soup_session_add_feature(Soup.session, (SoupSessionFeature*) Soup.cookiejar);
713 g_free(cookie_file);
716 GtkWidget *view = webkit_web_view_new();
717 w->widget = gtk_scrolled_window_new(NULL, NULL);
718 g_object_set_data(G_OBJECT(w->widget), "widget", w);
719 g_object_set_data(G_OBJECT(w->widget), "webview", view);
720 gtk_container_add(GTK_CONTAINER(w->widget), view);
722 show_scrollbars(w, TRUE);
724 /* connect webview signals */
725 g_object_connect((GObject*)view,
726 "signal::button-press-event", (GCallback)wv_button_press_cb, w,
727 "signal::expose-event", (GCallback)expose_cb, w,
728 "signal::focus-in-event", (GCallback)focus_cb, w,
729 "signal::focus-out-event", (GCallback)focus_cb, w,
730 "signal::hovering-over-link", (GCallback)link_hover_cb, w,
731 "signal::key-press-event", (GCallback)key_press_cb, w,
732 "signal::load-committed", (GCallback)load_commit_cb, w,
733 "signal::load-finished", (GCallback)load_finish_cb, w,
734 "signal::load-progress-changed", (GCallback)progress_cb, w,
735 "signal::load-started", (GCallback)load_start_cb, w,
736 "signal::navigation-policy-decision-requested", (GCallback)navigation_decision_cb, w,
737 "signal::parent-set", (GCallback)parent_set_cb, w,
738 "signal::title-changed", (GCallback)title_changed_cb, w,
739 NULL);
741 /* setup */
742 gtk_widget_show(view);
743 gtk_widget_show(w->widget);
745 return w;
748 // vim: ft=c:et:sw=4:ts=8:sts=4:tw=80