]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/webview_webkit.cpp
Do give focus to the wxNotebook page when switching to it under MSW.
[wxWidgets.git] / src / gtk / webview_webkit.cpp
CommitLineData
61b98a2d 1/////////////////////////////////////////////////////////////////////////////
8290e3cd 2// Name: src/gtk/webview_webkit.cpp
61b98a2d
SL
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
9d2f31db 13#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT
61b98a2d
SL
14
15#include "wx/stockitem.h"
8290e3cd 16#include "wx/gtk/webview_webkit.h"
61b98a2d
SL
17#include "wx/gtk/control.h"
18#include "wx/gtk/private.h"
f2049b68 19#include "wx/filesys.h"
eea4d01c 20#include "wx/base64.h"
825417a4 21#include "wx/log.h"
a0ff3611 22#include <webkit/webkit.h>
61b98a2d
SL
23
24// ----------------------------------------------------------------------------
25// GTK callbacks
26// ----------------------------------------------------------------------------
27
28extern "C"
29{
30
31static void
34326da7 32wxgtk_webview_webkit_load_status(GtkWidget* widget,
d363c7db
SL
33 GParamSpec*,
34 wxWebViewWebKit *webKitCtrl)
61b98a2d 35{
c3980646
VZ
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
61b98a2d
SL
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 {
ce88a107
SL
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 {
f0776dc4
VZ
57 WebKitWebHistoryItem*
58 newitem = webkit_web_history_item_new_with_data
59 (
60 url.utf8_str(),
61 webKitCtrl->GetCurrentTitle().utf8_str()
62 );
ce88a107
SL
63 webkit_web_back_forward_list_add_item(hist, newitem);
64 }
65
61b98a2d 66 webKitCtrl->m_busy = false;
04fa04d8
SL
67 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED,
68 webKitCtrl->GetId(),
3225a4b8 69 url, target);
61b98a2d
SL
70
71 if (webKitCtrl && webKitCtrl->GetEventHandler())
04fa04d8 72 webKitCtrl->GetEventHandler()->ProcessEvent(event);
61b98a2d
SL
73 }
74 else if (status == WEBKIT_LOAD_COMMITTED)
75 {
76 webKitCtrl->m_busy = true;
04fa04d8
SL
77 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
78 webKitCtrl->GetId(),
3225a4b8 79 url, target);
61b98a2d
SL
80
81 if (webKitCtrl && webKitCtrl->GetEventHandler())
04fa04d8 82 webKitCtrl->GetEventHandler()->ProcessEvent(event);
61b98a2d
SL
83 }
84}
85
780f7262 86static gboolean
36b52591 87wxgtk_webview_webkit_navigation(WebKitWebView *,
780f7262
SL
88 WebKitWebFrame *frame,
89 WebKitNetworkRequest *request,
153530af 90 WebKitWebNavigationAction *,
780f7262
SL
91 WebKitWebPolicyDecision *policy_decision,
92 wxWebViewWebKit *webKitCtrl)
61b98a2d 93{
36b52591
SL
94 if(webKitCtrl->m_guard)
95 {
96 webKitCtrl->m_guard = false;
34326da7 97 //We set this to make sure that we don't try to load the page again from
211da8a5
SL
98 //the resource request callback
99 webKitCtrl->m_vfsurl = webkit_network_request_get_uri(request);
100 webkit_web_policy_decision_use(policy_decision);
36b52591
SL
101 return FALSE;
102 }
103
61b98a2d
SL
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);
04fa04d8
SL
109 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
110 webKitCtrl->GetId(),
111 wxString( uri, wxConvUTF8 ),
3225a4b8 112 target);
61b98a2d
SL
113
114 if (webKitCtrl && webKitCtrl->GetEventHandler())
04fa04d8 115 webKitCtrl->GetEventHandler()->ProcessEvent(event);
61b98a2d 116
3225a4b8 117 if (!event.IsAllowed())
61b98a2d
SL
118 {
119 webKitCtrl->m_busy = false;
780f7262
SL
120 webkit_web_policy_decision_ignore(policy_decision);
121 return TRUE;
61b98a2d
SL
122 }
123 else
124 {
f2049b68 125 wxString wxuri = uri;
7d8d6163
SL
126 wxSharedPtr<wxWebViewHandler> handler;
127 wxVector<wxSharedPtr<wxWebViewHandler> > hanlders = webKitCtrl->GetHandlers();
f2049b68 128 //We are not vetoed so see if we match one of the additional handlers
7d8d6163 129 for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = hanlders.begin();
f2049b68
SL
130 it != hanlders.end(); ++it)
131 {
132 if(wxuri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
133 {
134 handler = (*it);
135 }
136 }
34326da7 137 //If we found a handler we can then use it to load the file directly
f2049b68
SL
138 //ourselves
139 if(handler)
140 {
36b52591 141 webKitCtrl->m_guard = true;
f2049b68 142 wxFSFile* file = handler->GetFile(wxuri);
36b52591
SL
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;
f2049b68 150 }
780f7262 151 return FALSE;
61b98a2d
SL
152 }
153}
154
155static gboolean
d363c7db
SL
156wxgtk_webview_webkit_error(WebKitWebView*,
157 WebKitWebFrame*,
158 gchar *uri,
159 gpointer web_error,
160 wxWebViewWebKit* webKitWindow)
61b98a2d
SL
161{
162 webKitWindow->m_busy = false;
04fa04d8 163 wxWebViewNavigationError type = wxWEB_NAV_ERR_OTHER;
61b98a2d
SL
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
04fa04d8
SL
282 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR,
283 webKitWindow->GetId(),
3225a4b8 284 uri, "");
04fa04d8
SL
285 event.SetString(description);
286 event.SetInt(type);
61b98a2d
SL
287
288 if (webKitWindow && webKitWindow->GetEventHandler())
289 {
04fa04d8 290 webKitWindow->GetEventHandler()->ProcessEvent(event);
61b98a2d
SL
291 }
292
293 return FALSE;
294}
295
0016bf1d 296static gboolean
d363c7db
SL
297wxgtk_webview_webkit_new_window(WebKitWebView*,
298 WebKitWebFrame *frame,
299 WebKitNetworkRequest *request,
300 WebKitWebNavigationAction*,
301 WebKitWebPolicyDecision *policy_decision,
302 wxWebViewWebKit *webKitCtrl)
0016bf1d
SL
303{
304 const gchar* uri = webkit_network_request_get_uri(request);
305
306 wxString target = webkit_web_frame_get_name (frame);
04fa04d8
SL
307 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
308 webKitCtrl->GetId(),
309 wxString( uri, wxConvUTF8 ),
3225a4b8 310 target);
0016bf1d
SL
311
312 if (webKitCtrl && webKitCtrl->GetEventHandler())
04fa04d8 313 webKitCtrl->GetEventHandler()->ProcessEvent(event);
0016bf1d 314
75b3bb61
SL
315 //We always want the user to handle this themselves
316 webkit_web_policy_decision_ignore(policy_decision);
0016bf1d
SL
317 return TRUE;
318}
61b98a2d 319
153530af 320static void
bd6f9534
SL
321wxgtk_webview_webkit_title_changed(WebKitWebView*,
322 WebKitWebFrame*,
153530af
SL
323 gchar *title,
324 wxWebViewWebKit *webKitCtrl)
325{
04fa04d8
SL
326 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED,
327 webKitCtrl->GetId(),
328 webKitCtrl->GetCurrentURL(),
3225a4b8 329 "");
04fa04d8 330 event.SetString(wxString(title, wxConvUTF8));
153530af
SL
331
332 if (webKitCtrl && webKitCtrl->GetEventHandler())
04fa04d8 333 webKitCtrl->GetEventHandler()->ProcessEvent(event);
153530af
SL
334
335}
336
211da8a5
SL
337static void
338wxgtk_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);
34326da7 346
7d8d6163
SL
347 wxSharedPtr<wxWebViewHandler> handler;
348 wxVector<wxSharedPtr<wxWebViewHandler> > hanlders = webKitCtrl->GetHandlers();
34326da7 349
211da8a5 350 //We are not vetoed so see if we match one of the additional handlers
7d8d6163 351 for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = hanlders.begin();
211da8a5
SL
352 it != hanlders.end(); ++it)
353 {
354 if(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
355 {
356 handler = (*it);
357 }
358 }
34326da7 359 //If we found a handler we can then use it to load the file directly
211da8a5
SL
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 {
eea4d01c 371 //We load the data into a data url to save it being written out again
211da8a5
SL
372 size_t size = file->GetStream()->GetLength();
373 char *buffer = new char[size];
211da8a5 374 file->GetStream()->Read(buffer, size);
eea4d01c 375 wxString data = wxBase64Encode(buffer, size);
211da8a5 376 delete[] buffer;
eea4d01c
SL
377 wxString mime = file->GetMimeType();
378 wxString path = "data:" + mime + ";base64," + data;
211da8a5 379 //Then we can redirect the call
f0776dc4 380 webkit_network_request_set_uri(request, path.utf8_str());
211da8a5 381 }
34326da7 382
211da8a5
SL
383 }
384}
385
61b98a2d
SL
386} // extern "C"
387
388//-----------------------------------------------------------------------------
b64b4e70 389// wxWebViewWebKit
61b98a2d
SL
390//-----------------------------------------------------------------------------
391
cddf4541 392wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewWebKit, wxWebView);
61b98a2d 393
b64b4e70 394bool wxWebViewWebKit::Create(wxWindow *parent,
61b98a2d
SL
395 wxWindowID id,
396 const wxString &url,
397 const wxPoint& pos,
398 const wxSize& size,
399 long style,
400 const wxString& name)
401{
61b98a2d 402 m_busy = false;
36b52591 403 m_guard = false;
66ac0400 404 FindClear();
61b98a2d 405
1f7c17f4
VZ
406 // We currently unconditionally impose scrolling in both directions as it's
407 // necessary to show arbitrary pages.
408 style |= wxHSCROLL | wxVSCROLL;
409
61b98a2d
SL
410 if (!PreCreation( parent, pos, size ) ||
411 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
412 {
b64b4e70 413 wxFAIL_MSG( wxT("wxWebViewWebKit creation failed") );
61b98a2d
SL
414 return false;
415 }
416
4c9bde5e 417 m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
1f7c17f4
VZ
418 GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
419 g_object_ref(m_widget);
61b98a2d 420
4c9bde5e 421 g_signal_connect_after(m_web_view, "navigation-policy-decision-requested",
780f7262 422 G_CALLBACK(wxgtk_webview_webkit_navigation),
61b98a2d 423 this);
34326da7 424 g_signal_connect_after(m_web_view, "load-error",
d363c7db 425 G_CALLBACK(wxgtk_webview_webkit_error),
61b98a2d
SL
426 this);
427
4c9bde5e 428 g_signal_connect_after(m_web_view, "new-window-policy-decision-requested",
d363c7db 429 G_CALLBACK(wxgtk_webview_webkit_new_window), this);
61b98a2d 430
4c9bde5e 431 g_signal_connect_after(m_web_view, "title-changed",
153530af
SL
432 G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
433
4c9bde5e 434 g_signal_connect_after(m_web_view, "resource-request-starting",
211da8a5
SL
435 G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
436
61b98a2d
SL
437 m_parent->DoAddChild( this );
438
439 PostCreation(size);
440
441 /* Open a webpage */
4c9bde5e 442 webkit_web_view_load_uri(m_web_view, url.utf8_str());
61b98a2d 443
152a5808
SL
444 //Get the initial history limit so we can enable and disable it later
445 WebKitWebBackForwardList* history;
4c9bde5e 446 history = webkit_web_view_get_back_forward_list(m_web_view);
152a5808
SL
447 m_historyLimit = webkit_web_back_forward_list_get_limit(history);
448
7cf17ea2
PC
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);
61b98a2d
SL
453
454 return true;
455}
456
c3980646
VZ
457wxWebViewWebKit::~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
b64b4e70 466bool wxWebViewWebKit::Enable( bool enable )
61b98a2d
SL
467{
468 if (!wxControl::Enable(enable))
469 return false;
470
9dc44eff 471 gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable);
61b98a2d
SL
472
473 //if (enable)
474 // GTKFixSensitivity();
475
476 return true;
477}
478
479GdkWindow*
b64b4e70 480wxWebViewWebKit::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
61b98a2d
SL
481{
482 GdkWindow* window = gtk_widget_get_parent_window(m_widget);
483 return window;
484}
485
b64b4e70 486void wxWebViewWebKit::ZoomIn()
61b98a2d 487{
4c9bde5e 488 webkit_web_view_zoom_in(m_web_view);
61b98a2d
SL
489}
490
b64b4e70 491void wxWebViewWebKit::ZoomOut()
61b98a2d 492{
4c9bde5e 493 webkit_web_view_zoom_out(m_web_view);
61b98a2d
SL
494}
495
b64b4e70 496void wxWebViewWebKit::SetWebkitZoom(float level)
61b98a2d 497{
4c9bde5e 498 webkit_web_view_set_zoom_level(m_web_view, level);
61b98a2d
SL
499}
500
e669ddde 501float wxWebViewWebKit::GetWebkitZoom() const
61b98a2d 502{
4c9bde5e 503 return webkit_web_view_get_zoom_level(m_web_view);
61b98a2d
SL
504}
505
b64b4e70 506void wxWebViewWebKit::Stop()
61b98a2d 507{
4c9bde5e 508 webkit_web_view_stop_loading(m_web_view);
61b98a2d
SL
509}
510
b64b4e70 511void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags)
61b98a2d
SL
512{
513 if (flags & wxWEB_VIEW_RELOAD_NO_CACHE)
514 {
4c9bde5e 515 webkit_web_view_reload_bypass_cache(m_web_view);
61b98a2d
SL
516 }
517 else
518 {
4c9bde5e 519 webkit_web_view_reload(m_web_view);
61b98a2d
SL
520 }
521}
522
4d0dddc7 523void wxWebViewWebKit::LoadURL(const wxString& url)
61b98a2d 524{
4c9bde5e 525 webkit_web_view_load_uri(m_web_view, wxGTK_CONV(url));
61b98a2d
SL
526}
527
528
b64b4e70 529void wxWebViewWebKit::GoBack()
61b98a2d 530{
4c9bde5e 531 webkit_web_view_go_back(m_web_view);
61b98a2d
SL
532}
533
b64b4e70 534void wxWebViewWebKit::GoForward()
61b98a2d 535{
4c9bde5e 536 webkit_web_view_go_forward(m_web_view);
61b98a2d
SL
537}
538
539
e669ddde 540bool wxWebViewWebKit::CanGoBack() const
61b98a2d 541{
4c9bde5e 542 return webkit_web_view_can_go_back(m_web_view);
61b98a2d
SL
543}
544
545
e669ddde 546bool wxWebViewWebKit::CanGoForward() const
61b98a2d 547{
4c9bde5e 548 return webkit_web_view_can_go_forward(m_web_view);
61b98a2d
SL
549}
550
152a5808
SL
551void wxWebViewWebKit::ClearHistory()
552{
553 WebKitWebBackForwardList* history;
4c9bde5e 554 history = webkit_web_view_get_back_forward_list(m_web_view);
152a5808
SL
555 webkit_web_back_forward_list_clear(history);
556}
557
558void wxWebViewWebKit::EnableHistory(bool enable)
559{
560 WebKitWebBackForwardList* history;
4c9bde5e 561 history = webkit_web_view_get_back_forward_list(m_web_view);
152a5808
SL
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}
61b98a2d 571
c13d6ac1 572wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetBackwardHistory()
19fc1a2f 573{
34326da7 574 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
19fc1a2f 575 WebKitWebBackForwardList* history;
4c9bde5e 576 history = webkit_web_view_get_back_forward_list(m_web_view);
34326da7 577 GList* list = webkit_web_back_forward_list_get_back_list_with_limit(history,
19fc1a2f
SL
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);
c13d6ac1 583 wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
263e3a83
SL
584 webkit_web_history_item_get_uri(gtkitem),
585 webkit_web_history_item_get_title(gtkitem));
586 wxitem->m_histItem = gtkitem;
c13d6ac1 587 wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
19fc1a2f 588 backhist.push_back(item);
19fc1a2f
SL
589 }
590 return backhist;
591}
592
c13d6ac1 593wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetForwardHistory()
19fc1a2f 594{
34326da7 595 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
19fc1a2f 596 WebKitWebBackForwardList* history;
4c9bde5e 597 history = webkit_web_view_get_back_forward_list(m_web_view);
34326da7 598 GList* list = webkit_web_back_forward_list_get_forward_list_with_limit(history,
19fc1a2f
SL
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);
c13d6ac1 603 wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
263e3a83
SL
604 webkit_web_history_item_get_uri(gtkitem),
605 webkit_web_history_item_get_title(gtkitem));
606 wxitem->m_histItem = gtkitem;
c13d6ac1 607 wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
19fc1a2f 608 forwardhist.push_back(item);
19fc1a2f
SL
609 }
610 return forwardhist;
611}
612
c13d6ac1 613void wxWebViewWebKit::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
19fc1a2f 614{
a0ff3611 615 WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)item->m_histItem;
19fc1a2f
SL
616 if(gtkitem)
617 {
34326da7 618 webkit_web_view_go_to_back_forward_item(m_web_view,
263e3a83 619 WEBKIT_WEB_HISTORY_ITEM(gtkitem));
19fc1a2f
SL
620 }
621}
622
e669ddde 623bool wxWebViewWebKit::CanCut() const
ae26e17b 624{
4c9bde5e 625 return webkit_web_view_can_cut_clipboard(m_web_view);
ae26e17b
SL
626}
627
e669ddde 628bool wxWebViewWebKit::CanCopy() const
ae26e17b 629{
4c9bde5e 630 return webkit_web_view_can_copy_clipboard(m_web_view);
ae26e17b
SL
631}
632
e669ddde 633bool wxWebViewWebKit::CanPaste() const
ae26e17b 634{
4c9bde5e 635 return webkit_web_view_can_paste_clipboard(m_web_view);
ae26e17b
SL
636}
637
638void wxWebViewWebKit::Cut()
639{
4c9bde5e 640 webkit_web_view_cut_clipboard(m_web_view);
ae26e17b
SL
641}
642
643void wxWebViewWebKit::Copy()
644{
4c9bde5e 645 webkit_web_view_copy_clipboard(m_web_view);
ae26e17b
SL
646}
647
648void wxWebViewWebKit::Paste()
649{
4c9bde5e 650 webkit_web_view_paste_clipboard(m_web_view);
ae26e17b
SL
651}
652
e669ddde 653bool wxWebViewWebKit::CanUndo() const
97e49559 654{
4c9bde5e 655 return webkit_web_view_can_undo(m_web_view);
97e49559
SL
656}
657
e669ddde 658bool wxWebViewWebKit::CanRedo() const
97e49559 659{
4c9bde5e 660 return webkit_web_view_can_redo(m_web_view);
97e49559
SL
661}
662
663void wxWebViewWebKit::Undo()
664{
4c9bde5e 665 webkit_web_view_undo(m_web_view);
97e49559
SL
666}
667
668void wxWebViewWebKit::Redo()
669{
4c9bde5e 670 webkit_web_view_redo(m_web_view);
97e49559
SL
671}
672
e669ddde 673wxString wxWebViewWebKit::GetCurrentURL() const
61b98a2d
SL
674{
675 // FIXME: check which encoding the web kit control uses instead of
676 // assuming UTF8 (here and elsewhere too)
4c9bde5e 677 return wxString::FromUTF8(webkit_web_view_get_uri(m_web_view));
61b98a2d
SL
678}
679
680
e669ddde 681wxString wxWebViewWebKit::GetCurrentTitle() const
61b98a2d 682{
4c9bde5e 683 return wxString::FromUTF8(webkit_web_view_get_title(m_web_view));
61b98a2d
SL
684}
685
686
e669ddde 687wxString wxWebViewWebKit::GetPageSource() const
61b98a2d 688{
4c9bde5e 689 WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
61b98a2d
SL
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
e669ddde 699wxWebViewZoom wxWebViewWebKit::GetZoom() const
61b98a2d
SL
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
b64b4e70 731void wxWebViewWebKit::SetZoom(wxWebViewZoom zoom)
61b98a2d
SL
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
b64b4e70 761void wxWebViewWebKit::SetZoomType(wxWebViewZoomType type)
61b98a2d 762{
4c9bde5e 763 webkit_web_view_set_full_content_zoom(m_web_view,
61b98a2d
SL
764 (type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT ?
765 TRUE : FALSE));
766}
767
b64b4e70 768wxWebViewZoomType wxWebViewWebKit::GetZoomType() const
61b98a2d 769{
4c9bde5e 770 gboolean fczoom = webkit_web_view_get_full_content_zoom(m_web_view);
61b98a2d
SL
771
772 if (fczoom) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT;
773 else return wxWEB_VIEW_ZOOM_TYPE_TEXT;
774}
775
b64b4e70 776bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType) const
61b98a2d
SL
777{
778 // this port supports all zoom types
779 return true;
780}
781
a977376a 782void wxWebViewWebKit::DoSetPage(const wxString& html, const wxString& baseUri)
61b98a2d 783{
4c9bde5e 784 webkit_web_view_load_string (m_web_view,
61b98a2d
SL
785 html.mb_str(wxConvUTF8),
786 "text/html",
787 "UTF-8",
788 baseUri.mb_str(wxConvUTF8));
789}
790
b64b4e70 791void wxWebViewWebKit::Print()
61b98a2d 792{
4c9bde5e 793 WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
61b98a2d
SL
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
e669ddde 805bool wxWebViewWebKit::IsBusy() const
61b98a2d
SL
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
c7cbe308
SL
831void wxWebViewWebKit::SetEditable(bool enable)
832{
4c9bde5e 833 webkit_web_view_set_editable(m_web_view, enable);
c7cbe308
SL
834}
835
e669ddde 836bool wxWebViewWebKit::IsEditable() const
c7cbe308 837{
4c9bde5e 838 return webkit_web_view_get_editable(m_web_view);
c7cbe308
SL
839}
840
63a65070
SL
841void wxWebViewWebKit::DeleteSelection()
842{
4c9bde5e 843 webkit_web_view_delete_selection(m_web_view);
63a65070
SL
844}
845
e669ddde 846bool wxWebViewWebKit::HasSelection() const
63a65070 847{
4c9bde5e 848 return webkit_web_view_has_selection(m_web_view);
63a65070
SL
849}
850
851void wxWebViewWebKit::SelectAll()
852{
4c9bde5e 853 webkit_web_view_select_all(m_web_view);
63a65070
SL
854}
855
e669ddde 856wxString wxWebViewWebKit::GetSelectedText() const
c9355a3d 857{
34326da7 858 WebKitDOMDocument* doc;
c9355a3d
SL
859 WebKitDOMDOMWindow* win;
860 WebKitDOMDOMSelection* sel;
861 WebKitDOMRange* range;
862
4c9bde5e 863 doc = webkit_web_view_get_dom_document(m_web_view);
c9355a3d
SL
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));
34326da7 866 range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
c9355a3d 867 0, NULL);
34326da7 868 return wxString(webkit_dom_range_get_text(WEBKIT_DOM_RANGE(range)),
c9355a3d
SL
869 wxConvUTF8);
870}
63a65070 871
e669ddde 872wxString wxWebViewWebKit::GetSelectedSource() const
0fe8a1b6 873{
34326da7 874 WebKitDOMDocument* doc;
0fe8a1b6
SL
875 WebKitDOMDOMWindow* win;
876 WebKitDOMDOMSelection* sel;
877 WebKitDOMRange* range;
878 WebKitDOMElement* div;
879 WebKitDOMDocumentFragment* clone;
880 WebKitDOMHTMLElement* html;
881
4c9bde5e 882 doc = webkit_web_view_get_dom_document(m_web_view);
0fe8a1b6
SL
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));
34326da7 885 range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
0fe8a1b6
SL
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
34326da7 893 return wxString(webkit_dom_html_element_get_inner_html(WEBKIT_DOM_HTML_ELEMENT(html)),
0fe8a1b6
SL
894 wxConvUTF8);
895}
896
41933aa5
SL
897void wxWebViewWebKit::ClearSelection()
898{
34326da7 899 WebKitDOMDocument* doc;
41933aa5
SL
900 WebKitDOMDOMWindow* win;
901 WebKitDOMDOMSelection* sel;
902
4c9bde5e 903 doc = webkit_web_view_get_dom_document(m_web_view);
41933aa5
SL
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
e669ddde 910wxString wxWebViewWebKit::GetPageText() const
241b769f 911{
34326da7 912 WebKitDOMDocument* doc;
241b769f
SL
913 WebKitDOMHTMLElement* body;
914
4c9bde5e 915 doc = webkit_web_view_get_dom_document(m_web_view);
241b769f 916 body = webkit_dom_document_get_body(WEBKIT_DOM_DOCUMENT(doc));
34326da7 917 return wxString(webkit_dom_html_element_get_inner_text(WEBKIT_DOM_HTML_ELEMENT(body)),
241b769f
SL
918 wxConvUTF8);
919}
920
c9ccc09c
SL
921void wxWebViewWebKit::RunScript(const wxString& javascript)
922{
34326da7 923 webkit_web_view_execute_script(m_web_view,
c9ccc09c
SL
924 javascript.mb_str(wxConvUTF8));
925}
926
7d8d6163 927void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
f2049b68
SL
928{
929 m_handlerList.push_back(handler);
930}
931
66ac0400
SL
932long 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
998void wxWebViewWebKit::FindClear()
999{
1000 m_findCount = 0;
1001 m_findFlags = 0;
1002 m_findText = "";
1003 m_findPosition = -1;
1004}
1005
61b98a2d
SL
1006// static
1007wxVisualAttributes
b64b4e70 1008wxWebViewWebKit::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
61b98a2d
SL
1009{
1010 return GetDefaultAttributesFromGTKWidget(webkit_web_view_new);
1011}
1012
1013
9d2f31db 1014#endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT