--- a/Source/WebKit/WPEPlatform/wpe/WPEView.h
+++ b/Source/WebKit/WPEPlatform/wpe/WPEView.h
@@ -109,6 +109,18 @@
 WPE_API gboolean              wpe_view_get_visible                  (WPEView            *view);
 WPE_API void                  wpe_view_set_visible                  (WPEView            *view,
                                                                      gboolean            visible);
+WPE_API gboolean              wpe_view_get_auto_resize_with_toplevel (WPEView            *view);
+WPE_API void                  wpe_view_set_auto_resize_with_toplevel (WPEView            *view,
+                                                                     gboolean            auto_resize);
+WPE_API void                  wpe_view_set_size                     (WPEView            *view,
+                                                                     int                 width,
+                                                                     int                 height);
+WPE_API void                  wpe_view_get_position_in_toplevel     (WPEView            *view,
+                                                                     int               *x,
+                                                                     int               *y);
+WPE_API void                  wpe_view_set_position_in_toplevel     (WPEView            *view,
+                                                                     int                 x,
+                                                                     int                 y);
 WPE_API gboolean              wpe_view_get_mapped                   (WPEView            *view);
 WPE_API void                  wpe_view_map                          (WPEView            *view);
 WPE_API void                  wpe_view_unmap                        (WPEView            *view);
--- a/Source/WebKit/WPEPlatform/wpe/WPEView.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/WPEView.cpp
@@ -65,6 +65,9 @@
     GRefPtr<WPEToplevel> toplevel;
     int width;
     int height;
+    int x { 0 };
+    int y { 0 };
+    bool autoResizeWithToplevel { true };
     gdouble scale { 1 };
     WPEToplevelState state;
     bool closed;
@@ -104,6 +107,9 @@
     PROP_TOPLEVEL,
     PROP_WIDTH,
     PROP_HEIGHT,
+    PROP_X,
+    PROP_Y,
+    PROP_AUTO_RESIZE_WITH_TOPLEVEL,
     PROP_SCALE,
     PROP_TOPLEVEL_STATE,
     PROP_SCREEN,
@@ -119,6 +125,7 @@
 enum {
     CLOSED,
     RESIZED,
+    POSITION_IN_TOPLEVEL_CHANGED,
     BUFFERS_CHANGED,
     BUFFER_RENDERED,
     BUFFER_RELEASED,
@@ -145,6 +152,15 @@
     case PROP_VISIBLE:
         wpe_view_set_visible(view, g_value_get_boolean(value));
         break;
+    case PROP_AUTO_RESIZE_WITH_TOPLEVEL:
+        wpe_view_set_auto_resize_with_toplevel(view, g_value_get_boolean(value));
+        break;
+    case PROP_X:
+        wpe_view_set_position_in_toplevel(view, g_value_get_int(value), view->priv->y);
+        break;
+    case PROP_Y:
+        wpe_view_set_position_in_toplevel(view, view->priv->x, g_value_get_int(value));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
     }
@@ -167,6 +183,15 @@
     case PROP_HEIGHT:
         g_value_set_int(value, wpe_view_get_height(view));
         break;
+    case PROP_X:
+        g_value_set_int(value, view->priv->x);
+        break;
+    case PROP_Y:
+        g_value_set_int(value, view->priv->y);
+        break;
+    case PROP_AUTO_RESIZE_WITH_TOPLEVEL:
+        g_value_set_boolean(value, wpe_view_get_auto_resize_with_toplevel(view));
+        break;
     case PROP_SCALE:
         g_value_set_double(value, wpe_view_get_scale(view));
         break;
@@ -266,6 +291,53 @@
             WEBKIT_PARAM_READABLE);
 
     /**
+     * WPEView:x:
+     *
+     * The view X position inside its toplevel, in logical coordinates.
+     * Only meaningful for toplevels that allow multiple views (see
+     * #WPEToplevel:max-views).
+     */
+    sObjProperties[PROP_X] =
+        g_param_spec_int(
+            "x",
+            nullptr, nullptr,
+            0, G_MAXINT, 0,
+            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE));
+
+    /**
+     * WPEView:y:
+     *
+     * The view Y position inside its toplevel, in logical coordinates.
+     * Only meaningful for toplevels that allow multiple views.
+     */
+    sObjProperties[PROP_Y] =
+        g_param_spec_int(
+            "y",
+            nullptr, nullptr,
+            0, G_MAXINT, 0,
+            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE));
+
+    /**
+     * WPEView:auto-resize-with-toplevel:
+     *
+     * Whether the view should automatically track its toplevel's size.
+     *
+     * When %TRUE (the default), the view is resized to match the toplevel
+     * size whenever the toplevel is resized. When %FALSE, the view keeps
+     * its current size and is responsible for handling layout itself; this
+     * is the mode used by multi-view-per-toplevel applications (e.g. a
+     * browser with a tab bar implemented as a separate WPEView).
+     *
+     * Calling wpe_view_set_size() implicitly sets this property to %FALSE.
+     */
+    sObjProperties[PROP_AUTO_RESIZE_WITH_TOPLEVEL] =
+        g_param_spec_boolean(
+            "auto-resize-with-toplevel",
+            nullptr, nullptr,
+            TRUE,
+            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE));
+
+    /**
      * WPEView:scale:
      *
      * The view scale.
@@ -385,6 +457,23 @@
         g_cclosure_marshal_generic,
         G_TYPE_NONE, 0);
 
+
+
+    /**
+     * WPEView::position-in-toplevel-changed:
+     * @view: a #WPEView
+     * @x: the new X position in toplevel coordinates
+     * @y: the new Y position in toplevel coordinates
+     *
+     * Emitted when @view's position inside its toplevel has changed.
+     */
+    signals[POSITION_IN_TOPLEVEL_CHANGED] = g_signal_new(
+        "position-in-toplevel-changed",
+        G_TYPE_FROM_CLASS(viewClass),
+        G_SIGNAL_RUN_LAST,
+        0, nullptr, nullptr,
+        g_cclosure_marshal_VOID__VOID,
+        G_TYPE_NONE, 0);
     /**
      * WPEView::buffers-changed:
      * @view: a #WPEView
@@ -514,6 +603,25 @@
     g_signal_emit(view, signals[TOPLEVEL_STATE_CHANGED], 0, previousState);
 }
 
+void wpeViewToplevelResized(WPEView* view, int toplevelWidth, int toplevelHeight)
+{
+    g_return_if_fail(WPE_IS_VIEW(view));
+
+    // Don't resize views here — that would override the application's
+    // explicit layout. Instead, the toplevel's "resized" signal (emitted by
+    // wpe_toplevel_resized) is what the application listens to and re-lays
+    // out views in response to.
+    //
+    // Legacy single-view-per-toplevel apps that rely on the view auto-
+    // filling the toplevel should pass max-views=1, in which case
+    // wpe_view_wayland_get_wl_surface() returns the toplevel surface and
+    // view size doesn't matter.
+    (void)view;
+    (void)toplevelWidth;
+    (void)toplevelHeight;
+}
+
+
 void wpeViewScaleChanged(WPEView* view, double scale)
 {
     if (view->priv->scale == scale)
@@ -1206,3 +1314,117 @@
 
     return nullptr;
 }
+
+
+/* --- Multi-view positioning API (added by multiview patch) --- */
+
+/**
+ * wpe_view_get_auto_resize_with_toplevel:
+ * @view: a #WPEView
+ *
+ * Get whether @view automatically tracks its toplevel's size.
+ *
+ * Returns: %TRUE if the view auto-resizes with its toplevel
+ */
+gboolean wpe_view_get_auto_resize_with_toplevel(WPEView* view)
+{
+    g_return_val_if_fail(WPE_IS_VIEW(view), TRUE);
+    return view->priv->autoResizeWithToplevel;
+}
+
+/**
+ * wpe_view_set_auto_resize_with_toplevel:
+ * @view: a #WPEView
+ * @auto_resize: whether to track the toplevel size
+ *
+ * Enable or disable automatic tracking of the toplevel size.
+ * Disabling this is required when laying out multiple views in
+ * the same toplevel (e.g. a tab bar view plus a content view).
+ */
+void wpe_view_set_auto_resize_with_toplevel(WPEView* view, gboolean auto_resize)
+{
+    g_return_if_fail(WPE_IS_VIEW(view));
+    auto_resize = !!auto_resize;
+    if (view->priv->autoResizeWithToplevel == auto_resize)
+        return;
+    view->priv->autoResizeWithToplevel = auto_resize;
+    g_object_notify_by_pspec(G_OBJECT(view), sObjProperties[PROP_AUTO_RESIZE_WITH_TOPLEVEL]);
+}
+
+/**
+ * wpe_view_set_size:
+ * @view: a #WPEView
+ * @width: new view width in logical coordinates
+ * @height: new view height in logical coordinates
+ *
+ * Explicitly set the @view size. This implicitly disables
+ * #WPEView:auto-resize-with-toplevel (the view no longer tracks its
+ * toplevel's size); use wpe_view_set_auto_resize_with_toplevel() to
+ * re-enable it.
+ *
+ * This is the WPE-level equivalent of #GtkAllocation in WebKitGTK and is
+ * intended for multi-view-per-toplevel layouts where each view has its
+ * own size independent of the toplevel.
+ */
+void wpe_view_set_size(WPEView* view, int width, int height)
+{
+    g_return_if_fail(WPE_IS_VIEW(view));
+    g_return_if_fail(width >= 0 && height >= 0);
+
+    if (view->priv->autoResizeWithToplevel) {
+        view->priv->autoResizeWithToplevel = false;
+        g_object_notify_by_pspec(G_OBJECT(view), sObjProperties[PROP_AUTO_RESIZE_WITH_TOPLEVEL]);
+    }
+    wpe_view_resized(view, width, height);
+}
+
+/**
+ * wpe_view_get_position_in_toplevel:
+ * @view: a #WPEView
+ * @x: (out) (nullable): return location for X position, or %NULL
+ * @y: (out) (nullable): return location for Y position, or %NULL
+ *
+ * Get the @view's position inside its toplevel, in logical coordinates.
+ */
+void wpe_view_get_position_in_toplevel(WPEView* view, int* x, int* y)
+{
+    g_return_if_fail(WPE_IS_VIEW(view));
+    if (x)
+        *x = view->priv->x;
+    if (y)
+        *y = view->priv->y;
+}
+
+/**
+ * wpe_view_set_position_in_toplevel:
+ * @view: a #WPEView
+ * @x: new X position in toplevel logical coordinates
+ * @y: new Y position in toplevel logical coordinates
+ *
+ * Set the @view's position inside its toplevel. This is the WPE-level
+ * equivalent of being allocated a non-zero origin inside a parent
+ * GtkWidget container in WebKitGTK. Required when laying out multiple
+ * views in one toplevel (e.g. a 30px-tall tab bar view at (0,0) and a
+ * content view at (0,30)).
+ */
+void wpe_view_set_position_in_toplevel(WPEView* view, int x, int y)
+{
+    g_return_if_fail(WPE_IS_VIEW(view));
+
+    auto* priv = view->priv;
+    if (priv->x == x && priv->y == y)
+        return;
+
+    g_object_freeze_notify(G_OBJECT(view));
+    if (priv->x != x) {
+        priv->x = x;
+        g_object_notify_by_pspec(G_OBJECT(view), sObjProperties[PROP_X]);
+    }
+    if (priv->y != y) {
+        priv->y = y;
+        g_object_notify_by_pspec(G_OBJECT(view), sObjProperties[PROP_Y]);
+    }
+    g_object_thaw_notify(G_OBJECT(view));
+
+    g_signal_emit(view, signals[POSITION_IN_TOPLEVEL_CHANGED], 0);
+}
--- a/Source/WebKit/WPEPlatform/wpe/WPEViewPrivate.h
+++ b/Source/WebKit/WPEPlatform/wpe/WPEViewPrivate.h
@@ -31,3 +31,4 @@
 void wpeViewScaleChanged(WPEView*, double);
 void wpeViewScreenChanged(WPEView*);
 void wpeViewPreferredBufferFormatsChanged(WPEView*);
+void wpeViewToplevelResized(WPEView*, int toplevelWidth, int toplevelHeight);
--- a/Source/WebKit/WPEPlatform/wpe/WPEToplevel.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/WPEToplevel.cpp
@@ -93,6 +93,14 @@
 
 static std::array<GParamSpec*, N_PROPERTIES> sObjProperties;
 
+enum {
+    RESIZED_SIGNAL,
+
+    LAST_SIGNAL
+};
+
+static std::array<unsigned, LAST_SIGNAL> signals;
+
 static void wpeToplevelConstructed(GObject* object)
 {
     G_OBJECT_CLASS(wpe_toplevel_parent_class)->constructed(object);
@@ -195,6 +203,24 @@
             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
     g_object_class_install_properties(objectClass, N_PROPERTIES, sObjProperties.data());
+
+    /**
+     * WPEToplevel::resized:
+     * @toplevel: a #WPEToplevel
+     * @width: the new toplevel width
+     * @height: the new toplevel height
+     *
+     * Emitted when the @toplevel has been resized. Applications with multi-
+     * view layouts should connect to this signal and call wpe_view_set_size()
+     * on each of their views to re-layout them inside the new toplevel size.
+     */
+    signals[RESIZED_SIGNAL] = g_signal_new(
+        "resized",
+        G_TYPE_FROM_CLASS(toplevelClass),
+        G_SIGNAL_RUN_LAST,
+        0, nullptr, nullptr,
+        g_cclosure_marshal_VOID__VOID,
+        G_TYPE_NONE, 0);
 }
 
 void wpeToplevelAddView(WPEToplevel* toplevel, WPEView* view)
@@ -408,8 +434,11 @@
     g_return_if_fail(WPE_IS_TOPLEVEL(toplevel));
 
     auto* priv = toplevel->priv;
+    bool changed = (priv->width != width || priv->height != height);
     priv->width = width;
     priv->height = height;
+    if (changed)
+        g_signal_emit(toplevel, signals[RESIZED_SIGNAL], 0);
 }
 
 /**
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEInputMethodContextWaylandV3.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEInputMethodContextWaylandV3.cpp
@@ -563,6 +563,21 @@
     auto* display = wpe_input_method_context_get_display(context);
     auto* global = textInputV3GetGlobalByDisplay(WPE_DISPLAY_WAYLAND(display));
 
+    // Patched: add the view's position-in-toplevel offset to the cursor
+    // rect. For multi-view toplevels, the content view's subsurface is
+    // offset from (0,0) (e.g. below a chrome bar). The text-input
+    // protocol expects surface-local coordinates, but the compositor
+    // may not add the subsurface offset, causing the IME candidate
+    // window to appear at the wrong position.
+    auto* view = wpe_input_method_context_get_view(context);
+    if (view) {
+        int vx = 0;
+        int vy = 0;
+        wpe_view_get_position_in_toplevel(view, &vx, &vy);
+        x += vx;
+        y += vy;
+    }
+
     if (self->priv->cursorRect.x == x && self->priv->cursorRect.y == y && self->priv->cursorRect.width == width && self->priv->cursorRect.height == height)
         return;
 
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWayland.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWayland.cpp
@@ -87,6 +87,7 @@
 struct _WPEDisplayWaylandPrivate {
     struct wl_display* wlDisplay;
     struct wl_compositor* wlCompositor;
+    struct wl_subcompositor* wlSubcompositor;
     struct xdg_wm_base* xdgWMBase;
     struct wl_shm* wlSHM;
     struct wl_data_device_manager* wlDataDeviceManager;
@@ -256,6 +257,7 @@
     g_clear_pointer(&priv->wlSHM, wl_shm_destroy);
     g_clear_pointer(&priv->wlDataDeviceManager, wl_data_device_manager_destroy);
     g_clear_pointer(&priv->xdgWMBase, xdg_wm_base_destroy);
+    g_clear_pointer(&priv->wlSubcompositor, wl_subcompositor_destroy);
     g_clear_pointer(&priv->wlCompositor, wl_compositor_destroy);
     g_clear_pointer(&priv->wlDisplay, wl_display_disconnect);
 
@@ -273,6 +275,8 @@
 
         if (interfaceName == "wl_compositor"_s)
             priv->wlCompositor = static_cast<struct wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, std::min<uint32_t>(version, 5)));
+        else if (interfaceName == "wl_subcompositor"_s)
+            priv->wlSubcompositor = static_cast<struct wl_subcompositor*>(wl_registry_bind(registry, name, &wl_subcompositor_interface, 1));
         else if (interfaceName == "xdg_wm_base"_s)
             priv->xdgWMBase = static_cast<struct xdg_wm_base*>(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1));
         // FIXME: support zxdg_shell_v6?
@@ -597,6 +601,12 @@
     return display->priv->xdgWMBase;
 }
 
+struct wl_subcompositor* wpeDisplayWaylandGetSubcompositor(WPEDisplayWayland* display)
+{
+    return display->priv->wlSubcompositor;
+}
+
+
 WPE::WaylandSeat* wpeDisplayWaylandGetSeat(WPEDisplayWayland* display)
 {
     return display->priv->wlSeat.get();
@@ -764,6 +774,22 @@
 }
 
 /**
+ * wpe_display_wayland_get_wl_subcompositor: (skip)
+ * @display: a #WPEDisplayWayland
+ *
+ * Get the Wayland `wl_subcompositor` global bound by @display.
+ *
+ * Returns: (transfer none) (nullable): a Wayland `wl_subcompositor`, or %NULL
+ *   if the compositor did not advertise the subcompositor global.
+ */
+struct wl_subcompositor* wpe_display_wayland_get_wl_subcompositor(WPEDisplayWayland* display)
+{
+    g_return_val_if_fail(WPE_IS_DISPLAY_WAYLAND(display), nullptr);
+    return display->priv->wlSubcompositor;
+}
+
+
+/**
  * wpe_display_wayland_get_wl_shm: (skip)
  * @display: a #WPEDisplayWayland
  *
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWayland.h
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWayland.h
@@ -45,6 +45,7 @@
                                                                     GError           **error);
 WPE_API struct wl_display    *wpe_display_wayland_get_wl_display   (WPEDisplayWayland *display);
 WPE_API struct wl_compositor *wpe_display_wayland_get_wl_compositor(WPEDisplayWayland *display);
+WPE_API struct wl_subcompositor *wpe_display_wayland_get_wl_subcompositor(WPEDisplayWayland *display);
 WPE_API struct wl_shm        *wpe_display_wayland_get_wl_shm       (WPEDisplayWayland *display);
 
 G_END_DECLS
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWaylandPrivate.h
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEDisplayWaylandPrivate.h
@@ -35,6 +35,7 @@
 #endif
 
 struct xdg_wm_base* wpeDisplayWaylandGetXDGWMBase(WPEDisplayWayland*);
+struct wl_subcompositor* wpeDisplayWaylandGetSubcompositor(WPEDisplayWayland*);
 WPE::WaylandSeat* wpeDisplayWaylandGetSeat(WPEDisplayWayland*);
 WPE::WaylandCursor* wpeDisplayWaylandGetCursor(WPEDisplayWayland*);
 struct wl_data_device_manager* wpeDisplayWaylandGetDataDeviceManager(WPEDisplayWayland*);
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEToplevelWayland.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEToplevelWayland.cpp
@@ -30,6 +30,7 @@
 #include "WPEBufferFormats.h"
 #include "WPEDisplayWaylandPrivate.h"
 #include "WPEToplevelWaylandPrivate.h"
+#include "WPEViewPrivate.h"
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 #include "xdg-shell-client-protocol.h"
 #if USE(XDG_DECORATION_UNSTABLE_V1)
@@ -284,10 +285,14 @@
 static void wpeToplevelWaylandResized(WPEToplevel* toplevel, int width, int height)
 {
     wpe_toplevel_resized(toplevel, width, height);
+    // Notify every view of the new toplevel size. Each view decides whether
+    // to actually resize itself, based on its #WPEView:auto-resize-with-toplevel
+    // flag (default TRUE for backward-compat single-view apps; set to FALSE
+    // implicitly by wpe_view_set_size(), or explicitly by the application).
     wpe_toplevel_foreach_view(toplevel, [](WPEToplevel* toplevel, WPEView* view, gpointer) -> gboolean {
         int width, height;
         wpe_toplevel_get_size(toplevel, &width, &height);
-        wpe_view_resized(view, width, height);
+        wpeViewToplevelResized(view, width, height);
         return FALSE;
     }, nullptr);
 }
@@ -318,6 +323,14 @@
         wpe_toplevel_state_changed(toplevel, priv->pendingState.state);
         priv->pendingState = { };
         xdg_surface_ack_configure(surface, serial);
+        // For multi-view toplevels (max-views > 1), no view commits the
+        // toplevel's main surface (each view commits its own subsurface).
+        // We must commit here to apply the acked configure state, otherwise
+        // the compositor waits indefinitely and the window never appears.
+        // For single-view toplevels (max-views=1, the default), the view's
+        // render path commits the toplevel surface, so this commit is
+        // redundant but harmless.
+        wl_surface_commit(priv->wlSurface);
     },
 };
 
@@ -924,6 +937,16 @@
     return toplevel->priv->surfaceSync;
 }
 
+void wpeToplevelWaylandSetCurrentView(WPEToplevelWayland* toplevel, WPEView* view)
+{
+    auto* priv = toplevel->priv;
+    // Always update visibleView to the view currently under the pointer.
+    // This makes keyboard focus follow the pointer — when the user moves
+    // the mouse over the content view, keyboard events go there; when over
+    // the chrome view (URL bar), keyboard events go there instead.
+    priv->visibleView.reset(view);
+}
+
 /**
  * wpe_toplevel_wayland_get_wl_surface: (skip)
  * @toplevel: a #WPEToplevelWayland
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEToplevelWaylandPrivate.h
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEToplevelWaylandPrivate.h
@@ -38,3 +38,32 @@
 WPEView* wpeToplevelWaylandGetVisibleViewUnderTouch(WPEToplevelWayland*);
 void wpeToplevelWaylandViewVisibilityChanged(WPEToplevelWayland*, WPEView*);
 struct zwp_linux_surface_synchronization_v1* wpeToplevelWaylandGetSurfaceSync(WPEToplevelWayland*);
+
+/*
+ * Multi-view notes (added by multiview patch):
+ *
+ * - Each WPEViewWayland owns its own wl_surface (priv->wlSurface) and a
+ *   wl_subsurface (priv->wlSubsurface) parented to the toplevel's main
+ *   wl_surface. The view's wl_surface user_data points to the WPEView,
+ *   NOT to the WPEToplevel.
+ *
+ * - The toplevel's main wl_surface still has its user_data pointing to
+ *   the WPEToplevel, for the seat code's legacy single-view fallback
+ *   (used when a toplevel surface receives events directly).
+ *
+ * - Pointer/keyboard/touch events on a view's subsurface are dispatched
+ *   directly to that view by WPEWaylandSeat (no hit-testing required;
+ *   Wayland's own surface-based event routing does the right thing).
+ *
+ * - Keyboard focus is per-toplevel in Wayland, so keyboard enter events
+ *   arrive on the toplevel's main surface. The seat code uses
+ *   priv->visibleView to decide which view gets keyboard focus. With the
+ *   multiview patch, pointer enter updates visibleView to the view under
+ *   the pointer, so keyboard focus follows the pointer (matching GTK's
+ *   implicit focus model).
+ */
+
+// Set the current "active" view — the view that should receive keyboard
+// focus events. Called by the seat code on pointer enter to track which
+// view the user is interacting with.
+void wpeToplevelWaylandSetCurrentView(WPEToplevelWayland* toplevel, WPEView* view);
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEViewWayland.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEViewWayland.cpp
@@ -96,6 +96,25 @@
     GRefPtr<WPEBuffer> buffer;
     struct wl_callback* frameCallback;
 
+    // Per-view wl_surface and wl_subsurface. With the multiview patch each
+    // WPEViewWayland owns its own wl_surface, parented to the toplevel's
+    // main wl_surface via wl_subsurface. When the view is in single-view-
+    // per-toplevel mode (the legacy default, max-views=1) the subsurface is
+    // still created — it just happens to be the only one and fills the
+    // entire toplevel.
+    //
+    // The wl_surface user_data is set to the WPEView (NOT to the WPEToplevel,
+    // unlike the toplevel's main surface). This lets WPEWaylandSeat dispatch
+    // pointer/keyboard/touch events directly to the right view without
+    // hit-testing.
+    struct wl_surface* wlSurface { nullptr };
+    struct wl_subsurface* wlSubsurface { nullptr };
+    // Per-view explicit-sync object (analogous to the toplevel's surfaceSync).
+    struct zwp_linux_surface_synchronization_v1* surfaceSync { nullptr };
+
+    unsigned long toplevelChangedID;
+    unsigned long positionChangedID;
+
 #if USE(SYSPROF_CAPTURE)
     std::unique_ptr<PresentationFeedbackStatistics> presentationFeedbackStatistics;
 #endif
@@ -110,42 +129,83 @@
 };
 WEBKIT_DEFINE_FINAL_TYPE(WPEViewWayland, wpe_view_wayland, WPE_TYPE_VIEW, WPEView)
 
+static void wpeViewWaylandEnsureSubsurface(WPEView* view);
+static void wpeViewWaylandDestroySubsurface(WPEView* view);
+static void wpeViewWaylandUpdateOpaqueRegion(WPEView* view);
+
 static void wpeViewWaylandConstructed(GObject* object)
 {
     G_OBJECT_CLASS(wpe_view_wayland_parent_class)->constructed(object);
 
     auto* view = WPE_VIEW(object);
     auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+
+    // Create this view's own wl_surface up front. It will be parented to
+    // the toplevel's main wl_surface as a wl_subsurface when (and if) the
+    // view is assigned a toplevel. Until then the surface is detached.
+    auto* display = WPE_DISPLAY_WAYLAND(wpe_view_get_display(view));
+    auto* wlCompositor = wpe_display_wayland_get_wl_compositor(display);
+    priv->wlSurface = wl_compositor_create_surface(wlCompositor);
+    // Tag the surface's user_data with the view so WPEWaylandSeat can
+    // dispatch events directly to this view (no hit-testing needed).
+    wl_surface_set_user_data(priv->wlSurface, view);
+
+    // Per-view explicit sync, if the compositor supports it. This is the
+    // analogue of the toplevel's surfaceSync; without it the view's
+    // dmabuf acquire/release fences can't be expressed per-surface.
+    if (auto* explicitSync = wpeDisplayWaylandGetLinuxExplicitSync(display))
+        priv->surfaceSync = zwp_linux_explicit_synchronization_v1_get_synchronization(explicitSync, priv->wlSurface);
+
     // The web view default background color is opaque white, so set the whole view region as opaque initially.
     priv->opaqueRegion.append({ 0, 0, wpe_view_get_width(view), wpe_view_get_height(view) });
 
     priv->resizedID = g_signal_connect(view, "resized", G_CALLBACK(+[](WPEView* view, gpointer) {
         auto* priv = WPE_VIEW_WAYLAND(view)->priv;
         priv->opaqueRegion.clear();
-        priv->opaqueRegion.append({ 0, 0, wpe_view_get_width(view), wpe_view_get_height(view) });
-        if (auto* toplevel = wpe_view_get_toplevel(view))
-            wpeToplevelWaylandSetOpaqueRectangles(WPE_TOPLEVEL_WAYLAND(toplevel), priv->opaqueRegion.mutableSpan().data(), priv->opaqueRegion.size());
+        int w = wpe_view_get_width(view);
+        int h = wpe_view_get_height(view);
+        if (w > 0 && h > 0)
+            priv->opaqueRegion.append({ 0, 0, w, h });
+        wpeViewWaylandUpdateOpaqueRegion(view);
     }), nullptr);
 
-    g_signal_connect(view, "notify::toplevel", G_CALLBACK(+[](WPEView* view, GParamSpec*, gpointer) {
+    // When the view's toplevel changes: create/destroy the wl_subsurface
+    // that parents this view's wl_surface to the toplevel's main wl_surface.
+    priv->toplevelChangedID = g_signal_connect(view, "notify::toplevel", G_CALLBACK(+[](WPEView* view, GParamSpec*, gpointer) {
         auto* toplevel = wpe_view_get_toplevel(view);
         if (!toplevel) {
+            wpeViewWaylandDestroySubsurface(view);
             wpe_view_unmap(view);
             return;
         }
 
-        int width;
-        int height;
-        wpe_toplevel_get_size(toplevel, &width, &height);
-        if (width && height)
-            wpe_view_resized(view, width, height);
-
-        auto* priv = WPE_VIEW_WAYLAND(view)->priv;
-        wpeToplevelWaylandSetOpaqueRectangles(WPE_TOPLEVEL_WAYLAND(toplevel), !priv->opaqueRegion.isEmpty() ? priv->opaqueRegion.mutableSpan().data() : nullptr, priv->opaqueRegion.size());
+        // Inherit toplevel size only if we're still in auto-resize mode.
+        // (wpeViewToplevelResized already handles subsequent resizes; this
+        // handles the initial set_toplevel call.)
+        if (wpe_view_get_auto_resize_with_toplevel(view)) {
+            int width;
+            int height;
+            wpe_toplevel_get_size(toplevel, &width, &height);
+            if (width && height)
+                wpe_view_resized(view, width, height);
+        }
 
+        wpeViewWaylandEnsureSubsurface(view);
+        wpeViewWaylandUpdateOpaqueRegion(view);
         wpe_view_map(view);
     }), nullptr);
 
+    // React to position-in-toplevel changes: move the subsurface.
+    priv->positionChangedID = g_signal_connect(view, "position-in-toplevel-changed", G_CALLBACK(+[](WPEView* view, gpointer) {
+        auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+        if (priv->wlSubsurface) {
+            int x;
+            int y;
+            wpe_view_get_position_in_toplevel(view, &x, &y);
+            wl_subsurface_set_position(priv->wlSubsurface, x, y);
+        }
+    }), nullptr);
+
     g_signal_connect(view, "notify::screen", G_CALLBACK(+[](WPEView* view, GParamSpec*, gpointer) {
         if (wpe_view_get_screen(view))
             wpe_view_map(view);
@@ -159,9 +219,106 @@
             return;
 
         wpeToplevelWaylandViewVisibilityChanged(WPE_TOPLEVEL_WAYLAND(toplevel), view);
+
+        // Z-order based show/hide. Buffer stays attached, no white screen.
+        // The ThreadedCompositor resume() patch ensures rendering resumes
+        // when the view becomes visible again.
+        auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+        if (priv->wlSubsurface && priv->wlSurface) {
+            auto* toplevelSurface = wpe_toplevel_wayland_get_wl_surface(WPE_TOPLEVEL_WAYLAND(toplevel));
+            if (wpe_view_get_visible(view))
+                wl_subsurface_place_above(priv->wlSubsurface, toplevelSurface);
+            else
+                wl_subsurface_place_below(priv->wlSubsurface, toplevelSurface);
+            wl_surface_commit(toplevelSurface);
+        }
     }), nullptr);
 }
 
+// Create the wl_subsurface that parents this view's wl_surface to the
+// toplevel's main wl_surface. Idempotent: safe to call when the subsurface
+// already exists.
+static void wpeViewWaylandEnsureSubsurface(WPEView* view)
+{
+    auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+    if (priv->wlSubsurface)
+        return;
+
+    auto* toplevel = wpe_view_get_toplevel(view);
+    if (!toplevel)
+        return;
+
+    // Single-view-per-toplevel (max-views == 1, the default): DON'T create a
+    // subsurface. The view renders directly to the toplevel's wl_surface
+    // (see wpe_view_wayland_get_wl_surface). This preserves the original
+    // behavior and ensures the xdg_toplevel window maps correctly.
+    if (wpe_toplevel_get_max_views(toplevel) == 1)
+        return;
+
+    auto* display = WPE_DISPLAY_WAYLAND(wpe_view_get_display(view));
+    auto* subcompositor = wpeDisplayWaylandGetSubcompositor(display);
+    if (!subcompositor) {
+        g_warning("WPEViewWayland: compositor did not advertise wl_subcompositor; "
+                  "multi-view-per-toplevel will not work. Falling back to attaching "
+                  "the view's wl_surface as a standalone (unparented) surface.");
+        return;
+    }
+
+    auto* toplevelSurface = wpe_toplevel_wayland_get_wl_surface(WPE_TOPLEVEL_WAYLAND(toplevel));
+    if (!toplevelSurface)
+        return;
+
+    priv->wlSubsurface = wl_subcompositor_get_subsurface(subcompositor, priv->wlSurface, toplevelSurface);
+
+    // Apply current position.
+    int x, y;
+    wpe_view_get_position_in_toplevel(view, &x, &y);
+    wl_subsurface_set_position(priv->wlSubsurface, x, y);
+
+    // Place the subsurface above the toplevel's main surface (which has no
+    // buffer attached — it just hosts the xdg_toplevel role and the subsurfaces).
+    wl_subsurface_place_above(priv->wlSubsurface, toplevelSurface);
+
+    // Synchro mode: 'desynchronized' so the compositor doesn't wait for the
+    // parent surface to commit before applying our commits. This is what
+    // browsers want — view commits should land ASAP.
+    wl_subsurface_set_desync(priv->wlSubsurface);
+
+    // Commit the PARENT (toplevel) surface so the subsurface's position and
+    // stacking take effect. Even in desync mode, wl_subsurface_set_position()
+    // and wl_subsurface_place_above() are double-buffered on the parent — they
+    // only apply when the parent surface commits. Without this, the subsurface
+    // exists in the compositor's object graph but is never positioned/stacked,
+    // so nothing is visible.
+    wl_surface_commit(toplevelSurface);
+}
+
+static void wpeViewWaylandDestroySubsurface(WPEView* view)
+{
+    auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+    g_clear_pointer(&priv->wlSubsurface, wl_subsurface_destroy);
+}
+
+static void wpeViewWaylandUpdateOpaqueRegion(WPEView* view)
+{
+    auto* priv = WPE_VIEW_WAYLAND(view)->priv;
+    if (!priv->wlSurface)
+        return;
+
+    auto* display = WPE_DISPLAY_WAYLAND(wpe_view_get_display(view));
+    auto* wlCompositor = wpe_display_wayland_get_wl_compositor(display);
+
+    struct wl_region* region = nullptr;
+    if (!priv->opaqueRegion.isEmpty()) {
+        region = wl_compositor_create_region(wlCompositor);
+        for (const auto& rect : priv->opaqueRegion)
+            wl_region_add(region, rect.x, rect.y, rect.width, rect.height);
+    }
+    wl_surface_set_opaque_region(priv->wlSurface, region);
+    if (region)
+        wl_region_destroy(region);
+}
+
 static void wpeViewWaylandDispose(GObject* object)
 {
     auto* priv = WPE_VIEW_WAYLAND(object)->priv;
@@ -169,6 +326,12 @@
     g_clear_pointer(&priv->lockedPointer, zwp_locked_pointer_v1_destroy);
     g_clear_pointer(&priv->relativePointer, zwp_relative_pointer_v1_destroy);
 
+    // Tear down the per-view subsurface and surface. Order matters: the
+    // wl_subsurface must be destroyed before its child wl_surface.
+    g_clear_pointer(&priv->wlSubsurface, wl_subsurface_destroy);
+    g_clear_pointer(&priv->surfaceSync, zwp_linux_surface_synchronization_v1_destroy);
+    g_clear_pointer(&priv->wlSurface, wl_surface_destroy);
+
 #if USE(SYSPROF_CAPTURE)
     priv->presentationFeedbackStatistics = nullptr;
 #endif
@@ -573,20 +736,28 @@
     auto* priv = WPE_VIEW_WAYLAND(view)->priv;
     priv->buffer = buffer;
 
-    wpeToplevelWaylandUpdateOpaqueRegion(WPE_TOPLEVEL_WAYLAND(toplevel));
+    wpeViewWaylandUpdateOpaqueRegion(WPE_VIEW(view));
 
     auto* wlSurface = wpe_view_wayland_get_wl_surface(WPE_VIEW_WAYLAND(view));
     wl_surface_attach(wlSurface, wlBuffer, 0, 0);
 
     auto renderingFence = UnixFileDescriptor { wpe_buffer_take_rendering_fence(buffer), UnixFileDescriptor::Adopt };
     if (renderingFence) {
-        auto* surfaceSync = wpeToplevelWaylandGetSurfaceSync(WPE_TOPLEVEL_WAYLAND(wpe_view_get_toplevel(view)));
-        zwp_linux_surface_synchronization_v1_set_acquire_fence(surfaceSync, renderingFence.value());
-
-        auto* release = zwp_linux_surface_synchronization_v1_get_release(surfaceSync);
-        zwp_linux_buffer_release_v1_add_listener(release, &bufferReleaseListener, buffer);
-        auto* dmaBufBuffer = static_cast<DMABufBuffer*>(wpe_buffer_get_user_data(buffer));
-        dmaBufBuffer->setRelease(release);
+        // Use the per-view explicit-sync object (created in constructed()).
+        // Falls back to the toplevel's sync object for legacy compositors
+        // that didn't allow per-surface explicit sync — though in practice
+        // if explicit sync is advertised at all it works per-surface.
+        auto* surfaceSync = priv->surfaceSync
+            ? priv->surfaceSync
+            : wpeToplevelWaylandGetSurfaceSync(WPE_TOPLEVEL_WAYLAND(wpe_view_get_toplevel(view)));
+        if (surfaceSync) {
+            zwp_linux_surface_synchronization_v1_set_acquire_fence(surfaceSync, renderingFence.value());
+
+            auto* release = zwp_linux_surface_synchronization_v1_get_release(surfaceSync);
+            zwp_linux_buffer_release_v1_add_listener(release, &bufferReleaseListener, buffer);
+            auto* dmaBufBuffer = static_cast<DMABufBuffer*>(wpe_buffer_get_user_data(buffer));
+            dmaBufBuffer->setRelease(release);
+        }
     }
 
     auto* display = WPE_DISPLAY_WAYLAND(wpe_view_get_display(view));
@@ -748,7 +919,20 @@
 {
     g_return_val_if_fail(WPE_IS_VIEW_WAYLAND(view), nullptr);
 
-    if (auto* toplevel = wpe_view_get_toplevel(WPE_VIEW(view)))
+    auto* toplevel = wpe_view_get_toplevel(WPE_VIEW(view));
+    if (!toplevel)
+        return nullptr;
+
+    // Single-view-per-toplevel (the default, max-views=1): render directly
+    // to the toplevel's wl_surface, exactly as the original code did. This
+    // is CRITICAL for the window to appear — xdg_toplevel only becomes
+    // "mapped" when a non-null buffer is committed on the toplevel surface.
+    // If we returned the view's own subsurface here, the toplevel would
+    // never get a buffer and the window would never map.
+    if (wpe_toplevel_get_max_views(toplevel) == 1)
         return wpe_toplevel_wayland_get_wl_surface(WPE_TOPLEVEL_WAYLAND(toplevel));
-    return nullptr;
+
+    // Multi-view (max-views > 1): each view owns its own wl_surface, parented
+    // to the toplevel's main surface via wl_subsurface. Return that.
+    return view->priv->wlSurface;
 }
--- a/Source/WebKit/WPEPlatform/wpe/wayland/WPEWaylandSeat.cpp
+++ b/Source/WebKit/WPEPlatform/wpe/wayland/WPEWaylandSeat.cpp
@@ -56,6 +56,52 @@
     wl_seat_destroy(m_seat);
 }
 
+
+// Look up the WPEView that owns the given wl_surface. With the multiview
+// patch, each WPEViewWayland's wl_surface has its user_data set to the view.
+// Falls back to the legacy path (surface is the toplevel's main surface,
+// user_data is the WPEToplevel, and we look up the toplevel's currently
+// mapped view via wpe_toplevel_foreach_view) when the surface is the
+// toplevel surface itself.
+//
+// NOTE: this is a free function, not a WaylandSeat member, so it must not
+// access seat->m_pointer / seat->m_keyboard (those are private). The caller
+// can do that itself if it needs seat-specific context.
+static GRefPtr<WPEView> wpeWaylandSeatLookupViewForSurface(struct wl_surface* surface, WPEToplevelWayland** outToplevel = nullptr)
+{
+    if (!surface)
+        return nullptr;
+    auto* userData = wl_surface_get_user_data(surface);
+    if (userData && WPE_IS_VIEW(userData)) {
+        auto* view = WPE_VIEW(userData);
+        if (outToplevel) {
+            auto* toplevel = wpe_view_get_toplevel(view);
+            *outToplevel = toplevel ? WPE_TOPLEVEL_WAYLAND(toplevel) : nullptr;
+        }
+        return view;
+    }
+    if (userData && WPE_IS_TOPLEVEL(userData)) {
+        auto* toplevel = WPE_TOPLEVEL_WAYLAND(userData);
+        if (outToplevel)
+            *outToplevel = toplevel;
+        // Legacy single-view fallback: pick the toplevel's first mapped view.
+        // (In the multi-view case this branch is essentially dead code —
+        // pointer/keyboard/touch events land on the view's subsurface, not
+        // the toplevel's main surface — but it's kept for safety, e.g. when
+        // the view hasn't yet created its subsurface.)
+        WPEView* view = nullptr;
+        wpe_toplevel_foreach_view(WPE_TOPLEVEL(toplevel), [](WPEToplevel*, WPEView* v, gpointer userData) -> gboolean {
+            if (wpe_view_get_mapped(v)) {
+                *static_cast<WPEView**>(userData) = v;
+                return TRUE;
+            }
+            return FALSE;
+        }, &view);
+        return view ? GRefPtr<WPEView>(view) : nullptr;
+    }
+    return nullptr;
+}
+
 const struct wl_pointer_listener WaylandSeat::s_pointerListener = {
     // enter
     [](void* data, struct wl_pointer*, uint32_t serial, struct wl_surface* surface, wl_fixed_t x, wl_fixed_t y)
@@ -63,14 +109,22 @@
         if (!surface)
             return;
 
-        auto* toplevel = wl_surface_get_user_data(surface);
-        if (!WPE_IS_TOPLEVEL(toplevel))
+        auto& seat = *static_cast<WaylandSeat*>(data);
+
+        // With the multiview patch, the surface's user_data may be either a
+        // WPEView (the common case — the surface is the view's own subsurface)
+        // or a WPEToplevel (legacy fallback — the surface is the toplevel's
+        // main surface, e.g. when no view has been added yet).
+        WPEToplevelWayland* toplevelWayland = nullptr;
+        GRefPtr<WPEView> view = wpeWaylandSeatLookupViewForSurface(surface, &toplevelWayland);
+        if (!toplevelWayland)
             return;
 
-        auto* toplevelWayland = WPE_TOPLEVEL_WAYLAND(toplevel);
         wpeToplevelWaylandSetHasPointer(toplevelWayland, true);
-
-        auto& seat = *static_cast<WaylandSeat*>(data);
+        // Track which view the pointer entered — this becomes the keyboard
+        // focus target when keyboard enter arrives (Wayland keyboard focus
+        // is per-toplevel, so we need to route it to the right view ourselves).
+        wpeToplevelWaylandSetCurrentView(toplevelWayland, view.get());
         seat.m_pointer.toplevel.reset(toplevelWayland);
         seat.m_pointer.x = wl_fixed_to_double(x);
         seat.m_pointer.y = wl_fixed_to_double(y);
@@ -80,7 +134,7 @@
 
         seat.updateCursor();
 
-        if (GRefPtr<WPEView> view = wpeToplevelWaylandGetVisibleViewUnderPointer(seat.m_pointer.toplevel.get()))
+        if (view)
             seat.emitPointerEnter(view.get());
     },
     // leave
@@ -307,19 +361,18 @@
         if (!surface)
             return;
 
-        auto* toplevel = wl_surface_get_user_data(surface);
-        if (!WPE_IS_TOPLEVEL(toplevel))
+        auto& seat = *static_cast<WaylandSeat*>(data);
+        WPEToplevelWayland* toplevelWayland = nullptr;
+        GRefPtr<WPEView> view = wpeWaylandSeatLookupViewForSurface(surface, &toplevelWayland);
+        if (!toplevelWayland)
             return;
 
-        auto* toplevelWayland = WPE_TOPLEVEL_WAYLAND(toplevel);
         wpeToplevelWaylandSetIsFocused(toplevelWayland, true);
-
-        auto& seat = *static_cast<WaylandSeat*>(data);
         seat.m_keyboard.toplevel.reset(toplevelWayland);
         seat.m_keyboard.repeat.key = 0;
         seat.m_keyboard.serial = serial;
 
-        if (GRefPtr<WPEView> view = wpeToplevelWaylandGetVisibleFocusedView(toplevelWayland))
+        if (view)
             wpe_view_focus_in(view.get());
     },
     // leave
@@ -395,18 +448,18 @@
         if (!surface)
             return;
 
-        auto* toplevel = wl_surface_get_user_data(surface);
-        if (!WPE_IS_TOPLEVEL(toplevel))
+        auto& seat = *static_cast<WaylandSeat*>(data);
+        WPEToplevelWayland* toplevelWayland = nullptr;
+        GRefPtr<WPEView> view = wpeWaylandSeatLookupViewForSurface(surface, &toplevelWayland);
+        if (!toplevelWayland)
             return;
 
-        auto& seat = *static_cast<WaylandSeat*>(data);
-        seat.m_touch.toplevel.reset(WPE_TOPLEVEL_WAYLAND(toplevel));
+        seat.m_touch.toplevel.reset(toplevelWayland);
 
         auto addResult = seat.m_touch.points.add(id, std::pair<double, double>(wl_fixed_to_double(x), wl_fixed_to_double(y)));
         if (seat.m_touch.points.size() == 1)
             wpeToplevelWaylandSetIsUnderTouch(seat.m_touch.toplevel.get(), true);
 
-        GRefPtr<WPEView> view = wpeToplevelWaylandGetVisibleViewUnderTouch(seat.m_touch.toplevel.get());
         if (!view)
             return;
 
--- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp
+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/ThreadedCompositor.cpp
@@ -239,6 +239,12 @@
         return;
 
     Locker locker { m_state.lock };
+    // Patched: schedule a rendering update on resume so the compositor
+    // renders a new frame even if nothing changed since suspend.
+    // Without this, the compositor stays in Idle state and the view
+    // shows a blank page when switched to.
+    if (m_state.state == State::Idle)
+        m_state.state = State::Scheduled;
     if (m_state.state == State::Scheduled && !isOnlyRenderingUpdatePendingAndWaitingForTiles())
         startRenderTimer();
 }
--- a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp
+++ b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp
@@ -80,6 +80,10 @@
     g_signal_connect(m_wpeView.get(), "notify::mapped", G_CALLBACK(+[](WPEView* view, GParamSpec*, gpointer userData) {
         auto& webView = *reinterpret_cast<ViewPlatform*>(userData);
         webView.activityStateChanged(WebCore::ActivityState::IsVisible, wpe_view_get_mapped(view));
+        // No forceRepaint here — it causes crashes (ASSERT in FrameRenderer) when
+        // switching tabs quickly. Instead, the WPEPlatform patch's notify::visible
+        // handler uses subsurface z-order to show/hide views, which keeps buffers
+        // attached and avoids the blank-page issue entirely.
     }), this);
     g_signal_connect(m_wpeView.get(), "resized", G_CALLBACK(+[](WPEView* view, gpointer userData) {
         auto& webView = *reinterpret_cast<ViewPlatform*>(userData);
