1 /* 2 * Copyright (C) 2007, 2008 Holger Hans Peter Freyther 3 * Copyright (C) 2007, 2008 Christian Dywan <christian (at) imendio.com> 4 * Copyright (C) 2008 Nuanti Ltd. 5 * Copyright (C) 2008 Alp Toker <alp (at) atoker.com> 6 * Copyright (C) 2008 Gustavo Noronha Silva <gns (at) gnome.org> 7 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 #include "config.h" 25 #include "ChromeClientGtk.h" 26 27 #include "Chrome.h" 28 #include "Console.h" 29 #include "DumpRenderTreeSupportGtk.h" 30 #include "Element.h" 31 #include "FileChooser.h" 32 #include "FileSystem.h" 33 #include "FloatRect.h" 34 #include "FrameLoadRequest.h" 35 #include "FrameView.h" 36 #include "GtkVersioning.h" 37 #include "HTMLNames.h" 38 #include "HitTestResult.h" 39 #include "Icon.h" 40 #include "IntRect.h" 41 #include "KURL.h" 42 #include "NavigationAction.h" 43 #include "NotImplemented.h" 44 #include "PlatformString.h" 45 #include "PopupMenuClient.h" 46 #include "PopupMenuGtk.h" 47 #include "SearchPopupMenuGtk.h" 48 #include "SecurityOrigin.h" 49 #include "WindowFeatures.h" 50 #include "webkitgeolocationpolicydecision.h" 51 #include "webkitgeolocationpolicydecisionprivate.h" 52 #include "webkitnetworkrequest.h" 53 #include "webkitsecurityoriginprivate.h" 54 #include "webkitviewportattributesprivate.h" 55 #include "webkitwebframeprivate.h" 56 #include "webkitwebview.h" 57 #include "webkitwebviewprivate.h" 58 #include "webkitwebwindowfeaturesprivate.h" 59 #include <glib.h> 60 #include <glib/gi18n-lib.h> 61 #include <gtk/gtk.h> 62 #include <wtf/text/CString.h> 63 64 #if ENABLE(DATABASE) 65 #include "DatabaseTracker.h" 66 #endif 67 68 using namespace WebCore; 69 70 namespace WebKit { 71 72 ChromeClient::ChromeClient(WebKitWebView* webView) 73 : m_webView(webView) 74 , m_closeSoonTimer(0) 75 , m_pendingScrollInvalidations(false) 76 { 77 ASSERT(m_webView); 78 } 79 80 void ChromeClient::chromeDestroyed() 81 { 82 if (m_closeSoonTimer) 83 g_source_remove(m_closeSoonTimer); 84 85 delete this; 86 } 87 88 FloatRect ChromeClient::windowRect() 89 { 90 GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView)); 91 if (gtk_widget_is_toplevel(window)) { 92 gint left, top, width, height; 93 gtk_window_get_position(GTK_WINDOW(window), &left, &top); 94 gtk_window_get_size(GTK_WINDOW(window), &width, &height); 95 return IntRect(left, top, width, height); 96 } 97 return FloatRect(); 98 } 99 100 void ChromeClient::setWindowRect(const FloatRect& rect) 101 { 102 IntRect intrect = IntRect(rect); 103 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 104 105 g_object_set(webWindowFeatures, 106 "x", intrect.x(), 107 "y", intrect.y(), 108 "width", intrect.width(), 109 "height", intrect.height(), 110 NULL); 111 112 gboolean autoResizeWindow; 113 WebKitWebSettings* settings = webkit_web_view_get_settings(m_webView); 114 g_object_get(settings, "auto-resize-window", &autoResizeWindow, NULL); 115 116 if (!autoResizeWindow) 117 return; 118 119 GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView)); 120 if (gtk_widget_is_toplevel(window)) { 121 gtk_window_move(GTK_WINDOW(window), intrect.x(), intrect.y()); 122 gtk_window_resize(GTK_WINDOW(window), intrect.width(), intrect.height()); 123 } 124 } 125 126 FloatRect ChromeClient::pageRect() 127 { 128 GtkAllocation allocation; 129 #if GTK_CHECK_VERSION(2, 18, 0) 130 gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation); 131 #else 132 allocation = GTK_WIDGET(m_webView)->allocation; 133 #endif 134 return IntRect(allocation.x, allocation.y, allocation.width, allocation.height); 135 } 136 137 float ChromeClient::scaleFactor() 138 { 139 // Not implementable 140 return 1.0; 141 } 142 143 void ChromeClient::focus() 144 { 145 gtk_widget_grab_focus(GTK_WIDGET(m_webView)); 146 } 147 148 void ChromeClient::unfocus() 149 { 150 GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView)); 151 if (gtk_widget_is_toplevel(window)) 152 gtk_window_set_focus(GTK_WINDOW(window), NULL); 153 } 154 155 Page* ChromeClient::createWindow(Frame* frame, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& coreFeatures, const NavigationAction&) 156 { 157 WebKitWebView* webView = 0; 158 159 g_signal_emit_by_name(m_webView, "create-web-view", kit(frame), &webView); 160 161 if (!webView) 162 return 0; 163 164 GRefPtr<WebKitWebWindowFeatures> webWindowFeatures(adoptGRef(kitNew(coreFeatures))); 165 g_object_set(webView, "window-features", webWindowFeatures.get(), NULL); 166 167 return core(webView); 168 } 169 170 void ChromeClient::show() 171 { 172 webkit_web_view_notify_ready(m_webView); 173 } 174 175 bool ChromeClient::canRunModal() 176 { 177 notImplemented(); 178 return false; 179 } 180 181 void ChromeClient::runModal() 182 { 183 notImplemented(); 184 } 185 186 void ChromeClient::setToolbarsVisible(bool visible) 187 { 188 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 189 190 g_object_set(webWindowFeatures, "toolbar-visible", visible, NULL); 191 } 192 193 bool ChromeClient::toolbarsVisible() 194 { 195 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 196 gboolean visible; 197 198 g_object_get(webWindowFeatures, "toolbar-visible", &visible, NULL); 199 return visible; 200 } 201 202 void ChromeClient::setStatusbarVisible(bool visible) 203 { 204 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 205 206 g_object_set(webWindowFeatures, "statusbar-visible", visible, NULL); 207 } 208 209 bool ChromeClient::statusbarVisible() 210 { 211 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 212 gboolean visible; 213 214 g_object_get(webWindowFeatures, "statusbar-visible", &visible, NULL); 215 return visible; 216 } 217 218 void ChromeClient::setScrollbarsVisible(bool visible) 219 { 220 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 221 222 g_object_set(webWindowFeatures, "scrollbar-visible", visible, NULL); 223 } 224 225 bool ChromeClient::scrollbarsVisible() 226 { 227 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 228 gboolean visible; 229 230 g_object_get(webWindowFeatures, "scrollbar-visible", &visible, NULL); 231 return visible; 232 } 233 234 void ChromeClient::setMenubarVisible(bool visible) 235 { 236 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 237 238 g_object_set(webWindowFeatures, "menubar-visible", visible, NULL); 239 } 240 241 bool ChromeClient::menubarVisible() 242 { 243 WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView); 244 gboolean visible; 245 246 g_object_get(webWindowFeatures, "menubar-visible", &visible, NULL); 247 return visible; 248 } 249 250 void ChromeClient::setResizable(bool) 251 { 252 // Ignored for now 253 } 254 255 static gboolean emitCloseWebViewSignalLater(WebKitWebView* view) 256 { 257 gboolean isHandled; 258 g_signal_emit_by_name(view, "close-web-view", &isHandled); 259 return FALSE; 260 } 261 262 void ChromeClient::closeWindowSoon() 263 { 264 // We may not have a WebView as create-web-view can return NULL. 265 if (!m_webView) 266 return; 267 if (m_closeSoonTimer) // Don't call close-web-view more than once. 268 return; 269 270 // We need to remove the parent WebView from WebViewSets here, before it actually 271 // closes, to make sure that JavaScript code that executes before it closes 272 // can't find it. Otherwise, window.open will select a closed WebView instead of 273 // opening a new one <rdar://problem/3572585>. 274 m_webView->priv->corePage->setGroupName(""); 275 276 // We also need to stop the load to prevent further parsing or JavaScript execution 277 // after the window has torn down <rdar://problem/4161660>. 278 webkit_web_view_stop_loading(m_webView); 279 280 // Clients commonly destroy the web view during the close-web-view signal, but our caller 281 // may need to send more signals to the web view. For instance, if this happened in the 282 // onload handler, it will need to call FrameLoaderClient::dispatchDidHandleOnloadEvents. 283 // Instead of firing the close-web-view signal now, fire it after the caller finishes. 284 // This seems to match the Mac/Windows port behavior. 285 m_closeSoonTimer = g_timeout_add(0, reinterpret_cast<GSourceFunc>(emitCloseWebViewSignalLater), m_webView); 286 } 287 288 bool ChromeClient::canTakeFocus(FocusDirection) 289 { 290 return gtk_widget_get_can_focus(GTK_WIDGET(m_webView)); 291 } 292 293 void ChromeClient::takeFocus(FocusDirection) 294 { 295 unfocus(); 296 } 297 298 void ChromeClient::focusedNodeChanged(Node*) 299 { 300 } 301 302 void ChromeClient::focusedFrameChanged(Frame*) 303 { 304 } 305 306 bool ChromeClient::canRunBeforeUnloadConfirmPanel() 307 { 308 return true; 309 } 310 311 bool ChromeClient::runBeforeUnloadConfirmPanel(const WTF::String& message, WebCore::Frame* frame) 312 { 313 return runJavaScriptConfirm(frame, message); 314 } 315 316 void ChromeClient::addMessageToConsole(WebCore::MessageSource source, WebCore::MessageType type, WebCore::MessageLevel level, const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceId) 317 { 318 gboolean retval; 319 g_signal_emit_by_name(m_webView, "console-message", message.utf8().data(), lineNumber, sourceId.utf8().data(), &retval); 320 } 321 322 void ChromeClient::runJavaScriptAlert(Frame* frame, const String& message) 323 { 324 gboolean retval; 325 g_signal_emit_by_name(m_webView, "script-alert", kit(frame), message.utf8().data(), &retval); 326 } 327 328 bool ChromeClient::runJavaScriptConfirm(Frame* frame, const String& message) 329 { 330 gboolean retval; 331 gboolean didConfirm; 332 g_signal_emit_by_name(m_webView, "script-confirm", kit(frame), message.utf8().data(), &didConfirm, &retval); 333 return didConfirm == TRUE; 334 } 335 336 bool ChromeClient::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) 337 { 338 gboolean retval; 339 gchar* value = 0; 340 g_signal_emit_by_name(m_webView, "script-prompt", kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value, &retval); 341 if (value) { 342 result = String::fromUTF8(value); 343 g_free(value); 344 return true; 345 } 346 return false; 347 } 348 349 void ChromeClient::setStatusbarText(const String& string) 350 { 351 CString stringMessage = string.utf8(); 352 g_signal_emit_by_name(m_webView, "status-bar-text-changed", stringMessage.data()); 353 } 354 355 bool ChromeClient::shouldInterruptJavaScript() 356 { 357 notImplemented(); 358 return false; 359 } 360 361 KeyboardUIMode ChromeClient::keyboardUIMode() 362 { 363 bool tabsToLinks = true; 364 if (DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled()) 365 tabsToLinks = DumpRenderTreeSupportGtk::linksIncludedInFocusChain(); 366 367 return tabsToLinks ? KeyboardAccessTabsToLinks : KeyboardAccessDefault; 368 } 369 370 IntRect ChromeClient::windowResizerRect() const 371 { 372 notImplemented(); 373 return IntRect(); 374 } 375 376 void ChromeClient::invalidateWindow(const IntRect&, bool immediate) 377 { 378 // If we've invalidated regions for scrolling, force GDK to process those invalidations 379 // now. This will also cause child windows to move right away. This prevents redraw 380 // artifacts with child windows (e.g. Flash plugin instances). 381 if (immediate && m_pendingScrollInvalidations) { 382 m_pendingScrollInvalidations = false; 383 if (GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView))) 384 gdk_window_process_updates(window, TRUE); 385 } 386 } 387 388 void ChromeClient::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate) 389 { 390 GdkRectangle rect = updateRect; 391 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView)); 392 393 if (window && !updateRect.isEmpty()) { 394 gdk_window_invalidate_rect(window, &rect, FALSE); 395 // We don't currently do immediate updates since they delay other UI elements. 396 //if (immediate) 397 // gdk_window_process_updates(window, FALSE); 398 } 399 } 400 401 void ChromeClient::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 402 { 403 invalidateContentsAndWindow(updateRect, immediate); 404 } 405 406 void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect) 407 { 408 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView)); 409 if (!window) 410 return; 411 412 m_pendingScrollInvalidations = true; 413 414 // We cannot use gdk_window_scroll here because it is only able to 415 // scroll the whole window at once, and we often need to scroll 416 // portions of the window only (think frames). 417 GdkRectangle area = clipRect; 418 GdkRectangle moveRect; 419 420 GdkRectangle sourceRect = area; 421 sourceRect.x -= delta.width(); 422 sourceRect.y -= delta.height(); 423 424 #ifdef GTK_API_VERSION_2 425 GdkRegion* invalidRegion = gdk_region_rectangle(&area); 426 427 if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) { 428 GdkRegion* moveRegion = gdk_region_rectangle(&moveRect); 429 gdk_window_move_region(window, moveRegion, delta.width(), delta.height()); 430 gdk_region_offset(moveRegion, delta.width(), delta.height()); 431 gdk_region_subtract(invalidRegion, moveRegion); 432 gdk_region_destroy(moveRegion); 433 } 434 435 gdk_window_invalidate_region(window, invalidRegion, FALSE); 436 gdk_region_destroy(invalidRegion); 437 #else 438 cairo_region_t* invalidRegion = cairo_region_create_rectangle(&area); 439 440 if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) { 441 cairo_region_t* moveRegion = cairo_region_create_rectangle(&moveRect); 442 gdk_window_move_region(window, moveRegion, delta.width(), delta.height()); 443 cairo_region_translate(moveRegion, delta.width(), delta.height()); 444 cairo_region_subtract(invalidRegion, moveRegion); 445 cairo_region_destroy(moveRegion); 446 } 447 448 gdk_window_invalidate_region(window, invalidRegion, FALSE); 449 cairo_region_destroy(invalidRegion); 450 #endif 451 } 452 453 // FIXME: this does not take into account the WM decorations 454 static IntPoint widgetScreenPosition(GtkWidget* widget) 455 { 456 GtkWidget* window = gtk_widget_get_toplevel(widget); 457 int widgetX = 0, widgetY = 0; 458 459 gtk_widget_translate_coordinates(widget, window, 0, 0, &widgetX, &widgetY); 460 461 IntPoint result(widgetX, widgetY); 462 int originX, originY; 463 gdk_window_get_origin(gtk_widget_get_window(window), &originX, &originY); 464 result.move(originX, originY); 465 466 return result; 467 } 468 469 IntRect ChromeClient::windowToScreen(const IntRect& rect) const 470 { 471 IntRect result(rect); 472 IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView)); 473 result.move(screenPosition.x(), screenPosition.y()); 474 475 return result; 476 } 477 478 IntPoint ChromeClient::screenToWindow(const IntPoint& point) const 479 { 480 IntPoint result(point); 481 IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView)); 482 result.move(-screenPosition.x(), -screenPosition.y()); 483 484 return result; 485 } 486 487 PlatformPageClient ChromeClient::platformPageClient() const 488 { 489 return GTK_WIDGET(m_webView); 490 } 491 492 void ChromeClient::contentsSizeChanged(Frame* frame, const IntSize& size) const 493 { 494 // We need to queue a resize request only if the size changed, 495 // otherwise we get into an infinite loop! 496 GtkWidget* widget = GTK_WIDGET(m_webView); 497 GtkRequisition requisition; 498 #if GTK_CHECK_VERSION(2, 20, 0) 499 gtk_widget_get_requisition(widget, &requisition); 500 #else 501 requisition = widget->requisition; 502 #endif 503 if (gtk_widget_get_realized(widget) 504 && (requisition.height != size.height()) 505 || (requisition.width != size.width())) 506 gtk_widget_queue_resize_no_redraw(widget); 507 } 508 509 void ChromeClient::scrollbarsModeDidChange() const 510 { 511 WebKitWebFrame* webFrame = webkit_web_view_get_main_frame(m_webView); 512 513 g_object_notify(G_OBJECT(webFrame), "horizontal-scrollbar-policy"); 514 g_object_notify(G_OBJECT(webFrame), "vertical-scrollbar-policy"); 515 516 gboolean isHandled; 517 g_signal_emit_by_name(webFrame, "scrollbars-policy-changed", &isHandled); 518 519 if (isHandled) 520 return; 521 522 GtkWidget* parent = gtk_widget_get_parent(GTK_WIDGET(m_webView)); 523 if (!parent || !GTK_IS_SCROLLED_WINDOW(parent)) 524 return; 525 526 GtkPolicyType horizontalPolicy = webkit_web_frame_get_horizontal_scrollbar_policy(webFrame); 527 GtkPolicyType verticalPolicy = webkit_web_frame_get_vertical_scrollbar_policy(webFrame); 528 529 // ScrolledWindow doesn't like to display only part of a widget if 530 // the scrollbars are completely disabled; We have a disparity 531 // here on what the policy requested by the web app is and what we 532 // can represent; the idea is not to show scrollbars, only. 533 if (horizontalPolicy == GTK_POLICY_NEVER) 534 horizontalPolicy = GTK_POLICY_AUTOMATIC; 535 536 if (verticalPolicy == GTK_POLICY_NEVER) 537 verticalPolicy = GTK_POLICY_AUTOMATIC; 538 539 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(parent), 540 horizontalPolicy, verticalPolicy); 541 } 542 543 void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) 544 { 545 // check if the element is a link... 546 bool isLink = hit.isLiveLink(); 547 if (isLink) { 548 KURL url = hit.absoluteLinkURL(); 549 if (!url.isEmpty() && url != m_hoveredLinkURL) { 550 TextDirection dir; 551 CString titleString = hit.title(dir).utf8(); 552 CString urlString = url.string().utf8(); 553 g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data()); 554 m_hoveredLinkURL = url; 555 } 556 } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { 557 g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0); 558 m_hoveredLinkURL = KURL(); 559 } 560 561 if (Node* node = hit.innerNonSharedNode()) { 562 Frame* frame = node->document()->frame(); 563 FrameView* view = frame ? frame->view() : 0; 564 m_webView->priv->tooltipArea = view ? view->contentsToWindow(node->getRect()) : IntRect(); 565 } else 566 m_webView->priv->tooltipArea = IntRect(); 567 } 568 569 void ChromeClient::setToolTip(const String& toolTip, TextDirection) 570 { 571 webkit_web_view_set_tooltip_text(m_webView, toolTip.utf8().data()); 572 } 573 574 void ChromeClient::print(Frame* frame) 575 { 576 WebKitWebFrame* webFrame = kit(frame); 577 gboolean isHandled = false; 578 g_signal_emit_by_name(m_webView, "print-requested", webFrame, &isHandled); 579 580 if (isHandled) 581 return; 582 583 webkit_web_frame_print(webFrame); 584 } 585 586 #if ENABLE(DATABASE) 587 void ChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName) 588 { 589 guint64 defaultQuota = webkit_get_default_web_database_quota(); 590 DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), defaultQuota); 591 592 WebKitWebFrame* webFrame = kit(frame); 593 WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(webFrame); 594 WebKitWebDatabase* webDatabase = webkit_security_origin_get_web_database(origin, databaseName.utf8().data()); 595 g_signal_emit_by_name(m_webView, "database-quota-exceeded", webFrame, webDatabase); 596 } 597 #endif 598 599 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 600 void ChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) 601 { 602 // FIXME: Free some space. 603 notImplemented(); 604 } 605 606 void ChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*) 607 { 608 notImplemented(); 609 } 610 #endif 611 612 void ChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser) 613 { 614 RefPtr<FileChooser> chooser = prpFileChooser; 615 616 GtkWidget* dialog = gtk_file_chooser_dialog_new(_("Upload File"), 617 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(m_webView))), 618 GTK_FILE_CHOOSER_ACTION_OPEN, 619 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 620 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, 621 NULL); 622 623 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), chooser->allowsMultipleFiles()); 624 625 if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { 626 if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog))) { 627 GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); 628 Vector<String> names; 629 for (GSList* item = filenames ; item ; item = item->next) { 630 if (!item->data) 631 continue; 632 names.append(filenameToString(static_cast<char*>(item->data))); 633 g_free(item->data); 634 } 635 g_slist_free(filenames); 636 chooser->chooseFiles(names); 637 } else { 638 gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); 639 if (filename) 640 chooser->chooseFile(filenameToString(filename)); 641 g_free(filename); 642 } 643 } 644 gtk_widget_destroy(dialog); 645 } 646 647 void ChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser) 648 { 649 chooser->iconLoaded(Icon::createIconForFiles(filenames)); 650 } 651 652 void ChromeClient::dispatchViewportDataDidChange(const ViewportArguments& arguments) const 653 { 654 // Recompute the viewport attributes making it valid. 655 webkitViewportAttributesRecompute(webkit_web_view_get_viewport_attributes(m_webView)); 656 } 657 658 void ChromeClient::setCursor(const Cursor& cursor) 659 { 660 // [GTK] Widget::setCursor() gets called frequently 661 // http://bugs.webkit.org/show_bug.cgi?id=16388 662 // Setting the cursor may be an expensive operation in some backends, 663 // so don't re-set the cursor if it's already set to the target value. 664 GdkWindow* window = gtk_widget_get_window(platformPageClient()); 665 GdkCursor* currentCursor = gdk_window_get_cursor(window); 666 GdkCursor* newCursor = cursor.platformCursor().get(); 667 if (currentCursor != newCursor) 668 gdk_window_set_cursor(window, newCursor); 669 } 670 671 void ChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) 672 { 673 WebKitWebFrame* webFrame = kit(frame); 674 GRefPtr<WebKitGeolocationPolicyDecision> policyDecision(adoptGRef(webkit_geolocation_policy_decision_new(webFrame, geolocation))); 675 676 gboolean isHandled = FALSE; 677 g_signal_emit_by_name(m_webView, "geolocation-policy-decision-requested", webFrame, policyDecision.get(), &isHandled); 678 if (!isHandled) 679 webkit_geolocation_policy_deny(policyDecision.get()); 680 } 681 682 void ChromeClient::cancelGeolocationPermissionRequestForFrame(WebCore::Frame* frame, WebCore::Geolocation*) 683 { 684 g_signal_emit_by_name(m_webView, "geolocation-policy-decision-cancelled", kit(frame)); 685 } 686 687 bool ChromeClient::selectItemWritingDirectionIsNatural() 688 { 689 return true; 690 } 691 692 bool ChromeClient::selectItemAlignmentFollowsMenuWritingDirection() 693 { 694 return false; 695 } 696 697 PassRefPtr<WebCore::PopupMenu> ChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const 698 { 699 return adoptRef(new PopupMenuGtk(client)); 700 } 701 702 PassRefPtr<WebCore::SearchPopupMenu> ChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const 703 { 704 return adoptRef(new SearchPopupMenuGtk(client)); 705 } 706 707 #if ENABLE(VIDEO) 708 709 bool ChromeClient::supportsFullscreenForNode(const Node* node) 710 { 711 return node->hasTagName(HTMLNames::videoTag); 712 } 713 714 void ChromeClient::enterFullscreenForNode(Node* node) 715 { 716 webViewEnterFullscreen(m_webView, node); 717 } 718 719 void ChromeClient::exitFullscreenForNode(Node* node) 720 { 721 webViewExitFullscreen(m_webView); 722 } 723 #endif 724 725 #if ENABLE(FULLSCREEN_API) 726 bool ChromeClient::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard) 727 { 728 if (withKeyboard) 729 return false; 730 731 return true; 732 } 733 734 void ChromeClient::enterFullScreenForElement(WebCore::Element* element) 735 { 736 element->document()->webkitWillEnterFullScreenForElement(element); 737 element->document()->webkitDidEnterFullScreenForElement(element); 738 } 739 740 void ChromeClient::exitFullScreenForElement(WebCore::Element* element) 741 { 742 element->document()->webkitWillExitFullScreenForElement(element); 743 element->document()->webkitDidExitFullScreenForElement(element); 744 } 745 #endif 746 747 748 } 749