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