Bug 1464823 - [Wayland] Don't paint until we have a visible wl_surface, r?jhorak draft
authorMartin Stransky <stransky@redhat.com>
Wed, 06 Jun 2018 11:30:27 +0200
changeset 804568 68f56e967997b3c09f92cab41e9a6077f1ec857b
parent 803993 adb08f5350758a9ad5e28b85560dc43f7750d207
push id112411
push userstransky@redhat.com
push dateWed, 06 Jun 2018 09:34:23 +0000
reviewersjhorak
bugs1464823
milestone62.0a1
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
widget/gtk/mozcontainer.cpp
widget/gtk/mozcontainer.h
widget/gtk/nsWindow.cpp
--- 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;
     }