[gtk+/overlay: 5/34] overlay: manage the parent window



commit 301caa8c977e2459dddcc204b1f0f73fd2281d7f
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Wed May 25 20:10:02 2011 +0200

    overlay: manage the parent window

 gtk/gtkoverlay.c |  181 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 gtk/gtkoverlay.h |    1 +
 2 files changed, 171 insertions(+), 11 deletions(-)
---
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
index e169b8e..b8a016a 100644
--- a/gtk/gtkoverlay.c
+++ b/gtk/gtkoverlay.c
@@ -49,6 +49,23 @@ enum
 
 G_DEFINE_TYPE (GtkOverlay, gtk_overlay, GTK_TYPE_CONTAINER)
 
+/* the reason for this is that the main widget doesn't need to set an offset
+   and it doesn't need an extra window */
+static void
+add_child (GtkOverlay *overlay,
+           GtkWidget  *widget)
+{
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkOverlayChild *child;
+
+  child = g_slice_new0 (GtkOverlayChild);
+  child->widget = widget;
+
+  gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
+
+  priv->children = g_slist_append (priv->children, child);
+}
+
 static GtkOverlayChild *
 get_child (GtkOverlay *overlay,
            GtkWidget  *widget)
@@ -68,6 +85,37 @@ get_child (GtkOverlay *overlay,
   return NULL;
 }
 
+static GdkWindow *
+gtk_overlay_create_child_window (GtkOverlay *overlay,
+                                 GtkWidget  *child)
+{
+  GtkWidget *widget = GTK_WIDGET (overlay);
+  GtkAllocation allocation;
+  GdkWindow *window;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  gtk_widget_get_allocation (child, &allocation);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+
+  window = gdk_window_new (gtk_widget_get_window (widget),
+                           &attributes, attributes_mask);
+  gdk_window_set_user_data (window, overlay);
+  gtk_style_context_set_background (gtk_widget_get_style_context (widget), window);
+
+  gtk_widget_set_parent_window (child, window);
+
+  return window;
+}
+
 static void
 gtk_overlay_dispose (GObject *object)
 {
@@ -110,7 +158,7 @@ gtk_overlay_set_property (GObject      *object,
     {
       case PROP_MAIN_WIDGET:
         priv->main_widget = g_value_get_object (value);
-        gtk_overlay_add (overlay, priv->main_widget, 0);
+        add_child (overlay, priv->main_widget);
         break;
       case PROP_RELATIVE_WIDGET:
         priv->relative_widget = g_value_get_object (value);
@@ -150,8 +198,22 @@ gtk_overlay_get_preferred_height (GtkWidget *widget,
 }
 
 static void
+gtk_overlay_child_allocate (GtkWidget           *child,
+                            GdkWindow           *child_window, /* can be NULL */
+                            const GtkAllocation *window_allocation,
+                            GtkAllocation       *child_allocation)
+{
+  if (child_window)
+    gdk_window_move_resize (child_window,
+                            window_allocation->x, window_allocation->y,
+                            window_allocation->width, window_allocation->height);
+
+  gtk_widget_size_allocate (child, child_allocation);
+}
+
+static void
 gtk_overlay_size_allocate (GtkWidget     *widget,
-                             GtkAllocation *allocation)
+                           GtkAllocation *allocation)
 {
   GtkOverlay *overlay = GTK_OVERLAY (widget);
   GtkOverlayPrivate *priv = overlay->priv;
@@ -176,13 +238,14 @@ gtk_overlay_size_allocate (GtkWidget     *widget,
   for (children = priv->children; children; children = g_slist_next (children))
     {
       GtkRequisition req;
-      GtkAllocation alloc;
+      GtkAllocation alloc, child_alloc;
       guint offset;
       GtkAlign halign, valign;
 
       child = children->data;
 
-      if (child->widget == priv->main_widget)
+      if (child->widget == priv->main_widget ||
+          !gtk_widget_get_visible (child->widget))
         continue;
 
       gtk_widget_get_preferred_size (child->widget, NULL, &req);
@@ -237,11 +300,104 @@ gtk_overlay_size_allocate (GtkWidget     *widget,
       alloc.width = MIN (main_alloc.width, req.width);
       alloc.height = MIN (main_alloc.height, req.height);
 
-      gtk_widget_size_allocate (child->widget, &alloc);
+      child_alloc.x = child_alloc.y = 0;
+      child_alloc.width = alloc.width;
+      child_alloc.height = alloc.height;
+
+      gtk_overlay_child_allocate (child->widget, child->window, &alloc, &child_alloc);
     }
 }
 
 static void
+gtk_overlay_realize (GtkWidget *widget)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (widget);
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkOverlayChild *child;
+  GSList *children;
+
+  GTK_WIDGET_CLASS (gtk_overlay_parent_class)->realize (widget);
+
+  for (children = priv->children; children; children = g_slist_next (children))
+    {
+      child = children->data;
+
+      if (child->widget == priv->main_widget)
+        {
+          child->window = gtk_widget_get_window (priv->main_widget);
+        }
+      else if (child->window == NULL)
+        {
+          child->window = gtk_overlay_create_child_window (overlay, child->widget);
+        }
+    }
+}
+
+static void
+gtk_overlay_unrealize (GtkWidget *widget)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (widget);
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkOverlayChild *child;
+  GSList *children;
+
+  for (children = priv->children; children; children = g_slist_next (children))
+    {
+      child = children->data;
+
+      if (child->widget == priv->main_widget)
+        child->window = NULL;
+      else
+        {
+          gtk_widget_set_parent_window (child->widget, NULL);
+          gdk_window_set_user_data (child->window, NULL);
+          gdk_window_destroy (child->window);
+          child->window = NULL;
+        }
+    }
+
+  GTK_WIDGET_CLASS (gtk_overlay_parent_class)->unrealize (widget);
+}
+
+static void
+gtk_overlay_map (GtkWidget *widget)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (widget);
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkOverlayChild *child;
+  GSList *children;
+
+  GTK_WIDGET_CLASS (gtk_overlay_parent_class)->map (widget);
+
+  for (children = priv->children; children; children = g_slist_next (children))
+    {
+      child = children->data;
+
+      if (child->window != NULL && gtk_widget_get_visible (child->widget) && gtk_widget_get_child_visible (child->widget))
+        gdk_window_show (child->window);
+    }
+}
+
+static void
+gtk_overlay_unmap (GtkWidget *widget)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (widget);
+  GtkOverlayPrivate *priv = overlay->priv;
+  GtkOverlayChild *child;
+  GSList *children;
+
+  for (children = priv->children; children; children = g_slist_next (children))
+    {
+      child = children->data;
+
+      if (child->window != NULL && gdk_window_is_visible (child->window))
+        gdk_window_hide (child->window);
+    }
+
+  GTK_WIDGET_CLASS (gtk_overlay_parent_class)->unmap (widget);
+}
+
+static void
 overlay_add (GtkContainer *overlay,
              GtkWidget    *widget)
 {
@@ -383,6 +539,10 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
   widget_class->get_preferred_width = gtk_overlay_get_preferred_width;
   widget_class->get_preferred_height = gtk_overlay_get_preferred_height;
   widget_class->size_allocate = gtk_overlay_size_allocate;
+  widget_class->realize = gtk_overlay_realize;
+  widget_class->unrealize = gtk_overlay_unrealize;
+  widget_class->map = gtk_overlay_map;
+  widget_class->unmap = gtk_overlay_unmap;
 
   container_class->add = overlay_add;
   container_class->remove = gtk_overlay_remove;
@@ -463,19 +623,18 @@ gtk_overlay_add (GtkOverlay *overlay,
                  GtkWidget  *widget,
                  guint       offset)
 {
-  GtkOverlayPrivate *priv = overlay->priv;
   GtkOverlayChild *child;
 
   g_return_if_fail (GTK_IS_OVERLAY (overlay));
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
-  child = g_slice_new (GtkOverlayChild);
-  child->widget = widget;
-  child->offset = offset;
+  add_child (overlay, widget);
 
-  gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
+  child = get_child (overlay, widget);
+  child->offset = offset;
 
-  priv->children = g_slist_append (priv->children, child);
+  if (gtk_widget_get_realized (GTK_WIDGET (overlay)))
+    child->window = gtk_overlay_create_child_window (overlay, widget);
 }
 
 void
diff --git a/gtk/gtkoverlay.h b/gtk/gtkoverlay.h
index b8065b7..273428b 100644
--- a/gtk/gtkoverlay.h
+++ b/gtk/gtkoverlay.h
@@ -70,6 +70,7 @@ struct _GtkOverlayClass
 struct _GtkOverlayChild
 {
   GtkWidget *widget;
+  GdkWindow *window;
   gint offset;
 };
 



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