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