[libhandy/wip/haecker-felix/flap-widget] Have separate windows for content and flap



commit 54de28d0a2b99ad618ef4ebaa8edae8ddf4aa42d
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Thu Nov 19 13:16:59 2020 +0500

    Have separate windows for content and flap
    
    I love GTK 3.

 src/hdy-flap.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 143 insertions(+), 25 deletions(-)
---
diff --git a/src/hdy-flap.c b/src/hdy-flap.c
index 1f579306..70050e9f 100644
--- a/src/hdy-flap.c
+++ b/src/hdy-flap.c
@@ -44,6 +44,12 @@ struct _HdyFlap
   GtkWidget *content;
   GtkWidget *flap;
 
+  GdkWindow *content_window;
+  GdkWindow *flap_window;
+
+  GtkAllocation flap_allocation;
+  GtkAllocation content_allocation;
+
   HdyFlapFoldPolicy fold_policy;
   GtkPackType flap_position;
   gboolean reveal_flap;
@@ -180,6 +186,9 @@ static void
 reveal_animation_done_cb (HdyFlap *self)
 {
   g_clear_pointer (&self->reveal_animation, hdy_animation_unref);
+
+  if (self->reveal_progress <= 0)
+    hdy_shadow_helper_clear_cache (self->shadow_helper);
 }
 
 static void
@@ -290,6 +299,59 @@ end_swipe_cb (HdySwipeTracker *tracker,
     set_reveal_flap (self, to > 0, duration, FALSE);
 }
 
+static void
+register_window (HdyFlap        *self,
+                 GtkWidget      *widget,
+                 GtkAllocation  *allocation,
+                 GdkWindow     **window)
+{
+  GdkWindowAttr attributes = { 0 };
+  GdkWindowAttributesType attributes_mask;
+
+  attributes.x = allocation->x;
+  attributes.y = allocation->y;
+  attributes.width = allocation->width;
+  attributes.height = allocation->height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes_mask = (GDK_WA_X | GDK_WA_Y) | GDK_WA_VISUAL;
+
+  attributes.event_mask = gtk_widget_get_events (GTK_WIDGET (self)) |
+                          gtk_widget_get_events (widget);
+
+  *window = gdk_window_new (gtk_widget_get_window (GTK_WIDGET (self)),
+                            &attributes, attributes_mask);
+  gtk_widget_register_window (GTK_WIDGET (self), *window);
+
+  gtk_widget_set_parent_window (widget, *window);
+
+  gdk_window_show (*window);
+}
+
+static void
+unregister_window (HdyFlap    *self,
+                   GdkWindow **window)
+{
+  if (!*window)
+    return;
+
+  gtk_widget_unregister_window (GTK_WIDGET (self), *window);
+  gdk_window_destroy (*window);
+  *window = NULL;
+}
+
+static void
+restack_windows (HdyFlap *self)
+{
+  if (self->content_window)
+    gdk_window_raise (self->content_window);
+
+  if (self->flap_window)
+    gdk_window_raise (self->flap_window);
+}
+
 static inline GtkPackType
 get_start_or_end (HdyFlap *self)
 {
@@ -523,7 +585,7 @@ hdy_flap_size_allocate (GtkWidget     *widget,
                         GtkAllocation *alloc)
 {
   HdyFlap *self = HDY_FLAP (widget);
-  GtkAllocation flap_alloc, content_alloc;
+  GtkAllocation child_alloc;
 
   gtk_widget_set_allocation (widget, alloc);
 
@@ -543,16 +605,41 @@ hdy_flap_size_allocate (GtkWidget     *widget,
       set_folded (self, alloc->height < content_min.height + flap_min.height);
   }
 
-  compute_allocation (self, alloc, &flap_alloc, &content_alloc);
+  compute_allocation (self, alloc, &self->flap_allocation, &self->content_allocation);
 
-  if (self->content)
-    gtk_widget_size_allocate (self->content, &content_alloc);
+  child_alloc.x = 0;
+  child_alloc.y = 0;
+
+  if (self->content) {
+    if (gtk_widget_get_realized (widget))
+      gdk_window_move_resize (self->content_window,
+                              self->content_allocation.x,
+                              self->content_allocation.y,
+                              self->content_allocation.width,
+                              self->content_allocation.height);
+
+    child_alloc.width = self->content_allocation.width;
+    child_alloc.height = self->content_allocation.height;
+
+    gtk_widget_size_allocate (self->content, &child_alloc);
+  }
 
   if (self->flap) {
     gtk_widget_set_child_visible (self->flap, self->reveal_progress > 0);
 
-    if (self->reveal_progress > 0)
-      gtk_widget_size_allocate (self->flap, &flap_alloc);
+    if (self->reveal_progress > 0) {
+      if (gtk_widget_get_realized (widget))
+        gdk_window_move_resize (self->flap_window,
+                                self->flap_allocation.x,
+                                self->flap_allocation.y,
+                                self->flap_allocation.width,
+                                self->flap_allocation.height);
+
+      child_alloc.width = self->flap_allocation.width;
+      child_alloc.height = self->flap_allocation.height;
+
+      gtk_widget_size_allocate (self->flap, &child_alloc);
+    }
   }
 
   gtk_widget_set_clip (widget, alloc);
@@ -662,24 +749,20 @@ hdy_flap_draw (GtkWidget *widget,
   height = gtk_widget_get_allocated_height (widget);
 
   if (self->orientation == GTK_ORIENTATION_VERTICAL) {
-    gint flap_height = gtk_widget_get_allocated_height (self->flap);
-
     if (self->flap_position == GTK_PACK_START) {
       shadow_direction = GTK_PAN_DIRECTION_UP;
-      shadow_y = (gint) round (flap_height * self->reveal_progress);
+      shadow_y = self->flap_allocation.y + self->flap_allocation.height;
     } else {
       shadow_direction = GTK_PAN_DIRECTION_DOWN;
-      shadow_y = (gint) -round (flap_height * self->reveal_progress);
+      shadow_y = self->flap_allocation.y - height;
     }
   } else {
-    gint flap_width = gtk_widget_get_allocated_width (self->flap);
-
     if (self->flap_position == get_start_or_end (self)) {
       shadow_direction = GTK_PAN_DIRECTION_LEFT;
-      shadow_x = (gint) round (flap_width * self->reveal_progress);
+      shadow_x = self->flap_allocation.x + self->flap_allocation.width;
     } else {
       shadow_direction = GTK_PAN_DIRECTION_RIGHT;
-      shadow_x = (gint) -round (flap_width * self->reveal_progress);
+      shadow_x = self->flap_allocation.x - width;
     }
   }
 
@@ -733,10 +816,23 @@ hdy_flap_realize (GtkWidget *widget)
   gtk_widget_register_window (widget, window);
 
   if (self->content)
-    gtk_widget_set_parent_window (self->content, window);
+    register_window (self, self->content, &self->content_allocation, &self->content_window);
 
   if (self->flap)
-    gtk_widget_set_parent_window (self->flap, window);
+    register_window (self, self->flap, &self->flap_allocation, &self->flap_window);
+
+  restack_windows (self);
+}
+
+static void
+hdy_flap_unrealize (GtkWidget *widget)
+{
+  HdyFlap *self = HDY_FLAP (widget);
+
+  unregister_window (self, &self->content_window);
+  unregister_window (self, &self->flap_window);
+
+  GTK_WIDGET_CLASS (hdy_flap_parent_class)->unrealize (widget);
 }
 
 static void
@@ -784,11 +880,13 @@ hdy_flap_add (GtkContainer *container,
     return;
   }
 
+  if (gtk_widget_get_realized (GTK_WIDGET (self))) {
+    register_window (self, widget, &self->content_allocation, &self->content_window);
+    restack_windows (self);
+  }
+
   gtk_widget_set_parent (widget, GTK_WIDGET (self));
   self->content = widget;
-
-  if (gtk_widget_get_realized (GTK_WIDGET (self)))
-    gtk_widget_set_parent_window (self->content, gtk_widget_get_window (GTK_WIDGET (self)));
 }
 
 static void
@@ -797,12 +895,22 @@ hdy_flap_remove (GtkContainer *container,
 {
   HdyFlap *self = HDY_FLAP (container);
 
-  if (widget == self->flap)
+  if (widget == self->flap) {
     hdy_flap_set_flap (self, NULL);
-  else if (widget == self->content)
+
+    return;
+  }
+
+  if (widget == self->content) {
+    if (gtk_widget_get_realized (GTK_WIDGET (self)))
+      unregister_window (self, &self->content_window);
+
     g_clear_pointer (&self->content, gtk_widget_unparent);
-  else
-    g_return_if_reached ();
+
+    return;
+  }
+
+  g_return_if_reached ();
 }
 
 static void
@@ -913,6 +1021,7 @@ hdy_flap_class_init (HdyFlapClass *klass)
   widget_class->size_allocate = hdy_flap_size_allocate;
   widget_class->draw = hdy_flap_draw;
   widget_class->realize = hdy_flap_realize;
+  widget_class->unrealize = hdy_flap_unrealize;
   widget_class->direction_changed = hdy_flap_direction_changed;
 
   container_class->remove = hdy_flap_remove;
@@ -1158,7 +1267,7 @@ hdy_flap_get_swipe_area (HdySwipeable           *swipeable,
   width = gtk_widget_get_allocated_width (GTK_WIDGET (self));
   height = gtk_widget_get_allocated_height (GTK_WIDGET (self));
 
-  gtk_widget_get_allocation (self->flap, &alloc);
+  alloc = self->flap_allocation;
 
   if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
     if (self->flap_position == get_start_or_end (self)) {
@@ -1245,12 +1354,21 @@ hdy_flap_set_flap (HdyFlap   *self,
   if (self->flap == flap)
     return;
 
-  if (self->flap)
+  if (self->flap) {
+    if (gtk_widget_get_realized (GTK_WIDGET (self)))
+      unregister_window (self, &self->flap_window);
+
     gtk_widget_unparent (self->flap);
+  }
 
   self->flap = flap;
 
   if (self->flap) {
+    if (gtk_widget_get_realized (GTK_WIDGET (self))) {
+      register_window (self, self->flap, &self->flap_allocation, &self->flap_window);
+      restack_windows (self);
+    }
+
     gtk_widget_set_parent (self->flap, GTK_WIDGET (self));
 
     if (gtk_widget_get_realized (GTK_WIDGET (self)))


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