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