]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
Mark abstract types as G_TYPE_FLAG_ABSTRACT. (#72383)
[~andy/gtk] / gtk / gtkpaned.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkintl.h"
28 #include "gtkpaned.h"
29 #include "gtkbindings.h"
30 #include "gtksignal.h"
31 #include "gdk/gdkkeysyms.h"
32 #include "gtkwindow.h"
33 #include "gtkmain.h"
34 #include "gtkmarshalers.h"
35
36 enum {
37   PROP_0,
38   PROP_POSITION,
39   PROP_POSITION_SET
40 };
41
42 enum {
43   CYCLE_CHILD_FOCUS,
44   TOGGLE_HANDLE_FOCUS,
45   MOVE_HANDLE,
46   CYCLE_HANDLE_FOCUS,
47   ACCEPT_POSITION,
48   CANCEL_POSITION,
49   LAST_SIGNAL
50 };
51
52 static void     gtk_paned_class_init            (GtkPanedClass    *klass);
53 static void     gtk_paned_init                  (GtkPaned         *paned);
54 static void     gtk_paned_set_property          (GObject          *object,
55                                                  guint             prop_id,
56                                                  const GValue     *value,
57                                                  GParamSpec       *pspec);
58 static void     gtk_paned_get_property          (GObject          *object,
59                                                  guint             prop_id,
60                                                  GValue           *value,
61                                                  GParamSpec       *pspec);
62 static void     gtk_paned_realize               (GtkWidget        *widget);
63 static void     gtk_paned_unrealize             (GtkWidget        *widget);
64 static void     gtk_paned_map                   (GtkWidget        *widget);
65 static void     gtk_paned_unmap                 (GtkWidget        *widget);
66 static gboolean gtk_paned_expose                (GtkWidget        *widget,
67                                                  GdkEventExpose   *event);
68 static gboolean gtk_paned_enter                 (GtkWidget        *widget,
69                                                  GdkEventCrossing *event);
70 static gboolean gtk_paned_leave                 (GtkWidget        *widget,
71                                                  GdkEventCrossing *event);
72 static gboolean gtk_paned_button_press          (GtkWidget      *widget,
73                                                  GdkEventButton *event);
74 static gboolean gtk_paned_button_release        (GtkWidget      *widget,
75                                                  GdkEventButton *event);
76 static gboolean gtk_paned_motion                (GtkWidget      *widget,
77                                                  GdkEventMotion *event);
78 static gboolean gtk_paned_focus                 (GtkWidget        *widget,
79                                                  GtkDirectionType  direction);
80 static void     gtk_paned_add                   (GtkContainer     *container,
81                                                  GtkWidget        *widget);
82 static void     gtk_paned_remove                (GtkContainer     *container,
83                                                  GtkWidget        *widget);
84 static void     gtk_paned_forall                (GtkContainer     *container,
85                                                  gboolean          include_internals,
86                                                  GtkCallback       callback,
87                                                  gpointer          callback_data);
88 static void     gtk_paned_set_focus_child       (GtkContainer     *container,
89                                                  GtkWidget        *child);
90 static void     gtk_paned_set_saved_focus       (GtkPaned         *paned,
91                                                  GtkWidget        *widget);
92 static void     gtk_paned_set_last_child1_focus (GtkPaned         *paned,
93                                                  GtkWidget        *widget);
94 static void     gtk_paned_set_last_child2_focus (GtkPaned         *paned,
95                                                  GtkWidget        *widget);
96 static gboolean gtk_paned_cycle_child_focus     (GtkPaned         *paned,
97                                                  gboolean          reverse);
98 static gboolean gtk_paned_cycle_handle_focus    (GtkPaned         *paned,
99                                                  gboolean          reverse);
100 static gboolean gtk_paned_move_handle           (GtkPaned         *paned,
101                                                  GtkScrollType     scroll);
102 static gboolean gtk_paned_accept_position       (GtkPaned         *paned);
103 static gboolean gtk_paned_cancel_position       (GtkPaned         *paned);
104 static gboolean gtk_paned_toggle_handle_focus   (GtkPaned         *paned);
105 static GtkType  gtk_paned_child_type            (GtkContainer     *container);
106
107 static GtkContainerClass *parent_class = NULL;
108
109
110 GtkType
111 gtk_paned_get_type (void)
112 {
113   static GtkType paned_type = 0;
114   
115   if (!paned_type)
116     {
117       static const GTypeInfo paned_info =
118       {
119         sizeof (GtkPanedClass),
120         NULL,            /* base_init */
121         NULL,            /* base_finalize */
122         (GClassInitFunc) gtk_paned_class_init,
123         NULL,            /* class_finalize */
124         NULL,            /* class_data */
125         sizeof (GtkPaned),
126         0,               /* n_preallocs */
127         (GInstanceInitFunc) gtk_paned_init,
128         NULL,            /* value_table */
129       };
130
131       paned_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkPaned",
132                                            &paned_info, G_TYPE_FLAG_ABSTRACT);
133     }
134   
135   return paned_type;
136 }
137
138 static guint signals[LAST_SIGNAL] = { 0 };
139
140 static void
141 add_tab_bindings (GtkBindingSet    *binding_set,
142                   GdkModifierType   modifiers,
143                   gboolean          reverse)
144 {
145   gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
146                                 "cycle_handle_focus", 1,
147                                 G_TYPE_BOOLEAN, reverse);
148   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
149                                 "cycle_handle_focus", 1,
150                                 G_TYPE_BOOLEAN, reverse);
151 }
152
153 static void
154 add_move_binding (GtkBindingSet   *binding_set,
155                   guint            keyval,
156                   GdkModifierType  mask,
157                   GtkScrollType    scroll)
158 {
159   gtk_binding_entry_add_signal (binding_set, keyval, mask,
160                                 "move_handle", 1,
161                                 GTK_TYPE_SCROLL_TYPE, scroll);
162 }
163
164 static void
165 gtk_paned_class_init (GtkPanedClass *class)
166 {
167   GObjectClass *object_class;
168   GtkWidgetClass *widget_class;
169   GtkContainerClass *container_class;
170   GtkPanedClass *paned_class;
171   GtkBindingSet *binding_set;
172
173   object_class = (GObjectClass *) class;
174   widget_class = (GtkWidgetClass *) class;
175   container_class = (GtkContainerClass *) class;
176   paned_class = (GtkPanedClass *) class;
177
178   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
179
180   object_class->set_property = gtk_paned_set_property;
181   object_class->get_property = gtk_paned_get_property;
182
183   widget_class->realize = gtk_paned_realize;
184   widget_class->unrealize = gtk_paned_unrealize;
185   widget_class->map = gtk_paned_map;
186   widget_class->unmap = gtk_paned_unmap;
187   widget_class->expose_event = gtk_paned_expose;
188   widget_class->focus = gtk_paned_focus;
189   widget_class->enter_notify_event = gtk_paned_enter;
190   widget_class->leave_notify_event = gtk_paned_leave;
191   widget_class->button_press_event = gtk_paned_button_press;
192   widget_class->button_release_event = gtk_paned_button_release;
193   widget_class->motion_notify_event = gtk_paned_motion;
194   
195   container_class->add = gtk_paned_add;
196   container_class->remove = gtk_paned_remove;
197   container_class->forall = gtk_paned_forall;
198   container_class->child_type = gtk_paned_child_type;
199   container_class->set_focus_child = gtk_paned_set_focus_child;
200
201   paned_class->cycle_child_focus = gtk_paned_cycle_child_focus;
202   paned_class->toggle_handle_focus = gtk_paned_toggle_handle_focus;
203   paned_class->move_handle = gtk_paned_move_handle;
204   paned_class->cycle_handle_focus = gtk_paned_cycle_handle_focus;
205   paned_class->accept_position = gtk_paned_accept_position;
206   paned_class->cancel_position = gtk_paned_cancel_position;
207   
208   g_object_class_install_property (object_class,
209                                    PROP_POSITION,
210                                    g_param_spec_int ("position",
211                                                      _("Position"),
212                                                      _("Position of paned separator in pixels (0 means all the way to the left/top)"),
213                                                      0,
214                                                      G_MAXINT,
215                                                      0,
216                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
217   g_object_class_install_property (object_class,
218                                    PROP_POSITION_SET,
219                                    g_param_spec_boolean ("position_set",
220                                                          _("Position Set"),
221                                                          _("TRUE if the Position property should be used"),
222                                                          FALSE,
223                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
224                                    
225   gtk_widget_class_install_style_property (widget_class,
226                                            g_param_spec_int ("handle_size",
227                                                              _("Handle Size"),
228                                                              _("Width of handle"),
229                                                              0,
230                                                              G_MAXINT,
231                                                              5,
232                                                              G_PARAM_READABLE));
233
234   signals [CYCLE_HANDLE_FOCUS] =
235     g_signal_new ("cycle_child_focus",
236                   G_TYPE_FROM_CLASS (object_class),
237                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
238                   G_STRUCT_OFFSET (GtkPanedClass, cycle_child_focus),
239                   NULL, NULL,
240                   _gtk_marshal_BOOLEAN__BOOLEAN,
241                   G_TYPE_BOOLEAN, 1,
242                   G_TYPE_BOOLEAN);
243
244   signals [TOGGLE_HANDLE_FOCUS] =
245     g_signal_new ("toggle_handle_focus",
246                   G_TYPE_FROM_CLASS (object_class),
247                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
248                   G_STRUCT_OFFSET (GtkPanedClass, toggle_handle_focus),
249                   NULL, NULL,
250                   _gtk_marshal_BOOLEAN__VOID,
251                   G_TYPE_BOOLEAN, 0);
252
253   signals[MOVE_HANDLE] =
254     g_signal_new ("move_handle",
255                   G_TYPE_FROM_CLASS (object_class),
256                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
257                   G_STRUCT_OFFSET (GtkPanedClass, move_handle),
258                   NULL, NULL,
259                   _gtk_marshal_BOOLEAN__ENUM,
260                   G_TYPE_BOOLEAN, 1,
261                   GTK_TYPE_SCROLL_TYPE);
262
263   signals [CYCLE_HANDLE_FOCUS] =
264     g_signal_new ("cycle_handle_focus",
265                   G_TYPE_FROM_CLASS (object_class),
266                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
267                   G_STRUCT_OFFSET (GtkPanedClass, cycle_handle_focus),
268                   NULL, NULL,
269                   _gtk_marshal_BOOLEAN__BOOLEAN,
270                   G_TYPE_BOOLEAN, 1,
271                   G_TYPE_BOOLEAN);
272
273   signals [ACCEPT_POSITION] =
274     g_signal_new ("accept_position",
275                   G_TYPE_FROM_CLASS (object_class),
276                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
277                   G_STRUCT_OFFSET (GtkPanedClass, accept_position),
278                   NULL, NULL,
279                   _gtk_marshal_BOOLEAN__VOID,
280                   G_TYPE_BOOLEAN, 0);
281
282   signals [CANCEL_POSITION] =
283     g_signal_new ("cancel_position",
284                   G_TYPE_FROM_CLASS (object_class),
285                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
286                   G_STRUCT_OFFSET (GtkPanedClass, cancel_position),
287                   NULL, NULL,
288                   _gtk_marshal_BOOLEAN__VOID,
289                   G_TYPE_BOOLEAN, 0);
290
291   binding_set = gtk_binding_set_by_class (object_class);
292
293   /* F6 and friends */
294   gtk_binding_entry_add_signal (binding_set,                            
295                                 GDK_F6, 0,
296                                 "cycle_child_focus", 1, 
297                                 G_TYPE_BOOLEAN, FALSE);
298   gtk_binding_entry_add_signal (binding_set,
299                                 GDK_F6, GDK_SHIFT_MASK,
300                                 "cycle_child_focus", 1,
301                                 G_TYPE_BOOLEAN, TRUE);
302
303   /* F8 and friends */
304   gtk_binding_entry_add_signal (binding_set,
305                                 GDK_F8, 0,
306                                 "toggle_handle_focus", 0);
307  
308   add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
309   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
310   add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
311   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
312
313   /* accept and cancel positions */
314   gtk_binding_entry_add_signal (binding_set,
315                                 GDK_Escape, 0,
316                                 "cancel_position", 0);
317
318   gtk_binding_entry_add_signal (binding_set,
319                                 GDK_Return, 0,
320                                 "accept_position", 0);
321   gtk_binding_entry_add_signal (binding_set,
322                                 GDK_KP_Enter, 0,
323                                 "accept_position", 0);
324   gtk_binding_entry_add_signal (binding_set,
325                                 GDK_space, 0,
326                                 "accept_position", 0);
327   gtk_binding_entry_add_signal (binding_set,
328                                 GDK_KP_Space, 0,
329                                 "accept_position", 0);
330
331   /* move handle */
332   add_move_binding (binding_set, GDK_Left, 0, GTK_SCROLL_STEP_LEFT);
333   add_move_binding (binding_set, GDK_KP_Left, 0, GTK_SCROLL_STEP_LEFT);
334   add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
335   add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
336
337   add_move_binding (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_RIGHT);
338   add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
339   add_move_binding (binding_set, GDK_KP_Right, 0, GTK_SCROLL_STEP_RIGHT);
340   add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
341
342   add_move_binding (binding_set, GDK_Up, 0, GTK_SCROLL_STEP_UP);
343   add_move_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
344   add_move_binding (binding_set, GDK_KP_Up, 0, GTK_SCROLL_STEP_UP);
345   add_move_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
346   add_move_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_UP);
347   add_move_binding (binding_set, GDK_KP_Page_Up, 0, GTK_SCROLL_PAGE_UP);
348
349   add_move_binding (binding_set, GDK_Down, 0, GTK_SCROLL_STEP_DOWN);
350   add_move_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
351   add_move_binding (binding_set, GDK_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
352   add_move_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
353   add_move_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
354   add_move_binding (binding_set, GDK_KP_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
355
356   add_move_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START);
357   add_move_binding (binding_set, GDK_KP_Home, 0, GTK_SCROLL_START);
358   add_move_binding (binding_set, GDK_End, 0, GTK_SCROLL_END);
359   add_move_binding (binding_set, GDK_KP_End, 0, GTK_SCROLL_END);
360 }
361
362 static GtkType
363 gtk_paned_child_type (GtkContainer *container)
364 {
365   if (!GTK_PANED (container)->child1 || !GTK_PANED (container)->child2)
366     return GTK_TYPE_WIDGET;
367   else
368     return GTK_TYPE_NONE;
369 }
370
371 static void
372 gtk_paned_init (GtkPaned *paned)
373 {
374   GTK_WIDGET_SET_FLAGS (paned, GTK_NO_WINDOW | GTK_CAN_FOCUS);
375   
376   paned->child1 = NULL;
377   paned->child2 = NULL;
378   paned->handle = NULL;
379   paned->xor_gc = NULL;
380   paned->cursor_type = GDK_CROSS;
381   
382   paned->handle_pos.width = 5;
383   paned->handle_pos.height = 5;
384   paned->position_set = FALSE;
385   paned->last_allocation = -1;
386   paned->in_drag = FALSE;
387
388   paned->saved_focus = NULL;
389   paned->last_child1_focus = NULL;
390   paned->last_child2_focus = NULL;
391   paned->in_recursion = FALSE;
392   paned->handle_prelit = FALSE;
393   paned->original_position = -1;
394   
395   paned->handle_pos.x = -1;
396   paned->handle_pos.y = -1;
397
398   paned->drag_pos = -1;
399 }
400
401 static void
402 gtk_paned_set_property (GObject        *object,
403                         guint           prop_id,
404                         const GValue   *value,
405                         GParamSpec     *pspec)
406 {
407   GtkPaned *paned = GTK_PANED (object);
408   
409   switch (prop_id)
410     {
411     case PROP_POSITION:
412       gtk_paned_set_position (paned, g_value_get_int (value));
413       break;
414     case PROP_POSITION_SET:
415       paned->position_set = g_value_get_boolean (value);
416       gtk_widget_queue_resize (GTK_WIDGET (paned));
417       break;
418     default:
419       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
420       break;
421     }
422 }
423
424 static void
425 gtk_paned_get_property (GObject        *object,
426                         guint           prop_id,
427                         GValue         *value,
428                         GParamSpec     *pspec)
429 {
430   GtkPaned *paned = GTK_PANED (object);
431   
432   switch (prop_id)
433     {
434     case PROP_POSITION:
435       g_value_set_int (value, paned->child1_size);
436       break;
437     case PROP_POSITION_SET:
438       g_value_set_boolean (value, paned->position_set);
439       break;
440     default:
441       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
442       break;
443     }
444 }
445
446 static void
447 gtk_paned_realize (GtkWidget *widget)
448 {
449   GtkPaned *paned;
450   GdkWindowAttr attributes;
451   gint attributes_mask;
452
453   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
454   paned = GTK_PANED (widget);
455
456   widget->window = gtk_widget_get_parent_window (widget);
457   gdk_window_ref (widget->window);
458   
459   attributes.window_type = GDK_WINDOW_CHILD;
460   attributes.wclass = GDK_INPUT_ONLY;
461   attributes.x = paned->handle_pos.x;
462   attributes.y = paned->handle_pos.y;
463   attributes.width = paned->handle_pos.width;
464   attributes.height = paned->handle_pos.height;
465   attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
466                                                   paned->cursor_type);
467   attributes.event_mask = gtk_widget_get_events (widget);
468   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
469                             GDK_BUTTON_RELEASE_MASK |
470                             GDK_ENTER_NOTIFY_MASK |
471                             GDK_LEAVE_NOTIFY_MASK |
472                             GDK_POINTER_MOTION_MASK |
473                             GDK_POINTER_MOTION_HINT_MASK);
474   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
475
476   paned->handle = gdk_window_new (widget->window,
477                                   &attributes, attributes_mask);
478   gdk_window_set_user_data (paned->handle, paned);
479   gdk_cursor_destroy (attributes.cursor);
480
481   widget->style = gtk_style_attach (widget->style, widget->window);
482
483   if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
484       paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
485     gdk_window_show (paned->handle);
486 }
487
488 static void
489 gtk_paned_unrealize (GtkWidget *widget)
490 {
491   GtkPaned *paned = GTK_PANED (widget);
492
493   if (paned->xor_gc)
494     {
495       gdk_gc_destroy (paned->xor_gc);
496       paned->xor_gc = NULL;
497     }
498
499   if (paned->handle)
500     {
501       gdk_window_set_user_data (paned->handle, NULL);
502       gdk_window_destroy (paned->handle);
503       paned->handle = NULL;
504     }
505
506   gtk_paned_set_last_child1_focus (paned, NULL);
507   gtk_paned_set_last_child2_focus (paned, NULL);
508   gtk_paned_set_saved_focus (paned, NULL);
509   
510   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
511     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
512 }
513
514 static void
515 gtk_paned_map (GtkWidget *widget)
516 {
517   GtkPaned *paned = GTK_PANED (widget);
518
519   gdk_window_show (paned->handle);
520
521   GTK_WIDGET_CLASS (parent_class)->map (widget);
522 }
523
524 static void
525 gtk_paned_unmap (GtkWidget *widget)
526 {
527   GtkPaned *paned = GTK_PANED (widget);
528     
529   gdk_window_hide (paned->handle);
530
531   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
532 }
533
534 static gboolean
535 gtk_paned_expose (GtkWidget      *widget,
536                   GdkEventExpose *event)
537 {
538   GtkPaned *paned = GTK_PANED (widget);
539
540   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
541       paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) &&
542       paned->child2 && GTK_WIDGET_VISIBLE (paned->child2))
543     {
544       GdkRegion *region;
545
546       region = gdk_region_rectangle (&paned->handle_pos);
547       gdk_region_intersect (region, event->region);
548
549       if (!gdk_region_empty (region))
550         {
551           GtkStateType state;
552           GdkRectangle clip;
553
554           gdk_region_get_clipbox (region, &clip);
555
556           if (gtk_widget_is_focus (widget))
557             state = GTK_STATE_SELECTED;
558           else if (paned->handle_prelit)
559             state = GTK_STATE_PRELIGHT;
560           else
561             state = GTK_WIDGET_STATE (widget);
562           
563           gtk_paint_handle (widget->style, widget->window,
564                             state, GTK_SHADOW_NONE,
565                             &clip, widget, "paned",
566                             paned->handle_pos.x, paned->handle_pos.y,
567                             paned->handle_pos.width, paned->handle_pos.height,
568                             paned->orientation);
569         }
570
571       gdk_region_destroy (region);
572     }
573
574   /* Chain up to draw children */
575   GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
576   
577   return FALSE;
578 }
579
580 static void
581 update_drag (GtkPaned *paned)
582 {
583   gint pos;
584   gint handle_size;
585   gint size;
586   
587   if (paned->orientation == GTK_ORIENTATION_HORIZONTAL)
588     gtk_widget_get_pointer (GTK_WIDGET (paned), NULL, &pos);
589   else
590     gtk_widget_get_pointer (GTK_WIDGET (paned), &pos, NULL);
591
592   gtk_widget_style_get (GTK_WIDGET (paned), "handle_size", &handle_size, NULL);
593   
594   size = pos - GTK_CONTAINER (paned)->border_width - paned->drag_pos;
595   size = CLAMP (size, paned->min_position, paned->max_position);
596
597   if (size != paned->child1_size)
598     gtk_paned_set_position (paned, size);
599 }
600
601 static gboolean
602 gtk_paned_enter (GtkWidget        *widget,
603                  GdkEventCrossing *event)
604 {
605   GtkPaned *paned = GTK_PANED (widget);
606   
607   if (paned->in_drag)
608     update_drag (paned);
609   else
610     {
611       paned->handle_prelit = TRUE;
612       gtk_widget_queue_draw_area (widget,
613                                   paned->handle_pos.x,
614                                   paned->handle_pos.y,
615                                   paned->handle_pos.width,
616                                   paned->handle_pos.height);
617     }
618   
619   return TRUE;
620 }
621
622 static gboolean
623 gtk_paned_leave (GtkWidget        *widget,
624                  GdkEventCrossing *event)
625 {
626   GtkPaned *paned = GTK_PANED (widget);
627   
628   if (paned->in_drag)
629     update_drag (paned);
630   else
631     {
632       paned->handle_prelit = FALSE;
633       gtk_widget_queue_draw_area (widget,
634                                   paned->handle_pos.x,
635                                   paned->handle_pos.y,
636                                   paned->handle_pos.width,
637                                   paned->handle_pos.height);
638     }
639
640   return TRUE;
641 }
642
643 static gboolean
644 gtk_paned_focus (GtkWidget        *widget,
645                  GtkDirectionType  direction)
646
647 {
648   gboolean retval;
649   
650   /* This is a hack, but how can this be done without
651    * excessive cut-and-paste from gtkcontainer.c?
652    */
653
654   GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
655   retval = (* GTK_WIDGET_CLASS (parent_class)->focus) (widget, direction);
656   GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
657
658   return retval;
659 }
660
661 static gboolean
662 gtk_paned_button_press (GtkWidget      *widget,
663                         GdkEventButton *event)
664 {
665   GtkPaned *paned = GTK_PANED (widget);
666
667   if (!paned->in_drag &&
668       (event->window == paned->handle) && (event->button == 1))
669     {
670       paned->in_drag = TRUE;
671
672       /* We need a server grab here, not gtk_grab_add(), since
673        * we don't want to pass events on to the widget's children */
674       gdk_pointer_grab (paned->handle, FALSE,
675                         GDK_POINTER_MOTION_HINT_MASK
676                         | GDK_BUTTON1_MOTION_MASK
677                         | GDK_BUTTON_RELEASE_MASK
678                         | GDK_ENTER_NOTIFY_MASK
679                         | GDK_LEAVE_NOTIFY_MASK,
680                         NULL, NULL,
681                         event->time);
682
683       if (paned->orientation == GTK_ORIENTATION_HORIZONTAL)
684         paned->drag_pos = event->y;
685       else
686         paned->drag_pos = event->x;
687       
688       return TRUE;
689     }
690
691   return FALSE;
692 }
693
694 static gboolean
695 gtk_paned_button_release (GtkWidget      *widget,
696                           GdkEventButton *event)
697 {
698   GtkPaned *paned = GTK_PANED (widget);
699
700   if (paned->in_drag && (event->button == 1))
701     {
702       paned->in_drag = FALSE;
703       paned->drag_pos = -1;
704       paned->position_set = TRUE;
705       gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
706                                   event->time);
707       return TRUE;
708     }
709
710   return FALSE;
711 }
712
713 static gboolean
714 gtk_paned_motion (GtkWidget      *widget,
715                   GdkEventMotion *event)
716 {
717   GtkPaned *paned = GTK_PANED (widget);
718   
719   if (paned->in_drag)
720     {
721       update_drag (paned);
722       return TRUE;
723     }
724   
725   return FALSE;
726 }
727
728 void
729 gtk_paned_add1 (GtkPaned  *paned,
730                 GtkWidget *widget)
731 {
732   gtk_paned_pack1 (paned, widget, FALSE, TRUE);
733 }
734
735 void
736 gtk_paned_add2 (GtkPaned  *paned,
737                 GtkWidget *widget)
738 {
739   gtk_paned_pack2 (paned, widget, TRUE, TRUE);
740 }
741
742 void
743 gtk_paned_pack1 (GtkPaned  *paned,
744                  GtkWidget *child,
745                  gboolean   resize,
746                  gboolean   shrink)
747 {
748   g_return_if_fail (GTK_IS_PANED (paned));
749   g_return_if_fail (GTK_IS_WIDGET (child));
750
751   if (!paned->child1)
752     {
753       paned->child1 = child;
754       paned->child1_resize = resize;
755       paned->child1_shrink = shrink;
756
757       gtk_widget_set_parent (child, GTK_WIDGET (paned));
758     }
759 }
760
761 void
762 gtk_paned_pack2 (GtkPaned  *paned,
763                  GtkWidget *child,
764                  gboolean   resize,
765                  gboolean   shrink)
766 {
767   g_return_if_fail (GTK_IS_PANED (paned));
768   g_return_if_fail (GTK_IS_WIDGET (child));
769
770   if (!paned->child2)
771     {
772       paned->child2 = child;
773       paned->child2_resize = resize;
774       paned->child2_shrink = shrink;
775
776       gtk_widget_set_parent (child, GTK_WIDGET (paned));
777     }
778 }
779
780
781 static void
782 gtk_paned_add (GtkContainer *container,
783                GtkWidget    *widget)
784 {
785   GtkPaned *paned;
786
787   g_return_if_fail (GTK_IS_PANED (container));
788
789   paned = GTK_PANED (container);
790
791   if (!paned->child1)
792     gtk_paned_add1 (paned, widget);
793   else if (!paned->child2)
794     gtk_paned_add2 (paned, widget);
795 }
796
797 static void
798 gtk_paned_remove (GtkContainer *container,
799                   GtkWidget    *widget)
800 {
801   GtkPaned *paned;
802   gboolean was_visible;
803
804   paned = GTK_PANED (container);
805   was_visible = GTK_WIDGET_VISIBLE (widget);
806
807   if (paned->child1 == widget)
808     {
809       gtk_widget_unparent (widget);
810
811       paned->child1 = NULL;
812
813       if (was_visible && GTK_WIDGET_VISIBLE (container))
814         gtk_widget_queue_resize (GTK_WIDGET (container));
815     }
816   else if (paned->child2 == widget)
817     {
818       gtk_widget_unparent (widget);
819
820       paned->child2 = NULL;
821
822       if (was_visible && GTK_WIDGET_VISIBLE (container))
823         gtk_widget_queue_resize (GTK_WIDGET (container));
824     }
825 }
826
827 static void
828 gtk_paned_forall (GtkContainer *container,
829                   gboolean      include_internals,
830                   GtkCallback   callback,
831                   gpointer      callback_data)
832 {
833   GtkPaned *paned;
834
835   g_return_if_fail (callback != NULL);
836
837   paned = GTK_PANED (container);
838
839   if (paned->child1)
840     (*callback) (paned->child1, callback_data);
841   if (paned->child2)
842     (*callback) (paned->child2, callback_data);
843 }
844
845 /**
846  * gtk_paned_get_position:
847  * @paned: a #GtkPaned widget
848  * 
849  * Obtains the position of the divider between the two panes.
850  * 
851  * Return value: position of the divider
852  **/
853 gint
854 gtk_paned_get_position (GtkPaned  *paned)
855 {
856   g_return_val_if_fail (GTK_IS_PANED (paned), 0);
857
858   return paned->child1_size;
859 }
860
861 /**
862  * gtk_paned_set_position:
863  * @paned: a #GtkPaned widget
864  * @position: pixel position of divider, a negative value means that the position
865  *            is unset.
866  * 
867  * Sets the position of the divider between the two panes.
868  **/
869 void
870 gtk_paned_set_position (GtkPaned *paned,
871                         gint      position)
872 {
873   GObject *object;
874   
875   g_return_if_fail (GTK_IS_PANED (paned));
876
877   object = G_OBJECT (paned);
878   
879   if (position >= 0)
880     {
881       /* We don't clamp here - the assumption is that
882        * if the total allocation changes at the same time
883        * as the position, the position set is with reference
884        * to the new total size. If only the position changes,
885        * then clamping will occur in gtk_paned_compute_position()
886        */
887
888       paned->child1_size = position;
889       paned->position_set = TRUE;
890     }
891   else
892     {
893       paned->position_set = FALSE;
894     }
895
896   g_object_freeze_notify (object);
897   g_object_notify (object, "position");
898   g_object_notify (object, "position_set");
899   g_object_thaw_notify (object);
900
901   gtk_widget_queue_resize (GTK_WIDGET (paned));
902 }
903
904 void
905 gtk_paned_compute_position (GtkPaned *paned,
906                             gint      allocation,
907                             gint      child1_req,
908                             gint      child2_req)
909 {
910   gint old_position;
911   
912   g_return_if_fail (GTK_IS_PANED (paned));
913
914   old_position = paned->child1_size;
915
916   paned->min_position = paned->child1_shrink ? 0 : child1_req;
917
918   paned->max_position = allocation;
919   if (!paned->child2_shrink)
920     paned->max_position = MAX (1, paned->max_position - child2_req);
921
922   if (!paned->position_set)
923     {
924       if (paned->child1_resize && !paned->child2_resize)
925         paned->child1_size = MAX (1, allocation - child2_req);
926       else if (!paned->child1_resize && paned->child2_resize)
927         paned->child1_size = child1_req;
928       else if (child1_req + child2_req != 0)
929         paned->child1_size = allocation * ((gdouble)child1_req / (child1_req + child2_req));
930       else
931         paned->child1_size = allocation * 0.5;
932     }
933   else
934     {
935       /* If the position was set before the initial allocation.
936        * (paned->last_allocation <= 0) just clamp it and leave it.
937        */
938       if (paned->last_allocation > 0)
939         {
940           if (paned->child1_resize && !paned->child2_resize)
941             paned->child1_size += allocation - paned->last_allocation;
942           else if (!(!paned->child1_resize && paned->child2_resize))
943             paned->child1_size = allocation * ((gdouble) paned->child1_size / (paned->last_allocation));
944         }
945     }
946
947   paned->child1_size = CLAMP (paned->child1_size,
948                               paned->min_position,
949                               paned->max_position);
950
951   if (paned->child1_size != old_position)
952     g_object_notify (G_OBJECT (paned), "position");
953
954   paned->last_allocation = allocation;
955 }
956
957 static void
958 gtk_paned_set_saved_focus (GtkPaned *paned, GtkWidget *widget)
959 {
960   if (paned->saved_focus)
961     g_object_remove_weak_pointer (G_OBJECT (paned->saved_focus),
962                                   (gpointer *)&(paned->saved_focus));
963
964   paned->saved_focus = widget;
965
966   if (paned->saved_focus)
967     g_object_add_weak_pointer (G_OBJECT (paned->saved_focus),
968                                (gpointer *)&(paned->saved_focus));
969 }
970
971 static void
972 gtk_paned_set_last_child1_focus (GtkPaned *paned, GtkWidget *widget)
973 {
974   if (paned->last_child1_focus)
975     g_object_remove_weak_pointer (G_OBJECT (paned->last_child1_focus),
976                                   (gpointer *)&(paned->last_child1_focus));
977
978   paned->last_child1_focus = widget;
979
980   if (paned->last_child1_focus)
981     g_object_add_weak_pointer (G_OBJECT (paned->last_child1_focus),
982                                (gpointer *)&(paned->last_child1_focus));
983 }
984
985 static void
986 gtk_paned_set_last_child2_focus (GtkPaned *paned, GtkWidget *widget)
987 {
988   if (paned->last_child2_focus)
989     g_object_remove_weak_pointer (G_OBJECT (paned->last_child2_focus),
990                                   (gpointer *)&(paned->last_child2_focus));
991
992   paned->last_child2_focus = widget;
993
994   if (paned->last_child2_focus)
995     g_object_add_weak_pointer (G_OBJECT (paned->last_child2_focus),
996                                (gpointer *)&(paned->last_child2_focus));
997 }
998
999 static GtkWidget *
1000 paned_get_focus_widget (GtkPaned *paned)
1001 {
1002   GtkWidget *toplevel;
1003
1004   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
1005   if (GTK_WIDGET_TOPLEVEL (toplevel))
1006     return GTK_WINDOW (toplevel)->focus_widget;
1007
1008   return NULL;
1009 }
1010
1011 static void
1012 gtk_paned_set_focus_child (GtkContainer *container,
1013                            GtkWidget    *focus_child)
1014 {
1015   GtkPaned *paned;
1016   
1017   g_return_if_fail (GTK_IS_PANED (container));
1018
1019   paned = GTK_PANED (container);
1020  
1021   if (focus_child == NULL)
1022     {
1023       GtkWidget *last_focus;
1024       GtkWidget *w;
1025       
1026       last_focus = paned_get_focus_widget (paned);
1027
1028       if (last_focus)
1029         {
1030           /* If there is one or more paned widgets between us and the
1031            * focus widget, we want the topmost of those as last_focus
1032            */
1033           for (w = last_focus; w != GTK_WIDGET (paned); w = w->parent)
1034             if (GTK_IS_PANED (w))
1035               last_focus = w;
1036           
1037           if (container->focus_child == paned->child1)
1038             gtk_paned_set_last_child1_focus (paned, last_focus);
1039           else if (container->focus_child == paned->child2)
1040             gtk_paned_set_last_child2_focus (paned, last_focus);
1041         }
1042     }
1043
1044   if (parent_class->set_focus_child)
1045     (* parent_class->set_focus_child) (container, focus_child);
1046 }
1047
1048 static void
1049 gtk_paned_get_cycle_chain (GtkPaned          *paned,
1050                            GtkDirectionType   direction,
1051                            GList            **widgets)
1052 {
1053   GtkContainer *container = GTK_CONTAINER (paned);
1054   GtkWidget *ancestor = NULL;
1055   GList *temp_list = NULL;
1056   GList *list;
1057
1058   if (paned->in_recursion)
1059     return;
1060
1061   g_assert (widgets != NULL);
1062
1063   if (paned->last_child1_focus &&
1064       !gtk_widget_is_ancestor (paned->last_child1_focus, GTK_WIDGET (paned)))
1065     {
1066       gtk_paned_set_last_child1_focus (paned, NULL);
1067     }
1068
1069   if (paned->last_child2_focus &&
1070       !gtk_widget_is_ancestor (paned->last_child2_focus, GTK_WIDGET (paned)))
1071     {
1072       gtk_paned_set_last_child2_focus (paned, NULL);
1073     }
1074
1075   if (GTK_WIDGET (paned)->parent)
1076     ancestor = gtk_widget_get_ancestor (GTK_WIDGET (paned)->parent, GTK_TYPE_PANED);
1077
1078   /* The idea here is that temp_list is a list of widgets we want to cycle
1079    * to. The list is prioritized so that the first element is our first
1080    * choice, the next our second, and so on.
1081    *
1082    * We can't just use g_list_reverse(), because we want to try
1083    * paned->last_child?_focus before paned->child?, both when we
1084    * are going forward and backward.
1085    */
1086   if (direction == GTK_DIR_TAB_FORWARD)
1087     {
1088       if (container->focus_child == paned->child1)
1089         {
1090           temp_list = g_list_append (temp_list, paned->last_child2_focus);
1091           temp_list = g_list_append (temp_list, paned->child2);
1092           temp_list = g_list_append (temp_list, ancestor);
1093         }
1094       else if (container->focus_child == paned->child2)
1095         {
1096           temp_list = g_list_append (temp_list, ancestor);
1097           temp_list = g_list_append (temp_list, paned->last_child1_focus);
1098           temp_list = g_list_append (temp_list, paned->child1);
1099         }
1100       else
1101         {
1102           temp_list = g_list_append (temp_list, paned->last_child1_focus);
1103           temp_list = g_list_append (temp_list, paned->child1);
1104           temp_list = g_list_append (temp_list, paned->last_child2_focus);
1105           temp_list = g_list_append (temp_list, paned->child2);
1106           temp_list = g_list_append (temp_list, ancestor);
1107         }
1108     }
1109   else
1110     {
1111       if (container->focus_child == paned->child1)
1112         {
1113           temp_list = g_list_append (temp_list, ancestor);
1114           temp_list = g_list_append (temp_list, paned->last_child2_focus);
1115           temp_list = g_list_append (temp_list, paned->child2);
1116         }
1117       else if (container->focus_child == paned->child2)
1118         {
1119           temp_list = g_list_append (temp_list, paned->last_child1_focus);
1120           temp_list = g_list_append (temp_list, paned->child1);
1121           temp_list = g_list_append (temp_list, ancestor);
1122         }
1123       else
1124         {
1125           temp_list = g_list_append (temp_list, paned->last_child2_focus);
1126           temp_list = g_list_append (temp_list, paned->child2);
1127           temp_list = g_list_append (temp_list, paned->last_child1_focus);
1128           temp_list = g_list_append (temp_list, paned->child1);
1129           temp_list = g_list_append (temp_list, ancestor);
1130         }
1131     }
1132
1133   /* Walk through the list and expand all the paned widgets. */
1134   for (list = temp_list; list != NULL; list = list->next)
1135     {
1136       GtkWidget *widget = list->data;
1137
1138       if (widget)
1139         {
1140           if (GTK_IS_PANED (widget))
1141             {
1142               paned->in_recursion = TRUE;
1143               gtk_paned_get_cycle_chain (GTK_PANED (widget), direction, widgets);
1144               paned->in_recursion = FALSE;
1145             }
1146           else
1147             {
1148               *widgets = g_list_append (*widgets, widget);
1149             }
1150         }
1151     }
1152
1153   g_list_free (temp_list);
1154 }
1155
1156 static gboolean
1157 gtk_paned_cycle_child_focus (GtkPaned *paned,
1158                              gboolean  reversed)
1159 {
1160   GList *cycle_chain = NULL;
1161   GList *list;
1162
1163   GtkDirectionType direction = reversed? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
1164
1165   /* ignore f6 if the handle is focused */
1166   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1167     return TRUE;
1168   
1169   /* we can't just let the event propagate up the hierarchy,
1170    * because the paned will want to cycle focus _unless_ an
1171    * ancestor paned handles the event
1172    */
1173   gtk_paned_get_cycle_chain (paned, direction, &cycle_chain);
1174
1175   for (list = cycle_chain; list != NULL; list = list->next)
1176     if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
1177       break;
1178
1179   g_list_free (cycle_chain);
1180   
1181   return TRUE;
1182 }
1183
1184 static void
1185 get_child_panes (GtkWidget  *widget,
1186                  GList     **panes)
1187 {
1188   if (GTK_IS_PANED (widget))
1189     {
1190       GtkPaned *paned = GTK_PANED (widget);
1191       
1192       get_child_panes (paned->child1, panes);
1193       *panes = g_list_prepend (*panes, widget);
1194       get_child_panes (paned->child2, panes);
1195     }
1196   else if (GTK_IS_CONTAINER (widget))
1197     {
1198       gtk_container_foreach (GTK_CONTAINER (widget),
1199                              (GtkCallback)get_child_panes, panes);
1200     }
1201 }
1202
1203 static GList *
1204 get_all_panes (GtkPaned *paned)
1205 {
1206   GtkPaned *topmost = NULL;
1207   GList *result = NULL;
1208   GtkWidget *w;
1209   
1210   for (w = GTK_WIDGET (paned); w != NULL; w = w->parent)
1211     {
1212       if (GTK_IS_PANED (w))
1213         topmost = GTK_PANED (w);
1214     }
1215
1216   g_assert (topmost);
1217
1218   get_child_panes (GTK_WIDGET (topmost), &result);
1219
1220   return g_list_reverse (result);
1221 }
1222
1223 static void
1224 gtk_paned_find_neighbours (GtkPaned  *paned,
1225                            GtkPaned **next,
1226                            GtkPaned **prev)
1227 {
1228   GList *all_panes = get_all_panes (paned);
1229   GList *this_link;
1230
1231   g_assert (all_panes);
1232
1233   this_link = g_list_find (all_panes, paned);
1234
1235   g_assert (this_link);
1236   
1237   if (this_link->next)
1238     *next = this_link->next->data;
1239   else
1240     *next = all_panes->data;
1241
1242   if (this_link->prev)
1243     *prev = this_link->prev->data;
1244   else
1245     *prev = g_list_last (all_panes)->data;
1246
1247   if (*next == paned)
1248     *next = NULL;
1249
1250   if (*prev == paned)
1251     *prev = NULL;
1252
1253   g_list_free (all_panes);
1254 }
1255
1256 static gboolean
1257 gtk_paned_move_handle (GtkPaned      *paned,
1258                        GtkScrollType  scroll)
1259 {
1260   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1261     {
1262       gint old_position;
1263       gint new_position;
1264       
1265       enum {
1266         SINGLE_STEP_SIZE = 1,
1267         PAGE_STEP_SIZE   = 75
1268       };
1269       
1270       old_position = gtk_paned_get_position (paned);
1271       
1272       switch (scroll)
1273         {
1274         case GTK_SCROLL_STEP_LEFT:
1275         case GTK_SCROLL_STEP_UP:
1276         case GTK_SCROLL_STEP_BACKWARD:
1277           new_position = old_position - SINGLE_STEP_SIZE;
1278           break;
1279           
1280         case GTK_SCROLL_STEP_RIGHT:
1281         case GTK_SCROLL_STEP_DOWN:
1282         case GTK_SCROLL_STEP_FORWARD:
1283           new_position = old_position + SINGLE_STEP_SIZE;
1284           break;
1285           
1286         case GTK_SCROLL_PAGE_LEFT:
1287         case GTK_SCROLL_PAGE_UP:
1288         case GTK_SCROLL_PAGE_BACKWARD:
1289           new_position = old_position - PAGE_STEP_SIZE;
1290           break;
1291           
1292         case GTK_SCROLL_PAGE_RIGHT:
1293         case GTK_SCROLL_PAGE_DOWN:
1294         case GTK_SCROLL_PAGE_FORWARD:
1295           new_position = old_position + PAGE_STEP_SIZE;
1296           break;
1297           
1298         case GTK_SCROLL_START:
1299           new_position = paned->min_position;
1300           break;
1301           
1302         case GTK_SCROLL_END:
1303           new_position = paned->max_position;
1304           break;
1305           
1306         default:
1307           new_position = old_position;
1308           break;
1309         }
1310       
1311       new_position = CLAMP (new_position, paned->min_position, paned->max_position);
1312       
1313       if (old_position != new_position)
1314         gtk_paned_set_position (paned, new_position);
1315
1316       return TRUE;
1317     }
1318
1319   return FALSE;
1320 }
1321
1322 static void
1323 gtk_paned_restore_focus (GtkPaned *paned)
1324 {
1325   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1326     {
1327       if (paned->saved_focus && GTK_WIDGET_SENSITIVE (paned->saved_focus))
1328         {
1329           gtk_widget_grab_focus (paned->saved_focus);
1330         }
1331       else
1332         {
1333           /* the saved focus is somehow not available for focusing,
1334            * try
1335            *   1) tabbing into the paned widget
1336            * if that didn't work,
1337            *   2) unset focus for the window if there is one
1338            */
1339           
1340           if (!gtk_widget_child_focus (GTK_WIDGET (paned), GTK_DIR_TAB_FORWARD))
1341             {
1342               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
1343               
1344               if (GTK_IS_WINDOW (toplevel))
1345                 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
1346             }
1347         }
1348       
1349       gtk_paned_set_saved_focus (paned, NULL);
1350     }
1351 }
1352
1353 static gboolean
1354 gtk_paned_accept_position (GtkPaned *paned)
1355 {
1356   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1357     {
1358       paned->original_position = -1;
1359       gtk_paned_restore_focus (paned);
1360
1361       return TRUE;
1362     }
1363
1364   return FALSE;
1365 }
1366
1367
1368 static gboolean
1369 gtk_paned_cancel_position (GtkPaned *paned)
1370 {
1371   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1372     {
1373       if (paned->original_position != -1)
1374         {
1375           gtk_paned_set_position (paned, paned->original_position);
1376           paned->original_position = -1;
1377         }
1378
1379       gtk_paned_restore_focus (paned);
1380       return TRUE;
1381     }
1382
1383   return FALSE;
1384 }
1385
1386 static gboolean
1387 gtk_paned_cycle_handle_focus (GtkPaned *paned,
1388                               gboolean  reversed)
1389 {
1390   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1391     {
1392       GtkPaned *next, *prev;
1393       GtkPaned *focus = NULL;
1394
1395       gtk_paned_find_neighbours (paned, &next, &prev);
1396
1397       if (reversed && prev)
1398         focus = prev;
1399       else if (!reversed && next)
1400         focus = next;
1401
1402       if (focus)
1403         {
1404           gtk_paned_set_saved_focus (focus, paned->saved_focus);
1405           gtk_paned_set_saved_focus (paned, NULL);
1406           gtk_widget_grab_focus (GTK_WIDGET (focus));
1407
1408           if (!gtk_widget_is_focus (GTK_WIDGET (paned)))
1409             {
1410               paned->original_position = -1;
1411               focus->original_position = gtk_paned_get_position (focus);
1412             }
1413         }
1414       
1415       return TRUE;
1416     }
1417
1418   return FALSE;
1419 }
1420
1421 static gboolean
1422 gtk_paned_toggle_handle_focus (GtkPaned *paned)
1423 {
1424   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
1425     {
1426       gtk_paned_accept_position (paned);
1427     }
1428   else
1429     {
1430       GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
1431
1432       if (GTK_IS_WINDOW (toplevel))
1433         gtk_paned_set_saved_focus (paned, GTK_WINDOW (toplevel)->focus_widget);
1434   
1435       gtk_widget_grab_focus (GTK_WIDGET (paned));
1436       paned->original_position = gtk_paned_get_position (paned);
1437     }
1438
1439   return TRUE;
1440 }