Bug 1464823 - [Wayland] Don't paint until we have a visible wl_surface, r?jhorak
It's based on a solution by Takuro Ashie <ashie@clear-code.com>
MozReview-Commit-ID: FqcdUJQJLdl
--- a/widget/gtk/mozcontainer.cpp
+++ b/widget/gtk/mozcontainer.cpp
@@ -207,16 +207,17 @@ moz_container_init (MozContainer *contai
gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
#if defined(MOZ_WAYLAND)
{
container->subcompositor = nullptr;
container->surface = nullptr;
container->subsurface = nullptr;
container->eglwindow = nullptr;
+ container->committed = false;
GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay =
(wl_display *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
@@ -226,33 +227,44 @@ moz_container_init (MozContainer *contai
wl_display_dispatch(display);
wl_display_roundtrip(display);
}
}
#endif
}
#if defined(MOZ_WAYLAND)
+static void
+moz_container_after_paint(GdkFrameClock *clock, MozContainer *container)
+{
+ container->committed = true;
+ g_signal_handlers_disconnect_by_func(clock,
+ reinterpret_cast<gpointer>(moz_container_after_paint), container);
+}
+
/* We want to draw to GdkWindow owned by mContainer from Compositor thread but
* Gtk+ can be used in main thread only. So we create wayland wl_surface
* and attach it as an overlay to GdkWindow.
*
* see gtk_clutter_embed_ensure_subsurface() at gtk-clutter-embed.c
-* for reference.
+ * for reference.
*/
static gboolean
moz_container_map_surface(MozContainer *container)
{
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlCompositor =
(wl_compositor *(*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
static auto sGdkWaylandWindowGetWlSurface =
(wl_surface *(*)(GdkWindow *))
dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
+ static auto sGdkWindowGetFrameClock =
+ (GdkFrameClock *(*)(GdkWindow *))
+ dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
if (GDK_IS_X11_DISPLAY(display))
return false;
if (container->subsurface && container->surface)
return true;
@@ -267,16 +279,21 @@ moz_container_map_surface(MozContainer *
wl_surface* gtk_surface = sGdkWaylandWindowGetWlSurface(window);
if (!gtk_surface) {
// We requested the underlying wl_surface too early when container
// is not realized yet. We'll try again before first rendering
// to mContainer.
return false;
}
+ GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
+ g_signal_connect_after(clock, "after-paint",
+ G_CALLBACK(moz_container_after_paint),
+ container);
+
container->subsurface =
wl_subcompositor_get_subsurface (container->subcompositor,
container->surface,
gtk_surface);
gint x, y;
gdk_window_get_position(window, &x, &y);
wl_subsurface_set_position(container->subsurface, x, y);
wl_subsurface_set_desync(container->subsurface);
@@ -293,16 +310,17 @@ moz_container_map_surface(MozContainer *
}
static void
moz_container_unmap_surface(MozContainer *container)
{
g_clear_pointer(&container->eglwindow, wl_egl_window_destroy);
g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
g_clear_pointer(&container->surface, wl_surface_destroy);
+ container->committed = false;
}
#endif
void
moz_container_map (GtkWidget *widget)
{
MozContainer *container;
@@ -564,17 +582,17 @@ moz_container_get_wl_surface(MozContaine
if (!container->subsurface || !container->surface) {
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
if (!gdk_window_is_visible(window))
return nullptr;
moz_container_map_surface(container);
}
- return container->surface;
+ return container->committed ? container->surface : nullptr;
}
struct wl_egl_window *
moz_container_get_wl_egl_window(MozContainer *container)
{
if (!container->eglwindow) {
struct wl_surface *wlsurf = moz_container_get_wl_surface(container);
if (!wlsurf)
--- a/widget/gtk/mozcontainer.h
+++ b/widget/gtk/mozcontainer.h
@@ -68,16 +68,17 @@ struct _MozContainer
GtkContainer container;
GList *children;
#ifdef MOZ_WAYLAND
struct wl_subcompositor *subcompositor;
struct wl_surface *surface;
struct wl_subsurface *subsurface;
struct wl_egl_window *eglwindow;
+ gboolean committed;
#endif
};
struct _MozContainerClass
{
GtkContainerClass parent_class;
};
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -2062,16 +2062,22 @@ nsWindow::OnExposeEvent(cairo_t *cr)
if (mIsDestroyed) {
return FALSE;
}
// Windows that are not visible will be painted after they become visible.
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
return FALSE;
+#ifdef MOZ_WAYLAND
+ // Window does not have visible wl_surface yet.
+ if (!mIsX11Display && !GetWaylandSurface())
+ return FALSE;
+#endif
+
nsIWidgetListener *listener = GetListener();
if (!listener)
return FALSE;
LayoutDeviceIntRegion exposeRegion;
if (!ExtractExposeRegion(exposeRegion, cr)) {
return FALSE;
}