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/>.
23 #include "widgets/common.h"
24 #include <JavaScriptCore/JavaScript.h>
25 #include <webkit/webkit.h>
26 #include <libsoup/soup.h>
31 SoupCookieJar
*cookiejar
;
32 } Soup
= { NULL
, NULL
};
57 GHashTable
*properties
= NULL
;
61 property_value_t type
;
67 property_t properties_table
[] = {
68 { "accept-language", CHAR
, SOUPSESSION
, TRUE
, NULL
},
69 { "accept-language-auto", BOOL
, SOUPSESSION
, TRUE
, NULL
},
70 { "auto-load-images", BOOL
, SETTINGS
, TRUE
, NULL
},
71 { "auto-resize-window", BOOL
, SETTINGS
, TRUE
, NULL
},
72 { "auto-shrink-images", BOOL
, SETTINGS
, TRUE
, NULL
},
73 { "cursive-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
74 { "custom-encoding", CHAR
, WEBKITVIEW
, TRUE
, NULL
},
75 { "default-encoding", CHAR
, SETTINGS
, TRUE
, NULL
},
76 { "default-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
77 { "default-font-size", INT
, SETTINGS
, TRUE
, NULL
},
78 { "default-monospace-font-size", INT
, SETTINGS
, TRUE
, NULL
},
79 { "editable", BOOL
, WEBKITVIEW
, TRUE
, NULL
},
80 { "enable-caret-browsing", BOOL
, SETTINGS
, TRUE
, NULL
},
81 { "enable-default-context-menu", BOOL
, SETTINGS
, TRUE
, NULL
},
82 { "enable-developer-extras", BOOL
, SETTINGS
, TRUE
, NULL
},
83 { "enable-dom-paste", BOOL
, SETTINGS
, TRUE
, NULL
},
84 { "enable-file-access-from-file-uris", BOOL
, SETTINGS
, TRUE
, NULL
},
85 { "enable-html5-database", BOOL
, SETTINGS
, TRUE
, NULL
},
86 { "enable-html5-local-storage", BOOL
, SETTINGS
, TRUE
, NULL
},
87 { "enable-java-applet", BOOL
, SETTINGS
, TRUE
, NULL
},
88 { "enable-offline-web-application-cache", BOOL
, SETTINGS
, TRUE
, NULL
},
89 { "enable-page-cache", BOOL
, SETTINGS
, TRUE
, NULL
},
90 { "enable-plugins", BOOL
, SETTINGS
, TRUE
, NULL
},
91 { "enable-private-browsing", BOOL
, SETTINGS
, TRUE
, NULL
},
92 { "enable-scripts", BOOL
, SETTINGS
, TRUE
, NULL
},
93 { "enable-site-specific-quirks", BOOL
, SETTINGS
, TRUE
, NULL
},
94 { "enable-spatial-navigation", BOOL
, SETTINGS
, TRUE
, NULL
},
95 { "enable-spell-checking", BOOL
, SETTINGS
, TRUE
, NULL
},
96 { "enable-universal-access-from-file-uris", BOOL
, SETTINGS
, TRUE
, NULL
},
97 { "enable-xss-auditor", BOOL
, SETTINGS
, TRUE
, NULL
},
98 { "encoding", CHAR
, WEBKITVIEW
, FALSE
, NULL
},
99 { "enforce-96-dpi", BOOL
, SETTINGS
, TRUE
, NULL
},
100 { "fantasy-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
101 { "full-content-zoom", BOOL
, WEBKITVIEW
, TRUE
, NULL
},
102 { "icon-uri", CHAR
, WEBKITVIEW
, FALSE
, NULL
},
103 { "idle-timeout", INT
, SOUPSESSION
, TRUE
, NULL
},
104 { "javascript-can-access-clipboard", BOOL
, SETTINGS
, TRUE
, NULL
},
105 { "javascript-can-open-windows-automatically", BOOL
, SETTINGS
, TRUE
, NULL
},
106 { "max-conns", INT
, SOUPSESSION
, TRUE
, NULL
},
107 { "max-conns-per-host", INT
, SOUPSESSION
, TRUE
, NULL
},
108 { "minimum-font-size", INT
, SETTINGS
, TRUE
, NULL
},
109 { "minimum-logical-font-size", INT
, SETTINGS
, TRUE
, NULL
},
110 { "monospace-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
111 { "print-backgrounds", BOOL
, SETTINGS
, TRUE
, NULL
},
112 { "progress", DOUBLE
, WEBKITVIEW
, FALSE
, NULL
},
113 { "proxy-uri", URI
, SOUPSESSION
, TRUE
, NULL
},
114 { "resizable-text-areas", BOOL
, SETTINGS
, TRUE
, NULL
},
115 { "sans-serif-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
116 { "serif-font-family", CHAR
, SETTINGS
, TRUE
, NULL
},
117 { "spell-checking-languages", CHAR
, SETTINGS
, TRUE
, NULL
},
118 { "ssl-ca-file", CHAR
, SOUPSESSION
, TRUE
, NULL
},
119 { "ssl-strict", BOOL
, SOUPSESSION
, TRUE
, NULL
},
120 { "tab-key-cycles-through-elements", BOOL
, SETTINGS
, TRUE
, NULL
},
121 { "timeout", INT
, SOUPSESSION
, TRUE
, NULL
},
122 { "title", CHAR
, WEBKITVIEW
, FALSE
, NULL
},
123 { "transparent", BOOL
, WEBKITVIEW
, TRUE
, NULL
},
124 { "uri", CHAR
, WEBKITVIEW
, TRUE
, NULL
},
125 { "use-ntlm", BOOL
, SOUPSESSION
, TRUE
, NULL
},
126 { "user-agent", CHAR
, SETTINGS
, TRUE
, NULL
},
127 { "user-stylesheet-uri", CHAR
, SETTINGS
, TRUE
, NULL
},
128 { "zoom-level", FLOAT
, WEBKITVIEW
, TRUE
, NULL
},
129 { "zoom-step", FLOAT
, SETTINGS
, TRUE
, NULL
},
130 { NULL
, 0, 0, 0, NULL
},
134 webview_init_properties() {
135 properties
= g_hash_table_new(g_str_hash
, g_str_equal
);
136 for (property_t
*p
= properties_table
; p
->name
; p
++) {
137 /* pre-compile "property::name" signals for each property */
138 if (!p
->signame
) p
->signame
= g_strdup_printf("property::%s", p
->name
);
139 g_hash_table_insert(properties
, (gpointer
) p
->name
, (gpointer
) p
);
144 webview_eval_js(WebKitWebView
*view
, const gchar
*script
, const gchar
*file
) {
145 WebKitWebFrame
*frame
;
146 JSGlobalContextRef context
;
147 JSObjectRef globalobject
;
149 JSStringRef js_script
;
150 JSValueRef js_result
;
151 JSValueRef js_exc
= NULL
;
152 JSStringRef js_result_string
;
153 GString
*result
= g_string_new(NULL
);
154 size_t js_result_size
;
156 frame
= webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(view
));
157 context
= webkit_web_frame_get_global_context(frame
);
158 globalobject
= JSContextGetGlobalObject(context
);
160 /* evaluate the script and get return value*/
161 js_script
= JSStringCreateWithUTF8CString(script
);
162 js_file
= JSStringCreateWithUTF8CString(file
);
163 js_result
= JSEvaluateScript(context
, js_script
, globalobject
, js_file
, 0, &js_exc
);
164 if (js_result
&& !JSValueIsUndefined(context
, js_result
)) {
165 js_result_string
= JSValueToStringCopy(context
, js_result
, NULL
);
166 js_result_size
= JSStringGetMaximumUTF8CStringSize(js_result_string
);
168 if (js_result_size
) {
169 char js_result_utf8
[js_result_size
];
170 JSStringGetUTF8CString(js_result_string
, js_result_utf8
, js_result_size
);
171 g_string_assign(result
, js_result_utf8
);
174 JSStringRelease(js_result_string
);
178 JSStringRef prop
, val
;
179 JSObjectRef exc
= JSValueToObject(context
, js_exc
, NULL
);
181 printf("Exception occured while executing script:\n");
184 prop
= JSStringCreateWithUTF8CString("sourceURL");
185 val
= JSValueToStringCopy(context
, JSObjectGetProperty(context
, exc
, prop
, NULL
), NULL
);
186 size
= JSStringGetMaximumUTF8CStringSize(val
);
189 JSStringGetUTF8CString(val
, cstr
, size
);
190 printf("At %s", cstr
);
192 JSStringRelease(prop
);
193 JSStringRelease(val
);
196 prop
= JSStringCreateWithUTF8CString("line");
197 val
= JSValueToStringCopy(context
, JSObjectGetProperty(context
, exc
, prop
, NULL
), NULL
);
198 size
= JSStringGetMaximumUTF8CStringSize(val
);
201 JSStringGetUTF8CString(val
, cstr
, size
);
202 printf(":%s: ", cstr
);
204 JSStringRelease(prop
);
205 JSStringRelease(val
);
208 val
= JSValueToStringCopy(context
, exc
, NULL
);
209 size
= JSStringGetMaximumUTF8CStringSize(val
);
212 JSStringGetUTF8CString(val
, cstr
, size
);
213 printf("%s\n", cstr
);
215 JSStringRelease(val
);
219 JSStringRelease(js_script
);
220 JSStringRelease(js_file
);
222 return g_string_free(result
, FALSE
);
226 luaH_webview_eval_js(lua_State
*L
)
228 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
229 WebKitWebView
*view
= WEBKIT_WEB_VIEW(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
230 const gchar
*script
= luaL_checkstring(L
, 2);
231 const gchar
*filename
= luaL_checkstring(L
, 3);
233 /* evaluate javascript script and push return result onto lua stack */
234 const gchar
*result
= webview_eval_js(view
, script
, filename
);
235 lua_pushstring(L
, result
);
240 notify_cb(WebKitWebView
*v
, GParamSpec
*ps
, widget_t
*w
)
244 /* emit "property::name" signal if found in properties table */
245 if ((p
= g_hash_table_lookup(properties
, ps
->name
))) {
246 lua_State
*L
= globalconf
.L
;
247 luaH_object_push(L
, w
->ref
);
248 luaH_object_emit_signal(L
, -1, p
->signame
, 0, 0);
254 notify_load_status_cb(WebKitWebView
*v
, GParamSpec
*ps
, widget_t
*w
)
258 /* Get load status */
259 WebKitLoadStatus status
;
260 g_object_get(G_OBJECT(v
), "load-status", &status
, NULL
);
262 /* get load status literal */
266 #define LT_CASE(a, l) case WEBKIT_LOAD_##a: name = l; break;
267 LT_CASE(PROVISIONAL
, "provisional")
268 LT_CASE(COMMITTED
, "committed")
269 LT_CASE(FINISHED
, "finished")
270 LT_CASE(FIRST_VISUALLY_NON_EMPTY_LAYOUT
, "first-visual")
271 LT_CASE(FAILED
, "failed")
275 warn("programmer error, unable to get load status literal");
279 lua_State
*L
= globalconf
.L
;
280 luaH_object_push(L
, w
->ref
);
281 lua_pushstring(L
, name
);
282 luaH_object_emit_signal(L
, -2, "load-status", 1, 0);
287 mime_type_decision_cb(WebKitWebView
*v
, WebKitWebFrame
*f
,
288 WebKitNetworkRequest
*r
, gchar
*mime
, WebKitWebPolicyDecision
*pd
,
293 lua_State
*L
= globalconf
.L
;
294 const gchar
*uri
= webkit_network_request_get_uri(r
);
297 luaH_object_push(L
, w
->ref
);
298 lua_pushstring(L
, uri
);
299 lua_pushstring(L
, mime
);
300 ret
= luaH_object_emit_signal(L
, -3, "mime-type-decision", 2, 1);
302 if (ret
&& !luaH_checkboolean(L
, -1))
303 /* User responded with false, ignore request */
304 webkit_web_policy_decision_ignore(pd
);
305 else if (!webkit_web_view_can_show_mime_type(v
, mime
))
306 webkit_web_policy_decision_download(pd
);
308 webkit_web_policy_decision_use(pd
);
315 new_window_decision_cb(WebKitWebView
*v
, WebKitWebFrame
*f
,
316 WebKitNetworkRequest
*r
, WebKitWebNavigationAction
*na
,
317 WebKitWebPolicyDecision
*pd
, widget_t
*w
)
321 lua_State
*L
= globalconf
.L
;
322 const gchar
*uri
= webkit_network_request_get_uri(r
);
323 gchar
*reason
= NULL
;
326 luaH_object_push(L
, w
->ref
);
327 lua_pushstring(L
, uri
);
329 switch (webkit_web_navigation_action_get_reason(na
)) {
331 #define NR_CASE(a, l) case WEBKIT_WEB_NAVIGATION_REASON_##a: reason = l; break;
332 NR_CASE(LINK_CLICKED
, "link-clicked");
333 NR_CASE(FORM_SUBMITTED
, "form-submitted");
334 NR_CASE(BACK_FORWARD
, "back-forward");
335 NR_CASE(RELOAD
, "reload");
336 NR_CASE(FORM_RESUBMITTED
, "form-resubmitted");
337 NR_CASE(OTHER
, "other");
341 warn("programmer error, unable to get web navigation reason literal");
345 lua_pushstring(L
, reason
);
346 ret
= luaH_object_emit_signal(L
, -3, "new-window-decision", 2, 1);
348 /* User responded with true, meaning a decision was made
349 * and the signal was handled */
350 if (ret
&& luaH_checkboolean(L
, -1))
352 webkit_web_policy_decision_ignore(pd
);
360 /* proceed with default behaviour */
364 static WebKitWebView
*
365 create_web_view_cb(WebKitWebView
*v
, WebKitWebFrame
*f
, widget_t
*w
)
371 WebKitWebView
*view
= NULL
;
374 lua_State
*L
= globalconf
.L
;
375 luaH_object_push(L
, w
->ref
);
377 ret
= luaH_object_emit_signal(L
, top
, "create-web-view", 0, 1);
378 if (ret
&& (new = luaH_checkudata(L
, top
+ 1, &widget_class
)))
379 view
= WEBKIT_WEB_VIEW(g_object_get_data(G_OBJECT(new->widget
), "webview"));
385 download_request_cb(WebKitWebView
*v
, GObject
*dl
, widget_t
*w
)
388 const gchar
*uri
= webkit_download_get_uri((WebKitDownload
*) dl
);
389 const gchar
*filename
= webkit_download_get_suggested_filename((WebKitDownload
*) dl
);
391 lua_State
*L
= globalconf
.L
;
392 luaH_object_push(L
, w
->ref
);
393 lua_pushstring(L
, uri
);
394 lua_pushstring(L
, filename
);
395 luaH_object_emit_signal(L
, -3, "download-request", 2, 0);
402 link_hover_cb(WebKitWebView
*view
, const char *t
, const gchar
*link
, widget_t
*w
)
405 lua_State
*L
= globalconf
.L
;
406 GObject
*ws
= G_OBJECT(view
);
407 gchar
*last_hover
= g_object_get_data(ws
, "hovered-uri");
409 /* links are identical, do nothing */
410 if (last_hover
&& !g_strcmp0(last_hover
, link
))
413 luaH_object_push(L
, w
->ref
);
416 lua_pushstring(L
, last_hover
);
417 g_object_set_data(ws
, "hovered-uri", NULL
);
418 luaH_object_emit_signal(L
, -2, "link-unhover", 1, 0);
422 lua_pushstring(L
, link
);
423 g_object_set_data_full(ws
, "hovered-uri", g_strdup(link
), g_free
);
424 luaH_object_emit_signal(L
, -2, "link-hover", 1, 0);
427 luaH_object_emit_signal(L
, -1, "property::hovered_uri", 0, 0);
431 /* Raises the "navigation-request" signal on a webkit navigation policy
432 * decision request. The default action is to load the requested uri.
434 * The signal handler is able to:
435 * - return true for the handler execution to stop and the request to continue
436 * - return false for the handler execution to stop and the request to hault
437 * - do nothing and give the navigation decision to the next signal handler
439 * This signal is also where you would attach custom scheme handlers to take
440 * over the navigation request by launching an external application.
443 navigation_decision_cb(WebKitWebView
*v
, WebKitWebFrame
*f
,
444 WebKitNetworkRequest
*r
, WebKitWebNavigationAction
*a
,
445 WebKitWebPolicyDecision
*p
, widget_t
*w
)
451 lua_State
*L
= globalconf
.L
;
452 const gchar
*uri
= webkit_network_request_get_uri(r
);
455 luaH_object_push(L
, w
->ref
);
456 lua_pushstring(L
, uri
);
457 ret
= luaH_object_emit_signal(L
, -2, "navigation-request", 1, 1);
459 if (ret
&& !luaH_checkboolean(L
, -1))
460 /* User responded with false, do not continue navigation request */
461 webkit_web_policy_decision_ignore(p
);
463 webkit_web_policy_decision_use(p
);
470 luaH_adjustment_push_values(lua_State
*L
, GtkAdjustment
*a
)
472 gdouble view_size
= gtk_adjustment_get_page_size(a
);
473 gdouble value
= gtk_adjustment_get_value(a
);
474 gdouble max
= gtk_adjustment_get_upper(a
) - view_size
;
475 lua_pushnumber(L
, value
);
476 lua_pushnumber(L
, (max
< 0 ? 0 : max
));
477 lua_pushnumber(L
, view_size
);
482 luaH_webview_get_vscroll(lua_State
*L
)
484 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
485 GtkAdjustment
*a
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(w
->widget
));
486 return luaH_adjustment_push_values(L
, a
);
490 luaH_webview_get_hscroll(lua_State
*L
)
492 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
493 GtkAdjustment
*a
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(w
->widget
));
494 return luaH_adjustment_push_values(L
, a
);
498 adjustment_set(GtkAdjustment
*a
, gdouble
new)
500 gdouble view_size
= gtk_adjustment_get_page_size(a
);
501 gdouble max
= gtk_adjustment_get_upper(a
) - view_size
;
502 gtk_adjustment_set_value(a
, ((new < 0 ? 0 : new) > max
? max
: new));
506 luaH_webview_set_scroll_vert(lua_State
*L
)
508 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
509 gdouble value
= (gdouble
) luaL_checknumber(L
, 2);
510 GtkAdjustment
*a
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(w
->widget
));
511 adjustment_set(a
, value
);
516 luaH_webview_set_scroll_horiz(lua_State
*L
)
518 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
519 gdouble value
= (gdouble
) luaL_checknumber(L
, 2);
520 GtkAdjustment
*a
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(w
->widget
));
521 adjustment_set(a
, value
);
526 luaH_webview_go_back(lua_State
*L
)
528 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
529 gint steps
= (gint
) luaL_checknumber(L
, 2);
530 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
531 webkit_web_view_go_back_or_forward(WEBKIT_WEB_VIEW(view
), steps
* -1);
536 luaH_webview_go_forward(lua_State
*L
)
538 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
539 gint steps
= (gint
) luaL_checknumber(L
, 2);
540 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
541 webkit_web_view_go_back_or_forward(WEBKIT_WEB_VIEW(view
), steps
);
546 luaH_webview_get_view_source(lua_State
*L
)
548 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
549 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
550 lua_pushboolean(L
, webkit_web_view_get_view_source_mode(WEBKIT_WEB_VIEW(view
)));
555 luaH_webview_set_view_source(lua_State
*L
)
558 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
559 gboolean show
= luaH_checkboolean(L
, 2);
560 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
561 webkit_web_view_set_view_source_mode(WEBKIT_WEB_VIEW(view
), show
);
562 if ((uri
= webkit_web_view_get_uri(WEBKIT_WEB_VIEW(view
))))
563 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view
), uri
);
568 luaH_webview_reload(lua_State
*L
)
570 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
571 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
572 webkit_web_view_reload(WEBKIT_WEB_VIEW(view
));
577 luaH_webview_search(lua_State
*L
)
579 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
580 WebKitWebView
*view
= WEBKIT_WEB_VIEW(GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview")));
581 const gchar
*text
= luaL_checkstring(L
, 2);
582 gboolean case_sensitive
= luaH_checkboolean(L
, 3);
583 gboolean forward
= luaH_checkboolean(L
, 4);
584 gboolean wrap
= luaH_checkboolean(L
, 5);
586 webkit_web_view_unmark_text_matches(view
);
587 webkit_web_view_search_text(view
, text
, case_sensitive
, forward
, wrap
);
588 webkit_web_view_mark_text_matches(view
, text
, case_sensitive
, 0);
589 webkit_web_view_set_highlight_text_matches(view
, TRUE
);
594 luaH_webview_clear_search(lua_State
*L
)
596 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
597 WebKitWebView
*view
= WEBKIT_WEB_VIEW(GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview")));
598 webkit_web_view_unmark_text_matches(view
);
602 inline static GObject
*
603 get_settings_object(GtkWidget
*view
, property_t
*p
)
607 return G_OBJECT(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(view
)));
609 return G_OBJECT(view
);
611 return G_OBJECT(Soup
.session
);
615 warn("programmer error: unknown settings scope for property: %s", p
->name
);
620 luaH_webview_get_prop(lua_State
*L
)
627 /* get webview widget */
628 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
629 GtkWidget
*view
= GTK_WIDGET(g_object_get_data(G_OBJECT(w
->widget
), "webview"));
631 /* get property struct */
632 const gchar
*name
= luaL_checkstring(L
, 2);
633 if ((p
= g_hash_table_lookup(properties
, name
))) {
634 so
= get_settings_object(view
, p
);
638 g_object_get(so
, p
->name
, &tmp
.b
, NULL
);
639 lua_pushboolean(L
, tmp
.b
);
643 g_object_get(so
, p
->name
, &tmp
.i
, NULL
);
644 lua_pushnumber(L
, tmp
.i
);
648 g_object_get(so
, p
->name
, &tmp
.f
, NULL
);
649 lua_pushnumber(L
, tmp
.f
);
653 g_object_get(so
, p
->name
, &tmp
.d
, NULL
);
654 lua_pushnumber(L
, tmp
.d
);
658 g_object_get(so
, p
->name
, &tmp
.c
, NULL
);
659 lua_pushstring(L
, tmp
.c
);
664 g_object_get(so
, p
->name
, &u
, NULL
);
665 tmp
.c
= soup_uri_to_string(u
, 0);
666 lua_pushstring(L
, tmp
.c
);
672 warn("programmer error: unknown property type for: %s", p
->name
);
676 warn("unknown property: %s", name
);
681 luaH_webview_set_prop(lua_State
*L
)
689 /* get webview widget */
690 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
691 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
693 /* get property struct */
694 const gchar
*name
= luaL_checkstring(L
, 2);
695 if ((p
= g_hash_table_lookup(properties
, name
))) {
697 warn("attempt to set read-only property: %s", p
->name
);
701 so
= get_settings_object(view
, p
);
704 tmp
.b
= luaH_checkboolean(L
, 3);
705 g_object_set(so
, p
->name
, tmp
.b
, NULL
);
709 tmp
.i
= (gint
) luaL_checknumber(L
, 3);
710 g_object_set(so
, p
->name
, tmp
.i
, NULL
);
714 tmp
.f
= (gfloat
) luaL_checknumber(L
, 3);
715 g_object_set(so
, p
->name
, tmp
.f
, NULL
);
719 tmp
.d
= (gdouble
) luaL_checknumber(L
, 3);
720 g_object_set(so
, p
->name
, tmp
.d
, NULL
);
724 tmp
.c
= (gchar
*) luaL_checkstring(L
, 3);
725 g_object_set(so
, p
->name
, tmp
.c
, NULL
);
729 tmp
.c
= (gchar
*) luaL_checklstring(L
, 3, &len
);
730 if (!len
|| g_strrstr(tmp
.c
, "://"))
731 tmp
.c
= g_strdup(tmp
.c
);
733 tmp
.c
= g_strdup_printf("http://%s", tmp
.c
);
734 u
= soup_uri_new(tmp
.c
);
735 if (!u
|| SOUP_URI_VALID_FOR_HTTP(u
))
736 g_object_set(so
, p
->name
, u
, NULL
);
738 luaL_error(L
, "cannot parse uri: %s", tmp
.c
);
739 if (u
) soup_uri_free(u
);
744 warn("programmer error: unknown property type for: %s", p
->name
);
748 warn("unknown property: %s", name
);
753 luaH_webview_loading(lua_State
*L
)
755 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
756 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
758 g_object_get(G_OBJECT(view
), "load-status", &s
, NULL
);
760 case WEBKIT_LOAD_PROVISIONAL
:
761 case WEBKIT_LOAD_COMMITTED
:
762 case WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT
:
763 lua_pushboolean(L
, TRUE
);
767 lua_pushboolean(L
, FALSE
);
774 show_scrollbars(widget_t
*w
, gboolean show
)
776 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
777 WebKitWebFrame
*mf
= webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(view
));
778 gulong id
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(view
), "hide_handler_id"));
782 g_signal_handler_disconnect((gpointer
) mf
, id
);
783 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w
->widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
786 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(w
->widget
), GTK_POLICY_NEVER
, GTK_POLICY_NEVER
);
787 id
= g_signal_connect(G_OBJECT(mf
), "scrollbars-policy-changed", G_CALLBACK(true_cb
), NULL
);
789 g_object_set_data(G_OBJECT(view
), "hide_handler_id", GINT_TO_POINTER(id
));
793 luaH_webview_index(lua_State
*L
, luakit_token_t token
)
795 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
796 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
801 LUAKIT_WIDGET_INDEX_COMMON
803 /* push property methods */
804 PF_CASE(GET_PROP
, luaH_webview_get_prop
)
805 PF_CASE(SET_PROP
, luaH_webview_set_prop
)
806 /* push scroll adjustment methods */
807 PF_CASE(GET_SCROLL_HORIZ
, luaH_webview_get_hscroll
)
808 PF_CASE(GET_SCROLL_VERT
, luaH_webview_get_vscroll
)
809 PF_CASE(SET_SCROLL_HORIZ
, luaH_webview_set_scroll_horiz
)
810 PF_CASE(SET_SCROLL_VERT
, luaH_webview_set_scroll_vert
)
811 /* push search methods */
812 PF_CASE(CLEAR_SEARCH
, luaH_webview_clear_search
)
813 PF_CASE(SEARCH
, luaH_webview_search
)
814 /* push history navigation methods */
815 PF_CASE(GO_BACK
, luaH_webview_go_back
)
816 PF_CASE(GO_FORWARD
, luaH_webview_go_forward
)
817 /* push misc webview methods */
818 PF_CASE(EVAL_JS
, luaH_webview_eval_js
)
819 PF_CASE(LOADING
, luaH_webview_loading
)
820 PF_CASE(RELOAD
, luaH_webview_reload
)
821 /* push source viewing methods */
822 PF_CASE(GET_VIEW_SOURCE
, luaH_webview_get_view_source
)
823 PF_CASE(SET_VIEW_SOURCE
, luaH_webview_set_view_source
)
825 /* push string properties */
826 PS_CASE(HOVERED_URI
, g_object_get_data(G_OBJECT(view
), "hovered-uri"))
829 g_object_get(G_OBJECT(view
), "uri", &tmp
.c
, NULL
);
830 lua_pushstring(L
, tmp
.c
);
835 warn("unknown property: %s", luaL_checkstring(L
, 2));
842 /* The __newindex method for the webview object */
844 luaH_webview_newindex(lua_State
*L
, luakit_token_t token
)
847 widget_t
*w
= luaH_checkudata(L
, 1, &widget_class
);
848 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
854 tmp
.c
= (gchar
*) luaL_checklstring(L
, 3, &len
);
855 if (g_strrstr(tmp
.c
, "://") || !g_strcmp0(tmp
.c
, "about:blank"))
856 tmp
.c
= g_strdup(tmp
.c
);
858 tmp
.c
= g_strdup_printf("http://%s", tmp
.c
);
859 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(view
), tmp
.c
);
863 case L_TK_SHOW_SCROLLBARS
:
864 show_scrollbars(w
, luaH_checkboolean(L
, 3));
868 warn("unknown property: %s", luaL_checkstring(L
, 2));
872 return luaH_object_emit_property_signal(L
, 1);
876 expose_cb(GtkWidget
*widget
, GdkEventExpose
*e
, widget_t
*w
)
880 lua_State
*L
= globalconf
.L
;
881 luaH_object_push(L
, w
->ref
);
882 luaH_object_emit_signal(L
, -1, "expose", 0, 0);
888 wv_button_press_cb(GtkWidget
*view
, GdkEventButton
*ev
, widget_t
*w
)
890 if((ev
->type
!= GDK_BUTTON_PRESS
) || (ev
->button
!= 1))
893 /* get webview hit context */
894 WebKitHitTestResult
*ht
= webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(view
), ev
);
896 g_object_get(ht
, "context", &c
, NULL
);
897 gint context
= (gint
) c
;
899 lua_State
*L
= globalconf
.L
;
900 luaH_object_push(L
, w
->ref
);
901 /* raise "form-active" when a user clicks on a form field and raise
902 * "root-active" when a user clicks elsewhere */
903 if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE
)
904 luaH_object_emit_signal(L
, -1, "form-active", 0, 0);
905 else if (context
& WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT
)
906 luaH_object_emit_signal(L
, -1, "root-active", 0, 0);
912 webview_destructor(widget_t
*w
)
914 GtkWidget
*view
= g_object_get_data(G_OBJECT(w
->widget
), "webview");
915 gtk_widget_destroy(GTK_WIDGET(view
));
916 gtk_widget_destroy(GTK_WIDGET(w
->widget
));
920 widget_webview(widget_t
*w
)
922 w
->index
= luaH_webview_index
;
923 w
->newindex
= luaH_webview_newindex
;
924 w
->destructor
= webview_destructor
;
926 /* init properties hash table */
928 webview_init_properties();
930 /* init soup session & cookies handling */
932 Soup
.session
= webkit_get_default_session();
933 gchar
*cookie_file
= g_build_filename(globalconf
.data_dir
, "cookies.txt", NULL
);
934 Soup
.cookiejar
= soup_cookie_jar_text_new(cookie_file
, FALSE
);
935 soup_session_add_feature(Soup
.session
, (SoupSessionFeature
*) Soup
.cookiejar
);
939 GtkWidget
*view
= webkit_web_view_new();
940 w
->widget
= gtk_scrolled_window_new(NULL
, NULL
);
941 g_object_set_data(G_OBJECT(w
->widget
), "widget", w
);
942 g_object_set_data(G_OBJECT(w
->widget
), "webview", view
);
943 gtk_container_add(GTK_CONTAINER(w
->widget
), view
);
945 /* set initial scrollbars state */
946 show_scrollbars(w
, TRUE
);
948 /* connect webview signals */
949 g_object_connect((GObject
*)view
,
950 "signal::button-press-event", (GCallback
)wv_button_press_cb
, w
,
951 "signal::button-release-event", (GCallback
)button_release_cb
, w
,
952 "signal::create-web-view", (GCallback
)create_web_view_cb
, w
,
953 "signal::download-requested", (GCallback
)download_request_cb
, w
,
954 "signal::expose-event", (GCallback
)expose_cb
, w
,
955 "signal::focus-in-event", (GCallback
)focus_cb
, w
,
956 "signal::focus-out-event", (GCallback
)focus_cb
, w
,
957 "signal::hovering-over-link", (GCallback
)link_hover_cb
, w
,
958 "signal::key-press-event", (GCallback
)key_press_cb
, w
,
959 "signal::mime-type-policy-decision-requested", (GCallback
)mime_type_decision_cb
, w
,
960 "signal::navigation-policy-decision-requested", (GCallback
)navigation_decision_cb
, w
,
961 "signal::new-window-policy-decision-requested", (GCallback
)new_window_decision_cb
, w
,
962 "signal::notify", (GCallback
)notify_cb
, w
,
963 "signal::notify::load-status", (GCallback
)notify_load_status_cb
, w
,
964 "signal::parent-set", (GCallback
)parent_set_cb
, w
,
968 gtk_widget_show(view
);
969 gtk_widget_show(w
->widget
);
974 // vim: ft=c:et:sw=4:ts=8:sts=4:tw=80