Rename source files for consistency
[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
14 #if wxHAVE_WEB_BACKEND_GTK_WEBKIT
15
16 #include "wx/stockitem.h"
17 #include "wx/gtk/webview_webkit.h"
18 #include "wx/gtk/control.h"
19 #include "wx/gtk/private.h"
20 #include "webkit/webkit.h"
21
22 // ----------------------------------------------------------------------------
23 // GTK callbacks
24 // ----------------------------------------------------------------------------
25
26 extern "C"
27 {
28
29 static void
30 wxgtk_webkitctrl_load_status_callback(GtkWidget* widget, GParamSpec* arg1,
31 wxWebViewGTKWebKit *webKitCtrl)
32 {
33 if (!webKitCtrl->m_ready) return;
34
35 wxString url = webKitCtrl->GetCurrentURL();
36
37 WebKitLoadStatus status;
38 g_object_get(G_OBJECT(widget), "load-status", &status, NULL);
39
40 wxString target; // TODO: get target (if possible)
41
42 if (status == WEBKIT_LOAD_FINISHED)
43 {
44 webKitCtrl->m_busy = false;
45 wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED,
46 webKitCtrl->GetId(),
47 url, target, false);
48
49 if (webKitCtrl && webKitCtrl->GetEventHandler())
50 webKitCtrl->GetEventHandler()->ProcessEvent(thisEvent);
51 }
52 else if (status == WEBKIT_LOAD_COMMITTED)
53 {
54 webKitCtrl->m_busy = true;
55 wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
56 webKitCtrl->GetId(),
57 url, target, false);
58
59 if (webKitCtrl && webKitCtrl->GetEventHandler())
60 webKitCtrl->GetEventHandler()->ProcessEvent(thisEvent);
61 }
62 }
63
64 static WebKitNavigationResponse
65 wxgtk_webkitctrl_navigation_requ_callback(WebKitWebView *web_view,
66 WebKitWebFrame *frame,
67 WebKitNetworkRequest *request,
68 wxWebViewGTKWebKit *webKitCtrl)
69 {
70 webKitCtrl->m_busy = true;
71
72 const gchar* uri = webkit_network_request_get_uri(request);
73
74 wxString target = webkit_web_frame_get_name (frame);
75 wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
76 webKitCtrl->GetId(),
77 wxString( uri, wxConvUTF8 ),
78 target,
79 true);
80
81 if (webKitCtrl && webKitCtrl->GetEventHandler())
82 webKitCtrl->GetEventHandler()->ProcessEvent(thisEvent);
83
84 if (thisEvent.IsVetoed())
85 {
86 webKitCtrl->m_busy = false;
87 return WEBKIT_NAVIGATION_RESPONSE_IGNORE;
88 }
89 else
90 {
91 return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
92 }
93 }
94
95 static gboolean
96 wxgtk_webkitctrl_error (WebKitWebView *web_view,
97 WebKitWebFrame *web_frame,
98 gchar *uri,
99 gpointer web_error,
100 wxWebViewGTKWebKit* webKitWindow)
101 {
102 webKitWindow->m_busy = false;
103 wxWebNavigationError type = wxWEB_NAV_ERR_OTHER;
104
105 GError* error = (GError*)web_error;
106 wxString description(error->message, wxConvUTF8);
107
108 if (strcmp(g_quark_to_string(error->domain), "soup_http_error_quark") == 0)
109 {
110 switch (error->code)
111 {
112 case SOUP_STATUS_CANCELLED:
113 type = wxWEB_NAV_ERR_USER_CANCELLED;
114 break;
115
116 case SOUP_STATUS_CANT_RESOLVE:
117 case SOUP_STATUS_NOT_FOUND:
118 type = wxWEB_NAV_ERR_NOT_FOUND;
119 break;
120
121 case SOUP_STATUS_CANT_RESOLVE_PROXY:
122 case SOUP_STATUS_CANT_CONNECT:
123 case SOUP_STATUS_CANT_CONNECT_PROXY:
124 case SOUP_STATUS_SSL_FAILED:
125 case SOUP_STATUS_IO_ERROR:
126 type = wxWEB_NAV_ERR_CONNECTION;
127 break;
128
129 case SOUP_STATUS_MALFORMED:
130 //case SOUP_STATUS_TOO_MANY_REDIRECTS:
131 type = wxWEB_NAV_ERR_REQUEST;
132 break;
133
134 //case SOUP_STATUS_NO_CONTENT:
135 //case SOUP_STATUS_RESET_CONTENT:
136
137 case SOUP_STATUS_BAD_REQUEST:
138 type = wxWEB_NAV_ERR_REQUEST;
139 break;
140
141 case SOUP_STATUS_UNAUTHORIZED:
142 case SOUP_STATUS_FORBIDDEN:
143 type = wxWEB_NAV_ERR_AUTH;
144 break;
145
146 case SOUP_STATUS_METHOD_NOT_ALLOWED:
147 case SOUP_STATUS_NOT_ACCEPTABLE:
148 type = wxWEB_NAV_ERR_SECURITY;
149 break;
150
151 case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
152 type = wxWEB_NAV_ERR_AUTH;
153 break;
154
155 case SOUP_STATUS_REQUEST_TIMEOUT:
156 type = wxWEB_NAV_ERR_CONNECTION;
157 break;
158
159 //case SOUP_STATUS_PAYMENT_REQUIRED:
160 case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE:
161 case SOUP_STATUS_REQUEST_URI_TOO_LONG:
162 case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE:
163 type = wxWEB_NAV_ERR_REQUEST;
164 break;
165
166 case SOUP_STATUS_BAD_GATEWAY:
167 case SOUP_STATUS_SERVICE_UNAVAILABLE:
168 case SOUP_STATUS_GATEWAY_TIMEOUT:
169 type = wxWEB_NAV_ERR_CONNECTION;
170 break;
171
172 case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
173 type = wxWEB_NAV_ERR_REQUEST;
174 break;
175 //case SOUP_STATUS_INSUFFICIENT_STORAGE:
176 //case SOUP_STATUS_NOT_EXTENDED:
177 }
178 }
179 else if (strcmp(g_quark_to_string(error->domain),
180 "webkit-network-error-quark") == 0)
181 {
182 switch (error->code)
183 {
184 //WEBKIT_NETWORK_ERROR_FAILED:
185 //WEBKIT_NETWORK_ERROR_TRANSPORT:
186
187 case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL:
188 type = wxWEB_NAV_ERR_REQUEST;
189 break;
190
191 case WEBKIT_NETWORK_ERROR_CANCELLED:
192 type = wxWEB_NAV_ERR_USER_CANCELLED;
193 break;
194
195 case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST:
196 type = wxWEB_NAV_ERR_NOT_FOUND;
197 break;
198 }
199 }
200 else if (strcmp(g_quark_to_string(error->domain),
201 "webkit-policy-error-quark") == 0)
202 {
203 switch (error->code)
204 {
205 //case WEBKIT_POLICY_ERROR_FAILED:
206 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE:
207 //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
208 //case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
209 case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT:
210 type = wxWEB_NAV_ERR_SECURITY;
211 break;
212 }
213 }
214 /*
215 webkit_plugin_error_quark
216 else
217 {
218 printf("Error domain %s\n", g_quark_to_string(error->domain));
219 }
220 */
221
222 wxWebNavigationEvent thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR,
223 webKitWindow->GetId(),
224 uri,
225 wxEmptyString,
226 false);
227 thisEvent.SetString(description);
228 thisEvent.SetInt(type);
229
230 if (webKitWindow && webKitWindow->GetEventHandler())
231 {
232 webKitWindow->GetEventHandler()->ProcessEvent(thisEvent);
233 }
234
235 return FALSE;
236 }
237
238
239 } // extern "C"
240
241 //-----------------------------------------------------------------------------
242 // wxWebViewGTKWebKit
243 //-----------------------------------------------------------------------------
244
245 //IMPLEMENT_DYNAMIC_CLASS(wxWebViewGTKWebKit, wxControl)
246
247 bool wxWebViewGTKWebKit::Create(wxWindow *parent,
248 wxWindowID id,
249 const wxString &url,
250 const wxPoint& pos,
251 const wxSize& size,
252 long style,
253 const wxString& name)
254 {
255 m_ready = false;
256 m_busy = false;
257
258 if (!PreCreation( parent, pos, size ) ||
259 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
260 {
261 wxFAIL_MSG( wxT("wxWebViewGTKWebKit creation failed") );
262 return false;
263 }
264
265 GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
266 web_view = webkit_web_view_new ();
267 g_object_ref(web_view); // TODO: check memory management
268
269 m_widget = scrolled_window;
270 g_object_ref(m_widget); // TODO: check memory management
271
272 /* Place the WebKitWebView in the GtkScrolledWindow */
273 gtk_container_add (GTK_CONTAINER (scrolled_window), web_view);
274 gtk_widget_show(m_widget);
275 gtk_widget_show(web_view);
276
277 g_signal_connect_after(web_view, "notify::load-status",
278 G_CALLBACK(wxgtk_webkitctrl_load_status_callback),
279 this);
280 g_signal_connect_after(web_view, "navigation-requested",
281 G_CALLBACK(wxgtk_webkitctrl_navigation_requ_callback),
282 this);
283 g_signal_connect_after(web_view, "load-error",
284 G_CALLBACK(wxgtk_webkitctrl_error),
285 this);
286
287 // this signal can be added if we care about new frames open requests
288 //g_signal_connect_after(web_view, "new-window-policy-decision-requested",
289 // G_CALLBACK(...), this);
290
291 m_parent->DoAddChild( this );
292
293 PostCreation(size);
294
295 /* Open a webpage */
296 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view), url);
297
298 m_ready = true;
299
300 return true;
301 }
302
303 bool wxWebViewGTKWebKit::Enable( bool enable )
304 {
305 if (!wxControl::Enable(enable))
306 return false;
307
308 gtk_widget_set_sensitive(GTK_BIN(m_widget)->child, enable);
309
310 //if (enable)
311 // GTKFixSensitivity();
312
313 return true;
314 }
315
316 GdkWindow*
317 wxWebViewGTKWebKit::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
318 {
319 GdkWindow* window = gtk_widget_get_parent_window(m_widget);
320 return window;
321 }
322
323 void wxWebViewGTKWebKit::ZoomIn()
324 {
325 webkit_web_view_zoom_in (WEBKIT_WEB_VIEW(web_view));
326 }
327
328 void wxWebViewGTKWebKit::ZoomOut()
329 {
330 webkit_web_view_zoom_out (WEBKIT_WEB_VIEW(web_view));
331 }
332
333 void wxWebViewGTKWebKit::SetWebkitZoom(float level)
334 {
335 webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(web_view), level);
336 }
337
338 float wxWebViewGTKWebKit::GetWebkitZoom()
339 {
340 return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW(web_view));
341 }
342
343 void wxWebViewGTKWebKit::Stop()
344 {
345 webkit_web_view_stop_loading (WEBKIT_WEB_VIEW(web_view));
346 }
347
348 void wxWebViewGTKWebKit::Reload(wxWebViewReloadFlags flags)
349 {
350 if (flags & wxWEB_VIEW_RELOAD_NO_CACHE)
351 {
352 webkit_web_view_reload_bypass_cache (WEBKIT_WEB_VIEW(web_view));
353 }
354 else
355 {
356 webkit_web_view_reload (WEBKIT_WEB_VIEW(web_view));
357 }
358 }
359
360 void wxWebViewGTKWebKit::LoadUrl(const wxString& url)
361 {
362 webkit_web_view_open(WEBKIT_WEB_VIEW(web_view), wxGTK_CONV(loc));
363 }
364
365
366 void wxWebViewGTKWebKit::GoBack()
367 {
368 webkit_web_view_go_back (WEBKIT_WEB_VIEW(web_view));
369 }
370
371 void wxWebViewGTKWebKit::GoForward()
372 {
373 webkit_web_view_go_forward (WEBKIT_WEB_VIEW(web_view));
374 }
375
376
377 bool wxWebViewGTKWebKit::CanGoBack()
378 {
379 return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW(web_view));
380 }
381
382
383 bool wxWebViewGTKWebKit::CanGoForward()
384 {
385 return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW(web_view));
386 }
387
388
389 wxString wxWebViewGTKWebKit::GetCurrentURL()
390 {
391 // FIXME: check which encoding the web kit control uses instead of
392 // assuming UTF8 (here and elsewhere too)
393 return wxString::FromUTF8(webkit_web_view_get_uri(
394 WEBKIT_WEB_VIEW(web_view)));
395 }
396
397
398 wxString wxWebViewGTKWebKit::GetCurrentTitle()
399 {
400 return wxString::FromUTF8(webkit_web_view_get_title(
401 WEBKIT_WEB_VIEW(web_view)));
402 }
403
404
405 wxString wxWebViewGTKWebKit::GetPageSource()
406 {
407 WebKitWebFrame* frame = webkit_web_view_get_main_frame(
408 WEBKIT_WEB_VIEW(web_view));
409 WebKitWebDataSource* src = webkit_web_frame_get_data_source (frame);
410
411 // TODO: check encoding with
412 // const gchar*
413 // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source);
414 return wxString(webkit_web_data_source_get_data (src)->str, wxConvUTF8);
415 }
416
417
418 wxWebViewZoom wxWebViewGTKWebKit::GetZoom()
419 {
420 float zoom = GetWebkitZoom();
421
422 // arbitrary way to map float zoom to our common zoom enum
423 if (zoom <= 0.65)
424 {
425 return wxWEB_VIEW_ZOOM_TINY;
426 }
427 else if (zoom > 0.65 && zoom <= 0.90)
428 {
429 return wxWEB_VIEW_ZOOM_SMALL;
430 }
431 else if (zoom > 0.90 && zoom <= 1.15)
432 {
433 return wxWEB_VIEW_ZOOM_MEDIUM;
434 }
435 else if (zoom > 1.15 && zoom <= 1.45)
436 {
437 return wxWEB_VIEW_ZOOM_LARGE;
438 }
439 else if (zoom > 1.45)
440 {
441 return wxWEB_VIEW_ZOOM_LARGEST;
442 }
443
444 // to shut up compilers, this can never be reached logically
445 wxASSERT(false);
446 return wxWEB_VIEW_ZOOM_MEDIUM;
447 }
448
449
450 void wxWebViewGTKWebKit::SetZoom(wxWebViewZoom zoom)
451 {
452 // arbitrary way to map our common zoom enum to float zoom
453 switch (zoom)
454 {
455 case wxWEB_VIEW_ZOOM_TINY:
456 SetWebkitZoom(0.6f);
457 break;
458
459 case wxWEB_VIEW_ZOOM_SMALL:
460 SetWebkitZoom(0.8f);
461 break;
462
463 case wxWEB_VIEW_ZOOM_MEDIUM:
464 SetWebkitZoom(1.0f);
465 break;
466
467 case wxWEB_VIEW_ZOOM_LARGE:
468 SetWebkitZoom(1.3);
469 break;
470
471 case wxWEB_VIEW_ZOOM_LARGEST:
472 SetWebkitZoom(1.6);
473 break;
474
475 default:
476 wxASSERT(false);
477 }
478 }
479
480 void wxWebViewGTKWebKit::SetZoomType(wxWebViewZoomType type)
481 {
482 webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(web_view),
483 (type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT ?
484 TRUE : FALSE));
485 }
486
487 wxWebViewZoomType wxWebViewGTKWebKit::GetZoomType() const
488 {
489 gboolean fczoom = webkit_web_view_get_full_content_zoom(
490 WEBKIT_WEB_VIEW(web_view));
491
492 if (fczoom) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT;
493 else return wxWEB_VIEW_ZOOM_TYPE_TEXT;
494 }
495
496 bool wxWebViewGTKWebKit::CanSetZoomType(wxWebViewZoomType) const
497 {
498 // this port supports all zoom types
499 return true;
500 }
501
502 void wxWebViewGTKWebKit::SetPage(const wxString& html, const wxString& baseUri)
503 {
504 webkit_web_view_load_string (WEBKIT_WEB_VIEW(web_view),
505 html.mb_str(wxConvUTF8),
506 "text/html",
507 "UTF-8",
508 baseUri.mb_str(wxConvUTF8));
509 }
510
511 void wxWebViewGTKWebKit::Print()
512 {
513 WebKitWebFrame* frame = webkit_web_view_get_main_frame(
514 WEBKIT_WEB_VIEW(web_view));
515 webkit_web_frame_print (frame);
516
517 // GtkPrintOperationResult webkit_web_frame_print_full
518 // (WebKitWebFrame *frame,
519 // GtkPrintOperation *operation,
520 // GtkPrintOperationAction action,
521 // GError **error);
522
523 }
524
525
526 bool wxWebViewGTKWebKit::IsBusy()
527 {
528 return m_busy;
529
530 // This code looks nice but returns true after a page was cancelled
531 /*
532 WebKitLoadStatus status = webkit_web_view_get_load_status
533 (WEBKIT_WEB_VIEW(web_view));
534
535
536 #if WEBKIT_CHECK_VERSION(1,1,16)
537 // WEBKIT_LOAD_FAILED is new in webkit 1.1.16
538 if (status == WEBKIT_LOAD_FAILED)
539 {
540 return false;
541 }
542 #endif
543 if (status == WEBKIT_LOAD_FINISHED)
544 {
545 return false;
546 }
547
548 return true;
549 */
550 }
551
552 // static
553 wxVisualAttributes
554 wxWebViewGTKWebKit::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
555 {
556 return GetDefaultAttributesFromGTKWidget(webkit_web_view_new);
557 }
558
559
560 #endif // wxHAVE_WEB_BACKEND_GTK_WEBKIT