[GTK] WebKit2GTK+ does not handle touchmove and touchend events correctly
[WebKit-https.git] / Source / WebKit / UIProcess / API / gtk / WebKitWebViewBase.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2011 Igalia S.L.
5  * Copyright (C) 2013 Gustavo Noronha Silva <gns@gnome.org>.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "WebKitWebViewBase.h"
31
32 #include "APIPageConfiguration.h"
33 #include "AcceleratedBackingStore.h"
34 #include "ActivityState.h"
35 #include "DrawingAreaProxyImpl.h"
36 #include "InputMethodFilter.h"
37 #include "KeyBindingTranslator.h"
38 #include "NativeWebKeyboardEvent.h"
39 #include "NativeWebMouseEvent.h"
40 #include "NativeWebWheelEvent.h"
41 #include "PageClientImpl.h"
42 #include "WebEventFactory.h"
43 #include "WebInspectorProxy.h"
44 #include "WebKit2Initialize.h"
45 #include "WebKitAuthenticationDialog.h"
46 #include "WebKitWebViewBaseAccessible.h"
47 #include "WebKitWebViewBasePrivate.h"
48 #include "WebPageGroup.h"
49 #include "WebPageProxy.h"
50 #include "WebPreferences.h"
51 #include "WebProcessPool.h"
52 #include "WebUserContentControllerProxy.h"
53 #include <WebCore/CairoUtilities.h>
54 #include <WebCore/GUniquePtrGtk.h>
55 #include <WebCore/GtkUtilities.h>
56 #include <WebCore/GtkVersioning.h>
57 #include <WebCore/NotImplemented.h>
58 #include <WebCore/PasteboardHelper.h>
59 #include <WebCore/PlatformDisplay.h>
60 #include <WebCore/RefPtrCairo.h>
61 #include <WebCore/Region.h>
62 #include <gdk/gdk.h>
63 #include <gdk/gdkkeysyms.h>
64 #include <glib/gi18n-lib.h>
65 #include <memory>
66 #include <wtf/HashMap.h>
67 #include <wtf/glib/GRefPtr.h>
68 #include <wtf/glib/WTFGType.h>
69 #include <wtf/text/CString.h>
70
71 #if ENABLE(FULLSCREEN_API)
72 #include "WebFullScreenManagerProxy.h"
73 #endif
74
75 #if PLATFORM(X11)
76 #include <gdk/gdkx.h>
77 #endif
78
79 // gtk_widget_get_scale_factor() appeared in GTK 3.10, but we also need
80 // to make sure we have cairo new enough to support cairo_surface_set_device_scale
81 #define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)
82
83 using namespace WebKit;
84 using namespace WebCore;
85
86 struct ClickCounter {
87 public:
88     void reset()
89     {
90         currentClickCount = 0;
91         previousClickPoint = IntPoint();
92         previousClickTime = 0;
93         previousClickButton = 0;
94     }
95
96     int currentClickCountForGdkButtonEvent(GdkEventButton* buttonEvent)
97     {
98         GdkEvent* event = reinterpret_cast<GdkEvent*>(buttonEvent);
99         int doubleClickDistance = 250;
100         int doubleClickTime = 5;
101         g_object_get(gtk_settings_get_for_screen(gdk_event_get_screen(event)),
102             "gtk-double-click-distance", &doubleClickDistance, "gtk-double-click-time", &doubleClickTime, nullptr);
103
104         // GTK+ only counts up to triple clicks, but WebCore wants to know about
105         // quadruple clicks, quintuple clicks, ad infinitum. Here, we replicate the
106         // GDK logic for counting clicks.
107         guint32 eventTime = gdk_event_get_time(event);
108         if (!eventTime) {
109             // Real events always have a non-zero time, but events synthesized
110             // by the WTR do not and we must calculate a time manually. This time
111             // is not calculated in the WTR, because GTK+ does not work well with
112             // anything other than GDK_CURRENT_TIME on synthesized events.
113             GTimeVal timeValue;
114             g_get_current_time(&timeValue);
115             eventTime = (timeValue.tv_sec * 1000) + (timeValue.tv_usec / 1000);
116         }
117
118         if ((event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
119             || ((std::abs(buttonEvent->x - previousClickPoint.x()) < doubleClickDistance)
120                 && (std::abs(buttonEvent->y - previousClickPoint.y()) < doubleClickDistance)
121                 && (eventTime - previousClickTime < static_cast<unsigned>(doubleClickTime))
122                 && (buttonEvent->button == previousClickButton)))
123             currentClickCount++;
124         else
125             currentClickCount = 1;
126
127         double x, y;
128         gdk_event_get_coords(event, &x, &y);
129         previousClickPoint = IntPoint(x, y);
130         previousClickButton = buttonEvent->button;
131         previousClickTime = eventTime;
132
133         return currentClickCount;
134     }
135
136 private:
137     int currentClickCount;
138     IntPoint previousClickPoint;
139     unsigned previousClickButton;
140     int previousClickTime;
141 };
142
143 typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
144 typedef HashMap<uint32_t, GUniquePtr<GdkEvent>> TouchEventsMap;
145
146 struct _WebKitWebViewBasePrivate {
147     _WebKitWebViewBasePrivate()
148         : updateActivityStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateActivityStateTimerFired)
149     {
150     }
151
152     void updateActivityStateTimerFired()
153     {
154         if (!pageProxy)
155             return;
156         pageProxy->activityStateDidChange(activityStateFlagsToUpdate);
157         activityStateFlagsToUpdate = ActivityState::NoFlags;
158     }
159
160     WebKitWebViewChildrenMap children;
161     std::unique_ptr<PageClientImpl> pageClient;
162     RefPtr<WebPageProxy> pageProxy;
163     bool shouldForwardNextKeyEvent { false };
164     bool shouldForwardNextWheelEvent { false };
165     ClickCounter clickCounter;
166     CString tooltipText;
167     IntRect tooltipArea;
168     GRefPtr<AtkObject> accessible;
169     GtkWidget* authenticationDialog { nullptr };
170     GtkWidget* inspectorView { nullptr };
171     AttachmentSide inspectorAttachmentSide { AttachmentSide::Bottom };
172     unsigned inspectorViewSize { 0 };
173     GUniquePtr<GdkEvent> contextMenuEvent;
174     WebContextMenuProxyGtk* activeContextMenuProxy { nullptr };
175     InputMethodFilter inputMethodFilter;
176     KeyBindingTranslator keyBindingTranslator;
177     TouchEventsMap touchEvents;
178     IntSize contentsSize;
179
180     GtkWindow* toplevelOnScreenWindow { nullptr };
181     unsigned long toplevelFocusInEventID { 0 };
182     unsigned long toplevelFocusOutEventID { 0 };
183     unsigned long toplevelWindowStateEventID { 0 };
184     unsigned long toplevelWindowRealizedID { 0 };
185
186     // View State.
187     ActivityState::Flags activityState { 0 };
188     ActivityState::Flags activityStateFlagsToUpdate { 0 };
189     RunLoop::Timer<WebKitWebViewBasePrivate> updateActivityStateTimer;
190
191 #if ENABLE(FULLSCREEN_API)
192     bool fullScreenModeActive { false };
193     GRefPtr<GDBusProxy> screenSaverProxy;
194     GRefPtr<GCancellable> screenSaverInhibitCancellable;
195     unsigned screenSaverCookie { 0 };
196 #endif
197
198     std::unique_ptr<AcceleratedBackingStore> acceleratedBackingStore;
199
200 #if ENABLE(DRAG_SUPPORT)
201     std::unique_ptr<DragAndDropHandler> dragAndDropHandler;
202 #endif
203
204 #if HAVE(GTK_GESTURES)
205     std::unique_ptr<GestureController> gestureController;
206 #endif
207 };
208
209 WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
210
211 static void webkitWebViewBaseScheduleUpdateActivityState(WebKitWebViewBase* webViewBase, ActivityState::Flags flagsToUpdate)
212 {
213     WebKitWebViewBasePrivate* priv = webViewBase->priv;
214     priv->activityStateFlagsToUpdate |= flagsToUpdate;
215     if (priv->updateActivityStateTimer.isActive())
216         return;
217
218     priv->updateActivityStateTimer.startOneShot(0_s);
219 }
220
221 static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
222 {
223     // Spurious focus in events can occur when the window is hidden.
224     if (!gtk_widget_get_visible(widget))
225         return FALSE;
226
227     WebKitWebViewBasePrivate* priv = webViewBase->priv;
228     if (priv->activityState & ActivityState::WindowIsActive)
229         return FALSE;
230
231     priv->activityState |= ActivityState::WindowIsActive;
232     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive);
233
234     return FALSE;
235 }
236
237 static gboolean toplevelWindowFocusOutEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
238 {
239     WebKitWebViewBasePrivate* priv = webViewBase->priv;
240     if (!(priv->activityState & ActivityState::WindowIsActive))
241         return FALSE;
242
243     priv->activityState &= ~ActivityState::WindowIsActive;
244     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive);
245
246     return FALSE;
247 }
248
249 static gboolean toplevelWindowStateEvent(GtkWidget*, GdkEventWindowState* event, WebKitWebViewBase* webViewBase)
250 {
251     WebKitWebViewBasePrivate* priv = webViewBase->priv;
252     if (!(event->changed_mask & GDK_WINDOW_STATE_ICONIFIED))
253         return FALSE;
254
255     bool visible = !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED);
256     if ((visible && priv->activityState & ActivityState::IsVisible) || (!visible && !(priv->activityState & ActivityState::IsVisible)))
257         return FALSE;
258
259     if (visible)
260         priv->activityState |= ActivityState::IsVisible;
261     else
262         priv->activityState &= ~ActivityState::IsVisible;
263     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible);
264
265     return FALSE;
266 }
267
268 static void toplevelWindowRealized(WebKitWebViewBase* webViewBase)
269 {
270     gtk_widget_realize(GTK_WIDGET(webViewBase));
271
272     WebKitWebViewBasePrivate* priv = webViewBase->priv;
273     if (priv->toplevelWindowRealizedID) {
274         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
275         priv->toplevelWindowRealizedID = 0;
276     }
277 }
278
279 static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window)
280 {
281     WebKitWebViewBasePrivate* priv = webViewBase->priv;
282     if (priv->toplevelOnScreenWindow == window)
283         return;
284
285     if (priv->toplevelFocusInEventID) {
286         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID);
287         priv->toplevelFocusInEventID = 0;
288     }
289     if (priv->toplevelFocusOutEventID) {
290         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID);
291         priv->toplevelFocusOutEventID = 0;
292     }
293     if (priv->toplevelWindowStateEventID) {
294         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowStateEventID);
295         priv->toplevelWindowStateEventID = 0;
296     }
297     if (priv->toplevelWindowRealizedID) {
298         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
299         priv->toplevelWindowRealizedID = 0;
300     }
301
302     priv->toplevelOnScreenWindow = window;
303
304     if (!priv->toplevelOnScreenWindow) {
305         ActivityState::Flags flagsToUpdate = 0;
306         if (priv->activityState & ActivityState::IsInWindow) {
307             priv->activityState &= ~ActivityState::IsInWindow;
308             flagsToUpdate |= ActivityState::IsInWindow;
309         }
310         if (priv->activityState & ActivityState::WindowIsActive) {
311             priv->activityState &= ~ActivityState::WindowIsActive;
312             flagsToUpdate |= ActivityState::IsInWindow;
313         }
314         if (flagsToUpdate)
315             webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
316
317         return;
318     }
319
320     priv->toplevelFocusInEventID =
321         g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event",
322                          G_CALLBACK(toplevelWindowFocusInEvent), webViewBase);
323     priv->toplevelFocusOutEventID =
324         g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event",
325                          G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase);
326     priv->toplevelWindowStateEventID =
327         g_signal_connect(priv->toplevelOnScreenWindow, "window-state-event", G_CALLBACK(toplevelWindowStateEvent), webViewBase);
328
329     if (gtk_widget_get_realized(GTK_WIDGET(window)))
330         gtk_widget_realize(GTK_WIDGET(webViewBase));
331     else
332         priv->toplevelWindowRealizedID = g_signal_connect_swapped(window, "realize", G_CALLBACK(toplevelWindowRealized), webViewBase);
333 }
334
335 static void webkitWebViewBaseRealize(GtkWidget* widget)
336 {
337     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
338     WebKitWebViewBasePrivate* priv = webView->priv;
339
340     gtk_widget_set_realized(widget, TRUE);
341
342     GtkAllocation allocation;
343     gtk_widget_get_allocation(widget, &allocation);
344
345     GdkWindowAttr attributes;
346     attributes.window_type = GDK_WINDOW_CHILD;
347     attributes.x = allocation.x;
348     attributes.y = allocation.y;
349     attributes.width = allocation.width;
350     attributes.height = allocation.height;
351     attributes.wclass = GDK_INPUT_OUTPUT;
352     attributes.visual = gtk_widget_get_visual(widget);
353     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
354         | GDK_EXPOSURE_MASK
355         | GDK_BUTTON_PRESS_MASK
356         | GDK_BUTTON_RELEASE_MASK
357         | GDK_SCROLL_MASK
358         | GDK_SMOOTH_SCROLL_MASK
359         | GDK_POINTER_MOTION_MASK
360         | GDK_ENTER_NOTIFY_MASK
361         | GDK_LEAVE_NOTIFY_MASK
362         | GDK_KEY_PRESS_MASK
363         | GDK_KEY_RELEASE_MASK
364         | GDK_BUTTON_MOTION_MASK
365         | GDK_BUTTON1_MOTION_MASK
366         | GDK_BUTTON2_MOTION_MASK
367         | GDK_BUTTON3_MOTION_MASK
368         | GDK_TOUCH_MASK;
369
370     gint attributesMask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
371
372     GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributesMask);
373     gtk_widget_set_window(widget, window);
374     gdk_window_set_user_data(window, widget);
375
376 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
377     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) {
378         if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()))
379             drawingArea->setNativeSurfaceHandleForCompositing(GDK_WINDOW_XID(window));
380     }
381 #endif
382
383     gtk_style_context_set_background(gtk_widget_get_style_context(widget), window);
384
385     gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window);
386 }
387
388 static void webkitWebViewBaseUnrealize(GtkWidget* widget)
389 {
390     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
391 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
392     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) {
393         if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webView->priv->pageProxy->drawingArea()))
394             drawingArea->destroyNativeSurfaceHandleForCompositing();
395     }
396 #endif
397     gtk_im_context_set_client_window(webView->priv->inputMethodFilter.context(), nullptr);
398
399     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unrealize(widget);
400 }
401
402 static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget)
403 {
404     WebKitWebViewBasePrivate* priv = webViewBase->priv;
405     return widget == priv->inspectorView || widget == priv->authenticationDialog;
406 }
407
408 static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* widget)
409 {
410     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
411     WebKitWebViewBasePrivate* priv = webView->priv;
412
413     // Internal widgets like the web inspector and authentication dialog have custom
414     // allocations so we don't need to add them to our list of children.
415     if (!webkitWebViewChildIsInternalWidget(webView, widget)) {
416         GtkAllocation childAllocation;
417         gtk_widget_get_allocation(widget, &childAllocation);
418         priv->children.set(widget, childAllocation);
419     }
420
421     gtk_widget_set_parent(widget, GTK_WIDGET(container));
422 }
423
424 void webkitWebViewBaseAddAuthenticationDialog(WebKitWebViewBase* webViewBase, GtkWidget* dialog)
425 {
426     WebKitWebViewBasePrivate* priv = webViewBase->priv;
427     priv->authenticationDialog = dialog;
428     gtk_container_add(GTK_CONTAINER(webViewBase), dialog);
429     gtk_widget_show(dialog);
430
431     // We need to draw the shadow over the widget.
432     gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
433 }
434
435 void webkitWebViewBaseAddWebInspector(WebKitWebViewBase* webViewBase, GtkWidget* inspector, AttachmentSide attachmentSide)
436 {
437     if (webViewBase->priv->inspectorView == inspector && webViewBase->priv->inspectorAttachmentSide == attachmentSide)
438         return;
439
440     webViewBase->priv->inspectorAttachmentSide = attachmentSide;
441
442     if (webViewBase->priv->inspectorView == inspector) {
443         gtk_widget_queue_resize(GTK_WIDGET(webViewBase));
444         return;
445     }
446
447     webViewBase->priv->inspectorView = inspector;
448     gtk_container_add(GTK_CONTAINER(webViewBase), inspector);
449 }
450
451 static void webkitWebViewBaseContainerRemove(GtkContainer* container, GtkWidget* widget)
452 {
453     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
454     WebKitWebViewBasePrivate* priv = webView->priv;
455     GtkWidget* widgetContainer = GTK_WIDGET(container);
456
457     gboolean wasVisible = gtk_widget_get_visible(widget);
458     gtk_widget_unparent(widget);
459
460     if (priv->inspectorView == widget) {
461         priv->inspectorView = 0;
462         priv->inspectorViewSize = 0;
463     } else if (priv->authenticationDialog == widget) {
464         priv->authenticationDialog = 0;
465     } else {
466         ASSERT(priv->children.contains(widget));
467         priv->children.remove(widget);
468     }
469     if (wasVisible && gtk_widget_get_visible(widgetContainer))
470         gtk_widget_queue_resize(widgetContainer);
471 }
472
473 static void webkitWebViewBaseContainerForall(GtkContainer* container, gboolean includeInternals, GtkCallback callback, gpointer callbackData)
474 {
475     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
476     WebKitWebViewBasePrivate* priv = webView->priv;
477
478     Vector<GtkWidget*> children;
479     copyKeysToVector(priv->children, children);
480     for (const auto& child : children) {
481         if (priv->children.contains(child))
482             (*callback)(child, callbackData);
483     }
484
485     if (includeInternals && priv->inspectorView)
486         (*callback)(priv->inspectorView, callbackData);
487
488     if (includeInternals && priv->authenticationDialog)
489         (*callback)(priv->authenticationDialog, callbackData);
490 }
491
492 void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* child, const IntRect& childRect)
493 {
494     const IntRect& geometry = webView->priv->children.get(child);
495     if (geometry == childRect)
496         return;
497
498     webView->priv->children.set(child, childRect);
499     gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
500 }
501
502 static void webkitWebViewBaseDispose(GObject* gobject)
503 {
504     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(gobject);
505     g_cancellable_cancel(webView->priv->screenSaverInhibitCancellable.get());
506     webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr);
507     webView->priv->pageProxy->close();
508     webView->priv->acceleratedBackingStore = nullptr;
509     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->dispose(gobject);
510 }
511
512 static void webkitWebViewBaseConstructed(GObject* object)
513 {
514     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->constructed(object);
515
516     GtkWidget* viewWidget = GTK_WIDGET(object);
517     gtk_widget_set_can_focus(viewWidget, TRUE);
518     gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), nullptr, 0,
519         static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
520     gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::singleton().targetList());
521
522     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv;
523     priv->pageClient = std::make_unique<PageClientImpl>(viewWidget);
524     priv->authenticationDialog = 0;
525 }
526
527 static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr)
528 {
529     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
530     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webViewBase->priv->pageProxy->drawingArea());
531     if (!drawingArea)
532         return FALSE;
533
534     GdkRectangle clipRect;
535     if (!gdk_cairo_get_clip_rectangle(cr, &clipRect))
536         return FALSE;
537
538     if (webViewBase->priv->acceleratedBackingStore && drawingArea->isInAcceleratedCompositingMode())
539         webViewBase->priv->acceleratedBackingStore->paint(cr, clipRect);
540     else {
541         WebCore::Region unpaintedRegion; // This is simply unused.
542         drawingArea->paint(cr, clipRect, unpaintedRegion);
543     }
544
545     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
546
547     return FALSE;
548 }
549
550 static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData)
551 {
552     if (!gtk_widget_get_visible(child))
553         return;
554
555     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(userData);
556     WebKitWebViewBasePrivate* priv = webViewBase->priv;
557     const IntRect& geometry = priv->children.get(child);
558     if (geometry.isEmpty())
559         return;
560
561     GtkAllocation childAllocation = geometry;
562     gtk_widget_size_allocate(child, &childAllocation);
563     priv->children.set(child, IntRect());
564 }
565
566 static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation)
567 {
568     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation);
569
570     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
571     gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase);
572
573     IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height);
574     WebKitWebViewBasePrivate* priv = webViewBase->priv;
575     if (priv->inspectorView) {
576         GtkAllocation childAllocation = viewRect;
577
578         if (priv->inspectorAttachmentSide == AttachmentSide::Bottom) {
579             int inspectorViewHeight = std::min(static_cast<int>(priv->inspectorViewSize), allocation->height);
580             childAllocation.x = 0;
581             childAllocation.y = allocation->height - inspectorViewHeight;
582             childAllocation.height = inspectorViewHeight;
583             viewRect.setHeight(std::max(allocation->height - inspectorViewHeight, 1));
584         } else {
585             int inspectorViewWidth = std::min(static_cast<int>(priv->inspectorViewSize), allocation->width);
586             childAllocation.y = 0;
587             childAllocation.x = allocation->width - inspectorViewWidth;
588             childAllocation.width = inspectorViewWidth;
589             viewRect.setWidth(std::max(allocation->width - inspectorViewWidth, 1));
590         }
591
592         gtk_widget_size_allocate(priv->inspectorView, &childAllocation);
593     }
594
595     // The authentication dialog is centered in the view rect, which means that it
596     // never overlaps the web inspector. Thus, we need to calculate the allocation here
597     // after calculating the inspector allocation.
598     if (priv->authenticationDialog) {
599         GtkRequisition minimumSize;
600         gtk_widget_get_preferred_size(priv->authenticationDialog, &minimumSize, nullptr);
601
602         GtkAllocation childAllocation = { 0, 0, std::max(minimumSize.width, viewRect.width()), std::max(minimumSize.height, viewRect.height()) };
603         gtk_widget_size_allocate(priv->authenticationDialog, &childAllocation);
604     }
605
606     if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()))
607         drawingArea->setSize(viewRect.size(), IntSize(), IntSize());
608 }
609
610 static void webkitWebViewBaseGetPreferredWidth(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
611 {
612     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
613     *minimumSize = 0;
614     *naturalSize = priv->contentsSize.width();
615 }
616
617 static void webkitWebViewBaseGetPreferredHeight(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
618 {
619     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
620     *minimumSize = 0;
621     *naturalSize = priv->contentsSize.height();
622 }
623
624 static void webkitWebViewBaseMap(GtkWidget* widget)
625 {
626     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->map(widget);
627
628     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
629     WebKitWebViewBasePrivate* priv = webViewBase->priv;
630     ActivityState::Flags flagsToUpdate = 0;
631     if (!(priv->activityState & ActivityState::IsVisible))
632         flagsToUpdate |= ActivityState::IsVisible;
633     if (priv->toplevelOnScreenWindow) {
634         if (!(priv->activityState & ActivityState::IsInWindow))
635             flagsToUpdate |= ActivityState::IsInWindow;
636         if (gtk_window_is_active(GTK_WINDOW(priv->toplevelOnScreenWindow)) && !(priv->activityState & ActivityState::WindowIsActive))
637             flagsToUpdate |= ActivityState::WindowIsActive;
638     }
639     if (!flagsToUpdate)
640         return;
641
642     priv->activityState |= flagsToUpdate;
643     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
644 }
645
646 static void webkitWebViewBaseUnmap(GtkWidget* widget)
647 {
648     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget);
649
650     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
651     WebKitWebViewBasePrivate* priv = webViewBase->priv;
652     if (!(priv->activityState & ActivityState::IsVisible))
653         return;
654
655     priv->activityState &= ~ActivityState::IsVisible;
656     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible);
657 }
658
659 static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event)
660 {
661     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
662     webkitWebViewBaseSetFocus(webViewBase, true);
663     webViewBase->priv->inputMethodFilter.notifyFocusedIn();
664
665     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
666 }
667
668 static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* event)
669 {
670     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
671     webkitWebViewBaseSetFocus(webViewBase, false);
672     webViewBase->priv->inputMethodFilter.notifyFocusedOut();
673
674     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
675 }
676
677 static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* keyEvent)
678 {
679     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
680     WebKitWebViewBasePrivate* priv = webViewBase->priv;
681
682 #if ENABLE(DEVELOPER_MODE) && OS(LINUX)
683     if ((keyEvent->state & GDK_CONTROL_MASK) && (keyEvent->state & GDK_SHIFT_MASK) && keyEvent->keyval == GDK_KEY_G) {
684         auto& preferences = priv->pageProxy->preferences();
685         preferences.setResourceUsageOverlayVisible(!preferences.resourceUsageOverlayVisible());
686         priv->shouldForwardNextKeyEvent = FALSE;
687         return TRUE;
688     }
689 #endif
690
691     if (priv->authenticationDialog)
692         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
693
694 #if ENABLE(FULLSCREEN_API)
695     if (priv->fullScreenModeActive) {
696         switch (keyEvent->keyval) {
697         case GDK_KEY_Escape:
698         case GDK_KEY_f:
699         case GDK_KEY_F:
700             priv->pageProxy->fullScreenManager()->requestExitFullScreen();
701             return TRUE;
702         default:
703             break;
704         }
705     }
706 #endif
707
708     // Since WebProcess key event handling is not synchronous, handle the event in two passes.
709     // When WebProcess processes the input event, it will call PageClientImpl::doneWithKeyEvent
710     // with event handled status which determines whether to pass the input event to parent or not
711     // using gtk_main_do_event().
712     if (priv->shouldForwardNextKeyEvent) {
713         priv->shouldForwardNextKeyEvent = FALSE;
714         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
715     }
716
717     // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
718     GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
719     priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
720         priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked,
721             !compositionResults.compositionUpdated() ? priv->keyBindingTranslator.commandsForKeyEvent(&event->key) : Vector<String>()));
722     });
723
724     return TRUE;
725 }
726
727 static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* keyEvent)
728 {
729     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
730     WebKitWebViewBasePrivate* priv = webViewBase->priv;
731
732     if (priv->shouldForwardNextKeyEvent) {
733         priv->shouldForwardNextKeyEvent = FALSE;
734         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, keyEvent);
735     }
736
737     // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
738     GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
739     priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
740         priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked, { }));
741     });
742
743     return TRUE;
744 }
745
746 static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventButton* buttonEvent)
747 {
748     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
749     WebKitWebViewBasePrivate* priv = webViewBase->priv;
750
751     if (priv->authenticationDialog)
752         return TRUE;
753
754     gtk_widget_grab_focus(widget);
755
756     priv->inputMethodFilter.notifyMouseButtonPress();
757
758     // For double and triple clicks GDK sends both a normal button press event
759     // and a specific type (like GDK_2BUTTON_PRESS). If we detect a special press
760     // coming up, ignore this event as it certainly generated the double or triple
761     // click. The consequence of not eating this event is two DOM button press events
762     // are generated.
763     GUniquePtr<GdkEvent> nextEvent(gdk_event_peek());
764     if (nextEvent && (nextEvent->any.type == GDK_2BUTTON_PRESS || nextEvent->any.type == GDK_3BUTTON_PRESS))
765         return TRUE;
766
767     // If it's a right click event save it as a possible context menu event.
768     if (buttonEvent->button == 3)
769         priv->contextMenuEvent.reset(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent)));
770
771     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent),
772         priv->clickCounter.currentClickCountForGdkButtonEvent(buttonEvent)));
773     return TRUE;
774 }
775
776 static gboolean webkitWebViewBaseButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event)
777 {
778     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
779     WebKitWebViewBasePrivate* priv = webViewBase->priv;
780
781     if (priv->authenticationDialog)
782         return TRUE;
783
784     gtk_widget_grab_focus(widget);
785     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
786
787     return TRUE;
788 }
789
790 static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* event)
791 {
792     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
793     WebKitWebViewBasePrivate* priv = webViewBase->priv;
794
795     if (std::exchange(priv->shouldForwardNextWheelEvent, false))
796         return FALSE;
797
798     if (priv->authenticationDialog)
799         return FALSE;
800
801     priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(reinterpret_cast<GdkEvent*>(event)));
802
803     return TRUE;
804 }
805
806 static gboolean webkitWebViewBasePopupMenu(GtkWidget* widget)
807 {
808     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
809     WebKitWebViewBasePrivate* priv = webViewBase->priv;
810
811     GdkEvent* currentEvent = gtk_get_current_event();
812     if (!currentEvent)
813         currentEvent = gdk_event_new(GDK_NOTHING);
814     priv->contextMenuEvent.reset(currentEvent);
815     priv->pageProxy->handleContextMenuKeyEvent();
816
817     return TRUE;
818 }
819
820 static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event)
821 {
822     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
823     WebKitWebViewBasePrivate* priv = webViewBase->priv;
824
825     if (priv->authenticationDialog) {
826         auto* widgetClass = GTK_WIDGET_CLASS(webkit_web_view_base_parent_class);
827         return widgetClass->motion_notify_event ? widgetClass->motion_notify_event(widget, event) : FALSE;
828     }
829
830     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
831
832     return FALSE;
833 }
834
835 static gboolean webkitWebViewBaseCrossingNotifyEvent(GtkWidget* widget, GdkEventCrossing* crosssingEvent)
836 {
837     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
838     WebKitWebViewBasePrivate* priv = webViewBase->priv;
839
840     if (priv->authenticationDialog)
841         return FALSE;
842
843     // In the case of crossing events, it's very important the actual coordinates the WebProcess receives, because once the mouse leaves
844     // the web view, the WebProcess won't receive more events until the mouse enters again in the web view. So, if the coordinates of the leave
845     // event are not accurate, the WebProcess might not know the mouse left the view. This can happen because of double to integer conversion,
846     // if the coordinates of the leave event are for example (25.2, -0.9), the WebProcess will receive (25, 0) and any hit test will succeed
847     // because those coordinates are inside the web view.
848     GtkAllocation allocation;
849     gtk_widget_get_allocation(widget, &allocation);
850     double width = allocation.width;
851     double height = allocation.height;
852     double x = crosssingEvent->x;
853     double y = crosssingEvent->y;
854     if (x < 0 && x > -1)
855         x = -1;
856     else if (x >= width && x < width + 1)
857         x = width + 1;
858     if (y < 0 && y > -1)
859         y = -1;
860     else if (y >= height && y < height + 1)
861         y = height + 1;
862
863     GdkEvent* event = reinterpret_cast<GdkEvent*>(crosssingEvent);
864     GUniquePtr<GdkEvent> copiedEvent;
865     if (x != crosssingEvent->x || y != crosssingEvent->y) {
866         copiedEvent.reset(gdk_event_copy(event));
867         copiedEvent->crossing.x = x;
868         copiedEvent->crossing.y = y;
869     }
870
871     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(copiedEvent ? copiedEvent.get() : event, 0 /* currentClickCount */));
872
873     return FALSE;
874 }
875
876 #if ENABLE(TOUCH_EVENTS)
877 static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPoints, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state)
878 {
879     gdouble x, y;
880     gdk_event_get_coords(event, &x, &y);
881
882     gdouble xRoot, yRoot;
883     gdk_event_get_root_coords(event, &xRoot, &yRoot);
884
885     uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event));
886     touchPoints.uncheckedAppend(WebPlatformTouchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y)));
887 }
888
889 static inline WebPlatformTouchPoint::TouchPointState touchPointStateForEvents(const GdkEvent* current, const GdkEvent* event)
890 {
891     if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event))
892         return WebPlatformTouchPoint::TouchStationary;
893
894     switch (current->type) {
895     case GDK_TOUCH_UPDATE:
896         return WebPlatformTouchPoint::TouchMoved;
897     case GDK_TOUCH_BEGIN:
898         return WebPlatformTouchPoint::TouchPressed;
899     case GDK_TOUCH_END:
900         return WebPlatformTouchPoint::TouchReleased;
901     default:
902         return WebPlatformTouchPoint::TouchStationary;
903     }
904 }
905
906 static void webkitWebViewBaseGetTouchPointsForEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Vector<WebPlatformTouchPoint>& touchPoints)
907 {
908     WebKitWebViewBasePrivate* priv = webViewBase->priv;
909     touchPoints.reserveInitialCapacity(event->type == GDK_TOUCH_END ? priv->touchEvents.size() + 1 : priv->touchEvents.size());
910
911     for (const auto& it : priv->touchEvents)
912         appendTouchEvent(touchPoints, it.value.get(), touchPointStateForEvents(it.value.get(), event));
913
914     // Touch was already removed from the TouchEventsMap, add it here.
915     if (event->type == GDK_TOUCH_END)
916         appendTouchEvent(touchPoints, event, WebPlatformTouchPoint::TouchReleased);
917 }
918
919 static gboolean webkitWebViewBaseTouchEvent(GtkWidget* widget, GdkEventTouch* event)
920 {
921     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
922     WebKitWebViewBasePrivate* priv = webViewBase->priv;
923
924     if (priv->authenticationDialog)
925         return TRUE;
926
927     GdkEvent* touchEvent = reinterpret_cast<GdkEvent*>(event);
928     uint32_t sequence = GPOINTER_TO_UINT(gdk_event_get_event_sequence(touchEvent));
929
930     switch (touchEvent->type) {
931     case GDK_TOUCH_BEGIN: {
932         ASSERT(!priv->touchEvents.contains(sequence));
933         GUniquePtr<GdkEvent> event(gdk_event_copy(touchEvent));
934         priv->touchEvents.add(sequence, WTFMove(event));
935         break;
936     }
937     case GDK_TOUCH_UPDATE: {
938         auto it = priv->touchEvents.find(sequence);
939         ASSERT(it != priv->touchEvents.end());
940         it->value.reset(gdk_event_copy(touchEvent));
941         break;
942     }
943     case GDK_TOUCH_END:
944         ASSERT(priv->touchEvents.contains(sequence));
945         priv->touchEvents.remove(sequence);
946         break;
947     default:
948         break;
949     }
950
951     Vector<WebPlatformTouchPoint> touchPoints;
952     webkitWebViewBaseGetTouchPointsForEvent(webViewBase, touchEvent, touchPoints);
953     priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), WTFMove(touchPoints)));
954
955     return TRUE;
956 }
957 #endif // ENABLE(TOUCH_EVENTS)
958
959 #if HAVE(GTK_GESTURES)
960 GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webViewBase)
961 {
962     WebKitWebViewBasePrivate* priv = webViewBase->priv;
963     if (!priv->gestureController)
964         priv->gestureController = std::make_unique<GestureController>(*priv->pageProxy);
965     return *priv->gestureController;
966 }
967 #endif
968
969 static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip)
970 {
971     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
972
973     if (keyboardMode) {
974         // TODO: https://bugs.webkit.org/show_bug.cgi?id=61732.
975         notImplemented();
976         return FALSE;
977     }
978
979     if (priv->tooltipText.length() <= 0)
980         return FALSE;
981
982     if (!priv->tooltipArea.isEmpty()) {
983         GdkRectangle area = priv->tooltipArea;
984         gtk_tooltip_set_tip_area(tooltip, &area);
985     } else
986         gtk_tooltip_set_tip_area(tooltip, 0);
987     gtk_tooltip_set_text(tooltip, priv->tooltipText.data());
988
989     return TRUE;
990 }
991
992 #if ENABLE(DRAG_SUPPORT)
993 static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint /* time */)
994 {
995     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
996     ASSERT(priv->dragAndDropHandler);
997     priv->dragAndDropHandler->fillDragData(context, selectionData, info);
998 }
999
1000 static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context)
1001 {
1002     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1003     ASSERT(priv->dragAndDropHandler);
1004     priv->dragAndDropHandler->finishDrag(context);
1005 }
1006
1007 static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint /* x */, gint /* y */, GtkSelectionData* selectionData, guint info, guint time)
1008 {
1009     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragEntered(context, selectionData, info, time);
1010 }
1011 #endif // ENABLE(DRAG_SUPPORT)
1012
1013 static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget)
1014 {
1015     // If the socket has already been created and embedded a plug ID, return it.
1016     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1017     if (priv->accessible && atk_socket_is_occupied(ATK_SOCKET(priv->accessible.get())))
1018         return priv->accessible.get();
1019
1020     // Create the accessible object and associate it to the widget.
1021     if (!priv->accessible) {
1022         priv->accessible = adoptGRef(ATK_OBJECT(webkitWebViewBaseAccessibleNew(widget)));
1023
1024         // Set the parent not to break bottom-up navigation.
1025         GtkWidget* parentWidget = gtk_widget_get_parent(widget);
1026         AtkObject* axParent = parentWidget ? gtk_widget_get_accessible(parentWidget) : 0;
1027         if (axParent)
1028             atk_object_set_parent(priv->accessible.get(), axParent);
1029     }
1030
1031     // Try to embed the plug in the socket, if posssible.
1032     String plugID = priv->pageProxy->accessibilityPlugID();
1033     if (plugID.isNull())
1034         return priv->accessible.get();
1035
1036     atk_socket_embed(ATK_SOCKET(priv->accessible.get()), const_cast<gchar*>(plugID.utf8().data()));
1037
1038     return priv->accessible.get();
1039 }
1040
1041 #if ENABLE(DRAG_SUPPORT)
1042 static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1043 {
1044     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragMotion(context, IntPoint(x, y), time);
1045     return TRUE;
1046 }
1047
1048 static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint /* time */)
1049 {
1050     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1051     ASSERT(priv->dragAndDropHandler);
1052     priv->dragAndDropHandler->dragLeave(context);
1053 }
1054
1055 static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1056 {
1057     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1058     ASSERT(priv->dragAndDropHandler);
1059     return priv->dragAndDropHandler->drop(context, IntPoint(x, y), time);
1060 }
1061 #endif // ENABLE(DRAG_SUPPORT)
1062
1063 static void webkitWebViewBaseHierarchyChanged(GtkWidget* widget, GtkWidget* oldToplevel)
1064 {
1065     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1066     if (widgetIsOnscreenToplevelWindow(oldToplevel) && GTK_WINDOW(oldToplevel) == priv->toplevelOnScreenWindow) {
1067         webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), nullptr);
1068         return;
1069     }
1070
1071     if (!oldToplevel) {
1072         GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
1073         if (widgetIsOnscreenToplevelWindow(toplevel))
1074             webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), GTK_WINDOW(toplevel));
1075     }
1076 }
1077
1078 static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction)
1079 {
1080     // If the authentication dialog is active, we need to forward focus events there. This
1081     // ensures that you can tab between elements in the box.
1082     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1083     if (priv->authenticationDialog) {
1084         gboolean returnValue;
1085         g_signal_emit_by_name(priv->authenticationDialog, "focus", direction, &returnValue);
1086         return returnValue;
1087     }
1088
1089     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus(widget, direction);
1090 }
1091
1092 static void webkitWebViewBaseDestroy(GtkWidget* widget)
1093 {
1094     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1095     if (priv->authenticationDialog)
1096         gtk_widget_destroy(priv->authenticationDialog);
1097
1098     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->destroy(widget);
1099 }
1100
1101 static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebViewBaseClass)
1102 {
1103     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass);
1104     widgetClass->realize = webkitWebViewBaseRealize;
1105     widgetClass->unrealize = webkitWebViewBaseUnrealize;
1106     widgetClass->draw = webkitWebViewBaseDraw;
1107     widgetClass->size_allocate = webkitWebViewBaseSizeAllocate;
1108     widgetClass->get_preferred_width = webkitWebViewBaseGetPreferredWidth;
1109     widgetClass->get_preferred_height = webkitWebViewBaseGetPreferredHeight;
1110     widgetClass->map = webkitWebViewBaseMap;
1111     widgetClass->unmap = webkitWebViewBaseUnmap;
1112     widgetClass->focus = webkitWebViewBaseFocus;
1113     widgetClass->focus_in_event = webkitWebViewBaseFocusInEvent;
1114     widgetClass->focus_out_event = webkitWebViewBaseFocusOutEvent;
1115     widgetClass->key_press_event = webkitWebViewBaseKeyPressEvent;
1116     widgetClass->key_release_event = webkitWebViewBaseKeyReleaseEvent;
1117     widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent;
1118     widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent;
1119     widgetClass->scroll_event = webkitWebViewBaseScrollEvent;
1120     widgetClass->popup_menu = webkitWebViewBasePopupMenu;
1121     widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent;
1122     widgetClass->enter_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1123     widgetClass->leave_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1124 #if ENABLE(TOUCH_EVENTS)
1125     widgetClass->touch_event = webkitWebViewBaseTouchEvent;
1126 #endif
1127     widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip;
1128 #if ENABLE(DRAG_SUPPORT)
1129     widgetClass->drag_end = webkitWebViewBaseDragEnd;
1130     widgetClass->drag_data_get = webkitWebViewBaseDragDataGet;
1131     widgetClass->drag_motion = webkitWebViewBaseDragMotion;
1132     widgetClass->drag_leave = webkitWebViewBaseDragLeave;
1133     widgetClass->drag_drop = webkitWebViewBaseDragDrop;
1134     widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived;
1135 #endif // ENABLE(DRAG_SUPPORT)
1136     widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
1137     widgetClass->hierarchy_changed = webkitWebViewBaseHierarchyChanged;
1138     widgetClass->destroy = webkitWebViewBaseDestroy;
1139
1140     GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass);
1141     gobjectClass->constructed = webkitWebViewBaseConstructed;
1142     gobjectClass->dispose = webkitWebViewBaseDispose;
1143
1144     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webkitWebViewBaseClass);
1145     containerClass->add = webkitWebViewBaseContainerAdd;
1146     containerClass->remove = webkitWebViewBaseContainerRemove;
1147     containerClass->forall = webkitWebViewBaseContainerForall;
1148
1149     // Before creating a WebKitWebViewBasePriv we need to be sure that WebKit is started.
1150     // Usually starting a context triggers InitializeWebKit2, but in case
1151     // we create a view without asking before for a default_context we get a crash.
1152     WebKit::InitializeWebKit2();
1153 }
1154
1155 WebKitWebViewBase* webkitWebViewBaseCreate(const API::PageConfiguration& configuration)
1156 {
1157     WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, nullptr));
1158     webkitWebViewBaseCreateWebPage(webkitWebViewBase, configuration.copy());
1159     return webkitWebViewBase;
1160 }
1161
1162 GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
1163 {
1164     return webkitWebViewBase->priv->inputMethodFilter.context();
1165 }
1166
1167 WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
1168 {
1169     return webkitWebViewBase->priv->pageProxy.get();
1170 }
1171
1172 #if HAVE(GTK_SCALE_FACTOR)
1173 static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase)
1174 {
1175     webkitWebViewBase->priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1176 }
1177 #endif // HAVE(GTK_SCALE_FACTOR)
1178
1179 void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<API::PageConfiguration>&& configuration)
1180 {
1181     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1182     WebProcessPool* processPool = configuration->processPool();
1183     priv->pageProxy = processPool->createWebPage(*priv->pageClient, WTFMove(configuration));
1184     priv->pageProxy->initializeWebPage();
1185
1186     priv->acceleratedBackingStore = AcceleratedBackingStore::create(*priv->pageProxy);
1187
1188     priv->inputMethodFilter.setPage(priv->pageProxy.get());
1189
1190 #if HAVE(GTK_SCALE_FACTOR)
1191     // We attach this here, because changes in scale factor are passed directly to the page proxy.
1192     priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1193     g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr);
1194 #endif
1195 }
1196
1197 void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
1198 {
1199     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1200     if (tooltip && tooltip[0] != '\0') {
1201         priv->tooltipText = tooltip;
1202         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), TRUE);
1203     } else {
1204         priv->tooltipText = "";
1205         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), FALSE);
1206     }
1207
1208     gtk_widget_trigger_tooltip_query(GTK_WIDGET(webViewBase));
1209 }
1210
1211 void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRect& tooltipArea)
1212 {
1213     webViewBase->priv->tooltipArea = tooltipArea;
1214 }
1215
1216 #if ENABLE(DRAG_SUPPORT)
1217 DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBase* webViewBase)
1218 {
1219     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1220     if (!priv->dragAndDropHandler)
1221         priv->dragAndDropHandler = std::make_unique<DragAndDropHandler>(*priv->pageProxy);
1222     return *priv->dragAndDropHandler;
1223 }
1224 #endif // ENABLE(DRAG_SUPPORT)
1225
1226 void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase)
1227 {
1228     webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE;
1229 }
1230
1231 void webkitWebViewBaseForwardNextWheelEvent(WebKitWebViewBase* webkitWebViewBase)
1232 {
1233     webkitWebViewBase->priv->shouldForwardNextWheelEvent = true;
1234 }
1235
1236 #if ENABLE(FULLSCREEN_API)
1237 static void screenSaverInhibitedCallback(GDBusProxy* screenSaverProxy, GAsyncResult* result, WebKitWebViewBase* webViewBase)
1238 {
1239     GRefPtr<GVariant> returnValue = adoptGRef(g_dbus_proxy_call_finish(screenSaverProxy, result, nullptr));
1240     if (returnValue)
1241         g_variant_get(returnValue.get(), "(u)", &webViewBase->priv->screenSaverCookie);
1242     webViewBase->priv->screenSaverInhibitCancellable = nullptr;
1243 }
1244
1245 static void webkitWebViewBaseSendInhibitMessageToScreenSaver(WebKitWebViewBase* webViewBase)
1246 {
1247     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1248     ASSERT(priv->screenSaverProxy);
1249     priv->screenSaverCookie = 0;
1250     if (!priv->screenSaverInhibitCancellable)
1251         priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new());
1252     g_dbus_proxy_call(priv->screenSaverProxy.get(), "Inhibit", g_variant_new("(ss)", g_get_prgname(), _("Website running in fullscreen mode")),
1253         G_DBUS_CALL_FLAGS_NONE, -1, priv->screenSaverInhibitCancellable.get(), reinterpret_cast<GAsyncReadyCallback>(screenSaverInhibitedCallback), webViewBase);
1254 }
1255
1256 static void screenSaverProxyCreatedCallback(GObject*, GAsyncResult* result, WebKitWebViewBase* webViewBase)
1257 {
1258     // WebKitWebViewBase cancels the proxy creation on dispose, which means this could be called
1259     // after the web view has been destroyed and g_dbus_proxy_new_for_bus_finish will return nullptr.
1260     // So, make sure we don't use the web view unless we have a valid proxy.
1261     // See https://bugs.webkit.org/show_bug.cgi?id=151653.
1262     GRefPtr<GDBusProxy> proxy = adoptGRef(g_dbus_proxy_new_for_bus_finish(result, nullptr));
1263     if (!proxy)
1264         return;
1265
1266     webViewBase->priv->screenSaverProxy = proxy;
1267     webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase);
1268 }
1269
1270 static void webkitWebViewBaseInhibitScreenSaver(WebKitWebViewBase* webViewBase)
1271 {
1272     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1273     if (priv->screenSaverCookie) {
1274         // Already inhibited.
1275         return;
1276     }
1277
1278     if (priv->screenSaverProxy) {
1279         webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase);
1280         return;
1281     }
1282
1283     priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new());
1284     g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS),
1285         nullptr, "org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver", priv->screenSaverInhibitCancellable.get(),
1286         reinterpret_cast<GAsyncReadyCallback>(screenSaverProxyCreatedCallback), webViewBase);
1287 }
1288
1289 static void webkitWebViewBaseUninhibitScreenSaver(WebKitWebViewBase* webViewBase)
1290 {
1291     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1292     if (!priv->screenSaverCookie) {
1293         // Not inhibited or it's being inhibited.
1294         g_cancellable_cancel(priv->screenSaverInhibitCancellable.get());
1295         return;
1296     }
1297
1298     // If we have a cookie we should have a proxy.
1299     ASSERT(priv->screenSaverProxy);
1300     g_dbus_proxy_call(priv->screenSaverProxy.get(), "UnInhibit", g_variant_new("(u)", priv->screenSaverCookie), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr);
1301     priv->screenSaverCookie = 0;
1302 }
1303 #endif
1304
1305 void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase)
1306 {
1307 #if ENABLE(FULLSCREEN_API)
1308     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1309     ASSERT(priv->fullScreenModeActive);
1310
1311     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1312     fullScreenManagerProxy->willEnterFullScreen();
1313
1314     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1315     if (gtk_widget_is_toplevel(topLevelWindow))
1316         gtk_window_fullscreen(GTK_WINDOW(topLevelWindow));
1317     fullScreenManagerProxy->didEnterFullScreen();
1318     priv->fullScreenModeActive = true;
1319     webkitWebViewBaseInhibitScreenSaver(webkitWebViewBase);
1320 #endif
1321 }
1322
1323 void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase)
1324 {
1325 #if ENABLE(FULLSCREEN_API)
1326     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1327     ASSERT(!priv->fullScreenModeActive);
1328
1329     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1330     fullScreenManagerProxy->willExitFullScreen();
1331
1332     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1333     if (gtk_widget_is_toplevel(topLevelWindow))
1334         gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow));
1335     fullScreenManagerProxy->didExitFullScreen();
1336     priv->fullScreenModeActive = false;
1337     webkitWebViewBaseUninhibitScreenSaver(webkitWebViewBase);
1338 #endif
1339 }
1340
1341 bool webkitWebViewBaseIsFullScreen(WebKitWebViewBase* webkitWebViewBase)
1342 {
1343 #if ENABLE(FULLSCREEN_API)
1344     return webkitWebViewBase->priv->fullScreenModeActive;
1345 #else
1346     return false;
1347 #endif
1348 }
1349
1350 void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase* webkitWebViewBase, unsigned size)
1351 {
1352     if (webkitWebViewBase->priv->inspectorViewSize == size)
1353         return;
1354     webkitWebViewBase->priv->inspectorViewSize = size;
1355     if (webkitWebViewBase->priv->inspectorView)
1356         gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1357 }
1358
1359 static void activeContextMenuUnmapped(GtkMenu* menu, WebKitWebViewBase* webViewBase)
1360 {
1361     if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkMenu() == menu)
1362         webViewBase->priv->activeContextMenuProxy = nullptr;
1363 }
1364
1365 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
1366 {
1367     webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
1368     g_signal_connect_object(contextMenuProxy->gtkMenu(), "unmap", G_CALLBACK(activeContextMenuUnmapped), webkitWebViewBase, static_cast<GConnectFlags>(0));
1369 }
1370
1371 WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
1372 {
1373     return webkitWebViewBase->priv->activeContextMenuProxy;
1374 }
1375
1376 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase)
1377 {
1378     return webkitWebViewBase->priv->contextMenuEvent.release();
1379 }
1380
1381 void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
1382 {
1383     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1384     if ((focused && priv->activityState & ActivityState::IsFocused) || (!focused && !(priv->activityState & ActivityState::IsFocused)))
1385         return;
1386
1387     ActivityState::Flags flagsToUpdate = ActivityState::IsFocused;
1388     if (focused) {
1389         priv->activityState |= ActivityState::IsFocused;
1390
1391         // If the view has received the focus and the window is not active
1392         // mark the current window as active now. This can happen if the
1393         // toplevel window is a GTK_WINDOW_POPUP and the focus has been
1394         // set programatically like WebKitTestRunner does, because POPUP
1395         // can't be focused.
1396         if (!(priv->activityState & ActivityState::WindowIsActive)) {
1397             priv->activityState |= ActivityState::WindowIsActive;
1398             flagsToUpdate |= ActivityState::WindowIsActive;
1399         }
1400     } else
1401         priv->activityState &= ~ActivityState::IsFocused;
1402
1403     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
1404 }
1405
1406 bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase)
1407 {
1408     return webViewBase->priv->activityState & ActivityState::WindowIsActive;
1409 }
1410
1411 bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase)
1412 {
1413     return webViewBase->priv->activityState & ActivityState::IsFocused;
1414 }
1415
1416 bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase)
1417 {
1418     return webViewBase->priv->activityState & ActivityState::IsVisible;
1419 }
1420
1421 bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
1422 {
1423     return webViewBase->priv->activityState & ActivityState::IsInWindow;
1424 }
1425
1426 void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
1427 {
1428     webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
1429 }
1430
1431 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
1432 {
1433     const auto& editorState = webkitWebViewBase->priv->pageProxy->editorState();
1434     if (!editorState.isMissingPostLayoutData)
1435         webkitWebViewBase->priv->inputMethodFilter.setCursorRect(editorState.postLayoutData().caretRectAtStart);
1436 }
1437
1438 void webkitWebViewBaseSetContentsSize(WebKitWebViewBase* webkitWebViewBase, const IntSize& contentsSize)
1439 {
1440     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1441     if (priv->contentsSize == contentsSize)
1442         return;
1443     priv->contentsSize = contentsSize;
1444 }
1445
1446 void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase)
1447 {
1448     webkitWebViewBase->priv->clickCounter.reset();
1449 }
1450
1451 void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1452 {
1453     if (webkitWebViewBase->priv->acceleratedBackingStore)
1454         webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1455 }
1456
1457 void webkitWebViewBaseUpdateAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1458 {
1459     if (webkitWebViewBase->priv->acceleratedBackingStore)
1460         webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1461 }
1462
1463 void webkitWebViewBaseExitAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase)
1464 {
1465     if (webkitWebViewBase->priv->acceleratedBackingStore)
1466         webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1467 }
1468
1469 void webkitWebViewBaseDidRelaunchWebProcess(WebKitWebViewBase* webkitWebViewBase)
1470 {
1471     // Queue a resize to ensure the new DrawingAreaProxy is resized.
1472     gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1473
1474 #if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1475     if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1476         return;
1477
1478     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1479     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
1480     ASSERT(drawingArea);
1481
1482     if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1483         return;
1484
1485     uint64_t windowID = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(webkitWebViewBase)));
1486     drawingArea->setNativeSurfaceHandleForCompositing(windowID);
1487 #else
1488     UNUSED_PARAM(webkitWebViewBase);
1489 #endif
1490 }
1491
1492 void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase)
1493 {
1494     if (webkitWebViewBase->priv->acceleratedBackingStore)
1495         webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1496 #if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1497     if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1498         return;
1499
1500     if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1501         return;
1502
1503     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1504     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
1505     ASSERT(drawingArea);
1506     drawingArea->destroyNativeSurfaceHandleForCompositing();
1507 #endif
1508 }