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