]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkoverlay.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkoverlay.c
index b964fff53a0048067b7252c0f5ab6dc1b9afe973..de80637d071cf811365fc122ada5c42033eaae26 100644 (file)
@@ -15,9 +15,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -37,8 +35,8 @@
  *
  * GtkOverlay is a container which contains a single main child, on top
  * of which it can place <firstterm>overlay</firstterm> widgets. The
- * position of each overlay widget is determined by its #GtkWidget::halign
- * and #GtkWidget::valign properties. E.g. a widget with both alignments
+ * position of each overlay widget is determined by its #GtkWidget:halign
+ * and #GtkWidget:valign properties. E.g. a widget with both alignments
  * set to %GTK_ALIGN_START will be placed at the top left corner of the
  * main widget, whereas an overlay with halign set to %GTK_ALIGN_CENTER
  * and valign set to %GTK_ALIGN_END will be placed a the bottom edge of
@@ -107,7 +105,7 @@ gtk_overlay_create_child_window (GtkOverlay *overlay,
 
   window = gdk_window_new (gtk_widget_get_window (widget),
                            &attributes, attributes_mask);
-  gdk_window_set_user_data (window, overlay);
+  gtk_widget_register_window (widget, window);
   gtk_style_context_set_background (gtk_widget_get_style_context (widget), window);
 
   gtk_widget_set_parent_window (child, window);
@@ -115,6 +113,129 @@ gtk_overlay_create_child_window (GtkOverlay *overlay,
   return window;
 }
 
+static GtkAlign
+effective_align (GtkAlign         align,
+                 GtkTextDirection direction)
+{
+  switch (align)
+    {
+    case GTK_ALIGN_START:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
+    case GTK_ALIGN_END:
+      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
+    default:
+      return align;
+    }
+}
+
+static void
+gtk_overlay_get_main_widget_allocation (GtkOverlay *overlay,
+                                        GtkAllocation *main_alloc_out)
+{
+  GtkWidget *main_widget;
+  GtkAllocation main_alloc;
+
+  main_widget = gtk_bin_get_child (GTK_BIN (overlay));
+
+  /* special-case scrolled windows */
+  if (GTK_IS_SCROLLED_WINDOW (main_widget))
+    {
+      GtkWidget *grandchild;
+      gint x, y;
+      gboolean res;
+
+      grandchild = gtk_bin_get_child (GTK_BIN (main_widget));
+      res = gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y);
+
+      if (res)
+        {
+          main_alloc.x = x;
+          main_alloc.y = y;
+        }
+      else
+        {
+          main_alloc.x = 0;
+          main_alloc.y = 0;
+        }
+
+      main_alloc.width = gtk_widget_get_allocated_width (grandchild);
+      main_alloc.height = gtk_widget_get_allocated_height (grandchild);
+    }
+  else
+    {
+      main_alloc.x = 0;
+      main_alloc.y = 0;
+      main_alloc.width = gtk_widget_get_allocated_width (main_widget);
+      main_alloc.height = gtk_widget_get_allocated_height (main_widget);
+    }
+
+  if (main_alloc_out)
+    *main_alloc_out = main_alloc;
+}
+
+static void
+gtk_overlay_child_update_style_classes (GtkOverlay *overlay,
+                                        GtkWidget *child,
+                                        GtkAllocation *child_allocation)
+{
+  GtkAllocation overlay_allocation, main_allocation;
+  GtkAlign valign, halign;
+  gboolean is_left, is_right, is_top, is_bottom;
+  gboolean has_left, has_right, has_top, has_bottom;
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (child);
+  has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
+  has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
+  has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
+  has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
+
+  is_left = is_right = is_top = is_bottom = FALSE;
+
+  gtk_overlay_get_main_widget_allocation (overlay, &main_allocation);
+  gtk_widget_get_allocation (GTK_WIDGET (overlay), &overlay_allocation);
+
+  main_allocation.x += overlay_allocation.x;
+  main_allocation.y += overlay_allocation.y;
+
+  halign = effective_align (gtk_widget_get_halign (child),
+                            gtk_widget_get_direction (child));
+
+  if (halign == GTK_ALIGN_START)
+    is_left = (child_allocation->x == main_allocation.x);
+  else if (halign == GTK_ALIGN_END)
+    is_right = (child_allocation->x + child_allocation->width ==
+                main_allocation.x + main_allocation.width);
+
+  valign = gtk_widget_get_valign (child);
+
+  if (valign == GTK_ALIGN_START)
+    is_top = (child_allocation->y == main_allocation.y);
+  else if (valign == GTK_ALIGN_END)
+    is_bottom = (child_allocation->y + child_allocation->height ==
+                 main_allocation.y + main_allocation.height);
+
+  if (has_left && !is_left)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
+  else if (!has_left && is_left)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+
+  if (has_right && !is_right)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
+  else if (!has_right && is_right)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+
+  if (has_top && !is_top)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
+  else if (!has_top && is_top)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
+
+  if (has_bottom && !is_bottom)
+    gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
+  else if (!has_bottom && is_bottom)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
+}
+
 static void
 gtk_overlay_child_allocate (GtkOverlay      *overlay,
                             GtkOverlayChild *child)
@@ -165,6 +286,7 @@ gtk_overlay_child_allocate (GtkOverlay      *overlay,
                             allocation.x, allocation.y,
                             allocation.width, allocation.height);
 
+  gtk_overlay_child_update_style_classes (overlay, child->widget, &allocation);
   gtk_widget_size_allocate (child->widget, &child_allocation);
 }
 
@@ -229,56 +351,17 @@ gtk_overlay_size_allocate (GtkWidget     *widget,
     }
 }
 
-static GtkAlign
-effective_align (GtkAlign         align,
-                 GtkTextDirection direction)
-{
-  switch (align)
-    {
-    case GTK_ALIGN_START:
-      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_END : GTK_ALIGN_START;
-    case GTK_ALIGN_END:
-      return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
-    default:
-      return align;
-    }
-}
-
 static gboolean
 gtk_overlay_get_child_position (GtkOverlay    *overlay,
                                 GtkWidget     *widget,
                                 GtkAllocation *alloc)
 {
-  GtkWidget *main_widget;
   GtkAllocation main_alloc;
   GtkRequisition req;
   GtkAlign halign;
   GtkTextDirection direction;
 
-  main_widget = gtk_bin_get_child (GTK_BIN (overlay));
-
-  /* special-case scrolled windows */
-  if (GTK_IS_SCROLLED_WINDOW (main_widget))
-    {
-      GtkWidget *grandchild;
-      gint x, y;
-
-      grandchild = gtk_bin_get_child (GTK_BIN (main_widget));
-      gtk_widget_translate_coordinates (grandchild, main_widget, 0, 0, &x, &y);
-
-      main_alloc.x = x;
-      main_alloc.y = y;
-      main_alloc.width = gtk_widget_get_allocated_width (grandchild);
-      main_alloc.height = gtk_widget_get_allocated_height (grandchild);
-    }
-  else
-    {
-      main_alloc.x = 0;
-      main_alloc.y = 0;
-      main_alloc.width = gtk_widget_get_allocated_width (main_widget);
-      main_alloc.height = gtk_widget_get_allocated_height (main_widget);
-    }
-
+  gtk_overlay_get_main_widget_allocation (overlay, &main_alloc);
   gtk_widget_get_preferred_size (widget, NULL, &req);
 
   alloc->x = main_alloc.x;
@@ -340,7 +423,10 @@ gtk_overlay_realize (GtkWidget *widget)
       child = children->data;
 
       if (child->window == NULL)
-        child->window = gtk_overlay_create_child_window (overlay, child->widget);
+       {
+         child->window = gtk_overlay_create_child_window (overlay, child->widget);
+         gtk_overlay_child_allocate (overlay, child);
+       }
     }
 }
 
@@ -357,7 +443,7 @@ gtk_overlay_unrealize (GtkWidget *widget)
       child = children->data;
 
       gtk_widget_set_parent_window (child->widget, NULL);
-      gdk_window_set_user_data (child->window, NULL);
+      gtk_widget_unregister_window (widget, child->window);
       gdk_window_destroy (child->window);
       child->window = NULL;
     }
@@ -453,7 +539,7 @@ gtk_overlay_remove (GtkContainer *container,
         {
           if (child->window != NULL)
             {
-              gdk_window_set_user_data (child->window, NULL);
+              gtk_widget_unregister_window (GTK_WIDGET (container), child->window);
               gdk_window_destroy (child->window);
             }
 
@@ -519,7 +605,7 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
    * GtkOverlay::get-child-position:
    * @overlay: the #GtkOverlay
    * @widget: the child widget to position
-   * @allocation: (out): return location for the allocation
+   * @allocation: (out caller-allocates): return location for the allocation
    *
    * The ::get-child-position signal is emitted to determine
    * the position and size of any overlay child widgets. A
@@ -605,7 +691,7 @@ gtk_overlay_new (void)
  * added with gtk_container_add().
  *
  * The position at which @widget is placed is determined
- * from its #GtkWidget::halign and #GtkWidget::valign properties.
+ * from its #GtkWidget:halign and #GtkWidget:valign properties.
  *
  * Since: 3.2
  */
@@ -628,6 +714,7 @@ gtk_overlay_add_overlay (GtkOverlay *overlay,
     {
       child->window = gtk_overlay_create_child_window (overlay, widget);
       gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
+      gtk_overlay_child_allocate (overlay, child);
     }
   else
     gtk_widget_set_parent (widget, GTK_WIDGET (overlay));