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