]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkpaned.c
separator: Don't use padding and borders wrongly
[~andy/gtk] / gtk / gtkpaned.c
index d608d066afe1a4aefcf9d0b35f19b236e8c28c5b..7c5ec381f3f0ab9eb0633692b53f4ce2009445dc 100644 (file)
@@ -12,9 +12,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 "gtkpaned.h"
 
-#include "gdk/gdkkeysyms.h"
 #include "gtkbindings.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
 #include "gtkorientable.h"
 #include "gtkwindow.h"
-
+#include "gtktypebuiltins.h"
+#include "gtkorientableprivate.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
+#include "a11y/gtkpanedaccessible.h"
 
+/**
+ * SECTION:gtkpaned
+ * @Short_description: A widget with two adjustable panes
+ * @Title: GtkPaned
+ *
+ * #GtkPaned has two panes, arranged either
+ * horizontally or vertically. The division between
+ * the two panes is adjustable by the user by dragging
+ * a handle.
+ *
+ * Child widgets are
+ * added to the panes of the widget with gtk_paned_pack1() and
+ * gtk_paned_pack2(). The division between the two children is set by default
+ * from the size requests of the children, but it can be adjusted by the
+ * user.
+ *
+ * A paned widget draws a separator between the two child widgets and a
+ * small handle that the user can drag to adjust the division. It does not
+ * draw any relief around the children or around the separator. (The space
+ * in which the separator is called the gutter.) Often, it is useful to put
+ * each child inside a #GtkFrame with the shadow type set to %GTK_SHADOW_IN
+ * so that the gutter appears as a ridge. No separator is drawn if one of
+ * the children is missing.
+ *
+ * Each child has two options that can be set, @resize and @shrink. If
+ * @resize is true, then when the #GtkPaned is resized, that child will
+ * expand or shrink along with the paned widget. If @shrink is true, then
+ * that child can be made smaller than its requisition by the user.
+ * Setting @shrink to %FALSE allows the application to set a minimum size.
+ * If @resize is false for both children, then this is treated as if
+ * @resize is true for both children.
+ *
+ * The application can set the position of the slider as if it were set
+ * by the user, by calling gtk_paned_set_position().
+ *
+ * <example>
+ * <title>Creating a paned widget with minimum sizes.</title>
+ * <programlisting>
+ * GtkWidget *hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+ * GtkWidget *frame1 = gtk_frame_new (NULL);
+ * GtkWidget *frame2 = gtk_frame_new (NULL);
+ * gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
+ * gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN);
+ *
+ * gtk_widget_set_size_request (hpaned, 200, -1);
+ *
+ * gtk_paned_pack1 (GTK_PANED (hpaned), frame1, TRUE, FALSE);
+ * gtk_widget_set_size_request (frame1, 50, -1);
+ *
+ * gtk_paned_pack2 (GTK_PANED (hpaned), frame2, FALSE, FALSE);
+ * gtk_widget_set_size_request (frame2, 50, -1);
+ * </programlisting>
+ * </example>
+ */
 
+enum {
+  CHILD1,
+  CHILD2
+};
 
 struct _GtkPanedPrivate
 {
-  GtkOrientation  orientation;
   GtkPaned       *first_paned;
   GtkWidget      *child1;
   GtkWidget      *child2;
+  GdkWindow      *child1_window;
+  GdkWindow      *child2_window;
   GtkWidget      *last_child1_focus;
   GtkWidget      *last_child2_focus;
   GtkWidget      *saved_focus;
+  GtkOrientation  orientation;
 
   GdkCursorType  cursor_type;
   GdkDevice     *grab_device;
@@ -62,6 +121,8 @@ struct _GtkPanedPrivate
   gint          min_position;
   gint          original_position;
 
+  guint32       grab_time;
+
   guint         handle_prelit : 1;
   guint         in_drag       : 1;
   guint         in_recursion  : 1;
@@ -70,8 +131,6 @@ struct _GtkPanedPrivate
   guint         child2_resize : 1;
   guint         child2_shrink : 1;
   guint         position_set  : 1;
-
-  guint32       grab_time;
 };
 
 enum {
@@ -125,6 +184,16 @@ static void     gtk_paned_get_preferred_width   (GtkWidget        *widget,
 static void     gtk_paned_get_preferred_height  (GtkWidget        *widget,
                                                  gint             *minimum,
                                                  gint             *natural);
+static void     gtk_paned_get_preferred_width_for_height
+                                                (GtkWidget        *widget,
+                                                 gint              height,
+                                                 gint             *minimum,
+                                                 gint             *natural);
+static void     gtk_paned_get_preferred_height_for_width
+                                                (GtkWidget        *widget,
+                                                 gint              width,
+                                                 gint             *minimum,
+                                                 gint              *natural);
 
 static void     gtk_paned_size_allocate         (GtkWidget        *widget,
                                                  GtkAllocation    *allocation);
@@ -132,8 +201,8 @@ static void     gtk_paned_realize               (GtkWidget        *widget);
 static void     gtk_paned_unrealize             (GtkWidget        *widget);
 static void     gtk_paned_map                   (GtkWidget        *widget);
 static void     gtk_paned_unmap                 (GtkWidget        *widget);
-static void     gtk_paned_state_changed         (GtkWidget        *widget,
-                                                 GtkStateType      previous_state);
+static void     gtk_paned_state_flags_changed   (GtkWidget        *widget,
+                                                 GtkStateFlags     previous_state);
 static gboolean gtk_paned_draw                  (GtkWidget        *widget,
                                                 cairo_t          *cr);
 static gboolean gtk_paned_enter                 (GtkWidget        *widget,
@@ -235,6 +304,8 @@ gtk_paned_class_init (GtkPanedClass *class)
 
   widget_class->get_preferred_width = gtk_paned_get_preferred_width;
   widget_class->get_preferred_height = gtk_paned_get_preferred_height;
+  widget_class->get_preferred_width_for_height = gtk_paned_get_preferred_width_for_height;
+  widget_class->get_preferred_height_for_width = gtk_paned_get_preferred_height_for_width;
   widget_class->size_allocate = gtk_paned_size_allocate;
   widget_class->realize = gtk_paned_realize;
   widget_class->unrealize = gtk_paned_unrealize;
@@ -249,7 +320,7 @@ gtk_paned_class_init (GtkPanedClass *class)
   widget_class->motion_notify_event = gtk_paned_motion;
   widget_class->grab_broken_event = gtk_paned_grab_broken;
   widget_class->grab_notify = gtk_paned_grab_notify;
-  widget_class->state_changed = gtk_paned_state_changed;
+  widget_class->state_flags_changed = gtk_paned_state_flags_changed;
 
   container_class->add = gtk_paned_add;
   container_class->remove = gtk_paned_remove;
@@ -581,6 +652,7 @@ gtk_paned_class_init (GtkPanedClass *class)
   add_move_binding (binding_set, GDK_KEY_KP_End, 0, GTK_SCROLL_END);
 
   g_type_class_add_private (object_class, sizeof (GtkPanedPrivate));
+  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_PANED_ACCESSIBLE);
 }
 
 static GType
@@ -617,7 +689,6 @@ gtk_paned_init (GtkPaned *paned)
   priv->child1 = NULL;
   priv->child2 = NULL;
   priv->handle = NULL;
-  priv->cursor_type = GDK_CROSS;
 
   priv->handle_pos.width = 5;
   priv->handle_pos.height = 5;
@@ -650,14 +721,15 @@ gtk_paned_set_property (GObject        *object,
     {
     case PROP_ORIENTATION:
       priv->orientation = g_value_get_enum (value);
+      _gtk_orientable_set_style_classes (GTK_ORIENTABLE (paned));
 
       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
         priv->cursor_type = GDK_SB_H_DOUBLE_ARROW;
       else
         priv->cursor_type = GDK_SB_V_DOUBLE_ARROW;
 
-      /* state_changed updates the cursor */
-      gtk_paned_state_changed (GTK_WIDGET (paned), gtk_widget_get_state (GTK_WIDGET (paned)));
+      /* state_flags_changed updates the cursor */
+      gtk_paned_state_flags_changed (GTK_WIDGET (paned), 0);
       gtk_widget_queue_resize (GTK_WIDGET (paned));
       break;
     case PROP_POSITION:
@@ -797,9 +869,29 @@ gtk_paned_finalize (GObject *object)
   G_OBJECT_CLASS (gtk_paned_parent_class)->finalize (object);
 }
 
+static void
+get_preferred_size_for_size (GtkWidget      *widget,
+                             GtkOrientation  orientation,
+                             gint            size,
+                             gint           *minimum,
+                             gint           *natural)
+{
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    if (size < 0)
+      gtk_widget_get_preferred_width (widget, minimum, natural);
+    else
+      gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
+  else
+    if (size < 0)
+      gtk_widget_get_preferred_height (widget, minimum, natural);
+    else
+      gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural);
+}
+
 static void
 gtk_paned_get_preferred_size (GtkWidget      *widget,
                               GtkOrientation  orientation,
+                              gint            size,
                               gint           *minimum,
                               gint           *natural)
 {
@@ -811,25 +903,22 @@ gtk_paned_get_preferred_size (GtkWidget      *widget,
 
   if (priv->child1 && gtk_widget_get_visible (priv->child1))
     {
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        gtk_widget_get_preferred_width (priv->child1, &child_min, &child_nat);
+      get_preferred_size_for_size (priv->child1, orientation, size, &child_min, &child_nat);
+      if (priv->child1_shrink && priv->orientation == orientation)
+        *minimum = 0;
       else
-        gtk_widget_get_preferred_height (priv->child1, &child_min, &child_nat);
-
-      *minimum = child_min;
+        *minimum = child_min;
       *natural = child_nat;
     }
 
   if (priv->child2 && gtk_widget_get_visible (priv->child2))
     {
-      if (orientation == GTK_ORIENTATION_HORIZONTAL)
-        gtk_widget_get_preferred_width (priv->child2, &child_min, &child_nat);
-      else
-        gtk_widget_get_preferred_height (priv->child2, &child_min, &child_nat);
+      get_preferred_size_for_size (priv->child2, orientation, size, &child_min, &child_nat);
 
       if (priv->orientation == orientation)
         {
-          *minimum += child_min;
+          if (!priv->child2_shrink)
+            *minimum += child_min;
           *natural += child_nat;
         }
       else
@@ -859,7 +948,7 @@ gtk_paned_get_preferred_width (GtkWidget *widget,
                                gint      *minimum,
                                gint      *natural)
 {
-  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum, natural);
+  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural);
 }
 
 static void
@@ -867,7 +956,25 @@ gtk_paned_get_preferred_height (GtkWidget *widget,
                                 gint      *minimum,
                                 gint      *natural)
 {
-  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum, natural);
+  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural);
+}
+
+static void
+gtk_paned_get_preferred_width_for_height (GtkWidget *widget,
+                                          gint       height,
+                                          gint      *minimum,
+                                          gint      *natural)
+{
+  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
+}
+
+static void
+gtk_paned_get_preferred_height_for_width (GtkWidget *widget,
+                                          gint       width,
+                                          gint      *minimum,
+                                          gint      *natural)
+{
+  gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
 }
 
 static void
@@ -884,82 +991,170 @@ flip_child (GtkWidget     *widget,
   child_pos->x = 2 * x + width - child_pos->x - child_pos->width;
 }
 
+static void
+gtk_paned_set_child_visible (GtkPaned  *paned,
+                             guint      id,
+                             gboolean   visible)
+{
+  GtkPanedPrivate *priv = paned->priv;
+  GtkWidget *child;
+
+  child = id == CHILD1 ? priv->child1 : priv->child2;
+
+  if (child == NULL)
+    return;
+
+  gtk_widget_set_child_visible (child, visible);
+
+  if (gtk_widget_get_mapped (GTK_WIDGET (paned)))
+    {
+      GdkWindow *window = id == CHILD1 ? priv->child1_window : priv->child2_window;
+
+      if (visible != gdk_window_is_visible (window))
+        {
+          if (visible)
+            gdk_window_show (window);
+          else
+            gdk_window_hide (window);
+        }
+    }
+}
+
+static void
+gtk_paned_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_paned_size_allocate (GtkWidget     *widget,
                          GtkAllocation *allocation)
 {
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
-  GtkAllocation widget_allocation;
 
   gtk_widget_set_allocation (widget, allocation);
 
   if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
       priv->child2 && gtk_widget_get_visible (priv->child2))
     {
-      GtkRequisition child1_requisition;
-      GtkRequisition child2_requisition;
-      GtkAllocation child1_allocation;
-      GtkAllocation child2_allocation;
+      GtkAllocation child1_allocation, window1_allocation;
+      GtkAllocation child2_allocation, window2_allocation;
       GtkAllocation priv_child1_allocation;
       GdkRectangle old_handle_pos;
       gint handle_size;
 
       gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
 
-      gtk_widget_get_preferred_size (priv->child1, &child1_requisition, NULL);
-      gtk_widget_get_preferred_size (priv->child2, &child2_requisition, NULL);
-
       old_handle_pos = priv->handle_pos;
 
-      gtk_widget_get_allocation (widget, &widget_allocation);
-
       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
         {
+          gint child1_width, child2_width;
+
+          gtk_widget_get_preferred_width_for_height (priv->child1,
+                                                     allocation->height,
+                                                     &child1_width, NULL);
+          gtk_widget_get_preferred_width_for_height (priv->child2,
+                                                     allocation->height,
+                                                     &child2_width, NULL);
+
           gtk_paned_calc_position (paned,
-                                   MAX (1, widget_allocation.width - handle_size),
-                                   child1_requisition.width,
-                                   child2_requisition.width);
+                                   MAX (1, allocation->width - handle_size),
+                                   child1_width,
+                                   child2_width);
 
-          priv->handle_pos.x = widget_allocation.x + priv->child1_size;
-          priv->handle_pos.y = widget_allocation.y;
+          priv->handle_pos.x = allocation->x + priv->child1_size;
+          priv->handle_pos.y = allocation->y;
           priv->handle_pos.width = handle_size;
-          priv->handle_pos.height = widget_allocation.height;
+          priv->handle_pos.height = allocation->height;
 
-          child1_allocation.height = child2_allocation.height = allocation->height;
-          child1_allocation.width = MAX (1, priv->child1_size);
-          child1_allocation.x = widget_allocation.x;
-          child1_allocation.y = child2_allocation.y = widget_allocation.y;
+          window1_allocation.height = window2_allocation.height = allocation->height;
+          window1_allocation.width = MAX (1, priv->child1_size);
+          window1_allocation.x = allocation->x;
+          window1_allocation.y = window2_allocation.y = allocation->y;
 
-          child2_allocation.x = child1_allocation.x + priv->child1_size + priv->handle_pos.width;
-          child2_allocation.width = MAX (1, widget_allocation.x + widget_allocation.width - child2_allocation.x);
+          window2_allocation.x = window1_allocation.x + priv->child1_size + priv->handle_pos.width;
+          window2_allocation.width = MAX (1, allocation->x + allocation->width - window2_allocation.x);
 
           if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
             {
-              flip_child (widget, &(child2_allocation));
-              flip_child (widget, &(child1_allocation));
+              flip_child (widget, &(window2_allocation));
+              flip_child (widget, &(window1_allocation));
               flip_child (widget, &(priv->handle_pos));
             }
+
+          child1_allocation.x = child1_allocation.y = 0;
+          child1_allocation.width = window1_allocation.width;
+          child1_allocation.height = window1_allocation.height;
+          if (child1_width > child1_allocation.width)
+            {
+              if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_LTR)
+                child1_allocation.x -= child1_width - child1_allocation.width;
+              child1_allocation.width = child1_width;
+            }
+
+          child2_allocation.x = child2_allocation.y = 0;
+          child2_allocation.width = window2_allocation.width;
+          child2_allocation.height = window2_allocation.height;
+          if (child2_width > child2_allocation.width)
+            {
+              if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
+                child2_allocation.x -= child2_width - child2_allocation.width;
+              child2_allocation.width = child2_width;
+            }
         }
       else
         {
+          gint child1_height, child2_height;
+
+          gtk_widget_get_preferred_height_for_width (priv->child1,
+                                                     allocation->width,
+                                                     &child1_height, NULL);
+          gtk_widget_get_preferred_height_for_width (priv->child2,
+                                                     allocation->width,
+                                                     &child2_height, NULL);
+
           gtk_paned_calc_position (paned,
-                                   MAX (1, widget_allocation.height - handle_size),
-                                   child1_requisition.height,
-                                   child2_requisition.height);
+                                   MAX (1, allocation->height - handle_size),
+                                   child1_height,
+                                   child2_height);
 
-          priv->handle_pos.x = widget_allocation.x;
-          priv->handle_pos.y = widget_allocation.y + priv->child1_size;
-          priv->handle_pos.width = widget_allocation.width;
+          priv->handle_pos.x = allocation->x;
+          priv->handle_pos.y = allocation->y + priv->child1_size;
+          priv->handle_pos.width = allocation->width;
           priv->handle_pos.height = handle_size;
 
-          child1_allocation.width = child2_allocation.width = allocation->width;
-          child1_allocation.height = MAX (1, priv->child1_size);
-          child1_allocation.x = child2_allocation.x = widget_allocation.x;
-          child1_allocation.y = widget_allocation.y;
+          window1_allocation.width = window2_allocation.width = allocation->width;
+          window1_allocation.height = MAX (1, priv->child1_size);
+          window1_allocation.x = window2_allocation.x = allocation->x;
+          window1_allocation.y = allocation->y;
 
-          child2_allocation.y = child1_allocation.y + priv->child1_size + priv->handle_pos.height;
-          child2_allocation.height = MAX (1, widget_allocation.y + widget_allocation.height - child2_allocation.y);
+          window2_allocation.y = window1_allocation.y + priv->child1_size + priv->handle_pos.height;
+          window2_allocation.height = MAX (1, allocation->y + allocation->height - window2_allocation.y);
+
+          child1_allocation.x = child1_allocation.y = 0;
+          child1_allocation.width = window1_allocation.width;
+          child1_allocation.height = window1_allocation.height;
+          if (child1_height > child1_allocation.height)
+            {
+              child1_allocation.y -= child1_height - child1_allocation.height;
+              child1_allocation.height = child1_height;
+            }
+
+          child2_allocation.x = child2_allocation.y = 0;
+          child2_allocation.width = window2_allocation.width;
+          child2_allocation.height = window2_allocation.height;
+          if (child2_height > child2_allocation.height)
+            child2_allocation.height = child2_height;
         }
 
       if (gtk_widget_get_mapped (widget) &&
@@ -1009,39 +1204,129 @@ gtk_paned_size_allocate (GtkWidget     *widget,
            (priv->orientation == GTK_ORIENTATION_VERTICAL &&
             priv_child1_allocation.height < child1_allocation.height)))
        {
-         gtk_widget_size_allocate (priv->child2, &child2_allocation);
-         gtk_widget_size_allocate (priv->child1, &child1_allocation);
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window2_allocation,
+                                    &child2_allocation);
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window1_allocation,
+                                    &child1_allocation);
        }
       else
        {
-         gtk_widget_size_allocate (priv->child1, &child1_allocation);
-         gtk_widget_size_allocate (priv->child2, &child2_allocation);
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window1_allocation,
+                                    &child1_allocation);
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window2_allocation,
+                                    &child2_allocation);
        }
     }
   else
     {
-      GtkAllocation child_allocation;
+      GtkAllocation window_allocation, child_allocation;
 
       if (gtk_widget_get_realized (widget))
        gdk_window_hide (priv->handle);
 
-      if (priv->child1)
-       gtk_widget_set_child_visible (priv->child1, TRUE);
-      if (priv->child2)
-       gtk_widget_set_child_visible (priv->child2, TRUE);
-
-      gtk_widget_get_allocation (widget, &widget_allocation);
-
-      child_allocation.x = widget_allocation.x;
-      child_allocation.y = widget_allocation.y;
+      window_allocation.x = allocation->x;
+      window_allocation.y = allocation->y;
+      window_allocation.width = allocation->width;
+      window_allocation.height = allocation->height;
+      child_allocation.x = child_allocation.y = 0;
       child_allocation.width = allocation->width;
       child_allocation.height = allocation->height;
 
       if (priv->child1 && gtk_widget_get_visible (priv->child1))
-       gtk_widget_size_allocate (priv->child1, &child_allocation);
+        {
+          gtk_paned_set_child_visible (paned, 0, TRUE);
+          if (priv->child2)
+            gtk_paned_set_child_visible (paned, 1, FALSE);
+
+          gtk_paned_child_allocate (priv->child1,
+                                    priv->child1_window,
+                                    &window_allocation,
+                                    &child_allocation);
+        }
       else if (priv->child2 && gtk_widget_get_visible (priv->child2))
-       gtk_widget_size_allocate (priv->child2, &child_allocation);
+        {
+          gtk_paned_set_child_visible (paned, 1, TRUE);
+          if (priv->child1)
+            gtk_paned_set_child_visible (paned, 0, FALSE);
+
+          gtk_paned_child_allocate (priv->child2,
+                                    priv->child2_window,
+                                    &window_allocation,
+                                    &child_allocation);
+        }
+      else
+        {
+          if (priv->child1)
+            gtk_paned_set_child_visible (paned, 0, FALSE);
+          if (priv->child2)
+            gtk_paned_set_child_visible (paned, 1, FALSE);
+        }
+    }
+}
+
+static GdkWindow *
+gtk_paned_create_child_window (GtkPaned  *paned,
+                               GtkWidget *child) /* may be NULL */
+{
+  GtkWidget *widget = GTK_WIDGET (paned);
+  GtkPanedPrivate *priv = paned->priv;
+  GdkWindow *window;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+  if (child)
+    {
+      GtkAllocation allocation;
+      int handle_size;
+
+      gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
+
+      gtk_widget_get_allocation (widget, &allocation);
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
+          child == priv->child2 && priv->child1 &&
+          gtk_widget_get_visible (priv->child1))
+        attributes.x = priv->handle_pos.x + handle_size;
+      else
+        attributes.x = allocation.x;
+      if (priv->orientation == GTK_ORIENTATION_VERTICAL &&
+          child == priv->child2 && priv->child1 &&
+          gtk_widget_get_visible (priv->child1))
+        attributes.y = priv->handle_pos.y + handle_size;
+      else
+        attributes.y = allocation.y;
+
+      gtk_widget_get_allocation (child, &allocation);
+      attributes.width = allocation.width;
+      attributes.height = allocation.height;
+      attributes_mask = GDK_WA_X | GDK_WA_Y;
     }
+  else
+    {
+      attributes.width = 1;
+      attributes.height = 1;
+      attributes_mask = 0;
+    }
+
+  window = gdk_window_new (gtk_widget_get_window (widget),
+                           &attributes, attributes_mask);
+  gtk_widget_register_window (widget, window);
+  gtk_style_context_set_background (gtk_widget_get_style_context (widget), window);
+
+  if (child)
+    gtk_widget_set_parent_window (child, window);
+
+  return window;
 }
 
 static void
@@ -1070,8 +1355,7 @@ gtk_paned_realize (GtkWidget *widget)
                            GDK_BUTTON_RELEASE_MASK |
                            GDK_ENTER_NOTIFY_MASK |
                            GDK_LEAVE_NOTIFY_MASK |
-                           GDK_POINTER_MOTION_MASK |
-                           GDK_POINTER_MOTION_HINT_MASK);
+                           GDK_POINTER_MOTION_MASK);
   attributes_mask = GDK_WA_X | GDK_WA_Y;
   if (gtk_widget_is_sensitive (widget))
     {
@@ -1082,15 +1366,12 @@ gtk_paned_realize (GtkWidget *widget)
 
   priv->handle = gdk_window_new (window,
                                  &attributes, attributes_mask);
-  gdk_window_set_user_data (priv->handle, paned);
+  gtk_widget_register_window (widget, priv->handle);
   if (attributes_mask & GDK_WA_CURSOR)
-    gdk_cursor_unref (attributes.cursor);
-
-  gtk_widget_style_attach (widget);
+    g_object_unref (attributes.cursor);
 
-  if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
-      priv->child2 && gtk_widget_get_visible (priv->child2))
-    gdk_window_show (priv->handle);
+  priv->child1_window = gtk_paned_create_child_window (paned, priv->child1);
+  priv->child2_window = gtk_paned_create_child_window (paned, priv->child2);
 }
 
 static void
@@ -1099,9 +1380,21 @@ gtk_paned_unrealize (GtkWidget *widget)
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
 
+  if (priv->child2)
+    gtk_widget_set_parent_window (priv->child2, NULL);
+  gtk_widget_unregister_window (widget, priv->child2_window);
+  gdk_window_destroy (priv->child2_window);
+  priv->child2_window = NULL;
+
+  if (priv->child1)
+    gtk_widget_set_parent_window (priv->child1, NULL);
+  gtk_widget_unregister_window (widget, priv->child1_window);
+  gdk_window_destroy (priv->child1_window);
+  priv->child1_window = NULL;
+
   if (priv->handle)
     {
-      gdk_window_set_user_data (priv->handle, NULL);
+      gtk_widget_unregister_window (widget, priv->handle);
       gdk_window_destroy (priv->handle);
       priv->handle = NULL;
     }
@@ -1120,7 +1413,14 @@ gtk_paned_map (GtkWidget *widget)
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
 
-  gdk_window_show (priv->handle);
+  if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
+      priv->child2 && gtk_widget_get_visible (priv->child2))
+    gdk_window_show (priv->handle);
+
+  if (priv->child1 && gtk_widget_get_visible (priv->child1) && gtk_widget_get_child_visible (priv->child1))
+    gdk_window_show (priv->child1_window);
+  if (priv->child2 && gtk_widget_get_visible (priv->child2) && gtk_widget_get_child_visible (priv->child2))
+    gdk_window_show (priv->child2_window);
 
   GTK_WIDGET_CLASS (gtk_paned_parent_class)->map (widget);
 }
@@ -1132,6 +1432,11 @@ gtk_paned_unmap (GtkWidget *widget)
   GtkPanedPrivate *priv = paned->priv;
 
   gdk_window_hide (priv->handle);
+  
+  if (gdk_window_is_visible (priv->child1_window))
+    gdk_window_hide (priv->child1_window);
+  if (gdk_window_is_visible (priv->child2_window))
+    gdk_window_hide (priv->child2_window);
 
   GTK_WIDGET_CLASS (gtk_paned_parent_class)->unmap (widget);
 }
@@ -1143,31 +1448,57 @@ gtk_paned_draw (GtkWidget *widget,
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
 
-  if (gtk_widget_get_visible (widget) && gtk_widget_get_mapped (widget) &&
+  if (gtk_cairo_should_draw_window (cr, priv->child1_window))
+    {
+      cairo_save (cr);
+      gtk_cairo_transform_to_window (cr, widget, priv->child1_window);
+      gtk_render_background (gtk_widget_get_style_context (widget),
+                             cr,
+                             0, 0,
+                             gdk_window_get_width (priv->child1_window),
+                             gdk_window_get_height (priv->child1_window));
+      cairo_restore (cr);
+    }
+
+  if (gtk_cairo_should_draw_window (cr, priv->child2_window))
+    {
+      cairo_save (cr);
+      gtk_cairo_transform_to_window (cr, widget, priv->child2_window);
+      gtk_render_background (gtk_widget_get_style_context (widget),
+                             cr,
+                             0, 0,
+                             gdk_window_get_width (priv->child2_window),
+                             gdk_window_get_height (priv->child2_window));
+      cairo_restore (cr);
+    }
+
+  if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)) &&
       priv->child1 && gtk_widget_get_visible (priv->child1) &&
       priv->child2 && gtk_widget_get_visible (priv->child2))
     {
-      GtkStateType state;
+      GtkStyleContext *context;
+      GtkStateFlags state;
       GtkAllocation allocation;
 
       gtk_widget_get_allocation (widget, &allocation);
-      
+      context = gtk_widget_get_style_context (widget);
+      state = gtk_widget_get_state_flags (widget);
+
       if (gtk_widget_is_focus (widget))
-       state = GTK_STATE_SELECTED;
-      else if (priv->handle_prelit)
-       state = GTK_STATE_PRELIGHT;
-      else
-       state = gtk_widget_get_state (widget);
-
-      gtk_paint_handle (gtk_widget_get_style (widget),
-                        cr,
-                       state, GTK_SHADOW_NONE,
-                       widget, "paned",
-                       priv->handle_pos.x - allocation.x,
-                        priv->handle_pos.y - allocation.y,
-                       priv->handle_pos.width,
-                        priv->handle_pos.height,
-                       !priv->orientation);
+       state |= GTK_STATE_FLAG_SELECTED;
+      if (priv->handle_prelit)
+       state |= GTK_STATE_FLAG_PRELIGHT;
+
+      gtk_style_context_save (context);
+      gtk_style_context_set_state (context, state);
+      gtk_style_context_add_class (context, GTK_STYLE_CLASS_PANE_SEPARATOR);
+      gtk_render_handle (context, cr,
+                         priv->handle_pos.x - allocation.x,
+                         priv->handle_pos.y - allocation.y,
+                         priv->handle_pos.width,
+                         priv->handle_pos.height);
+
+      gtk_style_context_restore (context);
     }
 
   /* Chain up to draw children */
@@ -1191,7 +1522,10 @@ is_rtl (GtkPaned *paned)
 }
 
 static void
-update_drag (GtkPaned *paned)
+update_drag (GtkPaned         *paned,
+             /* relative to priv->handle */
+             int               xpos,
+             int               ypos)
 {
   GtkPanedPrivate *priv = paned->priv;
   GtkAllocation allocation;
@@ -1199,11 +1533,18 @@ update_drag (GtkPaned *paned)
   gint pos;
   gint handle_size;
   gint size;
+  gint x, y;
 
+  gdk_window_get_position (priv->handle, &x, &y);
+  gtk_widget_get_allocation (widget, &allocation);
   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    gtk_widget_get_pointer (widget, &pos, NULL);
+    {
+      pos = xpos + x - allocation.x;
+    }
   else
-    gtk_widget_get_pointer (widget, NULL, &pos);
+    {
+      pos = ypos + y - allocation.y;
+    }
 
   pos -= priv->drag_pos;
 
@@ -1213,7 +1554,6 @@ update_drag (GtkPaned *paned)
                            "handle-size", &handle_size,
                            NULL);
 
-      gtk_widget_get_allocation (widget, &allocation);
       size = allocation.width - pos - handle_size;
     }
   else
@@ -1235,7 +1575,7 @@ gtk_paned_enter (GtkWidget        *widget,
   GtkPanedPrivate *priv = paned->priv;
 
   if (priv->in_drag)
-    update_drag (paned);
+    update_drag (paned, event->x, event->y);
   else
     {
       priv->handle_prelit = TRUE;
@@ -1257,7 +1597,7 @@ gtk_paned_leave (GtkWidget        *widget,
   GtkPanedPrivate *priv = paned->priv;
 
   if (priv->in_drag)
-    update_drag (paned);
+    update_drag (paned, event->x, event->y);
   else
     {
       priv->handle_prelit = FALSE;
@@ -1297,15 +1637,14 @@ gtk_paned_button_press (GtkWidget      *widget,
   GtkPanedPrivate *priv = paned->priv;
 
   if (!priv->in_drag &&
-      (event->window == priv->handle) && (event->button == 1))
+      (event->window == priv->handle) && (event->button == GDK_BUTTON_PRIMARY))
     {
       /* We need a server grab here, not gtk_grab_add(), since
        * we don't want to pass events on to the widget's children */
       if (gdk_device_grab (event->device,
                            priv->handle,
                            GDK_OWNERSHIP_WINDOW, FALSE,
-                           GDK_POINTER_MOTION_HINT_MASK
-                           | GDK_BUTTON1_MOTION_MASK
+                           GDK_BUTTON1_MOTION_MASK
                            | GDK_BUTTON_RELEASE_MASK
                            | GDK_ENTER_NOTIFY_MASK
                            | GDK_LEAVE_NOTIFY_MASK,
@@ -1371,8 +1710,8 @@ gtk_paned_grab_notify (GtkWidget *widget,
 }
 
 static void
-gtk_paned_state_changed (GtkWidget    *widget,
-                         GtkStateType  previous_state)
+gtk_paned_state_flags_changed (GtkWidget     *widget,
+                               GtkStateFlags  previous_state)
 {
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
@@ -1389,7 +1728,7 @@ gtk_paned_state_changed (GtkWidget    *widget,
       gdk_window_set_cursor (priv->handle, cursor);
 
       if (cursor)
-        gdk_cursor_unref (cursor);
+        g_object_unref (cursor);
     }
 }
 
@@ -1400,7 +1739,7 @@ gtk_paned_button_release (GtkWidget      *widget,
   GtkPaned *paned = GTK_PANED (widget);
   GtkPanedPrivate *priv = paned->priv;
 
-  if (priv->in_drag && (event->button == 1))
+  if (priv->in_drag && (event->button == GDK_BUTTON_PRIMARY))
     {
       stop_drag (paned);
 
@@ -1419,7 +1758,7 @@ gtk_paned_motion (GtkWidget      *widget,
 
   if (priv->in_drag)
     {
-      update_drag (paned);
+      update_drag (paned, event->x, event->y);
       return TRUE;
     }
   
@@ -1444,6 +1783,15 @@ gtk_paned_new (GtkOrientation orientation)
                        NULL);
 }
 
+/**
+ * gtk_paned_add1:
+ * @paned: a paned widget
+ * @child: the child to add
+ *
+ * Adds a child to the top or left pane with default parameters. This is
+ * equivalent to
+ * <literal>gtk_paned_pack1 (paned, child, FALSE, TRUE)</literal>.
+ */
 void
 gtk_paned_add1 (GtkPaned  *paned,
                GtkWidget *widget)
@@ -1451,6 +1799,15 @@ gtk_paned_add1 (GtkPaned  *paned,
   gtk_paned_pack1 (paned, widget, FALSE, TRUE);
 }
 
+/**
+ * gtk_paned_add2:
+ * @paned: a paned widget
+ * @child: the child to add
+ *
+ * Adds a child to the bottom or right pane with default parameters. This
+ * is equivalent to
+ * <literal>gtk_paned_pack2 (paned, child, TRUE, TRUE)</literal>.
+ */
 void
 gtk_paned_add2 (GtkPaned  *paned,
                GtkWidget *widget)
@@ -1458,6 +1815,15 @@ gtk_paned_add2 (GtkPaned  *paned,
   gtk_paned_pack2 (paned, widget, TRUE, TRUE);
 }
 
+/**
+ * gtk_paned_pack1:
+ * @paned: a paned widget
+ * @child: the child to add
+ * @resize: should this child expand when the paned widget is resized.
+ * @shrink: can this child be made smaller than its requisition.
+ *
+ * Adds a child to the top or left pane.
+ */
 void
 gtk_paned_pack1 (GtkPaned  *paned,
                 GtkWidget *child,
@@ -1477,10 +1843,20 @@ gtk_paned_pack1 (GtkPaned  *paned,
       priv->child1_resize = resize;
       priv->child1_shrink = shrink;
 
+      gtk_widget_set_parent_window (child, priv->child1_window);
       gtk_widget_set_parent (child, GTK_WIDGET (paned));
     }
 }
 
+/**
+ * gtk_paned_pack2:
+ * @paned: a paned widget
+ * @child: the child to add
+ * @resize: should this child expand when the paned widget is resized.
+ * @shrink: can this child be made smaller than its requisition.
+ *
+ * Adds a child to the bottom or right pane.
+ */
 void
 gtk_paned_pack2 (GtkPaned  *paned,
                 GtkWidget *child,
@@ -1500,6 +1876,7 @@ gtk_paned_pack2 (GtkPaned  *paned,
       priv->child2_resize = resize;
       priv->child2_shrink = shrink;
 
+      gtk_widget_set_parent_window (child, priv->child2_window);
       gtk_widget_set_parent (child, GTK_WIDGET (paned));
     }
 }
@@ -1537,6 +1914,9 @@ gtk_paned_remove (GtkContainer *container,
 
   if (priv->child1 == widget)
     {
+      if (priv->child1_window && gdk_window_is_visible (priv->child1_window))
+        gdk_window_hide (priv->child1_window);
+
       gtk_widget_unparent (widget);
 
       priv->child1 = NULL;
@@ -1546,6 +1926,9 @@ gtk_paned_remove (GtkContainer *container,
     }
   else if (priv->child2 == widget)
     {
+      if (priv->child2_window && gdk_window_is_visible (priv->child2_window))
+        gdk_window_hide (priv->child2_window);
+
       gtk_widget_unparent (widget);
 
       priv->child2 = NULL;
@@ -1736,10 +2119,10 @@ gtk_paned_calc_position (GtkPaned *paned,
                              priv->max_position);
 
   if (priv->child1)
-    gtk_widget_set_child_visible (priv->child1, priv->child1_size != 0);
+    gtk_paned_set_child_visible (paned, 0, priv->child1_size != 0);
   
   if (priv->child2)
-    gtk_widget_set_child_visible (priv->child2, priv->child1_size != allocation); 
+    gtk_paned_set_child_visible (paned, 1, priv->child1_size != allocation); 
 
   g_object_freeze_notify (G_OBJECT (paned));
   if (priv->child1_size != old_position)