[gtk+/toplevel-embedding] Allow GtkWindow to be parented if gtk_widget_set_parent_window() is called on one



commit 462dbe081492c3ae525292e568c40fdd6569ebd2
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Thu Dec 23 21:51:25 2010 +0900

    Allow GtkWindow to be parented if gtk_widget_set_parent_window() is called on one
    
    This patch makes gtk_widget_set_parent_window() undo the toplevelness
    of a GtkWindow, GtkWindow then realizes itself as a normal child widget
    and behaves like a normal GtkBin by checking gtk_widget_is_toplevel() in
    several places (show/hide/map/unmap/draw/size_allocate/check_resize/configure_event).

 gtk/gtkwidget.c |   11 ++++
 gtk/gtkwindow.c |  168 +++++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 149 insertions(+), 30 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 07f360c..ed5d73f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -8631,6 +8631,7 @@ gtk_widget_get_default_style (void)
 }
 
 #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
@@ -9081,6 +9082,16 @@ 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_window_set_is_toplevel (GTK_WINDOW (widget), FALSE);
+	  gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT);
+	}
     }
 }
 
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 2723c42..bfe5f79 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -4621,6 +4621,12 @@ gtk_window_show (GtkWidget *widget)
   GtkContainer *container = GTK_CONTAINER (window);
   gboolean need_resize;
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      GTK_WIDGET_CLASS (gtk_window_parent_class)->show (widget);
+      return;
+    }
+
   _gtk_widget_set_visible_flag (widget, TRUE);
 
   need_resize = _gtk_container_get_need_resize (container) || !gtk_widget_get_realized (widget);
@@ -4698,6 +4704,12 @@ gtk_window_hide (GtkWidget *widget)
   GtkWindow *window = GTK_WINDOW (widget);
   GtkWindowPrivate *priv = window->priv;
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      GTK_WIDGET_CLASS (gtk_window_parent_class)->hide (widget);
+      return;
+    }
+
   _gtk_widget_set_visible_flag (widget, FALSE);
   gtk_widget_unmap (widget);
 
@@ -4717,6 +4729,12 @@ gtk_window_map (GtkWidget *widget)
 
   gdk_window = gtk_widget_get_window (widget);
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      GTK_WIDGET_CLASS (gtk_window_parent_class)->map (widget);
+      return;
+    }
+
   gtk_widget_set_mapped (widget, TRUE);
 
   child = gtk_bin_get_child (&(window->bin));
@@ -4833,6 +4851,12 @@ gtk_window_unmap (GtkWidget *widget)
   GdkWindow *gdk_window;
   GdkWindowState state;
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      GTK_WIDGET_CLASS (gtk_window_parent_class)->unmap (widget);
+      return;
+    }
+
   gdk_window = gtk_widget_get_window (widget);
 
   gtk_widget_set_mapped (widget, FALSE);
@@ -4886,6 +4910,35 @@ gtk_window_realize (GtkWidget *widget)
 
   gtk_widget_get_allocation (widget, &allocation);
 
+  if (gtk_widget_get_parent_window (widget))
+    {
+      gtk_widget_set_realized (widget, TRUE);
+
+      attributes.x = allocation.x;
+      attributes.y = allocation.y;
+      attributes.width = allocation.width;
+      attributes.height = allocation.height;
+      attributes.window_type = GDK_WINDOW_CHILD;
+
+      attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
+
+      attributes.visual = gtk_widget_get_visual (widget);
+      attributes.wclass = GDK_INPUT_OUTPUT;
+
+      attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+      gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+				   &attributes, attributes_mask);
+      gtk_widget_set_window (widget, gdk_window);
+      gdk_window_set_user_data (gdk_window, widget);
+
+      gtk_widget_style_attach (widget);
+      gtk_style_set_background (gtk_widget_get_style (widget), gdk_window, GTK_STATE_NORMAL);
+
+      gdk_window_enable_synchronized_configure (gdk_window);
+      return;
+    }
+
   /* ensure widget tree is properly size allocated */
   if (allocation.x == -1 &&
       allocation.y == -1 &&
@@ -4933,6 +4986,7 @@ gtk_window_realize (GtkWidget *widget)
   attributes.wmclass_class = priv->wmclass_class;
   attributes.wclass = GDK_INPUT_OUTPUT;
   attributes.visual = gtk_widget_get_visual (widget);
+  attributes_mask   = 0;
 
   if (priv->has_frame)
     {
@@ -4953,7 +5007,7 @@ gtk_window_realize (GtkWidget *widget)
       attributes_mask = GDK_WA_VISUAL;
 
       priv->frame = gdk_window_new (gtk_widget_get_root_window (widget),
-				      &attributes, attributes_mask);
+				    &attributes, attributes_mask);
 						 
       if (priv->opacity_set)
 	gdk_window_set_opacity (priv->frame, priv->opacity);
@@ -5013,6 +5067,7 @@ gtk_window_realize (GtkWidget *widget)
   if (priv->frame)
     gtk_style_context_set_background (context, priv->frame);
 
+
   if (priv->transient_parent &&
       gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent)))
     gdk_window_set_transient_for (gdk_window,
@@ -5020,48 +5075,48 @@ gtk_window_realize (GtkWidget *widget)
 
   if (priv->wm_role)
     gdk_window_set_role (gdk_window, priv->wm_role);
-
+  
   if (!priv->decorated)
     gdk_window_set_decorations (gdk_window, 0);
-
+  
   if (!priv->deletable)
     gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE);
-
+  
   if (gtk_window_get_skip_pager_hint (window))
     gdk_window_set_skip_pager_hint (gdk_window, TRUE);
-
+  
   if (gtk_window_get_skip_taskbar_hint (window))
     gdk_window_set_skip_taskbar_hint (gdk_window, TRUE);
-
+  
   if (gtk_window_get_accept_focus (window))
     gdk_window_set_accept_focus (gdk_window, TRUE);
   else
     gdk_window_set_accept_focus (gdk_window, FALSE);
-
+  
   if (gtk_window_get_focus_on_map (window))
     gdk_window_set_focus_on_map (gdk_window, TRUE);
   else
     gdk_window_set_focus_on_map (gdk_window, FALSE);
-
+  
   if (priv->modal)
     gdk_window_set_modal_hint (gdk_window, TRUE);
   else
     gdk_window_set_modal_hint (gdk_window, FALSE);
-
+  
   if (priv->startup_id)
     {
 #ifdef GDK_WINDOWING_X11
       guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
       if (timestamp != GDK_CURRENT_TIME)
-        gdk_x11_window_set_user_time (gdk_window, timestamp);
+	gdk_x11_window_set_user_time (gdk_window, timestamp);
 #endif
       if (!startup_id_is_fake (priv->startup_id)) 
-        gdk_window_set_startup_id (gdk_window, priv->startup_id);
+	gdk_window_set_startup_id (gdk_window, priv->startup_id);
     }
-
+  
   /* Icons */
   gtk_window_realize_icon (window);
-
+  
   if (priv->has_resize_grip)
     resize_grip_create_window (window);
 }
@@ -5278,6 +5333,29 @@ gtk_window_size_allocate (GtkWidget     *widget,
 
   gtk_widget_set_allocation (widget, allocation);
 
+  if (gtk_widget_get_realized (widget))
+    {
+      /* If it's not a toplevel we're embedded, we need to resize the window's 
+       * window and skip the grip.
+       */
+      if (!gtk_widget_is_toplevel (widget))
+	{
+	  gdk_window_move_resize (gtk_widget_get_window (widget),
+				  allocation->x, allocation->y,
+				  allocation->width, allocation->height);
+	}
+      else
+	{
+	  if (priv->frame)
+	    gdk_window_resize (priv->frame,
+			       allocation->width + priv->frame_left + priv->frame_right,
+			       allocation->height + priv->frame_top + priv->frame_bottom);
+	  
+	  update_grip_visibility (window);
+	  set_grip_position (window);
+	}
+    }
+
   child = gtk_bin_get_child (&(window->bin));
   if (child && gtk_widget_get_visible (child))
     {
@@ -5291,16 +5369,6 @@ gtk_window_size_allocate (GtkWidget     *widget,
 
       gtk_widget_size_allocate (child, &child_allocation);
     }
-
-  if (gtk_widget_get_realized (widget))
-    {
-      if (priv->frame)
-        gdk_window_resize (priv->frame,
-                           allocation->width + priv->frame_left + priv->frame_right,
-                           allocation->height + priv->frame_top + priv->frame_bottom);
-      update_grip_visibility (window);
-      set_grip_position (window);
-    }
 }
 
 static gint
@@ -5371,6 +5439,15 @@ gtk_window_configure_event (GtkWidget         *widget,
   GtkWindowPrivate *priv = window->priv;
   gboolean expected_reply = priv->configure_request_count > 0;
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      if (GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event)
+  	return GTK_WIDGET_CLASS (gtk_window_parent_class)->configure_event (widget, event);
+
+      gdk_window_configure_finished (gtk_widget_get_window (widget));
+      return FALSE;
+    }
+
   /* priv->configure_request_count incremented for each
    * configure request, and decremented to a min of 0 for
    * each configure notify.
@@ -5432,7 +5509,8 @@ static gboolean
 gtk_window_state_event (GtkWidget           *widget,
                         GdkEventWindowState *event)
 {
-  update_grip_visibility (GTK_WINDOW (widget));
+  if (gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    update_grip_visibility (GTK_WINDOW (widget));
 
   return FALSE;
 }
@@ -5443,9 +5521,12 @@ gtk_window_direction_changed (GtkWidget        *widget,
 {
   GtkWindow *window = GTK_WINDOW (widget);
 
-  set_grip_cursor (window);
-  set_grip_position (window);
-  set_grip_shape (window);
+  if (gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    {
+      set_grip_cursor (window);
+      set_grip_position (window);
+      set_grip_shape (window);
+    }
 }
 
 static void
@@ -5454,7 +5535,8 @@ gtk_window_state_changed (GtkWidget    *widget,
 {
   GtkWindow *window = GTK_WINDOW (widget);
 
-  update_grip_visibility (window);
+  if (gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    update_grip_visibility (window);
 }
 
 static void
@@ -5555,7 +5637,8 @@ gtk_window_set_has_resize_grip (GtkWindow *window,
       priv->has_resize_grip = value;
       gtk_widget_queue_draw (widget);
 
-      if (gtk_widget_get_realized (widget))
+      if (gtk_widget_get_realized (widget) && 
+	  gtk_widget_is_toplevel (GTK_WIDGET (widget)))
         {
           if (priv->has_resize_grip && priv->grip_window == NULL)
             resize_grip_create_window (window);
@@ -5624,6 +5707,9 @@ gtk_window_resize_grip_is_visible (GtkWindow *window)
   if (!priv->resizable)
     return FALSE;
 
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (widget)))
+    return FALSE;
+
   if (gtk_widget_get_realized (widget))
     {
       GdkWindowState state;
@@ -6044,7 +6130,11 @@ gtk_window_client_event (GtkWidget	*widget,
 static void
 gtk_window_check_resize (GtkContainer *container)
 {
-  if (gtk_widget_get_visible (GTK_WIDGET (container)))
+  /* If the window is not toplevel anymore than it's embedded somewhere,
+   * so handle it like a normal window */
+  if (!gtk_widget_is_toplevel (GTK_WIDGET (container)))
+    GTK_CONTAINER_CLASS (gtk_window_parent_class)->check_resize (container);
+  else if (gtk_widget_get_visible (GTK_WIDGET (container)))
     gtk_window_move_resize (GTK_WINDOW (container));
 }
 
@@ -6802,6 +6892,7 @@ gtk_window_move_resize (GtkWindow *window)
   GtkWindowLastGeometryInfo saved_last_info;
   
   widget = GTK_WIDGET (window);
+
   gdk_window = gtk_widget_get_window (widget);
   container = GTK_CONTAINER (widget);
   info = gtk_window_get_geometry_info (window, TRUE);
@@ -7429,6 +7520,23 @@ gtk_window_draw (GtkWidget *widget,
   GtkStyleContext *context;
   gboolean ret = FALSE;
 
+  /* If the window is not toplevel anymore than it's embedded somewhere,
+   * so just chain up and paint the children */
+  if (!gtk_widget_is_toplevel (widget))
+    {
+      if (!gtk_widget_get_app_paintable (widget))
+	gtk_paint_flat_box (gtk_widget_get_style (widget),
+			    cr,
+			    gtk_widget_get_state (widget),
+			    GTK_SHADOW_NONE,
+			    widget, "window",
+			    0, 0,
+			    gtk_widget_get_allocated_width (widget),
+			    gtk_widget_get_allocated_height (widget));
+      
+      return GTK_WIDGET_CLASS (gtk_window_parent_class)->draw (widget, cr);
+    }
+
   context = gtk_widget_get_style_context (widget);
 
   gtk_style_context_save (context);



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