1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/webview.cpp 
   3 // Purpose:     GTK WebKit backend for web view component 
   4 // Author:      Marianne Gagnon, Robert Roebling 
   6 // Copyright:   (c) 2010 Marianne Gagnon, 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  14 #if wxHAVE_WEB_BACKEND_GTK_WEBKIT 
  16 #include "wx/stockitem.h" 
  17 #include "wx/gtk/webview.h" 
  18 #include "wx/gtk/control.h" 
  19 #include "wx/gtk/private.h" 
  20 #include "webkit/webkit.h" 
  22 // ---------------------------------------------------------------------------- 
  24 // ---------------------------------------------------------------------------- 
  30 wxgtk_webkitctrl_load_status_callback(GtkWidget
* widget
, GParamSpec
* arg1
, 
  31                                       wxWebViewGTKWebKit 
*webKitCtrl
) 
  33     if (!webKitCtrl
->m_ready
) return; 
  35     wxString url 
= webKitCtrl
->GetCurrentURL(); 
  37     WebKitLoadStatus status
; 
  38     g_object_get(G_OBJECT(widget
), "load-status", &status
, NULL
); 
  40     wxString target
; // TODO: get target (if possible) 
  42     if (status 
== WEBKIT_LOAD_FINISHED
) 
  44         webKitCtrl
->m_busy 
= false; 
  45         wxWebNavigationEvent 
thisEvent(wxEVT_COMMAND_WEB_VIEW_LOADED
, 
  49         if (webKitCtrl 
&& webKitCtrl
->GetEventHandler()) 
  50             webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
); 
  52     else if (status 
==  WEBKIT_LOAD_COMMITTED
) 
  54         webKitCtrl
->m_busy 
= true; 
  55         wxWebNavigationEvent 
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATED
, 
  59         if (webKitCtrl 
&& webKitCtrl
->GetEventHandler()) 
  60             webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
); 
  64 static WebKitNavigationResponse
 
  65 wxgtk_webkitctrl_navigation_requ_callback(WebKitWebView        
*web_view
, 
  66                                           WebKitWebFrame       
*frame
, 
  67                                           WebKitNetworkRequest 
*request
, 
  68                                           wxWebViewGTKWebKit      
*webKitCtrl
) 
  70     webKitCtrl
->m_busy 
= true; 
  72     const gchar
* uri 
= webkit_network_request_get_uri(request
); 
  74     wxString target 
= webkit_web_frame_get_name (frame
); 
  75     wxWebNavigationEvent 
thisEvent(wxEVT_COMMAND_WEB_VIEW_NAVIGATING
, 
  77                                    wxString( uri
, wxConvUTF8 
), 
  81     if (webKitCtrl 
&& webKitCtrl
->GetEventHandler()) 
  82         webKitCtrl
->GetEventHandler()->ProcessEvent(thisEvent
); 
  84     if (thisEvent
.IsVetoed()) 
  86         webKitCtrl
->m_busy 
= false; 
  87         return WEBKIT_NAVIGATION_RESPONSE_IGNORE
; 
  91         return  WEBKIT_NAVIGATION_RESPONSE_ACCEPT
; 
  96 wxgtk_webkitctrl_error (WebKitWebView  
*web_view
, 
  97                         WebKitWebFrame 
*web_frame
, 
 100                         wxWebViewGTKWebKit
* webKitWindow
) 
 102     webKitWindow
->m_busy 
= false; 
 103     wxWebNavigationError type 
= wxWEB_NAV_ERR_OTHER
; 
 105     GError
* error 
= (GError
*)web_error
; 
 106     wxString 
description(error
->message
, wxConvUTF8
); 
 108     if (strcmp(g_quark_to_string(error
->domain
), "soup_http_error_quark") == 0) 
 112             case SOUP_STATUS_CANCELLED
: 
 113                 type 
= wxWEB_NAV_ERR_USER_CANCELLED
; 
 116             case SOUP_STATUS_CANT_RESOLVE
: 
 117             case SOUP_STATUS_NOT_FOUND
: 
 118                 type 
= wxWEB_NAV_ERR_NOT_FOUND
; 
 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
; 
 129             case SOUP_STATUS_MALFORMED
: 
 130             //case SOUP_STATUS_TOO_MANY_REDIRECTS: 
 131                 type 
= wxWEB_NAV_ERR_REQUEST
; 
 134             //case SOUP_STATUS_NO_CONTENT: 
 135             //case SOUP_STATUS_RESET_CONTENT: 
 137             case SOUP_STATUS_BAD_REQUEST
: 
 138                 type 
= wxWEB_NAV_ERR_REQUEST
; 
 141             case SOUP_STATUS_UNAUTHORIZED
: 
 142             case SOUP_STATUS_FORBIDDEN
: 
 143                 type 
= wxWEB_NAV_ERR_AUTH
; 
 146             case SOUP_STATUS_METHOD_NOT_ALLOWED
: 
 147             case SOUP_STATUS_NOT_ACCEPTABLE
: 
 148                 type 
= wxWEB_NAV_ERR_SECURITY
; 
 151             case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED
: 
 152                 type 
= wxWEB_NAV_ERR_AUTH
; 
 155             case SOUP_STATUS_REQUEST_TIMEOUT
: 
 156                 type 
= wxWEB_NAV_ERR_CONNECTION
; 
 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
; 
 166             case SOUP_STATUS_BAD_GATEWAY
: 
 167             case SOUP_STATUS_SERVICE_UNAVAILABLE
: 
 168             case SOUP_STATUS_GATEWAY_TIMEOUT
: 
 169                 type 
= wxWEB_NAV_ERR_CONNECTION
; 
 172             case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED
: 
 173                 type 
= wxWEB_NAV_ERR_REQUEST
; 
 175             //case SOUP_STATUS_INSUFFICIENT_STORAGE: 
 176             //case SOUP_STATUS_NOT_EXTENDED: 
 179     else if (strcmp(g_quark_to_string(error
->domain
), 
 180                     "webkit-network-error-quark") == 0) 
 184             //WEBKIT_NETWORK_ERROR_FAILED: 
 185             //WEBKIT_NETWORK_ERROR_TRANSPORT: 
 187             case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL
: 
 188                 type 
= wxWEB_NAV_ERR_REQUEST
; 
 191             case WEBKIT_NETWORK_ERROR_CANCELLED
: 
 192                 type 
= wxWEB_NAV_ERR_USER_CANCELLED
; 
 195             case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST
: 
 196                 type 
= wxWEB_NAV_ERR_NOT_FOUND
; 
 200     else if (strcmp(g_quark_to_string(error
->domain
), 
 201                     "webkit-policy-error-quark") == 0) 
 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
; 
 215     webkit_plugin_error_quark 
 218         printf("Error domain %s\n", g_quark_to_string(error->domain)); 
 222     wxWebNavigationEvent 
thisEvent(wxEVT_COMMAND_WEB_VIEW_ERROR
, 
 223                                    webKitWindow
->GetId(), 
 227     thisEvent
.SetString(description
); 
 228     thisEvent
.SetInt(type
); 
 230     if (webKitWindow 
&& webKitWindow
->GetEventHandler()) 
 232         webKitWindow
->GetEventHandler()->ProcessEvent(thisEvent
); 
 241 //----------------------------------------------------------------------------- 
 242 // wxWebViewGTKWebKit 
 243 //----------------------------------------------------------------------------- 
 245 //IMPLEMENT_DYNAMIC_CLASS(wxWebViewGTKWebKit, wxControl) 
 247 bool wxWebViewGTKWebKit::Create(wxWindow 
*parent
, 
 253                       const wxString
& name
) 
 258     if (!PreCreation( parent
, pos
, size 
) || 
 259         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 261         wxFAIL_MSG( wxT("wxWebViewGTKWebKit creation failed") ); 
 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 
 269     m_widget 
= scrolled_window
; 
 270     g_object_ref(m_widget
); // TODO: check memory management 
 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
); 
 277     g_signal_connect_after(web_view
, "notify::load-status", 
 278                            G_CALLBACK(wxgtk_webkitctrl_load_status_callback
), 
 280     g_signal_connect_after(web_view
, "navigation-requested", 
 281                            G_CALLBACK(wxgtk_webkitctrl_navigation_requ_callback
), 
 283     g_signal_connect_after(web_view
, "load-error",  
 284                            G_CALLBACK(wxgtk_webkitctrl_error
), 
 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); 
 291     m_parent
->DoAddChild( this ); 
 296     webkit_web_view_load_uri (WEBKIT_WEB_VIEW (web_view
), url
); 
 303 bool wxWebViewGTKWebKit::Enable( bool enable 
) 
 305     if (!wxControl::Enable(enable
)) 
 308     gtk_widget_set_sensitive(GTK_BIN(m_widget
)->child
, enable
); 
 311     //    GTKFixSensitivity(); 
 317 wxWebViewGTKWebKit::GTKGetWindow(wxArrayGdkWindows
& WXUNUSED(windows
)) const 
 319     GdkWindow
* window 
= gtk_widget_get_parent_window(m_widget
); 
 323 void wxWebViewGTKWebKit::ZoomIn() 
 325     webkit_web_view_zoom_in (WEBKIT_WEB_VIEW(web_view
)); 
 328 void wxWebViewGTKWebKit::ZoomOut() 
 330     webkit_web_view_zoom_out (WEBKIT_WEB_VIEW(web_view
)); 
 333 void wxWebViewGTKWebKit::SetWebkitZoom(float level
) 
 335     webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW(web_view
), level
); 
 338 float wxWebViewGTKWebKit::GetWebkitZoom() 
 340     return webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW(web_view
)); 
 343 void wxWebViewGTKWebKit::Stop() 
 345      webkit_web_view_stop_loading (WEBKIT_WEB_VIEW(web_view
)); 
 348 void wxWebViewGTKWebKit::Reload(wxWebViewReloadFlags flags
) 
 350     if (flags 
& wxWEB_VIEW_RELOAD_NO_CACHE
) 
 352         webkit_web_view_reload_bypass_cache (WEBKIT_WEB_VIEW(web_view
)); 
 356         webkit_web_view_reload (WEBKIT_WEB_VIEW(web_view
)); 
 360 void wxWebViewGTKWebKit::LoadUrl(const wxString
& url
) 
 362     webkit_web_view_open(WEBKIT_WEB_VIEW(web_view
), wxGTK_CONV(loc
)); 
 366 void wxWebViewGTKWebKit::GoBack() 
 368     webkit_web_view_go_back (WEBKIT_WEB_VIEW(web_view
)); 
 371 void wxWebViewGTKWebKit::GoForward() 
 373     webkit_web_view_go_forward (WEBKIT_WEB_VIEW(web_view
)); 
 377 bool wxWebViewGTKWebKit::CanGoBack() 
 379     return webkit_web_view_can_go_back (WEBKIT_WEB_VIEW(web_view
)); 
 383 bool wxWebViewGTKWebKit::CanGoForward() 
 385     return webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW(web_view
)); 
 389 wxString 
wxWebViewGTKWebKit::GetCurrentURL() 
 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
))); 
 398 wxString 
wxWebViewGTKWebKit::GetCurrentTitle() 
 400     return wxString::FromUTF8(webkit_web_view_get_title( 
 401                                 WEBKIT_WEB_VIEW(web_view
))); 
 405 wxString 
wxWebViewGTKWebKit::GetPageSource() 
 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
); 
 411     // TODO: check encoding with 
 413     // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source); 
 414     return wxString(webkit_web_data_source_get_data (src
)->str
, wxConvUTF8
); 
 418 wxWebViewZoom 
wxWebViewGTKWebKit::GetZoom() 
 420     float zoom 
= GetWebkitZoom(); 
 422     // arbitrary way to map float zoom to our common zoom enum 
 425         return wxWEB_VIEW_ZOOM_TINY
; 
 427     else if (zoom 
> 0.65 && zoom 
<= 0.90) 
 429         return wxWEB_VIEW_ZOOM_SMALL
; 
 431     else if (zoom 
> 0.90 && zoom 
<= 1.15) 
 433         return wxWEB_VIEW_ZOOM_MEDIUM
; 
 435     else if (zoom 
> 1.15 && zoom 
<= 1.45) 
 437         return wxWEB_VIEW_ZOOM_LARGE
; 
 439     else if (zoom 
> 1.45) 
 441         return wxWEB_VIEW_ZOOM_LARGEST
; 
 444     // to shut up compilers, this can never be reached logically 
 446     return wxWEB_VIEW_ZOOM_MEDIUM
; 
 450 void wxWebViewGTKWebKit::SetZoom(wxWebViewZoom zoom
) 
 452     // arbitrary way to map our common zoom enum to float zoom 
 455         case wxWEB_VIEW_ZOOM_TINY
: 
 459         case wxWEB_VIEW_ZOOM_SMALL
: 
 463         case wxWEB_VIEW_ZOOM_MEDIUM
: 
 467         case wxWEB_VIEW_ZOOM_LARGE
: 
 471         case wxWEB_VIEW_ZOOM_LARGEST
: 
 480 void wxWebViewGTKWebKit::SetZoomType(wxWebViewZoomType type
) 
 482     webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(web_view
), 
 483                                           (type 
== wxWEB_VIEW_ZOOM_TYPE_LAYOUT 
? 
 487 wxWebViewZoomType 
wxWebViewGTKWebKit::GetZoomType() const 
 489     gboolean fczoom 
= webkit_web_view_get_full_content_zoom( 
 490             WEBKIT_WEB_VIEW(web_view
)); 
 492     if (fczoom
) return wxWEB_VIEW_ZOOM_TYPE_LAYOUT
; 
 493     else        return wxWEB_VIEW_ZOOM_TYPE_TEXT
; 
 496 bool wxWebViewGTKWebKit::CanSetZoomType(wxWebViewZoomType
) const 
 498     // this port supports all zoom types 
 502 void wxWebViewGTKWebKit::SetPage(const wxString
& html
, const wxString
& baseUri
) 
 504     webkit_web_view_load_string (WEBKIT_WEB_VIEW(web_view
), 
 505                                  html
.mb_str(wxConvUTF8
), 
 508                                  baseUri
.mb_str(wxConvUTF8
)); 
 511 void wxWebViewGTKWebKit::Print() 
 513     WebKitWebFrame
* frame 
= webkit_web_view_get_main_frame( 
 514             WEBKIT_WEB_VIEW(web_view
)); 
 515     webkit_web_frame_print (frame
); 
 517     // GtkPrintOperationResult  webkit_web_frame_print_full 
 518     //      (WebKitWebFrame *frame, 
 519     //       GtkPrintOperation *operation, 
 520     //       GtkPrintOperationAction action, 
 526 bool wxWebViewGTKWebKit::IsBusy() 
 530     // This code looks nice but returns true after a page was cancelled 
 532     WebKitLoadStatus status = webkit_web_view_get_load_status 
 533             (WEBKIT_WEB_VIEW(web_view)); 
 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) 
 543     if (status == WEBKIT_LOAD_FINISHED) 
 554 wxWebViewGTKWebKit::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 556      return GetDefaultAttributesFromGTKWidget(webkit_web_view_new
); 
 560 #endif // wxHAVE_WEB_BACKEND_GTK_WEBKIT