ChromeClientGtk.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
1/*
2 * Copyright (C) 2007, 2008 Holger Hans Peter Freyther
3 * Copyright (C) 2007, 2008 Christian Dywan <christian@imendio.com>
4 * Copyright (C) 2008 Nuanti Ltd.
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) 2008 Gustavo Noronha Silva <gns@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
68using namespace WebCore;
69
70namespace WebKit {
71
72ChromeClient::ChromeClient(WebKitWebView* webView)
73    : m_webView(webView)
74    , m_closeSoonTimer(0)
75    , m_pendingScrollInvalidations(false)
76{
77    ASSERT(m_webView);
78}
79
80void ChromeClient::chromeDestroyed()
81{
82    if (m_closeSoonTimer)
83        g_source_remove(m_closeSoonTimer);
84
85    delete this;
86}
87
88FloatRect 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
100void 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
126FloatRect 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
137float ChromeClient::scaleFactor()
138{
139    // Not implementable
140    return 1.0;
141}
142
143void ChromeClient::focus()
144{
145    gtk_widget_grab_focus(GTK_WIDGET(m_webView));
146}
147
148void 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
155Page* 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
170void ChromeClient::show()
171{
172    webkit_web_view_notify_ready(m_webView);
173}
174
175bool ChromeClient::canRunModal()
176{
177    notImplemented();
178    return false;
179}
180
181void ChromeClient::runModal()
182{
183    notImplemented();
184}
185
186void 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
193bool 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
202void 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
209bool 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
218void 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
225bool 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
234void 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
241bool 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
250void ChromeClient::setResizable(bool)
251{
252    // Ignored for now
253}
254
255static gboolean emitCloseWebViewSignalLater(WebKitWebView* view)
256{
257    gboolean isHandled;
258    g_signal_emit_by_name(view, "close-web-view", &isHandled);
259    return FALSE;
260}
261
262void 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
288bool ChromeClient::canTakeFocus(FocusDirection)
289{
290    return gtk_widget_get_can_focus(GTK_WIDGET(m_webView));
291}
292
293void ChromeClient::takeFocus(FocusDirection)
294{
295    unfocus();
296}
297
298void ChromeClient::focusedNodeChanged(Node*)
299{
300}
301
302void ChromeClient::focusedFrameChanged(Frame*)
303{
304}
305
306bool ChromeClient::canRunBeforeUnloadConfirmPanel()
307{
308    return true;
309}
310
311bool ChromeClient::runBeforeUnloadConfirmPanel(const WTF::String& message, WebCore::Frame* frame)
312{
313    return runJavaScriptConfirm(frame, message);
314}
315
316void 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
322void 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
328bool 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
336bool 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
349void 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
355bool ChromeClient::shouldInterruptJavaScript()
356{
357    notImplemented();
358    return false;
359}
360
361KeyboardUIMode ChromeClient::keyboardUIMode()
362{
363    bool tabsToLinks = true;
364    if (DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled())
365        tabsToLinks = DumpRenderTreeSupportGtk::linksIncludedInFocusChain();
366
367    return tabsToLinks ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
368}
369
370IntRect ChromeClient::windowResizerRect() const
371{
372    notImplemented();
373    return IntRect();
374}
375
376void 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
388void 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
401void ChromeClient::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
402{
403    invalidateContentsAndWindow(updateRect, immediate);
404}
405
406void 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
454static 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
469IntRect 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
478IntPoint 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
487PlatformPageClient ChromeClient::platformPageClient() const
488{
489    return GTK_WIDGET(m_webView);
490}
491
492void 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
509void 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
543void 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.prettyURL().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
569void ChromeClient::setToolTip(const String& toolTip, TextDirection)
570{
571    webkit_web_view_set_tooltip_text(m_webView, toolTip.utf8().data());
572}
573
574void 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)
587void 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)
600void ChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
601{
602    // FIXME: Free some space.
603    notImplemented();
604}
605
606void ChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*)
607{
608    notImplemented();
609}
610#endif
611
612void 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
647void ChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser)
648{
649    chooser->iconLoaded(Icon::createIconForFiles(filenames));
650}
651
652void 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
658void 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
671void 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
682void ChromeClient::cancelGeolocationPermissionRequestForFrame(WebCore::Frame* frame, WebCore::Geolocation*)
683{
684    g_signal_emit_by_name(m_webView, "geolocation-policy-decision-cancelled", kit(frame));
685}
686
687bool ChromeClient::selectItemWritingDirectionIsNatural()
688{
689    return true;
690}
691
692bool ChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
693{
694    return false;
695}
696
697PassRefPtr<WebCore::PopupMenu> ChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
698{
699    return adoptRef(new PopupMenuGtk(client));
700}
701
702PassRefPtr<WebCore::SearchPopupMenu> ChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
703{
704    return adoptRef(new SearchPopupMenuGtk(client));
705}
706
707#if ENABLE(VIDEO)
708
709bool ChromeClient::supportsFullscreenForNode(const Node* node)
710{
711    return node->hasTagName(HTMLNames::videoTag);
712}
713
714void ChromeClient::enterFullscreenForNode(Node* node)
715{
716    webViewEnterFullscreen(m_webView, node);
717}
718
719void ChromeClient::exitFullscreenForNode(Node* node)
720{
721    webViewExitFullscreen(m_webView);
722}
723#endif
724
725#if ENABLE(FULLSCREEN_API)
726bool ChromeClient::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard)
727{
728    if (withKeyboard)
729        return false;
730
731    return true;
732}
733
734void ChromeClient::enterFullScreenForElement(WebCore::Element* element)
735{
736    element->document()->webkitWillEnterFullScreenForElement(element);
737    element->document()->webkitDidEnterFullScreenForElement(element);
738}
739
740void ChromeClient::exitFullScreenForElement(WebCore::Element* element)
741{
742    element->document()->webkitWillExitFullScreenForElement(element);
743    element->document()->webkitDidExitFullScreenForElement(element);
744}
745#endif
746
747
748}
749