1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/webview_webkit.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"
13 #if wxUSE_WEBVIEW_WEBKIT
15 #include "wx/stockitem.h"
16 #include "wx/gtk/webview_webkit.h"
17 #include "wx/gtk/control.h"
18 #include "wx/gtk/private.h"
19 #include "webkit/webkit.h"
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
29 wxgtk_webkitctrl_load_status_callback(GtkWidget
* widget
, GParamSpec
* arg1
,
30 wxWebViewWebKit
*webKitCtrl
)
32 if (!webKitCtrl
->m_ready
) return;
34 wxString url
= webKitCtrl
->GetCurrentURL();
36 WebKitLoadStatus status
;
37 g_object_get(G_OBJECT(widget
), "load-status", &status
, NULL
);
39 wxString target
; // TODO: get target (if possible)
41 if (status
== WEBKIT_LOAD_FINISHED
)
43 webKitCtrl
->m_busy
= false;
44 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED
,
48 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
49 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
51 else if (status
== WEBKIT_LOAD_COMMITTED
)
53 webKitCtrl
->m_busy
= true;
54 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED
,
58 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
59 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
63 static WebKitNavigationResponse
64 wxgtk_webkitctrl_navigation_requ_callback(WebKitWebView
*web_view
,
65 WebKitWebFrame
*frame
,
66 WebKitNetworkRequest
*request
,
67 wxWebViewWebKit
*webKitCtrl
)
69 webKitCtrl
->m_busy
= true;
71 const gchar
* uri
= webkit_network_request_get_uri(request
);
73 wxString target
= webkit_web_frame_get_name (frame
);
74 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING
,
76 wxString( uri
, wxConvUTF8
),
80 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
81 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
83 if (thisEvent
.IsVetoed())
85 webKitCtrl
->m_busy
= false;
86 return WEBKIT_NAVIGATION_RESPONSE_IGNORE
;
90 return WEBKIT_NAVIGATION_RESPONSE_ACCEPT
;
95 wxgtk_webkitctrl_error (WebKitWebView
*web_view
,
96 WebKitWebFrame
*web_frame
,
99 wxWebViewWebKit
* webKitWindow
)
101 webKitWindow
->m_busy
= false;
102 wxWebNavigationError type
= wxWEB_NAV_ERR_OTHER
;
104 GError
* error
= (GError
*)web_error
;
105 wxString
description(error
->message
, wxConvUTF8
);
107 if (strcmp(g_quark_to_string(error
->domain
), "soup_http_error_quark") == 0)
111 case SOUP_STATUS_CANCELLED
:
112 type
= wxWEB_NAV_ERR_USER_CANCELLED
;
115 case SOUP_STATUS_CANT_RESOLVE
:
116 case SOUP_STATUS_NOT_FOUND
:
117 type
= wxWEB_NAV_ERR_NOT_FOUND
;
120 case SOUP_STATUS_CANT_RESOLVE_PROXY
:
121 case SOUP_STATUS_CANT_CONNECT
:
122 case SOUP_STATUS_CANT_CONNECT_PROXY
:
123 case SOUP_STATUS_SSL_FAILED
:
124 case SOUP_STATUS_IO_ERROR
:
125 type
= wxWEB_NAV_ERR_CONNECTION
;
128 case SOUP_STATUS_MALFORMED
:
129 //case SOUP_STATUS_TOO_MANY_REDIRECTS:
130 type
= wxWEB_NAV_ERR_REQUEST
;
133 //case SOUP_STATUS_NO_CONTENT:
134 //case SOUP_STATUS_RESET_CONTENT:
136 case SOUP_STATUS_BAD_REQUEST
:
137 type
= wxWEB_NAV_ERR_REQUEST
;
140 case SOUP_STATUS_UNAUTHORIZED
:
141 case SOUP_STATUS_FORBIDDEN
:
142 type
= wxWEB_NAV_ERR_AUTH
;
145 case SOUP_STATUS_METHOD_NOT_ALLOWED
:
146 case SOUP_STATUS_NOT_ACCEPTABLE
:
147 type
= wxWEB_NAV_ERR_SECURITY
;
150 case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED
:
151 type
= wxWEB_NAV_ERR_AUTH
;
154 case SOUP_STATUS_REQUEST_TIMEOUT
:
155 type
= wxWEB_NAV_ERR_CONNECTION
;
158 //case SOUP_STATUS_PAYMENT_REQUIRED:
159 case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE
:
160 case SOUP_STATUS_REQUEST_URI_TOO_LONG
:
161 case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE
:
162 type
= wxWEB_NAV_ERR_REQUEST
;
165 case SOUP_STATUS_BAD_GATEWAY
:
166 case SOUP_STATUS_SERVICE_UNAVAILABLE
:
167 case SOUP_STATUS_GATEWAY_TIMEOUT
:
168 type
= wxWEB_NAV_ERR_CONNECTION
;
171 case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED
:
172 type
= wxWEB_NAV_ERR_REQUEST
;
174 //case SOUP_STATUS_INSUFFICIENT_STORAGE:
175 //case SOUP_STATUS_NOT_EXTENDED:
178 else if (strcmp(g_quark_to_string(error
->domain
),
179 "webkit-network-error-quark") == 0)
183 //WEBKIT_NETWORK_ERROR_FAILED:
184 //WEBKIT_NETWORK_ERROR_TRANSPORT:
186 case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL
:
187 type
= wxWEB_NAV_ERR_REQUEST
;
190 case WEBKIT_NETWORK_ERROR_CANCELLED
:
191 type
= wxWEB_NAV_ERR_USER_CANCELLED
;
194 case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST
:
195 type
= wxWEB_NAV_ERR_NOT_FOUND
;
199 else if (strcmp(g_quark_to_string(error
->domain
),
200 "webkit-policy-error-quark") == 0)
204 //case WEBKIT_POLICY_ERROR_FAILED:
205 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE:
206 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
207 //case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
208 case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT
:
209 type
= wxWEB_NAV_ERR_SECURITY
;
214 webkit_plugin_error_quark
217 printf("Error domain %s\n", g_quark_to_string(error->domain));
221 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR
,
222 webKitWindow
->GetId(),
226 thisEvent
.SetString(description
);
227 thisEvent
.SetInt(type
);
229 if (webKitWindow
&& webKitWindow
->GetEventHandler())
231 webKitWindow
->GetEventHandler()->ProcessEvent(thisEvent
);
238 wxgtk_webkitctrl_new_window(WebKitWebView
*webView
,
239 WebKitWebFrame
*frame
,
240 WebKitNetworkRequest
*request
,
241 WebKitWebNavigationAction
*navigation_action
,
242 WebKitWebPolicyDecision
*policy_decision
,
243 wxWebViewWebKit
*webKitCtrl
)
245 const gchar
* uri
= webkit_network_request_get_uri(request
);
247 wxString target
= webkit_web_frame_get_name (frame
);
248 wxWebNavigationEvent
thisEvent(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW
,
250 wxString( uri
, wxConvUTF8
),
254 if (webKitCtrl
&& webKitCtrl
->GetEventHandler())
255 webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
);
257 if (thisEvent
.IsVetoed())
259 webkit_web_policy_decision_ignore(policy_decision
);
263 webkit_web_policy_decision_use(policy_decision
);
270 //-----------------------------------------------------------------------------
272 //-----------------------------------------------------------------------------
274 //IMPLEMENT_DYNAMIC_CLASS(wxWebViewWebKit, wxControl)
276 bool wxWebViewWebKit::Create(wxWindow
*parent
,
282 const wxString
& name
)
287 if (!PreCreation( parent
, pos
, size
) ||
288 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
290 wxFAIL_MSG( wxT("wxWebViewWebKit creation failed") );
294 GtkWidget
*scrolled_window
= gtk_scrolled_window_new (NULL
, NULL
);
295 web_view
= webkit_web_view_new ();
296 g_object_ref(web_view
); // TODO: check memory management
298 m_widget
= scrolled_window
;
299 g_object_ref(m_widget
); // TODO: check memory management
301 /* Place the WebKitWebView in the GtkScrolledWindow */
302 gtk_container_add (GTK_CONTAINER (scrolled_window
), web_view
);
303 gtk_widget_show(m_widget
);
304 gtk_widget_show(web_view
);
306 g_signal_connect_after(web_view
, "notify::load-status",
307 G_CALLBACK(wxgtk_webkitctrl_load_status_callback
),
309 g_signal_connect_after(web_view
, "navigation-requested",
310 G_CALLBACK(wxgtk_webkitctrl_navigation_requ_callback
),
312 g_signal_connect_after(web_view
, "load-error",
313 G_CALLBACK(wxgtk_webkitctrl_error
),
316 g_signal_connect_after(web_view
, "new-window-policy-decision-requested",
317 G_CALLBACK(wxgtk_webkitctrl_new_window
), this);
319 m_parent
->DoAddChild( this );
324 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view
), url
);
326 //Get the initial history limit so we can enable and disable it later
327 WebKitWebBackForwardList
* history
;
328 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
329 m_historyLimit
= webkit_web_back_forward_list_get_limit(history
);
336 bool wxWebViewWebKit::Enable( bool enable
)
338 if (!wxControl::Enable(enable
))
341 gtk_widget_set_sensitive(GTK_BIN(m_widget
)->child
, enable
);
344 // GTKFixSensitivity();
350 wxWebViewWebKit::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const
352 GdkWindow
* window
= gtk_widget_get_parent_window(m_widget
);
356 void wxWebViewWebKit::ZoomIn()
358 webkit_web_view_zoom_in (WEBKIT_WEB_VIEW(web_view
));
361 void wxWebViewWebKit::ZoomOut()
363 webkit_web_view_zoom_out (WEBKIT_WEB_VIEW(web_view
));
366 void wxWebViewWebKit::SetWebkitZoom(float level
)
368 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(web_view
), level
);
371 float wxWebViewWebKit::GetWebkitZoom()
373 return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW(web_view
));
376 void wxWebViewWebKit::Stop()
378 webkit_web_view_stop_loading (WEBKIT_WEB_VIEW(web_view
));
381 void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags
)
383 if (flags
& wxWEB_VIEW_RELOAD_NO_CACHE
)
385 webkit_web_view_reload_bypass_cache (WEBKIT_WEB_VIEW(web_view
));
389 webkit_web_view_reload (WEBKIT_WEB_VIEW(web_view
));
393 void wxWebViewWebKit::LoadUrl(const wxString
& url
)
395 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view
), wxGTK_CONV(url
));
399 void wxWebViewWebKit::GoBack()
401 webkit_web_view_go_back (WEBKIT_WEB_VIEW(web_view
));
404 void wxWebViewWebKit::GoForward()
406 webkit_web_view_go_forward (WEBKIT_WEB_VIEW(web_view
));
410 bool wxWebViewWebKit::CanGoBack()
412 return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW(web_view
));
416 bool wxWebViewWebKit::CanGoForward()
418 return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW(web_view
));
421 void wxWebViewWebKit::ClearHistory()
423 WebKitWebBackForwardList
* history
;
424 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
425 webkit_web_back_forward_list_clear(history
);
428 void wxWebViewWebKit::EnableHistory(bool enable
)
430 WebKitWebBackForwardList
* history
;
431 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
434 webkit_web_back_forward_list_set_limit(history
, m_historyLimit
);
438 webkit_web_back_forward_list_set_limit(history
, 0);
442 wxVector
<wxSharedPtr
<wxWebHistoryItem
> > wxWebViewWebKit::GetBackwardHistory()
444 wxVector
<wxSharedPtr
<wxWebHistoryItem
> > backhist
;
445 WebKitWebBackForwardList
* history
;
446 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
447 GList
* list
= webkit_web_back_forward_list_get_back_list_with_limit(history
,
449 //We need to iterate in reverse to get the order we desire
450 for(int i
= g_list_length(list
) - 1; i
>= 0 ; i
--)
452 WebKitWebHistoryItem
* gtkitem
= (WebKitWebHistoryItem
*)g_list_nth_data(list
, i
);
453 wxSharedPtr
<wxWebHistoryItem
> item(new wxWebHistoryItem(
454 webkit_web_history_item_get_uri(gtkitem
),
455 webkit_web_history_item_get_title(gtkitem
)));
456 backhist
.push_back(item
);
457 m_historyMap
[item
] = gtkitem
;
462 wxVector
<wxSharedPtr
<wxWebHistoryItem
> > wxWebViewWebKit::GetForwardHistory()
464 wxVector
<wxSharedPtr
<wxWebHistoryItem
> > forwardhist
;
465 WebKitWebBackForwardList
* history
;
466 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
467 GList
* list
= webkit_web_back_forward_list_get_forward_list_with_limit(history
,
469 for(guint i
= 0; i
< g_list_length(list
); i
++)
471 WebKitWebHistoryItem
* gtkitem
= (WebKitWebHistoryItem
*)g_list_nth_data(list
, i
);
472 wxSharedPtr
<wxWebHistoryItem
> item(new wxWebHistoryItem(
473 webkit_web_history_item_get_uri(gtkitem
),
474 webkit_web_history_item_get_title(gtkitem
)));
475 forwardhist
.push_back(item
);
476 m_historyMap
[item
] = gtkitem
;
481 void wxWebViewWebKit::LoadHistoryItem(wxSharedPtr
<wxWebHistoryItem
> item
)
483 WebKitWebHistoryItem
* gtkitem
= m_historyMap
[item
];
486 WebKitWebBackForwardList
* history
;
487 history
= webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(web_view
));
488 webkit_web_back_forward_list_go_to_item(history
, gtkitem
);
492 bool wxWebViewWebKit::CanCut()
494 return webkit_web_view_can_cut_clipboard(WEBKIT_WEB_VIEW(web_view
));
497 bool wxWebViewWebKit::CanCopy()
499 return webkit_web_view_can_copy_clipboard(WEBKIT_WEB_VIEW(web_view
));
502 bool wxWebViewWebKit::CanPaste()
504 return webkit_web_view_can_paste_clipboard(WEBKIT_WEB_VIEW(web_view
));
507 void wxWebViewWebKit::Cut()
509 webkit_web_view_cut_clipboard(WEBKIT_WEB_VIEW(web_view
));
512 void wxWebViewWebKit::Copy()
514 webkit_web_view_copy_clipboard(WEBKIT_WEB_VIEW(web_view
));
517 void wxWebViewWebKit::Paste()
519 webkit_web_view_paste_clipboard(WEBKIT_WEB_VIEW(web_view
));
522 bool wxWebViewWebKit::CanUndo()
524 return webkit_web_view_can_undo(WEBKIT_WEB_VIEW(web_view
));
527 bool wxWebViewWebKit::CanRedo()
529 return webkit_web_view_can_redo(WEBKIT_WEB_VIEW(web_view
));
532 void wxWebViewWebKit::Undo()
534 webkit_web_view_undo(WEBKIT_WEB_VIEW(web_view
));
537 void wxWebViewWebKit::Redo()
539 webkit_web_view_redo(WEBKIT_WEB_VIEW(web_view
));
542 wxString
wxWebViewWebKit::GetCurrentURL()
544 // FIXME: check which encoding the web kit control uses instead of
545 // assuming UTF8 (here and elsewhere too)
546 return wxString::FromUTF8(webkit_web_view_get_uri(
547 WEBKIT_WEB_VIEW(web_view
)));
551 wxString
wxWebViewWebKit::GetCurrentTitle()
553 return wxString::FromUTF8(webkit_web_view_get_title(
554 WEBKIT_WEB_VIEW(web_view
)));
558 wxString
wxWebViewWebKit::GetPageSource()
560 WebKitWebFrame
* frame
= webkit_web_view_get_main_frame(
561 WEBKIT_WEB_VIEW(web_view
));
562 WebKitWebDataSource
* src
= webkit_web_frame_get_data_source (frame
);
564 // TODO: check encoding with
566 // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source);
567 return wxString(webkit_web_data_source_get_data (src
)->str
, wxConvUTF8
);
571 wxWebViewZoom
wxWebViewWebKit::GetZoom()
573 float zoom
= GetWebkitZoom();
575 // arbitrary way to map float zoom to our common zoom enum
578 return wxWEB_VIEW_ZOOM_TINY
;
580 else if (zoom
> 0.65 && zoom
<= 0.90)
582 return wxWEB_VIEW_ZOOM_SMALL
;
584 else if (zoom
> 0.90 && zoom
<= 1.15)
586 return wxWEB_VIEW_ZOOM_MEDIUM
;
588 else if (zoom
> 1.15 && zoom
<= 1.45)
590 return wxWEB_VIEW_ZOOM_LARGE
;
592 else if (zoom
> 1.45)
594 return wxWEB_VIEW_ZOOM_LARGEST
;
597 // to shut up compilers, this can never be reached logically
599 return wxWEB_VIEW_ZOOM_MEDIUM
;
603 void wxWebViewWebKit::SetZoom(wxWebViewZoom zoom
)
605 // arbitrary way to map our common zoom enum to float zoom
608 case wxWEB_VIEW_ZOOM_TINY
:
612 case wxWEB_VIEW_ZOOM_SMALL
:
616 case wxWEB_VIEW_ZOOM_MEDIUM
:
620 case wxWEB_VIEW_ZOOM_LARGE
:
624 case wxWEB_VIEW_ZOOM_LARGEST
:
633 void wxWebViewWebKit::SetZoomType(wxWebViewZoomType type
)
635 webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(web_view
),
636 (type
== wxWEB_VIEW_ZOOM_TYPE_LAYOUT
?
640 wxWebViewZoomType
wxWebViewWebKit::GetZoomType() const
642 gboolean fczoom
= webkit_web_view_get_full_content_zoom(
643 WEBKIT_WEB_VIEW(web_view
));
645 if (fczoom
) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT
;
646 else return wxWEB_VIEW_ZOOM_TYPE_TEXT
;
649 bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType
) const
651 // this port supports all zoom types
655 void wxWebViewWebKit::SetPage(const wxString
& html
, const wxString
& baseUri
)
657 webkit_web_view_load_string (WEBKIT_WEB_VIEW(web_view
),
658 html
.mb_str(wxConvUTF8
),
661 baseUri
.mb_str(wxConvUTF8
));
664 void wxWebViewWebKit::Print()
666 WebKitWebFrame
* frame
= webkit_web_view_get_main_frame(
667 WEBKIT_WEB_VIEW(web_view
));
668 webkit_web_frame_print (frame
);
670 // GtkPrintOperationResult webkit_web_frame_print_full
671 // (WebKitWebFrame *frame,
672 // GtkPrintOperation *operation,
673 // GtkPrintOperationAction action,
679 bool wxWebViewWebKit::IsBusy()
683 // This code looks nice but returns true after a page was cancelled
685 WebKitLoadStatus status = webkit_web_view_get_load_status
686 (WEBKIT_WEB_VIEW(web_view));
689 #if WEBKIT_CHECK_VERSION(1,1,16)
690 // WEBKIT_LOAD_FAILED is new in webkit 1.1.16
691 if (status == WEBKIT_LOAD_FAILED)
696 if (status == WEBKIT_LOAD_FINISHED)
707 wxWebViewWebKit::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
709 return GetDefaultAttributesFromGTKWidget(webkit_web_view_new
);
713 #endif // wxHAVE_WEB_BACKEND_GTK_WEBKIT