2010-12-08 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
[WebKit-https.git] / 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 "Console.h"
28 #include "DumpRenderTreeSupportGtk.h"
29 #include "Element.h"
30 #include "FileChooser.h"
31 #include "FileSystem.h"
32 #include "FloatRect.h"
33 #include "FrameLoadRequest.h"
34 #include "FrameView.h"
35 #include "GtkVersioning.h"
36 #include "HTMLNames.h"
37 #include "HitTestResult.h"
38 #include "Icon.h"
39 #include "IntRect.h"
40 #include "KURL.h"
41 #include "NavigationAction.h"
42 #include "NotImplemented.h"
43 #include "PlatformString.h"
44 #include "PopupMenuClient.h"
45 #include "PopupMenuGtk.h"
46 #include "SearchPopupMenuGtk.h"
47 #include "SecurityOrigin.h"
48 #include "WindowFeatures.h"
49 #include "webkitgeolocationpolicydecision.h"
50 #include "webkitnetworkrequest.h"
51 #include "webkitprivate.h"
52 #include "webkitwebview.h"
53 #include "webkitwebviewprivate.h"
54 #include <glib.h>
55 #include <glib/gi18n-lib.h>
56 #include <gtk/gtk.h>
57 #include <wtf/text/CString.h>
58
59 #if ENABLE(DATABASE)
60 #include "DatabaseTracker.h"
61 #endif
62
63 using namespace WebCore;
64
65 namespace WebKit {
66
67 ChromeClient::ChromeClient(WebKitWebView* webView)
68     : m_webView(webView)
69 {
70     ASSERT(m_webView);
71 }
72
73 void ChromeClient::chromeDestroyed()
74 {
75     delete this;
76 }
77
78 FloatRect ChromeClient::windowRect()
79 {
80     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
81     if (gtk_widget_is_toplevel(window)) {
82         gint left, top, width, height;
83         gtk_window_get_position(GTK_WINDOW(window), &left, &top);
84         gtk_window_get_size(GTK_WINDOW(window), &width, &height);
85         return IntRect(left, top, width, height);
86     }
87     return FloatRect();
88 }
89
90 void ChromeClient::setWindowRect(const FloatRect& rect)
91 {
92     IntRect intrect = IntRect(rect);
93     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
94
95     g_object_set(webWindowFeatures,
96                  "x", intrect.x(),
97                  "y", intrect.y(),
98                  "width", intrect.width(),
99                  "height", intrect.height(),
100                  NULL);
101
102     gboolean autoResizeWindow;
103     WebKitWebSettings* settings = webkit_web_view_get_settings(m_webView);
104     g_object_get(settings, "auto-resize-window", &autoResizeWindow, NULL);
105
106     if (!autoResizeWindow)
107         return;
108
109     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
110     if (gtk_widget_is_toplevel(window)) {
111         gtk_window_move(GTK_WINDOW(window), intrect.x(), intrect.y());
112         gtk_window_resize(GTK_WINDOW(window), intrect.width(), intrect.height());
113     }
114 }
115
116 FloatRect ChromeClient::pageRect()
117 {
118     GtkAllocation allocation;
119 #if GTK_CHECK_VERSION(2, 18, 0)
120     gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation);
121 #else
122     allocation = GTK_WIDGET(m_webView)->allocation;
123 #endif
124     return IntRect(allocation.x, allocation.y, allocation.width, allocation.height);
125 }
126
127 float ChromeClient::scaleFactor()
128 {
129     // Not implementable
130     return 1.0;
131 }
132
133 void ChromeClient::focus()
134 {
135     gtk_widget_grab_focus(GTK_WIDGET(m_webView));
136 }
137
138 void ChromeClient::unfocus()
139 {
140     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
141     if (gtk_widget_is_toplevel(window))
142         gtk_window_set_focus(GTK_WINDOW(window), NULL);
143 }
144
145 Page* ChromeClient::createWindow(Frame* frame, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& coreFeatures, const NavigationAction&)
146 {
147     WebKitWebView* webView = 0;
148
149     g_signal_emit_by_name(m_webView, "create-web-view", kit(frame), &webView);
150
151     if (!webView)
152         return 0;
153
154     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_window_features_new_from_core_features(coreFeatures);
155     g_object_set(webView, "window-features", webWindowFeatures, NULL);
156     g_object_unref(webWindowFeatures);
157
158     if (!frameLoadRequest.isEmpty())
159         webkit_web_view_open(webView, frameLoadRequest.resourceRequest().url().string().utf8().data());
160
161     return core(webView);
162 }
163
164 void ChromeClient::show()
165 {
166     webkit_web_view_notify_ready(m_webView);
167 }
168
169 bool ChromeClient::canRunModal()
170 {
171     notImplemented();
172     return false;
173 }
174
175 void ChromeClient::runModal()
176 {
177     notImplemented();
178 }
179
180 void ChromeClient::setToolbarsVisible(bool visible)
181 {
182     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
183
184     g_object_set(webWindowFeatures, "toolbar-visible", visible, NULL);
185 }
186
187 bool ChromeClient::toolbarsVisible()
188 {
189     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
190     gboolean visible;
191
192     g_object_get(webWindowFeatures, "toolbar-visible", &visible, NULL);
193     return visible;
194 }
195
196 void ChromeClient::setStatusbarVisible(bool visible)
197 {
198     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
199
200     g_object_set(webWindowFeatures, "statusbar-visible", visible, NULL);
201 }
202
203 bool ChromeClient::statusbarVisible()
204 {
205     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
206     gboolean visible;
207
208     g_object_get(webWindowFeatures, "statusbar-visible", &visible, NULL);
209     return visible;
210 }
211
212 void ChromeClient::setScrollbarsVisible(bool visible)
213 {
214     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
215
216     g_object_set(webWindowFeatures, "scrollbar-visible", visible, NULL);
217 }
218
219 bool ChromeClient::scrollbarsVisible() {
220     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
221     gboolean visible;
222
223     g_object_get(webWindowFeatures, "scrollbar-visible", &visible, NULL);
224     return visible;
225 }
226
227 void ChromeClient::setMenubarVisible(bool visible)
228 {
229     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
230
231     g_object_set(webWindowFeatures, "menubar-visible", visible, NULL);
232 }
233
234 bool ChromeClient::menubarVisible()
235 {
236     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
237     gboolean visible;
238
239     g_object_get(webWindowFeatures, "menubar-visible", &visible, NULL);
240     return visible;
241 }
242
243 void ChromeClient::setResizable(bool)
244 {
245     // Ignored for now
246 }
247
248 void ChromeClient::closeWindowSoon()
249 {
250     // We may not have a WebView as create-web-view can return NULL.
251     if (!m_webView)
252         return;
253
254     webkit_web_view_stop_loading(m_webView);
255
256     gboolean isHandled = false;
257     g_signal_emit_by_name(m_webView, "close-web-view", &isHandled);
258
259     if (isHandled)
260         return;
261 }
262
263 bool ChromeClient::canTakeFocus(FocusDirection)
264 {
265     return gtk_widget_get_can_focus(GTK_WIDGET(m_webView));
266 }
267
268 void ChromeClient::takeFocus(FocusDirection)
269 {
270     unfocus();
271 }
272
273 void ChromeClient::focusedNodeChanged(Node*)
274 {
275 }
276
277 void ChromeClient::focusedFrameChanged(Frame*)
278 {
279 }
280
281 bool ChromeClient::canRunBeforeUnloadConfirmPanel()
282 {
283     return true;
284 }
285
286 bool ChromeClient::runBeforeUnloadConfirmPanel(const WTF::String& message, WebCore::Frame* frame)
287 {
288     return runJavaScriptConfirm(frame, message);
289 }
290
291 void ChromeClient::addMessageToConsole(WebCore::MessageSource source, WebCore::MessageType type, WebCore::MessageLevel level, const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceId)
292 {
293     gboolean retval;
294     g_signal_emit_by_name(m_webView, "console-message", message.utf8().data(), lineNumber, sourceId.utf8().data(), &retval);
295 }
296
297 void ChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
298 {
299     gboolean retval;
300     g_signal_emit_by_name(m_webView, "script-alert", kit(frame), message.utf8().data(), &retval);
301 }
302
303 bool ChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
304 {
305     gboolean retval;
306     gboolean didConfirm;
307     g_signal_emit_by_name(m_webView, "script-confirm", kit(frame), message.utf8().data(), &didConfirm, &retval);
308     return didConfirm == TRUE;
309 }
310
311 bool ChromeClient::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
312 {
313     gboolean retval;
314     gchar* value = 0;
315     g_signal_emit_by_name(m_webView, "script-prompt", kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value, &retval);
316     if (value) {
317         result = String::fromUTF8(value);
318         g_free(value);
319         return true;
320     }
321     return false;
322 }
323
324 void ChromeClient::setStatusbarText(const String& string)
325 {
326     CString stringMessage = string.utf8();
327     g_signal_emit_by_name(m_webView, "status-bar-text-changed", stringMessage.data());
328 }
329
330 bool ChromeClient::shouldInterruptJavaScript()
331 {
332     notImplemented();
333     return false;
334 }
335
336 bool ChromeClient::tabsToLinks() const
337 {
338     if (DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled())
339         return DumpRenderTreeSupportGtk::linksIncludedInFocusChain();
340
341     return true;
342 }
343
344 IntRect ChromeClient::windowResizerRect() const
345 {
346     notImplemented();
347     return IntRect();
348 }
349
350 void ChromeClient::invalidateWindow(const IntRect&, bool)
351 {
352     notImplemented();
353 }
354
355 void ChromeClient::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate)
356 {
357     GdkRectangle rect = updateRect;
358     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView));
359
360     if (window) {
361         gdk_window_invalidate_rect(window, &rect, FALSE);
362         // We don't currently do immediate updates since they delay other UI elements.
363         //if (immediate)
364         //    gdk_window_process_updates(window, FALSE);
365     }
366 }
367
368 void ChromeClient::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
369 {
370     invalidateContentsAndWindow(updateRect, immediate);
371 }
372
373 void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
374 {
375     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView));
376     if (!window)
377         return;
378
379     // We cannot use gdk_window_scroll here because it is only able to
380     // scroll the whole window at once, and we often need to scroll
381     // portions of the window only (think frames).
382     GdkRectangle area = clipRect;
383     GdkRectangle moveRect;
384
385     GdkRectangle sourceRect = area;
386     sourceRect.x -= delta.width();
387     sourceRect.y -= delta.height();
388
389 #ifdef GTK_API_VERSION_2
390     GdkRegion* invalidRegion = gdk_region_rectangle(&area);
391
392     if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
393         GdkRegion* moveRegion = gdk_region_rectangle(&moveRect);
394         gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
395         gdk_region_offset(moveRegion, delta.width(), delta.height());
396         gdk_region_subtract(invalidRegion, moveRegion);
397         gdk_region_destroy(moveRegion);
398     }
399
400     gdk_window_invalidate_region(window, invalidRegion, FALSE);
401     gdk_region_destroy(invalidRegion);
402 #else
403     cairo_region_t* invalidRegion = cairo_region_create_rectangle(&area);
404
405     if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
406         cairo_region_t* moveRegion = cairo_region_create_rectangle(&moveRect);
407         gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
408         cairo_region_translate(moveRegion, delta.width(), delta.height());
409         cairo_region_subtract(invalidRegion, moveRegion);
410         cairo_region_destroy(moveRegion);
411     }
412
413     gdk_window_invalidate_region(window, invalidRegion, FALSE);
414     cairo_region_destroy(invalidRegion);
415 #endif
416
417 }
418
419 // FIXME: this does not take into account the WM decorations
420 static IntPoint widgetScreenPosition(GtkWidget* widget)
421 {
422     GtkWidget* window = gtk_widget_get_toplevel(widget);
423     int widgetX = 0, widgetY = 0;
424
425     gtk_widget_translate_coordinates(widget, window, 0, 0, &widgetX, &widgetY);
426
427     IntPoint result(widgetX, widgetY);
428     int originX, originY;
429     gdk_window_get_origin(gtk_widget_get_window(window), &originX, &originY);
430     result.move(originX, originY);
431
432     return result;
433 }
434
435 IntRect ChromeClient::windowToScreen(const IntRect& rect) const
436 {
437     IntRect result(rect);
438     IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView));
439     result.move(screenPosition.x(), screenPosition.y());
440
441     return result;
442 }
443
444 IntPoint ChromeClient::screenToWindow(const IntPoint& point) const
445 {
446     IntPoint result(point);
447     IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView));
448     result.move(-screenPosition.x(), -screenPosition.y());
449
450     return result;
451 }
452
453 PlatformPageClient ChromeClient::platformPageClient() const
454 {
455     return GTK_WIDGET(m_webView);
456 }
457
458 void ChromeClient::contentsSizeChanged(Frame* frame, const IntSize& size) const
459 {
460     // We need to queue a resize request only if the size changed,
461     // otherwise we get into an infinite loop!
462     GtkWidget* widget = GTK_WIDGET(m_webView);
463     GtkRequisition requisition;
464 #if GTK_CHECK_VERSION(2, 20, 0)
465     gtk_widget_get_requisition(widget, &requisition);
466 #else
467     requisition = widget->requisition;
468 #endif
469     if (gtk_widget_get_realized(widget)
470         && (requisition.height != size.height())
471         || (requisition.width != size.width()))
472         gtk_widget_queue_resize_no_redraw(widget);
473 }
474
475 void ChromeClient::scrollbarsModeDidChange() const
476 {
477     WebKitWebFrame* webFrame = webkit_web_view_get_main_frame(m_webView);
478
479     g_object_notify(G_OBJECT(webFrame), "horizontal-scrollbar-policy");
480     g_object_notify(G_OBJECT(webFrame), "vertical-scrollbar-policy");
481
482     gboolean isHandled;
483     g_signal_emit_by_name(webFrame, "scrollbars-policy-changed", &isHandled);
484
485     if (isHandled)
486         return;
487
488     GtkWidget* parent = gtk_widget_get_parent(GTK_WIDGET(m_webView));
489     if (!parent || !GTK_IS_SCROLLED_WINDOW(parent))
490         return;
491
492     GtkPolicyType horizontalPolicy = webkit_web_frame_get_horizontal_scrollbar_policy(webFrame);
493     GtkPolicyType verticalPolicy = webkit_web_frame_get_vertical_scrollbar_policy(webFrame);
494
495     // ScrolledWindow doesn't like to display only part of a widget if
496     // the scrollbars are completely disabled; We have a disparity
497     // here on what the policy requested by the web app is and what we
498     // can represent; the idea is not to show scrollbars, only.
499     if (horizontalPolicy == GTK_POLICY_NEVER)
500         horizontalPolicy = GTK_POLICY_AUTOMATIC;
501
502     if (verticalPolicy == GTK_POLICY_NEVER)
503         verticalPolicy = GTK_POLICY_AUTOMATIC;
504
505     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(parent),
506                                    horizontalPolicy, verticalPolicy);
507 }
508
509 void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags)
510 {
511     // check if the element is a link...
512     bool isLink = hit.isLiveLink();
513     if (isLink) {
514         KURL url = hit.absoluteLinkURL();
515         if (!url.isEmpty() && url != m_hoveredLinkURL) {
516             TextDirection dir;
517             CString titleString = hit.title(dir).utf8();
518             CString urlString = url.prettyURL().utf8();
519             g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data());
520             m_hoveredLinkURL = url;
521         }
522     } else if (!isLink && !m_hoveredLinkURL.isEmpty()) {
523         g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0);
524         m_hoveredLinkURL = KURL();
525     }
526
527     if (Node* node = hit.innerNonSharedNode()) {
528         Frame* frame = node->document()->frame();
529         FrameView* view = frame ? frame->view() : 0;
530         m_webView->priv->tooltipArea = view ? view->contentsToWindow(node->getRect()) : IntRect();
531     } else
532         m_webView->priv->tooltipArea = IntRect();
533 }
534
535 void ChromeClient::setToolTip(const String& toolTip, TextDirection)
536 {
537     webkit_web_view_set_tooltip_text(m_webView, toolTip.utf8().data());
538 }
539
540 void ChromeClient::print(Frame* frame)
541 {
542     WebKitWebFrame* webFrame = kit(frame);
543     gboolean isHandled = false;
544     g_signal_emit_by_name(m_webView, "print-requested", webFrame, &isHandled);
545
546     if (isHandled)
547         return;
548
549     webkit_web_frame_print(webFrame);
550 }
551
552 #if ENABLE(DATABASE)
553 void ChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName)
554 {
555     guint64 defaultQuota = webkit_get_default_web_database_quota();
556     DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), defaultQuota);
557
558     WebKitWebFrame* webFrame = kit(frame);
559     WebKitWebView* webView = getViewFromFrame(webFrame);
560
561     WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(webFrame);
562     WebKitWebDatabase* webDatabase = webkit_security_origin_get_web_database(origin, databaseName.utf8().data());
563     g_signal_emit_by_name(webView, "database-quota-exceeded", webFrame, webDatabase);
564 }
565 #endif
566
567 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
568 void ChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
569 {
570     // FIXME: Free some space.
571     notImplemented();
572 }
573
574 void ChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*)
575 {
576     notImplemented();
577 }
578 #endif
579
580 void ChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser)
581 {
582     RefPtr<FileChooser> chooser = prpFileChooser;
583
584     GtkWidget* dialog = gtk_file_chooser_dialog_new(_("Upload File"),
585                                                     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(platformPageClient()))),
586                                                     GTK_FILE_CHOOSER_ACTION_OPEN,
587                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
588                                                     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
589                                                     NULL);
590
591     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), chooser->allowsMultipleFiles());
592
593     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
594         if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog))) {
595             GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
596             Vector<String> names;
597             for (GSList* item = filenames ; item ; item = item->next) {
598                 if (!item->data)
599                     continue;
600                 names.append(filenameToString(static_cast<char*>(item->data)));
601                 g_free(item->data);
602             }
603             g_slist_free(filenames);
604             chooser->chooseFiles(names);
605         } else {
606             gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
607             if (filename)
608                 chooser->chooseFile(filenameToString(filename));
609             g_free(filename);
610         }
611     }
612     gtk_widget_destroy(dialog);
613 }
614
615 void ChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser)
616 {
617     chooser->iconLoaded(Icon::createIconForFiles(filenames));
618 }
619
620 void ChromeClient::setCursor(const Cursor&)
621 {
622     notImplemented();
623 }
624
625 void ChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
626 {
627     WebKitWebFrame* webFrame = kit(frame);
628     WebKitWebView* webView = getViewFromFrame(webFrame);
629
630     PlatformRefPtr<WebKitGeolocationPolicyDecision> policyDecision(adoptPlatformRef(webkit_geolocation_policy_decision_new(webFrame, geolocation)));
631
632     gboolean isHandled = FALSE;
633     g_signal_emit_by_name(webView, "geolocation-policy-decision-requested", webFrame, policyDecision.get(), &isHandled);
634     if (!isHandled)
635         webkit_geolocation_policy_deny(policyDecision.get());
636 }
637
638 void ChromeClient::cancelGeolocationPermissionRequestForFrame(WebCore::Frame* frame, WebCore::Geolocation*)
639 {
640     WebKitWebFrame* webFrame = kit(frame);
641     WebKitWebView* webView = getViewFromFrame(webFrame);
642     g_signal_emit_by_name(webView, "geolocation-policy-decision-cancelled", webFrame);
643 }
644
645 bool ChromeClient::selectItemWritingDirectionIsNatural()
646 {
647     return true;
648 }
649
650 PassRefPtr<WebCore::PopupMenu> ChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
651 {
652     return adoptRef(new PopupMenuGtk(client));
653 }
654
655 PassRefPtr<WebCore::SearchPopupMenu> ChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
656 {
657     return adoptRef(new SearchPopupMenuGtk(client));
658 }
659
660 #if ENABLE(VIDEO)
661
662 bool ChromeClient::supportsFullscreenForNode(const Node* node)
663 {
664     return node->hasTagName(HTMLNames::videoTag);
665 }
666
667 void ChromeClient::enterFullscreenForNode(Node* node)
668 {
669     WebCore::Frame* frame = node->document()->frame();
670     WebKitWebFrame* webFrame = kit(frame);
671     WebKitWebView* webView = getViewFromFrame(webFrame);
672     webViewEnterFullscreen(webView, node);
673 }
674
675 void ChromeClient::exitFullscreenForNode(Node* node)
676 {
677     WebCore::Frame* frame = node->document()->frame();
678     WebKitWebFrame* webFrame = kit(frame);
679     WebKitWebView* webView = getViewFromFrame(webFrame);
680     webViewExitFullscreen(webView);
681 }
682 #endif
683
684 }