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