]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkpaned.c
Add a ::group-changed signal emitted when the radio button/menu item is
[~andy/gtk] / gtk / gtkpaned.c
index cb078fb3ede83c8cdd71581b9c7348bbef265053..288dad72181e0ff0d5fb525573e86ba9ac745627 100644 (file)
 enum {
   PROP_0,
   PROP_POSITION,
-  PROP_POSITION_SET
+  PROP_POSITION_SET,
+  PROP_MIN_POSITION,
+  PROP_MAX_POSITION
+};
+
+enum {
+  CHILD_PROP_0,
+  CHILD_PROP_RESIZE,
+  CHILD_PROP_SHRINK
 };
 
 enum {
@@ -59,6 +67,17 @@ static void     gtk_paned_get_property          (GObject          *object,
                                                 guint             prop_id,
                                                 GValue           *value,
                                                 GParamSpec       *pspec);
+static void gtk_paned_set_child_property        (GtkContainer      *container,
+                                                GtkWidget         *child,
+                                                guint              property_id,
+                                                const GValue      *value,
+                                                GParamSpec        *pspec);
+static void gtk_paned_get_child_property        (GtkContainer      *container,
+                                                GtkWidget         *child,
+                                                guint              property_id,
+                                                GValue            *value,
+                                                GParamSpec        *pspec);
+static void     gtk_paned_finalize              (GObject          *object);
 static void     gtk_paned_realize               (GtkWidget        *widget);
 static void     gtk_paned_unrealize             (GtkWidget        *widget);
 static void     gtk_paned_map                   (GtkWidget        *widget);
@@ -69,12 +88,12 @@ static gboolean gtk_paned_enter                 (GtkWidget        *widget,
                                                 GdkEventCrossing *event);
 static gboolean gtk_paned_leave                 (GtkWidget        *widget,
                                                 GdkEventCrossing *event);
-static gboolean gtk_paned_button_press         (GtkWidget      *widget,
-                                                GdkEventButton *event);
-static gboolean gtk_paned_button_release       (GtkWidget      *widget,
-                                                GdkEventButton *event);
-static gboolean gtk_paned_motion               (GtkWidget      *widget,
-                                                GdkEventMotion *event);
+static gboolean gtk_paned_button_press          (GtkWidget        *widget,
+                                                GdkEventButton   *event);
+static gboolean gtk_paned_button_release        (GtkWidget        *widget,
+                                                GdkEventButton   *event);
+static gboolean gtk_paned_motion                (GtkWidget        *widget,
+                                                GdkEventMotion   *event);
 static gboolean gtk_paned_focus                 (GtkWidget        *widget,
                                                 GtkDirectionType  direction);
 static void     gtk_paned_add                   (GtkContainer     *container,
@@ -89,6 +108,8 @@ static void     gtk_paned_set_focus_child       (GtkContainer     *container,
                                                 GtkWidget        *child);
 static void     gtk_paned_set_saved_focus       (GtkPaned         *paned,
                                                 GtkWidget        *widget);
+static void     gtk_paned_set_first_paned       (GtkPaned         *paned,
+                                                GtkPaned         *first_paned);
 static void     gtk_paned_set_last_child1_focus (GtkPaned         *paned,
                                                 GtkWidget        *widget);
 static void     gtk_paned_set_last_child2_focus (GtkPaned         *paned,
@@ -102,30 +123,36 @@ static gboolean gtk_paned_move_handle           (GtkPaned         *paned,
 static gboolean gtk_paned_accept_position       (GtkPaned         *paned);
 static gboolean gtk_paned_cancel_position       (GtkPaned         *paned);
 static gboolean gtk_paned_toggle_handle_focus   (GtkPaned         *paned);
-static GtkType  gtk_paned_child_type            (GtkContainer     *container);
+
+static GType    gtk_paned_child_type             (GtkContainer     *container);
 
 static GtkContainerClass *parent_class = NULL;
 
+struct _GtkPanedPrivate
+{
+  GtkWidget *saved_focus;
+  GtkPaned *first_paned;
+};
 
-GtkType
+GType
 gtk_paned_get_type (void)
 {
-  static GtkType paned_type = 0;
+  static GType paned_type = 0;
   
   if (!paned_type)
     {
       static const GTypeInfo paned_info =
       {
        sizeof (GtkPanedClass),
-       NULL,            /* base_init */
-       NULL,            /* base_finalize */
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
        (GClassInitFunc) gtk_paned_class_init,
-       NULL,            /* class_finalize */
-       NULL,            /* class_data */
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
        sizeof (GtkPaned),
-       0,               /* n_preallocs */
+       0,              /* n_preallocs */
        (GInstanceInitFunc) gtk_paned_init,
-       NULL,            /* value_table */
+       NULL,           /* value_table */
       };
 
       paned_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkPaned",
@@ -139,15 +166,12 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 static void
 add_tab_bindings (GtkBindingSet    *binding_set,
-                 GdkModifierType   modifiers,
-                 gboolean          reverse)
+                 GdkModifierType   modifiers)
 {
   gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
-                                "cycle_handle_focus", 1,
-                                G_TYPE_BOOLEAN, reverse);
+                                "toggle_handle_focus", 0);
   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
-                                "cycle_handle_focus", 1,
-                                G_TYPE_BOOLEAN, reverse);
+                               "toggle_handle_focus", 0);
 }
 
 static void
@@ -175,10 +199,11 @@ gtk_paned_class_init (GtkPanedClass *class)
   container_class = (GtkContainerClass *) class;
   paned_class = (GtkPanedClass *) class;
 
-  parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
+  parent_class = g_type_class_peek_parent (class);
 
   object_class->set_property = gtk_paned_set_property;
   object_class->get_property = gtk_paned_get_property;
+  object_class->finalize = gtk_paned_finalize;
 
   widget_class->realize = gtk_paned_realize;
   widget_class->unrealize = gtk_paned_unrealize;
@@ -197,6 +222,8 @@ gtk_paned_class_init (GtkPanedClass *class)
   container_class->forall = gtk_paned_forall;
   container_class->child_type = gtk_paned_child_type;
   container_class->set_focus_child = gtk_paned_set_focus_child;
+  container_class->set_child_property = gtk_paned_set_child_property;
+  container_class->get_child_property = gtk_paned_get_child_property;
 
   paned_class->cycle_child_focus = gtk_paned_cycle_child_focus;
   paned_class->toggle_handle_focus = gtk_paned_toggle_handle_focus;
@@ -204,12 +231,12 @@ gtk_paned_class_init (GtkPanedClass *class)
   paned_class->cycle_handle_focus = gtk_paned_cycle_handle_focus;
   paned_class->accept_position = gtk_paned_accept_position;
   paned_class->cancel_position = gtk_paned_cancel_position;
-  
+
   g_object_class_install_property (object_class,
                                   PROP_POSITION,
                                   g_param_spec_int ("position",
-                                                    _("Position"),
-                                                    _("Position of paned separator in pixels (0 means all the way to the left/top)"),
+                                                    P_("Position"),
+                                                    P_("Position of paned separator in pixels (0 means all the way to the left/top)"),
                                                     0,
                                                     G_MAXINT,
                                                     0,
@@ -217,19 +244,86 @@ gtk_paned_class_init (GtkPanedClass *class)
   g_object_class_install_property (object_class,
                                   PROP_POSITION_SET,
                                   g_param_spec_boolean ("position_set",
-                                                        _("Position Set"),
-                                                        _("TRUE if the Position property should be used"),
+                                                        P_("Position Set"),
+                                                        P_("TRUE if the Position property should be used"),
                                                         FALSE,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
                                   
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("handle_size",
-                                                            _("Handle Size"),
-                                                            _("Width of handle"),
+                                                            P_("Handle Size"),
+                                                            P_("Width of handle"),
                                                             0,
                                                             G_MAXINT,
                                                             5,
                                                             G_PARAM_READABLE));
+  /**
+   * GtkPaned:min-position:
+   *
+   * The smallest possible value for the position property. This property is derived from the
+   * size and shrinkability of the widget's children.
+   *
+   * Since: 2.4
+   */
+  g_object_class_install_property (object_class,
+                                  PROP_MIN_POSITION,
+                                  g_param_spec_int ("min_position",
+                                                    P_("Minimal Position"),
+                                                    P_("Smallest possible value for the \"position\" property"),
+                                                    0,
+                                                    G_MAXINT,
+                                                    0,
+                                                    G_PARAM_READABLE));
+
+  /**
+   * GtkPaned:max-position:
+   *
+   * The largest possible value for the position property. This property is derived from the
+   * size and shrinkability of the widget's children.
+   *
+   * Since: 2.4
+   */
+  g_object_class_install_property (object_class,
+                                  PROP_MIN_POSITION,
+                                  g_param_spec_int ("max_position",
+                                                    P_("Maximal Position"),
+                                                    P_("Largest possible value for the \"position\" property"),
+                                                    0,
+                                                    G_MAXINT,
+                                                    G_MAXINT,
+                                                    G_PARAM_READABLE));
+
+/**
+ * GtkPaned:resize:
+ *
+ * The "resize" child property determines whether the child expands and 
+ * shrinks along with the paned widget.
+ * 
+ * Since: 2.4 
+ */
+  gtk_container_class_install_child_property (container_class,
+                                             CHILD_PROP_RESIZE,
+                                             g_param_spec_boolean ("resize", 
+                                                                   P_("Resize"),
+                                                                   P_("If TRUE, the child expands and shrinks along with the paned widget"),
+                                                                   TRUE,
+                                                                   G_PARAM_READWRITE));
+
+/**
+ * GtkPaned:shrink:
+ *
+ * The "shrink" child property determines whether the child can be made 
+ * smaller than its requisition.
+ * 
+ * Since: 2.4 
+ */
+  gtk_container_class_install_child_property (container_class,
+                                             CHILD_PROP_SHRINK,
+                                             g_param_spec_boolean ("shrink", 
+                                                                   P_("Shrink"),
+                                                                   P_("If TRUE, the child can be made smaller than its requisition"),
+                                                                   TRUE,
+                                                                   G_PARAM_READWRITE));
 
   signals [CYCLE_HANDLE_FOCUS] =
     g_signal_new ("cycle_child_focus",
@@ -288,7 +382,7 @@ gtk_paned_class_init (GtkPanedClass *class)
                  _gtk_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);
 
-  binding_set = gtk_binding_set_by_class (object_class);
+  binding_set = gtk_binding_set_by_class (class);
 
   /* F6 and friends */
   gtk_binding_entry_add_signal (binding_set,                           
@@ -303,12 +397,18 @@ gtk_paned_class_init (GtkPanedClass *class)
   /* F8 and friends */
   gtk_binding_entry_add_signal (binding_set,
                                GDK_F8, 0,
-                               "toggle_handle_focus", 0);
+                               "cycle_handle_focus", 1,
+                               G_TYPE_BOOLEAN, FALSE);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_F8, GDK_SHIFT_MASK,
+                               "cycle_handle_focus", 1,
+                               G_TYPE_BOOLEAN, TRUE);
  
-  add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
-  add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
-  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
+  add_tab_bindings (binding_set, 0);
+  add_tab_bindings (binding_set, GDK_CONTROL_MASK);
+  add_tab_bindings (binding_set, GDK_SHIFT_MASK);
+  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
 
   /* accept and cancel positions */
   gtk_binding_entry_add_signal (binding_set,
@@ -359,13 +459,13 @@ gtk_paned_class_init (GtkPanedClass *class)
   add_move_binding (binding_set, GDK_KP_End, 0, GTK_SCROLL_END);
 }
 
-static GtkType
+static GType
 gtk_paned_child_type (GtkContainer *container)
 {
   if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
     return GTK_TYPE_WIDGET;
   else
-    return GTK_TYPE_NONE;
+    return G_TYPE_NONE;
 }
 
 static void
@@ -385,7 +485,7 @@ gtk_paned_init (GtkPaned *paned)
   paned->last_allocation = -1;
   paned->in_drag = FALSE;
 
-  paned->saved_focus = NULL;
+  paned->priv = g_new0 (GtkPanedPrivate, 1);
   paned->last_child1_focus = NULL;
   paned->last_child2_focus = NULL;
   paned->in_recursion = FALSE;
@@ -437,12 +537,110 @@ gtk_paned_get_property (GObject        *object,
     case PROP_POSITION_SET:
       g_value_set_boolean (value, paned->position_set);
       break;
+    case PROP_MIN_POSITION:
+      g_value_set_int (value, paned->min_position);
+      break;
+    case PROP_MAX_POSITION:
+      g_value_set_int (value, paned->max_position);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
     }
 }
 
+static void
+gtk_paned_set_child_property (GtkContainer    *container,
+                             GtkWidget       *child,
+                             guint            property_id,
+                             const GValue    *value,
+                             GParamSpec      *pspec)
+{
+  GtkPaned *paned = GTK_PANED (container);
+  gboolean old_value, new_value;
+
+  g_assert (child == paned->child1 || child == paned->child2);
+
+  new_value = g_value_get_boolean (value);
+  switch (property_id)
+    {
+    case CHILD_PROP_RESIZE:
+      if (child == paned->child1)
+       {
+         old_value = paned->child1_resize;
+         paned->child1_resize = new_value;
+       }
+      else
+       {
+         old_value = paned->child2_resize;
+         paned->child2_resize = new_value;
+       }
+      break;
+    case CHILD_PROP_SHRINK:
+      if (child == paned->child1)
+       {
+         old_value = paned->child1_shrink;
+         paned->child1_shrink = new_value;
+       }
+      else
+       {
+         old_value = paned->child2_shrink;
+         paned->child2_shrink = new_value;
+       }
+      break;
+    default:
+      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+      old_value = -1; /* quiet gcc */
+      break;
+    }
+  if (old_value != new_value)
+    gtk_widget_queue_resize (GTK_WIDGET (container));
+}
+
+static void
+gtk_paned_get_child_property (GtkContainer *container,
+                             GtkWidget    *child,
+                             guint         property_id,
+                             GValue       *value,
+                             GParamSpec   *pspec)
+{
+  GtkPaned *paned = GTK_PANED (container);
+
+  g_assert (child == paned->child1 || child == paned->child2);
+  
+  switch (property_id)
+    {
+    case CHILD_PROP_RESIZE:
+      if (child == paned->child1)
+       g_value_set_boolean (value, paned->child1_resize);
+      else
+       g_value_set_boolean (value, paned->child2_resize);
+      break;
+    case CHILD_PROP_SHRINK:
+      if (child == paned->child1)
+       g_value_set_boolean (value, paned->child1_shrink);
+      else
+       g_value_set_boolean (value, paned->child2_shrink);
+      break;
+    default:
+      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_paned_finalize (GObject *object)
+{
+  GtkPaned *paned = GTK_PANED (object);
+  
+  gtk_paned_set_saved_focus (paned, NULL);
+  gtk_paned_set_first_paned (paned, NULL);
+
+  g_free (paned->priv);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 static void
 gtk_paned_realize (GtkWidget *widget)
 {
@@ -454,7 +652,7 @@ gtk_paned_realize (GtkWidget *widget)
   paned = GTK_PANED (widget);
 
   widget->window = gtk_widget_get_parent_window (widget);
-  gdk_window_ref (widget->window);
+  g_object_ref (widget->window);
   
   attributes.window_type = GDK_WINDOW_CHILD;
   attributes.wclass = GDK_INPUT_ONLY;
@@ -476,7 +674,7 @@ gtk_paned_realize (GtkWidget *widget)
   paned->handle = gdk_window_new (widget->window,
                                  &attributes, attributes_mask);
   gdk_window_set_user_data (paned->handle, paned);
-  gdk_cursor_destroy (attributes.cursor);
+  gdk_cursor_unref (attributes.cursor);
 
   widget->style = gtk_style_attach (widget->style, widget->window);
 
@@ -492,7 +690,7 @@ gtk_paned_unrealize (GtkWidget *widget)
 
   if (paned->xor_gc)
     {
-      gdk_gc_destroy (paned->xor_gc);
+      g_object_unref (paned->xor_gc);
       paned->xor_gc = NULL;
     }
 
@@ -506,6 +704,7 @@ gtk_paned_unrealize (GtkWidget *widget)
   gtk_paned_set_last_child1_focus (paned, NULL);
   gtk_paned_set_last_child2_focus (paned, NULL);
   gtk_paned_set_saved_focus (paned, NULL);
+  gtk_paned_set_first_paned (paned, NULL);
   
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
@@ -577,6 +776,18 @@ gtk_paned_expose (GtkWidget      *widget,
   return FALSE;
 }
 
+static gboolean
+is_rtl (GtkPaned *paned)
+{
+  if (paned->orientation == GTK_ORIENTATION_VERTICAL &&
+      gtk_widget_get_direction (GTK_WIDGET (paned)) == GTK_TEXT_DIR_RTL)
+    {
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static void
 update_drag (GtkPaned *paned)
 {
@@ -589,9 +800,23 @@ update_drag (GtkPaned *paned)
   else
     gtk_widget_get_pointer (GTK_WIDGET (paned), &pos, NULL);
 
-  gtk_widget_style_get (GTK_WIDGET (paned), "handle_size", &handle_size, NULL);
+  pos -= paned->drag_pos;
+
+  if (is_rtl (paned))
+    {
+      gtk_widget_style_get (GTK_WIDGET (paned),
+                           "handle_size", &handle_size,
+                           NULL);
+      
+      size = GTK_WIDGET (paned)->allocation.width - pos - handle_size;
+    }
+  else
+    {
+      size = pos;
+    }
+
+  size -= GTK_CONTAINER (paned)->border_width;
   
-  size = pos - GTK_CONTAINER (paned)->border_width - paned->drag_pos;
   size = CLAMP (size, paned->min_position, paned->max_position);
 
   if (size != paned->child1_size)
@@ -901,6 +1126,42 @@ gtk_paned_set_position (GtkPaned *paned,
   gtk_widget_queue_resize (GTK_WIDGET (paned));
 }
 
+/**
+ * gtk_paned_get_child1:
+ * @paned: a #GtkPaned widget
+ * 
+ * Obtains the first child of the paned widget.
+ * 
+ * Return value: first child, or %NULL if it is not set.
+ *
+ * Since: 2.4
+ **/
+GtkWidget *
+gtk_paned_get_child1 (GtkPaned *paned)
+{
+  g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
+
+  return paned->child1;
+}
+
+/**
+ * gtk_paned_get_child2:
+ * @paned: a #GtkPaned widget
+ * 
+ * Obtains the second child of the paned widget.
+ * 
+ * Return value: second child, or %NULL if it is not set.
+ *
+ * Since: 2.4
+ **/
+GtkWidget *
+gtk_paned_get_child2 (GtkPaned *paned)
+{
+  g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
+
+  return paned->child2;
+}
+
 void
 gtk_paned_compute_position (GtkPaned *paned,
                            gint      allocation,
@@ -908,10 +1169,14 @@ gtk_paned_compute_position (GtkPaned *paned,
                            gint      child2_req)
 {
   gint old_position;
+  gint old_min_position;
+  gint old_max_position;
   
   g_return_if_fail (GTK_IS_PANED (paned));
 
   old_position = paned->child1_size;
+  old_min_position = paned->min_position;
+  old_max_position = paned->max_position;
 
   paned->min_position = paned->child1_shrink ? 0 : child1_req;
 
@@ -922,7 +1187,7 @@ gtk_paned_compute_position (GtkPaned *paned,
   if (!paned->position_set)
     {
       if (paned->child1_resize && !paned->child2_resize)
-       paned->child1_size = MAX (1, allocation - child2_req);
+       paned->child1_size = MAX (0, allocation - child2_req);
       else if (!paned->child1_resize && paned->child2_resize)
        paned->child1_size = child1_req;
       else if (child1_req + child2_req != 0)
@@ -948,8 +1213,17 @@ gtk_paned_compute_position (GtkPaned *paned,
                              paned->min_position,
                              paned->max_position);
 
+  gtk_widget_set_child_visible (paned->child1, paned->child1_size != 0);
+  gtk_widget_set_child_visible (paned->child2, paned->child1_size != allocation);
+
+  g_object_freeze_notify (G_OBJECT (paned));
   if (paned->child1_size != old_position)
     g_object_notify (G_OBJECT (paned), "position");
+  if (paned->min_position != old_min_position)
+    g_object_notify (G_OBJECT (paned), "min_position");
+  if (paned->max_position != old_max_position)
+    g_object_notify (G_OBJECT (paned), "max_position");
+  g_object_thaw_notify (G_OBJECT (paned));
 
   paned->last_allocation = allocation;
 }
@@ -957,15 +1231,29 @@ gtk_paned_compute_position (GtkPaned *paned,
 static void
 gtk_paned_set_saved_focus (GtkPaned *paned, GtkWidget *widget)
 {
-  if (paned->saved_focus)
-    g_object_remove_weak_pointer (G_OBJECT (paned->saved_focus),
-                                 (gpointer *)&(paned->saved_focus));
+  if (paned->priv->saved_focus)
+    g_object_remove_weak_pointer (G_OBJECT (paned->priv->saved_focus),
+                                 (gpointer *)&(paned->priv->saved_focus));
 
-  paned->saved_focus = widget;
+  paned->priv->saved_focus = widget;
 
-  if (paned->saved_focus)
-    g_object_add_weak_pointer (G_OBJECT (paned->saved_focus),
-                              (gpointer *)&(paned->saved_focus));
+  if (paned->priv->saved_focus)
+    g_object_add_weak_pointer (G_OBJECT (paned->priv->saved_focus),
+                              (gpointer *)&(paned->priv->saved_focus));
+}
+
+static void
+gtk_paned_set_first_paned (GtkPaned *paned, GtkPaned *first_paned)
+{
+  if (paned->priv->first_paned)
+    g_object_remove_weak_pointer (G_OBJECT (paned->priv->first_paned),
+                                 (gpointer *)&(paned->priv->first_paned));
+
+  paned->priv->first_paned = first_paned;
+
+  if (paned->priv->first_paned)
+    g_object_add_weak_pointer (G_OBJECT (paned->priv->first_paned),
+                              (gpointer *)&(paned->priv->first_paned));
 }
 
 static void
@@ -1130,7 +1418,7 @@ gtk_paned_get_cycle_chain (GtkPaned          *paned,
        }
     }
 
-  /* Walk through the list and expand all the paned widgets. */
+  /* Walk the list and expand all the paned widgets. */
   for (list = temp_list; list != NULL; list = list->next)
     {
       GtkWidget *widget = list->data;
@@ -1159,7 +1447,7 @@ gtk_paned_cycle_child_focus (GtkPaned *paned,
 {
   GList *cycle_chain = NULL;
   GList *list;
-
+  
   GtkDirectionType direction = reversed? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
 
   /* ignore f6 if the handle is focused */
@@ -1225,9 +1513,10 @@ gtk_paned_find_neighbours (GtkPaned  *paned,
                           GtkPaned **next,
                           GtkPaned **prev)
 {
-  GList *all_panes = get_all_panes (paned);
+  GList *all_panes;
   GList *this_link;
 
+  all_panes = get_all_panes (paned);
   g_assert (all_panes);
 
   this_link = g_list_find (all_panes, paned);
@@ -1244,12 +1533,6 @@ gtk_paned_find_neighbours (GtkPaned  *paned,
   else
     *prev = g_list_last (all_panes)->data;
 
-  if (*next == paned)
-    *next = NULL;
-
-  if (*prev == paned)
-    *prev = NULL;
-
   g_list_free (all_panes);
 }
 
@@ -1261,38 +1544,40 @@ gtk_paned_move_handle (GtkPaned      *paned,
     {
       gint old_position;
       gint new_position;
+      gint increment;
       
       enum {
        SINGLE_STEP_SIZE = 1,
        PAGE_STEP_SIZE   = 75
       };
       
-      old_position = gtk_paned_get_position (paned);
+      new_position = old_position = gtk_paned_get_position (paned);
+      increment = 0;
       
       switch (scroll)
        {
        case GTK_SCROLL_STEP_LEFT:
        case GTK_SCROLL_STEP_UP:
        case GTK_SCROLL_STEP_BACKWARD:
-         new_position = old_position - SINGLE_STEP_SIZE;
+         increment = - SINGLE_STEP_SIZE;
          break;
          
        case GTK_SCROLL_STEP_RIGHT:
        case GTK_SCROLL_STEP_DOWN:
        case GTK_SCROLL_STEP_FORWARD:
-         new_position = old_position + SINGLE_STEP_SIZE;
+         increment = SINGLE_STEP_SIZE;
          break;
          
        case GTK_SCROLL_PAGE_LEFT:
        case GTK_SCROLL_PAGE_UP:
        case GTK_SCROLL_PAGE_BACKWARD:
-         new_position = old_position - PAGE_STEP_SIZE;
+         increment = - PAGE_STEP_SIZE;
          break;
          
        case GTK_SCROLL_PAGE_RIGHT:
        case GTK_SCROLL_PAGE_DOWN:
        case GTK_SCROLL_PAGE_FORWARD:
-         new_position = old_position + PAGE_STEP_SIZE;
+         increment = PAGE_STEP_SIZE;
          break;
          
        case GTK_SCROLL_START:
@@ -1302,11 +1587,18 @@ gtk_paned_move_handle (GtkPaned      *paned,
        case GTK_SCROLL_END:
          new_position = paned->max_position;
          break;
-         
+
        default:
-         new_position = old_position;
          break;
        }
+
+      if (increment)
+       {
+         if (is_rtl (paned))
+           increment = -increment;
+         
+         new_position = old_position + increment;
+       }
       
       new_position = CLAMP (new_position, paned->min_position, paned->max_position);
       
@@ -1324,9 +1616,10 @@ gtk_paned_restore_focus (GtkPaned *paned)
 {
   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
     {
-      if (paned->saved_focus && GTK_WIDGET_SENSITIVE (paned->saved_focus))
+      if (paned->priv->saved_focus &&
+         GTK_WIDGET_SENSITIVE (paned->priv->saved_focus))
        {
-         gtk_widget_grab_focus (paned->saved_focus);
+         gtk_widget_grab_focus (paned->priv->saved_focus);
        }
       else
        {
@@ -1347,6 +1640,7 @@ gtk_paned_restore_focus (GtkPaned *paned)
        }
       
       gtk_paned_set_saved_focus (paned, NULL);
+      gtk_paned_set_first_paned (paned, NULL);
     }
 }
 
@@ -1387,54 +1681,128 @@ static gboolean
 gtk_paned_cycle_handle_focus (GtkPaned *paned,
                              gboolean  reversed)
 {
+  GtkPaned *next, *prev;
+  
   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
     {
-      GtkPaned *next, *prev;
       GtkPaned *focus = NULL;
 
+      if (!paned->priv->first_paned)
+       {
+         /* The first_pane has disappeared. As an ad-hoc solution,
+          * we make the currently focused paned the first_paned. To the
+          * user this will seem like the paned cycling has been reset.
+          */
+         
+         gtk_paned_set_first_paned (paned, paned);
+       }
+      
       gtk_paned_find_neighbours (paned, &next, &prev);
 
-      if (reversed && prev)
-       focus = prev;
-      else if (!reversed && next)
-       focus = next;
+      if (reversed && prev &&
+         prev != paned && paned != paned->priv->first_paned)
+       {
+         focus = prev;
+       }
+      else if (!reversed && next &&
+              next != paned && next != paned->priv->first_paned)
+       {
+         focus = next;
+       }
+      else
+       {
+         gtk_paned_accept_position (paned);
+         return TRUE;
+       }
 
-      if (focus)
+      g_assert (focus);
+      
+      gtk_paned_set_saved_focus (focus, paned->priv->saved_focus);
+      gtk_paned_set_first_paned (focus, paned->priv->first_paned);
+      
+      gtk_paned_set_saved_focus (paned, NULL);
+      gtk_paned_set_first_paned (paned, NULL);
+      
+      gtk_widget_grab_focus (GTK_WIDGET (focus));
+      
+      if (!gtk_widget_is_focus (GTK_WIDGET (paned)))
        {
-         gtk_paned_set_saved_focus (focus, paned->saved_focus);
-         gtk_paned_set_saved_focus (paned, NULL);
-         gtk_widget_grab_focus (GTK_WIDGET (focus));
+         paned->original_position = -1;
+         focus->original_position = gtk_paned_get_position (focus);
+       }
+    }
+  else
+    {
+      GtkContainer *container = GTK_CONTAINER (paned);
+      GtkPaned *focus;
+      GtkPaned *first;
+      GtkPaned *prev, *next;
+      GtkWidget *toplevel;
+
+      gtk_paned_find_neighbours (paned, &next, &prev);
 
-         if (!gtk_widget_is_focus (GTK_WIDGET (paned)))
+      if (container->focus_child == paned->child1)
+       {
+         if (reversed)
            {
-             paned->original_position = -1;
-             focus->original_position = gtk_paned_get_position (focus);
+             focus = prev;
+             first = paned;
+           }
+         else
+           {
+             focus = paned;
+             first = paned;
            }
        }
-      
-      return TRUE;
-    }
+      else if (container->focus_child == paned->child2)
+       {
+         if (reversed)
+           {
+             focus = paned;
+             first = next;
+           }
+         else
+           {
+             focus = next;
+             first = next;
+           }
+       }
+      else
+       {
+         /* Focus is not inside this paned, and we don't have focus.
+          * Presumably this happened because the application wants us
+          * to start keyboard navigating.
+          */
+         focus = paned;
 
-  return FALSE;
+         if (reversed)
+           first = paned;
+         else
+           first = next;
+       }
+
+      toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
+
+      if (GTK_IS_WINDOW (toplevel))
+       gtk_paned_set_saved_focus (focus, GTK_WINDOW (toplevel)->focus_widget);
+      gtk_paned_set_first_paned (focus, first);
+      focus->original_position = gtk_paned_get_position (focus); 
+
+      gtk_widget_grab_focus (GTK_WIDGET (focus));
+   }
+  
+  return TRUE;
 }
 
 static gboolean
 gtk_paned_toggle_handle_focus (GtkPaned *paned)
 {
+  /* This function/signal has the wrong name. It is called when you
+   * press Tab or Shift-Tab and what we do is act as if
+   * the user pressed Return and then Tab or Shift-Tab
+   */
   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
-    {
-      gtk_paned_accept_position (paned);
-    }
-  else
-    {
-      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
+    gtk_paned_accept_position (paned);
 
-      if (GTK_IS_WINDOW (toplevel))
-       gtk_paned_set_saved_focus (paned, GTK_WINDOW (toplevel)->focus_widget);
-  
-      gtk_widget_grab_focus (GTK_WIDGET (paned));
-      paned->original_position = gtk_paned_get_position (paned);
-    }
-
-  return TRUE;
+  return FALSE;
 }