]> Pileus Git - ~andy/gtk/commitdiff
Keyboard navigation for GtkPaned F6: cycle between panes. F8: focus handle
authorSoeren Sandmann <sandmann@daimi.au.dk>
Sat, 9 Feb 2002 13:05:02 +0000 (13:05 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Sat, 9 Feb 2002 13:05:02 +0000 (13:05 +0000)
Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>

* gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
F6: cycle between panes.
F8: focus handle (#53584)

* tests/testgtk.c: Add test cases for GtkPaned keyboard
navigation.

ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/gtkpaned.c
gtk/gtkpaned.h
tests/testgtk.c

index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index afd761312210c5bede600ae22f1b8becc88ee9b8..feeeb5f272fad3c48e90ec997effe60004c096c0 100644 (file)
@@ -1,3 +1,12 @@
+Sat Feb  9 13:58:41 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
+
+       * gtk/gtkpaned.[ch]: Keyboard navigation for GtkPaned
+       F6: cycle between panes.
+       F8: focus handle (#53584)
+       
+       * tests/testgtk.c: Add test cases for GtkPaned keyboard 
+       navigation.
+       
 Sat Feb  9 00:16:31 2002  Owen Taylor  <otaylor@redhat.com>
 
        * gdk/x11/gdkimage-x11.c (_gdk_x11_copy_to_image): 
index b0e3385e46b9526fafabca7e407af5925549ba18..e3b3a4bfacba2fdab09e80552aa7f9a944cbe1d5 100644 (file)
 
 #include "gtkintl.h"
 #include "gtkpaned.h"
+#include "gtkbindings.h"
+#include "gtksignal.h"
+#include "gdk/gdkkeysyms.h"
+#include "gtkwindow.h"
+#include "gtkmain.h"
+#include "gtkmarshalers.h"
 
 enum {
   PROP_0,
@@ -33,31 +39,60 @@ enum {
   PROP_POSITION_SET
 };
 
-static void    gtk_paned_class_init   (GtkPanedClass  *klass);
-static void    gtk_paned_init         (GtkPaned       *paned);
-static void    gtk_paned_set_property (GObject        *object,
-                                      guint           prop_id,
-                                      const GValue   *value,
-                                      GParamSpec     *pspec);
-static void    gtk_paned_get_property (GObject        *object,
-                                      guint           prop_id,
-                                      GValue         *value,
-                                      GParamSpec     *pspec);
-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 gint    gtk_paned_expose       (GtkWidget      *widget,
-                                      GdkEventExpose *event);
-static void    gtk_paned_add          (GtkContainer   *container,
-                                      GtkWidget      *widget);
-static void    gtk_paned_remove       (GtkContainer   *container,
-                                      GtkWidget      *widget);
-static void    gtk_paned_forall       (GtkContainer   *container,
-                                      gboolean        include_internals,
-                                      GtkCallback     callback,
-                                      gpointer        callback_data);
-static GtkType gtk_paned_child_type   (GtkContainer   *container);
+enum {
+  CYCLE_CHILD_FOCUS,
+  TOGGLE_HANDLE_FOCUS,
+  MOVE_HANDLE,
+  CYCLE_HANDLE_FOCUS,
+  LAST_SIGNAL,
+  ACCEPT_POSITION,
+  CANCEL_POSITION
+};
+
+static void     gtk_paned_class_init            (GtkPanedClass    *klass);
+static void     gtk_paned_init                  (GtkPaned         *paned);
+static void     gtk_paned_set_property          (GObject          *object,
+                                                guint             prop_id,
+                                                const GValue     *value,
+                                                GParamSpec       *pspec);
+static void     gtk_paned_get_property          (GObject          *object,
+                                                guint             prop_id,
+                                                GValue           *value,
+                                                GParamSpec       *pspec);
+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 gint     gtk_paned_expose                (GtkWidget        *widget,
+                                                GdkEventExpose   *event);
+static gboolean gtk_paned_focus                 (GtkWidget        *widget,
+                                                GtkDirectionType  direction);
+static void     gtk_paned_add                   (GtkContainer     *container,
+                                                GtkWidget        *widget);
+static void     gtk_paned_remove                (GtkContainer     *container,
+                                                GtkWidget        *widget);
+static void     gtk_paned_forall                (GtkContainer     *container,
+                                                gboolean          include_internals,
+                                                GtkCallback       callback,
+                                                gpointer          callback_data);
+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_last_child1_focus (GtkPaned         *paned,
+                                                GtkWidget        *widget);
+static void     gtk_paned_set_last_child2_focus (GtkPaned         *paned,
+                                                GtkWidget        *widget);
+static gboolean gtk_paned_cycle_child_focus     (GtkPaned         *paned,
+                                                gboolean          reverse);
+static gboolean gtk_paned_cycle_handle_focus    (GtkPaned         *paned,
+                                                gboolean          reverse);
+static gboolean gtk_paned_move_handle           (GtkPaned         *paned,
+                                                GtkScrollType     scroll);
+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 GtkContainerClass *parent_class = NULL;
 
@@ -87,16 +122,48 @@ gtk_paned_get_type (void)
   return paned_type;
 }
 
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+add_tab_bindings (GtkBindingSet    *binding_set,
+                 GdkModifierType   modifiers,
+                 gboolean          reverse)
+{
+  gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
+                                "cycle_handle_focus", 1,
+                                G_TYPE_BOOLEAN, reverse);
+  gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
+                                "cycle_handle_focus", 1,
+                                G_TYPE_BOOLEAN, reverse);
+  gtk_binding_entry_add_signal (binding_set, GDK_ISO_Left_Tab, modifiers,
+                                "cycle_handle_focus", 1,
+                                G_TYPE_BOOLEAN, reverse);
+}
+
+static void
+add_move_binding (GtkBindingSet   *binding_set,
+                 guint            keyval,
+                 GdkModifierType  mask,
+                 GtkScrollType    scroll)
+{
+  gtk_binding_entry_add_signal (binding_set, keyval, mask,
+                               "move_handle", 1,
+                               GTK_TYPE_SCROLL_TYPE, scroll);
+}
+
 static void
 gtk_paned_class_init (GtkPanedClass *class)
 {
   GObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkContainerClass *container_class;
+  GtkPanedClass *paned_class;
+  GtkBindingSet *binding_set;
 
   object_class = (GObjectClass *) class;
   widget_class = (GtkWidgetClass *) class;
   container_class = (GtkContainerClass *) class;
+  paned_class = (GtkPanedClass *) class;
 
   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
 
@@ -108,12 +175,21 @@ gtk_paned_class_init (GtkPanedClass *class)
   widget_class->map = gtk_paned_map;
   widget_class->unmap = gtk_paned_unmap;
   widget_class->expose_event = gtk_paned_expose;
+  widget_class->focus = gtk_paned_focus;
   
   container_class->add = gtk_paned_add;
   container_class->remove = gtk_paned_remove;
   container_class->forall = gtk_paned_forall;
   container_class->child_type = gtk_paned_child_type;
-
+  container_class->set_focus_child = gtk_paned_set_focus_child;
+
+  paned_class->cycle_child_focus = gtk_paned_cycle_child_focus;
+  paned_class->toggle_handle_focus = gtk_paned_toggle_handle_focus;
+  paned_class->move_handle = gtk_paned_move_handle;
+  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",
@@ -139,6 +215,133 @@ gtk_paned_class_init (GtkPanedClass *class)
                                                             G_MAXINT,
                                                             5,
                                                             G_PARAM_READABLE));
+
+  signals [CYCLE_HANDLE_FOCUS] =
+    g_signal_new ("cycle_child_focus",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkPanedClass, cycle_child_focus),
+                 NULL, NULL,
+                 _gtk_marshal_BOOLEAN__BOOLEAN,
+                 G_TYPE_BOOLEAN, 1,
+                 G_TYPE_BOOLEAN);
+
+  signals [TOGGLE_HANDLE_FOCUS] =
+    g_signal_new ("toggle_handle_focus",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkPanedClass, toggle_handle_focus),
+                 NULL, NULL,
+                 _gtk_marshal_BOOLEAN__VOID,
+                 G_TYPE_BOOLEAN, 0);
+
+  signals[MOVE_HANDLE] =
+    g_signal_new ("move_handle",
+                 G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GtkPanedClass, move_handle),
+                  NULL, NULL,
+                  _gtk_marshal_BOOLEAN__ENUM,
+                  G_TYPE_BOOLEAN, 1,
+                  GTK_TYPE_SCROLL_TYPE);
+
+  signals [CYCLE_HANDLE_FOCUS] =
+    g_signal_new ("cycle_handle_focus",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkPanedClass, cycle_handle_focus),
+                 NULL, NULL,
+                 _gtk_marshal_BOOLEAN__BOOLEAN,
+                 G_TYPE_BOOLEAN, 1,
+                 G_TYPE_BOOLEAN);
+
+  signals [ACCEPT_POSITION] =
+    g_signal_new ("accept_position",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkPanedClass, accept_position),
+                 NULL, NULL,
+                 _gtk_marshal_BOOLEAN__VOID,
+                 G_TYPE_BOOLEAN, 0);
+
+  signals [CANCEL_POSITION] =
+    g_signal_new ("cancel_position",
+                 G_TYPE_FROM_CLASS (object_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkPanedClass, cancel_position),
+                 NULL, NULL,
+                 _gtk_marshal_BOOLEAN__VOID,
+                 G_TYPE_BOOLEAN, 0);
+
+  binding_set = gtk_binding_set_by_class (object_class);
+
+  /* F6 and friends */
+  gtk_binding_entry_add_signal (binding_set,                           
+                                GDK_F6, 0,
+                                "cycle_child_focus", 1, 
+                                G_TYPE_BOOLEAN, FALSE);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_F6, GDK_SHIFT_MASK,
+                               "cycle_child_focus", 1,
+                               G_TYPE_BOOLEAN, TRUE);
+
+  /* F8 and friends */
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_F8, 0,
+                               "toggle_handle_focus", 0);
+  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);
+
+  /* accept and cancel positions */
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_Escape, 0,
+                               "cancel_position", 0);
+
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_Return, 0,
+                               "accept_position", 0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_KP_Enter, 0,
+                               "accept_position", 0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_space, 0,
+                               "accept_position", 0);
+  gtk_binding_entry_add_signal (binding_set,
+                               GDK_KP_Space, 0,
+                               "accept_position", 0);
+
+  /* move handle */
+  add_move_binding (binding_set, GDK_Left, 0, GTK_SCROLL_STEP_LEFT);
+  add_move_binding (binding_set, GDK_KP_Left, 0, GTK_SCROLL_STEP_LEFT);
+  add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
+  add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
+
+  add_move_binding (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_RIGHT);
+  add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
+  add_move_binding (binding_set, GDK_KP_Right, 0, GTK_SCROLL_STEP_RIGHT);
+  add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
+
+  add_move_binding (binding_set, GDK_Up, 0, GTK_SCROLL_STEP_UP);
+  add_move_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
+  add_move_binding (binding_set, GDK_KP_Up, 0, GTK_SCROLL_STEP_UP);
+  add_move_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
+  add_move_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_UP);
+  add_move_binding (binding_set, GDK_KP_Page_Up, 0, GTK_SCROLL_PAGE_UP);
+
+  add_move_binding (binding_set, GDK_Down, 0, GTK_SCROLL_STEP_DOWN);
+  add_move_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
+  add_move_binding (binding_set, GDK_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
+  add_move_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
+  add_move_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
+  add_move_binding (binding_set, GDK_KP_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
+
+  add_move_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START);
+  add_move_binding (binding_set, GDK_KP_Home, 0, GTK_SCROLL_START);
+  add_move_binding (binding_set, GDK_End, 0, GTK_SCROLL_END);
+  add_move_binding (binding_set, GDK_KP_End, 0, GTK_SCROLL_END);
 }
 
 static GtkType
@@ -153,7 +356,7 @@ gtk_paned_child_type (GtkContainer *container)
 static void
 gtk_paned_init (GtkPaned *paned)
 {
-  GTK_WIDGET_SET_FLAGS (paned, GTK_NO_WINDOW);
+  GTK_WIDGET_SET_FLAGS (paned, GTK_NO_WINDOW | GTK_CAN_FOCUS);
   
   paned->child1 = NULL;
   paned->child2 = NULL;
@@ -166,6 +369,12 @@ gtk_paned_init (GtkPaned *paned)
   paned->position_set = FALSE;
   paned->last_allocation = -1;
   paned->in_drag = FALSE;
+
+  paned->saved_focus = NULL;
+  paned->last_child1_focus = NULL;
+  paned->last_child2_focus = NULL;
+  paned->in_recursion = FALSE;
+  paned->original_position = -1;
   
   paned->handle_pos.x = -1;
   paned->handle_pos.y = -1;
@@ -272,6 +481,10 @@ gtk_paned_unrealize (GtkWidget *widget)
       paned->handle = NULL;
     }
 
+  gtk_paned_set_last_child1_focus (paned, NULL);
+  gtk_paned_set_last_child2_focus (paned, NULL);
+  gtk_paned_set_saved_focus (paned, NULL);
+  
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
@@ -313,12 +526,17 @@ gtk_paned_expose (GtkWidget      *widget,
 
       if (!gdk_region_empty (region))
        {
+         GtkStateType state;
          GdkRectangle clip;
 
          gdk_region_get_clipbox (region, &clip);
+
+         state = GTK_WIDGET_STATE (widget);
+         if (gtk_widget_is_focus (widget))
+           state = GTK_STATE_SELECTED;
          
          gtk_paint_handle (widget->style, widget->window,
-                           GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+                           state, GTK_SHADOW_NONE,
                            &clip, widget, "paned",
                            paned->handle_pos.x, paned->handle_pos.y,
                            paned->handle_pos.width, paned->handle_pos.height,
@@ -334,6 +552,24 @@ gtk_paned_expose (GtkWidget      *widget,
   return FALSE;
 }
 
+static gboolean
+gtk_paned_focus (GtkWidget        *widget,
+                GtkDirectionType  direction)
+
+{
+  gboolean retval;
+  
+  /* This is a hack, but how can this be done without
+   * excessive cut-and-paste from gtkcontainer.c?
+   */
+
+  GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
+  retval = (* GTK_WIDGET_CLASS (parent_class)->focus) (widget, direction);
+  GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+
+  return retval;
+}
+
 void
 gtk_paned_add1 (GtkPaned  *paned,
                GtkWidget *widget)
@@ -562,3 +798,488 @@ gtk_paned_compute_position (GtkPaned *paned,
 
   paned->last_allocation = allocation;
 }
+
+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));
+
+  paned->saved_focus = widget;
+
+  if (paned->saved_focus)
+    g_object_add_weak_pointer (G_OBJECT (paned->saved_focus),
+                              (gpointer *)&(paned->saved_focus));
+}
+
+static void
+gtk_paned_set_last_child1_focus (GtkPaned *paned, GtkWidget *widget)
+{
+  if (paned->last_child1_focus)
+    g_object_remove_weak_pointer (G_OBJECT (paned->last_child1_focus),
+                                 (gpointer *)&(paned->last_child1_focus));
+
+  paned->last_child1_focus = widget;
+
+  if (paned->last_child1_focus)
+    g_object_add_weak_pointer (G_OBJECT (paned->last_child1_focus),
+                              (gpointer *)&(paned->last_child1_focus));
+}
+
+static void
+gtk_paned_set_last_child2_focus (GtkPaned *paned, GtkWidget *widget)
+{
+  if (paned->last_child2_focus)
+    g_object_remove_weak_pointer (G_OBJECT (paned->last_child2_focus),
+                                 (gpointer *)&(paned->last_child2_focus));
+
+  paned->last_child2_focus = widget;
+
+  if (paned->last_child2_focus)
+    g_object_add_weak_pointer (G_OBJECT (paned->last_child2_focus),
+                              (gpointer *)&(paned->last_child2_focus));
+}
+
+static GtkWidget *
+paned_get_focus_widget (GtkPaned *paned)
+{
+  GtkWidget *toplevel;
+
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
+  if (GTK_WIDGET_TOPLEVEL (toplevel))
+    return GTK_WINDOW (toplevel)->focus_widget;
+
+  return NULL;
+}
+
+static void
+gtk_paned_set_focus_child (GtkContainer *container,
+                          GtkWidget    *focus_child)
+{
+  GtkPaned *paned;
+  
+  g_return_if_fail (GTK_IS_PANED (container));
+
+  paned = GTK_PANED (container);
+  if (focus_child == NULL)
+    {
+      GtkWidget *last_focus;
+      GtkWidget *w;
+      
+      last_focus = paned_get_focus_widget (paned);
+
+      if (last_focus)
+       {
+         /* If there is one or more paned widgets between us and the
+          * focus widget, we want the topmost of those as last_focus
+          */
+         for (w = last_focus; w != GTK_WIDGET (paned); w = w->parent)
+           if (GTK_IS_PANED (w))
+             last_focus = w;
+         
+         if (container->focus_child == paned->child1)
+           gtk_paned_set_last_child1_focus (paned, last_focus);
+         else if (container->focus_child == paned->child2)
+           gtk_paned_set_last_child2_focus (paned, last_focus);
+       }
+    }
+
+  if (parent_class->set_focus_child)
+    (* parent_class->set_focus_child) (container, focus_child);
+}
+
+static void
+gtk_paned_get_cycle_chain (GtkPaned          *paned,
+                          GtkDirectionType   direction,
+                          GList            **widgets)
+{
+  GtkContainer *container = GTK_CONTAINER (paned);
+  GtkWidget *ancestor = NULL;
+  GList *temp_list = NULL;
+  GList *list;
+
+  if (paned->in_recursion)
+    return;
+
+  g_assert (widgets != NULL);
+
+  if (paned->last_child1_focus &&
+      !gtk_widget_is_ancestor (paned->last_child1_focus, GTK_WIDGET (paned)))
+    {
+      gtk_paned_set_last_child1_focus (paned, NULL);
+    }
+
+  if (paned->last_child2_focus &&
+      !gtk_widget_is_ancestor (paned->last_child2_focus, GTK_WIDGET (paned)))
+    {
+      gtk_paned_set_last_child2_focus (paned, NULL);
+    }
+
+  if (GTK_WIDGET (paned)->parent)
+    ancestor = gtk_widget_get_ancestor (GTK_WIDGET (paned)->parent, GTK_TYPE_PANED);
+
+  /* The idea here is that temp_list is a list of widgets we want to cycle
+   * to. The list is prioritized so that the first element is our first
+   * choice, the next our second, and so on.
+   *
+   * We can't just use g_list_reverse(), because we want to try
+   * paned->last_child?_focus before paned->child?, both when we
+   * are going forward and backward.
+   */
+  if (direction == GTK_DIR_TAB_FORWARD)
+    {
+      if (container->focus_child == paned->child1)
+       {
+         temp_list = g_list_append (temp_list, paned->last_child2_focus);
+         temp_list = g_list_append (temp_list, paned->child2);
+         temp_list = g_list_append (temp_list, ancestor);
+       }
+      else if (container->focus_child == paned->child2)
+       {
+         temp_list = g_list_append (temp_list, ancestor);
+         temp_list = g_list_append (temp_list, paned->last_child1_focus);
+         temp_list = g_list_append (temp_list, paned->child1);
+       }
+      else
+       {
+         temp_list = g_list_append (temp_list, paned->last_child1_focus);
+         temp_list = g_list_append (temp_list, paned->child1);
+         temp_list = g_list_append (temp_list, paned->last_child2_focus);
+         temp_list = g_list_append (temp_list, paned->child2);
+         temp_list = g_list_append (temp_list, ancestor);
+       }
+    }
+  else
+    {
+      if (container->focus_child == paned->child1)
+       {
+         temp_list = g_list_append (temp_list, ancestor);
+         temp_list = g_list_append (temp_list, paned->last_child2_focus);
+         temp_list = g_list_append (temp_list, paned->child2);
+       }
+      else if (container->focus_child == paned->child2)
+       {
+         temp_list = g_list_append (temp_list, paned->last_child1_focus);
+         temp_list = g_list_append (temp_list, paned->child1);
+         temp_list = g_list_append (temp_list, ancestor);
+       }
+      else
+       {
+         temp_list = g_list_append (temp_list, paned->last_child2_focus);
+         temp_list = g_list_append (temp_list, paned->child2);
+         temp_list = g_list_append (temp_list, paned->last_child1_focus);
+         temp_list = g_list_append (temp_list, paned->child1);
+         temp_list = g_list_append (temp_list, ancestor);
+       }
+    }
+
+  /* Walk through the list and expand all the paned widgets. */
+  for (list = temp_list; list != NULL; list = list->next)
+    {
+      GtkWidget *widget = list->data;
+
+      if (widget)
+       {
+         if (GTK_IS_PANED (widget))
+           {
+             paned->in_recursion = TRUE;
+             gtk_paned_get_cycle_chain (GTK_PANED (widget), direction, widgets);
+             paned->in_recursion = FALSE;
+           }
+         else
+           {
+             *widgets = g_list_append (*widgets, widget);
+           }
+       }
+    }
+
+  g_list_free (temp_list);
+}
+
+static gboolean
+gtk_paned_cycle_child_focus (GtkPaned *paned,
+                            gboolean  reversed)
+{
+  GList *cycle_chain = NULL;
+  GList *list;
+
+  GtkDirectionType direction = reversed? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
+
+  /* ignore f6 if the handle is focused */
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    return TRUE;
+  
+  /* we can't just let the event propagate up the hierarchy,
+   * because the paned will want to cycle focus _unless_ an
+   * ancestor paned handles the event
+   */
+  gtk_paned_get_cycle_chain (paned, direction, &cycle_chain);
+
+  for (list = cycle_chain; list != NULL; list = list->next)
+    if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
+      break;
+
+  g_list_free (cycle_chain);
+  
+  return TRUE;
+}
+
+static void
+get_child_panes (GtkWidget  *widget,
+                GList     **panes)
+{
+  if (GTK_IS_PANED (widget))
+    {
+      GtkPaned *paned = GTK_PANED (widget);
+      
+      get_child_panes (paned->child1, panes);
+      *panes = g_list_prepend (*panes, widget);
+      get_child_panes (paned->child2, panes);
+    }
+  else if (GTK_IS_CONTAINER (widget))
+    {
+      gtk_container_foreach (GTK_CONTAINER (widget),
+                            (GtkCallback)get_child_panes, panes);
+    }
+}
+
+static GList *
+get_all_panes (GtkPaned *paned)
+{
+  GtkPaned *topmost = NULL;
+  GList *result = NULL;
+  GtkWidget *w;
+  
+  for (w = GTK_WIDGET (paned); w != NULL; w = w->parent)
+    {
+      if (GTK_IS_PANED (w))
+       topmost = GTK_PANED (w);
+    }
+
+  g_assert (topmost);
+
+  get_child_panes (GTK_WIDGET (topmost), &result);
+
+  return g_list_reverse (result);
+}
+
+static void
+gtk_paned_find_neighbours (GtkPaned  *paned,
+                          GtkPaned **next,
+                          GtkPaned **prev)
+{
+  GList *all_panes = get_all_panes (paned);
+  GList *this_link;
+
+  g_assert (all_panes);
+
+  this_link = g_list_find (all_panes, paned);
+
+  g_assert (this_link);
+  
+  if (this_link->next)
+    *next = this_link->next->data;
+  else
+    *next = all_panes->data;
+
+  if (this_link->prev)
+    *prev = this_link->prev->data;
+  else
+    *prev = g_list_last (all_panes)->data;
+
+  if (*next == paned)
+    *next = NULL;
+
+  if (*prev == paned)
+    *prev = NULL;
+
+  g_list_free (all_panes);
+}
+
+static gboolean
+gtk_paned_move_handle (GtkPaned      *paned,
+                      GtkScrollType  scroll)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      gint old_position;
+      gint new_position;
+      
+      enum {
+       SINGLE_STEP_SIZE = 1,
+       PAGE_STEP_SIZE   = 75,
+      };
+      
+      old_position = gtk_paned_get_position (paned);
+      
+      switch (scroll)
+       {
+       case GTK_SCROLL_STEP_LEFT:
+       case GTK_SCROLL_STEP_UP:
+       case GTK_SCROLL_STEP_BACKWARD:
+         new_position = old_position - 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;
+         break;
+         
+       case GTK_SCROLL_PAGE_LEFT:
+       case GTK_SCROLL_PAGE_UP:
+       case GTK_SCROLL_PAGE_BACKWARD:
+         new_position = old_position - 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;
+         break;
+         
+       case GTK_SCROLL_START:
+         new_position = paned->min_position;
+         break;
+         
+       case GTK_SCROLL_END:
+         new_position = paned->max_position;
+         break;
+         
+       default:
+         new_position = old_position;
+         break;
+       }
+      
+      new_position = CLAMP (new_position, paned->min_position, paned->max_position);
+      
+      if (old_position != new_position)
+       gtk_paned_set_position (paned, new_position);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gtk_paned_restore_focus (GtkPaned *paned)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      if (paned->saved_focus && GTK_WIDGET_SENSITIVE (paned->saved_focus))
+       {
+         gtk_widget_grab_focus (paned->saved_focus);
+       }
+      else
+       {
+         /* the saved focus is somehow not available for focusing,
+          * try
+          *   1) tabbing into the paned widget
+          * if that didn't work,
+          *   2) unset focus for the window if there is one
+          */
+         
+         if (!gtk_widget_child_focus (GTK_WIDGET (paned), GTK_DIR_TAB_FORWARD))
+           {
+             GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
+             
+             if (GTK_IS_WINDOW (toplevel))
+               gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
+           }
+       }
+      
+      gtk_paned_set_saved_focus (paned, NULL);
+    }
+}
+
+static gboolean
+gtk_paned_accept_position (GtkPaned *paned)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      paned->original_position = -1;
+      gtk_paned_restore_focus (paned);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+static gboolean
+gtk_paned_cancel_position (GtkPaned *paned)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      if (paned->original_position != -1)
+       {
+         gtk_paned_set_position (paned, paned->original_position);
+         paned->original_position = -1;
+       }
+
+      gtk_paned_restore_focus (paned);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+gtk_paned_cycle_handle_focus (GtkPaned *paned,
+                             gboolean  reversed)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      GtkPaned *next, *prev;
+      GtkPaned *focus = NULL;
+
+      gtk_paned_find_neighbours (paned, &next, &prev);
+
+      if (reversed && prev)
+       focus = prev;
+      else if (!reversed && next)
+       focus = next;
+
+      if (focus)
+       {
+         gtk_paned_set_saved_focus (focus, paned->saved_focus);
+         gtk_paned_set_saved_focus (paned, NULL);
+         gtk_widget_grab_focus (GTK_WIDGET (focus));
+
+         if (!gtk_widget_is_focus (GTK_WIDGET (paned)))
+           {
+             paned->original_position = -1;
+             focus->original_position = gtk_paned_get_position (focus);
+           }
+       }
+      
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+gtk_paned_toggle_handle_focus (GtkPaned *paned)
+{
+  if (gtk_widget_is_focus (GTK_WIDGET (paned)))
+    {
+      gtk_paned_accept_position (paned);
+    }
+  else
+    {
+      GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (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;
+}
index 7606be2a700e878618df6a2a8e883ec3312e4523..115dd12a6e284748ee86faaf0092a3f21e6a0f2c 100644 (file)
@@ -72,11 +72,28 @@ struct _GtkPaned
   guint child2_shrink : 1;
   guint child2_resize : 1;
   guint orientation : 1;
-};
+  guint in_recursion : 1;
 
+  GtkWidget *last_child1_focus;
+  GtkWidget *last_child2_focus;
+  GtkWidget *saved_focus;
+  
+  gint original_position;
+};
 struct _GtkPanedClass
 {
   GtkContainerClass parent_class;
+  
+  gboolean (* cycle_child_focus)   (GtkPaned      *paned,
+                                   gboolean       reverse); 
+  gboolean (* toggle_handle_focus) (GtkPaned      *paned);
+  gboolean (* move_handle)         (GtkPaned      *paned,
+                                   GtkScrollType  scroll);
+  gboolean (* cycle_handle_focus)  (GtkPaned      *paned,
+                                   gboolean       reverse);
+  gboolean (* accept_position)     (GtkPaned     *paned);
+  gboolean (* cancel_position)     (GtkPaned     *paned);
 };
 
 
index fbd4af4c64f834a43f6f56849a986639e7f10502..f2b23a81e96d663123e6408b1244680e1e5712fe 100644 (file)
@@ -7902,6 +7902,371 @@ create_panes (void)
     gtk_widget_destroy (window);
 }
 
+/*
+ * Paned keyboard navigation
+ */
+
+static GtkWidget*
+paned_keyboard_window1 (void)
+{
+  GtkWidget *window1;
+  GtkWidget *hpaned1;
+  GtkWidget *frame1;
+  GtkWidget *vbox1;
+  GtkWidget *button7;
+  GtkWidget *button8;
+  GtkWidget *button9;
+  GtkWidget *vpaned1;
+  GtkWidget *frame2;
+  GtkWidget *frame5;
+  GtkWidget *hbox1;
+  GtkWidget *button5;
+  GtkWidget *button6;
+  GtkWidget *frame3;
+  GtkWidget *frame4;
+  GtkWidget *table1;
+  GtkWidget *button1;
+  GtkWidget *button2;
+  GtkWidget *button3;
+  GtkWidget *button4;
+
+  window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window1), "Basic paned navigation");
+
+  hpaned1 = gtk_hpaned_new ();
+  gtk_container_add (GTK_CONTAINER (window1), hpaned1);
+
+  frame1 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (hpaned1), frame1, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
+
+  vbox1 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (frame1), vbox1);
+
+  button7 = gtk_button_new_with_label ("button7");
+  gtk_box_pack_start (GTK_BOX (vbox1), button7, FALSE, FALSE, 0);
+
+  button8 = gtk_button_new_with_label ("button8");
+  gtk_box_pack_start (GTK_BOX (vbox1), button8, FALSE, FALSE, 0);
+
+  button9 = gtk_button_new_with_label ("button9");
+  gtk_box_pack_start (GTK_BOX (vbox1), button9, FALSE, FALSE, 0);
+
+  vpaned1 = gtk_vpaned_new ();
+  gtk_paned_pack2 (GTK_PANED (hpaned1), vpaned1, TRUE, TRUE);
+
+  frame2 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (vpaned1), frame2, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN);
+
+  frame5 = gtk_frame_new (NULL);
+  gtk_container_add (GTK_CONTAINER (frame2), frame5);
+
+  hbox1 = gtk_hbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (frame5), hbox1);
+
+  button5 = gtk_button_new_with_label ("button5");
+  gtk_box_pack_start (GTK_BOX (hbox1), button5, FALSE, FALSE, 0);
+
+  button6 = gtk_button_new_with_label ("button6");
+  gtk_box_pack_start (GTK_BOX (hbox1), button6, FALSE, FALSE, 0);
+
+  frame3 = gtk_frame_new (NULL);
+  gtk_paned_pack2 (GTK_PANED (vpaned1), frame3, TRUE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame3), GTK_SHADOW_IN);
+
+  frame4 = gtk_frame_new ("Buttons");
+  gtk_container_add (GTK_CONTAINER (frame3), frame4);
+  gtk_container_set_border_width (GTK_CONTAINER (frame4), 15);
+
+  table1 = gtk_table_new (2, 2, FALSE);
+  gtk_container_add (GTK_CONTAINER (frame4), table1);
+  gtk_container_set_border_width (GTK_CONTAINER (table1), 11);
+
+  button1 = gtk_button_new_with_label ("button1");
+  gtk_table_attach (GTK_TABLE (table1), button1, 0, 1, 0, 1,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  button2 = gtk_button_new_with_label ("button2");
+  gtk_table_attach (GTK_TABLE (table1), button2, 1, 2, 0, 1,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  button3 = gtk_button_new_with_label ("button3");
+  gtk_table_attach (GTK_TABLE (table1), button3, 0, 1, 1, 2,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  button4 = gtk_button_new_with_label ("button4");
+  gtk_table_attach (GTK_TABLE (table1), button4, 1, 2, 1, 2,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  return window1;
+}
+
+static GtkWidget*
+paned_keyboard_window2 (void)
+{
+  GtkWidget *window2;
+  GtkWidget *hpaned2;
+  GtkWidget *frame6;
+  GtkWidget *button13;
+  GtkWidget *hbox2;
+  GtkWidget *vpaned2;
+  GtkWidget *frame7;
+  GtkWidget *button12;
+  GtkWidget *frame8;
+  GtkWidget *button11;
+  GtkWidget *button10;
+
+  window2 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window2), "\"button 10\" is not inside the horisontal pane");
+
+  hpaned2 = gtk_hpaned_new ();
+  gtk_container_add (GTK_CONTAINER (window2), hpaned2);
+
+  frame6 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (hpaned2), frame6, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame6), GTK_SHADOW_IN);
+
+  button13 = gtk_button_new_with_label ("button13");
+  gtk_container_add (GTK_CONTAINER (frame6), button13);
+
+  hbox2 = gtk_hbox_new (FALSE, 0);
+  gtk_paned_pack2 (GTK_PANED (hpaned2), hbox2, TRUE, TRUE);
+
+  vpaned2 = gtk_vpaned_new ();
+  gtk_box_pack_start (GTK_BOX (hbox2), vpaned2, TRUE, TRUE, 0);
+
+  frame7 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (vpaned2), frame7, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame7), GTK_SHADOW_IN);
+
+  button12 = gtk_button_new_with_label ("button12");
+  gtk_container_add (GTK_CONTAINER (frame7), button12);
+
+  frame8 = gtk_frame_new (NULL);
+  gtk_paned_pack2 (GTK_PANED (vpaned2), frame8, TRUE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame8), GTK_SHADOW_IN);
+
+  button11 = gtk_button_new_with_label ("button11");
+  gtk_container_add (GTK_CONTAINER (frame8), button11);
+
+  button10 = gtk_button_new_with_label ("button10");
+  gtk_box_pack_start (GTK_BOX (hbox2), button10, FALSE, FALSE, 0);
+
+  return window2;
+}
+
+static GtkWidget*
+paned_keyboard_window3 (void)
+{
+  GtkWidget *window3;
+  GtkWidget *vbox2;
+  GtkWidget *label1;
+  GtkWidget *hpaned3;
+  GtkWidget *frame9;
+  GtkWidget *button14;
+  GtkWidget *hpaned4;
+  GtkWidget *frame10;
+  GtkWidget *button15;
+  GtkWidget *hpaned5;
+  GtkWidget *frame11;
+  GtkWidget *button16;
+  GtkWidget *frame12;
+  GtkWidget *button17;
+
+  window3 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_object_set_data (GTK_OBJECT (window3), "window3", window3);
+  gtk_window_set_title (GTK_WINDOW (window3), "Nested panes");
+
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window3), vbox2);
+
+  label1 = gtk_label_new ("Three panes nested inside each other");
+  gtk_box_pack_start (GTK_BOX (vbox2), label1, FALSE, FALSE, 0);
+
+  hpaned3 = gtk_hpaned_new ();
+  gtk_box_pack_start (GTK_BOX (vbox2), hpaned3, TRUE, TRUE, 0);
+
+  frame9 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (hpaned3), frame9, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame9), GTK_SHADOW_IN);
+
+  button14 = gtk_button_new_with_label ("button14");
+  gtk_container_add (GTK_CONTAINER (frame9), button14);
+
+  hpaned4 = gtk_hpaned_new ();
+  gtk_paned_pack2 (GTK_PANED (hpaned3), hpaned4, TRUE, TRUE);
+
+  frame10 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (hpaned4), frame10, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame10), GTK_SHADOW_IN);
+
+  button15 = gtk_button_new_with_label ("button15");
+  gtk_container_add (GTK_CONTAINER (frame10), button15);
+
+  hpaned5 = gtk_hpaned_new ();
+  gtk_paned_pack2 (GTK_PANED (hpaned4), hpaned5, TRUE, TRUE);
+
+  frame11 = gtk_frame_new (NULL);
+  gtk_paned_pack1 (GTK_PANED (hpaned5), frame11, FALSE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame11), GTK_SHADOW_IN);
+
+  button16 = gtk_button_new_with_label ("button16");
+  gtk_container_add (GTK_CONTAINER (frame11), button16);
+
+  frame12 = gtk_frame_new (NULL);
+  gtk_paned_pack2 (GTK_PANED (hpaned5), frame12, TRUE, TRUE);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame12), GTK_SHADOW_IN);
+
+  button17 = gtk_button_new_with_label ("button17");
+  gtk_container_add (GTK_CONTAINER (frame12), button17);
+
+  return window3;
+}
+
+static GtkWidget*
+paned_keyboard_window4 (void)
+{
+  GtkWidget *window4;
+  GtkWidget *vbox3;
+  GtkWidget *label2;
+  GtkWidget *hpaned6;
+  GtkWidget *vpaned3;
+  GtkWidget *button19;
+  GtkWidget *button18;
+  GtkWidget *hbox3;
+  GtkWidget *vpaned4;
+  GtkWidget *button21;
+  GtkWidget *button20;
+  GtkWidget *vpaned5;
+  GtkWidget *button23;
+  GtkWidget *button22;
+  GtkWidget *vpaned6;
+  GtkWidget *button25;
+  GtkWidget *button24;
+
+  window4 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_object_set_data (GTK_OBJECT (window4), "window4", window4);
+  gtk_window_set_title (GTK_WINDOW (window4), "window4");
+
+  vbox3 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window4), vbox3);
+
+  label2 = gtk_label_new ("Widget tree:\n\nhpaned \n - vpaned\n - hbox\n    - vpaned\n    - vpaned\n    - vpaned\n");
+  gtk_box_pack_start (GTK_BOX (vbox3), label2, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_LEFT);
+
+  hpaned6 = gtk_hpaned_new ();
+  gtk_box_pack_start (GTK_BOX (vbox3), hpaned6, TRUE, TRUE, 0);
+
+  vpaned3 = gtk_vpaned_new ();
+  gtk_paned_pack1 (GTK_PANED (hpaned6), vpaned3, FALSE, TRUE);
+
+  button19 = gtk_button_new_with_label ("button19");
+  gtk_paned_pack1 (GTK_PANED (vpaned3), button19, FALSE, TRUE);
+
+  button18 = gtk_button_new_with_label ("button18");
+  gtk_paned_pack2 (GTK_PANED (vpaned3), button18, TRUE, TRUE);
+
+  hbox3 = gtk_hbox_new (FALSE, 0);
+  gtk_paned_pack2 (GTK_PANED (hpaned6), hbox3, TRUE, TRUE);
+
+  vpaned4 = gtk_vpaned_new ();
+  gtk_box_pack_start (GTK_BOX (hbox3), vpaned4, TRUE, TRUE, 0);
+
+  button21 = gtk_button_new_with_label ("button21");
+  gtk_paned_pack1 (GTK_PANED (vpaned4), button21, FALSE, TRUE);
+
+  button20 = gtk_button_new_with_label ("button20");
+  gtk_paned_pack2 (GTK_PANED (vpaned4), button20, TRUE, TRUE);
+
+  vpaned5 = gtk_vpaned_new ();
+  gtk_box_pack_start (GTK_BOX (hbox3), vpaned5, TRUE, TRUE, 0);
+
+  button23 = gtk_button_new_with_label ("button23");
+  gtk_paned_pack1 (GTK_PANED (vpaned5), button23, FALSE, TRUE);
+
+  button22 = gtk_button_new_with_label ("button22");
+  gtk_paned_pack2 (GTK_PANED (vpaned5), button22, TRUE, TRUE);
+
+  vpaned6 = gtk_vpaned_new ();
+  gtk_box_pack_start (GTK_BOX (hbox3), vpaned6, TRUE, TRUE, 0);
+
+  button25 = gtk_button_new_with_label ("button25");
+  gtk_paned_pack1 (GTK_PANED (vpaned6), button25, FALSE, TRUE);
+
+  button24 = gtk_button_new_with_label ("button24");
+  gtk_paned_pack2 (GTK_PANED (vpaned6), button24, TRUE, TRUE);
+
+  return window4;
+}
+
+static void
+create_paned_keyboard_navigation (void)
+{
+  static GtkWidget *window1 = NULL;
+  static GtkWidget *window2 = NULL;
+  static GtkWidget *window3 = NULL;
+  static GtkWidget *window4 = NULL;
+
+  if (!window1)
+    {
+      window1 = paned_keyboard_window1 ();
+      gtk_signal_connect (GTK_OBJECT (window1), "destroy",
+                         GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                         &window1);
+    }
+
+  if (!window2)
+    {
+      window2 = paned_keyboard_window2 ();
+      gtk_signal_connect (GTK_OBJECT (window2), "destroy",
+                         GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                         &window2);
+    }
+
+  if (!window3)
+    {
+      window3 = paned_keyboard_window3 ();
+      gtk_signal_connect (GTK_OBJECT (window3), "destroy",
+                         GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                         &window3);
+    }
+
+  if (!window4)
+    {
+      window4 = paned_keyboard_window4 ();
+      gtk_signal_connect (GTK_OBJECT (window4), "destroy",
+                         GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+                         &window4);
+    }
+
+  if (GTK_WIDGET_VISIBLE (window1))
+    gtk_widget_destroy (GTK_WIDGET (window1));
+  else
+    gtk_widget_show_all (GTK_WIDGET (window1));
+
+  if (GTK_WIDGET_VISIBLE (window2))
+    gtk_widget_destroy (GTK_WIDGET (window2));
+  else
+    gtk_widget_show_all (GTK_WIDGET (window2));
+
+  if (GTK_WIDGET_VISIBLE (window3))
+    gtk_widget_destroy (GTK_WIDGET (window3));
+  else
+    gtk_widget_show_all (GTK_WIDGET (window3));
+
+  if (GTK_WIDGET_VISIBLE (window4))
+    gtk_widget_destroy (GTK_WIDGET (window4));
+  else
+    gtk_widget_show_all (GTK_WIDGET (window4));
+}
+
+
 /*
  * Shaped Windows
  */
@@ -10966,6 +11331,7 @@ struct {
   { "modal window", create_modal_window, TRUE },
   { "notebook", create_notebook },
   { "panes", create_panes },
+  { "paned keyboard", create_paned_keyboard_navigation },
   { "pixmap", create_pixmap },
   { "preview color", create_color_preview, TRUE },
   { "preview gray", create_gray_preview, TRUE },