// Name: src/gtk/webview_webkit.cpp
// Purpose: GTK WebKit backend for web view component
// Author: Marianne Gagnon, Robert Roebling
-// Id: $Id$
// Copyright: (c) 2010 Marianne Gagnon, 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/gtk/private.h"
#include "wx/filesys.h"
#include "wx/base64.h"
+#include "wx/log.h"
#include <webkit/webkit.h>
// ----------------------------------------------------------------------------
GParamSpec*,
wxWebViewWebKit *webKitCtrl)
{
- // We can be called from webkit_web_view_dispose() during the window
- // destruction, don't use half-destroyed object in this case.
- if ( webKitCtrl->IsBeingDeleted() )
- return;
-
wxString url = webKitCtrl->GetCurrentURL();
WebKitLoadStatus status;
//We have to check if we are actually storing history
//If the item isn't added we add it ourselves, it isn't added otherwise
//with a custom scheme.
- if(WEBKIT_IS_WEB_HISTORY_ITEM(item) && webkit_web_history_item_get_uri(item) != url)
+ if(!item || (WEBKIT_IS_WEB_HISTORY_ITEM(item) &&
+ webkit_web_history_item_get_uri(item) != url))
{
WebKitWebHistoryItem*
newitem = webkit_web_history_item_new_with_data
}
webKitCtrl->m_busy = false;
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED,
+ wxWebViewEvent event(wxEVT_WEBVIEW_LOADED,
webKitCtrl->GetId(),
url, target);
else if (status == WEBKIT_LOAD_COMMITTED)
{
webKitCtrl->m_busy = true;
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
+ wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATED,
webKitCtrl->GetId(),
url, target);
WebKitWebPolicyDecision *policy_decision,
wxWebViewWebKit *webKitCtrl)
{
+ const gchar* uri = webkit_network_request_get_uri(request);
+ wxString target = webkit_web_frame_get_name (frame);
+
+ //If m_creating is true then we are the result of a new window
+ //and so we need to send the event and veto the load
+ if(webKitCtrl->m_creating)
+ {
+ webKitCtrl->m_creating = false;
+ wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
+ webKitCtrl->GetId(),
+ wxString(uri, wxConvUTF8),
+ target);
+
+ if(webKitCtrl && webKitCtrl->GetEventHandler())
+ webKitCtrl->GetEventHandler()->ProcessEvent(event);
+
+ webkit_web_policy_decision_ignore(policy_decision);
+ return TRUE;
+ }
+
if(webKitCtrl->m_guard)
{
webKitCtrl->m_guard = false;
webKitCtrl->m_busy = true;
- const gchar* uri = webkit_network_request_get_uri(request);
-
- wxString target = webkit_web_frame_get_name (frame);
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
+ wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
webKitCtrl->GetId(),
wxString( uri, wxConvUTF8 ),
target);
wxWebViewWebKit* webKitWindow)
{
webKitWindow->m_busy = false;
- wxWebViewNavigationError type = wxWEB_NAV_ERR_OTHER;
+ wxWebViewNavigationError type = wxWEBVIEW_NAV_ERR_OTHER;
GError* error = (GError*)web_error;
wxString description(error->message, wxConvUTF8);
switch (error->code)
{
case SOUP_STATUS_CANCELLED:
- type = wxWEB_NAV_ERR_USER_CANCELLED;
+ type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
break;
case SOUP_STATUS_CANT_RESOLVE:
case SOUP_STATUS_NOT_FOUND:
- type = wxWEB_NAV_ERR_NOT_FOUND;
+ type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
break;
case SOUP_STATUS_CANT_RESOLVE_PROXY:
case SOUP_STATUS_CANT_CONNECT_PROXY:
case SOUP_STATUS_SSL_FAILED:
case SOUP_STATUS_IO_ERROR:
- type = wxWEB_NAV_ERR_CONNECTION;
+ type = wxWEBVIEW_NAV_ERR_CONNECTION;
break;
case SOUP_STATUS_MALFORMED:
//case SOUP_STATUS_TOO_MANY_REDIRECTS:
- type = wxWEB_NAV_ERR_REQUEST;
+ type = wxWEBVIEW_NAV_ERR_REQUEST;
break;
//case SOUP_STATUS_NO_CONTENT:
//case SOUP_STATUS_RESET_CONTENT:
case SOUP_STATUS_BAD_REQUEST:
- type = wxWEB_NAV_ERR_REQUEST;
+ type = wxWEBVIEW_NAV_ERR_REQUEST;
break;
case SOUP_STATUS_UNAUTHORIZED:
case SOUP_STATUS_FORBIDDEN:
- type = wxWEB_NAV_ERR_AUTH;
+ type = wxWEBVIEW_NAV_ERR_AUTH;
break;
case SOUP_STATUS_METHOD_NOT_ALLOWED:
case SOUP_STATUS_NOT_ACCEPTABLE:
- type = wxWEB_NAV_ERR_SECURITY;
+ type = wxWEBVIEW_NAV_ERR_SECURITY;
break;
case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
- type = wxWEB_NAV_ERR_AUTH;
+ type = wxWEBVIEW_NAV_ERR_AUTH;
break;
case SOUP_STATUS_REQUEST_TIMEOUT:
- type = wxWEB_NAV_ERR_CONNECTION;
+ type = wxWEBVIEW_NAV_ERR_CONNECTION;
break;
//case SOUP_STATUS_PAYMENT_REQUIRED:
case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE:
case SOUP_STATUS_REQUEST_URI_TOO_LONG:
case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE:
- type = wxWEB_NAV_ERR_REQUEST;
+ type = wxWEBVIEW_NAV_ERR_REQUEST;
break;
case SOUP_STATUS_BAD_GATEWAY:
case SOUP_STATUS_SERVICE_UNAVAILABLE:
case SOUP_STATUS_GATEWAY_TIMEOUT:
- type = wxWEB_NAV_ERR_CONNECTION;
+ type = wxWEBVIEW_NAV_ERR_CONNECTION;
break;
case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
- type = wxWEB_NAV_ERR_REQUEST;
+ type = wxWEBVIEW_NAV_ERR_REQUEST;
break;
//case SOUP_STATUS_INSUFFICIENT_STORAGE:
//case SOUP_STATUS_NOT_EXTENDED:
//WEBKIT_NETWORK_ERROR_TRANSPORT:
case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL:
- type = wxWEB_NAV_ERR_REQUEST;
+ type = wxWEBVIEW_NAV_ERR_REQUEST;
break;
case WEBKIT_NETWORK_ERROR_CANCELLED:
- type = wxWEB_NAV_ERR_USER_CANCELLED;
+ type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
break;
case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST:
- type = wxWEB_NAV_ERR_NOT_FOUND;
+ type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
break;
}
}
//case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
//case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT:
- type = wxWEB_NAV_ERR_SECURITY;
+ type = wxWEBVIEW_NAV_ERR_SECURITY;
break;
}
}
}
*/
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR,
+ wxWebViewEvent event(wxEVT_WEBVIEW_ERROR,
webKitWindow->GetId(),
uri, "");
event.SetString(description);
const gchar* uri = webkit_network_request_get_uri(request);
wxString target = webkit_web_frame_get_name (frame);
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
+ wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
webKitCtrl->GetId(),
wxString( uri, wxConvUTF8 ),
target);
gchar *title,
wxWebViewWebKit *webKitCtrl)
{
- wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED,
+ wxWebViewEvent event(wxEVT_WEBVIEW_TITLE_CHANGED,
webKitCtrl->GetId(),
webKitCtrl->GetCurrentURL(),
"");
}
}
+#if WEBKIT_CHECK_VERSION(1, 10, 0)
+
+static gboolean
+wxgtk_webview_webkit_context_menu(WebKitWebView *,
+ GtkWidget *,
+ WebKitHitTestResult *,
+ gboolean,
+ wxWebViewWebKit *webKitCtrl)
+{
+ if(webKitCtrl->IsContextMenuEnabled())
+ return FALSE;
+ else
+ return TRUE;
+}
+
+#endif
+
+static WebKitWebView*
+wxgtk_webview_webkit_create_webview(WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ wxWebViewWebKit *webKitCtrl)
+{
+ //As we do not know the uri being loaded at this point allow the load to
+ //continue and catch it in navigation-policy-decision-requested
+ webKitCtrl->m_creating = true;
+ return web_view;
+}
+
} // extern "C"
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewWebKit, wxWebView);
+wxWebViewWebKit::wxWebViewWebKit()
+{
+ m_web_view = NULL;
+}
+
bool wxWebViewWebKit::Create(wxWindow *parent,
wxWindowID id,
const wxString &url,
{
m_busy = false;
m_guard = false;
+ m_creating = false;
+ FindClear();
+
+ // We currently unconditionally impose scrolling in both directions as it's
+ // necessary to show arbitrary pages.
+ style |= wxHSCROLL | wxVSCROLL;
if (!PreCreation( parent, pos, size ) ||
!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
return false;
}
- m_widget = gtk_scrolled_window_new(NULL, NULL);
- g_object_ref(m_widget);
m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
-
- /* Place the WebKitWebView in the GtkScrolledWindow */
- gtk_container_add(GTK_CONTAINER(m_widget), GTK_WIDGET(m_web_view));
- gtk_widget_show(GTK_WIDGET(m_web_view));
+ GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
+ g_object_ref(m_widget);
g_signal_connect_after(m_web_view, "navigation-policy-decision-requested",
G_CALLBACK(wxgtk_webview_webkit_navigation),
g_signal_connect_after(m_web_view, "resource-request-starting",
G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
+
+#if WEBKIT_CHECK_VERSION(1, 10, 0)
+ g_signal_connect_after(m_web_view, "context-menu",
+ G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
+#endif
+
+ g_signal_connect_after(m_web_view, "create-web-view",
+ G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
m_parent->DoAddChild( this );
wxWebViewWebKit::~wxWebViewWebKit()
{
- // The main goal here is to set m_isBeingDeleted to true to avoid the use
- // of this -- already half-destroyed -- object from WebKit callbacks, but
- // just setting it would prevent wxWindowDestroyEvent from being sent, so
- // send it now instead.
- SendDestroyEvent();
+ if (m_web_view)
+ GTKDisconnect(m_web_view);
}
bool wxWebViewWebKit::Enable( bool enable )
void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags)
{
- if (flags & wxWEB_VIEW_RELOAD_NO_CACHE)
+ if (flags & wxWEBVIEW_RELOAD_NO_CACHE)
{
webkit_web_view_reload_bypass_cache(m_web_view);
}
// arbitrary way to map float zoom to our common zoom enum
if (zoom <= 0.65)
{
- return wxWEB_VIEW_ZOOM_TINY;
+ return wxWEBVIEW_ZOOM_TINY;
}
else if (zoom > 0.65 && zoom <= 0.90)
{
- return wxWEB_VIEW_ZOOM_SMALL;
+ return wxWEBVIEW_ZOOM_SMALL;
}
else if (zoom > 0.90 && zoom <= 1.15)
{
- return wxWEB_VIEW_ZOOM_MEDIUM;
+ return wxWEBVIEW_ZOOM_MEDIUM;
}
else if (zoom > 1.15 && zoom <= 1.45)
{
- return wxWEB_VIEW_ZOOM_LARGE;
+ return wxWEBVIEW_ZOOM_LARGE;
}
else if (zoom > 1.45)
{
- return wxWEB_VIEW_ZOOM_LARGEST;
+ return wxWEBVIEW_ZOOM_LARGEST;
}
// to shut up compilers, this can never be reached logically
wxASSERT(false);
- return wxWEB_VIEW_ZOOM_MEDIUM;
+ return wxWEBVIEW_ZOOM_MEDIUM;
}
// arbitrary way to map our common zoom enum to float zoom
switch (zoom)
{
- case wxWEB_VIEW_ZOOM_TINY:
+ case wxWEBVIEW_ZOOM_TINY:
SetWebkitZoom(0.6f);
break;
- case wxWEB_VIEW_ZOOM_SMALL:
+ case wxWEBVIEW_ZOOM_SMALL:
SetWebkitZoom(0.8f);
break;
- case wxWEB_VIEW_ZOOM_MEDIUM:
+ case wxWEBVIEW_ZOOM_MEDIUM:
SetWebkitZoom(1.0f);
break;
- case wxWEB_VIEW_ZOOM_LARGE:
+ case wxWEBVIEW_ZOOM_LARGE:
SetWebkitZoom(1.3);
break;
- case wxWEB_VIEW_ZOOM_LARGEST:
+ case wxWEBVIEW_ZOOM_LARGEST:
SetWebkitZoom(1.6);
break;
void wxWebViewWebKit::SetZoomType(wxWebViewZoomType type)
{
webkit_web_view_set_full_content_zoom(m_web_view,
- (type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT ?
+ (type == wxWEBVIEW_ZOOM_TYPE_LAYOUT ?
TRUE : FALSE));
}
{
gboolean fczoom = webkit_web_view_get_full_content_zoom(m_web_view);
- if (fczoom) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT;
- else return wxWEB_VIEW_ZOOM_TYPE_TEXT;
+ if (fczoom) return wxWEBVIEW_ZOOM_TYPE_LAYOUT;
+ else return wxWEBVIEW_ZOOM_TYPE_TEXT;
}
bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType) const
return true;
}
-void wxWebViewWebKit::SetPage(const wxString& html, const wxString& baseUri)
+void wxWebViewWebKit::DoSetPage(const wxString& html, const wxString& baseUri)
{
webkit_web_view_load_string (m_web_view,
html.mb_str(wxConvUTF8),
m_handlerList.push_back(handler);
}
+void wxWebViewWebKit::EnableContextMenu(bool enable)
+{
+#if !WEBKIT_CHECK_VERSION(1, 10, 0) //If we are using an older version
+ g_object_set(webkit_web_view_get_settings(m_web_view),
+ "enable-default-context-menu", enable, NULL);
+#endif
+ wxWebView::EnableContextMenu(enable);
+}
+
+long wxWebViewWebKit::Find(const wxString& text, int flags)
+{
+ bool newSearch = false;
+ if(text != m_findText ||
+ (flags & wxWEBVIEW_FIND_MATCH_CASE) != (m_findFlags & wxWEBVIEW_FIND_MATCH_CASE))
+ {
+ newSearch = true;
+ //If it is a new search we need to clear existing highlights
+ webkit_web_view_unmark_text_matches(m_web_view);
+ webkit_web_view_set_highlight_text_matches(m_web_view, false);
+ }
+
+ m_findFlags = flags;
+ m_findText = text;
+
+ //If the search string is empty then we clear any selection and highlight
+ if(text == "")
+ {
+ webkit_web_view_unmark_text_matches(m_web_view);
+ webkit_web_view_set_highlight_text_matches(m_web_view, false);
+ ClearSelection();
+ return wxNOT_FOUND;
+ }
+
+ bool wrap = false, matchCase = false, forward = true;
+ if(flags & wxWEBVIEW_FIND_WRAP)
+ wrap = true;
+ if(flags & wxWEBVIEW_FIND_MATCH_CASE)
+ matchCase = true;
+ if(flags & wxWEBVIEW_FIND_BACKWARDS)
+ forward = false;
+
+ if(newSearch)
+ {
+ //Initially we mark the matches to know how many we have
+ m_findCount = webkit_web_view_mark_text_matches(m_web_view, wxGTK_CONV(text), matchCase, 0);
+ //In this case we return early to match IE behaviour
+ m_findPosition = -1;
+ return m_findCount;
+ }
+ else
+ {
+ if(forward)
+ m_findPosition++;
+ else
+ m_findPosition--;
+ if(m_findPosition < 0)
+ m_findPosition += m_findCount;
+ if(m_findPosition > m_findCount)
+ m_findPosition -= m_findCount;
+ }
+
+ //Highlight them if needed
+ bool highlight = flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT ? true : false;
+ webkit_web_view_set_highlight_text_matches(m_web_view, highlight);
+
+ if(!webkit_web_view_search_text(m_web_view, wxGTK_CONV(text), matchCase, forward, wrap))
+ {
+ m_findPosition = -1;
+ ClearSelection();
+ return wxNOT_FOUND;
+ }
+ wxLogMessage(wxString::Format("Returning %d", m_findPosition));
+ return newSearch ? m_findCount : m_findPosition;
+}
+
+void wxWebViewWebKit::FindClear()
+{
+ m_findCount = 0;
+ m_findFlags = 0;
+ m_findText = "";
+ m_findPosition = -1;
+}
+
// static
wxVisualAttributes
wxWebViewWebKit::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
{
- return GetDefaultAttributesFromGTKWidget(webkit_web_view_new);
+ return GetDefaultAttributesFromGTKWidget(webkit_web_view_new());
}