1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/webview_webkit.cpp
3 // Purpose: GTK WebKit backend for web view component
4 // Author: Marianne Gagnon, Robert Roebling
5 // Copyright: (c) 2010 Marianne Gagnon, 1998 Robert Roebling
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11
12 #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT
13
14 #include "wx/stockitem.h"
15 #include "wx/gtk/webview_webkit.h"
16 #include "wx/gtk/control.h"
17 #include "wx/gtk/private.h"
18 #include "wx/filesys.h"
19 #include "wx/base64.h"
20 #include "wx/log.h"
21 #include <webkit/webkit.h>
22
23 // ----------------------------------------------------------------------------
24 // GTK callbacks
25 // ----------------------------------------------------------------------------
26
27 extern "C"
28 {
29
30 static void
wxgtk_webview_webkit_load_status(GtkWidget * widget,GParamSpec *,wxWebViewWebKit * webKitCtrl)31 wxgtk_webview_webkit_load_status(GtkWidget* widget,
32 GParamSpec*,
33 wxWebViewWebKit *webKitCtrl)
34 {
35 wxString url = webKitCtrl->GetCurrentURL();
36
37 WebKitLoadStatus status;
38 g_object_get(G_OBJECT(widget), "load-status", &status, NULL);
39
40 wxString target; // TODO: get target (if possible)
41
42 if (status == WEBKIT_LOAD_FINISHED)
43 {
44 WebKitWebBackForwardList* hist = webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(widget));
45 WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_current_item(hist);
46 //We have to check if we are actually storing history
47 //If the item isn't added we add it ourselves, it isn't added otherwise
48 //with a custom scheme.
49 if(!item || (WEBKIT_IS_WEB_HISTORY_ITEM(item) &&
50 webkit_web_history_item_get_uri(item) != url))
51 {
52 WebKitWebHistoryItem*
53 newitem = webkit_web_history_item_new_with_data
54 (
55 url.utf8_str(),
56 webKitCtrl->GetCurrentTitle().utf8_str()
57 );
58 webkit_web_back_forward_list_add_item(hist, newitem);
59 }
60
61 webKitCtrl->m_busy = false;
62 wxWebViewEvent event(wxEVT_WEBVIEW_LOADED,
63 webKitCtrl->GetId(),
64 url, target);
65
66 webKitCtrl->HandleWindowEvent(event);
67 }
68 else if (status == WEBKIT_LOAD_COMMITTED)
69 {
70 webKitCtrl->m_busy = true;
71 wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATED,
72 webKitCtrl->GetId(),
73 url, target);
74
75 webKitCtrl->HandleWindowEvent(event);
76 }
77 }
78
79 static gboolean
wxgtk_webview_webkit_navigation(WebKitWebView *,WebKitWebFrame * frame,WebKitNetworkRequest * request,WebKitWebNavigationAction *,WebKitWebPolicyDecision * policy_decision,wxWebViewWebKit * webKitCtrl)80 wxgtk_webview_webkit_navigation(WebKitWebView *,
81 WebKitWebFrame *frame,
82 WebKitNetworkRequest *request,
83 WebKitWebNavigationAction *,
84 WebKitWebPolicyDecision *policy_decision,
85 wxWebViewWebKit *webKitCtrl)
86 {
87 const gchar* uri = webkit_network_request_get_uri(request);
88 wxString target = webkit_web_frame_get_name (frame);
89
90 //If m_creating is true then we are the result of a new window
91 //and so we need to send the event and veto the load
92 if(webKitCtrl->m_creating)
93 {
94 webKitCtrl->m_creating = false;
95 wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
96 webKitCtrl->GetId(),
97 wxString(uri, wxConvUTF8),
98 target);
99
100 webKitCtrl->HandleWindowEvent(event);
101
102 webkit_web_policy_decision_ignore(policy_decision);
103 return TRUE;
104 }
105
106 if(webKitCtrl->m_guard)
107 {
108 webKitCtrl->m_guard = false;
109 //We set this to make sure that we don't try to load the page again from
110 //the resource request callback
111 webKitCtrl->m_vfsurl = webkit_network_request_get_uri(request);
112 webkit_web_policy_decision_use(policy_decision);
113 return FALSE;
114 }
115
116 webKitCtrl->m_busy = true;
117
118 wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
119 webKitCtrl->GetId(),
120 wxString( uri, wxConvUTF8 ),
121 target);
122
123 webKitCtrl->HandleWindowEvent(event);
124
125 if (!event.IsAllowed())
126 {
127 webKitCtrl->m_busy = false;
128 webkit_web_policy_decision_ignore(policy_decision);
129 return TRUE;
130 }
131 else
132 {
133 wxString wxuri = uri;
134 wxSharedPtr<wxWebViewHandler> handler;
135 wxVector<wxSharedPtr<wxWebViewHandler> > hanlders = webKitCtrl->GetHandlers();
136 //We are not vetoed so see if we match one of the additional handlers
137 for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = hanlders.begin();
138 it != hanlders.end(); ++it)
139 {
140 if(wxuri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
141 {
142 handler = (*it);
143 }
144 }
145 //If we found a handler we can then use it to load the file directly
146 //ourselves
147 if(handler)
148 {
149 webKitCtrl->m_guard = true;
150 wxFSFile* file = handler->GetFile(wxuri);
151 if(file)
152 {
153 webKitCtrl->SetPage(*file->GetStream(), wxuri);
154 }
155 //We need to throw some sort of error here if file is NULL
156 webkit_web_policy_decision_ignore(policy_decision);
157 return TRUE;
158 }
159 return FALSE;
160 }
161 }
162
163 static gboolean
wxgtk_webview_webkit_error(WebKitWebView *,WebKitWebFrame *,gchar * uri,gpointer web_error,wxWebViewWebKit * webKitWindow)164 wxgtk_webview_webkit_error(WebKitWebView*,
165 WebKitWebFrame*,
166 gchar *uri,
167 gpointer web_error,
168 wxWebViewWebKit* webKitWindow)
169 {
170 webKitWindow->m_busy = false;
171 wxWebViewNavigationError type = wxWEBVIEW_NAV_ERR_OTHER;
172
173 GError* error = (GError*)web_error;
174 wxString description(error->message, wxConvUTF8);
175
176 if (strcmp(g_quark_to_string(error->domain), "soup_http_error_quark") == 0)
177 {
178 switch (error->code)
179 {
180 case SOUP_STATUS_CANCELLED:
181 type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
182 break;
183
184 case SOUP_STATUS_CANT_RESOLVE:
185 case SOUP_STATUS_NOT_FOUND:
186 type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
187 break;
188
189 case SOUP_STATUS_CANT_RESOLVE_PROXY:
190 case SOUP_STATUS_CANT_CONNECT:
191 case SOUP_STATUS_CANT_CONNECT_PROXY:
192 case SOUP_STATUS_SSL_FAILED:
193 case SOUP_STATUS_IO_ERROR:
194 type = wxWEBVIEW_NAV_ERR_CONNECTION;
195 break;
196
197 case SOUP_STATUS_MALFORMED:
198 //case SOUP_STATUS_TOO_MANY_REDIRECTS:
199 type = wxWEBVIEW_NAV_ERR_REQUEST;
200 break;
201
202 //case SOUP_STATUS_NO_CONTENT:
203 //case SOUP_STATUS_RESET_CONTENT:
204
205 case SOUP_STATUS_BAD_REQUEST:
206 type = wxWEBVIEW_NAV_ERR_REQUEST;
207 break;
208
209 case SOUP_STATUS_UNAUTHORIZED:
210 case SOUP_STATUS_FORBIDDEN:
211 type = wxWEBVIEW_NAV_ERR_AUTH;
212 break;
213
214 case SOUP_STATUS_METHOD_NOT_ALLOWED:
215 case SOUP_STATUS_NOT_ACCEPTABLE:
216 type = wxWEBVIEW_NAV_ERR_SECURITY;
217 break;
218
219 case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
220 type = wxWEBVIEW_NAV_ERR_AUTH;
221 break;
222
223 case SOUP_STATUS_REQUEST_TIMEOUT:
224 type = wxWEBVIEW_NAV_ERR_CONNECTION;
225 break;
226
227 //case SOUP_STATUS_PAYMENT_REQUIRED:
228 case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE:
229 case SOUP_STATUS_REQUEST_URI_TOO_LONG:
230 case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE:
231 type = wxWEBVIEW_NAV_ERR_REQUEST;
232 break;
233
234 case SOUP_STATUS_BAD_GATEWAY:
235 case SOUP_STATUS_SERVICE_UNAVAILABLE:
236 case SOUP_STATUS_GATEWAY_TIMEOUT:
237 type = wxWEBVIEW_NAV_ERR_CONNECTION;
238 break;
239
240 case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
241 type = wxWEBVIEW_NAV_ERR_REQUEST;
242 break;
243 //case SOUP_STATUS_INSUFFICIENT_STORAGE:
244 //case SOUP_STATUS_NOT_EXTENDED:
245 }
246 }
247 else if (strcmp(g_quark_to_string(error->domain),
248 "webkit-network-error-quark") == 0)
249 {
250 switch (error->code)
251 {
252 //WEBKIT_NETWORK_ERROR_FAILED:
253 //WEBKIT_NETWORK_ERROR_TRANSPORT:
254
255 case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL:
256 type = wxWEBVIEW_NAV_ERR_REQUEST;
257 break;
258
259 case WEBKIT_NETWORK_ERROR_CANCELLED:
260 type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
261 break;
262
263 case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST:
264 type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
265 break;
266 }
267 }
268 else if (strcmp(g_quark_to_string(error->domain),
269 "webkit-policy-error-quark") == 0)
270 {
271 switch (error->code)
272 {
273 //case WEBKIT_POLICY_ERROR_FAILED:
274 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE:
275 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
276 //case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
277 case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT:
278 type = wxWEBVIEW_NAV_ERR_SECURITY;
279 break;
280 }
281 }
282 /*
283 webkit_plugin_error_quark
284 else
285 {
286 printf("Error domain %s\n", g_quark_to_string(error->domain));
287 }
288 */
289
290 wxWebViewEvent event(wxEVT_WEBVIEW_ERROR,
291 webKitWindow->GetId(),
292 uri, "");
293 event.SetString(description);
294 event.SetInt(type);
295
296 webKitWindow->HandleWindowEvent(event);
297
298 return FALSE;
299 }
300
301 static gboolean
wxgtk_webview_webkit_new_window(WebKitWebView *,WebKitWebFrame * frame,WebKitNetworkRequest * request,WebKitWebNavigationAction *,WebKitWebPolicyDecision * policy_decision,wxWebViewWebKit * webKitCtrl)302 wxgtk_webview_webkit_new_window(WebKitWebView*,
303 WebKitWebFrame *frame,
304 WebKitNetworkRequest *request,
305 WebKitWebNavigationAction*,
306 WebKitWebPolicyDecision *policy_decision,
307 wxWebViewWebKit *webKitCtrl)
308 {
309 const gchar* uri = webkit_network_request_get_uri(request);
310
311 wxString target = webkit_web_frame_get_name (frame);
312 wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
313 webKitCtrl->GetId(),
314 wxString( uri, wxConvUTF8 ),
315 target);
316
317 webKitCtrl->HandleWindowEvent(event);
318
319 //We always want the user to handle this themselves
320 webkit_web_policy_decision_ignore(policy_decision);
321 return TRUE;
322 }
323
324 static void
wxgtk_webview_webkit_title_changed(WebKitWebView *,WebKitWebFrame *,gchar * title,wxWebViewWebKit * webKitCtrl)325 wxgtk_webview_webkit_title_changed(WebKitWebView*,
326 WebKitWebFrame*,
327 gchar *title,
328 wxWebViewWebKit *webKitCtrl)
329 {
330 wxWebViewEvent event(wxEVT_WEBVIEW_TITLE_CHANGED,
331 webKitCtrl->GetId(),
332 webKitCtrl->GetCurrentURL(),
333 "");
334 event.SetString(wxString(title, wxConvUTF8));
335
336 webKitCtrl->HandleWindowEvent(event);
337 }
338
339 static void
wxgtk_webview_webkit_resource_req(WebKitWebView *,WebKitWebFrame *,WebKitWebResource *,WebKitNetworkRequest * request,WebKitNetworkResponse *,wxWebViewWebKit * webKitCtrl)340 wxgtk_webview_webkit_resource_req(WebKitWebView *,
341 WebKitWebFrame *,
342 WebKitWebResource *,
343 WebKitNetworkRequest *request,
344 WebKitNetworkResponse *,
345 wxWebViewWebKit *webKitCtrl)
346 {
347 wxString uri = webkit_network_request_get_uri(request);
348
349 wxSharedPtr<wxWebViewHandler> handler;
350 wxVector<wxSharedPtr<wxWebViewHandler> > hanlders = webKitCtrl->GetHandlers();
351
352 //We are not vetoed so see if we match one of the additional handlers
353 for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = hanlders.begin();
354 it != hanlders.end(); ++it)
355 {
356 if(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
357 {
358 handler = (*it);
359 }
360 }
361 //If we found a handler we can then use it to load the file directly
362 //ourselves
363 if(handler)
364 {
365 //If it is requsting the page itself then return as we have already
366 //loaded it from the archive
367 if(webKitCtrl->m_vfsurl == uri)
368 return;
369
370 wxFSFile* file = handler->GetFile(uri);
371 if(file)
372 {
373 //We load the data into a data url to save it being written out again
374 size_t size = file->GetStream()->GetLength();
375 char *buffer = new char[size];
376 file->GetStream()->Read(buffer, size);
377 wxString data = wxBase64Encode(buffer, size);
378 delete[] buffer;
379 wxString mime = file->GetMimeType();
380 wxString path = "data:" + mime + ";base64," + data;
381 //Then we can redirect the call
382 webkit_network_request_set_uri(request, path.utf8_str());
383 }
384
385 }
386 }
387
388 #if WEBKIT_CHECK_VERSION(1, 10, 0)
389
390 static gboolean
wxgtk_webview_webkit_context_menu(WebKitWebView *,GtkWidget *,WebKitHitTestResult *,gboolean,wxWebViewWebKit * webKitCtrl)391 wxgtk_webview_webkit_context_menu(WebKitWebView *,
392 GtkWidget *,
393 WebKitHitTestResult *,
394 gboolean,
395 wxWebViewWebKit *webKitCtrl)
396 {
397 return !webKitCtrl->IsContextMenuEnabled();
398 }
399
400 #endif
401
402 static WebKitWebView*
wxgtk_webview_webkit_create_webview(WebKitWebView * web_view,WebKitWebFrame *,wxWebViewWebKit * webKitCtrl)403 wxgtk_webview_webkit_create_webview(WebKitWebView *web_view,
404 WebKitWebFrame*,
405 wxWebViewWebKit *webKitCtrl)
406 {
407 //As we do not know the uri being loaded at this point allow the load to
408 //continue and catch it in navigation-policy-decision-requested
409 webKitCtrl->m_creating = true;
410 return web_view;
411 }
412
413 } // extern "C"
414
415 //-----------------------------------------------------------------------------
416 // wxWebViewWebKit
417 //-----------------------------------------------------------------------------
418
419 wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewWebKit, wxWebView);
420
wxWebViewWebKit()421 wxWebViewWebKit::wxWebViewWebKit()
422 {
423 m_web_view = NULL;
424 }
425
Create(wxWindow * parent,wxWindowID id,const wxString & url,const wxPoint & pos,const wxSize & size,long style,const wxString & name)426 bool wxWebViewWebKit::Create(wxWindow *parent,
427 wxWindowID id,
428 const wxString &url,
429 const wxPoint& pos,
430 const wxSize& size,
431 long style,
432 const wxString& name)
433 {
434 m_web_view = NULL;
435 m_busy = false;
436 m_guard = false;
437 m_creating = false;
438 FindClear();
439
440 // We currently unconditionally impose scrolling in both directions as it's
441 // necessary to show arbitrary pages.
442 style |= wxHSCROLL | wxVSCROLL;
443
444 if (!PreCreation( parent, pos, size ) ||
445 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
446 {
447 wxFAIL_MSG( wxT("wxWebViewWebKit creation failed") );
448 return false;
449 }
450
451 m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
452 GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
453 g_object_ref(m_widget);
454
455 g_signal_connect_after(m_web_view, "navigation-policy-decision-requested",
456 G_CALLBACK(wxgtk_webview_webkit_navigation),
457 this);
458 g_signal_connect_after(m_web_view, "load-error",
459 G_CALLBACK(wxgtk_webview_webkit_error),
460 this);
461
462 g_signal_connect_after(m_web_view, "new-window-policy-decision-requested",
463 G_CALLBACK(wxgtk_webview_webkit_new_window), this);
464
465 g_signal_connect_after(m_web_view, "title-changed",
466 G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
467
468 g_signal_connect_after(m_web_view, "resource-request-starting",
469 G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
470
471 #if WEBKIT_CHECK_VERSION(1, 10, 0)
472 g_signal_connect_after(m_web_view, "context-menu",
473 G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
474 #endif
475
476 g_signal_connect_after(m_web_view, "create-web-view",
477 G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
478
479 m_parent->DoAddChild( this );
480
481 PostCreation(size);
482
483 /* Open a webpage */
484 webkit_web_view_load_uri(m_web_view, url.utf8_str());
485
486 //Get the initial history limit so we can enable and disable it later
487 WebKitWebBackForwardList* history;
488 history = webkit_web_view_get_back_forward_list(m_web_view);
489 m_historyLimit = webkit_web_back_forward_list_get_limit(history);
490
491 // last to avoid getting signal too early
492 g_signal_connect_after(m_web_view, "notify::load-status",
493 G_CALLBACK(wxgtk_webview_webkit_load_status),
494 this);
495
496 return true;
497 }
498
~wxWebViewWebKit()499 wxWebViewWebKit::~wxWebViewWebKit()
500 {
501 if (m_web_view)
502 GTKDisconnect(m_web_view);
503 }
504
Enable(bool enable)505 bool wxWebViewWebKit::Enable( bool enable )
506 {
507 if (!wxControl::Enable(enable))
508 return false;
509
510 gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable);
511
512 //if (enable)
513 // GTKFixSensitivity();
514
515 return true;
516 }
517
518 GdkWindow*
GTKGetWindow(wxArrayGdkWindows & WXUNUSED (windows)) const519 wxWebViewWebKit::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
520 {
521 GdkWindow* window = gtk_widget_get_parent_window(m_widget);
522 return window;
523 }
524
ZoomIn()525 void wxWebViewWebKit::ZoomIn()
526 {
527 webkit_web_view_zoom_in(m_web_view);
528 }
529
ZoomOut()530 void wxWebViewWebKit::ZoomOut()
531 {
532 webkit_web_view_zoom_out(m_web_view);
533 }
534
SetWebkitZoom(float level)535 void wxWebViewWebKit::SetWebkitZoom(float level)
536 {
537 webkit_web_view_set_zoom_level(m_web_view, level);
538 }
539
GetWebkitZoom() const540 float wxWebViewWebKit::GetWebkitZoom() const
541 {
542 return webkit_web_view_get_zoom_level(m_web_view);
543 }
544
Stop()545 void wxWebViewWebKit::Stop()
546 {
547 webkit_web_view_stop_loading(m_web_view);
548 }
549
Reload(wxWebViewReloadFlags flags)550 void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags)
551 {
552 if (flags & wxWEBVIEW_RELOAD_NO_CACHE)
553 {
554 webkit_web_view_reload_bypass_cache(m_web_view);
555 }
556 else
557 {
558 webkit_web_view_reload(m_web_view);
559 }
560 }
561
LoadURL(const wxString & url)562 void wxWebViewWebKit::LoadURL(const wxString& url)
563 {
564 webkit_web_view_load_uri(m_web_view, wxGTK_CONV(url));
565 }
566
567
GoBack()568 void wxWebViewWebKit::GoBack()
569 {
570 webkit_web_view_go_back(m_web_view);
571 }
572
GoForward()573 void wxWebViewWebKit::GoForward()
574 {
575 webkit_web_view_go_forward(m_web_view);
576 }
577
578
CanGoBack() const579 bool wxWebViewWebKit::CanGoBack() const
580 {
581 return webkit_web_view_can_go_back(m_web_view) != 0;
582 }
583
584
CanGoForward() const585 bool wxWebViewWebKit::CanGoForward() const
586 {
587 return webkit_web_view_can_go_forward(m_web_view) != 0;
588 }
589
ClearHistory()590 void wxWebViewWebKit::ClearHistory()
591 {
592 WebKitWebBackForwardList* history;
593 history = webkit_web_view_get_back_forward_list(m_web_view);
594 webkit_web_back_forward_list_clear(history);
595 }
596
EnableHistory(bool enable)597 void wxWebViewWebKit::EnableHistory(bool enable)
598 {
599 WebKitWebBackForwardList* history;
600 history = webkit_web_view_get_back_forward_list(m_web_view);
601 if(enable)
602 {
603 webkit_web_back_forward_list_set_limit(history, m_historyLimit);
604 }
605 else
606 {
607 webkit_web_back_forward_list_set_limit(history, 0);
608 }
609 }
610
GetBackwardHistory()611 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetBackwardHistory()
612 {
613 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
614 WebKitWebBackForwardList* history;
615 history = webkit_web_view_get_back_forward_list(m_web_view);
616 GList* list = webkit_web_back_forward_list_get_back_list_with_limit(history,
617 m_historyLimit);
618 //We need to iterate in reverse to get the order we desire
619 for(int i = g_list_length(list) - 1; i >= 0 ; i--)
620 {
621 WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)g_list_nth_data(list, i);
622 wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
623 webkit_web_history_item_get_uri(gtkitem),
624 webkit_web_history_item_get_title(gtkitem));
625 wxitem->m_histItem = gtkitem;
626 wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
627 backhist.push_back(item);
628 }
629 return backhist;
630 }
631
GetForwardHistory()632 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetForwardHistory()
633 {
634 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
635 WebKitWebBackForwardList* history;
636 history = webkit_web_view_get_back_forward_list(m_web_view);
637 GList* list = webkit_web_back_forward_list_get_forward_list_with_limit(history,
638 m_historyLimit);
639 for(guint i = 0; i < g_list_length(list); i++)
640 {
641 WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)g_list_nth_data(list, i);
642 wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
643 webkit_web_history_item_get_uri(gtkitem),
644 webkit_web_history_item_get_title(gtkitem));
645 wxitem->m_histItem = gtkitem;
646 wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
647 forwardhist.push_back(item);
648 }
649 return forwardhist;
650 }
651
LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)652 void wxWebViewWebKit::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
653 {
654 WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)item->m_histItem;
655 if(gtkitem)
656 {
657 webkit_web_view_go_to_back_forward_item(m_web_view,
658 WEBKIT_WEB_HISTORY_ITEM(gtkitem));
659 }
660 }
661
CanCut() const662 bool wxWebViewWebKit::CanCut() const
663 {
664 return webkit_web_view_can_cut_clipboard(m_web_view) != 0;
665 }
666
CanCopy() const667 bool wxWebViewWebKit::CanCopy() const
668 {
669 return webkit_web_view_can_copy_clipboard(m_web_view) != 0;
670 }
671
CanPaste() const672 bool wxWebViewWebKit::CanPaste() const
673 {
674 return webkit_web_view_can_paste_clipboard(m_web_view) != 0;
675 }
676
Cut()677 void wxWebViewWebKit::Cut()
678 {
679 webkit_web_view_cut_clipboard(m_web_view);
680 }
681
Copy()682 void wxWebViewWebKit::Copy()
683 {
684 webkit_web_view_copy_clipboard(m_web_view);
685 }
686
Paste()687 void wxWebViewWebKit::Paste()
688 {
689 webkit_web_view_paste_clipboard(m_web_view);
690 }
691
CanUndo() const692 bool wxWebViewWebKit::CanUndo() const
693 {
694 return webkit_web_view_can_undo(m_web_view) != 0;
695 }
696
CanRedo() const697 bool wxWebViewWebKit::CanRedo() const
698 {
699 return webkit_web_view_can_redo(m_web_view) != 0;
700 }
701
Undo()702 void wxWebViewWebKit::Undo()
703 {
704 webkit_web_view_undo(m_web_view);
705 }
706
Redo()707 void wxWebViewWebKit::Redo()
708 {
709 webkit_web_view_redo(m_web_view);
710 }
711
GetCurrentURL() const712 wxString wxWebViewWebKit::GetCurrentURL() const
713 {
714 // FIXME: check which encoding the web kit control uses instead of
715 // assuming UTF8 (here and elsewhere too)
716 return wxString::FromUTF8(webkit_web_view_get_uri(m_web_view));
717 }
718
719
GetCurrentTitle() const720 wxString wxWebViewWebKit::GetCurrentTitle() const
721 {
722 return wxString::FromUTF8(webkit_web_view_get_title(m_web_view));
723 }
724
725
GetPageSource() const726 wxString wxWebViewWebKit::GetPageSource() const
727 {
728 WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
729 WebKitWebDataSource* src = webkit_web_frame_get_data_source (frame);
730
731 // TODO: check encoding with
732 // const gchar*
733 // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source);
734 return wxString(webkit_web_data_source_get_data (src)->str, wxConvUTF8);
735 }
736
737
GetZoom() const738 wxWebViewZoom wxWebViewWebKit::GetZoom() const
739 {
740 float zoom = GetWebkitZoom();
741
742 // arbitrary way to map float zoom to our common zoom enum
743 if (zoom <= 0.65)
744 {
745 return wxWEBVIEW_ZOOM_TINY;
746 }
747 if (zoom <= 0.90)
748 {
749 return wxWEBVIEW_ZOOM_SMALL;
750 }
751 if (zoom <= 1.15)
752 {
753 return wxWEBVIEW_ZOOM_MEDIUM;
754 }
755 if (zoom <= 1.45)
756 {
757 return wxWEBVIEW_ZOOM_LARGE;
758 }
759 return wxWEBVIEW_ZOOM_LARGEST;
760 }
761
762
SetZoom(wxWebViewZoom zoom)763 void wxWebViewWebKit::SetZoom(wxWebViewZoom zoom)
764 {
765 // arbitrary way to map our common zoom enum to float zoom
766 switch (zoom)
767 {
768 case wxWEBVIEW_ZOOM_TINY:
769 SetWebkitZoom(0.6f);
770 break;
771
772 case wxWEBVIEW_ZOOM_SMALL:
773 SetWebkitZoom(0.8f);
774 break;
775
776 case wxWEBVIEW_ZOOM_MEDIUM:
777 SetWebkitZoom(1.0f);
778 break;
779
780 case wxWEBVIEW_ZOOM_LARGE:
781 SetWebkitZoom(1.3);
782 break;
783
784 case wxWEBVIEW_ZOOM_LARGEST:
785 SetWebkitZoom(1.6);
786 break;
787
788 default:
789 wxFAIL;
790 }
791 }
792
SetZoomType(wxWebViewZoomType type)793 void wxWebViewWebKit::SetZoomType(wxWebViewZoomType type)
794 {
795 webkit_web_view_set_full_content_zoom(m_web_view,
796 type == wxWEBVIEW_ZOOM_TYPE_LAYOUT);
797 }
798
GetZoomType() const799 wxWebViewZoomType wxWebViewWebKit::GetZoomType() const
800 {
801 gboolean fczoom = webkit_web_view_get_full_content_zoom(m_web_view);
802
803 if (fczoom) return wxWEBVIEW_ZOOM_TYPE_LAYOUT;
804 else return wxWEBVIEW_ZOOM_TYPE_TEXT;
805 }
806
CanSetZoomType(wxWebViewZoomType) const807 bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType) const
808 {
809 // this port supports all zoom types
810 return true;
811 }
812
DoSetPage(const wxString & html,const wxString & baseUri)813 void wxWebViewWebKit::DoSetPage(const wxString& html, const wxString& baseUri)
814 {
815 webkit_web_view_load_string (m_web_view,
816 html.mb_str(wxConvUTF8),
817 "text/html",
818 "UTF-8",
819 baseUri.mb_str(wxConvUTF8));
820 }
821
Print()822 void wxWebViewWebKit::Print()
823 {
824 WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
825 webkit_web_frame_print (frame);
826
827 // GtkPrintOperationResult webkit_web_frame_print_full
828 // (WebKitWebFrame *frame,
829 // GtkPrintOperation *operation,
830 // GtkPrintOperationAction action,
831 // GError **error);
832
833 }
834
835
IsBusy() const836 bool wxWebViewWebKit::IsBusy() const
837 {
838 return m_busy;
839
840 // This code looks nice but returns true after a page was cancelled
841 /*
842 WebKitLoadStatus status = webkit_web_view_get_load_status
843 (WEBKIT_WEB_VIEW(web_view));
844
845
846 #if WEBKIT_CHECK_VERSION(1,1,16)
847 // WEBKIT_LOAD_FAILED is new in webkit 1.1.16
848 if (status == WEBKIT_LOAD_FAILED)
849 {
850 return false;
851 }
852 #endif
853 if (status == WEBKIT_LOAD_FINISHED)
854 {
855 return false;
856 }
857
858 return true;
859 */
860 }
861
SetEditable(bool enable)862 void wxWebViewWebKit::SetEditable(bool enable)
863 {
864 webkit_web_view_set_editable(m_web_view, enable);
865 }
866
IsEditable() const867 bool wxWebViewWebKit::IsEditable() const
868 {
869 return webkit_web_view_get_editable(m_web_view) != 0;
870 }
871
DeleteSelection()872 void wxWebViewWebKit::DeleteSelection()
873 {
874 webkit_web_view_delete_selection(m_web_view);
875 }
876
HasSelection() const877 bool wxWebViewWebKit::HasSelection() const
878 {
879 return webkit_web_view_has_selection(m_web_view) != 0;
880 }
881
SelectAll()882 void wxWebViewWebKit::SelectAll()
883 {
884 webkit_web_view_select_all(m_web_view);
885 }
886
GetSelectedText() const887 wxString wxWebViewWebKit::GetSelectedText() const
888 {
889 WebKitDOMDocument* doc;
890 WebKitDOMDOMWindow* win;
891 WebKitDOMDOMSelection* sel;
892 WebKitDOMRange* range;
893
894 doc = webkit_web_view_get_dom_document(m_web_view);
895 win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
896 sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
897 range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
898 0, NULL);
899 return wxString(webkit_dom_range_get_text(WEBKIT_DOM_RANGE(range)),
900 wxConvUTF8);
901 }
902
GetSelectedSource() const903 wxString wxWebViewWebKit::GetSelectedSource() const
904 {
905 WebKitDOMDocument* doc;
906 WebKitDOMDOMWindow* win;
907 WebKitDOMDOMSelection* sel;
908 WebKitDOMRange* range;
909 WebKitDOMElement* div;
910 WebKitDOMDocumentFragment* clone;
911 WebKitDOMHTMLElement* html;
912
913 doc = webkit_web_view_get_dom_document(m_web_view);
914 win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
915 sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
916 range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
917 0, NULL);
918 div = webkit_dom_document_create_element(WEBKIT_DOM_DOCUMENT(doc), "div", NULL);
919
920 clone = webkit_dom_range_clone_contents(WEBKIT_DOM_RANGE(range), NULL);
921 webkit_dom_node_append_child(&div->parent_instance, &clone->parent_instance, NULL);
922 html = (WebKitDOMHTMLElement*)div;
923
924 return wxString(webkit_dom_html_element_get_inner_html(WEBKIT_DOM_HTML_ELEMENT(html)),
925 wxConvUTF8);
926 }
927
ClearSelection()928 void wxWebViewWebKit::ClearSelection()
929 {
930 WebKitDOMDocument* doc;
931 WebKitDOMDOMWindow* win;
932 WebKitDOMDOMSelection* sel;
933
934 doc = webkit_web_view_get_dom_document(m_web_view);
935 win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
936 sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
937 webkit_dom_dom_selection_remove_all_ranges(WEBKIT_DOM_DOM_SELECTION(sel));
938
939 }
940
GetPageText() const941 wxString wxWebViewWebKit::GetPageText() const
942 {
943 WebKitDOMDocument* doc;
944 WebKitDOMHTMLElement* body;
945
946 doc = webkit_web_view_get_dom_document(m_web_view);
947 body = webkit_dom_document_get_body(WEBKIT_DOM_DOCUMENT(doc));
948 return wxString(webkit_dom_html_element_get_inner_text(WEBKIT_DOM_HTML_ELEMENT(body)),
949 wxConvUTF8);
950 }
951
RunScript(const wxString & javascript)952 void wxWebViewWebKit::RunScript(const wxString& javascript)
953 {
954 webkit_web_view_execute_script(m_web_view,
955 javascript.mb_str(wxConvUTF8));
956 }
957
RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)958 void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
959 {
960 m_handlerList.push_back(handler);
961 }
962
EnableContextMenu(bool enable)963 void wxWebViewWebKit::EnableContextMenu(bool enable)
964 {
965 #if !WEBKIT_CHECK_VERSION(1, 10, 0) //If we are using an older version
966 g_object_set(webkit_web_view_get_settings(m_web_view),
967 "enable-default-context-menu", enable, NULL);
968 #endif
969 wxWebView::EnableContextMenu(enable);
970 }
971
Find(const wxString & text,int flags)972 long wxWebViewWebKit::Find(const wxString& text, int flags)
973 {
974 bool newSearch = false;
975 if(text != m_findText ||
976 (flags & wxWEBVIEW_FIND_MATCH_CASE) != (m_findFlags & wxWEBVIEW_FIND_MATCH_CASE))
977 {
978 newSearch = true;
979 //If it is a new search we need to clear existing highlights
980 webkit_web_view_unmark_text_matches(m_web_view);
981 webkit_web_view_set_highlight_text_matches(m_web_view, false);
982 }
983
984 m_findFlags = flags;
985 m_findText = text;
986
987 //If the search string is empty then we clear any selection and highlight
988 if(text == "")
989 {
990 webkit_web_view_unmark_text_matches(m_web_view);
991 webkit_web_view_set_highlight_text_matches(m_web_view, false);
992 ClearSelection();
993 return wxNOT_FOUND;
994 }
995
996 bool wrap = false, matchCase = false, forward = true;
997 if(flags & wxWEBVIEW_FIND_WRAP)
998 wrap = true;
999 if(flags & wxWEBVIEW_FIND_MATCH_CASE)
1000 matchCase = true;
1001 if(flags & wxWEBVIEW_FIND_BACKWARDS)
1002 forward = false;
1003
1004 if(newSearch)
1005 {
1006 //Initially we mark the matches to know how many we have
1007 m_findCount = webkit_web_view_mark_text_matches(m_web_view, wxGTK_CONV(text), matchCase, 0);
1008 //In this case we return early to match IE behaviour
1009 m_findPosition = -1;
1010 return m_findCount;
1011 }
1012 else
1013 {
1014 if(forward)
1015 m_findPosition++;
1016 else
1017 m_findPosition--;
1018 if(m_findPosition < 0)
1019 m_findPosition += m_findCount;
1020 if(m_findPosition > m_findCount)
1021 m_findPosition -= m_findCount;
1022 }
1023
1024 //Highlight them if needed
1025 bool highlight = flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT ? true : false;
1026 webkit_web_view_set_highlight_text_matches(m_web_view, highlight);
1027
1028 if(!webkit_web_view_search_text(m_web_view, wxGTK_CONV(text), matchCase, forward, wrap))
1029 {
1030 m_findPosition = -1;
1031 ClearSelection();
1032 return wxNOT_FOUND;
1033 }
1034 wxLogMessage(wxString::Format("Returning %d", m_findPosition));
1035 return newSearch ? m_findCount : m_findPosition;
1036 }
1037
FindClear()1038 void wxWebViewWebKit::FindClear()
1039 {
1040 m_findCount = 0;
1041 m_findFlags = 0;
1042 m_findText = "";
1043 m_findPosition = -1;
1044 }
1045
1046 // static
1047 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))1048 wxWebViewWebKit::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1049 {
1050 return GetDefaultAttributesFromGTKWidget(webkit_web_view_new());
1051 }
1052
1053
1054 #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT
1055