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