1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/webview.cpp
3 // Purpose: GTK WebKit backend for web view component
4 // Author: Marianne Gagnon, Robert Roebling
6 // Copyright: (c) 2010 Marianne Gagnon, 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #if wxHAVE_WEB_BACKEND_GTK_WEBKIT
16 #include "wx/stockitem.h"
17 #include "wx/gtk/webview.h"
18 #include "wx/gtk/control.h"
19 #include "wx/gtk/private.h"
20 #include "webkit/webkit.h"
22 // ----------------------------------------------------------------------------
24 // ----------------------------------------------------------------------------
30 wxgtk_webkitctrl_load_status_callback(GtkWidget
* widget
, GParamSpec
* arg1
,
31 wxWebViewGTKWebKit
*webKitCtrl
)
33 if (!webKitCtrl
->m_ready
) return;
35 wxString url
= webKitCtrl
->GetCurrentURL();
37 WebKitLoadStatus status
;
38 g_object_get(G_OBJECT(widget
), "load-status", &status
, NULL
);
40 wxString target
; // TODO: get target (if possible)
42 if (status
== WEBKIT_LOAD_FINISHED
)
44 webKitCtrl
->m_busy
= false;
45 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED
,
49 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
50 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
52 else if (status
== WEBKIT_LOAD_COMMITTED
)
54 webKitCtrl
->m_busy
= true;
55 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED
,
59 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
60 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
64 static WebKitNavigationResponse
65 wxgtk_webkitctrl_navigation_requ_callback(WebKitWebView
*web_view
,
66 WebKitWebFrame
*frame
,
67 WebKitNetworkRequest
*request
,
68 wxWebViewGTKWebKit
*webKitCtrl
)
70 webKitCtrl
->m_busy
= true;
72 const gchar
* uri
= webkit_network_request_get_uri(request
);
74 wxString target
= webkit_web_frame_get_name (frame
);
75 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING
,
77 wxString( uri
, wxConvUTF8
),
81 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
82 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
84 if (thisEvent
.IsVetoed())
86 webKitCtrl
->m_busy
= false;
87 return WEBKIT_NAVIGATION_RESPONSE_IGNORE
;
91 return WEBKIT_NAVIGATION_RESPONSE_ACCEPT
;
96 wxgtk_webkitctrl_error (WebKitWebView
*web_view
,
97 WebKitWebFrame
*web_frame
,
100 wxWebViewGTKWebKit
* webKitWindow
)
102 webKitWindow
->m_busy
= false;
103 wxWebNavigationError type
= wxWEB_NAV_ERR_OTHER
;
105 GError
* error
= (GError
*)web_error
;
106 wxString
description(error
->message
, wxConvUTF8
);
108 if (strcmp(g_quark_to_string(error
->domain
), "soup_http_error_quark") == 0)
112 case SOUP_STATUS_CANCELLED
:
113 type
= wxWEB_NAV_ERR_USER_CANCELLED
;
116 case SOUP_STATUS_CANT_RESOLVE
:
117 case SOUP_STATUS_NOT_FOUND
:
118 type
= wxWEB_NAV_ERR_NOT_FOUND
;
121 case SOUP_STATUS_CANT_RESOLVE_PROXY
:
122 case SOUP_STATUS_CANT_CONNECT
:
123 case SOUP_STATUS_CANT_CONNECT_PROXY
:
124 case SOUP_STATUS_SSL_FAILED
:
125 case SOUP_STATUS_IO_ERROR
:
126 type
= wxWEB_NAV_ERR_CONNECTION
;
129 case SOUP_STATUS_MALFORMED
:
130 //case SOUP_STATUS_TOO_MANY_REDIRECTS:
131 type
= wxWEB_NAV_ERR_REQUEST
;
134 //case SOUP_STATUS_NO_CONTENT:
135 //case SOUP_STATUS_RESET_CONTENT:
137 case SOUP_STATUS_BAD_REQUEST
:
138 type
= wxWEB_NAV_ERR_REQUEST
;
141 case SOUP_STATUS_UNAUTHORIZED
:
142 case SOUP_STATUS_FORBIDDEN
:
143 type
= wxWEB_NAV_ERR_AUTH
;
146 case SOUP_STATUS_METHOD_NOT_ALLOWED
:
147 case SOUP_STATUS_NOT_ACCEPTABLE
:
148 type
= wxWEB_NAV_ERR_SECURITY
;
151 case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED
:
152 type
= wxWEB_NAV_ERR_AUTH
;
155 case SOUP_STATUS_REQUEST_TIMEOUT
:
156 type
= wxWEB_NAV_ERR_CONNECTION
;
159 //case SOUP_STATUS_PAYMENT_REQUIRED:
160 case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE
:
161 case SOUP_STATUS_REQUEST_URI_TOO_LONG
:
162 case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE
:
163 type
= wxWEB_NAV_ERR_REQUEST
;
166 case SOUP_STATUS_BAD_GATEWAY
:
167 case SOUP_STATUS_SERVICE_UNAVAILABLE
:
168 case SOUP_STATUS_GATEWAY_TIMEOUT
:
169 type
= wxWEB_NAV_ERR_CONNECTION
;
172 case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED
:
173 type
= wxWEB_NAV_ERR_REQUEST
;
175 //case SOUP_STATUS_INSUFFICIENT_STORAGE:
176 //case SOUP_STATUS_NOT_EXTENDED:
179 else if (strcmp(g_quark_to_string(error
->domain
),
180 "webkit-network-error-quark") == 0)
184 //WEBKIT_NETWORK_ERROR_FAILED:
185 //WEBKIT_NETWORK_ERROR_TRANSPORT:
187 case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL
:
188 type
= wxWEB_NAV_ERR_REQUEST
;
191 case WEBKIT_NETWORK_ERROR_CANCELLED
:
192 type
= wxWEB_NAV_ERR_USER_CANCELLED
;
195 case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST
:
196 type
= wxWEB_NAV_ERR_NOT_FOUND
;
200 else if (strcmp(g_quark_to_string(error
->domain
),
201 "webkit-policy-error-quark") == 0)
205 //case WEBKIT_POLICY_ERROR_FAILED:
206 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE:
207 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
208 //case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
209 case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT
:
210 type
= wxWEB_NAV_ERR_SECURITY
;
215 webkit_plugin_error_quark
218 printf("Error domain %s\n", g_quark_to_string(error->domain));
222 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR
,
223 webKitWindow
->GetId(),
227 thisEvent
.SetString(description
);
228 thisEvent
.SetInt(type
);
230 if (webKitWindow
&& webKitWindow
->GetEventHandler())
232 webKitWindow
->GetEventHandler()->ProcessEvent(thisEvent
);
241 //-----------------------------------------------------------------------------
242 // wxWebViewGTKWebKit
243 //-----------------------------------------------------------------------------
245 //IMPLEMENT_DYNAMIC_CLASS(wxWebViewGTKWebKit, wxControl)
247 bool wxWebViewGTKWebKit::Create(wxWindow
*parent
,
253 const wxString
& name
)
258 if (!PreCreation( parent
, pos
, size
) ||
259 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
261 wxFAIL_MSG( wxT("wxWebViewGTKWebKit creation failed") );
265 GtkWidget
*scrolled_window
= gtk_scrolled_window_new (NULL
, NULL
);
266 web_view
= webkit_web_view_new ();
267 g_object_ref(web_view
); // TODO: check memory management
269 m_widget
= scrolled_window
;
270 g_object_ref(m_widget
); // TODO: check memory management
272 /* Place the WebKitWebView in the GtkScrolledWindow */
273 gtk_container_add (GTK_CONTAINER (scrolled_window
), web_view
);
274 gtk_widget_show(m_widget
);
275 gtk_widget_show(web_view
);
277 g_signal_connect_after(web_view
, "notify::load-status",
278 G_CALLBACK(wxgtk_webkitctrl_load_status_callback
),
280 g_signal_connect_after(web_view
, "navigation-requested",
281 G_CALLBACK(wxgtk_webkitctrl_navigation_requ_callback
),
283 g_signal_connect_after(web_view
, "load-error",
284 G_CALLBACK(wxgtk_webkitctrl_error
),
287 // this signal can be added if we care about new frames open requests
288 //g_signal_connect_after(web_view, "new-window-policy-decision-requested",
289 // G_CALLBACK(...), this);
291 m_parent
->DoAddChild( this );
296 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view
), url
);
303 bool wxWebViewGTKWebKit::Enable( bool enable
)
305 if (!wxControl::Enable(enable
))
308 gtk_widget_set_sensitive(GTK_BIN(m_widget
)->child
, enable
);
311 // GTKFixSensitivity();
317 wxWebViewGTKWebKit::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
319 GdkWindow
* window
= gtk_widget_get_parent_window(m_widget
);
323 void wxWebViewGTKWebKit::ZoomIn()
325 webkit_web_view_zoom_in (WEBKIT_WEB_VIEW(web_view
));
328 void wxWebViewGTKWebKit::ZoomOut()
330 webkit_web_view_zoom_out (WEBKIT_WEB_VIEW(web_view
));
333 void wxWebViewGTKWebKit::SetWebkitZoom(float level
)
335 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(web_view
), level
);
338 float wxWebViewGTKWebKit::GetWebkitZoom()
340 return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW(web_view
));
343 void wxWebViewGTKWebKit::Stop()
345 webkit_web_view_stop_loading (WEBKIT_WEB_VIEW(web_view
));
348 void wxWebViewGTKWebKit::Reload(wxWebViewReloadFlags flags
)
350 if (flags
& wxWEB_VIEW_RELOAD_NO_CACHE
)
352 webkit_web_view_reload_bypass_cache (WEBKIT_WEB_VIEW(web_view
));
356 webkit_web_view_reload (WEBKIT_WEB_VIEW(web_view
));
360 void wxWebViewGTKWebKit::LoadUrl(const wxString
& url
)
362 webkit_web_view_open(WEBKIT_WEB_VIEW(web_view
), wxGTK_CONV(loc
));
366 void wxWebViewGTKWebKit::GoBack()
368 webkit_web_view_go_back (WEBKIT_WEB_VIEW(web_view
));
371 void wxWebViewGTKWebKit::GoForward()
373 webkit_web_view_go_forward (WEBKIT_WEB_VIEW(web_view
));
377 bool wxWebViewGTKWebKit::CanGoBack()
379 return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW(web_view
));
383 bool wxWebViewGTKWebKit::CanGoForward()
385 return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW(web_view
));
389 wxString
wxWebViewGTKWebKit::GetCurrentURL()
391 // FIXME: check which encoding the web kit control uses instead of
392 // assuming UTF8 (here and elsewhere too)
393 return wxString::FromUTF8(webkit_web_view_get_uri(
394 WEBKIT_WEB_VIEW(web_view
)));
398 wxString
wxWebViewGTKWebKit::GetCurrentTitle()
400 return wxString::FromUTF8(webkit_web_view_get_title(
401 WEBKIT_WEB_VIEW(web_view
)));
405 wxString
wxWebViewGTKWebKit::GetPageSource()
407 WebKitWebFrame
* frame
= webkit_web_view_get_main_frame(
408 WEBKIT_WEB_VIEW(web_view
));
409 WebKitWebDataSource
* src
= webkit_web_frame_get_data_source (frame
);
411 // TODO: check encoding with
413 // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source);
414 return wxString(webkit_web_data_source_get_data (src
)->str
, wxConvUTF8
);
418 wxWebViewZoom
wxWebViewGTKWebKit::GetZoom()
420 float zoom
= GetWebkitZoom();
422 // arbitrary way to map float zoom to our common zoom enum
425 return wxWEB_VIEW_ZOOM_TINY
;
427 else if (zoom
> 0.65 && zoom
<= 0.90)
429 return wxWEB_VIEW_ZOOM_SMALL
;
431 else if (zoom
> 0.90 && zoom
<= 1.15)
433 return wxWEB_VIEW_ZOOM_MEDIUM
;
435 else if (zoom
> 1.15 && zoom
<= 1.45)
437 return wxWEB_VIEW_ZOOM_LARGE
;
439 else if (zoom
> 1.45)
441 return wxWEB_VIEW_ZOOM_LARGEST
;
444 // to shut up compilers, this can never be reached logically
446 return wxWEB_VIEW_ZOOM_MEDIUM
;
450 void wxWebViewGTKWebKit::SetZoom(wxWebViewZoom zoom
)
452 // arbitrary way to map our common zoom enum to float zoom
455 case wxWEB_VIEW_ZOOM_TINY
:
459 case wxWEB_VIEW_ZOOM_SMALL
:
463 case wxWEB_VIEW_ZOOM_MEDIUM
:
467 case wxWEB_VIEW_ZOOM_LARGE
:
471 case wxWEB_VIEW_ZOOM_LARGEST
:
480 void wxWebViewGTKWebKit::SetZoomType(wxWebViewZoomType type
)
482 webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(web_view
),
483 (type
== wxWEB_VIEW_ZOOM_TYPE_LAYOUT
?
487 wxWebViewZoomType
wxWebViewGTKWebKit::GetZoomType() const
489 gboolean fczoom
= webkit_web_view_get_full_content_zoom(
490 WEBKIT_WEB_VIEW(web_view
));
492 if (fczoom
) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT
;
493 else return wxWEB_VIEW_ZOOM_TYPE_TEXT
;
496 bool wxWebViewGTKWebKit::CanSetZoomType(wxWebViewZoomType
) const
498 // this port supports all zoom types
502 void wxWebViewGTKWebKit::SetPage(const wxString
& html
, const wxString
& baseUri
)
504 webkit_web_view_load_string (WEBKIT_WEB_VIEW(web_view
),
505 html
.mb_str(wxConvUTF8
),
508 baseUri
.mb_str(wxConvUTF8
));
511 void wxWebViewGTKWebKit::Print()
513 WebKitWebFrame
* frame
= webkit_web_view_get_main_frame(
514 WEBKIT_WEB_VIEW(web_view
));
515 webkit_web_frame_print (frame
);
517 // GtkPrintOperationResult webkit_web_frame_print_full
518 // (WebKitWebFrame *frame,
519 // GtkPrintOperation *operation,
520 // GtkPrintOperationAction action,
526 bool wxWebViewGTKWebKit::IsBusy()
530 // This code looks nice but returns true after a page was cancelled
532 WebKitLoadStatus status = webkit_web_view_get_load_status
533 (WEBKIT_WEB_VIEW(web_view));
536 #if WEBKIT_CHECK_VERSION(1,1,16)
537 // WEBKIT_LOAD_FAILED is new in webkit 1.1.16
538 if (status == WEBKIT_LOAD_FAILED)
543 if (status == WEBKIT_LOAD_FINISHED)
554 wxWebViewGTKWebKit::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
556 return GetDefaultAttributesFromGTKWidget(webkit_web_view_new
);
560 #endif // wxHAVE_WEB_BACKEND_GTK_WEBKIT