]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkwidget.c
Fixed focus handling on embedded windows.
[~andy/gtk] / gtk / gtkwidget.c
index ca61f04a20f7903a3c199c10884dcc77837e7730..4ee58865acef0e9c9397cda606d87b1e0322c50a 100644 (file)
  */
 
 #include "config.h"
+
 #include <stdarg.h>
 #include <string.h>
 #include <locale.h>
+
+#include <gobject/gvaluecollector.h>
+#include <gobject/gobjectnotifyqueue.c>
+#include <cairo-gobject.h>
+
 #include "gtkcontainer.h"
 #include "gtkaccelmap.h"
 #include "gtkclipboard.h"
 #include "gtkiconfactory.h"
 #include "gtkintl.h"
-#include "gtkmain.h"
+#include "gtkmainprivate.h"
 #include "gtkmarshalers.h"
 #include "gtkrc.h"
 #include "gtkselection.h"
-#include "gtksettings.h"
+#include "gtksettingsprivate.h"
 #include "gtksizegroup-private.h"
 #include "gtkwidget.h"
 #include "gtkwidgetprivate.h"
 #include "gtkwindowprivate.h"
 #include "gtkbindings.h"
 #include "gtkprivate.h"
-#include "gdk/gdk.h"
-#include "gdk/gdkprivate.h" /* Used in gtk_reset_shapes_recurse to avoid copy */
-#include <gobject/gvaluecollector.h>
-#include <gobject/gobjectnotifyqueue.c>
-#include <cairo-gobject.h>
-#include "gdk/gdkkeysyms.h"
 #include "gtkaccessible.h"
 #include "gtktooltip.h"
 #include "gtkinvisible.h"
@@ -63,6 +63,7 @@
 #include "gtkmodifierstyle.h"
 #include "gtkversion.h"
 #include "gtkdebug.h"
+#include "gtktypebuiltins.h"
 
 
 /**
@@ -313,7 +314,7 @@ struct _GtkWidgetPrivate
   guint has_grab              : 1;
   guint shadowed              : 1;
   guint rc_style              : 1;
-  guint user_style            : 1;
+  guint style_update_pending  : 1;
   guint app_paintable         : 1;
   guint double_buffered       : 1;
   guint redraw_on_alloc       : 1;
@@ -369,6 +370,11 @@ struct _GtkWidgetPrivate
    */
   GtkWidget *parent;
 
+#ifdef G_ENABLE_DEBUG
+  /* Number of gtk_widget_push_verify_invariants () */
+  guint verifying_invariants_count;
+#endif /* G_ENABLE_DEBUG */
+
   /* Widget's path for styling */
   GtkWidgetPath *path;
 };
@@ -556,14 +562,20 @@ static void             gtk_widget_real_move_focus              (GtkWidget
                                                                  GtkDirectionType  direction);
 static gboolean                gtk_widget_real_keynav_failed           (GtkWidget        *widget,
                                                                 GtkDirectionType  direction);
+#ifdef G_ENABLE_DEBUG
+static void             gtk_widget_verify_invariants            (GtkWidget        *widget);
+static void             gtk_widget_push_verify_invariants       (GtkWidget        *widget);
+static void             gtk_widget_pop_verify_invariants        (GtkWidget        *widget);
+#else
+#define                 gtk_widget_verify_invariants(widget)
+#define                 gtk_widget_push_verify_invariants(widget)
+#define                 gtk_widget_pop_verify_invariants(widget)
+#endif
 static PangoContext*   gtk_widget_peek_pango_context           (GtkWidget        *widget);
 static void            gtk_widget_update_pango_context         (GtkWidget        *widget);
 static void            gtk_widget_propagate_state              (GtkWidget        *widget,
                                                                 GtkStateData     *data);
-static void             gtk_widget_reset_rc_style               (GtkWidget        *widget);
-static void            gtk_widget_set_style_internal           (GtkWidget        *widget,
-                                                                GtkStyle         *style,
-                                                                gboolean          initial_emission);
+;
 static gint            gtk_widget_event_internal               (GtkWidget        *widget,
                                                                 GdkEvent         *event);
 static gboolean                gtk_widget_real_mnemonic_activate       (GtkWidget        *widget,
@@ -2150,13 +2162,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
    * @widget: the object which received the signal
    * @event: (type Gdk.EventAny): the #GdkEventAny which triggered this signal
    *
-   * The ::unmap-event signal may be emitted when the @widget's window is
+   * The ::unmap-event signal will be emitted when the @widget's window is
    * unmapped. A window is unmapped when it becomes invisible on the screen.
    *
-   * For performance reasons GTK+ may not emit ::unmap-event, so one
-   * should always also implement ::unrealize in order to release
-   * resources and disconnect signal handlers.
-   *
    * To receive this signal, the #GdkWindow associated to the widget needs
    * to enable the #GDK_STRUCTURE_MASK mask. GDK will enable this mask
    * automatically for all new windows.
@@ -2449,7 +2457,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
     g_signal_new (I_("drag-failed"),
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
-                 0, _gtk_boolean_handled_accumulator, NULL,
+                 G_STRUCT_OFFSET (GtkWidgetClass, drag_failed),
+                 _gtk_boolean_handled_accumulator, NULL,
                  _gtk_marshal_BOOLEAN__OBJECT_ENUM,
                  G_TYPE_BOOLEAN, 2,
                  GDK_TYPE_DRAG_CONTEXT,
@@ -3698,8 +3707,9 @@ gtk_widget_unparent (GtkWidget *widget)
   if (priv->parent == NULL)
     return;
 
-  /* keep this function in sync with gtk_menu_detach()
-   */
+  /* keep this function in sync with gtk_menu_detach() */
+
+  gtk_widget_push_verify_invariants (widget);
 
   g_object_freeze_notify (G_OBJECT (widget));
   nqueue = g_object_notify_queue_freeze (G_OBJECT (widget), _gtk_widget_child_property_notify_context);
@@ -3737,6 +3747,12 @@ gtk_widget_unparent (GtkWidget *widget)
        gtk_widget_unrealize (widget);
     }
 
+  /* Need to unset the parent window early, this can result in 
+   * an additional "hierarchy-changed" propagation if we are removing
+   * a parented GtkWindow from the hierarchy.
+   */
+  gtk_widget_set_parent_window (widget, NULL);
+
   /* Removing a widget from a container restores the child visible
    * flag to the default state, so it doesn't affect the child
    * in the next parent.
@@ -3745,7 +3761,6 @@ gtk_widget_unparent (GtkWidget *widget)
 
   old_parent = priv->parent;
   priv->parent = NULL;
-  gtk_widget_set_parent_window (widget, NULL);
 
   /* parent may no longer expand if the removed
    * child was expand=TRUE and could therefore
@@ -3760,7 +3775,7 @@ gtk_widget_unparent (GtkWidget *widget)
     }
 
   g_signal_emit (widget, widget_signals[PARENT_SET], 0, old_parent);
-  if (toplevel)
+  if (toplevel && gtk_widget_is_toplevel (toplevel))
     {
       _gtk_widget_propagate_hierarchy_changed (widget, toplevel);
       g_object_unref (toplevel);
@@ -3771,6 +3786,8 @@ gtk_widget_unparent (GtkWidget *widget)
   if (!priv->parent)
     g_object_notify_queue_clear (G_OBJECT (widget), nqueue);
   g_object_notify_queue_thaw (G_OBJECT (widget), nqueue);
+
+  gtk_widget_pop_verify_invariants (widget);
   g_object_unref (widget);
 }
 
@@ -3852,8 +3869,10 @@ gtk_widget_show (GtkWidget *widget)
   if (!gtk_widget_get_visible (widget))
     {
       g_object_ref (widget);
+      gtk_widget_push_verify_invariants (widget);
+
       if (!gtk_widget_is_toplevel (widget))
-       gtk_widget_queue_resize (widget);
+        gtk_widget_queue_resize (widget);
 
       /* see comment in set_parent() for why this should and can be
        * conditional
@@ -3868,6 +3887,8 @@ gtk_widget_show (GtkWidget *widget)
 
       g_signal_emit (widget, widget_signals[SHOW], 0);
       g_object_notify (G_OBJECT (widget), "visible");
+
+      gtk_widget_pop_verify_invariants (widget);
       g_object_unref (widget);
     }
 }
@@ -3949,8 +3970,10 @@ gtk_widget_hide (GtkWidget *widget)
       GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
 
       g_object_ref (widget);
+      gtk_widget_push_verify_invariants (widget);
+
       if (toplevel != widget && gtk_widget_is_toplevel (toplevel))
-       _gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
+        _gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
 
       /* a parent may now be expand=FALSE since we're hidden. */
       if (widget->priv->need_compute_expand ||
@@ -3964,6 +3987,8 @@ gtk_widget_hide (GtkWidget *widget)
       if (!gtk_widget_is_toplevel (widget))
        gtk_widget_queue_resize (widget);
       g_object_notify (G_OBJECT (widget), "visible");
+
+      gtk_widget_pop_verify_invariants (widget);
       g_object_unref (widget);
     }
 }
@@ -4123,13 +4148,17 @@ gtk_widget_map (GtkWidget *widget)
 
   if (!gtk_widget_get_mapped (widget))
     {
+      gtk_widget_push_verify_invariants (widget);
+
       if (!gtk_widget_get_realized (widget))
-       gtk_widget_realize (widget);
+        gtk_widget_realize (widget);
 
       g_signal_emit (widget, widget_signals[MAP], 0);
 
       if (!gtk_widget_get_has_window (widget))
-       gdk_window_invalidate_rect (priv->window, &priv->allocation, FALSE);
+        gdk_window_invalidate_rect (priv->window, &priv->allocation, FALSE);
+
+      gtk_widget_pop_verify_invariants (widget);
 
       _gtk_widget_start_state_transitions (widget);
     }
@@ -4153,10 +4182,14 @@ gtk_widget_unmap (GtkWidget *widget)
 
   if (gtk_widget_get_mapped (widget))
     {
+      gtk_widget_push_verify_invariants (widget);
+
       if (!gtk_widget_get_has_window (widget))
        gdk_window_invalidate_rect (priv->window, &priv->allocation, FALSE);
       _gtk_tooltip_hide (widget);
       g_signal_emit (widget, widget_signals[UNMAP], 0);
+
+      gtk_widget_pop_verify_invariants (widget);
     }
 }
 
@@ -4222,6 +4255,8 @@ gtk_widget_realize (GtkWidget *widget)
 
   if (!gtk_widget_get_realized (widget))
     {
+      gtk_widget_push_verify_invariants (widget);
+
       /*
        if (GTK_IS_CONTAINER (widget) && gtk_widget_get_has_window (widget))
          g_message ("gtk_widget_realize(%s)", G_OBJECT_TYPE_NAME (widget));
@@ -4238,6 +4273,9 @@ gtk_widget_realize (GtkWidget *widget)
 
       gtk_widget_ensure_style (widget);
 
+      if (priv->style_update_pending)
+        g_signal_emit (widget, widget_signals[STYLE_UPDATED], 0);
+
       g_signal_emit (widget, widget_signals[REALIZE], 0);
 
       gtk_widget_real_set_has_tooltip (widget,
@@ -4258,6 +4296,8 @@ gtk_widget_realize (GtkWidget *widget)
         gdk_window_set_support_multidevice (priv->window, TRUE);
 
       _gtk_widget_enable_device_events (widget);
+
+      gtk_widget_pop_verify_invariants (widget);
     }
 }
 
@@ -4274,6 +4314,8 @@ gtk_widget_unrealize (GtkWidget *widget)
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
+  gtk_widget_push_verify_invariants (widget);
+
   if (widget->priv->has_shape_mask)
     gtk_widget_shape_combine_region (widget, NULL);
 
@@ -4283,12 +4325,18 @@ gtk_widget_unrealize (GtkWidget *widget)
   if (gtk_widget_get_realized (widget))
     {
       g_object_ref (widget);
-      _gtk_tooltip_hide (widget);
+
+      if (widget->priv->mapped)
+        gtk_widget_unmap (widget);
+
       g_signal_emit (widget, widget_signals[UNREALIZE], 0);
+      g_assert (!widget->priv->mapped);
       gtk_widget_set_realized (widget, FALSE);
-      gtk_widget_set_mapped (widget, FALSE);
+
       g_object_unref (widget);
     }
+
+  gtk_widget_pop_verify_invariants (widget);
 }
 
 /*****************************************
@@ -4588,6 +4636,8 @@ gtk_widget_size_allocate (GtkWidget       *widget,
 
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
+  gtk_widget_push_verify_invariants (widget);
+
 #ifdef G_ENABLE_DEBUG
   if (gtk_get_debug_flags () & GTK_DEBUG_GEOMETRY)
     {
@@ -4687,7 +4737,7 @@ gtk_widget_size_allocate (GtkWidget       *widget,
                      old_allocation.y != real_allocation.y);
 
   if (!alloc_needed && !size_changed && !position_changed)
-    return;
+    goto out;
 
   g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
 
@@ -4739,6 +4789,9 @@ gtk_widget_size_allocate (GtkWidget       *widget,
       gtk_widget_invalidate_widget_windows (priv->parent, invalidate);
       cairo_region_destroy (invalidate);
     }
+
+out:
+  gtk_widget_pop_verify_invariants (widget);
 }
 
 /**
@@ -6290,9 +6343,29 @@ gtk_widget_real_query_tooltip (GtkWidget  *widget,
 static void
 gtk_widget_real_style_updated (GtkWidget *widget)
 {
+  if (gtk_widget_get_realized (widget))
+    {
+      /* Trigger ::style-set for old
+       * widgets not listening to this
+       */
+      g_signal_emit (widget,
+                     widget_signals[STYLE_SET],
+                     0,
+                     widget->priv->style);
+    }
+
   if (widget->priv->context)
-    gtk_style_context_invalidate (widget->priv->context);
-  gtk_widget_queue_resize (widget);
+    {
+      gtk_style_context_invalidate (widget->priv->context);
+
+      if (gtk_widget_get_realized (widget) &&
+          gtk_widget_get_has_window (widget))
+        gtk_style_context_set_background (widget->priv->context,
+                                          widget->priv->window);
+    }
+
+  if (widget->priv->anchored)
+    gtk_widget_queue_resize (widget);
 }
 
 static gboolean
@@ -6734,9 +6807,6 @@ gtk_widget_set_name (GtkWidget     *widget,
   if (priv->context)
     gtk_style_context_set_path (priv->context, priv->path);
 
-  if (priv->rc_style)
-    gtk_widget_reset_rc_style (widget);
-
   g_object_notify (G_OBJECT (widget), "name");
 }
 
@@ -7085,9 +7155,11 @@ gtk_widget_get_has_window (GtkWidget *widget)
  * gtk_widget_is_toplevel:
  * @widget: a #GtkWidget
  *
- * Determines whether @widget is a toplevel widget. Currently only
- * #GtkWindow and #GtkInvisible are toplevel widgets. Toplevel
- * widgets have no parent widget.
+ * Determines whether @widget is a toplevel widget.
+ *
+ * Currently only #GtkWindow and #GtkInvisible (and out-of-process
+ * #GtkPlugs) are toplevel widgets. Toplevel widgets have no parent
+ * widget.
  *
  * Return value: %TRUE if @widget is a toplevel, %FALSE otherwise
  *
@@ -7502,6 +7574,9 @@ gtk_widget_set_parent (GtkWidget *widget,
    */
 
   g_object_ref_sink (widget);
+
+  gtk_widget_push_verify_invariants (widget);
+
   priv->parent = parent;
 
   parent_flags = gtk_widget_get_state_flags (parent);
@@ -7565,6 +7640,8 @@ gtk_widget_set_parent (GtkWidget *widget,
       gtk_style_context_set_screen (widget->priv->context,
                                     gtk_widget_get_screen (widget));
     }
+
+  gtk_widget_pop_verify_invariants (widget);
 }
 
 /**
@@ -7658,23 +7735,6 @@ gtk_widget_set_style (GtkWidget *widget,
                      GtkStyle  *style)
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
-
-  if (style)
-    {
-      gboolean initial_emission;
-
-      initial_emission = !widget->priv->rc_style && !widget->priv->user_style;
-
-      widget->priv->rc_style = FALSE;
-      widget->priv->user_style = TRUE;
-
-      gtk_widget_set_style_internal (widget, style, initial_emission);
-    }
-  else
-    {
-      if (widget->priv->user_style)
-       gtk_widget_reset_rc_style (widget);
-    }
 }
 
 /**
@@ -7694,46 +7754,25 @@ gtk_widget_ensure_style (GtkWidget *widget)
   g_return_if_fail (GTK_IS_WIDGET (widget));
 
   if (!widget->priv->style ||
-      !gtk_style_has_context (widget->priv->style))
+      widget->priv->style == gtk_widget_get_default_style ())
     {
       GtkStyle *style;
 
+      if (widget->priv->style)
+        g_object_unref (widget->priv->style);
+
       style = g_object_new (GTK_TYPE_STYLE,
                             "context", gtk_widget_get_style_context (widget),
                             NULL);
 
-      gtk_widget_set_style_internal (widget, style, TRUE);
-      g_object_unref (style);
-    }
-
-#if 0
-  if (!widget->priv->rc_style && !widget->priv->user_style)
-    gtk_widget_reset_rc_style (widget);
-#endif
-}
-
-/* Look up the RC style for this widget, unsetting any user style that
- * may be in effect currently
- **/
-static void
-gtk_widget_reset_rc_style (GtkWidget *widget)
-{
-  GtkWidgetPrivate *priv = widget->priv;
-  GtkStyle *new_style = NULL;
-  gboolean initial_emission;
+      widget->priv->style = g_object_ref (style);
 
-  initial_emission = !priv->rc_style && !priv->user_style;
-
-  priv->user_style = FALSE;
-  priv->rc_style = TRUE;
-
-  if (gtk_widget_has_screen (widget))
-    new_style = gtk_rc_get_style (widget);
-  if (!new_style)
-    new_style = gtk_widget_get_default_style ();
+      g_signal_emit (widget,
+                     widget_signals[STYLE_SET],
+                     0, NULL);
 
-  if (initial_emission || new_style != priv->style)
-    gtk_widget_set_style_internal (widget, new_style, initial_emission);
+      g_object_unref (style);
+    }
 }
 
 /**
@@ -7790,13 +7829,6 @@ gtk_widget_modify_style (GtkWidget      *widget,
                           quark_rc_style,
                           gtk_rc_style_copy (style),
                           (GDestroyNotify) g_object_unref);
-
-  /* note that "style" may be invalid here if it was the old
-   * modifier style and the only reference was our own.
-   */
-
-  if (widget->priv->rc_style)
-    gtk_widget_reset_rc_style (widget);
 }
 
 /**
@@ -7888,11 +7920,6 @@ modifier_style_changed (GtkModifierStyle *style,
 
   context = gtk_widget_get_style_context (widget);
   gtk_style_context_invalidate (context);
-
-  g_signal_emit (widget,
-                 widget_signals[STYLE_SET],
-                 0,
-                 widget->priv->style);
 }
 
 static GtkModifierStyle *
@@ -8347,59 +8374,6 @@ static void
 gtk_widget_real_style_set (GtkWidget *widget,
                            GtkStyle  *previous_style)
 {
-  GtkWidgetPrivate *priv = widget->priv;
-
-  if (gtk_widget_get_realized (widget) &&
-      gtk_widget_get_has_window (widget))
-    gtk_style_set_background (priv->style, priv->window,
-                              gtk_widget_get_state (widget));
-}
-
-static void
-gtk_widget_set_style_internal (GtkWidget *widget,
-                              GtkStyle  *style,
-                              gboolean   initial_emission)
-{
-  GtkWidgetPrivate *priv = widget->priv;
-
-  g_object_ref (widget);
-  g_object_freeze_notify (G_OBJECT (widget));
-
-  if (priv->style != style)
-    {
-      GtkStyle *previous_style;
-
-      if (gtk_widget_get_realized (widget))
-        gtk_style_detach (priv->style);
-
-      previous_style = priv->style;
-      priv->style = style;
-      g_object_ref (priv->style);
-
-      if (gtk_widget_get_realized (widget))
-       priv->style = gtk_style_attach (priv->style, priv->window);
-
-      gtk_widget_update_pango_context (widget);
-      g_signal_emit (widget,
-                    widget_signals[STYLE_SET],
-                    0,
-                    initial_emission ? NULL : previous_style);
-      g_object_unref (previous_style);
-
-      if (priv->anchored && !initial_emission)
-       gtk_widget_queue_resize (widget);
-    }
-  else if (initial_emission)
-    {
-      gtk_widget_update_pango_context (widget);
-      g_signal_emit (widget,
-                    widget_signals[STYLE_SET],
-                    0,
-                    NULL);
-    }
-  g_object_notify (G_OBJECT (widget), "style");
-  g_object_thaw_notify (G_OBJECT (widget));
-  g_object_unref (widget);
 }
 
 typedef struct {
@@ -8594,11 +8568,6 @@ _gtk_widget_propagate_screen_changed (GtkWidget    *widget,
 static void
 reset_style_recurse (GtkWidget *widget, gpointer data)
 {
-#if 0
-  if (widget->priv->rc_style)
-    gtk_widget_reset_rc_style (widget);
-#endif
-
   if (widget->priv->context)
     {
       _gtk_widget_update_path (widget);
@@ -8673,6 +8642,192 @@ gtk_widget_get_default_style (void)
   return gtk_default_style;
 }
 
+#ifdef G_ENABLE_DEBUG
+
+/* Verify invariants, see docs/widget_system.txt for notes on much of
+ * this.  Invariants may be temporarily broken while we're in the
+ * process of updating state, of course, so you can only
+ * verify_invariants() after a given operation is complete.
+ * Use push/pop_verify_invariants to help with that.
+ */
+static void
+gtk_widget_verify_invariants (GtkWidget *widget)
+{
+  GtkWidget *parent;
+
+  if (widget->priv->verifying_invariants_count > 0)
+    return;
+
+  parent = widget->priv->parent;
+
+  if (widget->priv->mapped)
+    {
+      /* Mapped implies ... */
+
+      if (!widget->priv->realized)
+        g_warning ("%s %p is mapped but not realized",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+
+      if (!widget->priv->visible)
+        g_warning ("%s %p is mapped but not visible",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+
+      if (!widget->priv->toplevel)
+        {
+          if (!widget->priv->child_visible)
+            g_warning ("%s %p is mapped but not child_visible",
+                       G_OBJECT_TYPE_NAME (widget), widget);
+        }
+    }
+  else
+    {
+      /* Not mapped implies... */
+
+#if 0
+  /* This check makes sense for normal toplevels, but for
+   * something like a toplevel that is embedded within a clutter
+   * state, mapping may depend on external factors.
+   */
+      if (widget->priv->toplevel)
+        {
+          if (widget->priv->visible)
+            g_warning ("%s %p toplevel is visible but not mapped",
+                       G_OBJECT_TYPE_NAME (widget), widget);
+        }
+#endif
+    }
+
+  /* Parent related checks aren't possible if parent has
+   * verifying_invariants_count > 0 because parent needs to recurse
+   * children first before the invariants will hold.
+   */
+  if (parent == NULL || parent->priv->verifying_invariants_count == 0)
+    {
+      if (parent &&
+          parent->priv->realized)
+        {
+          /* Parent realized implies... */
+
+#if 0
+          /* This is in widget_system.txt but appears to fail
+           * because there's no gtk_container_realize() that
+           * realizes all children... instead we just lazily
+           * wait for map to fix things up.
+           */
+          if (!widget->priv->realized)
+            g_warning ("%s %p is realized but child %s %p is not realized",
+                       G_OBJECT_TYPE_NAME (parent), parent,
+                       G_OBJECT_TYPE_NAME (widget), widget);
+#endif
+        }
+      else if (!widget->priv->toplevel)
+        {
+          /* No parent or parent not realized on non-toplevel implies... */
+
+          if (widget->priv->realized && !widget->priv->in_reparent)
+            g_warning ("%s %p is not realized but child %s %p is realized",
+                       parent ? G_OBJECT_TYPE_NAME (parent) : "no parent", parent,
+                       G_OBJECT_TYPE_NAME (widget), widget);
+        }
+
+      if (parent &&
+          parent->priv->mapped &&
+          widget->priv->visible &&
+          widget->priv->child_visible)
+        {
+          /* Parent mapped and we are visible implies... */
+
+          if (!widget->priv->mapped)
+            g_warning ("%s %p is mapped but visible child %s %p is not mapped",
+                       G_OBJECT_TYPE_NAME (parent), parent,
+                       G_OBJECT_TYPE_NAME (widget), widget);
+        }
+      else if (!widget->priv->toplevel)
+        {
+          /* No parent or parent not mapped on non-toplevel implies... */
+
+          if (widget->priv->mapped && !widget->priv->in_reparent)
+            g_warning ("%s %p is mapped but visible=%d child_visible=%d parent %s %p mapped=%d",
+                       G_OBJECT_TYPE_NAME (widget), widget,
+                       widget->priv->visible,
+                       widget->priv->child_visible,
+                       parent ? G_OBJECT_TYPE_NAME (parent) : "no parent", parent,
+                       parent ? parent->priv->mapped : FALSE);
+        }
+    }
+
+  if (!widget->priv->realized)
+    {
+      /* Not realized implies... */
+
+#if 0
+      /* widget_system.txt says these hold, but they don't. */
+      if (widget->priv->resize_pending)
+        g_warning ("%s %p resize pending but not realized",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+
+      if (widget->priv->alloc_needed)
+        g_warning ("%s %p alloc needed but not realized",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+
+      if (widget->priv->width_request_needed)
+        g_warning ("%s %p width request needed but not realized",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+
+      if (widget->priv->height_request_needed)
+        g_warning ("%s %p height request needed but not realized",
+                   G_OBJECT_TYPE_NAME (widget), widget);
+#endif
+    }
+}
+
+/* The point of this push/pop is that invariants may not hold while
+ * we're busy making changes. So we only check at the outermost call
+ * on the call stack, after we finish updating everything.
+ */
+static void
+gtk_widget_push_verify_invariants (GtkWidget *widget)
+{
+  widget->priv->verifying_invariants_count += 1;
+}
+
+static void
+gtk_widget_verify_child_invariants (GtkWidget *widget,
+                                    gpointer   client_data)
+{
+  /* We don't recurse further; this is a one-level check. */
+  gtk_widget_verify_invariants (widget);
+}
+
+static void
+gtk_widget_pop_verify_invariants (GtkWidget *widget)
+{
+  g_assert (widget->priv->verifying_invariants_count > 0);
+
+  widget->priv->verifying_invariants_count -= 1;
+
+  if (widget->priv->verifying_invariants_count == 0)
+    {
+      gtk_widget_verify_invariants (widget);
+
+      if (GTK_IS_CONTAINER (widget))
+        {
+          /* Check one level of children, because our
+           * push_verify_invariants() will have prevented some of the
+           * checks. This does not recurse because if recursion is
+           * needed, it will happen naturally as each child has a
+           * push/pop on that child. For example if we're recursively
+           * mapping children, we'll push/pop on each child as we map
+           * it.
+           */
+          gtk_container_forall (GTK_CONTAINER (widget),
+                                gtk_widget_verify_child_invariants,
+                                NULL);
+        }
+    }
+}
+#endif /* G_ENABLE_DEBUG */
+
 static PangoContext *
 gtk_widget_peek_pango_context (GtkWidget *widget)
 {
@@ -8919,6 +9074,16 @@ gtk_widget_render_icon (GtkWidget      *widget,
  * @parent_window: the new parent window.
  *
  * Sets a non default parent window for @widget.
+ *
+ * For GtkWindow classes, setting a @parent_window effects whether 
+ * the window is a toplevel window or can be embedded into other
+ * widgets.
+ *
+ * <note><para>
+ * For GtkWindow classes, this needs to be called before the
+ * window is realized.
+ * </para></note>
+ * 
  **/
 void
 gtk_widget_set_parent_window   (GtkWidget           *widget,
@@ -8939,6 +9104,13 @@ gtk_widget_set_parent_window   (GtkWidget           *widget,
        g_object_unref (old_parent_window);
       if (parent_window)
        g_object_ref (parent_window);
+
+      /* Unset toplevel flag when adding a parent window to a widget,
+       * this is the primary entry point to allow toplevels to be
+       * embeddable.
+       */
+      if (GTK_IS_WINDOW (widget) && !GTK_IS_PLUG (widget))
+       _gtk_window_set_is_toplevel (GTK_WINDOW (widget), parent_window == NULL);
     }
 }
 
@@ -9002,6 +9174,7 @@ gtk_widget_set_child_visible (GtkWidget *widget,
   priv = widget->priv;
 
   g_object_ref (widget);
+  gtk_widget_verify_invariants (widget);
 
   if (is_visible)
     priv->child_visible = TRUE;
@@ -9026,6 +9199,7 @@ gtk_widget_set_child_visible (GtkWidget *widget,
        gtk_widget_unmap (widget);
     }
 
+  gtk_widget_verify_invariants (widget);
   g_object_unref (widget);
 }
 
@@ -10370,10 +10544,7 @@ gtk_widget_real_unrealize (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = widget->priv;
 
-  if (gtk_widget_get_mapped (widget))
-    gtk_widget_real_unmap (widget);
-
-  gtk_widget_set_mapped (widget, FALSE);
+  g_assert (!widget->priv->mapped);
 
   /* printf ("unrealizing %s\n", g_type_name (G_TYPE_FROM_INSTANCE (widget)));
    */
@@ -13797,7 +13968,20 @@ style_context_changed (GtkStyleContext *context,
 {
   GtkWidget *widget = user_data;
 
-  g_signal_emit (widget, widget_signals[STYLE_UPDATED], 0);
+  gtk_widget_update_pango_context (widget);
+
+  if (gtk_widget_get_realized (widget))
+    g_signal_emit (widget, widget_signals[STYLE_UPDATED], 0);
+  else
+    {
+      /* Compress all style updates so it
+       * is only emitted once pre-realize.
+       */
+      widget->priv->style_update_pending = TRUE;
+    }
+
+  if (widget->priv->anchored)
+    gtk_widget_queue_resize (widget);
 }
 
 /**