diff --git a/docs/changes.txt b/docs/changes.txt index 6ad30469d8..9eb241556d 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -209,6 +209,7 @@ wxGTK: - Implement ShowPosition() for single-line wxTextCtrl. - Improve wx{Client,Paint,Screen,Window}DC::GetPPI() (GTK+ 3). - Suppress focus loss events for wxChoice and wxComboBox on opening popup. +- Make custom URI schemes work WebKit2-based wxWebView (Scott Talbert). wxMSW: diff --git a/include/wx/gtk/private/error.h b/include/wx/gtk/private/error.h index e3b49475b7..25802dd6f3 100644 --- a/include/wx/gtk/private/error.h +++ b/include/wx/gtk/private/error.h @@ -21,6 +21,7 @@ class wxGtkError { public: wxGtkError() { m_error = NULL; } + explicit wxGtkError(GError* error) { m_error = error; } ~wxGtkError() { if ( m_error ) g_error_free(m_error); } GError** Out() @@ -37,6 +38,11 @@ public: return m_error != NULL; } + operator GError*() const + { + return m_error; + } + wxString GetMessage() const { return wxString::FromUTF8(m_error->message); diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index c65c41c3ad..cc495dea75 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -67,7 +67,7 @@ wxgtk_webview_webkit_load_changed(GtkWidget *, } static gboolean -wxgtk_webview_webkit_navigation(WebKitWebView *web_view, +wxgtk_webview_webkit_navigation(WebKitWebView *, WebKitPolicyDecision *decision, wxWebViewWebKit *webKitCtrl) { @@ -93,16 +93,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view, return TRUE; } - if(webKitCtrl->m_guard) - { - webKitCtrl->m_guard = false; - //We set this to make sure that we don't try to load the page again from - //the resource request callback - webKitCtrl->m_vfsurl = webkit_web_view_get_uri(web_view); - webkit_policy_decision_use(decision); - return FALSE; - } - webKitCtrl->m_busy = true; wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING, @@ -120,32 +110,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view, } else { - wxString wxuri = uri; - wxSharedPtr handler; - wxVector > handlers = webKitCtrl->GetHandlers(); - //We are not vetoed so see if we match one of the additional handlers - for(wxVector >::iterator it = handlers.begin(); - it != handlers.end(); ++it) - { - if(wxuri.substr(0, (*it)->GetName().length()) == (*it)->GetName()) - { - handler = (*it); - } - } - //If we found a handler we can then use it to load the file directly - //ourselves - if(handler) - { - webKitCtrl->m_guard = true; - wxFSFile* file = handler->GetFile(wxuri); - if(file) - { - webKitCtrl->SetPage(*file->GetStream(), wxuri); - } - //We need to throw some sort of error here if file is NULL - webkit_policy_decision_ignore(decision); - return TRUE; - } return FALSE; } } @@ -325,49 +289,53 @@ wxgtk_webview_webkit_title_changed(GtkWidget* widget, } static void -wxgtk_webview_webkit_resource_req(WebKitWebView *, - WebKitWebResource *, - WebKitURIRequest *request, - wxWebViewWebKit *webKitCtrl) +wxgtk_webview_webkit_uri_scheme_request_cb(WebKitURISchemeRequest *request, + wxWebViewWebKit *webKitCtrl) { - wxString uri = webkit_uri_request_get_uri(request); + const wxString scheme = wxString::FromUTF8(webkit_uri_scheme_request_get_scheme(request)); wxSharedPtr handler; wxVector > handlers = webKitCtrl->GetHandlers(); - //We are not vetoed so see if we match one of the additional handlers for(wxVector >::iterator it = handlers.begin(); it != handlers.end(); ++it) { - if(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName()) + if(scheme == (*it)->GetName()) { handler = (*it); } } - //If we found a handler we can then use it to load the file directly - //ourselves + if(handler) { - //If it is requsting the page itself then return as we have already - //loaded it from the archive - if(webKitCtrl->m_vfsurl == uri) - return; + const wxString uri = wxString::FromUTF8(webkit_uri_scheme_request_get_uri(request)); wxFSFile* file = handler->GetFile(uri); if(file) { - //We load the data into a data url to save it being written out again - size_t size = file->GetStream()->GetLength(); - char *buffer = new char[size]; - file->GetStream()->Read(buffer, size); - wxString data = wxBase64Encode(buffer, size); - delete[] buffer; + gint64 length = file->GetStream()->GetLength(); + guint8 *data = g_new(guint8, length); + file->GetStream()->Read(data, length); + GInputStream *stream = g_memory_input_stream_new_from_data(data, + length, + g_free); wxString mime = file->GetMimeType(); - wxString path = "data:" + mime + ";base64," + data; - //Then we can redirect the call - webkit_uri_request_set_uri(request, path.utf8_str()); + webkit_uri_scheme_request_finish(request, stream, length, mime.utf8_str()); } - + else + { + wxGtkError error(g_error_new(WEBKIT_NETWORK_ERROR, + WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST, + "File not found: %s", uri.utf8_str().data())); + webkit_uri_scheme_request_finish_error(request, error); + } + } + else + { + wxGtkError error(g_error_new(WEBKIT_NETWORK_ERROR, + WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL, + "Unknown scheme: %s", scheme.utf8_str().data())); + webkit_uri_scheme_request_finish_error(request, error); } } @@ -569,38 +537,35 @@ bool wxWebViewWebKit::Create(wxWindow *parent, } SetupWebExtensionServer(); - g_signal_connect_after(webkit_web_context_get_default(), - "initialize-web-extensions", - G_CALLBACK(wxgtk_initialize_web_extensions), - m_dbusServer); + g_signal_connect(webkit_web_context_get_default(), + "initialize-web-extensions", + G_CALLBACK(wxgtk_initialize_web_extensions), + m_dbusServer); m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new()); GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view)); g_object_ref(m_widget); - g_signal_connect_after(m_web_view, "decide-policy", - G_CALLBACK(wxgtk_webview_webkit_decide_policy), - this); + g_signal_connect(m_web_view, "decide-policy", + G_CALLBACK(wxgtk_webview_webkit_decide_policy), + this); - g_signal_connect_after(m_web_view, "load-failed", - G_CALLBACK(wxgtk_webview_webkit_load_failed), this); + g_signal_connect(m_web_view, "load-failed", + G_CALLBACK(wxgtk_webview_webkit_load_failed), this); - g_signal_connect_after(m_web_view, "notify::title", - G_CALLBACK(wxgtk_webview_webkit_title_changed), this); + g_signal_connect(m_web_view, "notify::title", + G_CALLBACK(wxgtk_webview_webkit_title_changed), this); - g_signal_connect_after(m_web_view, "resource-load-started", - G_CALLBACK(wxgtk_webview_webkit_resource_req), this); + g_signal_connect(m_web_view, "context-menu", + G_CALLBACK(wxgtk_webview_webkit_context_menu), this); - g_signal_connect_after(m_web_view, "context-menu", - G_CALLBACK(wxgtk_webview_webkit_context_menu), this); - - g_signal_connect_after(m_web_view, "create", - G_CALLBACK(wxgtk_webview_webkit_create_webview), this); + g_signal_connect(m_web_view, "create", + G_CALLBACK(wxgtk_webview_webkit_create_webview), this); WebKitFindController* findctrl = webkit_web_view_get_find_controller(m_web_view); - g_signal_connect_after(findctrl, "counted-matches", - G_CALLBACK(wxgtk_webview_webkit_counted_matches), - &m_findCount); + g_signal_connect(findctrl, "counted-matches", + G_CALLBACK(wxgtk_webview_webkit_counted_matches), + &m_findCount); m_parent->DoAddChild( this ); @@ -610,9 +575,9 @@ bool wxWebViewWebKit::Create(wxWindow *parent, webkit_web_view_load_uri(m_web_view, url.utf8_str()); // last to avoid getting signal too early - g_signal_connect_after(m_web_view, "load-changed", - G_CALLBACK(wxgtk_webview_webkit_load_changed), - this); + g_signal_connect(m_web_view, "load-changed", + G_CALLBACK(wxgtk_webview_webkit_load_changed), + this); return true; } @@ -1279,6 +1244,10 @@ bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output) void wxWebViewWebKit::RegisterHandler(wxSharedPtr handler) { m_handlerList.push_back(handler); + WebKitWebContext* context = webkit_web_context_get_default(); + webkit_web_context_register_uri_scheme(context, handler->GetName().utf8_str(), + (WebKitURISchemeRequestCallback)wxgtk_webview_webkit_uri_scheme_request_cb, + this, NULL); } void wxWebViewWebKit::EnableContextMenu(bool enable)