Bug 1667851 [Wayland] Use map_event to create wl_subsurface of MozContainer when it's size is already allocated, r=jhorak

- Recently we use size allocation event to create wl_subsurface of MozContainer. Unfortunately size allocation event
  is not called when a window is opened second time, as its size is already set. Use map_event to create
  wl_subsurface in this case.

Depends on D104550

Differential Revision: https://phabricator.services.mozilla.com/D104551
This commit is contained in:
stransky
2021-02-09 19:41:10 +00:00
parent 00be9a0257
commit 01a743d096
4 changed files with 64 additions and 22 deletions

View File

@@ -29,7 +29,7 @@
* We need to wait until wl_surface of mContainer is created
* and then we create and attach our wl_subsurface to it.
*
* wl_subsurface creation has these steps:
* First wl_subsurface creation has these steps:
*
* 1) moz_container_wayland_size_allocate() handler is called when
* mContainer size/position is known.
@@ -41,6 +41,11 @@
* when wl_surface owned by mozContainer is ready.
* We call initial_draw_cbs() handler and we can create our wl_subsurface
* on top of wl_surface owned by mozContainer.
*
* When MozContainer hides/show again, moz_container_wayland_size_allocate()
* handler may not be called as MozContainer size is set. So after first
* show/hide sequence use moz_container_wayland_map_event() to create
* wl_subsurface of MozContainer.
*/
#include "MozContainer.h"
@@ -76,6 +81,8 @@ static void moz_container_wayland_destroy(GtkWidget* widget);
/* widget class methods */
static void moz_container_wayland_map(GtkWidget* widget);
static gboolean moz_container_wayland_map_event(GtkWidget* widget,
GdkEventAny* event);
static void moz_container_wayland_unmap(GtkWidget* widget);
static void moz_container_wayland_size_allocate(GtkWidget* widget,
GtkAllocation* allocation);
@@ -94,6 +101,22 @@ static nsWindow* moz_container_get_nsWindow(MozContainer* container) {
// Imlemented in MozContainer.cpp
void moz_container_realize(GtkWidget* widget);
// Invalidate gtk wl_surface to commit changes to wl_subsurface.
// wl_subsurface changes are effective when parent surface is commited.
static void moz_container_wayland_invalidate(MozContainer* container) {
LOGWAYLAND(("moz_container_wayland_invalidate [%p]\n", (void*)container));
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
if (!window) {
LOGWAYLAND((" Failed - missing GdkWindow!\n"));
return;
}
GdkRectangle rect = (GdkRectangle){0, 0, gdk_window_get_width(window),
gdk_window_get_height(window)};
gdk_window_invalidate_rect(window, &rect, true);
}
static void moz_container_wayland_move_locked(MozContainer* container, int dx,
int dy) {
LOGWAYLAND(
@@ -110,15 +133,6 @@ static void moz_container_wayland_move_locked(MozContainer* container, int dx,
wl_subsurface_set_position(wl_container->subsurface,
wl_container->subsurface_dx,
wl_container->subsurface_dy);
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
if (window) {
GdkRectangle rect = (GdkRectangle){0, 0, gdk_window_get_width(window),
gdk_window_get_height(window)};
// wl_subsurface_set_position is actually property of parent surface
// which is effective when parent surface is commited.
gdk_window_invalidate_rect(window, &rect, true);
}
}
// This is called from layout/compositor code only with
@@ -140,6 +154,7 @@ void moz_container_wayland_class_init(MozContainerClass* klass) {
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
widget_class->map = moz_container_wayland_map;
widget_class->map_event = moz_container_wayland_map_event;
widget_class->destroy = moz_container_wayland_destroy;
widget_class->unmap = moz_container_wayland_unmap;
widget_class->realize = moz_container_realize;
@@ -157,6 +172,7 @@ void moz_container_wayland_init(MozContainerWayland* container) {
container->surface_needs_clear = true;
container->subsurface_dx = 0;
container->subsurface_dy = 0;
container->before_first_size_alloc = true;
container->initial_draw_cbs.clear();
container->container_lock = new mozilla::Mutex("MozContainer lock");
}
@@ -212,6 +228,30 @@ static void moz_container_wayland_unmap_internal(MozContainer* container) {
LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container));
}
static gboolean moz_container_wayland_map_event(GtkWidget* widget,
GdkEventAny* event) {
MozContainerWayland* wl_container = &MOZ_CONTAINER(widget)->wl_container;
LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)MOZ_CONTAINER(widget)));
// Don't create wl_subsurface in map_event when it's already created or
// if we create it for the first time.
if (wl_container->ready_to_draw || wl_container->before_first_size_alloc) {
return FALSE;
}
MutexAutoLock lock(*wl_container->container_lock);
if (!wl_container->surface) {
if (!moz_container_wayland_surface_create_locked(MOZ_CONTAINER(widget))) {
return FALSE;
}
}
moz_container_wayland_set_scale_factor_locked(MOZ_CONTAINER(widget));
moz_container_wayland_set_opaque_region_locked(MOZ_CONTAINER(widget));
moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
return FALSE;
}
void moz_container_wayland_map(GtkWidget* widget) {
LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)widget));
@@ -264,18 +304,17 @@ void moz_container_wayland_size_allocate(GtkWidget* widget,
// We need to position our subsurface according to GdkWindow
// when offset changes (GdkWindow is maximized for instance).
// see gtk-clutter-embed.c for reference.
if (gfxPlatformGtk::GetPlatform()->IsWaylandDisplay()) {
MutexAutoLock lock(*container->wl_container.container_lock);
if (!container->wl_container.surface) {
if (!moz_container_wayland_surface_create_locked(container)) {
return;
}
MutexAutoLock lock(*container->wl_container.container_lock);
if (!container->wl_container.surface) {
if (!moz_container_wayland_surface_create_locked(container)) {
return;
}
moz_container_wayland_set_scale_factor_locked(container);
moz_container_wayland_set_opaque_region_locked(container);
moz_container_wayland_move_locked(container, allocation->x,
allocation->y);
}
moz_container_wayland_set_scale_factor_locked(container);
moz_container_wayland_set_opaque_region_locked(container);
moz_container_wayland_move_locked(container, allocation->x, allocation->y);
moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
container->wl_container.before_first_size_alloc = false;
}
}
@@ -398,7 +437,7 @@ static bool moz_container_wayland_surface_create_locked(
wl_surface_commit(wl_container->surface);
wl_display_flush(WaylandDisplayGet()->GetDisplay());
LOGWAYLAND((" created surface %p ID %p\n", (void*)wl_container->surface,
LOGWAYLAND((" created surface %p ID %d\n", (void*)wl_container->surface,
wl_proxy_get_id((struct wl_proxy*)wl_container->surface)));
return true;
}

View File

@@ -42,6 +42,7 @@ struct MozContainerWayland {
gboolean opaque_region_fullscreen;
gboolean surface_needs_clear;
gboolean ready_to_draw;
gboolean before_first_size_alloc;
std::vector<std::function<void(void)>> initial_draw_cbs;
// mozcontainer is used from Compositor and Rendering threads
// so we need to control access to mozcontainer where wayland internals

View File

@@ -1080,6 +1080,7 @@ void nsWindow::AddCSDDecorationSize(int* aWidth, int* aHeight) {
}
}
#ifdef MOZ_WAYLAND
bool nsWindow::GetCSDDecorationOffset(int* aDx, int* aDy) {
if (mSizeState == nsSizeMode_Normal &&
mCSDSupportLevel == GTK_DECORATION_CLIENT && mDrawInTitlebar) {
@@ -1091,6 +1092,7 @@ bool nsWindow::GetCSDDecorationOffset(int* aDx, int* aDy) {
return false;
}
}
#endif
void nsWindow::ApplySizeConstraints(void) {
if (mShell) {

View File

@@ -238,6 +238,7 @@ class nsWindow final : public nsBaseWidget {
void SetProgress(unsigned long progressPercent);
#ifdef MOZ_WAYLAND
bool GetCSDDecorationOffset(int* aDx, int* aDy);
void SetEGLNativeWindowSize(const LayoutDeviceIntSize& aEGLWindowSize);
static nsWindow* GetFocusedWindow();
#endif
@@ -264,7 +265,6 @@ class nsWindow final : public nsBaseWidget {
void UpdateClientOffsetFromFrameExtents();
void UpdateClientOffsetFromCSDWindow();
bool GetCSDDecorationOffset(int* aDx, int* aDy);
void DispatchContextMenuEventFromMouseEvent(uint16_t domButton,
GdkEventButton* aEvent);