This allows this code to be compiled with WebKit2 2.6 included in Debian Jessie. Closes https://github.com/wxWidgets/wxWidgets/pull/519
431 lines
15 KiB
C++
431 lines
15 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/gtk/webview_webkit2_extension.cpp
|
|
// Purpose: GTK WebKit2 extension for web view component
|
|
// Author: Scott Talbert
|
|
// Copyright: (c) 2017 Scott Talbert
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wx/defs.h"
|
|
#include "wx/gtk/private/webview_webkit2_extension.h"
|
|
#include <webkit2/webkit-web-extension.h>
|
|
#define WEBKIT_DOM_USE_UNSTABLE_API
|
|
#include <webkitdom/WebKitDOMDOMSelection.h>
|
|
#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
|
|
|
|
static const char introspection_xml[] =
|
|
"<node>"
|
|
" <interface name='org.wxwidgets.wxGTK.WebExtension'>"
|
|
" <method name='ClearSelection'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" </method>"
|
|
" <method name='DeleteSelection'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" </method>"
|
|
" <method name='GetPageSource'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" <arg type='s' name='source' direction='out'/>"
|
|
" </method>"
|
|
" <method name='GetPageText'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" <arg type='s' name='text' direction='out'/>"
|
|
" </method>"
|
|
" <method name='GetSelectedSource'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" <arg type='s' name='source' direction='out'/>"
|
|
" </method>"
|
|
" <method name='GetSelectedText'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" <arg type='s' name='text' direction='out'/>"
|
|
" </method>"
|
|
" <method name='HasSelection'>"
|
|
" <arg type='t' name='page_id' direction='in'/>"
|
|
" <arg type='b' name='has_selection' direction='out'/>"
|
|
" </method>"
|
|
" </interface>"
|
|
"</node>";
|
|
|
|
class wxWebViewWebKitExtension;
|
|
|
|
static gboolean
|
|
wxgtk_webview_authorize_authenticated_peer_cb(GDBusAuthObserver *observer,
|
|
GIOStream *stream,
|
|
GCredentials *credentials,
|
|
wxWebViewWebKitExtension *extension);
|
|
static void
|
|
wxgtk_webview_dbus_connection_created_cb(GObject *source_object,
|
|
GAsyncResult *result,
|
|
wxWebViewWebKitExtension *extension);
|
|
|
|
static wxWebViewWebKitExtension *gs_extension = NULL;
|
|
|
|
class wxWebViewWebKitExtension
|
|
{
|
|
public:
|
|
wxWebViewWebKitExtension(WebKitWebExtension *webkit_extension, const char* server_address);
|
|
void ClearSelection(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void DeleteSelection(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void GetPageSource(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void GetPageText(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void GetSelectedSource(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void GetSelectedText(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void HasSelection(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void SetDBusConnection(GDBusConnection *dbusConnection);
|
|
|
|
private:
|
|
WebKitWebPage* GetWebPageOrReturnError(GVariant *parameters, GDBusMethodInvocation *invocation);
|
|
void ReturnDBusStringValue(GDBusMethodInvocation *invocation, gchar *value);
|
|
|
|
GDBusConnection *m_dbusConnection;
|
|
WebKitWebExtension *m_webkitExtension;
|
|
};
|
|
|
|
wxWebViewWebKitExtension::wxWebViewWebKitExtension(WebKitWebExtension *extension, const char* server_address)
|
|
{
|
|
m_webkitExtension = (WebKitWebExtension*)g_object_ref(extension);
|
|
|
|
GDBusAuthObserver *observer = g_dbus_auth_observer_new();
|
|
g_signal_connect(observer, "authorize-authenticated-peer",
|
|
G_CALLBACK(wxgtk_webview_authorize_authenticated_peer_cb),
|
|
this);
|
|
|
|
g_dbus_connection_new_for_address(server_address,
|
|
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
|
|
observer,
|
|
NULL,
|
|
(GAsyncReadyCallback)wxgtk_webview_dbus_connection_created_cb,
|
|
this);
|
|
g_object_unref(observer);
|
|
}
|
|
|
|
WebKitWebPage* wxWebViewWebKitExtension::GetWebPageOrReturnError(GVariant *parameters, GDBusMethodInvocation *invocation)
|
|
{
|
|
guint64 page_id;
|
|
g_variant_get(parameters, "(t)", &page_id);
|
|
WebKitWebPage *web_page = webkit_web_extension_get_page(m_webkitExtension,
|
|
page_id);
|
|
if (!web_page)
|
|
{
|
|
g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
|
|
G_DBUS_ERROR_INVALID_ARGS,
|
|
"Invalid page ID: %" G_GUINT64_FORMAT, page_id);
|
|
}
|
|
return web_page;
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::GetSelectedSource(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc);
|
|
WebKitDOMDOMSelection *sel = webkit_dom_dom_window_get_selection(win);
|
|
g_object_unref(win);
|
|
if (!sel)
|
|
{
|
|
ReturnDBusStringValue(invocation, NULL);
|
|
return;
|
|
}
|
|
WebKitDOMRange *range = webkit_dom_dom_selection_get_range_at(sel, 0, NULL);
|
|
if (!range)
|
|
{
|
|
ReturnDBusStringValue(invocation, NULL);
|
|
return;
|
|
}
|
|
WebKitDOMElement *div = webkit_dom_document_create_element(doc, "div",
|
|
NULL);
|
|
WebKitDOMDocumentFragment *clone = webkit_dom_range_clone_contents(range,
|
|
NULL);
|
|
webkit_dom_node_append_child(&div->parent_instance,
|
|
&clone->parent_instance, NULL);
|
|
WebKitDOMElement *html = (WebKitDOMElement*)div;
|
|
#if WEBKIT_CHECK_VERSION(2, 8, 0)
|
|
gchar *text = webkit_dom_element_get_inner_html(html);
|
|
#else
|
|
gchar *text = webkit_dom_html_element_get_inner_html(WEBKIT_DOM_HTML_ELEMENT(html));
|
|
#endif
|
|
g_object_unref(range);
|
|
|
|
ReturnDBusStringValue(invocation, text);
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::GetPageSource(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMElement *body = webkit_dom_document_get_document_element(doc);
|
|
#if WEBKIT_CHECK_VERSION(2, 8, 0)
|
|
gchar *source = webkit_dom_element_get_outer_html(body);
|
|
#else
|
|
gchar *source =
|
|
webkit_dom_html_element_get_outer_html(WEBKIT_DOM_HTML_ELEMENT(body));
|
|
#endif
|
|
g_dbus_method_invocation_return_value(invocation,
|
|
g_variant_new("(s)", source ? source : ""));
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::GetPageText(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMHTMLElement *body = webkit_dom_document_get_body(doc);
|
|
gchar *text = webkit_dom_html_element_get_inner_text(body);
|
|
g_dbus_method_invocation_return_value(invocation,
|
|
g_variant_new("(s)", text));
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::GetSelectedText(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc);
|
|
WebKitDOMDOMSelection *sel = webkit_dom_dom_window_get_selection(win);
|
|
g_object_unref(win);
|
|
if (!sel)
|
|
{
|
|
ReturnDBusStringValue(invocation, NULL);
|
|
return;
|
|
}
|
|
WebKitDOMRange *range = webkit_dom_dom_selection_get_range_at(sel, 0, NULL);
|
|
if (!range)
|
|
{
|
|
ReturnDBusStringValue(invocation, NULL);
|
|
return;
|
|
}
|
|
gchar *text = webkit_dom_range_get_text(range);
|
|
g_object_unref(range);
|
|
|
|
ReturnDBusStringValue(invocation, text);
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::ClearSelection(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc);
|
|
WebKitDOMDOMSelection *sel = webkit_dom_dom_window_get_selection(win);
|
|
g_object_unref(win);
|
|
if (sel)
|
|
{
|
|
webkit_dom_dom_selection_remove_all_ranges(sel);
|
|
}
|
|
|
|
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::HasSelection(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc);
|
|
WebKitDOMDOMSelection *sel = webkit_dom_dom_window_get_selection(win);
|
|
g_object_unref(win);
|
|
gboolean has_selection = FALSE;
|
|
if (WEBKIT_DOM_IS_DOM_SELECTION(sel))
|
|
{
|
|
if (!webkit_dom_dom_selection_get_is_collapsed(sel))
|
|
{
|
|
has_selection = TRUE;
|
|
}
|
|
}
|
|
g_dbus_method_invocation_return_value(invocation,
|
|
g_variant_new("(b)", has_selection));
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::DeleteSelection(GVariant *parameters,
|
|
GDBusMethodInvocation *invocation)
|
|
{
|
|
WebKitWebPage *web_page = GetWebPageOrReturnError(parameters, invocation);
|
|
if (!web_page)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WebKitDOMDocument *doc = webkit_web_page_get_dom_document(web_page);
|
|
WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc);
|
|
WebKitDOMDOMSelection *sel = webkit_dom_dom_window_get_selection(win);
|
|
g_object_unref(win);
|
|
if (sel)
|
|
{
|
|
webkit_dom_dom_selection_delete_from_document(sel);
|
|
}
|
|
|
|
g_dbus_method_invocation_return_value(invocation, NULL);
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::ReturnDBusStringValue(GDBusMethodInvocation *invocation, gchar *value)
|
|
{
|
|
g_dbus_method_invocation_return_value(invocation,
|
|
g_variant_new("(s)", value ? value : ""));
|
|
}
|
|
|
|
void wxWebViewWebKitExtension::SetDBusConnection(GDBusConnection *dbusConnection)
|
|
{
|
|
m_dbusConnection = dbusConnection;
|
|
}
|
|
|
|
static void
|
|
wxgtk_webview_handle_method_call(GDBusConnection *connection,
|
|
const char *sender,
|
|
const char *object_path,
|
|
const char *interface_name,
|
|
const char *method_name,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation,
|
|
gpointer user_data)
|
|
{
|
|
if (g_strcmp0(interface_name, WXGTK_WEB_EXTENSION_INTERFACE) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
wxWebViewWebKitExtension *extension = (wxWebViewWebKitExtension*)user_data;
|
|
|
|
if (g_strcmp0(method_name, "ClearSelection") == 0)
|
|
{
|
|
extension->ClearSelection(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "DeleteSelection") == 0)
|
|
{
|
|
extension->DeleteSelection(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "GetPageSource") == 0)
|
|
{
|
|
extension->GetPageSource(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "GetPageText") == 0)
|
|
{
|
|
extension->GetPageText(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "GetSelectedSource") == 0)
|
|
{
|
|
extension->GetSelectedSource(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "GetSelectedText") == 0)
|
|
{
|
|
extension->GetSelectedText(parameters, invocation);
|
|
}
|
|
else if (g_strcmp0(method_name, "HasSelection") == 0)
|
|
{
|
|
extension->HasSelection(parameters, invocation);
|
|
}
|
|
}
|
|
|
|
static const GDBusInterfaceVTable interface_vtable = {
|
|
wxgtk_webview_handle_method_call,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
gboolean
|
|
wxgtk_webview_dbus_peer_is_authorized(GCredentials *peer_credentials)
|
|
{
|
|
static GCredentials *own_credentials = g_credentials_new();
|
|
GError *error = NULL;
|
|
|
|
if (peer_credentials && g_credentials_is_same_user(peer_credentials, own_credentials, &error))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
g_warning("Failed to authorize web extension connection: %s", error->message);
|
|
g_error_free(error);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
wxgtk_webview_authorize_authenticated_peer_cb(GDBusAuthObserver *observer,
|
|
GIOStream *stream,
|
|
GCredentials *credentials,
|
|
wxWebViewWebKitExtension *extension)
|
|
{
|
|
return wxgtk_webview_dbus_peer_is_authorized(credentials);
|
|
}
|
|
|
|
static void
|
|
wxgtk_webview_dbus_connection_created_cb(GObject *source_object,
|
|
GAsyncResult *result,
|
|
wxWebViewWebKitExtension *extension)
|
|
{
|
|
static GDBusNodeInfo *introspection_data =
|
|
g_dbus_node_info_new_for_xml(introspection_xml, NULL);
|
|
|
|
GError *error = NULL;
|
|
GDBusConnection *connection =
|
|
g_dbus_connection_new_for_address_finish(result, &error);
|
|
if (error)
|
|
{
|
|
g_warning("Failed to connect to UI process: %s", error->message);
|
|
g_error_free(error);
|
|
return;
|
|
}
|
|
|
|
guint registration_id =
|
|
g_dbus_connection_register_object(connection,
|
|
WXGTK_WEB_EXTENSION_OBJECT_PATH,
|
|
introspection_data->interfaces[0],
|
|
&interface_vtable,
|
|
extension,
|
|
NULL,
|
|
&error);
|
|
if (!registration_id)
|
|
{
|
|
g_warning ("Failed to register web extension object: %s\n", error->message);
|
|
g_error_free (error);
|
|
g_object_unref (connection);
|
|
return;
|
|
}
|
|
|
|
extension->SetDBusConnection(connection);
|
|
}
|
|
|
|
extern "C" WXEXPORT void
|
|
webkit_web_extension_initialize_with_user_data (WebKitWebExtension *webkit_extension,
|
|
GVariant *user_data)
|
|
{
|
|
const char *server_address;
|
|
|
|
g_variant_get (user_data, "(&s)", &server_address);
|
|
|
|
gs_extension = new wxWebViewWebKitExtension(webkit_extension,
|
|
server_address);
|
|
}
|