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