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>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
30 #include "WebKitWebViewBase.h"
32 #include "APIPageConfiguration.h"
33 #include "AcceleratedBackingStore.h"
34 #include "DrawingAreaProxyImpl.h"
35 #include "InputMethodFilter.h"
36 #include "KeyBindingTranslator.h"
37 #include "NativeWebKeyboardEvent.h"
38 #include "NativeWebMouseEvent.h"
39 #include "NativeWebWheelEvent.h"
40 #include "PageClientImpl.h"
41 #include "ViewState.h"
42 #include "WebEventFactory.h"
43 #include "WebFullScreenClientGtk.h"
44 #include "WebInspectorProxy.h"
45 #include "WebKit2Initialize.h"
46 #include "WebKitAuthenticationDialog.h"
47 #include "WebKitPrivate.h"
48 #include "WebKitWebViewBaseAccessible.h"
49 #include "WebKitWebViewBasePrivate.h"
50 #include "WebPageGroup.h"
51 #include "WebPageProxy.h"
52 #include "WebPreferences.h"
53 #include "WebProcessPool.h"
54 #include "WebUserContentControllerProxy.h"
55 #include <WebCore/CairoUtilities.h>
56 #include <WebCore/GUniquePtrGtk.h>
57 #include <WebCore/GtkUtilities.h>
58 #include <WebCore/GtkVersioning.h>
59 #include <WebCore/NotImplemented.h>
60 #include <WebCore/PasteboardHelper.h>
61 #include <WebCore/PlatformDisplay.h>
62 #include <WebCore/RefPtrCairo.h>
63 #include <WebCore/Region.h>
65 #include <gdk/gdkkeysyms.h>
66 #include <glib/gi18n-lib.h>
68 #include <wtf/HashMap.h>
69 #include <wtf/glib/GRefPtr.h>
70 #include <wtf/text/CString.h>
72 #if ENABLE(FULLSCREEN_API)
73 #include "WebFullScreenManagerProxy.h"
80 // gtk_widget_get_scale_factor() appeared in GTK 3.10, but we also need
81 // to make sure we have cairo new enough to support cairo_surface_set_device_scale
82 #define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)
84 using namespace WebKit;
85 using namespace WebCore;
91 currentClickCount = 0;
92 previousClickPoint = IntPoint();
93 previousClickTime = 0;
94 previousClickButton = 0;
97 int currentClickCountForGdkButtonEvent(GdkEventButton* buttonEvent)
99 GdkEvent* event = reinterpret_cast<GdkEvent*>(buttonEvent);
100 int doubleClickDistance = 250;
101 int doubleClickTime = 5;
102 g_object_get(gtk_settings_get_for_screen(gdk_event_get_screen(event)),
103 "gtk-double-click-distance", &doubleClickDistance, "gtk-double-click-time", &doubleClickTime, nullptr);
105 // GTK+ only counts up to triple clicks, but WebCore wants to know about
106 // quadruple clicks, quintuple clicks, ad infinitum. Here, we replicate the
107 // GDK logic for counting clicks.
108 guint32 eventTime = gdk_event_get_time(event);
110 // Real events always have a non-zero time, but events synthesized
111 // by the WTR do not and we must calculate a time manually. This time
112 // is not calculated in the WTR, because GTK+ does not work well with
113 // anything other than GDK_CURRENT_TIME on synthesized events.
115 g_get_current_time(&timeValue);
116 eventTime = (timeValue.tv_sec * 1000) + (timeValue.tv_usec / 1000);
119 if ((event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
120 || ((std::abs(buttonEvent->x - previousClickPoint.x()) < doubleClickDistance)
121 && (std::abs(buttonEvent->y - previousClickPoint.y()) < doubleClickDistance)
122 && (eventTime - previousClickTime < static_cast<unsigned>(doubleClickTime))
123 && (buttonEvent->button == previousClickButton)))
126 currentClickCount = 1;
129 gdk_event_get_coords(event, &x, &y);
130 previousClickPoint = IntPoint(x, y);
131 previousClickButton = buttonEvent->button;
132 previousClickTime = eventTime;
134 return currentClickCount;
138 int currentClickCount;
139 IntPoint previousClickPoint;
140 unsigned previousClickButton;
141 int previousClickTime;
144 typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
145 typedef HashMap<uint32_t, GUniquePtr<GdkEvent>> TouchEventsMap;
147 struct _WebKitWebViewBasePrivate {
148 _WebKitWebViewBasePrivate()
149 : updateViewStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateViewStateTimerFired)
153 void updateViewStateTimerFired()
157 pageProxy->viewStateDidChange(viewStateFlagsToUpdate);
158 viewStateFlagsToUpdate = ViewState::NoFlags;
161 WebKitWebViewChildrenMap children;
162 std::unique_ptr<PageClientImpl> pageClient;
163 RefPtr<WebPageProxy> pageProxy;
164 bool shouldForwardNextKeyEvent;
165 bool shouldForwardNextWheelEvent;
166 ClickCounter clickCounter;
169 GRefPtr<AtkObject> accessible;
170 GtkWidget* authenticationDialog;
171 GtkWidget* inspectorView;
172 AttachmentSide inspectorAttachmentSide;
173 unsigned inspectorViewSize;
174 GUniquePtr<GdkEvent> contextMenuEvent;
175 WebContextMenuProxyGtk* activeContextMenuProxy;
176 InputMethodFilter inputMethodFilter;
177 KeyBindingTranslator keyBindingTranslator;
178 TouchEventsMap touchEvents;
179 IntSize contentsSize;
181 GtkWindow* toplevelOnScreenWindow;
182 unsigned long toplevelFocusInEventID;
183 unsigned long toplevelFocusOutEventID;
184 unsigned long toplevelWindowStateEventID;
185 unsigned long toplevelWindowRealizedID;
188 ViewState::Flags viewState;
189 ViewState::Flags viewStateFlagsToUpdate;
190 RunLoop::Timer<WebKitWebViewBasePrivate> updateViewStateTimer;
192 WebKitWebViewBaseDownloadRequestHandler downloadHandler;
194 #if ENABLE(FULLSCREEN_API)
195 bool fullScreenModeActive;
196 WebFullScreenClientGtk fullScreenClient;
197 GRefPtr<GDBusProxy> screenSaverProxy;
198 GRefPtr<GCancellable> screenSaverInhibitCancellable;
199 unsigned screenSaverCookie;
202 std::unique_ptr<AcceleratedBackingStore> acceleratedBackingStore;
204 #if ENABLE(DRAG_SUPPORT)
205 std::unique_ptr<DragAndDropHandler> dragAndDropHandler;
208 #if HAVE(GTK_GESTURES)
209 std::unique_ptr<GestureController> gestureController;
213 WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
215 static void webkitWebViewBaseScheduleUpdateViewState(WebKitWebViewBase* webViewBase, ViewState::Flags flagsToUpdate)
217 WebKitWebViewBasePrivate* priv = webViewBase->priv;
218 priv->viewStateFlagsToUpdate |= flagsToUpdate;
219 if (priv->updateViewStateTimer.isActive())
222 priv->updateViewStateTimer.startOneShot(0);
225 static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
227 // Spurious focus in events can occur when the window is hidden.
228 if (!gtk_widget_get_visible(widget))
231 WebKitWebViewBasePrivate* priv = webViewBase->priv;
232 if (priv->viewState & ViewState::WindowIsActive)
235 priv->viewState |= ViewState::WindowIsActive;
236 webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::WindowIsActive);
241 static gboolean toplevelWindowFocusOutEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
243 WebKitWebViewBasePrivate* priv = webViewBase->priv;
244 if (!(priv->viewState & ViewState::WindowIsActive))
247 priv->viewState &= ~ViewState::WindowIsActive;
248 webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::WindowIsActive);
253 static gboolean toplevelWindowStateEvent(GtkWidget*, GdkEventWindowState* event, WebKitWebViewBase* webViewBase)
255 WebKitWebViewBasePrivate* priv = webViewBase->priv;
256 if (!(event->changed_mask & GDK_WINDOW_STATE_ICONIFIED))
259 bool visible = !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED);
260 if ((visible && priv->viewState & ViewState::IsVisible) || (!visible && !(priv->viewState & ViewState::IsVisible)))
264 priv->viewState |= ViewState::IsVisible;
266 priv->viewState &= ~ViewState::IsVisible;
267 webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::IsVisible);
272 static void toplevelWindowRealized(WebKitWebViewBase* webViewBase)
274 gtk_widget_realize(GTK_WIDGET(webViewBase));
276 WebKitWebViewBasePrivate* priv = webViewBase->priv;
277 if (priv->toplevelWindowRealizedID) {
278 g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
279 priv->toplevelWindowRealizedID = 0;
283 static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window)
285 WebKitWebViewBasePrivate* priv = webViewBase->priv;
286 if (priv->toplevelOnScreenWindow == window)
289 if (priv->toplevelFocusInEventID) {
290 g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID);
291 priv->toplevelFocusInEventID = 0;
293 if (priv->toplevelFocusOutEventID) {
294 g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID);
295 priv->toplevelFocusOutEventID = 0;
297 if (priv->toplevelWindowStateEventID) {
298 g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowStateEventID);
299 priv->toplevelWindowStateEventID = 0;
301 if (priv->toplevelWindowRealizedID) {
302 g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
303 priv->toplevelWindowRealizedID = 0;
306 priv->toplevelOnScreenWindow = window;
308 if (!priv->toplevelOnScreenWindow) {
309 ViewState::Flags flagsToUpdate = 0;
310 if (priv->viewState & ViewState::IsInWindow) {
311 priv->viewState &= ~ViewState::IsInWindow;
312 flagsToUpdate |= ViewState::IsInWindow;
314 if (priv->viewState & ViewState::WindowIsActive) {
315 priv->viewState &= ~ViewState::WindowIsActive;
316 flagsToUpdate |= ViewState::IsInWindow;
319 webkitWebViewBaseScheduleUpdateViewState(webViewBase, flagsToUpdate);
324 priv->toplevelFocusInEventID =
325 g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event",
326 G_CALLBACK(toplevelWindowFocusInEvent), webViewBase);
327 priv->toplevelFocusOutEventID =
328 g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event",
329 G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase);
330 priv->toplevelWindowStateEventID =
331 g_signal_connect(priv->toplevelOnScreenWindow, "window-state-event", G_CALLBACK(toplevelWindowStateEvent), webViewBase);
333 if (gtk_widget_get_realized(GTK_WIDGET(window)))
334 gtk_widget_realize(GTK_WIDGET(webViewBase));
336 priv->toplevelWindowRealizedID = g_signal_connect_swapped(window, "realize", G_CALLBACK(toplevelWindowRealized), webViewBase);
339 static void webkitWebViewBaseRealize(GtkWidget* widget)
341 WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
342 WebKitWebViewBasePrivate* priv = webView->priv;
344 gtk_widget_set_realized(widget, TRUE);
346 GtkAllocation allocation;
347 gtk_widget_get_allocation(widget, &allocation);
349 GdkWindowAttr attributes;
350 attributes.window_type = GDK_WINDOW_CHILD;
351 attributes.x = allocation.x;
352 attributes.y = allocation.y;
353 attributes.width = allocation.width;
354 attributes.height = allocation.height;
355 attributes.wclass = GDK_INPUT_OUTPUT;
356 attributes.visual = gtk_widget_get_visual(widget);
357 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
359 | GDK_BUTTON_PRESS_MASK
360 | GDK_BUTTON_RELEASE_MASK
362 | GDK_SMOOTH_SCROLL_MASK
363 | GDK_POINTER_MOTION_MASK
364 | GDK_ENTER_NOTIFY_MASK
365 | GDK_LEAVE_NOTIFY_MASK
367 | GDK_KEY_RELEASE_MASK
368 | GDK_BUTTON_MOTION_MASK
369 | GDK_BUTTON1_MOTION_MASK
370 | GDK_BUTTON2_MOTION_MASK
371 | GDK_BUTTON3_MOTION_MASK
374 gint attributesMask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
376 GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributesMask);
377 gtk_widget_set_window(widget, window);
378 gdk_window_set_user_data(window, widget);
380 #if USE(TEXTURE_MAPPER) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
381 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()))
382 drawingArea->setNativeSurfaceHandleForCompositing(GDK_WINDOW_XID(window));
385 gtk_style_context_set_background(gtk_widget_get_style_context(widget), window);
387 gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window);
390 static void webkitWebViewBaseUnrealize(GtkWidget* widget)
392 WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
393 #if USE(TEXTURE_MAPPER) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
394 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webView->priv->pageProxy->drawingArea()))
395 drawingArea->destroyNativeSurfaceHandleForCompositing();
397 gtk_im_context_set_client_window(webView->priv->inputMethodFilter.context(), nullptr);
399 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unrealize(widget);
402 static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget)
404 WebKitWebViewBasePrivate* priv = webViewBase->priv;
405 return widget == priv->inspectorView || widget == priv->authenticationDialog;
408 static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* widget)
410 WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
411 WebKitWebViewBasePrivate* priv = webView->priv;
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);
421 gtk_widget_set_parent(widget, GTK_WIDGET(container));
424 void webkitWebViewBaseAddAuthenticationDialog(WebKitWebViewBase* webViewBase, GtkWidget* dialog)
426 WebKitWebViewBasePrivate* priv = webViewBase->priv;
427 priv->authenticationDialog = dialog;
428 gtk_container_add(GTK_CONTAINER(webViewBase), dialog);
429 gtk_widget_show(dialog);
431 // We need to draw the shadow over the widget.
432 gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
435 void webkitWebViewBaseAddWebInspector(WebKitWebViewBase* webViewBase, GtkWidget* inspector, AttachmentSide attachmentSide)
437 if (webViewBase->priv->inspectorView == inspector && webViewBase->priv->inspectorAttachmentSide == attachmentSide)
440 webViewBase->priv->inspectorAttachmentSide = attachmentSide;
442 if (webViewBase->priv->inspectorView == inspector) {
443 gtk_widget_queue_resize(GTK_WIDGET(webViewBase));
447 webViewBase->priv->inspectorView = inspector;
448 gtk_container_add(GTK_CONTAINER(webViewBase), inspector);
451 static void webkitWebViewBaseContainerRemove(GtkContainer* container, GtkWidget* widget)
453 WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
454 WebKitWebViewBasePrivate* priv = webView->priv;
455 GtkWidget* widgetContainer = GTK_WIDGET(container);
457 gboolean wasVisible = gtk_widget_get_visible(widget);
458 gtk_widget_unparent(widget);
460 if (priv->inspectorView == widget) {
461 priv->inspectorView = 0;
462 priv->inspectorViewSize = 0;
463 } else if (priv->authenticationDialog == widget) {
464 priv->authenticationDialog = 0;
466 ASSERT(priv->children.contains(widget));
467 priv->children.remove(widget);
469 if (wasVisible && gtk_widget_get_visible(widgetContainer))
470 gtk_widget_queue_resize(widgetContainer);
473 static void webkitWebViewBaseContainerForall(GtkContainer* container, gboolean includeInternals, GtkCallback callback, gpointer callbackData)
475 WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
476 WebKitWebViewBasePrivate* priv = webView->priv;
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);
485 if (includeInternals && priv->inspectorView)
486 (*callback)(priv->inspectorView, callbackData);
488 if (includeInternals && priv->authenticationDialog)
489 (*callback)(priv->authenticationDialog, callbackData);
492 void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* child, const IntRect& childRect)
494 const IntRect& geometry = webView->priv->children.get(child);
495 if (geometry == childRect)
498 webView->priv->children.set(child, childRect);
499 gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
502 static void webkitWebViewBaseDispose(GObject* gobject)
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);
512 static void webkitWebViewBaseConstructed(GObject* object)
514 G_OBJECT_CLASS(webkit_web_view_base_parent_class)->constructed(object);
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());
522 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv;
523 priv->pageClient = std::make_unique<PageClientImpl>(viewWidget);
524 priv->authenticationDialog = 0;
527 static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr)
529 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
530 DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webViewBase->priv->pageProxy->drawingArea());
534 GdkRectangle clipRect;
535 if (!gdk_cairo_get_clip_rectangle(cr, &clipRect))
538 if (webViewBase->priv->acceleratedBackingStore && drawingArea->isInAcceleratedCompositingMode())
539 webViewBase->priv->acceleratedBackingStore->paint(cr, clipRect);
541 WebCore::Region unpaintedRegion; // This is simply unused.
542 drawingArea->paint(cr, clipRect, unpaintedRegion);
545 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
550 static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData)
552 if (!gtk_widget_get_visible(child))
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())
561 GtkAllocation childAllocation = geometry;
562 gtk_widget_size_allocate(child, &childAllocation);
563 priv->children.set(child, IntRect());
566 static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation)
568 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation);
570 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
571 gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase);
573 IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height);
574 WebKitWebViewBasePrivate* priv = webViewBase->priv;
575 if (priv->inspectorView) {
576 GtkAllocation childAllocation = viewRect;
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));
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));
592 gtk_widget_size_allocate(priv->inspectorView, &childAllocation);
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);
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);
606 if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()))
607 drawingArea->setSize(viewRect.size(), IntSize(), IntSize());
610 static void webkitWebViewBaseGetPreferredWidth(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
612 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
614 *naturalSize = priv->contentsSize.width();
617 static void webkitWebViewBaseGetPreferredHeight(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
619 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
621 *naturalSize = priv->contentsSize.height();
624 static void webkitWebViewBaseMap(GtkWidget* widget)
626 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->map(widget);
628 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
629 WebKitWebViewBasePrivate* priv = webViewBase->priv;
630 ViewState::Flags flagsToUpdate = 0;
631 if (!(priv->viewState & ViewState::IsVisible))
632 flagsToUpdate |= ViewState::IsVisible;
633 if (priv->toplevelOnScreenWindow) {
634 if (!(priv->viewState & ViewState::IsInWindow))
635 flagsToUpdate |= ViewState::IsInWindow;
636 if (gtk_window_is_active(GTK_WINDOW(priv->toplevelOnScreenWindow)) && !(priv->viewState & ViewState::WindowIsActive))
637 flagsToUpdate |= ViewState::WindowIsActive;
642 priv->viewState |= flagsToUpdate;
643 webkitWebViewBaseScheduleUpdateViewState(webViewBase, flagsToUpdate);
646 static void webkitWebViewBaseUnmap(GtkWidget* widget)
648 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget);
650 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
651 WebKitWebViewBasePrivate* priv = webViewBase->priv;
652 if (!(priv->viewState & ViewState::IsVisible))
655 priv->viewState &= ~ViewState::IsVisible;
656 webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::IsVisible);
659 static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event)
661 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
662 webkitWebViewBaseSetFocus(webViewBase, true);
663 webViewBase->priv->inputMethodFilter.notifyFocusedIn();
665 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
668 static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* event)
670 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
671 webkitWebViewBaseSetFocus(webViewBase, false);
672 webViewBase->priv->inputMethodFilter.notifyFocusedOut();
674 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
677 static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* keyEvent)
679 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
680 WebKitWebViewBasePrivate* priv = webViewBase->priv;
682 if (priv->authenticationDialog)
683 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
685 #if ENABLE(FULLSCREEN_API)
686 if (priv->fullScreenModeActive) {
687 switch (keyEvent->keyval) {
691 priv->pageProxy->fullScreenManager()->requestExitFullScreen();
699 // Since WebProcess key event handling is not synchronous, handle the event in two passes.
700 // When WebProcess processes the input event, it will call PageClientImpl::doneWithKeyEvent
701 // with event handled status which determines whether to pass the input event to parent or not
702 // using gtk_main_do_event().
703 if (priv->shouldForwardNextKeyEvent) {
704 priv->shouldForwardNextKeyEvent = FALSE;
705 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
708 // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
709 GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
710 priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
711 priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked,
712 !compositionResults.compositionUpdated() ? priv->keyBindingTranslator.commandsForKeyEvent(&event->key) : Vector<String>()));
718 static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* keyEvent)
720 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
721 WebKitWebViewBasePrivate* priv = webViewBase->priv;
723 if (priv->shouldForwardNextKeyEvent) {
724 priv->shouldForwardNextKeyEvent = FALSE;
725 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, keyEvent);
728 // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
729 GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
730 priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
731 priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked, { }));
737 static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventButton* buttonEvent)
739 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
740 WebKitWebViewBasePrivate* priv = webViewBase->priv;
742 if (priv->authenticationDialog)
745 gtk_widget_grab_focus(widget);
747 priv->inputMethodFilter.notifyMouseButtonPress();
749 // For double and triple clicks GDK sends both a normal button press event
750 // and a specific type (like GDK_2BUTTON_PRESS). If we detect a special press
751 // coming up, ignore this event as it certainly generated the double or triple
752 // click. The consequence of not eating this event is two DOM button press events
754 GUniquePtr<GdkEvent> nextEvent(gdk_event_peek());
755 if (nextEvent && (nextEvent->any.type == GDK_2BUTTON_PRESS || nextEvent->any.type == GDK_3BUTTON_PRESS))
758 // If it's a right click event save it as a possible context menu event.
759 if (buttonEvent->button == 3)
760 priv->contextMenuEvent.reset(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent)));
762 priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent),
763 priv->clickCounter.currentClickCountForGdkButtonEvent(buttonEvent)));
767 static gboolean webkitWebViewBaseButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event)
769 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
770 WebKitWebViewBasePrivate* priv = webViewBase->priv;
772 if (priv->authenticationDialog)
775 gtk_widget_grab_focus(widget);
776 priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
781 static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* event)
783 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
784 WebKitWebViewBasePrivate* priv = webViewBase->priv;
786 if (std::exchange(priv->shouldForwardNextWheelEvent, false))
789 if (priv->authenticationDialog)
792 priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(reinterpret_cast<GdkEvent*>(event)));
797 static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event)
799 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
800 WebKitWebViewBasePrivate* priv = webViewBase->priv;
802 if (priv->authenticationDialog) {
803 auto* widgetClass = GTK_WIDGET_CLASS(webkit_web_view_base_parent_class);
804 return widgetClass->motion_notify_event ? widgetClass->motion_notify_event(widget, event) : FALSE;
807 priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
812 static gboolean webkitWebViewBaseCrossingNotifyEvent(GtkWidget* widget, GdkEventCrossing* crosssingEvent)
814 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
815 WebKitWebViewBasePrivate* priv = webViewBase->priv;
817 if (priv->authenticationDialog)
820 // In the case of crossing events, it's very important the actual coordinates the WebProcess receives, because once the mouse leaves
821 // 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
822 // event are not accurate, the WebProcess might not know the mouse left the view. This can happen because of double to integer conversion,
823 // 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
824 // because those coordinates are inside the web view.
825 GtkAllocation allocation;
826 gtk_widget_get_allocation(widget, &allocation);
827 double width = allocation.width;
828 double height = allocation.height;
829 double x = crosssingEvent->x;
830 double y = crosssingEvent->y;
833 else if (x >= width && x < width + 1)
837 else if (y >= height && y < height + 1)
840 GdkEvent* event = reinterpret_cast<GdkEvent*>(crosssingEvent);
841 GUniquePtr<GdkEvent> copiedEvent;
842 if (x != crosssingEvent->x || y != crosssingEvent->y) {
843 copiedEvent.reset(gdk_event_copy(event));
844 copiedEvent->crossing.x = x;
845 copiedEvent->crossing.y = y;
848 priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(copiedEvent ? copiedEvent.get() : event, 0 /* currentClickCount */));
853 #if ENABLE(TOUCH_EVENTS)
854 static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPoints, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state)
857 gdk_event_get_coords(event, &x, &y);
859 gdouble xRoot, yRoot;
860 gdk_event_get_root_coords(event, &xRoot, &yRoot);
862 uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event));
863 touchPoints.uncheckedAppend(WebPlatformTouchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y)));
866 static inline WebPlatformTouchPoint::TouchPointState touchPointStateForEvents(const GdkEvent* current, const GdkEvent* event)
868 if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event))
869 return WebPlatformTouchPoint::TouchStationary;
871 switch (current->type) {
872 case GDK_TOUCH_UPDATE:
873 return WebPlatformTouchPoint::TouchMoved;
874 case GDK_TOUCH_BEGIN:
875 return WebPlatformTouchPoint::TouchPressed;
877 return WebPlatformTouchPoint::TouchReleased;
879 return WebPlatformTouchPoint::TouchStationary;
883 static void webkitWebViewBaseGetTouchPointsForEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Vector<WebPlatformTouchPoint>& touchPoints)
885 WebKitWebViewBasePrivate* priv = webViewBase->priv;
886 touchPoints.reserveInitialCapacity(event->type == GDK_TOUCH_END ? priv->touchEvents.size() + 1 : priv->touchEvents.size());
888 for (const auto& it : priv->touchEvents)
889 appendTouchEvent(touchPoints, it.value.get(), touchPointStateForEvents(it.value.get(), event));
891 // Touch was already removed from the TouchEventsMap, add it here.
892 if (event->type == GDK_TOUCH_END)
893 appendTouchEvent(touchPoints, event, WebPlatformTouchPoint::TouchReleased);
896 static gboolean webkitWebViewBaseTouchEvent(GtkWidget* widget, GdkEventTouch* event)
898 WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
899 WebKitWebViewBasePrivate* priv = webViewBase->priv;
901 if (priv->authenticationDialog)
904 GdkEvent* touchEvent = reinterpret_cast<GdkEvent*>(event);
905 uint32_t sequence = GPOINTER_TO_UINT(gdk_event_get_event_sequence(touchEvent));
907 #if HAVE(GTK_GESTURES)
908 GestureController& gestureController = webkitWebViewBaseGestureController(webViewBase);
909 if (gestureController.isProcessingGestures()) {
910 // If we are already processing gestures is because the WebProcess didn't handle the
911 // BEGIN touch event, so pass subsequent events to the GestureController.
912 gestureController.handleEvent(touchEvent);
913 // Remove the gesture event sequence from the handled touch events
914 // list to avoid the gesure sequence and a touch sequence of same
916 priv->touchEvents.remove(sequence);
921 switch (touchEvent->type) {
922 case GDK_TOUCH_BEGIN: {
923 ASSERT(!priv->touchEvents.contains(sequence));
924 GUniquePtr<GdkEvent> event(gdk_event_copy(touchEvent));
925 priv->touchEvents.add(sequence, WTFMove(event));
928 case GDK_TOUCH_UPDATE: {
929 auto it = priv->touchEvents.find(sequence);
930 ASSERT(it != priv->touchEvents.end());
931 it->value.reset(gdk_event_copy(touchEvent));
935 ASSERT(priv->touchEvents.contains(sequence));
936 priv->touchEvents.remove(sequence);
942 Vector<WebPlatformTouchPoint> touchPoints;
943 webkitWebViewBaseGetTouchPointsForEvent(webViewBase, touchEvent, touchPoints);
944 priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), WTFMove(touchPoints)));
948 #endif // ENABLE(TOUCH_EVENTS)
950 #if HAVE(GTK_GESTURES)
951 GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webViewBase)
953 WebKitWebViewBasePrivate* priv = webViewBase->priv;
954 if (!priv->gestureController)
955 priv->gestureController = std::make_unique<GestureController>(*priv->pageProxy);
956 return *priv->gestureController;
960 static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip)
962 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
965 // TODO: https://bugs.webkit.org/show_bug.cgi?id=61732.
970 if (priv->tooltipText.length() <= 0)
973 if (!priv->tooltipArea.isEmpty()) {
974 GdkRectangle area = priv->tooltipArea;
975 gtk_tooltip_set_tip_area(tooltip, &area);
977 gtk_tooltip_set_tip_area(tooltip, 0);
978 gtk_tooltip_set_text(tooltip, priv->tooltipText.data());
983 #if ENABLE(DRAG_SUPPORT)
984 static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint /* time */)
986 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
987 ASSERT(priv->dragAndDropHandler);
988 priv->dragAndDropHandler->fillDragData(context, selectionData, info);
991 static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context)
993 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
994 ASSERT(priv->dragAndDropHandler);
995 priv->dragAndDropHandler->finishDrag(context);
998 static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint /* x */, gint /* y */, GtkSelectionData* selectionData, guint info, guint time)
1000 webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragEntered(context, selectionData, info, time);
1002 #endif // ENABLE(DRAG_SUPPORT)
1004 static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget)
1006 // If the socket has already been created and embedded a plug ID, return it.
1007 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1008 if (priv->accessible && atk_socket_is_occupied(ATK_SOCKET(priv->accessible.get())))
1009 return priv->accessible.get();
1011 // Create the accessible object and associate it to the widget.
1012 if (!priv->accessible) {
1013 priv->accessible = adoptGRef(ATK_OBJECT(webkitWebViewBaseAccessibleNew(widget)));
1015 // Set the parent not to break bottom-up navigation.
1016 GtkWidget* parentWidget = gtk_widget_get_parent(widget);
1017 AtkObject* axParent = parentWidget ? gtk_widget_get_accessible(parentWidget) : 0;
1019 atk_object_set_parent(priv->accessible.get(), axParent);
1022 // Try to embed the plug in the socket, if posssible.
1023 String plugID = priv->pageProxy->accessibilityPlugID();
1024 if (plugID.isNull())
1025 return priv->accessible.get();
1027 atk_socket_embed(ATK_SOCKET(priv->accessible.get()), const_cast<gchar*>(plugID.utf8().data()));
1029 return priv->accessible.get();
1032 #if ENABLE(DRAG_SUPPORT)
1033 static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1035 webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragMotion(context, IntPoint(x, y), time);
1039 static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint /* time */)
1041 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1042 ASSERT(priv->dragAndDropHandler);
1043 priv->dragAndDropHandler->dragLeave(context);
1046 static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1048 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1049 ASSERT(priv->dragAndDropHandler);
1050 return priv->dragAndDropHandler->drop(context, IntPoint(x, y), time);
1052 #endif // ENABLE(DRAG_SUPPORT)
1054 static void webkitWebViewBaseHierarchyChanged(GtkWidget* widget, GtkWidget* oldToplevel)
1056 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1057 if (widgetIsOnscreenToplevelWindow(oldToplevel) && GTK_WINDOW(oldToplevel) == priv->toplevelOnScreenWindow) {
1058 webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), nullptr);
1063 GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
1064 if (widgetIsOnscreenToplevelWindow(toplevel))
1065 webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), GTK_WINDOW(toplevel));
1069 static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction)
1071 // If the authentication dialog is active, we need to forward focus events there. This
1072 // ensures that you can tab between elements in the box.
1073 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1074 if (priv->authenticationDialog) {
1075 gboolean returnValue;
1076 g_signal_emit_by_name(priv->authenticationDialog, "focus", direction, &returnValue);
1080 return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus(widget, direction);
1083 static void webkitWebViewBaseDestroy(GtkWidget* widget)
1085 WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1086 if (priv->authenticationDialog)
1087 gtk_widget_destroy(priv->authenticationDialog);
1089 GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->destroy(widget);
1092 static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebViewBaseClass)
1094 GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass);
1095 widgetClass->realize = webkitWebViewBaseRealize;
1096 widgetClass->unrealize = webkitWebViewBaseUnrealize;
1097 widgetClass->draw = webkitWebViewBaseDraw;
1098 widgetClass->size_allocate = webkitWebViewBaseSizeAllocate;
1099 widgetClass->get_preferred_width = webkitWebViewBaseGetPreferredWidth;
1100 widgetClass->get_preferred_height = webkitWebViewBaseGetPreferredHeight;
1101 widgetClass->map = webkitWebViewBaseMap;
1102 widgetClass->unmap = webkitWebViewBaseUnmap;
1103 widgetClass->focus = webkitWebViewBaseFocus;
1104 widgetClass->focus_in_event = webkitWebViewBaseFocusInEvent;
1105 widgetClass->focus_out_event = webkitWebViewBaseFocusOutEvent;
1106 widgetClass->key_press_event = webkitWebViewBaseKeyPressEvent;
1107 widgetClass->key_release_event = webkitWebViewBaseKeyReleaseEvent;
1108 widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent;
1109 widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent;
1110 widgetClass->scroll_event = webkitWebViewBaseScrollEvent;
1111 widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent;
1112 widgetClass->enter_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1113 widgetClass->leave_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1114 #if ENABLE(TOUCH_EVENTS)
1115 widgetClass->touch_event = webkitWebViewBaseTouchEvent;
1117 widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip;
1118 #if ENABLE(DRAG_SUPPORT)
1119 widgetClass->drag_end = webkitWebViewBaseDragEnd;
1120 widgetClass->drag_data_get = webkitWebViewBaseDragDataGet;
1121 widgetClass->drag_motion = webkitWebViewBaseDragMotion;
1122 widgetClass->drag_leave = webkitWebViewBaseDragLeave;
1123 widgetClass->drag_drop = webkitWebViewBaseDragDrop;
1124 widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived;
1125 #endif // ENABLE(DRAG_SUPPORT)
1126 widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
1127 widgetClass->hierarchy_changed = webkitWebViewBaseHierarchyChanged;
1128 widgetClass->destroy = webkitWebViewBaseDestroy;
1130 GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass);
1131 gobjectClass->constructed = webkitWebViewBaseConstructed;
1132 gobjectClass->dispose = webkitWebViewBaseDispose;
1134 GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webkitWebViewBaseClass);
1135 containerClass->add = webkitWebViewBaseContainerAdd;
1136 containerClass->remove = webkitWebViewBaseContainerRemove;
1137 containerClass->forall = webkitWebViewBaseContainerForall;
1139 // Before creating a WebKitWebViewBasePriv we need to be sure that WebKit is started.
1140 // Usually starting a context triggers InitializeWebKit2, but in case
1141 // we create a view without asking before for a default_context we get a crash.
1142 WebKit::InitializeWebKit2();
1145 WebKitWebViewBase* webkitWebViewBaseCreate(const API::PageConfiguration& configuration)
1147 WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, nullptr));
1148 webkitWebViewBaseCreateWebPage(webkitWebViewBase, configuration.copy());
1149 return webkitWebViewBase;
1152 GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
1154 return webkitWebViewBase->priv->inputMethodFilter.context();
1157 WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
1159 return webkitWebViewBase->priv->pageProxy.get();
1162 #if HAVE(GTK_SCALE_FACTOR)
1163 static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase)
1165 webkitWebViewBase->priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1167 #endif // HAVE(GTK_SCALE_FACTOR)
1169 void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<API::PageConfiguration>&& configuration)
1171 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1172 WebProcessPool* processPool = configuration->processPool();
1173 priv->pageProxy = processPool->createWebPage(*priv->pageClient, WTFMove(configuration));
1174 priv->pageProxy->initializeWebPage();
1176 priv->acceleratedBackingStore = AcceleratedBackingStore::create(*priv->pageProxy);
1178 priv->inputMethodFilter.setPage(priv->pageProxy.get());
1180 #if HAVE(GTK_SCALE_FACTOR)
1181 // We attach this here, because changes in scale factor are passed directly to the page proxy.
1182 priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1183 g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr);
1187 void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
1189 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1190 if (tooltip && tooltip[0] != '\0') {
1191 priv->tooltipText = tooltip;
1192 gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), TRUE);
1194 priv->tooltipText = "";
1195 gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), FALSE);
1198 gtk_widget_trigger_tooltip_query(GTK_WIDGET(webViewBase));
1201 void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRect& tooltipArea)
1203 webViewBase->priv->tooltipArea = tooltipArea;
1206 #if ENABLE(DRAG_SUPPORT)
1207 DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBase* webViewBase)
1209 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1210 if (!priv->dragAndDropHandler)
1211 priv->dragAndDropHandler = std::make_unique<DragAndDropHandler>(*priv->pageProxy);
1212 return *priv->dragAndDropHandler;
1214 #endif // ENABLE(DRAG_SUPPORT)
1216 void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase)
1218 webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE;
1221 void webkitWebViewBaseForwardNextWheelEvent(WebKitWebViewBase* webkitWebViewBase)
1223 webkitWebViewBase->priv->shouldForwardNextWheelEvent = true;
1226 #if ENABLE(FULLSCREEN_API)
1227 static void screenSaverInhibitedCallback(GDBusProxy* screenSaverProxy, GAsyncResult* result, WebKitWebViewBase* webViewBase)
1229 GRefPtr<GVariant> returnValue = adoptGRef(g_dbus_proxy_call_finish(screenSaverProxy, result, nullptr));
1231 g_variant_get(returnValue.get(), "(u)", &webViewBase->priv->screenSaverCookie);
1232 webViewBase->priv->screenSaverInhibitCancellable = nullptr;
1235 static void webkitWebViewBaseSendInhibitMessageToScreenSaver(WebKitWebViewBase* webViewBase)
1237 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1238 ASSERT(priv->screenSaverProxy);
1239 priv->screenSaverCookie = 0;
1240 if (!priv->screenSaverInhibitCancellable)
1241 priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new());
1242 g_dbus_proxy_call(priv->screenSaverProxy.get(), "Inhibit", g_variant_new("(ss)", g_get_prgname(), _("Website running in fullscreen mode")),
1243 G_DBUS_CALL_FLAGS_NONE, -1, priv->screenSaverInhibitCancellable.get(), reinterpret_cast<GAsyncReadyCallback>(screenSaverInhibitedCallback), webViewBase);
1246 static void screenSaverProxyCreatedCallback(GObject*, GAsyncResult* result, WebKitWebViewBase* webViewBase)
1248 // WebKitWebViewBase cancels the proxy creation on dispose, which means this could be called
1249 // after the web view has been destroyed and g_dbus_proxy_new_for_bus_finish will return nullptr.
1250 // So, make sure we don't use the web view unless we have a valid proxy.
1251 // See https://bugs.webkit.org/show_bug.cgi?id=151653.
1252 GRefPtr<GDBusProxy> proxy = adoptGRef(g_dbus_proxy_new_for_bus_finish(result, nullptr));
1256 webViewBase->priv->screenSaverProxy = proxy;
1257 webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase);
1260 static void webkitWebViewBaseInhibitScreenSaver(WebKitWebViewBase* webViewBase)
1262 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1263 if (priv->screenSaverCookie) {
1264 // Already inhibited.
1268 if (priv->screenSaverProxy) {
1269 webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase);
1273 priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new());
1274 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),
1275 nullptr, "org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver", priv->screenSaverInhibitCancellable.get(),
1276 reinterpret_cast<GAsyncReadyCallback>(screenSaverProxyCreatedCallback), webViewBase);
1279 static void webkitWebViewBaseUninhibitScreenSaver(WebKitWebViewBase* webViewBase)
1281 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1282 if (!priv->screenSaverCookie) {
1283 // Not inhibited or it's being inhibited.
1284 g_cancellable_cancel(priv->screenSaverInhibitCancellable.get());
1288 // If we have a cookie we should have a proxy.
1289 ASSERT(priv->screenSaverProxy);
1290 g_dbus_proxy_call(priv->screenSaverProxy.get(), "UnInhibit", g_variant_new("(u)", priv->screenSaverCookie), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr);
1291 priv->screenSaverCookie = 0;
1295 void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase)
1297 #if ENABLE(FULLSCREEN_API)
1298 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1299 if (priv->fullScreenModeActive)
1302 if (!priv->fullScreenClient.willEnterFullScreen())
1305 WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1306 fullScreenManagerProxy->willEnterFullScreen();
1308 GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1309 if (gtk_widget_is_toplevel(topLevelWindow))
1310 gtk_window_fullscreen(GTK_WINDOW(topLevelWindow));
1311 fullScreenManagerProxy->didEnterFullScreen();
1312 priv->fullScreenModeActive = true;
1313 webkitWebViewBaseInhibitScreenSaver(webkitWebViewBase);
1317 void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase)
1319 #if ENABLE(FULLSCREEN_API)
1320 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1321 if (!priv->fullScreenModeActive)
1324 if (!priv->fullScreenClient.willExitFullScreen())
1327 WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1328 fullScreenManagerProxy->willExitFullScreen();
1330 GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1331 if (gtk_widget_is_toplevel(topLevelWindow))
1332 gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow));
1333 fullScreenManagerProxy->didExitFullScreen();
1334 priv->fullScreenModeActive = false;
1335 webkitWebViewBaseUninhibitScreenSaver(webkitWebViewBase);
1339 void webkitWebViewBaseInitializeFullScreenClient(WebKitWebViewBase* webkitWebViewBase, const WKFullScreenClientGtkBase* wkClient)
1341 webkitWebViewBase->priv->fullScreenClient.initialize(wkClient);
1344 void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase* webkitWebViewBase, unsigned size)
1346 if (webkitWebViewBase->priv->inspectorViewSize == size)
1348 webkitWebViewBase->priv->inspectorViewSize = size;
1349 if (webkitWebViewBase->priv->inspectorView)
1350 gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1353 static void activeContextMenuUnmapped(GtkMenu* menu, WebKitWebViewBase* webViewBase)
1355 if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkMenu() == menu)
1356 webViewBase->priv->activeContextMenuProxy = nullptr;
1359 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
1361 webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
1362 g_signal_connect_object(contextMenuProxy->gtkMenu(), "unmap", G_CALLBACK(activeContextMenuUnmapped), webkitWebViewBase, static_cast<GConnectFlags>(0));
1365 WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
1367 return webkitWebViewBase->priv->activeContextMenuProxy;
1370 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase)
1372 return webkitWebViewBase->priv->contextMenuEvent.release();
1375 void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
1377 WebKitWebViewBasePrivate* priv = webViewBase->priv;
1378 if ((focused && priv->viewState & ViewState::IsFocused) || (!focused && !(priv->viewState & ViewState::IsFocused)))
1381 ViewState::Flags flagsToUpdate = ViewState::IsFocused;
1383 priv->viewState |= ViewState::IsFocused;
1385 // If the view has received the focus and the window is not active
1386 // mark the current window as active now. This can happen if the
1387 // toplevel window is a GTK_WINDOW_POPUP and the focus has been
1388 // set programatically like WebKitTestRunner does, because POPUP
1389 // can't be focused.
1390 if (!(priv->viewState & ViewState::WindowIsActive)) {
1391 priv->viewState |= ViewState::WindowIsActive;
1392 flagsToUpdate |= ViewState::WindowIsActive;
1395 priv->viewState &= ~ViewState::IsFocused;
1397 webkitWebViewBaseScheduleUpdateViewState(webViewBase, flagsToUpdate);
1400 bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase)
1402 return webViewBase->priv->viewState & ViewState::WindowIsActive;
1405 bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase)
1407 return webViewBase->priv->viewState & ViewState::IsFocused;
1410 bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase)
1412 return webViewBase->priv->viewState & ViewState::IsVisible;
1415 bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
1417 return webViewBase->priv->viewState & ViewState::IsInWindow;
1420 void webkitWebViewBaseSetDownloadRequestHandler(WebKitWebViewBase* webViewBase, WebKitWebViewBaseDownloadRequestHandler downloadHandler)
1422 webViewBase->priv->downloadHandler = downloadHandler;
1425 void webkitWebViewBaseHandleDownloadRequest(WebKitWebViewBase* webViewBase, DownloadProxy* download)
1427 if (webViewBase->priv->downloadHandler)
1428 webViewBase->priv->downloadHandler(webViewBase, download);
1431 void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
1433 webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
1436 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
1438 const auto& editorState = webkitWebViewBase->priv->pageProxy->editorState();
1439 if (!editorState.isMissingPostLayoutData)
1440 webkitWebViewBase->priv->inputMethodFilter.setCursorRect(editorState.postLayoutData().caretRectAtStart);
1443 void webkitWebViewBaseSetContentsSize(WebKitWebViewBase* webkitWebViewBase, const IntSize& contentsSize)
1445 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1446 if (priv->contentsSize == contentsSize)
1448 priv->contentsSize = contentsSize;
1451 void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase)
1453 webkitWebViewBase->priv->clickCounter.reset();
1456 void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1458 if (webkitWebViewBase->priv->acceleratedBackingStore)
1459 webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1462 void webkitWebViewBaseUpdateAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1464 if (webkitWebViewBase->priv->acceleratedBackingStore)
1465 webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1468 void webkitWebViewBaseExitAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase)
1470 if (webkitWebViewBase->priv->acceleratedBackingStore)
1471 webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1474 void webkitWebViewBaseDidRelaunchWebProcess(WebKitWebViewBase* webkitWebViewBase)
1476 // Queue a resize to ensure the new DrawingAreaProxy is resized.
1477 gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1479 #if PLATFORM(X11) && USE(TEXTURE_MAPPER) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1480 if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1483 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1484 DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
1485 ASSERT(drawingArea);
1487 if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1490 uint64_t windowID = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(webkitWebViewBase)));
1491 drawingArea->setNativeSurfaceHandleForCompositing(windowID);
1493 UNUSED_PARAM(webkitWebViewBase);
1497 void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase)
1499 if (webkitWebViewBase->priv->acceleratedBackingStore)
1500 webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1501 #if PLATFORM(X11) && USE(TEXTURE_MAPPER) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1502 if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1505 if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1508 WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1509 DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
1510 ASSERT(drawingArea);
1511 drawingArea->destroyNativeSurfaceHandleForCompositing();