[gtk+/wip/matthiasc/subsurface] wip: subsurface window type



commit b54e24ea292a3c8385474126015b8129eb763195
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jan 28 23:30:29 2018 +0100

    wip: subsurface window type
    
    Make subsurfaces for X11 as follows:
    - toplevel
    - override-redirect
    - moves with the parent
    Attempt to use subsurfaces for popovers again
    This does not quite work yet

 gdk/gdkwindow.c          |   68 ++++++++++++++++++++++++------------------
 gdk/gdkwindow.h          |    4 ++
 gdk/x11/gdkdisplay-x11.c |   10 +++++-
 gdk/x11/gdkwindow-x11.c  |   75 ++++++++++++++++++++++++++++++++++++++++-----
 gdk/x11/gdkwindow-x11.h  |   10 ++++++
 gtk/gtkmain.c            |    1 +
 gtk/gtkpopover.c         |   32 +++++--------------
 gtk/gtkwidget.c          |    7 ++++
 gtk/gtkwindow.c          |    8 ++++-
 9 files changed, 151 insertions(+), 64 deletions(-)
---
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 6641c12..66ac01f 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -458,12 +458,6 @@ gdk_window_get_property (GObject    *object,
     }
 }
 
-static gboolean
-gdk_window_is_subsurface (GdkWindow *window)
-{
-   return window->window_type == GDK_WINDOW_SUBSURFACE;
-}
-
 static GdkWindow *
 gdk_window_get_impl_window (GdkWindow *window)
 {
@@ -700,10 +694,7 @@ recompute_visible_regions_internal (GdkWindow *private,
   old_abs_y = private->abs_y;
 
   /* Update absolute position */
-  if ((gdk_window_has_impl (private) &&
-       private->window_type != GDK_WINDOW_SUBSURFACE) ||
-      (gdk_window_is_toplevel (private) &&
-       private->window_type == GDK_WINDOW_SUBSURFACE))
+  if (gdk_window_has_impl (private))
     {
       /* Native windows and toplevel subsurfaces start here */
       private->abs_x = 0;
@@ -745,7 +736,7 @@ recompute_visible_regions_internal (GdkWindow *private,
            cairo_region_intersect (new_clip, private->shape);
        }
       else
-         new_clip = cairo_region_create ();
+        new_clip = cairo_region_create ();
 
       if (private->clip_region == NULL ||
          !cairo_region_equal (private->clip_region, new_clip))
@@ -855,7 +846,7 @@ get_native_device_event_mask (GdkWindow *private,
 
       mask = private->event_mask;
 
-      /* We need thse for all native windows so we can
+      /* We need these for all native windows so we can
         emulate events on children: */
       mask |=
        GDK_EXPOSURE_MASK |
@@ -929,13 +920,6 @@ gdk_window_new (GdkDisplay    *display,
                   "a window of type GDK_WINDOW_ROOT");
       break;
     case GDK_WINDOW_SUBSURFACE:
-#ifdef GDK_WINDOWING_WAYLAND
-      if (!GDK_IS_WAYLAND_DISPLAY (display))
-        {
-          g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
-          return NULL;
-        }
-#endif
       break;
     case GDK_WINDOW_CHILD:
       if (GDK_WINDOW_TYPE (parent) == GDK_WINDOW_ROOT ||
@@ -975,11 +959,6 @@ gdk_window_new (GdkDisplay    *display,
       native = TRUE; /* Always use native windows for toplevels */
     }
 
-#ifdef GDK_WINDOWING_WAYLAND
-  if (window->window_type == GDK_WINDOW_SUBSURFACE)
-    native = TRUE; /* Always use native windows for subsurfaces as well */
-#endif
-
   if (native)
     {
       event_mask = get_native_event_mask (window);
@@ -1065,6 +1044,41 @@ gdk_window_new_popup (GdkDisplay         *display,
 }
 
 /**
+ * gdk_window_new_subsurface: (constructor)
+ * @parent: the parent window
+ * @position: placement of the window relative to @parent
+ *
+ * Creates a new toplevel window that is attached to @parent.
+ * The window will bypass window management and move together
+ * with its parent.
+ *
+ * Returns: (transfer full): the new #GdkWindow
+ *
+ * Since: 3.94
+ **/
+GdkWindow *
+gdk_window_new_subsurface (GdkWindow          *parent,
+                           const GdkRectangle *position)
+{
+  GdkWindowAttr attr;
+  GdkWindow *window;
+
+  g_return_val_if_fail (GDK_IS_WINDOW (parent), NULL);
+
+  attr.wclass = GDK_INPUT_OUTPUT;
+  attr.x = position->x;
+  attr.y = position->y;
+  attr.width = position->width;
+  attr.height = position->height;
+  attr.window_type = GDK_WINDOW_SUBSURFACE;
+
+  window = gdk_window_new (gdk_window_get_display (parent), NULL, &attr);
+  gdk_window_set_transient_for (window, parent);
+
+  return window;
+}
+
+/**
  * gdk_window_new_temp: (constructor)
  * @display: the display to create the window on
  *
@@ -1547,9 +1561,6 @@ gdk_window_get_parent (GdkWindow *window)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
-  if (gdk_window_is_subsurface (window))
-    return window->transient_for;
-  else
     return window->parent;
 }
 
@@ -1570,8 +1581,7 @@ gdk_window_get_toplevel (GdkWindow *window)
 {
   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
-  while (window->window_type == GDK_WINDOW_CHILD ||
-         window->window_type == GDK_WINDOW_SUBSURFACE)
+  while (window->window_type == GDK_WINDOW_CHILD)
     {
       if (gdk_window_is_toplevel (window))
        break;
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index e33e70c..4338239 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -452,6 +452,10 @@ GdkWindow *   gdk_window_new_toplevel          (GdkDisplay    *display,
 GDK_AVAILABLE_IN_3_90
 GdkWindow *   gdk_window_new_popup             (GdkDisplay    *display,
                                                 const GdkRectangle *position);
+GDK_AVAILABLE_IN_3_94
+GdkWindow *   gdk_window_new_subsurface        (GdkWindow          *parent,
+                                                const GdkRectangle *position);
+
 GDK_AVAILABLE_IN_3_90
 GdkWindow *   gdk_window_new_temp              (GdkDisplay    *display);
 GDK_AVAILABLE_IN_3_90
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 67a7217..172add0 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -992,8 +992,14 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
            }
          if (!is_substructure)
            {
-             window->x = event->configure.x;
-             window->y = event->configure.y;
+              if (window->x != event->configure.x ||
+                  window->y != event->configure.y)
+                {
+                 window->x = event->configure.x;
+                 window->y = event->configure.y;
+
+                  gdk_x11_window_update_position (window_impl);
+                }
 
               if (window_impl->unscaled_width != xevent->xconfigure.width ||
                   window_impl->unscaled_height != xevent->xconfigure.height)
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 83f8dea..dcda6bb 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -113,10 +113,12 @@ static void        gdk_window_impl_x11_finalize   (GObject            *object);
 #define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window)           \
   (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL ||   \
    GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP ||       \
+   GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE || \
    GDK_WINDOW_TYPE (window) == GDK_WINDOW_FOREIGN)
 
 #define WINDOW_IS_TOPLEVEL(window)                      \
   (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TOPLEVEL ||   \
+   GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE || \
    GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
 
 /* Return whether time1 is considered later than time2 as far as xserver
@@ -510,9 +512,16 @@ gdk_window_impl_x11_finalize (GObject *object)
   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (object));
 
   impl = GDK_WINDOW_IMPL_X11 (object);
-
   wrapper = impl->wrapper;
 
+  if (wrapper->transient_for)
+    {
+      GdkWindowImplX11 *x11_parent;
+
+      x11_parent = GDK_WINDOW_IMPL_X11 (wrapper->transient_for->impl);
+      x11_parent->transients = g_list_remove (x11_parent->transients, wrapper);
+    }
+
   if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
     unhook_surface_changed (wrapper);
 
@@ -900,6 +909,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
     {
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_TEMP:
+    case GDK_WINDOW_SUBSURFACE:
       if (window->parent)
         {
           /* The common code warns for this case */
@@ -928,7 +938,8 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
       xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
       xattributes_mask |= CWColormap;
 
-      if (window->window_type == GDK_WINDOW_TEMP)
+      if (window->window_type == GDK_WINDOW_TEMP ||
+          window->window_type == GDK_WINDOW_SUBSURFACE)
         {
           xattributes.save_under = True;
           xattributes.override_redirect = True;
@@ -944,7 +955,8 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
     {
       class = InputOnly;
 
-      if (window->window_type == GDK_WINDOW_TEMP)
+      if (window->window_type == GDK_WINDOW_TEMP ||
+          window->window_type == GDK_WINDOW_SUBSURFACE)
         {
           xattributes.override_redirect = True;
           xattributes_mask |= CWOverrideRedirect;
@@ -992,6 +1004,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
 
   switch (GDK_WINDOW_TYPE (window))
     {
+    case GDK_WINDOW_SUBSURFACE:
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_TEMP:
       gdk_window_set_title (window, get_default_title ());
@@ -1450,6 +1463,7 @@ gdk_window_x11_hide (GdkWindow *window)
     {
     case GDK_WINDOW_TOPLEVEL:
     case GDK_WINDOW_TEMP: /* ? */
+    case GDK_WINDOW_SUBSURFACE:
       gdk_window_withdraw (window);
       return;
       
@@ -1583,6 +1597,17 @@ gdk_window_x11_move_resize (GdkWindow *window,
                             gint       width,
                             gint       height)
 {
+  if (gdk_window_get_window_type (window) == GDK_WINDOW_SUBSURFACE)
+    {
+      GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+      impl->offset_x = x;
+      impl->offset_y = y;
+
+      x = window->transient_for->x + impl->offset_x;
+      y = window->transient_for->y + impl->offset_y;
+    }
+
   if (with_move && (width < 0 && height < 0))
     window_x11_move (window, x, y);
   else
@@ -1595,6 +1620,23 @@ gdk_window_x11_move_resize (GdkWindow *window,
 }
 
 void
+gdk_x11_window_update_position (GdkWindowImplX11 *impl)
+{
+  GList *l;
+
+  for (l = impl->transients; l; l = l->next)
+    {
+      GdkWindow *window = l->data;
+
+      if (gdk_window_get_window_type (window) == GDK_WINDOW_SUBSURFACE)
+        {
+          GdkWindowImplX11 *win_impl = GDK_WINDOW_IMPL_X11 (window->impl);
+          gdk_window_x11_move_resize (window, TRUE, win_impl->offset_x, win_impl->offset_y, window->width, 
window->height);
+        }
+    }
+}
+
+void
 _gdk_x11_window_set_window_scale (GdkWindow *window,
                                  int scale)
 {
@@ -2446,19 +2488,34 @@ static void
 gdk_x11_window_set_transient_for (GdkWindow *window,
                                  GdkWindow *parent)
 {
+  GdkWindowImplX11 *x11_parent;
+
   if (GDK_WINDOW_DESTROYED (window) ||
       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
     return;
 
   /* XSetTransientForHint() doesn't allow unsetting, so do it manually */
   if (parent && !GDK_WINDOW_DESTROYED (parent))
-    XSetTransientForHint (GDK_WINDOW_XDISPLAY (window), 
-                         GDK_WINDOW_XID (window),
-                         GDK_WINDOW_XID (parent));
+    {
+      XSetTransientForHint (GDK_WINDOW_XDISPLAY (window),
+                            GDK_WINDOW_XID (window),
+                            GDK_WINDOW_XID (parent));
+
+      x11_parent = GDK_WINDOW_IMPL_X11 (parent->impl);
+      x11_parent->transients = g_list_prepend (x11_parent->transients, window);
+    }
   else
-    XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
-                     GDK_WINDOW_XID (window),
-                     gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
"WM_TRANSIENT_FOR"));
+    {
+      if (window->transient_for)
+        {
+          x11_parent = GDK_WINDOW_IMPL_X11 (window->transient_for->impl);
+          x11_parent->transients = g_list_remove (x11_parent->transients, window);
+        }
+
+      XDeleteProperty (GDK_WINDOW_XDISPLAY (window),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window), 
"WM_TRANSIENT_FOR"));
+    }
 }
 
 GdkCursor *
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 2199692..8e438b2 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -89,6 +89,14 @@ struct _GdkWindowImplX11
 #if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
   Damage damage;
 #endif
+
+  /* Subsurfaces are positioned relative to their transient parent.
+   * We keep the offset here.
+   */
+  int offset_x;
+  int offset_y;
+
+  GList *transients;
 };
  
 struct _GdkWindowImplX11Class 
@@ -191,9 +199,11 @@ GdkToplevelX11 *_gdk_x11_window_get_toplevel        (GdkWindow *window);
 GdkCursor      *_gdk_x11_window_get_cursor          (GdkWindow *window);
 
 void            _gdk_x11_window_update_size         (GdkWindowImplX11 *impl);
+void            gdk_x11_window_update_position      (GdkWindowImplX11 *impl);
 void            _gdk_x11_window_set_window_scale    (GdkWindow *window,
                                                     int        scale);
 
+
 G_END_DECLS
 
 #endif /* __GDK_WINDOW_X11_H__ */
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index fcd1f36..b813fe2 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1546,6 +1546,7 @@ handle_pointing_event (GdkEvent *event)
     return widget;
 
   toplevel_widget = gtk_widget_get_toplevel (widget);
+g_print ("pointing event on %s\n", G_OBJECT_TYPE_NAME (toplevel_widget));
   if (!GTK_IS_WINDOW (toplevel_widget))
     return widget;
 
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 58b89ec..2fa8dab 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -472,36 +472,21 @@ gtk_popover_realize (GtkWidget *widget)
 {
   GtkAllocation allocation;
   GdkWindow *window;
+  GtkWidget *toplevel;
+  GskRenderer *renderer;
 
+  toplevel = gtk_widget_get_toplevel (widget);
   gtk_widget_get_window_allocation (widget, &allocation);
 
-  /* We want to use subsurfaces for popovers, so they can extend outside
-   * the main window, but for that, we first need to have clean subsurface
-   * support that works with GSK.
-   */
-#if 0
-  if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
-    {
-      GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
-
-      g_assert (GTK_IS_WINDOW (toplevel));
-
-      window = gdk_wayland_window_new_subsurface (gtk_widget_get_display (toplevel),
-                                                  &allocation);
-
-      gdk_window_set_transient_for (window,
-                                    gtk_widget_get_window (toplevel));
-    }
-  else
-#endif
-    {
-      window = gdk_window_new_child (gtk_widget_get_parent_window (widget),
-                                     &allocation);
-    }
+  window = gdk_window_new_subsurface (gtk_widget_get_window (toplevel),
+                                      &allocation);
 
   gtk_widget_set_window (widget, window);
   gtk_widget_register_window (widget, window);
   gtk_widget_set_realized (widget, TRUE);
+
+  renderer = gsk_renderer_new_for_window (window);
+  g_object_set_data_full (G_OBJECT (window), "renderer", renderer, g_object_unref);
 }
 
 static void
@@ -1021,6 +1006,7 @@ gtk_popover_update_shape (GtkPopover *popover)
   GdkWindow *win;
   cairo_t *cr;
 
+  return;
 #ifdef GDK_WINDOWING_WAYLAND
   if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)))
     return;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index b138629..93ca9d1 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -5446,6 +5446,13 @@ static GskRenderer *
 gtk_widget_get_renderer (GtkWidget *widget)
 {
   GtkWidget *toplevel;
+  GdkWindow *window;
+  GskRenderer *renderer;
+
+  window = gtk_widget_get_window (widget);
+  renderer = g_object_get_data (G_OBJECT (window), "renderer");
+  if (renderer)
+    return renderer;
 
   toplevel = _gtk_widget_get_toplevel (widget);
   if (_gtk_widget_is_toplevel (toplevel))
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 147e505..bf7aff9 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -6953,7 +6953,11 @@ gtk_window_realize (GtkWidget *widget)
   gtk_widget_set_realized (widget, TRUE);
 
   if (priv->renderer == NULL)
-    priv->renderer = gsk_renderer_new_for_window (gdk_window);
+    {
+      priv->renderer = gsk_renderer_new_for_window (gdk_window);
+      g_object_set_data_full (G_OBJECT (gdk_window), "renderer",
+                              g_object_ref (priv->renderer), g_object_unref);
+    }
 
   if (priv->transient_parent &&
       _gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
@@ -9385,11 +9389,13 @@ gtk_window_snapshot (GtkWidget   *widget,
         gtk_widget_snapshot_child (widget, child, snapshot);
     }
 
+#if 0
   for (l = priv->popovers.head; l; l = l->next)
     {
       GtkWindowPopover *data = l->data;
       gtk_widget_snapshot_child (widget, data->widget, snapshot);
     }
+#endif
 
   gtk_debug_updates_snapshot (widget, snapshot);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]